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.3.1.1 (Berkeley) 02/23/95
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/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
rtable_init(table)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
route_init()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
rtalloc(ro)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 *
rtalloc1(dst,report)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
rtfree(rt)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 void
ifafree(ifa)132 ifafree(ifa)
133 register struct ifaddr *ifa;
134 {
135 if (ifa == NULL)
136 panic("ifafree");
137 if (ifa->ifa_refcnt == 0)
138 free(ifa, M_IFADDR);
139 else
140 ifa->ifa_refcnt--;
141 }
142
143 /*
144 * Force a routing table entry to the specified
145 * destination to go through the given gateway.
146 * Normally called as a result of a routing redirect
147 * message from the network layer.
148 *
149 * N.B.: must be called at splnet
150 *
151 */
152 int
rtredirect(dst,gateway,netmask,flags,src,rtp)153 rtredirect(dst, gateway, netmask, flags, src, rtp)
154 struct sockaddr *dst, *gateway, *netmask, *src;
155 int flags;
156 struct rtentry **rtp;
157 {
158 register struct rtentry *rt;
159 int error = 0;
160 short *stat = 0;
161 struct rt_addrinfo info;
162 struct ifaddr *ifa;
163
164 /* verify the gateway is directly reachable */
165 if ((ifa = ifa_ifwithnet(gateway)) == 0) {
166 error = ENETUNREACH;
167 goto out;
168 }
169 rt = rtalloc1(dst, 0);
170 /*
171 * If the redirect isn't from our current router for this dst,
172 * it's either old or wrong. If it redirects us to ourselves,
173 * we have a routing loop, perhaps as a result of an interface
174 * going down recently.
175 */
176 #define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
177 if (!(flags & RTF_DONE) && rt &&
178 (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
179 error = EINVAL;
180 else if (ifa_ifwithaddr(gateway))
181 error = EHOSTUNREACH;
182 if (error)
183 goto done;
184 /*
185 * Create a new entry if we just got back a wildcard entry
186 * or the the lookup failed. This is necessary for hosts
187 * which use routing redirects generated by smart gateways
188 * to dynamically build the routing tables.
189 */
190 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
191 goto create;
192 /*
193 * Don't listen to the redirect if it's
194 * for a route to an interface.
195 */
196 if (rt->rt_flags & RTF_GATEWAY) {
197 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
198 /*
199 * Changing from route to net => route to host.
200 * Create new route, rather than smashing route to net.
201 */
202 create:
203 flags |= RTF_GATEWAY | RTF_DYNAMIC;
204 error = rtrequest((int)RTM_ADD, dst, gateway,
205 netmask, flags,
206 (struct rtentry **)0);
207 stat = &rtstat.rts_dynamic;
208 } else {
209 /*
210 * Smash the current notion of the gateway to
211 * this destination. Should check about netmask!!!
212 */
213 rt->rt_flags |= RTF_MODIFIED;
214 flags |= RTF_MODIFIED;
215 stat = &rtstat.rts_newgateway;
216 rt_setgate(rt, rt_key(rt), gateway);
217 }
218 } else
219 error = EHOSTUNREACH;
220 done:
221 if (rt) {
222 if (rtp && !error)
223 *rtp = rt;
224 else
225 rtfree(rt);
226 }
227 out:
228 if (error)
229 rtstat.rts_badredirect++;
230 else if (stat != NULL)
231 (*stat)++;
232 bzero((caddr_t)&info, sizeof(info));
233 info.rti_info[RTAX_DST] = dst;
234 info.rti_info[RTAX_GATEWAY] = gateway;
235 info.rti_info[RTAX_NETMASK] = netmask;
236 info.rti_info[RTAX_AUTHOR] = src;
237 rt_missmsg(RTM_REDIRECT, &info, flags, error);
238 }
239
240 /*
241 * Routing table ioctl interface.
242 */
243 int
rtioctl(req,data,p)244 rtioctl(req, data, p)
245 u_long req;
246 caddr_t data;
247 struct proc *p;
248 {
249 return (EOPNOTSUPP);
250 }
251
252 struct ifaddr *
ifa_ifwithroute(flags,dst,gateway)253 ifa_ifwithroute(flags, dst, gateway)
254 int flags;
255 struct sockaddr *dst, *gateway;
256 {
257 register struct ifaddr *ifa;
258 if ((flags & RTF_GATEWAY) == 0) {
259 /*
260 * If we are adding a route to an interface,
261 * and the interface is a pt to pt link
262 * we should search for the destination
263 * as our clue to the interface. Otherwise
264 * we can use the local address.
265 */
266 ifa = 0;
267 if (flags & RTF_HOST)
268 ifa = ifa_ifwithdstaddr(dst);
269 if (ifa == 0)
270 ifa = ifa_ifwithaddr(gateway);
271 } else {
272 /*
273 * If we are adding a route to a remote net
274 * or host, the gateway may still be on the
275 * other end of a pt to pt link.
276 */
277 ifa = ifa_ifwithdstaddr(gateway);
278 }
279 if (ifa == 0)
280 ifa = ifa_ifwithnet(gateway);
281 return (ifa);
282 }
283
284 int
rtrequest(req,dst,gateway,netmask,flags,ret_nrt)285 rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
286 int req, flags;
287 struct sockaddr *dst, *gateway, *netmask;
288 struct rtentry **ret_nrt;
289 {
290 struct rt_addrinfo info;
291
292 bzero((caddr_t)&info, sizeof(info));
293 info.rti_flags = flags;
294 info.rti_info[RTAX_DST] = dst;
295 info.rti_info[RTAX_GATEWAY] = gateway;
296 info.rti_info[RTAX_NETMASK] = netmask;
297 return rtrequest1(req, &info, ret_nrt);
298 }
299
300 /*
301 * These (questionable) definitions of apparent local variables apply
302 * to the next two functions. XXXXXX!!!
303 */
304 #define dst info->rti_info[RTAX_DST]
305 #define gateway info->rti_info[RTAX_GATEWAY]
306 #define netmask info->rti_info[RTAX_NETMASK]
307 #define ifaaddr info->rti_info[RTAX_IFA]
308 #define ifpaddr info->rti_info[RTAX_IFP]
309 #define flags info->rti_flags
310
311 int
rt_getifa(info)312 rt_getifa(info)
313 register struct rt_addrinfo *info;
314 {
315 struct ifaddr *ifa;
316 int error = 0;
317
318 /* ifp may be specified by sockaddr_dl
319 when protocol address is ambiguous */
320 if (info->rti_ifp == 0 && ifpaddr && ifpaddr->sa_family == AF_LINK) {
321 ifa = ifa_ifwithnet(ifpaddr);
322 info->rti_ifp = ifa ? ifa->ifa_ifp : 0;
323 }
324 if (info->rti_ifa == 0) {
325 struct sockaddr *sa;
326
327 sa = ifaaddr ? ifaaddr : (gateway ? gateway : dst);
328 if (sa && info->rti_ifp)
329 info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
330 else if (dst && gateway)
331 info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
332 else if (sa)
333 info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
334 }
335 if (ifa = info->rti_ifa) {
336 if (info->rti_ifp == 0)
337 info->rti_ifp = ifa->ifa_ifp;
338 } else
339 error = ENETUNREACH;
340 return error;
341 }
342
343 int
rtrequest1(req,info,ret_nrt)344 rtrequest1(req, info, ret_nrt)
345 int req;
346 register struct rt_addrinfo *info;
347 struct rtentry **ret_nrt;
348 {
349 int s = splnet(); int error = 0;
350 register struct rtentry *rt;
351 register struct radix_node *rn;
352 register struct radix_node_head *rnh;
353 struct ifaddr *ifa;
354 struct sockaddr *ndst;
355 #define senderr(x) { error = x ; goto bad; }
356
357 if ((rnh = rt_tables[dst->sa_family]) == 0)
358 senderr(EAFNOSUPPORT);
359 if (flags & RTF_HOST)
360 netmask = 0;
361 switch (req) {
362 case RTM_DELPKT:
363 if (rnh->rnh_deladdr == 0)
364 senderr(EOPNOTSUPP);
365 rn = rnh->rnh_delpkt(info->rti_pkthdr, (caddr_t)info, rnh);
366 goto delete;
367 case RTM_DELETE:
368 rn = rnh->rnh_deladdr(dst, netmask, rnh);
369 delete:
370 if (rn == 0)
371 senderr(ESRCH);
372 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
373 panic ("rtrequest delete");
374 rt = (struct rtentry *)rn;
375 rt->rt_flags &= ~RTF_UP;
376 if (rt->rt_gwroute) {
377 rt = rt->rt_gwroute; RTFREE(rt);
378 (rt = (struct rtentry *)rn)->rt_gwroute = 0;
379 }
380 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
381 ifa->ifa_rtrequest(req, rt, info);
382 rttrash++;
383 if (ret_nrt)
384 *ret_nrt = rt;
385 else if (rt->rt_refcnt <= 0) {
386 rt->rt_refcnt++;
387 rtfree(rt);
388 }
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_ADDPKT:
402 if (rnh->rnh_addpkt == 0)
403 senderr(EOPNOTSUPP);
404 /*FALLTHROUGH*/
405 case RTM_ADD:
406 if (info->rti_ifa == 0 && (error = rt_getifa(info)))
407 senderr(error);
408 ifa = info->rti_ifa;
409 makeroute:
410 R_Malloc(rt, struct rtentry *, sizeof(*rt));
411 if (rt == 0)
412 senderr(ENOBUFS);
413 Bzero(rt, sizeof(*rt));
414 rt->rt_flags = RTF_UP | flags;
415 if (rt_setgate(rt, dst, gateway)) {
416 Free(rt);
417 senderr(ENOBUFS);
418 }
419 if (req == RTM_ADDPKT) {
420 rn = rnh->rnh_addpkt(info->rti_pkthdr, (caddr_t)info,
421 rnh, rt->rt_nodes);
422 goto add; /* addpkt() must allocate space */
423 }
424 ndst = rt_key(rt);
425 if (netmask) {
426 rt_maskedcopy(dst, ndst, netmask);
427 } else
428 Bcopy(dst, ndst, dst->sa_len);
429 rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
430 rnh, rt->rt_nodes);
431 add:
432 if (rn == 0) {
433 if (rt->rt_gwroute)
434 rtfree(rt->rt_gwroute);
435 Free(rt_key(rt));
436 Free(rt);
437 senderr(EEXIST);
438 }
439 ifa->ifa_refcnt++;
440 rt->rt_ifa = ifa;
441 rt->rt_ifp = ifa->ifa_ifp;
442 if (req == RTM_RESOLVE)
443 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
444 if (ifa->ifa_rtrequest)
445 ifa->ifa_rtrequest(req, rt, info);
446 if (ret_nrt) {
447 *ret_nrt = rt;
448 rt->rt_refcnt++;
449 }
450 break;
451 default:
452 error = EOPNOTSUPP;
453 }
454 bad:
455 splx(s);
456 return (error);
457 #undef dst
458 #undef gateway
459 #undef netmask
460 #undef ifaaddr
461 #undef ifpaddr
462 #undef flags
463 }
464 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
465
466 int
rt_setgate(rt0,dst,gate)467 rt_setgate(rt0, dst, gate)
468 struct rtentry *rt0;
469 struct sockaddr *dst, *gate;
470 {
471 caddr_t new, old;
472 int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
473 register struct rtentry *rt = rt0;
474
475 if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
476 old = (caddr_t)rt_key(rt);
477 R_Malloc(new, caddr_t, dlen + glen);
478 if (new == 0)
479 return 1;
480 rt->rt_nodes->rn_key = new;
481 } else {
482 new = rt->rt_nodes->rn_key;
483 old = 0;
484 }
485 Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
486 if (old) {
487 Bcopy(dst, new, dlen);
488 Free(old);
489 }
490 if (rt->rt_gwroute) {
491 rt = rt->rt_gwroute; RTFREE(rt);
492 rt = rt0; rt->rt_gwroute = 0;
493 }
494 return 0;
495 }
496
497 void
rt_maskedcopy(src,dst,netmask)498 rt_maskedcopy(src, dst, netmask)
499 struct sockaddr *src, *dst, *netmask;
500 {
501 register u_char *cp1 = (u_char *)src;
502 register u_char *cp2 = (u_char *)dst;
503 register u_char *cp3 = (u_char *)netmask;
504 u_char *cplim = cp2 + *cp3;
505 u_char *cplim2 = cp2 + *cp1;
506
507 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
508 cp3 += 2;
509 if (cplim > cplim2)
510 cplim = cplim2;
511 while (cp2 < cplim)
512 *cp2++ = *cp1++ & *cp3++;
513 if (cp2 < cplim2)
514 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
515 }
516
517 /*
518 * Set up a routing table entry, normally
519 * for an interface.
520 */
521 int
rtinit(ifa,cmd,flags)522 rtinit(ifa, cmd, flags)
523 register struct ifaddr *ifa;
524 int cmd, flags;
525 {
526 register struct rtentry *rt;
527 register struct sockaddr *dst;
528 register struct sockaddr *deldst;
529 struct mbuf *m = 0;
530 struct rtentry *nrt = 0;
531 struct radix_node_head *rnh;
532 struct radix_node *rn;
533 int error;
534 struct rt_addrinfo info;
535
536 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
537 if (cmd == RTM_DELETE) {
538 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
539 m = m_get(M_WAIT, MT_SONAME);
540 deldst = mtod(m, struct sockaddr *);
541 rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
542 dst = deldst;
543 }
544 if ((rnh = rt_tables[dst->sa_family]) == 0 ||
545 (rn = rnh->rnh_lookup(dst, ifa->ifa_netmask, rnh)) == 0 ||
546 (rn->rn_flags & RNF_ROOT) != 0 ||
547 ((struct rtentry *)rn)->rt_ifa != ifa ||
548 !equal(rt_key(rt), dst))
549 {
550 if (m)
551 (void) m_free(m);
552 return (flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
553 }
554 }
555 bzero((caddr_t)&info, sizeof(info));
556 info.rti_ifa = ifa;
557 info.rti_flags = flags | ifa->ifa_flags;
558 info.rti_info[RTAX_DST] = dst;
559 info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
560 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
561 error = rtrequest1(cmd, &info, &nrt);
562
563 if (error == 0 && (rt = nrt)) {
564 rt_newaddrmsg(cmd, ifa, error, rt);
565 if (cmd == RTM_DELETE) {
566 if (rt->rt_refcnt <= 0) {
567 rt->rt_refcnt++;
568 rtfree(rt);
569 }
570 } else if (cmd == RTM_ADD)
571 rt->rt_refcnt--;
572 }
573 if (m)
574 (void) m_free(m);
575 return (error);
576 }
577