|
|
1.1 root 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:
77: struct route_cb route_cb;
78: static struct rtstat rtstat;
79: struct radix_node_head *rt_tables[AF_MAX+1];
80:
81: static int rttrash; /* routes not in table but not freed */
82:
83: static void rt_maskedcopy __P((struct sockaddr *,
84: struct sockaddr *, struct sockaddr *));
85: static void rtable_init __P((void **));
86:
87: static void
88: rtable_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:
98: void
99: route_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: */
108: void
109: rtalloc(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:
117: void
118: rtalloc_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: */
131: struct rtentry *
132: rtalloc1(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: */
209: void
210: rtfree(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:
277: void
278: ifafree(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: */
298: void
299: rtredirect(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;
369: done:
370: if (rt) {
371: if (rtp && !error)
372: *rtp = rt;
373: else
374: rtfree(rt);
375: }
376: out:
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: */
392: int
393: rtioctl(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:
410: struct ifaddr *
411: ifa_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:
459: static int rt_fixdelete __P((struct radix_node *, void *));
460: static int rt_fixchange __P((struct radix_node *, void *));
461:
462: struct 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: */
471: int
472: rtrequest(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: }
705: bad:
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: */
717: static int
718: rt_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
749: static int rtfcdebug = 0;
750: #endif
751:
752: static int
753: rt_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:
816: int
817: rt_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:
922: static void
923: rt_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: */
946: int
947: rtinit(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: ifa->ifa_refcnt++;
1074: /*
1075: * Now ask the protocol to check if it needs
1076: * any special processing in its new form.
1077: */
1078: if (ifa->ifa_rtrequest)
1079: ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
1080: }
1081: /*
1082: * notify any listenning routing agents of the change
1083: */
1084: rt_newaddrmsg(cmd, ifa, error, nrt);
1085: }
1086: return (error);
1087: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.