route.c revision 1.81 1 /* $NetBSD: route.c,v 1.81 2006/12/07 19:37:08 joerg Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Kevin M. Lahey of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*
41 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
42 * All rights reserved.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 * notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * 3. Neither the name of the project nor the names of its contributors
53 * may be used to endorse or promote products derived from this software
54 * without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 */
68
69 /*
70 * Copyright (c) 1980, 1986, 1991, 1993
71 * The Regents of the University of California. All rights reserved.
72 *
73 * Redistribution and use in source and binary forms, with or without
74 * modification, are permitted provided that the following conditions
75 * are met:
76 * 1. Redistributions of source code must retain the above copyright
77 * notice, this list of conditions and the following disclaimer.
78 * 2. Redistributions in binary form must reproduce the above copyright
79 * notice, this list of conditions and the following disclaimer in the
80 * documentation and/or other materials provided with the distribution.
81 * 3. Neither the name of the University nor the names of its contributors
82 * may be used to endorse or promote products derived from this software
83 * without specific prior written permission.
84 *
85 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
86 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
87 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
88 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
89 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
90 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
91 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
93 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95 * SUCH DAMAGE.
96 *
97 * @(#)route.c 8.3 (Berkeley) 1/9/95
98 */
99
100 #include <sys/cdefs.h>
101 __KERNEL_RCSID(0, "$NetBSD: route.c,v 1.81 2006/12/07 19:37:08 joerg Exp $");
102
103 #include <sys/param.h>
104 #include <sys/systm.h>
105 #include <sys/callout.h>
106 #include <sys/proc.h>
107 #include <sys/mbuf.h>
108 #include <sys/socket.h>
109 #include <sys/socketvar.h>
110 #include <sys/domain.h>
111 #include <sys/protosw.h>
112 #include <sys/kernel.h>
113 #include <sys/ioctl.h>
114 #include <sys/pool.h>
115
116 #include <net/if.h>
117 #include <net/route.h>
118 #include <net/raw_cb.h>
119
120 #include <netinet/in.h>
121 #include <netinet/in_var.h>
122
123
124 struct route_cb route_cb;
125 struct rtstat rtstat;
126 struct radix_node_head *rt_tables[AF_MAX+1];
127
128 int rttrash; /* routes not in table but not freed */
129 struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
130
131 POOL_INIT(rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl", NULL);
132 POOL_INIT(rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", NULL);
133
134 struct callout rt_timer_ch; /* callout for rt_timer_timer() */
135
136 static int rtdeletemsg(struct rtentry *);
137 static int rtflushclone1(struct radix_node *, void *);
138 static void rtflushclone(struct radix_node_head *, struct rtentry *);
139
140 struct ifaddr *
141 rt_get_ifa(struct rtentry *rt)
142 {
143 struct ifaddr *ifa;
144
145 if ((ifa = rt->rt_ifa) == NULL)
146 return ifa;
147 else if (ifa->ifa_getifa == NULL)
148 return ifa;
149 #if 0
150 else if (ifa->ifa_seqno != NULL && *ifa->ifa_seqno == rt->rt_ifa_seqno)
151 return ifa;
152 #endif
153 else {
154 ifa = (*ifa->ifa_getifa)(ifa, rt_key(rt));
155 rt_replace_ifa(rt, ifa);
156 return ifa;
157 }
158 }
159
160 static void
161 rt_set_ifa1(struct rtentry *rt, struct ifaddr *ifa)
162 {
163 rt->rt_ifa = ifa;
164 if (ifa->ifa_seqno != NULL)
165 rt->rt_ifa_seqno = *ifa->ifa_seqno;
166 }
167
168 void
169 rt_replace_ifa(struct rtentry *rt, struct ifaddr *ifa)
170 {
171 IFAREF(ifa);
172 IFAFREE(rt->rt_ifa);
173 rt_set_ifa1(rt, ifa);
174 }
175
176 static void
177 rt_set_ifa(struct rtentry *rt, struct ifaddr *ifa)
178 {
179 IFAREF(ifa);
180 rt_set_ifa1(rt, ifa);
181 }
182
183 void
184 rtable_init(void **table)
185 {
186 struct domain *dom;
187 DOMAIN_FOREACH(dom)
188 if (dom->dom_rtattach)
189 dom->dom_rtattach(&table[dom->dom_family],
190 dom->dom_rtoffset);
191 }
192
193 void
194 route_init(void)
195 {
196
197 rn_init(); /* initialize all zeroes, all ones, mask table */
198 rtable_init((void **)rt_tables);
199 }
200
201 /*
202 * Packet routing routines.
203 */
204 void
205 rtalloc(struct route *ro)
206 {
207 if (ro->ro_rt != NULL) {
208 if (ro->ro_rt->rt_ifp != NULL &&
209 (ro->ro_rt->rt_flags & RTF_UP) != 0)
210 return;
211 RTFREE(ro->ro_rt);
212 }
213 ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
214 }
215
216 struct rtentry *
217 rtalloc1(const struct sockaddr *dst, int report)
218 {
219 struct radix_node_head *rnh = rt_tables[dst->sa_family];
220 struct rtentry *rt;
221 struct radix_node *rn;
222 struct rtentry *newrt = NULL;
223 struct rt_addrinfo info;
224 int s = splsoftnet(), err = 0, msgtype = RTM_MISS;
225
226 if (rnh && (rn = rnh->rnh_matchaddr(dst, rnh)) &&
227 ((rn->rn_flags & RNF_ROOT) == 0)) {
228 newrt = rt = (struct rtentry *)rn;
229 if (report && (rt->rt_flags & RTF_CLONING)) {
230 err = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0,
231 &newrt);
232 if (err) {
233 newrt = rt;
234 rt->rt_refcnt++;
235 goto miss;
236 }
237 KASSERT(newrt != NULL);
238 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
239 msgtype = RTM_RESOLVE;
240 goto miss;
241 }
242 /* Inform listeners of the new route */
243 memset(&info, 0, sizeof(info));
244 info.rti_info[RTAX_DST] = rt_key(rt);
245 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
246 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
247 if (rt->rt_ifp != NULL) {
248 info.rti_info[RTAX_IFP] =
249 TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
250 info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
251 }
252 rt_missmsg(RTM_ADD, &info, rt->rt_flags, 0);
253 } else
254 rt->rt_refcnt++;
255 } else {
256 rtstat.rts_unreach++;
257 miss: if (report) {
258 memset((caddr_t)&info, 0, sizeof(info));
259 info.rti_info[RTAX_DST] = dst;
260 rt_missmsg(msgtype, &info, 0, err);
261 }
262 }
263 splx(s);
264 return (newrt);
265 }
266
267 void
268 rtfree(struct rtentry *rt)
269 {
270 struct ifaddr *ifa;
271
272 if (rt == NULL)
273 panic("rtfree");
274 rt->rt_refcnt--;
275 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
276 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
277 panic ("rtfree 2");
278 rttrash--;
279 if (rt->rt_refcnt < 0) {
280 printf("rtfree: %p not freed (neg refs)\n", rt);
281 return;
282 }
283 rt_timer_remove_all(rt, 0);
284 ifa = rt->rt_ifa;
285 rt->rt_ifa = NULL;
286 IFAFREE(ifa);
287 rt->rt_ifp = NULL;
288 Free(rt_key(rt));
289 pool_put(&rtentry_pool, rt);
290 }
291 }
292
293 void
294 ifafree(struct ifaddr *ifa)
295 {
296
297 #ifdef DIAGNOSTIC
298 if (ifa == NULL)
299 panic("ifafree: null ifa");
300 if (ifa->ifa_refcnt != 0)
301 panic("ifafree: ifa_refcnt != 0 (%d)", ifa->ifa_refcnt);
302 #endif
303 #ifdef IFAREF_DEBUG
304 printf("ifafree: freeing ifaddr %p\n", ifa);
305 #endif
306 free(ifa, M_IFADDR);
307 }
308
309 /*
310 * Force a routing table entry to the specified
311 * destination to go through the given gateway.
312 * Normally called as a result of a routing redirect
313 * message from the network layer.
314 *
315 * N.B.: must be called at splsoftnet
316 */
317 void
318 rtredirect(const struct sockaddr *dst, const struct sockaddr *gateway,
319 const struct sockaddr *netmask, int flags, const struct sockaddr *src,
320 struct rtentry **rtp)
321 {
322 struct rtentry *rt;
323 int error = 0;
324 u_quad_t *stat = NULL;
325 struct rt_addrinfo info;
326 struct ifaddr *ifa;
327
328 /* verify the gateway is directly reachable */
329 if ((ifa = ifa_ifwithnet(gateway)) == NULL) {
330 error = ENETUNREACH;
331 goto out;
332 }
333 rt = rtalloc1(dst, 0);
334 /*
335 * If the redirect isn't from our current router for this dst,
336 * it's either old or wrong. If it redirects us to ourselves,
337 * we have a routing loop, perhaps as a result of an interface
338 * going down recently.
339 */
340 #define equal(a1, a2) \
341 ((a1)->sa_len == (a2)->sa_len && \
342 memcmp((a1), (a2), (a1)->sa_len) == 0)
343 if (!(flags & RTF_DONE) && rt &&
344 (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
345 error = EINVAL;
346 else if (ifa_ifwithaddr(gateway))
347 error = EHOSTUNREACH;
348 if (error)
349 goto done;
350 /*
351 * Create a new entry if we just got back a wildcard entry
352 * or the lookup failed. This is necessary for hosts
353 * which use routing redirects generated by smart gateways
354 * to dynamically build the routing tables.
355 */
356 if ((rt == NULL) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
357 goto create;
358 /*
359 * Don't listen to the redirect if it's
360 * for a route to an interface.
361 */
362 if (rt->rt_flags & RTF_GATEWAY) {
363 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
364 /*
365 * Changing from route to net => route to host.
366 * Create new route, rather than smashing route to net.
367 */
368 create:
369 if (rt)
370 rtfree(rt);
371 flags |= RTF_GATEWAY | RTF_DYNAMIC;
372 info.rti_info[RTAX_DST] = dst;
373 info.rti_info[RTAX_GATEWAY] = gateway;
374 info.rti_info[RTAX_NETMASK] = netmask;
375 info.rti_ifa = ifa;
376 info.rti_flags = flags;
377 rt = NULL;
378 error = rtrequest1(RTM_ADD, &info, &rt);
379 if (rt != NULL)
380 flags = rt->rt_flags;
381 stat = &rtstat.rts_dynamic;
382 } else {
383 /*
384 * Smash the current notion of the gateway to
385 * this destination. Should check about netmask!!!
386 */
387 rt->rt_flags |= RTF_MODIFIED;
388 flags |= RTF_MODIFIED;
389 stat = &rtstat.rts_newgateway;
390 rt_setgate(rt, rt_key(rt), gateway);
391 }
392 } else
393 error = EHOSTUNREACH;
394 done:
395 if (rt) {
396 if (rtp && !error)
397 *rtp = rt;
398 else
399 rtfree(rt);
400 }
401 out:
402 if (error)
403 rtstat.rts_badredirect++;
404 else if (stat != NULL)
405 (*stat)++;
406 memset((caddr_t)&info, 0, sizeof(info));
407 info.rti_info[RTAX_DST] = dst;
408 info.rti_info[RTAX_GATEWAY] = gateway;
409 info.rti_info[RTAX_NETMASK] = netmask;
410 info.rti_info[RTAX_AUTHOR] = src;
411 rt_missmsg(RTM_REDIRECT, &info, flags, error);
412 }
413
414 /*
415 * Delete a route and generate a message
416 */
417 static int
418 rtdeletemsg(struct rtentry *rt)
419 {
420 int error;
421 struct rt_addrinfo info;
422
423 /*
424 * Request the new route so that the entry is not actually
425 * deleted. That will allow the information being reported to
426 * be accurate (and consistent with route_output()).
427 */
428 memset((caddr_t)&info, 0, sizeof(info));
429 info.rti_info[RTAX_DST] = rt_key(rt);
430 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
431 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
432 info.rti_flags = rt->rt_flags;
433 error = rtrequest1(RTM_DELETE, &info, &rt);
434
435 rt_missmsg(RTM_DELETE, &info, info.rti_flags, error);
436
437 /* Adjust the refcount */
438 if (error == 0 && rt->rt_refcnt <= 0) {
439 rt->rt_refcnt++;
440 rtfree(rt);
441 }
442 return (error);
443 }
444
445 static int
446 rtflushclone1(struct radix_node *rn, void *arg)
447 {
448 struct rtentry *rt, *parent;
449
450 rt = (struct rtentry *)rn;
451 parent = (struct rtentry *)arg;
452 if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent)
453 rtdeletemsg(rt);
454 return 0;
455 }
456
457 static void
458 rtflushclone(struct radix_node_head *rnh, struct rtentry *parent)
459 {
460
461 #ifdef DIAGNOSTIC
462 if (!parent || (parent->rt_flags & RTF_CLONING) == 0)
463 panic("rtflushclone: called with a non-cloning route");
464 if (!rnh->rnh_walktree)
465 panic("rtflushclone: no rnh_walktree");
466 #endif
467 rnh->rnh_walktree(rnh, rtflushclone1, (void *)parent);
468 }
469
470 /*
471 * Routing table ioctl interface.
472 */
473 int
474 rtioctl(u_long req, caddr_t data, struct lwp *l)
475 {
476 return (EOPNOTSUPP);
477 }
478
479 struct ifaddr *
480 ifa_ifwithroute(int flags, const struct sockaddr *dst,
481 const struct sockaddr *gateway)
482 {
483 struct ifaddr *ifa;
484 if ((flags & RTF_GATEWAY) == 0) {
485 /*
486 * If we are adding a route to an interface,
487 * and the interface is a pt to pt link
488 * we should search for the destination
489 * as our clue to the interface. Otherwise
490 * we can use the local address.
491 */
492 ifa = NULL;
493 if (flags & RTF_HOST)
494 ifa = ifa_ifwithdstaddr(dst);
495 if (ifa == NULL)
496 ifa = ifa_ifwithaddr(gateway);
497 } else {
498 /*
499 * If we are adding a route to a remote net
500 * or host, the gateway may still be on the
501 * other end of a pt to pt link.
502 */
503 ifa = ifa_ifwithdstaddr(gateway);
504 }
505 if (ifa == NULL)
506 ifa = ifa_ifwithnet(gateway);
507 if (ifa == NULL) {
508 struct rtentry *rt = rtalloc1(dst, 0);
509 if (rt == NULL)
510 return NULL;
511 rt->rt_refcnt--;
512 if ((ifa = rt->rt_ifa) == NULL)
513 return NULL;
514 }
515 if (ifa->ifa_addr->sa_family != dst->sa_family) {
516 struct ifaddr *oifa = ifa;
517 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
518 if (ifa == 0)
519 ifa = oifa;
520 }
521 return (ifa);
522 }
523
524 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
525
526 int
527 rtrequest(int req, const struct sockaddr *dst, const struct sockaddr *gateway,
528 const struct sockaddr *netmask, int flags, struct rtentry **ret_nrt)
529 {
530 struct rt_addrinfo info;
531
532 memset(&info, 0, sizeof(info));
533 info.rti_flags = flags;
534 info.rti_info[RTAX_DST] = dst;
535 info.rti_info[RTAX_GATEWAY] = gateway;
536 info.rti_info[RTAX_NETMASK] = netmask;
537 return rtrequest1(req, &info, ret_nrt);
538 }
539
540 int
541 rt_getifa(struct rt_addrinfo *info)
542 {
543 struct ifaddr *ifa;
544 const struct sockaddr *dst = info->rti_info[RTAX_DST];
545 const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
546 const struct sockaddr *ifaaddr = info->rti_info[RTAX_IFA];
547 const struct sockaddr *ifpaddr = info->rti_info[RTAX_IFP];
548 int flags = info->rti_flags;
549
550 /*
551 * ifp may be specified by sockaddr_dl when protocol address
552 * is ambiguous
553 */
554 if (info->rti_ifp == NULL && ifpaddr != NULL
555 && ifpaddr->sa_family == AF_LINK &&
556 (ifa = ifa_ifwithnet((const struct sockaddr *)ifpaddr)) != NULL)
557 info->rti_ifp = ifa->ifa_ifp;
558 if (info->rti_ifa == NULL && ifaaddr != NULL)
559 info->rti_ifa = ifa_ifwithaddr(ifaaddr);
560 if (info->rti_ifa == NULL) {
561 const struct sockaddr *sa;
562
563 sa = ifaaddr != NULL ? ifaaddr :
564 (gateway != NULL ? gateway : dst);
565 if (sa != NULL && info->rti_ifp != NULL)
566 info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
567 else if (dst != NULL && gateway != NULL)
568 info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
569 else if (sa != NULL)
570 info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
571 }
572 if ((ifa = info->rti_ifa) == NULL)
573 return ENETUNREACH;
574 if (ifa->ifa_getifa != NULL)
575 info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst);
576 if (info->rti_ifp == NULL)
577 info->rti_ifp = ifa->ifa_ifp;
578 return 0;
579 }
580
581 int
582 rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
583 {
584 int s = splsoftnet();
585 int error = 0;
586 struct rtentry *rt, *crt;
587 struct radix_node *rn;
588 struct radix_node_head *rnh;
589 struct ifaddr *ifa;
590 struct sockaddr_storage deldst;
591 const struct sockaddr *dst = info->rti_info[RTAX_DST];
592 const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
593 const struct sockaddr *netmask = info->rti_info[RTAX_NETMASK];
594 int flags = info->rti_flags;
595 #define senderr(x) { error = x ; goto bad; }
596
597 if ((rnh = rt_tables[dst->sa_family]) == NULL)
598 senderr(ESRCH);
599 if (flags & RTF_HOST)
600 netmask = NULL;
601 switch (req) {
602 case RTM_DELETE:
603 if (netmask) {
604 rt_maskedcopy(dst, (struct sockaddr *)&deldst, netmask);
605 dst = (struct sockaddr *)&deldst;
606 }
607 if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == NULL)
608 senderr(ESRCH);
609 rt = (struct rtentry *)rn;
610 if ((rt->rt_flags & RTF_CLONING) != 0) {
611 /* clean up any cloned children */
612 rtflushclone(rnh, rt);
613 }
614 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL)
615 senderr(ESRCH);
616 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
617 panic ("rtrequest delete");
618 rt = (struct rtentry *)rn;
619 if (rt->rt_gwroute) {
620 RTFREE(rt->rt_gwroute);
621 rt->rt_gwroute = NULL;
622 }
623 if (rt->rt_parent) {
624 rt->rt_parent->rt_refcnt--;
625 rt->rt_parent = NULL;
626 }
627 rt->rt_flags &= ~RTF_UP;
628 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
629 ifa->ifa_rtrequest(RTM_DELETE, rt, info);
630 rttrash++;
631 if (ret_nrt)
632 *ret_nrt = rt;
633 else if (rt->rt_refcnt <= 0) {
634 rt->rt_refcnt++;
635 rtfree(rt);
636 }
637 break;
638
639 case RTM_RESOLVE:
640 if (ret_nrt == NULL || (rt = *ret_nrt) == NULL)
641 senderr(EINVAL);
642 if ((rt->rt_flags & RTF_CLONING) == 0)
643 senderr(EINVAL);
644 ifa = rt->rt_ifa;
645 flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC);
646 flags |= RTF_CLONED;
647 gateway = rt->rt_gateway;
648 if ((netmask = rt->rt_genmask) == NULL)
649 flags |= RTF_HOST;
650 goto makeroute;
651
652 case RTM_ADD:
653 if (info->rti_ifa == NULL && (error = rt_getifa(info)))
654 senderr(error);
655 ifa = info->rti_ifa;
656 makeroute:
657 /* Already at splsoftnet() so pool_get/pool_put are safe */
658 rt = pool_get(&rtentry_pool, PR_NOWAIT);
659 if (rt == NULL)
660 senderr(ENOBUFS);
661 Bzero(rt, sizeof(*rt));
662 rt->rt_flags = RTF_UP | flags;
663 LIST_INIT(&rt->rt_timer);
664 if (rt_setgate(rt, dst, gateway)) {
665 pool_put(&rtentry_pool, rt);
666 senderr(ENOBUFS);
667 }
668 if (netmask) {
669 rt_maskedcopy(dst, rt_key(rt), netmask);
670 } else
671 Bcopy(dst, rt_key(rt), dst->sa_len);
672 rt_set_ifa(rt, ifa);
673 rt->rt_ifp = ifa->ifa_ifp;
674 if (req == RTM_RESOLVE) {
675 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
676 rt->rt_parent = *ret_nrt;
677 rt->rt_parent->rt_refcnt++;
678 }
679 rn = rnh->rnh_addaddr(rt_key(rt), netmask, rnh, rt->rt_nodes);
680 if (rn == NULL && (crt = rtalloc1(rt_key(rt), 0)) != NULL) {
681 /* overwrite cloned route */
682 if ((crt->rt_flags & RTF_CLONED) != 0) {
683 rtdeletemsg(crt);
684 rn = rnh->rnh_addaddr(rt_key(rt),
685 netmask, rnh, rt->rt_nodes);
686 }
687 RTFREE(crt);
688 }
689 if (rn == NULL) {
690 IFAFREE(ifa);
691 if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent)
692 rtfree(rt->rt_parent);
693 if (rt->rt_gwroute)
694 rtfree(rt->rt_gwroute);
695 Free(rt_key(rt));
696 pool_put(&rtentry_pool, rt);
697 senderr(EEXIST);
698 }
699 if (ifa->ifa_rtrequest)
700 ifa->ifa_rtrequest(req, rt, info);
701 if (ret_nrt) {
702 *ret_nrt = rt;
703 rt->rt_refcnt++;
704 }
705 if ((rt->rt_flags & RTF_CLONING) != 0) {
706 /* clean up any cloned children */
707 rtflushclone(rnh, rt);
708 }
709 break;
710 }
711 bad:
712 splx(s);
713 return (error);
714 }
715
716 int
717 rt_setgate( struct rtentry *rt0, const struct sockaddr *dst,
718 const struct sockaddr *gate)
719 {
720 char *new, *old;
721 u_int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
722 struct rtentry *rt = rt0;
723
724 if (rt->rt_gateway == NULL || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
725 old = (caddr_t)rt_key(rt);
726 R_Malloc(new, caddr_t, dlen + glen);
727 if (new == NULL)
728 return 1;
729 Bzero(new, dlen + glen);
730 rt->rt_nodes->rn_key = new;
731 } else {
732 new = __UNCONST(rt->rt_nodes->rn_key); /*XXXUNCONST*/
733 old = NULL;
734 }
735 Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
736 if (old) {
737 Bcopy(dst, new, dlen);
738 Free(old);
739 }
740 if (rt->rt_gwroute) {
741 RTFREE(rt->rt_gwroute);
742 rt->rt_gwroute = NULL;
743 }
744 if (rt->rt_flags & RTF_GATEWAY) {
745 rt->rt_gwroute = rtalloc1(gate, 1);
746 /*
747 * If we switched gateways, grab the MTU from the new
748 * gateway route if the current MTU, if the current MTU is
749 * greater than the MTU of gateway.
750 * Note that, if the MTU of gateway is 0, we will reset the
751 * MTU of the route to run PMTUD again from scratch. XXX
752 */
753 if (rt->rt_gwroute
754 && !(rt->rt_rmx.rmx_locks & RTV_MTU)
755 && rt->rt_rmx.rmx_mtu
756 && rt->rt_rmx.rmx_mtu > rt->rt_gwroute->rt_rmx.rmx_mtu) {
757 rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu;
758 }
759 }
760 return 0;
761 }
762
763 void
764 rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst,
765 const struct sockaddr *netmask)
766 {
767 const u_char *cp1 = (const u_char *)src;
768 u_char *cp2 = (u_char *)dst;
769 const u_char *cp3 = (const u_char *)netmask;
770 u_char *cplim = cp2 + *cp3;
771 u_char *cplim2 = cp2 + *cp1;
772
773 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
774 cp3 += 2;
775 if (cplim > cplim2)
776 cplim = cplim2;
777 while (cp2 < cplim)
778 *cp2++ = *cp1++ & *cp3++;
779 if (cp2 < cplim2)
780 memset(cp2, 0, (unsigned)(cplim2 - cp2));
781 }
782
783 /*
784 * Set up or tear down a routing table entry, normally
785 * for an interface.
786 */
787 int
788 rtinit(struct ifaddr *ifa, int cmd, int flags)
789 {
790 struct rtentry *rt;
791 struct sockaddr *dst, *odst;
792 struct sockaddr_storage deldst;
793 struct rtentry *nrt = NULL;
794 int error;
795 struct rt_addrinfo info;
796
797 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
798 if (cmd == RTM_DELETE) {
799 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
800 /* Delete subnet route for this interface */
801 odst = dst;
802 dst = (struct sockaddr *)&deldst;
803 rt_maskedcopy(odst, dst, ifa->ifa_netmask);
804 }
805 if ((rt = rtalloc1(dst, 0)) != NULL) {
806 rt->rt_refcnt--;
807 if (rt->rt_ifa != ifa)
808 return (flags & RTF_HOST ? EHOSTUNREACH
809 : ENETUNREACH);
810 }
811 }
812 memset(&info, 0, sizeof(info));
813 info.rti_ifa = ifa;
814 info.rti_flags = flags | ifa->ifa_flags;
815 info.rti_info[RTAX_DST] = dst;
816 info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr;
817 /*
818 * XXX here, it seems that we are assuming that ifa_netmask is NULL
819 * for RTF_HOST. bsdi4 passes NULL explicitly (via intermediate
820 * variable) when RTF_HOST is 1. still not sure if i can safely
821 * change it to meet bsdi4 behavior.
822 */
823 info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask;
824 error = rtrequest1(cmd, &info, &nrt);
825 if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
826 rt_newaddrmsg(cmd, ifa, error, nrt);
827 if (rt->rt_refcnt <= 0) {
828 rt->rt_refcnt++;
829 rtfree(rt);
830 }
831 }
832 if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
833 rt->rt_refcnt--;
834 if (rt->rt_ifa != ifa) {
835 printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
836 rt->rt_ifa);
837 if (rt->rt_ifa->ifa_rtrequest)
838 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL);
839 rt_replace_ifa(rt, ifa);
840 rt->rt_ifp = ifa->ifa_ifp;
841 if (ifa->ifa_rtrequest)
842 ifa->ifa_rtrequest(RTM_ADD, rt, NULL);
843 }
844 rt_newaddrmsg(cmd, ifa, error, nrt);
845 }
846 return (error);
847 }
848
849 /*
850 * Route timer routines. These routes allow functions to be called
851 * for various routes at any time. This is useful in supporting
852 * path MTU discovery and redirect route deletion.
853 *
854 * This is similar to some BSDI internal functions, but it provides
855 * for multiple queues for efficiency's sake...
856 */
857
858 LIST_HEAD(, rttimer_queue) rttimer_queue_head;
859 static int rt_init_done = 0;
860
861 #define RTTIMER_CALLOUT(r) do { \
862 if (r->rtt_func != NULL) { \
863 (*r->rtt_func)(r->rtt_rt, r); \
864 } else { \
865 rtrequest((int) RTM_DELETE, \
866 (struct sockaddr *)rt_key(r->rtt_rt), \
867 0, 0, 0, 0); \
868 } \
869 } while (/*CONSTCOND*/0)
870
871 /*
872 * Some subtle order problems with domain initialization mean that
873 * we cannot count on this being run from rt_init before various
874 * protocol initializations are done. Therefore, we make sure
875 * that this is run when the first queue is added...
876 */
877
878 void
879 rt_timer_init(void)
880 {
881 assert(rt_init_done == 0);
882
883 LIST_INIT(&rttimer_queue_head);
884 callout_init(&rt_timer_ch);
885 callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
886 rt_init_done = 1;
887 }
888
889 struct rttimer_queue *
890 rt_timer_queue_create(u_int timeout)
891 {
892 struct rttimer_queue *rtq;
893
894 if (rt_init_done == 0)
895 rt_timer_init();
896
897 R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
898 if (rtq == NULL)
899 return (NULL);
900 Bzero(rtq, sizeof *rtq);
901
902 rtq->rtq_timeout = timeout;
903 rtq->rtq_count = 0;
904 TAILQ_INIT(&rtq->rtq_head);
905 LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
906
907 return (rtq);
908 }
909
910 void
911 rt_timer_queue_change(struct rttimer_queue *rtq, long timeout)
912 {
913
914 rtq->rtq_timeout = timeout;
915 }
916
917 void
918 rt_timer_queue_remove_all(struct rttimer_queue *rtq, int destroy)
919 {
920 struct rttimer *r;
921
922 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL) {
923 LIST_REMOVE(r, rtt_link);
924 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
925 if (destroy)
926 RTTIMER_CALLOUT(r);
927 /* we are already at splsoftnet */
928 pool_put(&rttimer_pool, r);
929 if (rtq->rtq_count > 0)
930 rtq->rtq_count--;
931 else
932 printf("rt_timer_queue_remove_all: "
933 "rtq_count reached 0\n");
934 }
935 }
936
937 void
938 rt_timer_queue_destroy(struct rttimer_queue *rtq, int destroy)
939 {
940
941 rt_timer_queue_remove_all(rtq, destroy);
942
943 LIST_REMOVE(rtq, rtq_link);
944
945 /*
946 * Caller is responsible for freeing the rttimer_queue structure.
947 */
948 }
949
950 unsigned long
951 rt_timer_count(struct rttimer_queue *rtq)
952 {
953 return rtq->rtq_count;
954 }
955
956 void
957 rt_timer_remove_all(struct rtentry *rt, int destroy)
958 {
959 struct rttimer *r;
960
961 while ((r = LIST_FIRST(&rt->rt_timer)) != NULL) {
962 LIST_REMOVE(r, rtt_link);
963 TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
964 if (destroy)
965 RTTIMER_CALLOUT(r);
966 if (r->rtt_queue->rtq_count > 0)
967 r->rtt_queue->rtq_count--;
968 else
969 printf("rt_timer_remove_all: rtq_count reached 0\n");
970 /* we are already at splsoftnet */
971 pool_put(&rttimer_pool, r);
972 }
973 }
974
975 int
976 rt_timer_add(struct rtentry *rt,
977 void (*func)(struct rtentry *, struct rttimer *),
978 struct rttimer_queue *queue)
979 {
980 struct rttimer *r;
981 int s;
982
983 /*
984 * If there's already a timer with this action, destroy it before
985 * we add a new one.
986 */
987 for (r = LIST_FIRST(&rt->rt_timer); r != NULL;
988 r = LIST_NEXT(r, rtt_link)) {
989 if (r->rtt_func == func) {
990 LIST_REMOVE(r, rtt_link);
991 TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
992 if (r->rtt_queue->rtq_count > 0)
993 r->rtt_queue->rtq_count--;
994 else
995 printf("rt_timer_add: rtq_count reached 0\n");
996 s = splsoftnet();
997 pool_put(&rttimer_pool, r);
998 splx(s);
999 break; /* only one per list, so we can quit... */
1000 }
1001 }
1002
1003 s = splsoftnet();
1004 r = pool_get(&rttimer_pool, PR_NOWAIT);
1005 splx(s);
1006 if (r == NULL)
1007 return (ENOBUFS);
1008 Bzero(r, sizeof(*r));
1009
1010 r->rtt_rt = rt;
1011 r->rtt_time = time_uptime;
1012 r->rtt_func = func;
1013 r->rtt_queue = queue;
1014 LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link);
1015 TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next);
1016 r->rtt_queue->rtq_count++;
1017
1018 return (0);
1019 }
1020
1021 /* ARGSUSED */
1022 void
1023 rt_timer_timer(void *arg)
1024 {
1025 struct rttimer_queue *rtq;
1026 struct rttimer *r;
1027 int s;
1028
1029 s = splsoftnet();
1030 for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL;
1031 rtq = LIST_NEXT(rtq, rtq_link)) {
1032 while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL &&
1033 (r->rtt_time + rtq->rtq_timeout) < time_uptime) {
1034 LIST_REMOVE(r, rtt_link);
1035 TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next);
1036 RTTIMER_CALLOUT(r);
1037 pool_put(&rttimer_pool, r);
1038 if (rtq->rtq_count > 0)
1039 rtq->rtq_count--;
1040 else
1041 printf("rt_timer_timer: rtq_count reached 0\n");
1042 }
1043 }
1044 splx(s);
1045
1046 callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL);
1047 }
1048