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