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