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