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