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