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