xref: /original-bsd/sys/net/route.c (revision 3705696b)
1 /*
2  * Copyright (c) 1980, 1986, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)route.c	8.1 (Berkeley) 06/11/93
8  */
9 
10 #include <sys/param.h>
11 #include <sys/systm.h>
12 #include <sys/proc.h>
13 #include <sys/mbuf.h>
14 #include <sys/socket.h>
15 #include <sys/socketvar.h>
16 #include <sys/domain.h>
17 #include <sys/protosw.h>
18 #include <sys/ioctl.h>
19 
20 #include <net/if.h>
21 #include <net/af.h>
22 #include <net/route.h>
23 #include <net/raw_cb.h>
24 
25 #include <netinet/in.h>
26 #include <netinet/in_var.h>
27 
28 #ifdef NS
29 #include <netns/ns.h>
30 #endif
31 
32 #define	SA(p) ((struct sockaddr *)(p))
33 
34 int	rttrash;		/* routes not in table but not freed */
35 struct	sockaddr wildcard;	/* zero valued cookie for wildcard searches */
36 
37 void
38 rtable_init(table)
39 	void **table;
40 {
41 	struct domain *dom;
42 	for (dom = domains; dom; dom = dom->dom_next)
43 		if (dom->dom_rtattach)
44 			dom->dom_rtattach(&table[dom->dom_family],
45 			    dom->dom_rtoffset);
46 }
47 
48 void
49 route_init()
50 {
51 	rn_init();	/* initialize all zeroes, all ones, mask table */
52 	rtable_init((void **)rt_tables);
53 }
54 
55 /*
56  * Packet routing routines.
57  */
58 void
59 rtalloc(ro)
60 	register struct route *ro;
61 {
62 	if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
63 		return;				 /* XXX */
64 	ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
65 }
66 
67 struct rtentry *
68 rtalloc1(dst, report)
69 	register struct sockaddr *dst;
70 	int report;
71 {
72 	register struct radix_node_head *rnh = rt_tables[dst->sa_family];
73 	register struct rtentry *rt;
74 	register struct radix_node *rn;
75 	struct rtentry *newrt = 0;
76 	struct rt_addrinfo info;
77 	int  s = splnet(), err = 0, msgtype = RTM_MISS;
78 
79 	if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
80 	    ((rn->rn_flags & RNF_ROOT) == 0)) {
81 		newrt = rt = (struct rtentry *)rn;
82 		if (report && (rt->rt_flags & RTF_CLONING)) {
83 			err = rtrequest(RTM_RESOLVE, dst, SA(0),
84 					      SA(0), 0, &newrt);
85 			if (err) {
86 				newrt = rt;
87 				rt->rt_refcnt++;
88 				goto miss;
89 			}
90 			if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
91 				msgtype = RTM_RESOLVE;
92 				goto miss;
93 			}
94 		} else
95 			rt->rt_refcnt++;
96 	} else {
97 		rtstat.rts_unreach++;
98 	miss:	if (report) {
99 			bzero((caddr_t)&info, sizeof(info));
100 			info.rti_info[RTAX_DST] = dst;
101 			rt_missmsg(msgtype, &info, 0, err);
102 		}
103 	}
104 	splx(s);
105 	return (newrt);
106 }
107 
108 void
109 rtfree(rt)
110 	register struct rtentry *rt;
111 {
112 	register struct ifaddr *ifa;
113 
114 	if (rt == 0)
115 		panic("rtfree");
116 	rt->rt_refcnt--;
117 	if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
118 		if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
119 			panic ("rtfree 2");
120 		rttrash--;
121 		if (rt->rt_refcnt < 0) {
122 			printf("rtfree: %x not freed (neg refs)\n", rt);
123 			return;
124 		}
125 		ifa = rt->rt_ifa;
126 		IFAFREE(ifa);
127 		Free(rt_key(rt));
128 		Free(rt);
129 	}
130 }
131 
132 void
133 ifafree(ifa)
134 	register struct ifaddr *ifa;
135 {
136 	if (ifa == NULL)
137 		panic("ifafree");
138 	if (ifa->ifa_refcnt == 0)
139 		free(ifa, M_IFADDR);
140 	else
141 		ifa->ifa_refcnt--;
142 }
143 
144 /*
145  * Force a routing table entry to the specified
146  * destination to go through the given gateway.
147  * Normally called as a result of a routing redirect
148  * message from the network layer.
149  *
150  * N.B.: must be called at splnet
151  *
152  */
153 int
154 rtredirect(dst, gateway, netmask, flags, src, rtp)
155 	struct sockaddr *dst, *gateway, *netmask, *src;
156 	int flags;
157 	struct rtentry **rtp;
158 {
159 	register struct rtentry *rt;
160 	int error = 0;
161 	short *stat = 0;
162 	struct rt_addrinfo info;
163 	struct ifaddr *ifa;
164 
165 	/* verify the gateway is directly reachable */
166 	if ((ifa = ifa_ifwithnet(gateway)) == 0) {
167 		error = ENETUNREACH;
168 		goto out;
169 	}
170 	rt = rtalloc1(dst, 0);
171 	/*
172 	 * If the redirect isn't from our current router for this dst,
173 	 * it's either old or wrong.  If it redirects us to ourselves,
174 	 * we have a routing loop, perhaps as a result of an interface
175 	 * going down recently.
176 	 */
177 #define	equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
178 	if (!(flags & RTF_DONE) && rt &&
179 	     (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
180 		error = EINVAL;
181 	else if (ifa_ifwithaddr(gateway))
182 		error = EHOSTUNREACH;
183 	if (error)
184 		goto done;
185 	/*
186 	 * Create a new entry if we just got back a wildcard entry
187 	 * or the the lookup failed.  This is necessary for hosts
188 	 * which use routing redirects generated by smart gateways
189 	 * to dynamically build the routing tables.
190 	 */
191 	if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
192 		goto create;
193 	/*
194 	 * Don't listen to the redirect if it's
195 	 * for a route to an interface.
196 	 */
197 	if (rt->rt_flags & RTF_GATEWAY) {
198 		if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
199 			/*
200 			 * Changing from route to net => route to host.
201 			 * Create new route, rather than smashing route to net.
202 			 */
203 		create:
204 			flags |=  RTF_GATEWAY | RTF_DYNAMIC;
205 			error = rtrequest((int)RTM_ADD, dst, gateway,
206 				    netmask, flags,
207 				    (struct rtentry **)0);
208 			stat = &rtstat.rts_dynamic;
209 		} else {
210 			/*
211 			 * Smash the current notion of the gateway to
212 			 * this destination.  Should check about netmask!!!
213 			 */
214 			rt->rt_flags |= RTF_MODIFIED;
215 			flags |= RTF_MODIFIED;
216 			stat = &rtstat.rts_newgateway;
217 			rt_setgate(rt, rt_key(rt), gateway);
218 		}
219 	} else
220 		error = EHOSTUNREACH;
221 done:
222 	if (rt) {
223 		if (rtp && !error)
224 			*rtp = rt;
225 		else
226 			rtfree(rt);
227 	}
228 out:
229 	if (error)
230 		rtstat.rts_badredirect++;
231 	else if (stat != NULL)
232 		(*stat)++;
233 	bzero((caddr_t)&info, sizeof(info));
234 	info.rti_info[RTAX_DST] = dst;
235 	info.rti_info[RTAX_GATEWAY] = gateway;
236 	info.rti_info[RTAX_NETMASK] = netmask;
237 	info.rti_info[RTAX_AUTHOR] = src;
238 	rt_missmsg(RTM_REDIRECT, &info, flags, error);
239 }
240 
241 /*
242 * Routing table ioctl interface.
243 */
244 int
245 rtioctl(req, data, p)
246 	int req;
247 	caddr_t data;
248 	struct proc *p;
249 {
250 	return (EOPNOTSUPP);
251 }
252 
253 struct ifaddr *
254 ifa_ifwithroute(flags, dst, gateway)
255 	int flags;
256 	struct sockaddr	*dst, *gateway;
257 {
258 	register struct ifaddr *ifa;
259 	if ((flags & RTF_GATEWAY) == 0) {
260 		/*
261 		 * If we are adding a route to an interface,
262 		 * and the interface is a pt to pt link
263 		 * we should search for the destination
264 		 * as our clue to the interface.  Otherwise
265 		 * we can use the local address.
266 		 */
267 		ifa = 0;
268 		if (flags & RTF_HOST)
269 			ifa = ifa_ifwithdstaddr(dst);
270 		if (ifa == 0)
271 			ifa = ifa_ifwithaddr(gateway);
272 	} else {
273 		/*
274 		 * If we are adding a route to a remote net
275 		 * or host, the gateway may still be on the
276 		 * other end of a pt to pt link.
277 		 */
278 		ifa = ifa_ifwithdstaddr(gateway);
279 	}
280 	if (ifa == 0)
281 		ifa = ifa_ifwithnet(gateway);
282 	if (ifa == 0) {
283 		struct rtentry *rt = rtalloc1(dst, 0);
284 		if (rt == 0)
285 			return (0);
286 		rt->rt_refcnt--;
287 		if ((ifa = rt->rt_ifa) == 0)
288 			return (0);
289 	}
290 	if (ifa->ifa_addr->sa_family != dst->sa_family) {
291 		struct ifaddr *oifa = ifa;
292 		ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
293 		if (ifa == 0)
294 			ifa = oifa;
295 	}
296 	return (ifa);
297 }
298 
299 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
300 
301 int
302 rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
303 	int req, flags;
304 	struct sockaddr *dst, *gateway, *netmask;
305 	struct rtentry **ret_nrt;
306 {
307 	int s = splnet(); int error = 0;
308 	register struct rtentry *rt;
309 	register struct radix_node *rn;
310 	register struct radix_node_head *rnh;
311 	struct ifaddr *ifa;
312 	struct sockaddr *ndst;
313 #define senderr(x) { error = x ; goto bad; }
314 
315 	if ((rnh = rt_tables[dst->sa_family]) == 0)
316 		senderr(ESRCH);
317 	if (flags & RTF_HOST)
318 		netmask = 0;
319 	switch (req) {
320 	case RTM_DELETE:
321 		if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
322 			senderr(ESRCH);
323 		if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
324 			panic ("rtrequest delete");
325 		rt = (struct rtentry *)rn;
326 		rt->rt_flags &= ~RTF_UP;
327 		if (rt->rt_gwroute) {
328 			rt = rt->rt_gwroute; RTFREE(rt);
329 			(rt = (struct rtentry *)rn)->rt_gwroute = 0;
330 		}
331 		if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
332 			ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
333 		rttrash++;
334 		if (ret_nrt)
335 			*ret_nrt = rt;
336 		else if (rt->rt_refcnt <= 0) {
337 			rt->rt_refcnt++;
338 			rtfree(rt);
339 		}
340 		break;
341 
342 	case RTM_RESOLVE:
343 		if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
344 			senderr(EINVAL);
345 		ifa = rt->rt_ifa;
346 		flags = rt->rt_flags & ~RTF_CLONING;
347 		gateway = rt->rt_gateway;
348 		if ((netmask = rt->rt_genmask) == 0)
349 			flags |= RTF_HOST;
350 		goto makeroute;
351 
352 	case RTM_ADD:
353 		if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
354 			senderr(ENETUNREACH);
355 	makeroute:
356 		R_Malloc(rt, struct rtentry *, sizeof(*rt));
357 		if (rt == 0)
358 			senderr(ENOBUFS);
359 		Bzero(rt, sizeof(*rt));
360 		rt->rt_flags = RTF_UP | flags;
361 		if (rt_setgate(rt, dst, gateway)) {
362 			Free(rt);
363 			senderr(ENOBUFS);
364 		}
365 		ndst = rt_key(rt);
366 		if (netmask) {
367 			rt_maskedcopy(dst, ndst, netmask);
368 		} else
369 			Bcopy(dst, ndst, dst->sa_len);
370 		rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
371 					rnh, rt->rt_nodes);
372 		if (rn == 0) {
373 			if (rt->rt_gwroute)
374 				rtfree(rt->rt_gwroute);
375 			Free(rt_key(rt));
376 			Free(rt);
377 			senderr(EEXIST);
378 		}
379 		ifa->ifa_refcnt++;
380 		rt->rt_ifa = ifa;
381 		rt->rt_ifp = ifa->ifa_ifp;
382 		if (req == RTM_RESOLVE)
383 			rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
384 		if (ifa->ifa_rtrequest)
385 			ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
386 		if (ret_nrt) {
387 			*ret_nrt = rt;
388 			rt->rt_refcnt++;
389 		}
390 		break;
391 	}
392 bad:
393 	splx(s);
394 	return (error);
395 }
396 
397 int
398 rt_setgate(rt0, dst, gate)
399 	struct rtentry *rt0;
400 	struct sockaddr *dst, *gate;
401 {
402 	caddr_t new, old;
403 	int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
404 	register struct rtentry *rt = rt0;
405 
406 	if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
407 		old = (caddr_t)rt_key(rt);
408 		R_Malloc(new, caddr_t, dlen + glen);
409 		if (new == 0)
410 			return 1;
411 		rt->rt_nodes->rn_key = new;
412 	} else {
413 		new = rt->rt_nodes->rn_key;
414 		old = 0;
415 	}
416 	Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
417 	if (old) {
418 		Bcopy(dst, new, dlen);
419 		Free(old);
420 	}
421 	if (rt->rt_gwroute) {
422 		rt = rt->rt_gwroute; RTFREE(rt);
423 		rt = rt0; rt->rt_gwroute = 0;
424 	}
425 	if (rt->rt_flags & RTF_GATEWAY) {
426 		rt->rt_gwroute = rtalloc1(gate, 1);
427 	}
428 	return 0;
429 }
430 
431 void
432 rt_maskedcopy(src, dst, netmask)
433 	struct sockaddr *src, *dst, *netmask;
434 {
435 	register u_char *cp1 = (u_char *)src;
436 	register u_char *cp2 = (u_char *)dst;
437 	register u_char *cp3 = (u_char *)netmask;
438 	u_char *cplim = cp2 + *cp3;
439 	u_char *cplim2 = cp2 + *cp1;
440 
441 	*cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
442 	cp3 += 2;
443 	if (cplim > cplim2)
444 		cplim = cplim2;
445 	while (cp2 < cplim)
446 		*cp2++ = *cp1++ & *cp3++;
447 	if (cp2 < cplim2)
448 		bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
449 }
450 
451 /*
452  * Set up a routing table entry, normally
453  * for an interface.
454  */
455 int
456 rtinit(ifa, cmd, flags)
457 	register struct ifaddr *ifa;
458 	int cmd, flags;
459 {
460 	register struct rtentry *rt;
461 	register struct sockaddr *dst;
462 	register struct sockaddr *deldst;
463 	struct mbuf *m = 0;
464 	struct rtentry *nrt = 0;
465 	int error;
466 
467 	dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
468 	if (cmd == RTM_DELETE) {
469 		if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
470 			m = m_get(M_WAIT, MT_SONAME);
471 			deldst = mtod(m, struct sockaddr *);
472 			rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
473 			dst = deldst;
474 		}
475 		if (rt = rtalloc1(dst, 0)) {
476 			rt->rt_refcnt--;
477 			if (rt->rt_ifa != ifa) {
478 				if (m)
479 					(void) m_free(m);
480 				return (flags & RTF_HOST ? EHOSTUNREACH
481 							: ENETUNREACH);
482 			}
483 		}
484 	}
485 	error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
486 			flags | ifa->ifa_flags, &nrt);
487 	if (m)
488 		(void) m_free(m);
489 	if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
490 		rt_newaddrmsg(cmd, ifa, error, nrt);
491 		if (rt->rt_refcnt <= 0) {
492 			rt->rt_refcnt++;
493 			rtfree(rt);
494 		}
495 	}
496 	if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
497 		rt->rt_refcnt--;
498 		if (rt->rt_ifa != ifa) {
499 			printf("rtinit: wrong ifa (%x) was (%x)\n", ifa,
500 				rt->rt_ifa);
501 			if (rt->rt_ifa->ifa_rtrequest)
502 			    rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
503 			IFAFREE(rt->rt_ifa);
504 			rt->rt_ifa = ifa;
505 			rt->rt_ifp = ifa->ifa_ifp;
506 			ifa->ifa_refcnt++;
507 			if (ifa->ifa_rtrequest)
508 			    ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
509 		}
510 		rt_newaddrmsg(cmd, ifa, error, nrt);
511 	}
512 	return (error);
513 }
514