Home | History | Annotate | Line # | Download | only in net
route.c revision 1.19
      1 /*	$NetBSD: route.c,v 1.19 1998/07/05 06:49:17 jonathan Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Kevin M. Lahey of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the NetBSD
     22  *	Foundation, Inc. and its contributors.
     23  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24  *    contributors may be used to endorse or promote products derived
     25  *    from this software without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37  * POSSIBILITY OF SUCH DAMAGE.
     38  */
     39 
     40 /*
     41  * Copyright (c) 1980, 1986, 1991, 1993
     42  *	The Regents of the University of California.  All rights reserved.
     43  *
     44  * Redistribution and use in source and binary forms, with or without
     45  * modification, are permitted provided that the following conditions
     46  * are met:
     47  * 1. Redistributions of source code must retain the above copyright
     48  *    notice, this list of conditions and the following disclaimer.
     49  * 2. Redistributions in binary form must reproduce the above copyright
     50  *    notice, this list of conditions and the following disclaimer in the
     51  *    documentation and/or other materials provided with the distribution.
     52  * 3. All advertising materials mentioning features or use of this software
     53  *    must display the following acknowledgement:
     54  *	This product includes software developed by the University of
     55  *	California, Berkeley and its contributors.
     56  * 4. Neither the name of the University nor the names of its contributors
     57  *    may be used to endorse or promote products derived from this software
     58  *    without specific prior written permission.
     59  *
     60  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     61  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     62  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     63  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     64  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     65  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     66  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     67  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     68  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     69  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     70  * SUCH DAMAGE.
     71  *
     72  *	@(#)route.c	8.3 (Berkeley) 1/9/95
     73  */
     74 
     75 #include "opt_ns.h"
     76 
     77 #include <sys/param.h>
     78 #include <sys/systm.h>
     79 #include <sys/proc.h>
     80 #include <sys/mbuf.h>
     81 #include <sys/socket.h>
     82 #include <sys/socketvar.h>
     83 #include <sys/domain.h>
     84 #include <sys/protosw.h>
     85 #include <sys/kernel.h>
     86 #include <sys/ioctl.h>
     87 
     88 #include <net/if.h>
     89 #include <net/route.h>
     90 #include <net/raw_cb.h>
     91 
     92 #include <netinet/in.h>
     93 #include <netinet/in_var.h>
     94 
     95 #ifdef NS
     96 #include <netns/ns.h>
     97 #endif
     98 
     99 #define	SA(p) ((struct sockaddr *)(p))
    100 
    101 int	rttrash;		/* routes not in table but not freed */
    102 struct	sockaddr wildcard;	/* zero valued cookie for wildcard searches */
    103 
    104 void
    105 rtable_init(table)
    106 	void **table;
    107 {
    108 	struct domain *dom;
    109 	for (dom = domains; dom; dom = dom->dom_next)
    110 		if (dom->dom_rtattach)
    111 			dom->dom_rtattach(&table[dom->dom_family],
    112 			    dom->dom_rtoffset);
    113 }
    114 
    115 void
    116 route_init()
    117 {
    118 	rn_init();	/* initialize all zeroes, all ones, mask table */
    119 	rtable_init((void **)rt_tables);
    120 }
    121 
    122 /*
    123  * Packet routing routines.
    124  */
    125 void
    126 rtalloc(ro)
    127 	register struct route *ro;
    128 {
    129 	if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP))
    130 		return;				 /* XXX */
    131 	ro->ro_rt = rtalloc1(&ro->ro_dst, 1);
    132 }
    133 
    134 struct rtentry *
    135 rtalloc1(dst, report)
    136 	register struct sockaddr *dst;
    137 	int report;
    138 {
    139 	register struct radix_node_head *rnh = rt_tables[dst->sa_family];
    140 	register struct rtentry *rt;
    141 	register struct radix_node *rn;
    142 	struct rtentry *newrt = 0;
    143 	struct rt_addrinfo info;
    144 	int  s = splsoftnet(), err = 0, msgtype = RTM_MISS;
    145 
    146 	if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) &&
    147 	    ((rn->rn_flags & RNF_ROOT) == 0)) {
    148 		newrt = rt = (struct rtentry *)rn;
    149 		if (report && (rt->rt_flags & RTF_CLONING)) {
    150 			err = rtrequest(RTM_RESOLVE, dst, SA(0),
    151 					      SA(0), 0, &newrt);
    152 			if (err) {
    153 				newrt = rt;
    154 				rt->rt_refcnt++;
    155 				goto miss;
    156 			}
    157 			if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) {
    158 				msgtype = RTM_RESOLVE;
    159 				goto miss;
    160 			}
    161 		} else
    162 			rt->rt_refcnt++;
    163 	} else {
    164 		rtstat.rts_unreach++;
    165 	miss:	if (report) {
    166 			bzero((caddr_t)&info, sizeof(info));
    167 			info.rti_info[RTAX_DST] = dst;
    168 			rt_missmsg(msgtype, &info, 0, err);
    169 		}
    170 	}
    171 	splx(s);
    172 	return (newrt);
    173 }
    174 
    175 void
    176 rtfree(rt)
    177 	register struct rtentry *rt;
    178 {
    179 	register struct ifaddr *ifa;
    180 
    181 	if (rt == 0)
    182 		panic("rtfree");
    183 	rt->rt_refcnt--;
    184 	if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) {
    185 		if (rt->rt_nodes->rn_flags & (RNF_ACTIVE | RNF_ROOT))
    186 			panic ("rtfree 2");
    187 		rttrash--;
    188 		if (rt->rt_refcnt < 0) {
    189 			printf("rtfree: %p not freed (neg refs)\n", rt);
    190 			return;
    191 		}
    192 		rt_timer_remove_all(rt);
    193 		ifa = rt->rt_ifa;
    194 		IFAFREE(ifa);
    195 		Free(rt_key(rt));
    196 		Free(rt);
    197 	}
    198 }
    199 
    200 void
    201 ifafree(ifa)
    202 	register struct ifaddr *ifa;
    203 {
    204 	if (ifa == NULL)
    205 		panic("ifafree");
    206 	if (ifa->ifa_refcnt == 0)
    207 		free(ifa, M_IFADDR);
    208 	else
    209 		ifa->ifa_refcnt--;
    210 }
    211 
    212 /*
    213  * Force a routing table entry to the specified
    214  * destination to go through the given gateway.
    215  * Normally called as a result of a routing redirect
    216  * message from the network layer.
    217  *
    218  * N.B.: must be called at splsoftnet
    219  *
    220  */
    221 void
    222 rtredirect(dst, gateway, netmask, flags, src, rtp)
    223 	struct sockaddr *dst, *gateway, *netmask, *src;
    224 	int flags;
    225 	struct rtentry **rtp;
    226 {
    227 	register struct rtentry *rt;
    228 	int error = 0;
    229 	short *stat = 0;
    230 	struct rt_addrinfo info;
    231 	struct ifaddr *ifa;
    232 
    233 	/* verify the gateway is directly reachable */
    234 	if ((ifa = ifa_ifwithnet(gateway)) == 0) {
    235 		error = ENETUNREACH;
    236 		goto out;
    237 	}
    238 	rt = rtalloc1(dst, 0);
    239 	/*
    240 	 * If the redirect isn't from our current router for this dst,
    241 	 * it's either old or wrong.  If it redirects us to ourselves,
    242 	 * we have a routing loop, perhaps as a result of an interface
    243 	 * going down recently.
    244 	 */
    245 #define	equal(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), (a1)->sa_len) == 0)
    246 	if (!(flags & RTF_DONE) && rt &&
    247 	     (!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa))
    248 		error = EINVAL;
    249 	else if (ifa_ifwithaddr(gateway))
    250 		error = EHOSTUNREACH;
    251 	if (error)
    252 		goto done;
    253 	/*
    254 	 * Create a new entry if we just got back a wildcard entry
    255 	 * or the the lookup failed.  This is necessary for hosts
    256 	 * which use routing redirects generated by smart gateways
    257 	 * to dynamically build the routing tables.
    258 	 */
    259 	if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
    260 		goto create;
    261 	/*
    262 	 * Don't listen to the redirect if it's
    263 	 * for a route to an interface.
    264 	 */
    265 	if (rt->rt_flags & RTF_GATEWAY) {
    266 		if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
    267 			/*
    268 			 * Changing from route to net => route to host.
    269 			 * Create new route, rather than smashing route to net.
    270 			 */
    271 		create:
    272 			flags |=  RTF_GATEWAY | RTF_DYNAMIC;
    273 			error = rtrequest((int)RTM_ADD, dst, gateway,
    274 				    netmask, flags,
    275 				    (struct rtentry **)0);
    276 			stat = &rtstat.rts_dynamic;
    277 		} else {
    278 			/*
    279 			 * Smash the current notion of the gateway to
    280 			 * this destination.  Should check about netmask!!!
    281 			 */
    282 			rt->rt_flags |= RTF_MODIFIED;
    283 			flags |= RTF_MODIFIED;
    284 			stat = &rtstat.rts_newgateway;
    285 			rt_setgate(rt, rt_key(rt), gateway);
    286 		}
    287 	} else
    288 		error = EHOSTUNREACH;
    289 done:
    290 	if (rt) {
    291 		if (rtp && !error)
    292 			*rtp = rt;
    293 		else
    294 			rtfree(rt);
    295 	}
    296 out:
    297 	if (error)
    298 		rtstat.rts_badredirect++;
    299 	else if (stat != NULL)
    300 		(*stat)++;
    301 	bzero((caddr_t)&info, sizeof(info));
    302 	info.rti_info[RTAX_DST] = dst;
    303 	info.rti_info[RTAX_GATEWAY] = gateway;
    304 	info.rti_info[RTAX_NETMASK] = netmask;
    305 	info.rti_info[RTAX_AUTHOR] = src;
    306 	rt_missmsg(RTM_REDIRECT, &info, flags, error);
    307 }
    308 
    309 /*
    310 * Routing table ioctl interface.
    311 */
    312 int
    313 rtioctl(req, data, p)
    314 	u_long req;
    315 	caddr_t data;
    316 	struct proc *p;
    317 {
    318 	return (EOPNOTSUPP);
    319 }
    320 
    321 struct ifaddr *
    322 ifa_ifwithroute(flags, dst, gateway)
    323 	int flags;
    324 	struct sockaddr	*dst, *gateway;
    325 {
    326 	register struct ifaddr *ifa;
    327 	if ((flags & RTF_GATEWAY) == 0) {
    328 		/*
    329 		 * If we are adding a route to an interface,
    330 		 * and the interface is a pt to pt link
    331 		 * we should search for the destination
    332 		 * as our clue to the interface.  Otherwise
    333 		 * we can use the local address.
    334 		 */
    335 		ifa = 0;
    336 		if (flags & RTF_HOST)
    337 			ifa = ifa_ifwithdstaddr(dst);
    338 		if (ifa == 0)
    339 			ifa = ifa_ifwithaddr(gateway);
    340 	} else {
    341 		/*
    342 		 * If we are adding a route to a remote net
    343 		 * or host, the gateway may still be on the
    344 		 * other end of a pt to pt link.
    345 		 */
    346 		ifa = ifa_ifwithdstaddr(gateway);
    347 	}
    348 	if (ifa == 0)
    349 		ifa = ifa_ifwithnet(gateway);
    350 	if (ifa == 0) {
    351 		struct rtentry *rt = rtalloc1(dst, 0);
    352 		if (rt == 0)
    353 			return (0);
    354 		rt->rt_refcnt--;
    355 		if ((ifa = rt->rt_ifa) == 0)
    356 			return (0);
    357 	}
    358 	if (ifa->ifa_addr->sa_family != dst->sa_family) {
    359 		struct ifaddr *oifa = ifa;
    360 		ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
    361 		if (ifa == 0)
    362 			ifa = oifa;
    363 	}
    364 	return (ifa);
    365 }
    366 
    367 #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
    368 
    369 int
    370 rtrequest(req, dst, gateway, netmask, flags, ret_nrt)
    371 	int req, flags;
    372 	struct sockaddr *dst, *gateway, *netmask;
    373 	struct rtentry **ret_nrt;
    374 {
    375 	int s = splsoftnet(); int error = 0;
    376 	register struct rtentry *rt;
    377 	register struct radix_node *rn;
    378 	register struct radix_node_head *rnh;
    379 	struct ifaddr *ifa;
    380 	struct sockaddr *ndst;
    381 #define senderr(x) { error = x ; goto bad; }
    382 
    383 	if ((rnh = rt_tables[dst->sa_family]) == 0)
    384 		senderr(ESRCH);
    385 	if (flags & RTF_HOST)
    386 		netmask = 0;
    387 	switch (req) {
    388 	case RTM_DELETE:
    389 		if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0)
    390 			senderr(ESRCH);
    391 		if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT))
    392 			panic ("rtrequest delete");
    393 		rt = (struct rtentry *)rn;
    394 		rt->rt_flags &= ~RTF_UP;
    395 		if (rt->rt_gwroute) {
    396 			rt = rt->rt_gwroute; RTFREE(rt);
    397 			(rt = (struct rtentry *)rn)->rt_gwroute = 0;
    398 		}
    399 		if ((ifa = rt->rt_ifa) && ifa->ifa_rtrequest)
    400 			ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
    401 		rttrash++;
    402 		if (ret_nrt)
    403 			*ret_nrt = rt;
    404 		else if (rt->rt_refcnt <= 0) {
    405 			rt->rt_refcnt++;
    406 			rtfree(rt);
    407 		}
    408 		break;
    409 
    410 	case RTM_RESOLVE:
    411 		if (ret_nrt == 0 || (rt = *ret_nrt) == 0)
    412 			senderr(EINVAL);
    413 		ifa = rt->rt_ifa;
    414 		flags = rt->rt_flags & ~RTF_CLONING;
    415 		gateway = rt->rt_gateway;
    416 		if ((netmask = rt->rt_genmask) == 0)
    417 			flags |= RTF_HOST;
    418 		goto makeroute;
    419 
    420 	case RTM_ADD:
    421 		if ((ifa = ifa_ifwithroute(flags, dst, gateway)) == 0)
    422 			senderr(ENETUNREACH);
    423 	makeroute:
    424 		R_Malloc(rt, struct rtentry *, sizeof(*rt));
    425 		if (rt == 0)
    426 			senderr(ENOBUFS);
    427 		Bzero(rt, sizeof(*rt));
    428 		rt->rt_flags = RTF_UP | flags;
    429 		LIST_INIT(&rt->rt_timer);
    430 		if (rt_setgate(rt, dst, gateway)) {
    431 			Free(rt);
    432 			senderr(ENOBUFS);
    433 		}
    434 		ndst = rt_key(rt);
    435 		if (netmask) {
    436 			rt_maskedcopy(dst, ndst, netmask);
    437 		} else
    438 			Bcopy(dst, ndst, dst->sa_len);
    439 		rn = rnh->rnh_addaddr((caddr_t)ndst, (caddr_t)netmask,
    440 					rnh, rt->rt_nodes);
    441 		if (rn == 0) {
    442 			if (rt->rt_gwroute)
    443 				rtfree(rt->rt_gwroute);
    444 			Free(rt_key(rt));
    445 			Free(rt);
    446 			senderr(EEXIST);
    447 		}
    448 		ifa->ifa_refcnt++;
    449 		rt->rt_ifa = ifa;
    450 		rt->rt_ifp = ifa->ifa_ifp;
    451 		if (req == RTM_RESOLVE)
    452 			rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */
    453 		if (ifa->ifa_rtrequest)
    454 			ifa->ifa_rtrequest(req, rt, SA(ret_nrt ? *ret_nrt : 0));
    455 		if (ret_nrt) {
    456 			*ret_nrt = rt;
    457 			rt->rt_refcnt++;
    458 		}
    459 		break;
    460 	}
    461 bad:
    462 	splx(s);
    463 	return (error);
    464 }
    465 
    466 int
    467 rt_setgate(rt0, dst, gate)
    468 	struct rtentry *rt0;
    469 	struct sockaddr *dst, *gate;
    470 {
    471 	caddr_t new, old;
    472 	int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len);
    473 	register struct rtentry *rt = rt0;
    474 
    475 	if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) {
    476 		old = (caddr_t)rt_key(rt);
    477 		R_Malloc(new, caddr_t, dlen + glen);
    478 		if (new == 0)
    479 			return 1;
    480 		rt->rt_nodes->rn_key = new;
    481 	} else {
    482 		new = rt->rt_nodes->rn_key;
    483 		old = 0;
    484 	}
    485 	Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen);
    486 	if (old) {
    487 		Bcopy(dst, new, dlen);
    488 		Free(old);
    489 	}
    490 	if (rt->rt_gwroute) {
    491 		rt = rt->rt_gwroute; RTFREE(rt);
    492 		rt = rt0; rt->rt_gwroute = 0;
    493 	}
    494 	if (rt->rt_flags & RTF_GATEWAY) {
    495 		rt->rt_gwroute = rtalloc1(gate, 1);
    496 	}
    497 	return 0;
    498 }
    499 
    500 void
    501 rt_maskedcopy(src, dst, netmask)
    502 	struct sockaddr *src, *dst, *netmask;
    503 {
    504 	register u_char *cp1 = (u_char *)src;
    505 	register u_char *cp2 = (u_char *)dst;
    506 	register u_char *cp3 = (u_char *)netmask;
    507 	u_char *cplim = cp2 + *cp3;
    508 	u_char *cplim2 = cp2 + *cp1;
    509 
    510 	*cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */
    511 	cp3 += 2;
    512 	if (cplim > cplim2)
    513 		cplim = cplim2;
    514 	while (cp2 < cplim)
    515 		*cp2++ = *cp1++ & *cp3++;
    516 	if (cp2 < cplim2)
    517 		bzero((caddr_t)cp2, (unsigned)(cplim2 - cp2));
    518 }
    519 
    520 /*
    521  * Set up a routing table entry, normally
    522  * for an interface.
    523  */
    524 int
    525 rtinit(ifa, cmd, flags)
    526 	register struct ifaddr *ifa;
    527 	int cmd, flags;
    528 {
    529 	register struct rtentry *rt;
    530 	register struct sockaddr *dst;
    531 	register struct sockaddr *deldst;
    532 	struct mbuf *m = 0;
    533 	struct rtentry *nrt = 0;
    534 	int error;
    535 
    536 	dst = flags & RTF_HOST ? ifa->ifa_dstaddr : ifa->ifa_addr;
    537 	if (cmd == RTM_DELETE) {
    538 		if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) {
    539 			m = m_get(M_WAIT, MT_SONAME);
    540 			deldst = mtod(m, struct sockaddr *);
    541 			rt_maskedcopy(dst, deldst, ifa->ifa_netmask);
    542 			dst = deldst;
    543 		}
    544 		if ((rt = rtalloc1(dst, 0)) != NULL) {
    545 			rt->rt_refcnt--;
    546 			if (rt->rt_ifa != ifa) {
    547 				if (m)
    548 					(void) m_free(m);
    549 				return (flags & RTF_HOST ? EHOSTUNREACH
    550 							: ENETUNREACH);
    551 			}
    552 		}
    553 	}
    554 	error = rtrequest(cmd, dst, ifa->ifa_addr, ifa->ifa_netmask,
    555 			flags | ifa->ifa_flags, &nrt);
    556 	if (m)
    557 		(void) m_free(m);
    558 	if (cmd == RTM_DELETE && error == 0 && (rt = nrt)) {
    559 		rt_newaddrmsg(cmd, ifa, error, nrt);
    560 		if (rt->rt_refcnt <= 0) {
    561 			rt->rt_refcnt++;
    562 			rtfree(rt);
    563 		}
    564 	}
    565 	if (cmd == RTM_ADD && error == 0 && (rt = nrt)) {
    566 		rt->rt_refcnt--;
    567 		if (rt->rt_ifa != ifa) {
    568 			printf("rtinit: wrong ifa (%p) was (%p)\n", ifa,
    569 				rt->rt_ifa);
    570 			if (rt->rt_ifa->ifa_rtrequest)
    571 			    rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, SA(0));
    572 			IFAFREE(rt->rt_ifa);
    573 			rt->rt_ifa = ifa;
    574 			rt->rt_ifp = ifa->ifa_ifp;
    575 			ifa->ifa_refcnt++;
    576 			if (ifa->ifa_rtrequest)
    577 			    ifa->ifa_rtrequest(RTM_ADD, rt, SA(0));
    578 		}
    579 		rt_newaddrmsg(cmd, ifa, error, nrt);
    580 	}
    581 	return (error);
    582 }
    583 
    584 /*
    585  * Route timer routines.  These routes allow functions to be called
    586  * for various routes at any time.  This is useful in supporting
    587  * path MTU discovery and redirect route deletion.
    588  *
    589  * This is similar to some BSDI internal functions, but it provides
    590  * for multiple queues for efficiency's sake...
    591  */
    592 
    593 LIST_HEAD(, rttimer_queue) rttimer_queue_head;
    594 static int rt_init_done = 0;
    595 
    596 #define RTTIMER_CALLOUT(r)	{				\
    597 	if (r->rtt_func != NULL) {				\
    598 		r->rtt_func(r->rtt_rt, r);			\
    599 	} else {						\
    600 		rtrequest((int) RTM_DELETE,			\
    601 			  (struct sockaddr *)rt_key(r->rtt_rt),	\
    602 			  0, 0, 0, 0);				\
    603 	}							\
    604 }
    605 
    606 /*
    607  * Some subtle order problems with domain initialization mean that
    608  * we cannot count on this being run from rt_init before various
    609  * protocol initializations are done.  Therefore, we make sure
    610  * that this is run when the first queue is added...
    611  */
    612 
    613 void
    614 rt_timer_init()
    615 {
    616 	assert(rt_init_done == 0);
    617 
    618 	LIST_INIT(&rttimer_queue_head);
    619 	timeout(rt_timer_timer, NULL, hz);  /* every second */
    620 	rt_init_done = 1;
    621 }
    622 
    623 
    624 struct rttimer_queue *
    625 rt_timer_queue_create(timeout)
    626 	u_int	timeout;
    627 {
    628 	struct rttimer_queue *rtq;
    629 
    630 	if (rt_init_done == 0)
    631 		rt_timer_init();
    632 
    633 	R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq);
    634 	if (rtq == NULL)
    635 		return NULL;
    636 
    637 	rtq->rtq_timeout = timeout;
    638 	CIRCLEQ_INIT(&rtq->rtq_head);
    639 	LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link);
    640 
    641 	return rtq;
    642 }
    643 
    644 
    645 void
    646 rt_timer_queue_change(rtq, timeout)
    647 	struct rttimer_queue *rtq;
    648 	long timeout;
    649 {
    650 	rtq->rtq_timeout = timeout;
    651 }
    652 
    653 
    654 void
    655 rt_timer_queue_destroy(rtq, destroy)
    656 	struct rttimer_queue *rtq;
    657 	int destroy;
    658 {
    659 	struct rttimer *r, *r0;
    660 
    661 	r = CIRCLEQ_FIRST(&rtq->rtq_head);
    662 	while (r != (struct rttimer *) &rtq->rtq_head) {
    663 		r0 = CIRCLEQ_NEXT(r, rtt_next);
    664 		CIRCLEQ_REMOVE(&rtq->rtq_head, r, rtt_next);
    665 		LIST_REMOVE(r, rtt_link);
    666 		if (destroy != 0)
    667 			RTTIMER_CALLOUT(r);
    668 		Free(r);
    669 		r = r0;
    670 	}
    671 
    672 	LIST_REMOVE(rtq, rtq_link);
    673 }
    674 
    675 
    676 void
    677 rt_timer_remove_all(rt)
    678 	struct rtentry *rt;
    679 {
    680 	struct rttimer *r, *r0;
    681 
    682 	r = LIST_FIRST(&rt->rt_timer);
    683 	while (r) {
    684 		r0 = LIST_NEXT(r, rtt_link);
    685 		LIST_REMOVE(r, rtt_link);
    686 		CIRCLEQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
    687 		Free(r);
    688 		r = r0;
    689 	}
    690 }
    691 
    692 
    693 int
    694 rt_timer_add(rt, func, queue)
    695 	struct rtentry *rt;
    696 	void(*func) __P((struct rtentry *, struct rttimer *));
    697 	struct rttimer_queue *queue;
    698 {
    699 	struct rttimer *r, *rttimer;
    700 	int s;
    701 	long current_time;
    702 
    703 	s = splclock();
    704 	current_time = mono_time.tv_sec;
    705 	splx(s);
    706 
    707 	for (r = LIST_FIRST(&rt->rt_timer); r; r = LIST_NEXT(r, rtt_link)) {
    708 		if (r->rtt_func == func) {
    709 			LIST_REMOVE(r, rtt_link);
    710 			CIRCLEQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next);
    711 			Free(r);
    712 			break;  /* only one per list, so we can quit... */
    713 		}
    714 	}
    715 
    716 	R_Malloc(rttimer, struct rttimer *, sizeof *rttimer);
    717 	if (rttimer == NULL)
    718 		return ENOBUFS;
    719 
    720 	rttimer->rtt_rt = rt;
    721 	rttimer->rtt_time = current_time;
    722 	rttimer->rtt_func = func;
    723 	rttimer->rtt_queue = queue;
    724 	LIST_INSERT_HEAD(&rt->rt_timer, rttimer, rtt_link);
    725 
    726 	r = CIRCLEQ_LAST(&queue->rtq_head);
    727 	while (r && r != (struct rttimer *) &queue->rtq_head &&
    728 	       r->rtt_time > current_time)
    729 		r = CIRCLEQ_PREV(r, rtt_next);
    730 
    731 	if (r)
    732 		CIRCLEQ_INSERT_AFTER(&queue->rtq_head, r, rttimer, rtt_next);
    733 	else
    734 		CIRCLEQ_INSERT_HEAD(&queue->rtq_head, rttimer, rtt_next);
    735 
    736 	return 0;
    737 }
    738 
    739 /* ARGSUSED */
    740 void
    741 rt_timer_timer(arg)
    742 	void *arg;
    743 {
    744 	struct rttimer *r, *rttimer;
    745 	struct rttimer_queue	*rtq;
    746 	long current_time;
    747 	int s;
    748 
    749 	s = splclock();
    750 	current_time = mono_time.tv_sec;
    751 	splx(s);
    752 
    753 	for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL;
    754 	     rtq = LIST_NEXT(rtq, rtq_link)) {
    755 		rttimer = CIRCLEQ_FIRST(&rtq->rtq_head);
    756 		while (rttimer != (struct rttimer *) &rtq->rtq_head &&
    757 		       (rttimer->rtt_time + rtq->rtq_timeout) < current_time) {
    758 			r = CIRCLEQ_NEXT(rttimer, rtt_next);
    759 			CIRCLEQ_REMOVE(&rtq->rtq_head, rttimer, rtt_next);
    760 			LIST_REMOVE(rttimer, rtt_link);
    761 			RTTIMER_CALLOUT(rttimer);
    762 			Free(rttimer);
    763 			rttimer = r;
    764 		}
    765 	}
    766 
    767 	timeout(rt_timer_timer, NULL, hz);  /* every second */
    768 }
    769