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