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