]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/route.c
xnu-201.tar.gz
[apple/xnu.git] / bsd / net / route.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * Copyright (c) 1980, 1986, 1991, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)route.c 8.2 (Berkeley) 11/15/93
55 */
56
57#if NOTFB31
58#include "opt_inet.h"
59#include "opt_mrouting.h"
60#endif
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/malloc.h>
65#include <sys/mbuf.h>
66#include <sys/socket.h>
67#include <sys/domain.h>
68
69#include <net/if.h>
70#include <net/route.h>
71
72#include <netinet/in.h>
73#include <netinet/ip_mroute.h>
74
75#define SA(p) ((struct sockaddr *)(p))
76
77struct route_cb route_cb;
78static struct rtstat rtstat;
79struct radix_node_head *rt_tables[AF_MAX+1];
80
81static int rttrash; /* routes not in table but not freed */
82
83static void rt_maskedcopy __P((struct sockaddr *,
84 struct sockaddr *, struct sockaddr *));
85static void rtable_init __P((void **));
86
87static void
88rtable_init(table)
89 void **table;
90{
91 struct domain *dom;
92 for (dom = domains; dom; dom = dom->dom_next)
93 if (dom->dom_rtattach)
94 dom->dom_rtattach(&table[dom->dom_family],
95 dom->dom_rtoffset);
96}
97
98void
99route_init()
100{
101 rn_init(); /* initialize all zeroes, all ones, mask table */
102 rtable_init((void **)rt_tables);
103}
104
105/*
106 * Packet routing routines.
107 */
108void
109rtalloc(ro)
110 register struct route *ro;
111{
112 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
113 return; /* XXX */
114 ro->ro_rt = rtalloc1(&ro->ro_dst, 1, 0UL);
115}
116
117void
118rtalloc_ign(ro, ignore)
119 register struct route *ro;
120 u_long ignore;
121{
122 if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
123 return; /* XXX */
124 ro->ro_rt = rtalloc1(&ro->ro_dst, 1, ignore);
125}
126
127/*
128 * Look up the route that matches the address given
129 * Or, at least try.. Create a cloned route if needed.
130 */
131struct rtentry *
132rtalloc1(dst, report, ignflags)
133 register struct sockaddr *dst;
134 int report;
135 u_long ignflags;
136{
137 register struct radix_node_head *rnh = rt_tables[dst->sa_family];
138 register struct rtentry *rt;
139 register struct radix_node *rn;
140 struct rtentry *newrt = 0;
141 struct rt_addrinfo info;
142 u_long nflags;
143 int s = splnet(), err = 0, msgtype = RTM_MISS;
144
145 /*
146 * Look up the address in the table for that Address Family
147 */
148 if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
149 ((rn->rn_flags & RNF_ROOT) == 0)) {
150 /*
151 * If we find it and it's not the root node, then
152 * get a refernce on the rtentry associated.
153 */
154 newrt = rt = (struct rtentry *)rn;
155 nflags = rt->rt_flags & ~ignflags;
156 if (report && (nflags & (RTF_CLONING | RTF_PRCLONING))) {
157 /*
158 * We are apparently adding (report = 0 in delete).
159 * If it requires that it be cloned, do so.
160 * (This implies it wasn't a HOST route.)
161 */
162 err = rtrequest(RTM_RESOLVE, dst, SA(0),
163 SA(0), 0, &newrt);
164 if (err) {
165 /*
166 * If the cloning didn't succeed, maybe
167 * what we have will do. Return that.
168 */
169 newrt = rt;
170 rt->rt_refcnt++;
171 goto miss;
172 }
173 if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
174 /*
175 * If the new route specifies it be
176 * externally resolved, then go do that.
177 */
178 msgtype = RTM_RESOLVE;
179 goto miss;
180 }
181 } else
182 rt->rt_refcnt++;
183 } else {
184 /*
185 * Either we hit the root or couldn't find any match,
186 * Which basically means
187 * "caint get there frm here"
188 */
189 rtstat.rts_unreach++;
190 miss: if (report) {
191 /*
192 * If required, report the failure to the supervising
193 * Authorities.
194 * For a delete, this is not an error. (report == 0)
195 */
196 bzero((caddr_t)&info, sizeof(info));
197 info.rti_info[RTAX_DST] = dst;
198 rt_missmsg(msgtype, &info, 0, err);
199 }
200 }
201 splx(s);
202 return (newrt);
203}
204
205/*
206 * Remove a reference count from an rtentry.
207 * If the count gets low enough, take it out of the routing table
208 */
209void
210rtfree(rt)
211 register struct rtentry *rt;
212{
213 /*
214 * find the tree for that address family
215 */
216 register struct radix_node_head *rnh =
217 rt_tables[rt_key(rt)->sa_family];
218 register struct ifaddr *ifa;
219
220 if (rt == 0 || rnh == 0)
221 panic("rtfree");
222
223 /*
224 * decrement the reference count by one and if it reaches 0,
225 * and there is a close function defined, call the close function
226 */
227 rt->rt_refcnt--;
228 if(rnh->rnh_close && rt->rt_refcnt == 0) {
229 rnh->rnh_close((struct radix_node *)rt, rnh);
230 }
231
232 /*
233 * If we are no longer "up" (and ref == 0)
234 * then we can free the resources associated
235 * with the route.
236 */
237 if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
238 if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
239 panic ("rtfree 2");
240 /*
241 * the rtentry must have been removed from the routing table
242 * so it is represented in rttrash.. remove that now.
243 */
244 rttrash--;
245
246#ifdef DIAGNOSTIC
247 if (rt->rt_refcnt < 0) {
248 printf("rtfree: %p not freed (neg refs)\n", rt);
249 return;
250 }
251#endif
252
253 /*
254 * release references on items we hold them on..
255 * e.g other routes and ifaddrs.
256 */
257 if((ifa = rt->rt_ifa))
258 IFAFREE(ifa);
259 if (rt->rt_parent) {
260 RTFREE(rt->rt_parent);
261 }
262
263 /*
264 * The key is separatly alloc'd so free it (see rt_setgate()).
265 * This also frees the gateway, as they are always malloc'd
266 * together.
267 */
268 Free(rt_key(rt));
269
270 /*
271 * and the rtentry itself of course
272 */
273 Free(rt);
274 }
275}
276
277void
278ifafree(ifa)
279 register struct ifaddr *ifa;
280{
281 if (ifa == NULL)
282 panic("ifafree");
283 if (ifa->ifa_refcnt == 0)
284 FREE(ifa, M_IFADDR);
285 else
286 ifa->ifa_refcnt--;
287}
288
289/*
290 * Force a routing table entry to the specified
291 * destination to go through the given gateway.
292 * Normally called as a result of a routing redirect
293 * message from the network layer.
294 *
295 * N.B.: must be called at splnet
296 *
297 */
298void
299rtredirect(dst, gateway, netmask, flags, src, rtp)
300 struct sockaddr *dst, *gateway, *netmask, *src;
301 int flags;
302 struct rtentry **rtp;
303{
304 register struct rtentry *rt;
305 int error = 0;
306 short *stat = 0;
307 struct rt_addrinfo info;
308 struct ifaddr *ifa;
309
310 /* verify the gateway is directly reachable */
311 if ((ifa = ifa_ifwithnet(gateway)) == 0) {
312 error = ENETUNREACH;
313 goto out;
314 }
315 rt = rtalloc1(dst, 0, 0UL);
316 /*
317 * If the redirect isn't from our current router for this dst,
318 * it's either old or wrong. If it redirects us to ourselves,
319 * we have a routing loop, perhaps as a result of an interface
320 * going down recently.
321 */
322#define equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
323 if (!(flags & RTF_DONE) && rt &&
324 (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
325 error = EINVAL;
326 else if (ifa_ifwithaddr(gateway))
327 error = EHOSTUNREACH;
328 if (error)
329 goto done;
330 /*
331 * Create a new entry if we just got back a wildcard entry
332 * or the the lookup failed. This is necessary for hosts
333 * which use routing redirects generated by smart gateways
334 * to dynamically build the routing tables.
335 */
336 if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
337 goto create;
338 /*
339 * Don't listen to the redirect if it's
340 * for a route to an interface.
341 */
342 if (rt->rt_flags & RTF_GATEWAY) {
343 if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
344 /*
345 * Changing from route to net => route to host.
346 * Create new route, rather than smashing route to net.
347 */
348 create:
349 flags |= RTF_GATEWAY | RTF_DYNAMIC;
350 error = rtrequest((int)RTM_ADD, dst, gateway,
351 netmask, flags,
352 (struct rtentry **)0);
353 stat = &rtstat.rts_dynamic;
354 } else {
355 /*
356 * Smash the current notion of the gateway to
357 * this destination. Should check about netmask!!!
358 */
359 rt->rt_flags |= RTF_MODIFIED;
360 flags |= RTF_MODIFIED;
361 stat = &rtstat.rts_newgateway;
362 /*
363 * add the key and gateway (in one malloc'd chunk).
364 */
365 rt_setgate(rt, rt_key(rt), gateway);
366 }
367 } else
368 error = EHOSTUNREACH;
369done:
370 if (rt) {
371 if (rtp && !error)
372 *rtp = rt;
373 else
374 rtfree(rt);
375 }
376out:
377 if (error)
378 rtstat.rts_badredirect++;
379 else if (stat != NULL)
380 (*stat)++;
381 bzero((caddr_t)&info, sizeof(info));
382 info.rti_info[RTAX_DST] = dst;
383 info.rti_info[RTAX_GATEWAY] = gateway;
384 info.rti_info[RTAX_NETMASK] = netmask;
385 info.rti_info[RTAX_AUTHOR] = src;
386 rt_missmsg(RTM_REDIRECT, &info, flags, error);
387}
388
389/*
390* Routing table ioctl interface.
391*/
392int
393rtioctl(req, data, p)
394 int req;
395 caddr_t data;
396 struct proc *p;
397{
398#if INET
399 /* Multicast goop, grrr... */
400#if MROUTING
401 return mrt_ioctl(req, data);
402#else
403 return mrt_ioctl(req, data, p);
404#endif
405#else /* INET */
406 return ENXIO;
407#endif /* INET */
408}
409
410struct ifaddr *
411ifa_ifwithroute(flags, dst, gateway)
412 int flags;
413 struct sockaddr *dst, *gateway;
414{
415 register struct ifaddr *ifa;
416 if ((flags & RTF_GATEWAY) == 0) {
417 /*
418 * If we are adding a route to an interface,
419 * and the interface is a pt to pt link
420 * we should search for the destination
421 * as our clue to the interface. Otherwise
422 * we can use the local address.
423 */
424 ifa = 0;
425 if (flags & RTF_HOST) {
426 ifa = ifa_ifwithdstaddr(dst);
427 }
428 if (ifa == 0)
429 ifa = ifa_ifwithaddr(gateway);
430 } else {
431 /*
432 * If we are adding a route to a remote net
433 * or host, the gateway may still be on the
434 * other end of a pt to pt link.
435 */
436 ifa = ifa_ifwithdstaddr(gateway);
437 }
438 if (ifa == 0)
439 ifa = ifa_ifwithnet(gateway);
440 if (ifa == 0) {
441 struct rtentry *rt = rtalloc1(dst, 0, 0UL);
442 if (rt == 0)
443 return (0);
444 rt->rt_refcnt--;
445 if ((ifa = rt->rt_ifa) == 0)
446 return (0);
447 }
448 if (ifa->ifa_addr->sa_family != dst->sa_family) {
449 struct ifaddr *oifa = ifa;
450 ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
451 if (ifa == 0)
452 ifa = oifa;
453 }
454 return (ifa);
455}
456
457#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
458
459static int rt_fixdelete __P((struct radix_node *, void *));
460static int rt_fixchange __P((struct radix_node *, void *));
461
462struct rtfc_arg {
463 struct rtentry *rt0;
464 struct radix_node_head *rnh;
465};
466
467/*
468 * Do appropriate manipulations of a routing tree given
469 * all the bits of info needed
470 */
471int
472rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
473 int req, flags;
474 struct sockaddr *dst, *gateway, *netmask;
475 struct rtentry **ret_nrt;
476{
477 int s = splnet(); int error = 0;
478 register struct rtentry *rt;
479 register struct radix_node *rn;
480 register struct radix_node_head *rnh;
481 struct ifaddr *ifa;
482 struct sockaddr *ndst;
483#define senderr(x) { error = x ; goto bad; }
484
485 /*
486 * Find the correct routing tree to use for this Address Family
487 */
488 if ((rnh = rt_tables[dst->sa_family]) == 0)
489 senderr(ESRCH);
490 /*
491 * If we are adding a host route then we don't want to put
492 * a netmask in the tree
493 */
494 if (flags & RTF_HOST)
495 netmask = 0;
496 switch (req) {
497 case RTM_DELETE:
498 /*
499 * Remove the item from the tree and return it.
500 * Complain if it is not there and do no more processing.
501 */
502 if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
503 senderr(ESRCH);
504 if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
505 panic ("rtrequest delete");
506 rt = (struct rtentry *)rn;
507
508 /*
509 * Now search what's left of the subtree for any cloned
510 * routes which might have been formed from this node.
511 */
512 if ((rt->rt_flags & RTF_PRCLONING) && netmask) {
513 rnh->rnh_walktree_from(rnh, dst, netmask,
514 rt_fixdelete, rt);
515 }
516
517 /*
518 * Remove any external references we may have.
519 * This might result in another rtentry being freed if
520 * we held its last reference.
521 */
522 if (rt->rt_gwroute) {
523 rt = rt->rt_gwroute;
524 RTFREE(rt);
525 (rt = (struct rtentry *)rn)->rt_gwroute = 0;
526 }
527
528 /*
529 * NB: RTF_UP must be set during the search above,
530 * because we might delete the last ref, causing
531 * rt to get freed prematurely.
532 * eh? then why not just add a reference?
533 * I'm not sure how RTF_UP helps matters. (JRE)
534 */
535 rt->rt_flags &= ~RTF_UP;
536
537 /*
538 * give the protocol a chance to keep things in sync.
539 */
540 if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
541 ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
542
543 /*
544 * one more rtentry floating around that is not
545 * linked to the routing table.
546 */
547 rttrash++;
548
549 /*
550 * If the caller wants it, then it can have it,
551 * but it's up to it to free the rtentry as we won't be
552 * doing it.
553 */
554 if (ret_nrt)
555 *ret_nrt = rt;
556 else if (rt->rt_refcnt <= 0) {
557 rt->rt_refcnt++;
558 rtfree(rt);
559 }
560 break;
561
562 case RTM_RESOLVE:
563 if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
564 senderr(EINVAL);
565 ifa = rt->rt_ifa;
566 flags = rt->rt_flags &
567 ~(RTF_CLONING | RTF_PRCLONING | RTF_STATIC);
568 flags |= RTF_WASCLONED;
569 gateway = rt->rt_gateway;
570 if ((netmask = rt->rt_genmask) == 0)
571 flags |= RTF_HOST;
572 goto makeroute;
573
574 case RTM_ADD:
575 if ((flags & RTF_GATEWAY) && !gateway)
576 panic("rtrequest: GATEWAY but no gateway");
577
578 if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
579 senderr(ENETUNREACH);
580
581 makeroute:
582 R_Malloc(rt, struct rtentry *, sizeof(*rt));
583 if (rt == 0)
584 senderr(ENOBUFS);
585 Bzero(rt, sizeof(*rt));
586 rt->rt_flags = RTF_UP | flags;
587 /*
588 * Add the gateway. Possibly re-malloc-ing the storage for it
589 * also add the rt_gwroute if possible.
590 */
591 if (error = rt_setgate(rt, dst, gateway)) {
592 Free(rt);
593 senderr(error);
594 }
595
596 /*
597 * point to the (possibly newly malloc'd) dest address.
598 */
599 ndst = rt_key(rt);
600
601 /*
602 * make sure it contains the value we want (masked if needed).
603 */
604 if (netmask) {
605 rt_maskedcopy(dst, ndst, netmask);
606 } else
607 Bcopy(dst, ndst, dst->sa_len);
608
609 /*
610 * Note that we now have a reference to the ifa.
611 * This moved from below so that rnh->rnh_addaddr() can
612 * examine the ifa and ifa->ifa_ifp if it so desires.
613 */
614 ifa->ifa_refcnt++;
615 rt->rt_ifa = ifa;
616 rt->rt_ifp = ifa->ifa_ifp;
617 rt->rt_dlt = ifa->ifa_dlt;
618 rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
619 rnh, rt->rt_nodes);
620 if (rn == 0) {
621 struct rtentry *rt2;
622 /*
623 * Uh-oh, we already have one of these in the tree.
624 * We do a special hack: if the route that's already
625 * there was generated by the protocol-cloning
626 * mechanism, then we just blow it away and retry
627 * the insertion of the new one.
628 */
629 rt2 = rtalloc1(dst, 0, RTF_PRCLONING);
630 if (rt2 && rt2->rt_parent) {
631 rtrequest(RTM_DELETE,
632 (struct sockaddr *)rt_key(rt2),
633 rt2->rt_gateway,
634 rt_mask(rt2), rt2->rt_flags, 0);
635 RTFREE(rt2);
636 rn = rnh->rnh_addaddr((caddr_t)ndst,
637 (caddr_t)netmask,
638 rnh, rt->rt_nodes);
639 } else if (rt2) {
640 /* undo the extra ref we got */
641 RTFREE(rt2);
642 }
643 }
644
645 /*
646 * If it still failed to go into the tree,
647 * then un-make it (this should be a function)
648 */
649 if (rn == 0) {
650 if (rt->rt_gwroute)
651 rtfree(rt->rt_gwroute);
652 if (rt->rt_ifa) {
653 IFAFREE(rt->rt_ifa);
654 }
655 Free(rt_key(rt));
656 Free(rt);
657 senderr(EEXIST);
658 }
659
660 rt->rt_parent = 0;
661
662 /*
663 * If we got here from RESOLVE, then we are cloning
664 * so clone the rest, and note that we
665 * are a clone (and increment the parent's references)
666 */
667 if (req == RTM_RESOLVE) {
668 rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
669 if ((*ret_nrt)->rt_flags & RTF_PRCLONING) {
670 rt->rt_parent = (*ret_nrt);
671 (*ret_nrt)->rt_refcnt++;
672 }
673 }
674
675 /*
676 * if this protocol has something to add to this then
677 * allow it to do that as well.
678 */
679 if (ifa->ifa_rtrequest)
680 ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
681
682 /*
683 * We repeat the same procedure from rt_setgate() here because
684 * it doesn't fire when we call it there because the node
685 * hasn't been added to the tree yet.
686 */
687 if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {
688 struct rtfc_arg arg;
689 arg.rnh = rnh;
690 arg.rt0 = rt;
691 rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),
692 rt_fixchange, &arg);
693 }
694
695 /*
696 * actually return a resultant rtentry and
697 * give the caller a single reference.
698 */
699 if (ret_nrt) {
700 *ret_nrt = rt;
701 rt->rt_refcnt++;
702 }
703 break;
704 }
705bad:
706 splx(s);
707 return (error);
708}
709
710/*
711 * Called from rtrequest(RTM_DELETE, ...) to fix up the route's ``family''
712 * (i.e., the routes related to it by the operation of cloning). This
713 * routine is iterated over all potential former-child-routes by way of
714 * rnh->rnh_walktree_from() above, and those that actually are children of
715 * the late parent (passed in as VP here) are themselves deleted.
716 */
717static int
718rt_fixdelete(rn, vp)
719 struct radix_node *rn;
720 void *vp;
721{
722 struct rtentry *rt = (struct rtentry *)rn;
723 struct rtentry *rt0 = vp;
724
725 if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) {
726 return rtrequest(RTM_DELETE, rt_key(rt),
727 (struct sockaddr *)0, rt_mask(rt),
728 rt->rt_flags, (struct rtentry **)0);
729 }
730 return 0;
731}
732
733/*
734 * This routine is called from rt_setgate() to do the analogous thing for
735 * adds and changes. There is the added complication in this case of a
736 * middle insert; i.e., insertion of a new network route between an older
737 * network route and (cloned) host routes. For this reason, a simple check
738 * of rt->rt_parent is insufficient; each candidate route must be tested
739 * against the (mask, value) of the new route (passed as before in vp)
740 * to see if the new route matches it. Unfortunately, this has the obnoxious
741 * property of also triggering for insertion /above/ a pre-existing network
742 * route and clones. Sigh. This may be fixed some day.
743 *
744 * XXX - it may be possible to do fixdelete() for changes and reserve this
745 * routine just for adds. I'm not sure why I thought it was necessary to do
746 * changes this way.
747 */
748#ifdef DEBUG
749static int rtfcdebug = 0;
750#endif
751
752static int
753rt_fixchange(rn, vp)
754 struct radix_node *rn;
755 void *vp;
756{
757 struct rtentry *rt = (struct rtentry *)rn;
758 struct rtfc_arg *ap = vp;
759 struct rtentry *rt0 = ap->rt0;
760 struct radix_node_head *rnh = ap->rnh;
761 u_char *xk1, *xm1, *xk2;
762 int i, len;
763
764#ifdef DEBUG
765 if (rtfcdebug)
766 printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0);
767#endif
768
769 if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) {
770#ifdef DEBUG
771 if(rtfcdebug) printf("no parent or pinned\n");
772#endif
773 return 0;
774 }
775
776 if (rt->rt_parent == rt0) {
777#ifdef DEBUG
778 if(rtfcdebug) printf("parent match\n");
779#endif
780 return rtrequest(RTM_DELETE, rt_key(rt),
781 (struct sockaddr *)0, rt_mask(rt),
782 rt->rt_flags, (struct rtentry **)0);
783 }
784
785 /*
786 * There probably is a function somewhere which does this...
787 * if not, there should be.
788 */
789 len = imin(((struct sockaddr *)rt_key(rt0))->sa_len,
790 ((struct sockaddr *)rt_key(rt))->sa_len);
791
792 xk1 = (u_char *)rt_key(rt0);
793 xm1 = (u_char *)rt_mask(rt0);
794 xk2 = (u_char *)rt_key(rt);
795
796 for (i = rnh->rnh_treetop->rn_off; i < len; i++) {
797 if ((xk2[i] & xm1[i]) != xk1[i]) {
798#ifdef DEBUG
799 if(rtfcdebug) printf("no match\n");
800#endif
801 return 0;
802 }
803 }
804
805 /*
806 * OK, this node is a clone, and matches the node currently being
807 * changed/added under the node's mask. So, get rid of it.
808 */
809#ifdef DEBUG
810 if(rtfcdebug) printf("deleting\n");
811#endif
812 return rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,
813 rt_mask(rt), rt->rt_flags, (struct rtentry **)0);
814}
815
816int
817rt_setgate(rt0, dst, gate)
818 struct rtentry *rt0;
819 struct sockaddr *dst, *gate;
820{
821 caddr_t new, old;
822 int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
823 register struct rtentry *rt = rt0;
824 struct radix_node_head *rnh = rt_tables[dst->sa_family];
825
826 /*
827 * A host route with the destination equal to the gateway
828 * will interfere with keeping LLINFO in the routing
829 * table, so disallow it.
830 */
831 if (((rt0->rt_flags & (RTF_HOST|RTF_GATEWAY|RTF_LLINFO)) ==
832 (RTF_HOST|RTF_GATEWAY)) &&
833 (dst->sa_len == gate->sa_len) &&
834 (bcmp(dst, gate, dst->sa_len) == 0)) {
835 /*
836 * The route might already exist if this is an RTM_CHANGE
837 * or a routing redirect, so try to delete it.
838 */
839 if (rt_key(rt0))
840 rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt0),
841 rt0->rt_gateway, rt_mask(rt0), rt0->rt_flags, 0);
842 return EADDRNOTAVAIL;
843 }
844
845 /*
846 * Both dst and gateway are stored in the same malloc'd chunk
847 * (If I ever get my hands on....)
848 * if we need to malloc a new chunk, then keep the old one around
849 * till we don't need it any more.
850 */
851 if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
852 old = (caddr_t)rt_key(rt);
853 R_Malloc(new, caddr_t, dlen + glen);
854 if (new == 0)
855 return ENOBUFS;
856 rt->rt_nodes->rn_key = new;
857 } else {
858 /*
859 * otherwise just overwrite the old one
860 */
861 new = rt->rt_nodes->rn_key;
862 old = 0;
863 }
864
865 /*
866 * copy the new gateway value into the memory chunk
867 */
868 Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
869
870 /*
871 * if we are replacing the chunk (or it's new) we need to
872 * replace the dst as well
873 */
874 if (old) {
875 Bcopy(dst, new, dlen);
876 Free(old);
877 }
878
879 /*
880 * If there is already a gwroute, it's now almost definitly wrong
881 * so drop it.
882 */
883 if (rt->rt_gwroute) {
884 rt = rt->rt_gwroute; RTFREE(rt);
885 rt = rt0; rt->rt_gwroute = 0;
886 }
887 /*
888 * Cloning loop avoidance:
889 * In the presence of protocol-cloning and bad configuration,
890 * it is possible to get stuck in bottomless mutual recursion
891 * (rtrequest rt_setgate rtalloc1). We avoid this by not allowing
892 * protocol-cloning to operate for gateways (which is probably the
893 * correct choice anyway), and avoid the resulting reference loops
894 * by disallowing any route to run through itself as a gateway.
895 * This is obviously mandatory when we get rt->rt_output().
896 */
897 if (rt->rt_flags & RTF_GATEWAY) {
898 rt->rt_gwroute = rtalloc1(gate, 1, RTF_PRCLONING);
899 if (rt->rt_gwroute == rt) {
900 RTFREE(rt->rt_gwroute);
901 rt->rt_gwroute = 0;
902 return EDQUOT; /* failure */
903 }
904 }
905
906 /*
907 * This isn't going to do anything useful for host routes, so
908 * don't bother. Also make sure we have a reasonable mask
909 * (we don't yet have one during adds).
910 */
911 if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {
912 struct rtfc_arg arg;
913 arg.rnh = rnh;
914 arg.rt0 = rt;
915 rnh->rnh_walktree_from(rnh, rt_key(rt), rt_mask(rt),
916 rt_fixchange, &arg);
917 }
918
919 return 0;
920}
921
922static void
923rt_maskedcopy(src, dst, netmask)
924 struct sockaddr *src, *dst, *netmask;
925{
926 register u_char *cp1 = (u_char *)src;
927 register u_char *cp2 = (u_char *)dst;
928 register u_char *cp3 = (u_char *)netmask;
929 u_char *cplim = cp2 + *cp3;
930 u_char *cplim2 = cp2 + *cp1;
931
932 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
933 cp3 += 2;
934 if (cplim > cplim2)
935 cplim = cplim2;
936 while (cp2 < cplim)
937 *cp2++ = *cp1++ & *cp3++;
938 if (cp2 < cplim2)
939 bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
940}
941
942/*
943 * Set up a routing table entry, normally
944 * for an interface.
945 */
946int
947rtinit(ifa, cmd, flags)
948 register struct ifaddr *ifa;
949 int cmd, flags;
950{
951 register struct rtentry *rt;
952 register struct sockaddr *dst;
953 register struct sockaddr *deldst;
954 struct mbuf *m = 0;
955 struct rtentry *nrt = 0;
956 int error;
957
958 dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
959 /*
960 * If it's a delete, check that if it exists, it's on the correct
961 * interface or we might scrub a route to another ifa which would
962 * be confusing at best and possibly worse.
963 */
964 if (cmd == RTM_DELETE) {
965 /*
966 * It's a delete, so it should already exist..
967 * If it's a net, mask off the host bits
968 * (Assuming we have a mask)
969 */
970 if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
971 m = m_get(M_WAIT, MT_SONAME);
972 deldst = mtod(m, struct sockaddr *);
973 rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
974 dst = deldst;
975 }
976 /*
977 * Get an rtentry that is in the routing tree and
978 * contains the correct info. (if this fails, can't get there).
979 * We set "report" to FALSE so that if it doesn't exist,
980 * it doesn't report an error or clone a route, etc. etc.
981 */
982 rt = rtalloc1(dst, 0, 0UL);
983 if (rt) {
984 /*
985 * Ok so we found the rtentry. it has an extra reference
986 * for us at this stage. we won't need that so
987 * lop that off now.
988 */
989 rt->rt_refcnt--;
990 if (rt->rt_ifa != ifa) {
991 /*
992 * If the interface in the rtentry doesn't match
993 * the interface we are using, then we don't
994 * want to delete it, so return an error.
995 * This seems to be the only point of
996 * this whole RTM_DELETE clause.
997 */
998 if (m)
999 (void) m_free(m);
1000 return (flags & RTF_HOST ? EHOSTUNREACH
1001 : ENETUNREACH);
1002 }
1003 }
1004 /* XXX */
1005#if 0
1006 else {
1007 /*
1008 * One would think that as we are deleting, and we know
1009 * it doesn't exist, we could just return at this point
1010 * with an "ELSE" clause, but apparently not..
1011 */
1012 return (flags & RTF_HOST ? EHOSTUNREACH
1013 : ENETUNREACH);
1014 }
1015#endif
1016 }
1017 /*
1018 * Do the actual request
1019 */
1020 error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
1021 flags | ifa->ifa_flags, &nrt);
1022 if (m)
1023 (void) m_free(m);
1024 /*
1025 * If we are deleting, and we found an entry, then
1026 * it's been removed from the tree.. now throw it away.
1027 */
1028 if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
1029 /*
1030 * notify any listenning routing agents of the change
1031 */
1032 rt_newaddrmsg(cmd, ifa, error, nrt);
1033 if (rt->rt_refcnt <= 0) {
1034 rt->rt_refcnt++;
1035 rtfree(rt);
1036 }
1037 }
1038
1039 /*
1040 * We are adding, and we have a returned routing entry.
1041 * We need to sanity check the result.
1042 */
1043 if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
1044 /*
1045 * We just wanted to add it.. we don't actually need a reference
1046 */
1047 rt->rt_refcnt--;
1048 /*
1049 * If it came back with an unexpected interface, then it must
1050 * have already existed or something. (XXX)
1051 */
1052 if (rt->rt_ifa != ifa) {
1053 printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
1054 rt->rt_ifa);
1055 /*
1056 * Ask that the protocol in question
1057 * remove anything it has associated with
1058 * this route and ifaddr.
1059 */
1060 if (rt->rt_ifa->ifa_rtrequest)
1061 rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
1062 /*
1063 * Remove the referenve to the it's ifaddr.
1064 */
1065 IFAFREE(rt->rt_ifa);
1066 /*
1067 * And substitute in references to the ifaddr
1068 * we are adding.
1069 */
1070 rt->rt_ifa = ifa;
1071 rt->rt_ifp = ifa->ifa_ifp;
1072 rt->rt_dlt = ifa->ifa_dlt;
1073 rt->rt_rmx.rmx_mtu = ifa->ifa_ifp->if_mtu;
1074 ifa->ifa_refcnt++;
1075 /*
1076 * Now ask the protocol to check if it needs
1077 * any special processing in its new form.
1078 */
1079 if (ifa->ifa_rtrequest)
1080 ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
1081 }
1082 /*
1083 * notify any listenning routing agents of the change
1084 */
1085 rt_newaddrmsg(cmd, ifa, error, nrt);
1086 }
1087 return (error);
1088}