xref: /freebsd/sys/netinet6/nd6_rtr.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/malloc.h>
35 #include <sys/mbuf.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/time.h>
39 #include <sys/kernel.h>
40 #include <sys/errno.h>
41 #include <sys/syslog.h>
42 
43 #include <net/if.h>
44 #include <net/if_types.h>
45 #include <net/if_dl.h>
46 #include <net/route.h>
47 #include <net/radix.h>
48 
49 #include <netinet/in.h>
50 #include <netinet6/in6_var.h>
51 #include <netinet6/ip6.h>
52 #include <netinet6/ip6_var.h>
53 #include <netinet6/nd6.h>
54 #include <netinet6/icmp6.h>
55 
56 #include <net/net_osdep.h>
57 
58 #define	SDL(s)	((struct sockaddr_dl *)s)
59 
60 static struct	nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
61 static int	prelist_add __P((struct nd_prefix *, struct nd_defrouter *));
62 static struct	nd_prefix *prefix_lookup __P((struct nd_prefix *));
63 static struct	in6_ifaddr *in6_ifadd __P((struct ifnet *, struct in6_addr *,
64 					   struct in6_addr *, int));
65 static struct	nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
66 						 struct nd_defrouter *));
67 static void	pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
68 static void	pfxrtr_del __P((struct nd_pfxrouter *));
69 static void	pfxlist_onlink_check __P((void));
70 static void	nd6_detach_prefix __P((struct nd_prefix *));
71 static void	nd6_attach_prefix __P((struct nd_prefix *));
72 
73 static void	in6_init_address_ltimes __P((struct nd_prefix *ndpr,
74 					     struct in6_addrlifetime *lt6));
75 
76 static int	rt6_deleteroute __P((struct radix_node *, void *));
77 
78 extern int	nd6_recalc_reachtm_interval;
79 
80 /*
81  * Receive Router Solicitation Message - just for routers.
82  * Router solicitation/advertisement is mostly managed by userland program
83  * (rtadvd) so here we have no function like nd6_ra_output().
84  *
85  * Based on RFC 2461
86  */
87 void
88 nd6_rs_input(m, off, icmp6len)
89 	struct	mbuf *m;
90 	int off, icmp6len;
91 {
92 	struct ifnet *ifp = m->m_pkthdr.rcvif;
93 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
94 	struct nd_router_solicit *nd_rs
95 		= (struct nd_router_solicit *)((caddr_t)ip6 + off);
96 	struct in6_addr saddr6 = ip6->ip6_src;
97 	char *lladdr = NULL;
98 	int lladdrlen = 0;
99 	union nd_opts ndopts;
100 
101 	/* If I'm not a router, ignore it. */
102 	if (ip6_accept_rtadv != 0 || ip6_forwarding != 1)
103 		return;
104 
105 	/* Sanity checks */
106 	if (ip6->ip6_hlim != 255) {
107 		log(LOG_ERR,
108 		    "nd6_rs_input: invalid hlim %d\n", ip6->ip6_hlim);
109 		return;
110 	}
111 
112 	/*
113 	 * Don't update the neighbor cache, if src = ::.
114 	 * This indicates that the src has no IP address assigned yet.
115 	 */
116 	if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
117 		return;
118 
119 	icmp6len -= sizeof(*nd_rs);
120 	nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
121 	if (nd6_options(&ndopts) < 0) {
122 		log(LOG_INFO, "nd6_rs_input: invalid ND option, ignored\n");
123 		return;
124 	}
125 
126 	if (ndopts.nd_opts_src_lladdr) {
127 		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
128 		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
129 	}
130 
131 	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
132 		log(LOG_INFO,
133 		    "nd6_rs_input: lladdrlen mismatch for %s "
134 		    "(if %d, RS packet %d)\n",
135 			ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
136 	}
137 
138 	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
139 }
140 
141 /*
142  * Receive Router Advertisement Message.
143  *
144  * Based on RFC 2461
145  * TODO: on-link bit on prefix information
146  * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
147  */
148 void
149 nd6_ra_input(m, off, icmp6len)
150 	struct	mbuf *m;
151 	int off, icmp6len;
152 {
153 	struct ifnet *ifp = m->m_pkthdr.rcvif;
154 	struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
155 	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
156 	struct nd_router_advert *nd_ra =
157 		(struct nd_router_advert *)((caddr_t)ip6 + off);
158 	struct in6_addr saddr6 = ip6->ip6_src;
159 	union nd_opts ndopts;
160 	struct nd_defrouter *dr;
161 
162 	if (ip6_accept_rtadv == 0)
163 		return;
164 
165 	if (ip6->ip6_hlim != 255) {
166 		log(LOG_ERR,
167 		    "nd6_ra_input: invalid hlim %d\n", ip6->ip6_hlim);
168 		return;
169 	}
170 
171 	if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
172 		log(LOG_ERR,
173 		    "nd6_ra_input: src %s is not link-local\n",
174 		    ip6_sprintf(&saddr6));
175 		return;
176 	}
177 
178 	icmp6len -= sizeof(*nd_ra);
179 	nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
180 	if (nd6_options(&ndopts) < 0) {
181 		log(LOG_INFO, "nd6_ra_input: invalid ND option, ignored\n");
182 		return;
183 	}
184 
185     {
186 	struct nd_defrouter dr0;
187 	u_int32_t advreachable = nd_ra->nd_ra_reachable;
188 
189 	dr0.rtaddr = saddr6;
190 	dr0.flags  = nd_ra->nd_ra_flags_reserved;
191 	dr0.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
192 	dr0.expire = time_second + dr0.rtlifetime;
193 	dr0.ifp = ifp;
194 	/* unspecified or not? (RFC 2461 6.3.4) */
195 	if (advreachable) {
196 		NTOHL(advreachable);
197 		if (advreachable <= MAX_REACHABLE_TIME &&
198 		    ndi->basereachable != advreachable) {
199 			ndi->basereachable = advreachable;
200 			ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
201 			ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
202 		}
203 	}
204 	if (nd_ra->nd_ra_retransmit)
205 		ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
206 	if (nd_ra->nd_ra_curhoplimit)
207 		ndi->chlim = nd_ra->nd_ra_curhoplimit;
208 	dr = defrtrlist_update(&dr0);
209     }
210 
211 	/*
212 	 * prefix
213 	 */
214 	if (ndopts.nd_opts_pi) {
215 		struct nd_opt_hdr *pt;
216 		struct nd_opt_prefix_info *pi;
217 		struct nd_prefix pr;
218 
219 		for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
220 		     pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
221 		     pt = (struct nd_opt_hdr *)((caddr_t)pt +
222 						(pt->nd_opt_len << 3))) {
223 			if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
224 				continue;
225 			pi = (struct nd_opt_prefix_info *)pt;
226 
227 			if (pi->nd_opt_pi_len != 4) {
228 				log(LOG_INFO, "nd6_ra_input: invalid option "
229 					"len %d for prefix information option, "
230 					"ignored\n", pi->nd_opt_pi_len);
231 				continue;
232 			}
233 
234 			if (128 < pi->nd_opt_pi_prefix_len) {
235 				log(LOG_INFO, "nd6_ra_input: invalid prefix "
236 					"len %d for prefix information option, "
237 					"ignored\n", pi->nd_opt_pi_prefix_len);
238 				continue;
239 			}
240 
241 			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
242 			 || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
243 				log(LOG_INFO, "nd6_ra_input: invalid prefix "
244 					"%s, ignored\n",
245 					ip6_sprintf(&pi->nd_opt_pi_prefix));
246 				continue;
247 			}
248 
249 			/* aggregatable unicast address, rfc2374 */
250 			if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
251 			 && pi->nd_opt_pi_prefix_len != 64) {
252 				log(LOG_INFO, "nd6_ra_input: invalid prefixlen "
253 					"%d for rfc2374 prefix %s, ignored\n",
254 					pi->nd_opt_pi_prefix_len,
255 					ip6_sprintf(&pi->nd_opt_pi_prefix));
256 				continue;
257 			}
258 
259 			bzero(&pr, sizeof(pr));
260 			pr.ndpr_prefix.sin6_family = AF_INET6;
261 			pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
262 			pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
263 			pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
264 
265 			pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
266 					      ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
267 			pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
268 					    ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
269 			pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
270 			pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
271 			pr.ndpr_pltime =
272 				ntohl(pi->nd_opt_pi_preferred_time);
273 
274 			if (in6_init_prefix_ltimes(&pr))
275 				continue; /* prefix lifetime init failed */
276 
277 			(void)prelist_update(&pr, dr, m);
278 		}
279 	}
280 
281 	/*
282 	 * MTU
283 	 */
284 	if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
285 		u_int32_t mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
286 
287 		/* lower bound */
288 		if (mtu < IPV6_MMTU) {
289 			log(LOG_INFO, "nd6_ra_input: bogus mtu option "
290 			    "mtu=%d sent from %s, ignoring\n",
291 			    mtu, ip6_sprintf(&ip6->ip6_src));
292 			goto skip;
293 		}
294 
295 		/* upper bound */
296 		if (ndi->maxmtu) {
297 			if (mtu <= ndi->maxmtu) {
298 				int change = (ndi->linkmtu != mtu);
299 
300 				ndi->linkmtu = mtu;
301 				if (change) /* in6_maxmtu may change */
302 					in6_setmaxmtu();
303 			} else {
304 				log(LOG_INFO, "nd6_ra_input: bogus mtu "
305 				    "mtu=%d sent from %s; "
306 				    "exceeds maxmtu %d, ignoring\n",
307 				    mtu, ip6_sprintf(&ip6->ip6_src),
308 				    ndi->maxmtu);
309 			}
310 		} else {
311 			log(LOG_INFO, "nd6_ra_input: mtu option "
312 			    "mtu=%d sent from %s; maxmtu unknown, "
313 			    "ignoring\n",
314 			    mtu, ip6_sprintf(&ip6->ip6_src));
315 		}
316 	}
317 
318  skip:
319 
320 	/*
321 	 * Src linkaddress
322 	 */
323     {
324 	char *lladdr = NULL;
325 	int lladdrlen = 0;
326 
327 	if (ndopts.nd_opts_src_lladdr) {
328 		lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
329 		lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
330 	}
331 
332 	if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
333 		log(LOG_INFO,
334 		    "nd6_ra_input: lladdrlen mismatch for %s "
335 		    "(if %d, RA packet %d)\n",
336 			ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2);
337 	}
338 
339 	nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
340     }
341 }
342 
343 /*
344  * default router list proccessing sub routines
345  */
346 void
347 defrouter_addreq(new)
348 	struct nd_defrouter *new;
349 {
350 	struct sockaddr_in6 def, mask, gate;
351 	int s;
352 
353 	Bzero(&def, sizeof(def));
354 	Bzero(&mask, sizeof(mask));
355 	Bzero(&gate, sizeof(gate));
356 
357 	def.sin6_len = mask.sin6_len = gate.sin6_len
358 		= sizeof(struct sockaddr_in6);
359 	def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
360 	gate.sin6_addr = new->rtaddr;
361 
362 	s = splnet();
363 	(void)rtrequest(RTM_ADD, (struct sockaddr *)&def,
364 		(struct sockaddr *)&gate, (struct sockaddr *)&mask,
365 		RTF_GATEWAY, NULL);
366 	splx(s);
367 	return;
368 }
369 
370 struct nd_defrouter *
371 defrouter_lookup(addr, ifp)
372 	struct in6_addr *addr;
373 	struct ifnet *ifp;
374 {
375 	struct nd_defrouter *dr;
376 
377 	LIST_FOREACH(dr, &nd_defrouter, dr_entry)
378 		if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
379 			return(dr);
380 
381 	return(NULL);		/* search failed */
382 }
383 
384 void
385 defrouter_delreq(dr, dofree)
386 	struct nd_defrouter *dr;
387 	int dofree;
388 {
389 	struct sockaddr_in6 def, mask, gate;
390 
391 	Bzero(&def, sizeof(def));
392 	Bzero(&mask, sizeof(mask));
393 	Bzero(&gate, sizeof(gate));
394 
395 	def.sin6_len = mask.sin6_len = gate.sin6_len
396 		= sizeof(struct sockaddr_in6);
397 	def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
398 	gate.sin6_addr = dr->rtaddr;
399 
400 	rtrequest(RTM_DELETE, (struct sockaddr *)&def,
401 		  (struct sockaddr *)&gate,
402 		  (struct sockaddr *)&mask,
403 		  RTF_GATEWAY, (struct rtentry **)0);
404 
405 	if (dofree)
406 		free(dr, M_IP6NDP);
407 
408 	if (!LIST_EMPTY(&nd_defrouter))
409 		defrouter_addreq(LIST_FIRST(&nd_defrouter));
410 
411 	/*
412 	 * xxx update the Destination Cache entries for all
413 	 * destinations using that neighbor as a router (7.2.5)
414 	 */
415 }
416 
417 void
418 defrtrlist_del(dr)
419 	struct nd_defrouter *dr;
420 {
421 	struct nd_defrouter *deldr = NULL;
422 	struct nd_prefix *pr;
423 
424 	/*
425 	 * Flush all the routing table entries that use the router
426 	 * as a next hop.
427 	 */
428 	if (!ip6_forwarding && ip6_accept_rtadv) {
429 		/* above is a good condition? */
430 		rt6_flush(&dr->rtaddr, dr->ifp);
431 	}
432 
433 	if (dr == LIST_FIRST(&nd_defrouter))
434 		deldr = dr;	/* The router is primary. */
435 
436 	LIST_REMOVE(dr, dr_entry);
437 
438 	/*
439 	 * Also delete all the pointers to the router in each prefix lists.
440 	 */
441 	LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
442 		struct nd_pfxrouter *pfxrtr;
443 		if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
444 			pfxrtr_del(pfxrtr);
445 	}
446 	pfxlist_onlink_check();
447 
448 	/*
449 	 * If the router is the primary one, delete the default route
450 	 * entry in the routing table.
451 	 */
452 	if (deldr)
453 		defrouter_delreq(deldr, 0);
454 	free(dr, M_IP6NDP);
455 }
456 
457 static struct nd_defrouter *
458 defrtrlist_update(new)
459 	struct nd_defrouter *new;
460 {
461 	struct nd_defrouter *dr, *n;
462 	int s = splnet();
463 
464 	if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
465 		/* entry exists */
466 		if (new->rtlifetime == 0) {
467 			defrtrlist_del(dr);
468 			dr = NULL;
469 		} else {
470 			/* override */
471 			dr->flags = new->flags; /* xxx flag check */
472 			dr->rtlifetime = new->rtlifetime;
473 			dr->expire = new->expire;
474 		}
475 		splx(s);
476 		return(dr);
477 	}
478 
479 	/* entry does not exist */
480 	if (new->rtlifetime == 0) {
481 		splx(s);
482 		return(NULL);
483 	}
484 
485 	n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
486 	if (n == NULL) {
487 		splx(s);
488 		return(NULL);
489 	}
490 	bzero(n, sizeof(*n));
491 	*n = *new;
492 	if (LIST_EMPTY(&nd_defrouter)) {
493 		LIST_INSERT_HEAD(&nd_defrouter, n, dr_entry);
494 		defrouter_addreq(n);
495 	} else {
496 		LIST_INSERT_AFTER(LIST_FIRST(&nd_defrouter), n, dr_entry);
497 		defrouter_addreq(n);
498 	}
499 	splx(s);
500 
501 	return(n);
502 }
503 
504 static struct nd_pfxrouter *
505 pfxrtr_lookup(pr, dr)
506 	struct nd_prefix *pr;
507 	struct nd_defrouter *dr;
508 {
509 	struct nd_pfxrouter *search;
510 
511 	LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) {
512 		if (search->router == dr)
513 			break;
514 	}
515 
516 	return(search);
517 }
518 
519 static void
520 pfxrtr_add(pr, dr)
521 	struct nd_prefix *pr;
522 	struct nd_defrouter *dr;
523 {
524 	struct nd_pfxrouter *new;
525 
526 	new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
527 	if (new == NULL)
528 		return;
529 	bzero(new, sizeof(*new));
530 	new->router = dr;
531 
532 	LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
533 
534 	pfxlist_onlink_check();
535 }
536 
537 static void
538 pfxrtr_del(pfr)
539 	struct nd_pfxrouter *pfr;
540 {
541 	LIST_REMOVE(pfr, pfr_entry);
542 	free(pfr, M_IP6NDP);
543 }
544 
545 static struct nd_prefix *
546 prefix_lookup(pr)
547 	struct nd_prefix *pr;
548 {
549 	struct nd_prefix *search;
550 
551 	LIST_FOREACH(search, &nd_prefix, ndpr_entry) {
552 		if (pr->ndpr_ifp == search->ndpr_ifp &&
553 		    pr->ndpr_plen == search->ndpr_plen &&
554 		    in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
555 					 &search->ndpr_prefix.sin6_addr,
556 					 pr->ndpr_plen)
557 		    ) {
558 			break;
559 		}
560 	}
561 
562 	return(search);
563 }
564 
565 static int
566 prelist_add(pr, dr)
567 	struct nd_prefix *pr;
568 	struct nd_defrouter *dr;
569 {
570 	struct nd_prefix *new;
571 	int i, s;
572 
573 	new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
574 	if (new == NULL)
575 		return ENOMEM;
576 	bzero(new, sizeof(*new));
577 	*new = *pr;
578 
579 	/* initilization */
580 	new->ndpr_statef_onlink = pr->ndpr_statef_onlink;
581 	LIST_INIT(&new->ndpr_advrtrs);
582 	in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
583 	/* make prefix in the canonical form */
584 	for (i = 0; i < 4; i++)
585 		new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
586 			new->ndpr_mask.s6_addr32[i];
587 
588 	/* xxx ND_OPT_PI_FLAG_ONLINK processing */
589 
590 	s = splnet();
591 	/* link ndpr_entry to nd_prefix list */
592 	LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
593 	splx(s);
594 
595 	if (dr)
596 		pfxrtr_add(new, dr);
597 
598 	return 0;
599 }
600 
601 void
602 prelist_remove(pr)
603 	struct nd_prefix *pr;
604 {
605 	struct nd_pfxrouter *pfr, *next;
606 	int s;
607 
608 	s = splnet();
609 	/* unlink ndpr_entry from nd_prefix list */
610 	LIST_REMOVE(pr, ndpr_entry);
611 	splx(s);
612 
613 	/* free list of routers that adversed the prefix */
614 	for (pfr = LIST_FIRST(&pr->ndpr_advrtrs); pfr; pfr = next) {
615 		next = LIST_NEXT(pfr, pfr_entry);
616 
617 		free(pfr, M_IP6NDP);
618 	}
619 	free(pr, M_IP6NDP);
620 
621 	pfxlist_onlink_check();
622 }
623 
624 /*
625  * NOTE: We set address lifetime to keep
626  *	address lifetime <= prefix lifetime
627  * invariant.  This is to simplify on-link determination code.
628  * If onlink determination is udated, this routine may have to be updated too.
629  */
630 int
631 prelist_update(new, dr, m)
632 	struct nd_prefix *new;
633 	struct nd_defrouter *dr; /* may be NULL */
634 	struct mbuf *m;
635 {
636 	struct in6_ifaddr *ia6 = NULL;
637 	struct nd_prefix *pr;
638 	int s = splnet();
639 	int error = 0;
640 	int auth;
641 	struct in6_addrlifetime *lt6;
642 
643 	auth = 0;
644 	if (m) {
645 		/*
646 		 * Authenticity for NA consists authentication for
647 		 * both IP header and IP datagrams, doesn't it ?
648 		 */
649 #if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
650 		auth = (m->m_flags & M_AUTHIPHDR
651 		     && m->m_flags & M_AUTHIPDGM) ? 1 : 0;
652 #endif
653 	}
654 
655 	if ((pr = prefix_lookup(new)) != NULL) {
656 		if (pr->ndpr_ifp != new->ndpr_ifp) {
657 			error = EADDRNOTAVAIL;
658 			goto end;
659 		}
660 		/* update prefix information */
661 		pr->ndpr_flags = new->ndpr_flags;
662 		pr->ndpr_vltime = new->ndpr_vltime;
663 		pr->ndpr_pltime = new->ndpr_pltime;
664 		pr->ndpr_preferred = new->ndpr_preferred;
665 		pr->ndpr_expire = new->ndpr_expire;
666 
667 		/*
668 		 * RFC 2462 5.5.3 (d) or (e)
669 		 * We got a prefix which we have seen in the past.
670 		 */
671 		if (!new->ndpr_raf_auto)
672 			goto noautoconf1;
673 
674 		if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
675 			ia6 = NULL;
676 		else
677 			ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
678 
679 		if (ia6 == NULL) {
680 			/*
681 			 * Special case:
682 			 * (1) We have seen the prefix advertised before, but
683 			 * we have never performed autoconfig for this prefix.
684 			 * This is because Autonomous bit was 0 previously, or
685 			 * autoconfig failed due to some other reasons.
686 			 * (2) We have seen the prefix advertised before and
687 			 * we have performed autoconfig in the past, but
688 			 * we seem to have no interface address right now.
689 			 * This is because the interface address have expired.
690 			 *
691 			 * This prefix is fresh, with respect to autoconfig
692 			 * process.
693 			 *
694 			 * Add an address based on RFC 2462 5.5.3 (d).
695 			 */
696 			ia6 = in6_ifadd(pr->ndpr_ifp,
697 				&pr->ndpr_prefix.sin6_addr, &pr->ndpr_addr,
698 				new->ndpr_plen);
699 			if (!ia6) {
700 				error = EADDRNOTAVAIL;
701 				log(LOG_ERR, "prelist_update: failed to add a "
702 				    "new address\n");
703 				goto noautoconf1;
704 			}
705 
706 			lt6 = &ia6->ia6_lifetime;
707 
708 			/* address lifetime <= prefix lifetime */
709 			lt6->ia6t_vltime = new->ndpr_vltime;
710 			lt6->ia6t_pltime = new->ndpr_pltime;
711 			in6_init_address_ltimes(new, lt6);
712 		} else {
713 #define	TWOHOUR		(120*60)
714 			/*
715 			 * We have seen the prefix before, and we have added
716 			 * interface address in the past.  We still have
717 			 * the interface address assigned.
718 			 *
719 			 * update address lifetime based on RFC 2462
720 			 * 5.5.3 (e).
721 			 */
722 			int update = 0;
723 
724 			lt6 = &ia6->ia6_lifetime;
725 
726 			/*
727 			 * update to RFC 2462 5.5.3 (e) from Jim Bound,
728 			 * (ipng 6712)
729 			 */
730 			if (TWOHOUR < new->ndpr_vltime
731 			 || lt6->ia6t_vltime < new->ndpr_vltime) {
732 				lt6->ia6t_vltime = new->ndpr_vltime;
733 				update++;
734 			} else if (auth) {
735 				lt6->ia6t_vltime = new->ndpr_vltime;
736 				update++;
737 			}
738 
739 			/* jim bound rule is not imposed for pref lifetime */
740 			lt6->ia6t_pltime = new->ndpr_pltime;
741 
742 			update++;
743 			if (update)
744 				in6_init_address_ltimes(new, lt6);
745 		}
746 
747  noautoconf1:
748 
749 		if (dr && pfxrtr_lookup(pr, dr) == NULL)
750 			pfxrtr_add(pr, dr);
751 	} else {
752 		int error_tmp;
753 
754 		if (new->ndpr_vltime == 0) goto end;
755 
756 		bzero(&new->ndpr_addr, sizeof(struct in6_addr));
757 
758 		/*
759 		 * RFC 2462 5.5.3 (d)
760 		 * We got a fresh prefix.  Perform some sanity checks
761 		 * and add an interface address by appending interface ID
762 		 * to the advertised prefix.
763 		 */
764 		if (!new->ndpr_raf_auto)
765 			goto noautoconf2;
766 
767 		ia6 = in6_ifadd(new->ndpr_ifp, &new->ndpr_prefix.sin6_addr,
768 			  &new->ndpr_addr, new->ndpr_plen);
769 		if (!ia6) {
770 			error = EADDRNOTAVAIL;
771 			log(LOG_ERR, "prelist_update: "
772 				"failed to add a new address\n");
773 			goto noautoconf2;
774 		}
775 		/* set onlink bit if an interface route is configured */
776 		new->ndpr_statef_onlink = (ia6->ia_flags & IFA_ROUTE) ? 1 : 0;
777 
778 		lt6 = &ia6->ia6_lifetime;
779 
780 		/* address lifetime <= prefix lifetime */
781 		lt6->ia6t_vltime = new->ndpr_vltime;
782 		lt6->ia6t_pltime = new->ndpr_pltime;
783 		in6_init_address_ltimes(new, lt6);
784 
785  noautoconf2:
786 		error_tmp = prelist_add(new, dr);
787 		error = error_tmp ? error_tmp : error;
788 	}
789 
790  end:
791 	splx(s);
792 	return error;
793 }
794 
795 /*
796  * Check if each prefix in the prefix list has at least one available router
797  * that advertised the prefix.
798  * If the check fails, the prefix may be off-link because, for example,
799  * we have moved from the network but the lifetime of the prefix has not
800  * been expired yet. So we should not use the prefix if there is another
801  * prefix that has an available router.
802  * But if there is no prefix that has an availble router, we still regards
803  * all the prefixes as on-link. This is because we can't tell if all the
804  * routers are simply dead or if we really moved from the network and there
805  * is no router around us.
806  */
807 static void
808 pfxlist_onlink_check()
809 {
810 	struct nd_prefix *pr;
811 
812 	LIST_FOREACH(pr, &nd_prefix, ndpr_entry)
813 		if (!LIST_EMPTY(&pr->ndpr_advrtrs)) /* pr has an available router */
814 			break;
815 
816 	if (pr) {
817 		/*
818 		 * There is at least one prefix that has a router. First,
819 		 * detach prefixes which has no advertising router and then
820 		 * attach other prefixes. The order is important since an
821 		 * attached prefix and a detached prefix may have a same
822 		 * interface route.
823 		 */
824 		LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
825 			if (LIST_EMPTY(&pr->ndpr_advrtrs) &&
826 			    pr->ndpr_statef_onlink) {
827 				pr->ndpr_statef_onlink = 0;
828 				nd6_detach_prefix(pr);
829 			}
830 		}
831 		LIST_FOREACH(pr, &nd_prefix, ndpr_entry) {
832 			if (!LIST_EMPTY(&pr->ndpr_advrtrs) &&
833 				 pr->ndpr_statef_onlink == 0)
834 				nd6_attach_prefix(pr);
835 		}
836 	} else {
837 		/* there is no prefix that has a router */
838 		LIST_FOREACH(pr, &nd_prefix, ndpr_entry)
839 			if (pr->ndpr_statef_onlink == 0)
840 				nd6_attach_prefix(pr);
841 	}
842 }
843 
844 static void
845 nd6_detach_prefix(pr)
846 	struct nd_prefix *pr;
847 {
848 	struct in6_ifaddr *ia6;
849 	struct sockaddr_in6 sa6, mask6;
850 
851 	/*
852 	 * Delete the interface route associated with the prefix.
853 	 */
854 	bzero(&sa6, sizeof(sa6));
855 	sa6.sin6_family = AF_INET6;
856 	sa6.sin6_len = sizeof(sa6);
857 	bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
858 	      sizeof(struct in6_addr));
859 	bzero(&mask6, sizeof(mask6));
860 	mask6.sin6_family = AF_INET6;
861 	mask6.sin6_len = sizeof(sa6);
862 	bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
863 	{
864 		int e;
865 
866 		e = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
867 			      (struct sockaddr *)&mask6, 0, NULL);
868 		if (e) {
869 			log(LOG_ERR,
870 			    "nd6_detach_prefix: failed to delete route: "
871 			    "%s/%d (errno = %d)\n",
872 			    ip6_sprintf(&sa6.sin6_addr),
873 			    pr->ndpr_plen,
874 			    e);
875 		}
876 	}
877 
878 	/*
879 	 * Mark the address derived from the prefix detached so that
880 	 * it won't be used as a source address for a new connection.
881 	 */
882 	if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
883 		ia6 = NULL;
884 	else
885 		ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
886 	if (ia6)
887 		ia6->ia6_flags |= IN6_IFF_DETACHED;
888 }
889 
890 static void
891 nd6_attach_prefix(pr)
892 	struct nd_prefix *pr;
893 {
894 	struct ifaddr *ifa;
895 	struct in6_ifaddr *ia6;
896 
897 	/*
898 	 * Add the interface route associated with the prefix(if necessary)
899 	 * Should we consider if the L bit is set in pr->ndpr_flags?
900 	 */
901 	ifa = ifaof_ifpforaddr((struct sockaddr *)&pr->ndpr_prefix,
902 			       pr->ndpr_ifp);
903 	if (ifa == NULL) {
904 		log(LOG_ERR,
905 		    "nd6_attach_prefix: failed to find any ifaddr"
906 		    " to add route for a prefix(%s/%d)\n",
907 		    ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen);
908 	} else {
909 		int e;
910 		struct sockaddr_in6 mask6;
911 
912 		bzero(&mask6, sizeof(mask6));
913 		mask6.sin6_family = AF_INET6;
914 		mask6.sin6_len = sizeof(mask6);
915 		mask6.sin6_addr = pr->ndpr_mask;
916 		e = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
917 			      ifa->ifa_addr, (struct sockaddr *)&mask6,
918 			      ifa->ifa_flags, NULL);
919 		if (e == 0)
920 			pr->ndpr_statef_onlink = 1;
921 		else {
922 			log(LOG_ERR,
923 			    "nd6_attach_prefix: failed to add route for"
924 			    " a prefix(%s/%d), errno = %d\n",
925 			    ip6_sprintf(&pr->ndpr_addr), pr->ndpr_plen, e);
926 		}
927 	}
928 
929 	/*
930 	 * Now the address derived from the prefix can be used as a source
931 	 * for a new connection, so clear the detached flag.
932 	 */
933 	if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr))
934 		ia6 = NULL;
935 	else
936 		ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr);
937 	if (ia6) {
938 		ia6->ia6_flags &= ~IN6_IFF_DETACHED;
939 		if (pr->ndpr_statef_onlink)
940 			ia6->ia_flags |= IFA_ROUTE;
941 	}
942 }
943 
944 static struct in6_ifaddr *
945 in6_ifadd(ifp, in6, addr, prefixlen)
946 	struct ifnet *ifp;
947 	struct in6_addr *in6;
948 	struct in6_addr *addr;
949 	int prefixlen;	/* prefix len of the new prefix in "in6" */
950 {
951 	struct ifaddr *ifa;
952 	struct in6_ifaddr *ia, *ib, *oia;
953 	int s, error;
954 	struct in6_addr mask;
955 
956 	in6_len2mask(&mask, prefixlen);
957 
958 	/* find link-local address (will be interface ID) */
959 	ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
960 	if (ifa)
961 		ib = (struct in6_ifaddr *)ifa;
962 	else
963 		return NULL;
964 
965 	/* prefixlen + ifidlen must be equal to 128 */
966 	if (prefixlen != in6_mask2len(&ib->ia_prefixmask.sin6_addr)) {
967 		log(LOG_ERR, "in6_ifadd: wrong prefixlen for %s"
968 			"(prefix=%d ifid=%d)\n", if_name(ifp),
969 			prefixlen,
970 			128 - in6_mask2len(&ib->ia_prefixmask.sin6_addr));
971 		return NULL;
972 	}
973 
974 	/* make ifaddr */
975 	ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_DONTWAIT);
976 	if (ia == NULL) {
977 		printf("ENOBUFS in in6_ifadd %d\n", __LINE__);
978 		return NULL;
979 	}
980 
981 	bzero((caddr_t)ia, sizeof(*ia));
982 	ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
983 	ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
984 	ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
985 	ia->ia_ifp = ifp;
986 
987 	/* link to in6_ifaddr */
988 	if ((oia = in6_ifaddr) != NULL) {
989 		for( ; oia->ia_next; oia = oia->ia_next)
990 			continue;
991 		oia->ia_next = ia;
992 	} else
993 		in6_ifaddr = ia;
994 
995 	/* link to if_addrlist */
996 	if (!TAILQ_EMPTY(&ifp->if_addrlist)) {
997 		TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia,
998 			ifa_list);
999 	}
1000 
1001 	/* new address */
1002 	ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
1003 	ia->ia_addr.sin6_family = AF_INET6;
1004 	/* prefix */
1005 	bcopy(in6, &ia->ia_addr.sin6_addr, sizeof(ia->ia_addr.sin6_addr));
1006 	ia->ia_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
1007 	ia->ia_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
1008 	ia->ia_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
1009 	ia->ia_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
1010 	/* interface ID */
1011 	ia->ia_addr.sin6_addr.s6_addr32[0]
1012 		|= (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
1013 	ia->ia_addr.sin6_addr.s6_addr32[1]
1014 		|= (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
1015 	ia->ia_addr.sin6_addr.s6_addr32[2]
1016 		|= (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
1017 	ia->ia_addr.sin6_addr.s6_addr32[3]
1018 		|= (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
1019 
1020 	/* new prefix */
1021 	ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
1022 	ia->ia_prefixmask.sin6_family = AF_INET6;
1023 	bcopy(&mask, &ia->ia_prefixmask.sin6_addr,
1024 		sizeof(ia->ia_prefixmask.sin6_addr));
1025 
1026 	/* same routine */
1027 	ia->ia_ifa.ifa_rtrequest =
1028 		(ifp->if_type == IFT_PPP) ? nd6_p2p_rtrequest : nd6_rtrequest;
1029 	ia->ia_ifa.ifa_flags |= RTF_CLONING;
1030 	ia->ia_ifa.ifa_metric = ifp->if_metric;
1031 
1032 	/* add interface route */
1033 	if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP|RTF_CLONING))) {
1034 		log(LOG_NOTICE, "in6_ifadd: failed to add an interface route "
1035 		    "for %s/%d on %s, errno = %d\n",
1036 		    ip6_sprintf(&ia->ia_addr.sin6_addr), prefixlen,
1037 		    if_name(ifp), error);
1038 	} else
1039 		ia->ia_flags |= IFA_ROUTE;
1040 
1041 	*addr = ia->ia_addr.sin6_addr;
1042 
1043 	if (ifp->if_flags & IFF_MULTICAST) {
1044 		int error;	/* not used */
1045 		struct in6_addr sol6;
1046 
1047 		/* join solicited node multicast address */
1048 		bzero(&sol6, sizeof(sol6));
1049 		sol6.s6_addr16[0] = htons(0xff02);
1050 		sol6.s6_addr16[1] = htons(ifp->if_index);
1051 		sol6.s6_addr32[1] = 0;
1052 		sol6.s6_addr32[2] = htonl(1);
1053 		sol6.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
1054 		sol6.s6_addr8[12] = 0xff;
1055 		(void)in6_addmulti(&sol6, ifp, &error);
1056 	}
1057 
1058 	ia->ia6_flags |= IN6_IFF_TENTATIVE;
1059 
1060 	/*
1061 	 * To make the interface up. Only AF_INET6 in ia is used...
1062 	 */
1063 	s = splimp();
1064 	if (ifp->if_ioctl && (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) {
1065 		splx(s);
1066 		return NULL;
1067 	}
1068 	splx(s);
1069 
1070 	/* Perform DAD, if needed. */
1071 	nd6_dad_start((struct ifaddr *)ia, NULL);
1072 
1073 	return ia;
1074 }
1075 
1076 int
1077 in6_ifdel(ifp, in6)
1078 	struct ifnet *ifp;
1079 	struct in6_addr *in6;
1080 {
1081 	struct in6_ifaddr *ia = (struct in6_ifaddr *)NULL;
1082 	struct in6_ifaddr *oia = (struct in6_ifaddr *)NULL;
1083 
1084 	if (!ifp)
1085 		return -1;
1086 
1087 	ia = in6ifa_ifpwithaddr(ifp, in6);
1088 	if (!ia)
1089 		return -1;
1090 
1091 	if (ifp->if_flags & IFF_MULTICAST) {
1092 		/*
1093 		 * delete solicited multicast addr for deleting host id
1094 		 */
1095 		struct in6_multi *in6m;
1096 		struct in6_addr llsol;
1097 		bzero(&llsol, sizeof(struct in6_addr));
1098 		llsol.s6_addr16[0] = htons(0xff02);
1099 		llsol.s6_addr16[1] = htons(ifp->if_index);
1100 		llsol.s6_addr32[1] = 0;
1101 		llsol.s6_addr32[2] = htonl(1);
1102 		llsol.s6_addr32[3] =
1103 				ia->ia_addr.sin6_addr.s6_addr32[3];
1104 		llsol.s6_addr8[12] = 0xff;
1105 
1106 		IN6_LOOKUP_MULTI(llsol, ifp, in6m);
1107 		if (in6m)
1108 			in6_delmulti(in6m);
1109 	}
1110 
1111 	if (ia->ia_flags & IFA_ROUTE) {
1112 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
1113 		ia->ia_flags &= ~IFA_ROUTE;
1114 	}
1115 
1116 	TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
1117 
1118 	/* lladdr is never deleted */
1119 	oia = ia;
1120 	if (oia == (ia = in6_ifaddr))
1121 		in6_ifaddr = ia->ia_next;
1122 	else {
1123 		while (ia->ia_next && (ia->ia_next != oia))
1124 			ia = ia->ia_next;
1125 		if (ia->ia_next)
1126 			ia->ia_next = oia->ia_next;
1127 		else
1128 			return -1;
1129 	}
1130 
1131 	IFAFREE((&oia->ia_ifa));
1132 /* xxx
1133 	rtrequest(RTM_DELETE,
1134 		  (struct sockaddr *)&ia->ia_addr,
1135 		  (struct sockaddr *)0
1136 		  (struct sockaddr *)&ia->ia_prefixmask,
1137 		  RTF_UP|RTF_CLONING,
1138 		  (struct rtentry **)0);
1139 */
1140 	return 0;
1141 }
1142 
1143 int
1144 in6_init_prefix_ltimes(struct nd_prefix *ndpr)
1145 {
1146 
1147 	/* check if preferred lifetime > valid lifetime */
1148 	if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
1149 		log(LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
1150 		    "(%d) is greater than valid lifetime(%d)\n",
1151 		    (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime);
1152 		return (EINVAL);
1153 	}
1154 	if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
1155 		ndpr->ndpr_preferred = 0;
1156 	else
1157 		ndpr->ndpr_preferred = time_second + ndpr->ndpr_pltime;
1158 	if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
1159 		ndpr->ndpr_expire = 0;
1160 	else
1161 		ndpr->ndpr_expire = time_second + ndpr->ndpr_vltime;
1162 
1163 	return 0;
1164 }
1165 
1166 static void
1167 in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
1168 {
1169 
1170 	/* init ia6t_expire */
1171 	if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
1172 		lt6->ia6t_expire = 0;
1173 	else {
1174 		lt6->ia6t_expire = time_second;
1175 		lt6->ia6t_expire += lt6->ia6t_vltime;
1176 	}
1177 	/* init ia6t_preferred */
1178 	if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
1179 		lt6->ia6t_preferred = 0;
1180 	else {
1181 		lt6->ia6t_preferred = time_second;
1182 		lt6->ia6t_preferred += lt6->ia6t_pltime;
1183 	}
1184 	/* ensure addr lifetime <= prefix lifetime */
1185 	if (new->ndpr_expire && lt6->ia6t_expire &&
1186 	    new->ndpr_expire < lt6->ia6t_expire)
1187 		lt6->ia6t_expire = new->ndpr_expire;
1188 	if (new->ndpr_preferred && lt6->ia6t_preferred
1189 	    && new->ndpr_preferred < lt6->ia6t_preferred)
1190 		lt6->ia6t_preferred = new->ndpr_preferred;
1191 }
1192 
1193 /*
1194  * Delete all the routing table entries that use the specified gateway.
1195  * XXX: this function causes search through all entries of routing table, so
1196  * it shouldn't be called when acting as a router.
1197  */
1198 void
1199 rt6_flush(gateway, ifp)
1200     struct in6_addr *gateway;
1201     struct ifnet *ifp;
1202 {
1203 	struct radix_node_head *rnh = rt_tables[AF_INET6];
1204 	int s = splnet();
1205 
1206 	/* We'll care only link-local addresses */
1207 	if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
1208 		splx(s);
1209 		return;
1210 	}
1211 	/* XXX: hack for KAME's link-local address kludge */
1212 	gateway->s6_addr16[1] = htons(ifp->if_index);
1213 
1214 	rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
1215 	splx(s);
1216 }
1217 
1218 static int
1219 rt6_deleteroute(rn, arg)
1220 	struct radix_node *rn;
1221 	void *arg;
1222 {
1223 #define SIN6(s)	((struct sockaddr_in6 *)s)
1224 	struct rtentry *rt = (struct rtentry *)rn;
1225 	struct in6_addr *gate = (struct in6_addr *)arg;
1226 
1227 	if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
1228 		return(0);
1229 
1230 	if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr))
1231 		return(0);
1232 
1233 	/*
1234 	 * We delete only host route. This means, in particular, we don't
1235 	 * delete default route.
1236 	 */
1237 	if ((rt->rt_flags & RTF_HOST) == 0)
1238 		return(0);
1239 
1240 	return(rtrequest(RTM_DELETE, rt_key(rt),
1241 			 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0));
1242 #undef SIN6
1243 }
1244