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