1*8a7bb304Sitojun /* $OpenBSD: nd6.c,v 1.31 2001/03/21 21:57:10 itojun Exp $ */ 2*8a7bb304Sitojun /* $KAME: nd6.c,v 1.137 2001/03/21 21:52:06 jinmei Exp $ */ 3287546eaSitojun 4287546eaSitojun /* 5287546eaSitojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6287546eaSitojun * All rights reserved. 7287546eaSitojun * 8287546eaSitojun * Redistribution and use in source and binary forms, with or without 9287546eaSitojun * modification, are permitted provided that the following conditions 10287546eaSitojun * are met: 11287546eaSitojun * 1. Redistributions of source code must retain the above copyright 12287546eaSitojun * notice, this list of conditions and the following disclaimer. 13287546eaSitojun * 2. Redistributions in binary form must reproduce the above copyright 14287546eaSitojun * notice, this list of conditions and the following disclaimer in the 15287546eaSitojun * documentation and/or other materials provided with the distribution. 16287546eaSitojun * 3. Neither the name of the project nor the names of its contributors 17287546eaSitojun * may be used to endorse or promote products derived from this software 18287546eaSitojun * without specific prior written permission. 19287546eaSitojun * 20287546eaSitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21287546eaSitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22287546eaSitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23287546eaSitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24287546eaSitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25287546eaSitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26287546eaSitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27287546eaSitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28287546eaSitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29287546eaSitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30287546eaSitojun * SUCH DAMAGE. 31287546eaSitojun */ 32287546eaSitojun 33287546eaSitojun /* 34287546eaSitojun * XXX 35287546eaSitojun * KAME 970409 note: 36287546eaSitojun * BSD/OS version heavily modifies this code, related to llinfo. 37287546eaSitojun * Since we don't have BSD/OS version of net/route.c in our hand, 38287546eaSitojun * I left the code mostly as it was in 970310. -- itojun 39287546eaSitojun */ 40287546eaSitojun 41287546eaSitojun #include <sys/param.h> 42287546eaSitojun #include <sys/systm.h> 43b3c1e4c1Sitojun #include <sys/timeout.h> 44287546eaSitojun #include <sys/malloc.h> 45287546eaSitojun #include <sys/mbuf.h> 46287546eaSitojun #include <sys/socket.h> 47287546eaSitojun #include <sys/sockio.h> 48287546eaSitojun #include <sys/time.h> 49287546eaSitojun #include <sys/kernel.h> 50f4f4d166Sitojun #include <sys/protosw.h> 51287546eaSitojun #include <sys/errno.h> 52287546eaSitojun #include <sys/ioctl.h> 53287546eaSitojun #include <sys/syslog.h> 54287546eaSitojun #include <sys/queue.h> 553c4c637fSangelos #include <dev/rndvar.h> 56287546eaSitojun 57287546eaSitojun #include <net/if.h> 58287546eaSitojun #include <net/if_dl.h> 59287546eaSitojun #include <net/if_types.h> 60287546eaSitojun #include <net/if_atm.h> 61287546eaSitojun #include <net/route.h> 62287546eaSitojun 63287546eaSitojun #include <netinet/in.h> 64287546eaSitojun #include <netinet/if_ether.h> 6558aa7d74Sangelos 66287546eaSitojun #include <netinet6/in6_var.h> 67fa86ee14Sitojun #include <netinet/ip6.h> 68287546eaSitojun #include <netinet6/ip6_var.h> 69287546eaSitojun #include <netinet6/nd6.h> 70287546eaSitojun #include <netinet6/in6_prefix.h> 71fa86ee14Sitojun #include <netinet/icmp6.h> 72287546eaSitojun 73287546eaSitojun #include <net/net_osdep.h> 74287546eaSitojun 75287546eaSitojun #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */ 76287546eaSitojun #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */ 77287546eaSitojun 78287546eaSitojun #define SIN6(s) ((struct sockaddr_in6 *)s) 79287546eaSitojun #define SDL(s) ((struct sockaddr_dl *)s) 80287546eaSitojun 81287546eaSitojun /* timer values */ 82287546eaSitojun int nd6_prune = 1; /* walk list every 1 seconds */ 83287546eaSitojun int nd6_delay = 5; /* delay first probe time 5 second */ 84287546eaSitojun int nd6_umaxtries = 3; /* maximum unicast query */ 85287546eaSitojun int nd6_mmaxtries = 3; /* maximum multicast query */ 86287546eaSitojun int nd6_useloopback = 1; /* use loopback interface for local traffic */ 87be4e9e12Sitojun int nd6_gctimer = (60 * 60 * 24); /* 1 day: garbage collection timer */ 88287546eaSitojun 89287546eaSitojun /* preventing too many loops in ND option parsing */ 90287546eaSitojun int nd6_maxndopt = 10; /* max # of ND options allowed */ 91287546eaSitojun 92f6e55599Sitojun int nd6_maxnudhint = 0; /* max # of subsequent upper layer hints */ 93f6e55599Sitojun 94b79da24aSitojun #ifdef ND6_DEBUG 95b79da24aSitojun int nd6_debug = 1; 96b79da24aSitojun #else 97b79da24aSitojun int nd6_debug = 0; 98b79da24aSitojun #endif 99b79da24aSitojun 100287546eaSitojun /* for debugging? */ 101287546eaSitojun static int nd6_inuse, nd6_allocated; 102287546eaSitojun 103287546eaSitojun struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; 104cfab95f2Sitojun static size_t nd_ifinfo_indexlim = 8; 105287546eaSitojun struct nd_ifinfo *nd_ifinfo = NULL; 106f4f4d166Sitojun struct nd_drhead nd_defrouter; 107287546eaSitojun struct nd_prhead nd_prefix = { 0 }; 108287546eaSitojun 109287546eaSitojun int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; 110287546eaSitojun static struct sockaddr_in6 all1_sa; 111287546eaSitojun 112287546eaSitojun static void nd6_slowtimo __P((void *)); 113287546eaSitojun 114b3c1e4c1Sitojun struct timeout nd6_slowtimo_ch; 115b3c1e4c1Sitojun struct timeout nd6_timer_ch; 116b3c1e4c1Sitojun extern struct timeout in6_tmpaddrtimer_ch; 117b3c1e4c1Sitojun 118287546eaSitojun void 119287546eaSitojun nd6_init() 120287546eaSitojun { 121287546eaSitojun static int nd6_init_done = 0; 122287546eaSitojun int i; 123287546eaSitojun 124287546eaSitojun if (nd6_init_done) { 125287546eaSitojun log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); 126287546eaSitojun return; 127287546eaSitojun } 128287546eaSitojun 129287546eaSitojun all1_sa.sin6_family = AF_INET6; 130287546eaSitojun all1_sa.sin6_len = sizeof(struct sockaddr_in6); 131287546eaSitojun for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) 132287546eaSitojun all1_sa.sin6_addr.s6_addr[i] = 0xff; 133287546eaSitojun 134f4f4d166Sitojun /* initialization of the default router list */ 135f4f4d166Sitojun TAILQ_INIT(&nd_defrouter); 136f4f4d166Sitojun 137287546eaSitojun nd6_init_done = 1; 138287546eaSitojun 139287546eaSitojun /* start timer */ 140b3c1e4c1Sitojun timeout_set(&nd6_slowtimo_ch, nd6_slowtimo, NULL); 141b3c1e4c1Sitojun timeout_add(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz); 142287546eaSitojun } 143287546eaSitojun 144287546eaSitojun void 145287546eaSitojun nd6_ifattach(ifp) 146287546eaSitojun struct ifnet *ifp; 147287546eaSitojun { 148287546eaSitojun 149287546eaSitojun /* 150287546eaSitojun * We have some arrays that should be indexed by if_index. 151287546eaSitojun * since if_index will grow dynamically, they should grow too. 152287546eaSitojun */ 153cfab95f2Sitojun if (nd_ifinfo == NULL || if_index >= nd_ifinfo_indexlim) { 154287546eaSitojun size_t n; 155287546eaSitojun caddr_t q; 156287546eaSitojun 157cfab95f2Sitojun while (if_index >= nd_ifinfo_indexlim) 158cfab95f2Sitojun nd_ifinfo_indexlim <<= 1; 159287546eaSitojun 160287546eaSitojun /* grow nd_ifinfo */ 161cfab95f2Sitojun n = nd_ifinfo_indexlim * sizeof(struct nd_ifinfo); 162287546eaSitojun q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK); 163287546eaSitojun bzero(q, n); 164287546eaSitojun if (nd_ifinfo) { 165287546eaSitojun bcopy((caddr_t)nd_ifinfo, q, n/2); 166287546eaSitojun free((caddr_t)nd_ifinfo, M_IP6NDP); 167287546eaSitojun } 168287546eaSitojun nd_ifinfo = (struct nd_ifinfo *)q; 169287546eaSitojun } 170287546eaSitojun 171287546eaSitojun #define ND nd_ifinfo[ifp->if_index] 172d374aaacSitojun 17315bd77d2Sitojun /* 17415bd77d2Sitojun * Don't initialize if called twice. 17515bd77d2Sitojun * XXX: to detect this, we should choose a member that is never set 17615bd77d2Sitojun * before initialization of the ND structure itself. We formaly used 17715bd77d2Sitojun * the linkmtu member, which was not suitable because it could be 17815bd77d2Sitojun * initialized via "ifconfig mtu". 17915bd77d2Sitojun */ 18015bd77d2Sitojun if (ND.basereachable) 181d374aaacSitojun return; 182d374aaacSitojun 183287546eaSitojun ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu; 184287546eaSitojun ND.chlim = IPV6_DEFHLIM; 185287546eaSitojun ND.basereachable = REACHABLE_TIME; 186287546eaSitojun ND.reachable = ND_COMPUTE_RTIME(ND.basereachable); 187287546eaSitojun ND.retrans = RETRANS_TIMER; 188287546eaSitojun ND.receivedra = 0; 189d374aaacSitojun ND.flags = ND6_IFF_PERFORMNUD; 190287546eaSitojun nd6_setmtu(ifp); 191287546eaSitojun #undef ND 192287546eaSitojun } 193287546eaSitojun 194287546eaSitojun /* 195287546eaSitojun * Reset ND level link MTU. This function is called when the physical MTU 196287546eaSitojun * changes, which means we might have to adjust the ND level MTU. 197287546eaSitojun */ 198287546eaSitojun void 199287546eaSitojun nd6_setmtu(ifp) 200287546eaSitojun struct ifnet *ifp; 201287546eaSitojun { 202287546eaSitojun struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; 203287546eaSitojun u_long oldmaxmtu = ndi->maxmtu; 204287546eaSitojun u_long oldlinkmtu = ndi->linkmtu; 205287546eaSitojun 206287546eaSitojun switch (ifp->if_type) { 207287546eaSitojun case IFT_ARCNET: /* XXX MTU handling needs more work */ 208287546eaSitojun ndi->maxmtu = MIN(60480, ifp->if_mtu); 209287546eaSitojun break; 210287546eaSitojun case IFT_ETHER: 211287546eaSitojun ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); 212287546eaSitojun break; 213287546eaSitojun case IFT_ATM: 214287546eaSitojun ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); 215287546eaSitojun break; 216287546eaSitojun default: 217287546eaSitojun ndi->maxmtu = ifp->if_mtu; 218287546eaSitojun break; 219287546eaSitojun } 220287546eaSitojun 221287546eaSitojun if (oldmaxmtu != ndi->maxmtu) { 222287546eaSitojun /* 223287546eaSitojun * If the ND level MTU is not set yet, or if the maxmtu 224287546eaSitojun * is reset to a smaller value than the ND level MTU, 225287546eaSitojun * also reset the ND level MTU. 226287546eaSitojun */ 227287546eaSitojun if (ndi->linkmtu == 0 || 228287546eaSitojun ndi->maxmtu < ndi->linkmtu) { 229287546eaSitojun ndi->linkmtu = ndi->maxmtu; 230287546eaSitojun /* also adjust in6_maxmtu if necessary. */ 231287546eaSitojun if (oldlinkmtu == 0) { 232287546eaSitojun /* 233287546eaSitojun * XXX: the case analysis is grotty, but 234287546eaSitojun * it is not efficient to call in6_setmaxmtu() 235287546eaSitojun * here when we are during the initialization 236287546eaSitojun * procedure. 237287546eaSitojun */ 238287546eaSitojun if (in6_maxmtu < ndi->linkmtu) 239287546eaSitojun in6_maxmtu = ndi->linkmtu; 240f6e55599Sitojun } else 241287546eaSitojun in6_setmaxmtu(); 242287546eaSitojun } 243287546eaSitojun } 244287546eaSitojun #undef MIN 245287546eaSitojun } 246287546eaSitojun 247287546eaSitojun void 248287546eaSitojun nd6_option_init(opt, icmp6len, ndopts) 249287546eaSitojun void *opt; 250287546eaSitojun int icmp6len; 251287546eaSitojun union nd_opts *ndopts; 252287546eaSitojun { 253287546eaSitojun bzero(ndopts, sizeof(*ndopts)); 254287546eaSitojun ndopts->nd_opts_search = (struct nd_opt_hdr *)opt; 255287546eaSitojun ndopts->nd_opts_last 256287546eaSitojun = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len); 257287546eaSitojun 258287546eaSitojun if (icmp6len == 0) { 259287546eaSitojun ndopts->nd_opts_done = 1; 260287546eaSitojun ndopts->nd_opts_search = NULL; 261287546eaSitojun } 262287546eaSitojun } 263287546eaSitojun 264287546eaSitojun /* 265287546eaSitojun * Take one ND option. 266287546eaSitojun */ 267287546eaSitojun struct nd_opt_hdr * 268287546eaSitojun nd6_option(ndopts) 269287546eaSitojun union nd_opts *ndopts; 270287546eaSitojun { 271287546eaSitojun struct nd_opt_hdr *nd_opt; 272287546eaSitojun int olen; 273287546eaSitojun 274287546eaSitojun if (!ndopts) 275287546eaSitojun panic("ndopts == NULL in nd6_option\n"); 276287546eaSitojun if (!ndopts->nd_opts_last) 277287546eaSitojun panic("uninitialized ndopts in nd6_option\n"); 278287546eaSitojun if (!ndopts->nd_opts_search) 279287546eaSitojun return NULL; 280287546eaSitojun if (ndopts->nd_opts_done) 281287546eaSitojun return NULL; 282287546eaSitojun 283287546eaSitojun nd_opt = ndopts->nd_opts_search; 284287546eaSitojun 28515bd77d2Sitojun /* make sure nd_opt_len is inside the buffer */ 28615bd77d2Sitojun if ((caddr_t)&nd_opt->nd_opt_len >= (caddr_t)ndopts->nd_opts_last) { 28715bd77d2Sitojun bzero(ndopts, sizeof(*ndopts)); 28815bd77d2Sitojun return NULL; 28915bd77d2Sitojun } 29015bd77d2Sitojun 291287546eaSitojun olen = nd_opt->nd_opt_len << 3; 292287546eaSitojun if (olen == 0) { 293287546eaSitojun /* 294287546eaSitojun * Message validation requires that all included 295287546eaSitojun * options have a length that is greater than zero. 296287546eaSitojun */ 297287546eaSitojun bzero(ndopts, sizeof(*ndopts)); 298287546eaSitojun return NULL; 299287546eaSitojun } 300287546eaSitojun 301287546eaSitojun ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); 30215bd77d2Sitojun if (ndopts->nd_opts_search > ndopts->nd_opts_last) { 30315bd77d2Sitojun /* option overruns the end of buffer, invalid */ 30415bd77d2Sitojun bzero(ndopts, sizeof(*ndopts)); 30515bd77d2Sitojun return NULL; 30615bd77d2Sitojun } else if (ndopts->nd_opts_search == ndopts->nd_opts_last) { 30715bd77d2Sitojun /* reached the end of options chain */ 308287546eaSitojun ndopts->nd_opts_done = 1; 309287546eaSitojun ndopts->nd_opts_search = NULL; 310287546eaSitojun } 311287546eaSitojun return nd_opt; 312287546eaSitojun } 313287546eaSitojun 314287546eaSitojun /* 315287546eaSitojun * Parse multiple ND options. 316287546eaSitojun * This function is much easier to use, for ND routines that do not need 317287546eaSitojun * multiple options of the same type. 318287546eaSitojun */ 319287546eaSitojun int 320287546eaSitojun nd6_options(ndopts) 321287546eaSitojun union nd_opts *ndopts; 322287546eaSitojun { 323287546eaSitojun struct nd_opt_hdr *nd_opt; 324287546eaSitojun int i = 0; 325287546eaSitojun 326287546eaSitojun if (!ndopts) 327287546eaSitojun panic("ndopts == NULL in nd6_options\n"); 328287546eaSitojun if (!ndopts->nd_opts_last) 329287546eaSitojun panic("uninitialized ndopts in nd6_options\n"); 330287546eaSitojun if (!ndopts->nd_opts_search) 331287546eaSitojun return 0; 332287546eaSitojun 333287546eaSitojun while (1) { 334287546eaSitojun nd_opt = nd6_option(ndopts); 335287546eaSitojun if (!nd_opt && !ndopts->nd_opts_last) { 336287546eaSitojun /* 337287546eaSitojun * Message validation requires that all included 338287546eaSitojun * options have a length that is greater than zero. 339287546eaSitojun */ 340b79da24aSitojun icmp6stat.icp6s_nd_badopt++; 341287546eaSitojun bzero(ndopts, sizeof(*ndopts)); 342287546eaSitojun return -1; 343287546eaSitojun } 344287546eaSitojun 345287546eaSitojun if (!nd_opt) 346287546eaSitojun goto skip1; 347287546eaSitojun 348287546eaSitojun switch (nd_opt->nd_opt_type) { 349287546eaSitojun case ND_OPT_SOURCE_LINKADDR: 350287546eaSitojun case ND_OPT_TARGET_LINKADDR: 351287546eaSitojun case ND_OPT_MTU: 352287546eaSitojun case ND_OPT_REDIRECTED_HEADER: 353287546eaSitojun if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { 35415bd77d2Sitojun nd6log((LOG_INFO, 35515bd77d2Sitojun "duplicated ND6 option found (type=%d)\n", 35615bd77d2Sitojun nd_opt->nd_opt_type)); 357287546eaSitojun /* XXX bark? */ 358287546eaSitojun } else { 359287546eaSitojun ndopts->nd_opt_array[nd_opt->nd_opt_type] 360287546eaSitojun = nd_opt; 361287546eaSitojun } 362287546eaSitojun break; 363287546eaSitojun case ND_OPT_PREFIX_INFORMATION: 364287546eaSitojun if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) { 365287546eaSitojun ndopts->nd_opt_array[nd_opt->nd_opt_type] 366287546eaSitojun = nd_opt; 367287546eaSitojun } 368287546eaSitojun ndopts->nd_opts_pi_end = 369287546eaSitojun (struct nd_opt_prefix_info *)nd_opt; 370287546eaSitojun break; 371287546eaSitojun default: 372287546eaSitojun /* 373287546eaSitojun * Unknown options must be silently ignored, 374287546eaSitojun * to accomodate future extension to the protocol. 375287546eaSitojun */ 376b79da24aSitojun nd6log((LOG_DEBUG, 377287546eaSitojun "nd6_options: unsupported option %d - " 378b79da24aSitojun "option ignored\n", nd_opt->nd_opt_type)); 379287546eaSitojun } 380287546eaSitojun 381287546eaSitojun skip1: 382287546eaSitojun i++; 383287546eaSitojun if (i > nd6_maxndopt) { 384287546eaSitojun icmp6stat.icp6s_nd_toomanyopt++; 385b79da24aSitojun nd6log((LOG_INFO, "too many loop in nd opt\n")); 386287546eaSitojun break; 387287546eaSitojun } 388287546eaSitojun 389287546eaSitojun if (ndopts->nd_opts_done) 390287546eaSitojun break; 391287546eaSitojun } 392287546eaSitojun 393287546eaSitojun return 0; 394287546eaSitojun } 395287546eaSitojun 396287546eaSitojun /* 397287546eaSitojun * ND6 timer routine to expire default route list and prefix list 398287546eaSitojun */ 399287546eaSitojun void 400287546eaSitojun nd6_timer(ignored_arg) 401287546eaSitojun void *ignored_arg; 402287546eaSitojun { 403287546eaSitojun int s; 404b3c1e4c1Sitojun struct llinfo_nd6 *ln; 405b3c1e4c1Sitojun struct nd_defrouter *dr; 406b3c1e4c1Sitojun struct nd_prefix *pr; 407287546eaSitojun long time_second = time.tv_sec; 408287546eaSitojun 409287546eaSitojun s = splnet(); 41058aa7d74Sangelos 411b3c1e4c1Sitojun timeout_set(&nd6_timer_ch, nd6_timer, NULL); 412b3c1e4c1Sitojun timeout_add(&nd6_timer_ch, nd6_prune * hz); 413287546eaSitojun 414287546eaSitojun ln = llinfo_nd6.ln_next; 415287546eaSitojun /* XXX BSD/OS separates this code -- itojun */ 416287546eaSitojun while (ln && ln != &llinfo_nd6) { 417287546eaSitojun struct rtentry *rt; 418287546eaSitojun struct ifnet *ifp; 419287546eaSitojun struct sockaddr_in6 *dst; 420287546eaSitojun struct llinfo_nd6 *next = ln->ln_next; 421d374aaacSitojun /* XXX: used for the DELAY case only: */ 422d374aaacSitojun struct nd_ifinfo *ndi = NULL; 423287546eaSitojun 424287546eaSitojun if ((rt = ln->ln_rt) == NULL) { 425287546eaSitojun ln = next; 426287546eaSitojun continue; 427287546eaSitojun } 428287546eaSitojun if ((ifp = rt->rt_ifp) == NULL) { 429287546eaSitojun ln = next; 430287546eaSitojun continue; 431287546eaSitojun } 432d374aaacSitojun ndi = &nd_ifinfo[ifp->if_index]; 433287546eaSitojun dst = (struct sockaddr_in6 *)rt_key(rt); 434287546eaSitojun 435287546eaSitojun if (ln->ln_expire > time_second) { 436287546eaSitojun ln = next; 437287546eaSitojun continue; 438287546eaSitojun } 439287546eaSitojun 440287546eaSitojun /* sanity check */ 441287546eaSitojun if (!rt) 442287546eaSitojun panic("rt=0 in nd6_timer(ln=%p)\n", ln); 443d374aaacSitojun if (rt->rt_llinfo && (struct llinfo_nd6 *)rt->rt_llinfo != ln) 444d374aaacSitojun panic("rt_llinfo(%p) is not equal to ln(%p)\n", 445d374aaacSitojun rt->rt_llinfo, ln); 446287546eaSitojun if (!dst) 447287546eaSitojun panic("dst=0 in nd6_timer(ln=%p)\n", ln); 448287546eaSitojun 449287546eaSitojun switch (ln->ln_state) { 450287546eaSitojun case ND6_LLINFO_INCOMPLETE: 451287546eaSitojun if (ln->ln_asked < nd6_mmaxtries) { 452287546eaSitojun ln->ln_asked++; 453287546eaSitojun ln->ln_expire = time_second + 454287546eaSitojun nd_ifinfo[ifp->if_index].retrans / 1000; 455287546eaSitojun nd6_ns_output(ifp, NULL, &dst->sin6_addr, 456287546eaSitojun ln, 0); 457287546eaSitojun } else { 458287546eaSitojun struct mbuf *m = ln->ln_hold; 459287546eaSitojun if (m) { 460287546eaSitojun if (rt->rt_ifp) { 461287546eaSitojun /* 462287546eaSitojun * Fake rcvif to make ICMP error 463287546eaSitojun * more helpful in diagnosing 464287546eaSitojun * for the receiver. 465287546eaSitojun * XXX: should we consider 466287546eaSitojun * older rcvif? 467287546eaSitojun */ 468287546eaSitojun m->m_pkthdr.rcvif = rt->rt_ifp; 469287546eaSitojun } 470287546eaSitojun icmp6_error(m, ICMP6_DST_UNREACH, 471287546eaSitojun ICMP6_DST_UNREACH_ADDR, 0); 472287546eaSitojun ln->ln_hold = NULL; 473287546eaSitojun } 47429760ae1Sitojun next = nd6_free(rt); 475287546eaSitojun } 476287546eaSitojun break; 477287546eaSitojun case ND6_LLINFO_REACHABLE: 478be4e9e12Sitojun if (ln->ln_expire) { 479287546eaSitojun ln->ln_state = ND6_LLINFO_STALE; 480be4e9e12Sitojun ln->ln_expire = time_second + nd6_gctimer; 481be4e9e12Sitojun } 482287546eaSitojun break; 483be4e9e12Sitojun 484be4e9e12Sitojun case ND6_LLINFO_STALE: 485be4e9e12Sitojun /* Garbage Collection(RFC 2461 5.3) */ 486be4e9e12Sitojun if (ln->ln_expire) 487be4e9e12Sitojun next = nd6_free(rt); 488be4e9e12Sitojun break; 489be4e9e12Sitojun 490287546eaSitojun case ND6_LLINFO_DELAY: 491d374aaacSitojun if (ndi && (ndi->flags & ND6_IFF_PERFORMNUD) != 0) { 492d374aaacSitojun /* We need NUD */ 493287546eaSitojun ln->ln_asked = 1; 494287546eaSitojun ln->ln_state = ND6_LLINFO_PROBE; 495287546eaSitojun ln->ln_expire = time_second + 496d374aaacSitojun ndi->retrans / 1000; 497d374aaacSitojun nd6_ns_output(ifp, &dst->sin6_addr, 498d374aaacSitojun &dst->sin6_addr, 499287546eaSitojun ln, 0); 500be4e9e12Sitojun } else { 501d374aaacSitojun ln->ln_state = ND6_LLINFO_STALE; /* XXX */ 502be4e9e12Sitojun ln->ln_expire = time_second + nd6_gctimer; 503be4e9e12Sitojun } 504287546eaSitojun break; 505287546eaSitojun case ND6_LLINFO_PROBE: 506287546eaSitojun if (ln->ln_asked < nd6_umaxtries) { 507287546eaSitojun ln->ln_asked++; 508287546eaSitojun ln->ln_expire = time_second + 509287546eaSitojun nd_ifinfo[ifp->if_index].retrans / 1000; 510287546eaSitojun nd6_ns_output(ifp, &dst->sin6_addr, 511287546eaSitojun &dst->sin6_addr, ln, 0); 51229760ae1Sitojun } else 51329760ae1Sitojun next = nd6_free(rt); 514287546eaSitojun break; 515287546eaSitojun } 516287546eaSitojun ln = next; 517287546eaSitojun } 518287546eaSitojun 5190a2c5741Sitojun /* expire default router list */ 520f4f4d166Sitojun dr = TAILQ_FIRST(&nd_defrouter); 521287546eaSitojun while (dr) { 522287546eaSitojun if (dr->expire && dr->expire < time_second) { 523287546eaSitojun struct nd_defrouter *t; 524f4f4d166Sitojun t = TAILQ_NEXT(dr, dr_entry); 525287546eaSitojun defrtrlist_del(dr); 526287546eaSitojun dr = t; 527287546eaSitojun } else 528f4f4d166Sitojun dr = TAILQ_NEXT(dr, dr_entry); 529287546eaSitojun } 530287546eaSitojun pr = nd_prefix.lh_first; 531287546eaSitojun while (pr) { 532287546eaSitojun struct in6_ifaddr *ia6; 533287546eaSitojun struct in6_addrlifetime *lt6; 534287546eaSitojun 535287546eaSitojun if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 536287546eaSitojun ia6 = NULL; 537287546eaSitojun else 538287546eaSitojun ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); 539287546eaSitojun 540287546eaSitojun if (ia6) { 541287546eaSitojun /* check address lifetime */ 542287546eaSitojun lt6 = &ia6->ia6_lifetime; 543287546eaSitojun if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second) 544287546eaSitojun ia6->ia6_flags |= IN6_IFF_DEPRECATED; 545287546eaSitojun if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) { 546287546eaSitojun if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 547287546eaSitojun in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 548287546eaSitojun /* xxx ND_OPT_PI_FLAG_ONLINK processing */ 549287546eaSitojun } 550287546eaSitojun } 551287546eaSitojun 552287546eaSitojun /* 553287546eaSitojun * check prefix lifetime. 554287546eaSitojun * since pltime is just for autoconf, pltime processing for 555287546eaSitojun * prefix is not necessary. 556287546eaSitojun * 557287546eaSitojun * we offset expire time by NDPR_KEEP_EXPIRE, so that we 558287546eaSitojun * can use the old prefix information to validate the 559287546eaSitojun * next prefix information to come. See prelist_update() 560287546eaSitojun * for actual validation. 561287546eaSitojun */ 562287546eaSitojun if (pr->ndpr_expire 563287546eaSitojun && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { 564287546eaSitojun struct nd_prefix *t; 565287546eaSitojun t = pr->ndpr_next; 566287546eaSitojun 567287546eaSitojun /* 568287546eaSitojun * address expiration and prefix expiration are 569287546eaSitojun * separate. NEVER perform in6_ifdel here. 570287546eaSitojun */ 571287546eaSitojun 572287546eaSitojun prelist_remove(pr); 573287546eaSitojun pr = t; 574287546eaSitojun } else 575287546eaSitojun pr = pr->ndpr_next; 576287546eaSitojun } 577287546eaSitojun splx(s); 578287546eaSitojun } 579287546eaSitojun 58022770369Sitojun /* 58122770369Sitojun * Nuke neighbor cache/prefix/default router management table, right before 58222770369Sitojun * ifp goes away. 58322770369Sitojun */ 58422770369Sitojun void 58522770369Sitojun nd6_purge(ifp) 58622770369Sitojun struct ifnet *ifp; 58722770369Sitojun { 58822770369Sitojun struct llinfo_nd6 *ln, *nln; 58922770369Sitojun struct nd_defrouter *dr, *ndr, drany; 59022770369Sitojun struct nd_prefix *pr, *npr; 59122770369Sitojun 59222770369Sitojun /* Nuke default router list entries toward ifp */ 593f4f4d166Sitojun if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { 59422770369Sitojun /* 59522770369Sitojun * The first entry of the list may be stored in 59622770369Sitojun * the routing table, so we'll delete it later. 59722770369Sitojun */ 598f4f4d166Sitojun for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = ndr) { 599f4f4d166Sitojun ndr = TAILQ_NEXT(dr, dr_entry); 60022770369Sitojun if (dr->ifp == ifp) 60122770369Sitojun defrtrlist_del(dr); 60222770369Sitojun } 603f4f4d166Sitojun dr = TAILQ_FIRST(&nd_defrouter); 60422770369Sitojun if (dr->ifp == ifp) 60522770369Sitojun defrtrlist_del(dr); 60622770369Sitojun } 60722770369Sitojun 60822770369Sitojun /* Nuke prefix list entries toward ifp */ 60922770369Sitojun for (pr = nd_prefix.lh_first; pr; pr = npr) { 61022770369Sitojun npr = pr->ndpr_next; 61122770369Sitojun if (pr->ndpr_ifp == ifp) { 61222770369Sitojun if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 61322770369Sitojun in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 61422770369Sitojun prelist_remove(pr); 61522770369Sitojun } 61622770369Sitojun } 61722770369Sitojun 618f4f4d166Sitojun /* cancel default outgoing interface setting */ 619f4f4d166Sitojun if (nd6_defifindex == ifp->if_index) 620f4f4d166Sitojun nd6_setdefaultiface(0); 621f4f4d166Sitojun 62222770369Sitojun /* refresh default router list */ 62322770369Sitojun bzero(&drany, sizeof(drany)); 62422770369Sitojun defrouter_delreq(&drany, 0); 625f4f4d166Sitojun defrouter_select(); 62622770369Sitojun 62722770369Sitojun /* 62822770369Sitojun * Nuke neighbor cache entries for the ifp. 62922770369Sitojun * Note that rt->rt_ifp may not be the same as ifp, 63022770369Sitojun * due to KAME goto ours hack. See RTM_RESOLVE case in 63122770369Sitojun * nd6_rtrequest(), and ip6_input(). 63222770369Sitojun */ 63322770369Sitojun ln = llinfo_nd6.ln_next; 63422770369Sitojun while (ln && ln != &llinfo_nd6) { 63522770369Sitojun struct rtentry *rt; 63622770369Sitojun struct sockaddr_dl *sdl; 63722770369Sitojun 63822770369Sitojun nln = ln->ln_next; 63922770369Sitojun rt = ln->ln_rt; 64022770369Sitojun if (rt && rt->rt_gateway && 64122770369Sitojun rt->rt_gateway->sa_family == AF_LINK) { 64222770369Sitojun sdl = (struct sockaddr_dl *)rt->rt_gateway; 64322770369Sitojun if (sdl->sdl_index == ifp->if_index) 64429760ae1Sitojun nln = nd6_free(rt); 64522770369Sitojun } 64622770369Sitojun ln = nln; 64722770369Sitojun } 64822770369Sitojun } 64922770369Sitojun 650287546eaSitojun struct rtentry * 651287546eaSitojun nd6_lookup(addr6, create, ifp) 652287546eaSitojun struct in6_addr *addr6; 653287546eaSitojun int create; 654287546eaSitojun struct ifnet *ifp; 655287546eaSitojun { 656287546eaSitojun struct rtentry *rt; 657287546eaSitojun struct sockaddr_in6 sin6; 658287546eaSitojun 659287546eaSitojun bzero(&sin6, sizeof(sin6)); 660287546eaSitojun sin6.sin6_len = sizeof(struct sockaddr_in6); 661287546eaSitojun sin6.sin6_family = AF_INET6; 662287546eaSitojun sin6.sin6_addr = *addr6; 66358aa7d74Sangelos rt = rtalloc1((struct sockaddr *)&sin6, create); 664287546eaSitojun if (rt && (rt->rt_flags & RTF_LLINFO) == 0) { 665287546eaSitojun /* 666287546eaSitojun * This is the case for the default route. 667287546eaSitojun * If we want to create a neighbor cache for the address, we 668287546eaSitojun * should free the route for the destination and allocate an 669287546eaSitojun * interface route. 670287546eaSitojun */ 671287546eaSitojun if (create) { 672287546eaSitojun RTFREE(rt); 673287546eaSitojun rt = 0; 674287546eaSitojun } 675287546eaSitojun } 676287546eaSitojun if (!rt) { 677287546eaSitojun if (create && ifp) { 678d374aaacSitojun int e; 679d374aaacSitojun 680287546eaSitojun /* 681287546eaSitojun * If no route is available and create is set, 682287546eaSitojun * we allocate a host route for the destination 683287546eaSitojun * and treat it like an interface route. 684287546eaSitojun * This hack is necessary for a neighbor which can't 685287546eaSitojun * be covered by our own prefix. 686287546eaSitojun */ 687287546eaSitojun struct ifaddr *ifa = 688287546eaSitojun ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); 689287546eaSitojun if (ifa == NULL) 690287546eaSitojun return(NULL); 691287546eaSitojun 692287546eaSitojun /* 693287546eaSitojun * Create a new route. RTF_LLINFO is necessary 694287546eaSitojun * to create a Neighbor Cache entry for the 695287546eaSitojun * destination in nd6_rtrequest which will be 696287546eaSitojun * called in rtequest via ifa->ifa_rtrequest. 697287546eaSitojun */ 698d374aaacSitojun if ((e = rtrequest(RTM_ADD, (struct sockaddr *)&sin6, 699287546eaSitojun ifa->ifa_addr, 700287546eaSitojun (struct sockaddr *)&all1_sa, 701287546eaSitojun (ifa->ifa_flags | 702d374aaacSitojun RTF_HOST | RTF_LLINFO) & 703d374aaacSitojun ~RTF_CLONING, 704d374aaacSitojun &rt)) != 0) 705287546eaSitojun log(LOG_ERR, 706287546eaSitojun "nd6_lookup: failed to add route for a " 707d374aaacSitojun "neighbor(%s), errno=%d\n", 708d374aaacSitojun ip6_sprintf(addr6), e); 709287546eaSitojun if (rt == NULL) 710287546eaSitojun return(NULL); 711287546eaSitojun if (rt->rt_llinfo) { 712287546eaSitojun struct llinfo_nd6 *ln = 713287546eaSitojun (struct llinfo_nd6 *)rt->rt_llinfo; 714287546eaSitojun ln->ln_state = ND6_LLINFO_NOSTATE; 715287546eaSitojun } 716f6e55599Sitojun } else 717287546eaSitojun return(NULL); 718287546eaSitojun } 719287546eaSitojun rt->rt_refcnt--; 720287546eaSitojun /* 721287546eaSitojun * Validation for the entry. 722287546eaSitojun * XXX: we can't use rt->rt_ifp to check for the interface, since 723287546eaSitojun * it might be the loopback interface if the entry is for our 724287546eaSitojun * own address on a non-loopback interface. Instead, we should 725287546eaSitojun * use rt->rt_ifa->ifa_ifp, which would specify the REAL interface. 726287546eaSitojun */ 727287546eaSitojun if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || 728287546eaSitojun rt->rt_gateway->sa_family != AF_LINK || 729287546eaSitojun (ifp && rt->rt_ifa->ifa_ifp != ifp)) { 730287546eaSitojun if (create) { 731287546eaSitojun log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", 732287546eaSitojun ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); 733287546eaSitojun /* xxx more logs... kazu */ 734287546eaSitojun } 735287546eaSitojun return(0); 736287546eaSitojun } 737287546eaSitojun return(rt); 738287546eaSitojun } 739287546eaSitojun 740287546eaSitojun /* 741287546eaSitojun * Detect if a given IPv6 address identifies a neighbor on a given link. 742287546eaSitojun * XXX: should take care of the destination of a p2p link? 743287546eaSitojun */ 744287546eaSitojun int 745287546eaSitojun nd6_is_addr_neighbor(addr, ifp) 746cfb6b8dfSitojun struct sockaddr_in6 *addr; 747287546eaSitojun struct ifnet *ifp; 748287546eaSitojun { 749b3c1e4c1Sitojun struct ifaddr *ifa; 750287546eaSitojun int i; 751287546eaSitojun 752287546eaSitojun #define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr) 753287546eaSitojun #define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr) 754287546eaSitojun 755cfb6b8dfSitojun /* 756cfb6b8dfSitojun * A link-local address is always a neighbor. 757cfb6b8dfSitojun * XXX: we should use the sin6_scope_id field rather than the embedded 758cfb6b8dfSitojun * interface index. 759cfb6b8dfSitojun */ 760cfb6b8dfSitojun if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr) && 761cfb6b8dfSitojun ntohs(*(u_int16_t *)&addr->sin6_addr.s6_addr[2]) == ifp->if_index) 762287546eaSitojun return(1); 763287546eaSitojun 764287546eaSitojun /* 765287546eaSitojun * If the address matches one of our addresses, 766287546eaSitojun * it should be a neighbor. 767287546eaSitojun */ 768287546eaSitojun for (ifa = ifp->if_addrlist.tqh_first; 769287546eaSitojun ifa; 770287546eaSitojun ifa = ifa->ifa_list.tqe_next) 771287546eaSitojun { 772287546eaSitojun if (ifa->ifa_addr->sa_family != AF_INET6) 773287546eaSitojun next: continue; 774287546eaSitojun 775287546eaSitojun for (i = 0; i < 4; i++) { 776cfb6b8dfSitojun if ((IFADDR6(ifa).s6_addr32[i] ^ 777cfb6b8dfSitojun addr->sin6_addr.s6_addr32[i]) & 778287546eaSitojun IFMASK6(ifa).s6_addr32[i]) 779287546eaSitojun goto next; 780287546eaSitojun } 781287546eaSitojun return(1); 782287546eaSitojun } 783287546eaSitojun 784287546eaSitojun /* 785287546eaSitojun * Even if the address matches none of our addresses, it might be 786287546eaSitojun * in the neighbor cache. 787287546eaSitojun */ 788cfb6b8dfSitojun if (nd6_lookup(&addr->sin6_addr, 0, ifp)) 789287546eaSitojun return(1); 790287546eaSitojun 791287546eaSitojun return(0); 792287546eaSitojun #undef IFADDR6 793287546eaSitojun #undef IFMASK6 794287546eaSitojun } 795287546eaSitojun 796287546eaSitojun /* 797287546eaSitojun * Free an nd6 llinfo entry. 798287546eaSitojun */ 79929760ae1Sitojun struct llinfo_nd6 * 800287546eaSitojun nd6_free(rt) 801287546eaSitojun struct rtentry *rt; 802287546eaSitojun { 80329760ae1Sitojun struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo, *next; 804f4f4d166Sitojun struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; 805287546eaSitojun struct nd_defrouter *dr; 806287546eaSitojun 807287546eaSitojun /* 808f4f4d166Sitojun * Clear all destination cache entries for the neighbor. 809f4f4d166Sitojun * XXX: is it better to restrict this to hosts? 810287546eaSitojun */ 811f4f4d166Sitojun pfctlinput(PRC_HOSTDEAD, rt_key(rt)); 812f4f4d166Sitojun 813f4f4d166Sitojun if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ 814f4f4d166Sitojun int s; 815f4f4d166Sitojun s = splnet(); 816f4f4d166Sitojun dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 817f4f4d166Sitojun rt->rt_ifp); 818f4f4d166Sitojun if (ln->ln_router || dr) { 819f4f4d166Sitojun /* 820f4f4d166Sitojun * rt6_flush must be called whether or not the neighbor 821f4f4d166Sitojun * is in the Default Router List. 822f4f4d166Sitojun * See a corresponding comment in nd6_na_input(). 823f4f4d166Sitojun */ 824f4f4d166Sitojun rt6_flush(&in6, rt->rt_ifp); 825f4f4d166Sitojun } 826f4f4d166Sitojun 827f4f4d166Sitojun if (dr) { 828f4f4d166Sitojun /* 829f4f4d166Sitojun * Unreachablity of a router might affect the default 830f4f4d166Sitojun * router selection and on-link detection of advertised 831f4f4d166Sitojun * prefixes. 832f4f4d166Sitojun */ 833f4f4d166Sitojun 834f4f4d166Sitojun /* 835f4f4d166Sitojun * Temporarily fake the state to choose a new default 836f4f4d166Sitojun * router and to perform on-link determination of 837f4f4d166Sitojun * prefixes coreectly. 838f4f4d166Sitojun * Below the state will be set correctly, 839f4f4d166Sitojun * or the entry itself will be deleted. 840f4f4d166Sitojun */ 841f4f4d166Sitojun ln->ln_state = ND6_LLINFO_INCOMPLETE; 842f4f4d166Sitojun 843f4f4d166Sitojun if (dr == TAILQ_FIRST(&nd_defrouter)) { 844f4f4d166Sitojun /* 845f4f4d166Sitojun * It is used as the current default router, 846f4f4d166Sitojun * so we have to move it to the end of the 847f4f4d166Sitojun * list and choose a new one. 848f4f4d166Sitojun * XXX: it is not very efficient if this is 849f4f4d166Sitojun * the only router. 850f4f4d166Sitojun */ 851f4f4d166Sitojun TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 852f4f4d166Sitojun TAILQ_INSERT_TAIL(&nd_defrouter, dr, dr_entry); 853f4f4d166Sitojun 854f4f4d166Sitojun defrouter_select(); 855f4f4d166Sitojun } 856f4f4d166Sitojun pfxlist_onlink_check(); 857287546eaSitojun } 858287546eaSitojun splx(s); 859287546eaSitojun } 860287546eaSitojun 86129760ae1Sitojun /* 86229760ae1Sitojun * Before deleting the entry, remember the next entry as the 86329760ae1Sitojun * return value. We need this because pfxlist_onlink_check() above 86429760ae1Sitojun * might have freed other entries (particularly the old next entry) as 86529760ae1Sitojun * a side effect (XXX). 86629760ae1Sitojun */ 86729760ae1Sitojun next = ln->ln_next; 86829760ae1Sitojun 86929760ae1Sitojun /* 87029760ae1Sitojun * Detach the route from the routing tree and the list of neighbor 87129760ae1Sitojun * caches, and disable the route entry not to be used in already 87229760ae1Sitojun * cached routes. 87329760ae1Sitojun */ 874f4f4d166Sitojun rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, 875f4f4d166Sitojun rt_mask(rt), 0, (struct rtentry **)0); 87629760ae1Sitojun 8770a2c5741Sitojun return(next); 878287546eaSitojun } 879287546eaSitojun 880287546eaSitojun /* 881287546eaSitojun * Upper-layer reachability hint for Neighbor Unreachability Detection. 882287546eaSitojun * 883287546eaSitojun * XXX cost-effective metods? 884287546eaSitojun */ 885287546eaSitojun void 886f6e55599Sitojun nd6_nud_hint(rt, dst6, force) 887287546eaSitojun struct rtentry *rt; 888287546eaSitojun struct in6_addr *dst6; 889f6e55599Sitojun int force; 890287546eaSitojun { 891287546eaSitojun struct llinfo_nd6 *ln; 892287546eaSitojun long time_second = time.tv_sec; 893287546eaSitojun 894287546eaSitojun /* 895287546eaSitojun * If the caller specified "rt", use that. Otherwise, resolve the 896287546eaSitojun * routing table by supplied "dst6". 897287546eaSitojun */ 898287546eaSitojun if (!rt) { 899287546eaSitojun if (!dst6) 900287546eaSitojun return; 901287546eaSitojun if (!(rt = nd6_lookup(dst6, 0, NULL))) 902287546eaSitojun return; 903287546eaSitojun } 904287546eaSitojun 905f6e55599Sitojun if ((rt->rt_flags & RTF_GATEWAY) != 0 || 906f6e55599Sitojun (rt->rt_flags & RTF_LLINFO) == 0 || 907f6e55599Sitojun !rt->rt_llinfo || !rt->rt_gateway || 908f6e55599Sitojun rt->rt_gateway->sa_family != AF_LINK) { 909287546eaSitojun /* This is not a host route. */ 910287546eaSitojun return; 911287546eaSitojun } 912287546eaSitojun 913287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 914804d8827Sitojun if (ln->ln_state < ND6_LLINFO_REACHABLE) 915287546eaSitojun return; 916287546eaSitojun 917f6e55599Sitojun /* 918f6e55599Sitojun * if we get upper-layer reachability confirmation many times, 919f6e55599Sitojun * it is possible we have false information. 920f6e55599Sitojun */ 921f6e55599Sitojun if (!force) { 922f6e55599Sitojun ln->ln_byhint++; 923f6e55599Sitojun if (ln->ln_byhint > nd6_maxnudhint) 924f6e55599Sitojun return; 925f6e55599Sitojun } 926f6e55599Sitojun 927287546eaSitojun ln->ln_state = ND6_LLINFO_REACHABLE; 928287546eaSitojun if (ln->ln_expire) 929287546eaSitojun ln->ln_expire = time_second + 930287546eaSitojun nd_ifinfo[rt->rt_ifp->if_index].reachable; 931287546eaSitojun } 932287546eaSitojun 933287546eaSitojun #ifdef OLDIP6OUTPUT 934287546eaSitojun /* 935287546eaSitojun * Resolve an IP6 address into an ethernet address. If success, 936287546eaSitojun * desten is filled in. If there is no entry in ndptab, 937287546eaSitojun * set one up and multicast a solicitation for the IP6 address. 938287546eaSitojun * Hold onto this mbuf and resend it once the address 939287546eaSitojun * is finally resolved. A return value of 1 indicates 940287546eaSitojun * that desten has been filled in and the packet should be sent 941287546eaSitojun * normally; a 0 return indicates that the packet has been 942287546eaSitojun * taken over here, either now or for later transmission. 943287546eaSitojun */ 944287546eaSitojun int 945287546eaSitojun nd6_resolve(ifp, rt, m, dst, desten) 946287546eaSitojun struct ifnet *ifp; 947287546eaSitojun struct rtentry *rt; 948287546eaSitojun struct mbuf *m; 949287546eaSitojun struct sockaddr *dst; 950287546eaSitojun u_char *desten; 951287546eaSitojun { 952287546eaSitojun struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; 953287546eaSitojun struct sockaddr_dl *sdl; 954287546eaSitojun long time_second = time.tv_sec; 955287546eaSitojun 956287546eaSitojun if (m->m_flags & M_MCAST) { 957287546eaSitojun switch (ifp->if_type) { 958287546eaSitojun case IFT_ETHER: 959287546eaSitojun case IFT_FDDI: 960287546eaSitojun ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, 961287546eaSitojun desten); 962287546eaSitojun return(1); 963287546eaSitojun break; 964287546eaSitojun case IFT_ARCNET: 965287546eaSitojun *desten = 0; 966287546eaSitojun return(1); 967287546eaSitojun default: 9680a2c5741Sitojun m_freem(m); 969287546eaSitojun return(0); 970287546eaSitojun } 971287546eaSitojun } 972287546eaSitojun if (rt && (rt->rt_flags & RTF_LLINFO) != 0) 973287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 974287546eaSitojun else { 975287546eaSitojun if ((rt = nd6_lookup(&(SIN6(dst)->sin6_addr), 1, ifp)) != NULL) 976287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 977287546eaSitojun } 978287546eaSitojun if (!ln || !rt) { 979287546eaSitojun log(LOG_DEBUG, "nd6_resolve: can't allocate llinfo for %s\n", 980287546eaSitojun ip6_sprintf(&(SIN6(dst)->sin6_addr))); 981287546eaSitojun m_freem(m); 982287546eaSitojun return(0); 983287546eaSitojun } 984287546eaSitojun sdl = SDL(rt->rt_gateway); 985287546eaSitojun /* 986287546eaSitojun * Ckeck the address family and length is valid, the address 987287546eaSitojun * is resolved; otherwise, try to resolve. 988287546eaSitojun */ 989287546eaSitojun if (ln->ln_state >= ND6_LLINFO_REACHABLE 990287546eaSitojun && sdl->sdl_family == AF_LINK 991287546eaSitojun && sdl->sdl_alen != 0) { 992287546eaSitojun bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 993287546eaSitojun if (ln->ln_state == ND6_LLINFO_STALE) { 994287546eaSitojun ln->ln_asked = 0; 995287546eaSitojun ln->ln_state = ND6_LLINFO_DELAY; 996287546eaSitojun ln->ln_expire = time_second + nd6_delay; 997287546eaSitojun } 998287546eaSitojun return(1); 999287546eaSitojun } 1000287546eaSitojun /* 1001287546eaSitojun * There is an ndp entry, but no ethernet address 1002287546eaSitojun * response yet. Replace the held mbuf with this 1003287546eaSitojun * latest one. 1004287546eaSitojun * 1005287546eaSitojun * XXX Does the code conform to rate-limiting rule? 1006287546eaSitojun * (RFC 2461 7.2.2) 1007287546eaSitojun */ 1008efcf292bSitojun if (ln->ln_state == ND6_LLINFO_NOSTATE) 1009287546eaSitojun ln->ln_state = ND6_LLINFO_INCOMPLETE; 1010287546eaSitojun if (ln->ln_hold) 1011287546eaSitojun m_freem(ln->ln_hold); 1012287546eaSitojun ln->ln_hold = m; 1013287546eaSitojun if (ln->ln_expire) { 1014287546eaSitojun if (ln->ln_asked < nd6_mmaxtries && 1015287546eaSitojun ln->ln_expire < time_second) { 1016287546eaSitojun ln->ln_asked++; 1017287546eaSitojun ln->ln_expire = time_second + 1018287546eaSitojun nd_ifinfo[ifp->if_index].retrans / 1000; 1019287546eaSitojun nd6_ns_output(ifp, NULL, &(SIN6(dst)->sin6_addr), 1020287546eaSitojun ln, 0); 1021287546eaSitojun } 1022287546eaSitojun } 10230a2c5741Sitojun /* do not free mbuf here, it is queued into llinfo_nd6 */ 1024287546eaSitojun return(0); 1025287546eaSitojun } 1026287546eaSitojun #endif /* OLDIP6OUTPUT */ 1027287546eaSitojun 1028287546eaSitojun void 1029afed035cSitojun nd6_rtrequest(req, rt, info) 1030287546eaSitojun int req; 1031287546eaSitojun struct rtentry *rt; 1032afed035cSitojun struct rt_addrinfo *info; /* xxx unused */ 1033287546eaSitojun { 1034287546eaSitojun struct sockaddr *gate = rt->rt_gateway; 1035287546eaSitojun struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; 1036287546eaSitojun static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1037287546eaSitojun struct ifnet *ifp = rt->rt_ifp; 1038287546eaSitojun struct ifaddr *ifa; 1039287546eaSitojun long time_second = time.tv_sec; 1040287546eaSitojun 1041287546eaSitojun if (rt->rt_flags & RTF_GATEWAY) 1042287546eaSitojun return; 1043287546eaSitojun 1044287546eaSitojun switch (req) { 1045287546eaSitojun case RTM_ADD: 1046287546eaSitojun /* 1047287546eaSitojun * There is no backward compatibility :) 1048287546eaSitojun * 1049287546eaSitojun * if ((rt->rt_flags & RTF_HOST) == 0 && 1050287546eaSitojun * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 1051287546eaSitojun * rt->rt_flags |= RTF_CLONING; 1052287546eaSitojun */ 1053f4f4d166Sitojun if (rt->rt_flags & (RTF_CLONING | RTF_LLINFO)) { 1054287546eaSitojun /* 1055287546eaSitojun * Case 1: This route should come from 1056287546eaSitojun * a route to interface. RTF_LLINFO flag is set 1057287546eaSitojun * for a host route whose destination should be 1058287546eaSitojun * treated as on-link. 1059287546eaSitojun */ 1060287546eaSitojun rt_setgate(rt, rt_key(rt), 1061287546eaSitojun (struct sockaddr *)&null_sdl); 1062287546eaSitojun gate = rt->rt_gateway; 1063287546eaSitojun SDL(gate)->sdl_type = ifp->if_type; 1064287546eaSitojun SDL(gate)->sdl_index = ifp->if_index; 1065287546eaSitojun if (ln) 1066287546eaSitojun ln->ln_expire = time_second; 1067287546eaSitojun #if 1 1068287546eaSitojun if (ln && ln->ln_expire == 0) { 10690a2c5741Sitojun /* kludge for desktops */ 1070287546eaSitojun #if 0 1071287546eaSitojun printf("nd6_request: time.tv_sec is zero; " 1072287546eaSitojun "treat it as 1\n"); 1073287546eaSitojun #endif 1074287546eaSitojun ln->ln_expire = 1; 1075287546eaSitojun } 1076287546eaSitojun #endif 1077287546eaSitojun if (rt->rt_flags & RTF_CLONING) 1078287546eaSitojun break; 1079287546eaSitojun } 1080f4f4d166Sitojun /* 1081f4f4d166Sitojun * In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here. 1082f4f4d166Sitojun * We don't do that here since llinfo is not ready yet. 1083f4f4d166Sitojun * 1084f4f4d166Sitojun * There are also couple of other things to be discussed: 1085f4f4d166Sitojun * - unsolicited NA code needs improvement beforehand 1086f4f4d166Sitojun * - RFC2461 says we MAY send multicast unsolicited NA 1087f4f4d166Sitojun * (7.2.6 paragraph 4), however, it also says that we 1088f4f4d166Sitojun * SHOULD provide a mechanism to prevent multicast NA storm. 1089f4f4d166Sitojun * we don't have anything like it right now. 1090841d7adbSitojun * note that the mechanism needs a mutual agreement 1091f4f4d166Sitojun * between proxies, which means that we need to implement 1092841d7adbSitojun * a new protocol, or a new kludge. 1093841d7adbSitojun * - from RFC2461 6.2.4, host MUST NOT send an unsolicited NA. 1094f4f4d166Sitojun * we need to check ip6forwarding before sending it. 1095f4f4d166Sitojun * (or should we allow proxy ND configuration only for 1096f4f4d166Sitojun * routers? there's no mention about proxy ND from hosts) 1097f4f4d166Sitojun */ 1098f4f4d166Sitojun #if 0 1099f4f4d166Sitojun /* XXX it does not work */ 1100287546eaSitojun if (rt->rt_flags & RTF_ANNOUNCE) 1101287546eaSitojun nd6_na_output(ifp, 1102287546eaSitojun &SIN6(rt_key(rt))->sin6_addr, 1103287546eaSitojun &SIN6(rt_key(rt))->sin6_addr, 1104287546eaSitojun ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1105f4f4d166Sitojun 1, NULL); 1106f4f4d166Sitojun #endif 1107287546eaSitojun /* FALLTHROUGH */ 1108287546eaSitojun case RTM_RESOLVE: 1109d374aaacSitojun if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 1110d374aaacSitojun /* 1111d374aaacSitojun * Address resolution isn't necessary for a point to 1112d374aaacSitojun * point link, so we can skip this test for a p2p link. 1113d374aaacSitojun */ 1114287546eaSitojun if (gate->sa_family != AF_LINK || 1115287546eaSitojun gate->sa_len < sizeof(null_sdl)) { 1116d374aaacSitojun log(LOG_DEBUG, 11170a2c5741Sitojun "nd6_rtrequest: bad gateway value: %s\n", 11180a2c5741Sitojun if_name(ifp)); 1119287546eaSitojun break; 1120287546eaSitojun } 1121287546eaSitojun SDL(gate)->sdl_type = ifp->if_type; 1122287546eaSitojun SDL(gate)->sdl_index = ifp->if_index; 1123d374aaacSitojun } 1124d374aaacSitojun if (ln != NULL) 1125287546eaSitojun break; /* This happens on a route change */ 1126287546eaSitojun /* 1127287546eaSitojun * Case 2: This route may come from cloning, or a manual route 1128287546eaSitojun * add with a LL address. 1129287546eaSitojun */ 1130287546eaSitojun R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln)); 1131287546eaSitojun rt->rt_llinfo = (caddr_t)ln; 1132287546eaSitojun if (!ln) { 1133287546eaSitojun log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); 1134287546eaSitojun break; 1135287546eaSitojun } 1136287546eaSitojun nd6_inuse++; 1137287546eaSitojun nd6_allocated++; 1138287546eaSitojun Bzero(ln, sizeof(*ln)); 1139287546eaSitojun ln->ln_rt = rt; 1140287546eaSitojun /* this is required for "ndp" command. - shin */ 1141287546eaSitojun if (req == RTM_ADD) { 1142287546eaSitojun /* 1143287546eaSitojun * gate should have some valid AF_LINK entry, 1144287546eaSitojun * and ln->ln_expire should have some lifetime 1145287546eaSitojun * which is specified by ndp command. 1146287546eaSitojun */ 1147287546eaSitojun ln->ln_state = ND6_LLINFO_REACHABLE; 1148f6e55599Sitojun ln->ln_byhint = 0; 1149287546eaSitojun } else { 1150287546eaSitojun /* 1151287546eaSitojun * When req == RTM_RESOLVE, rt is created and 1152287546eaSitojun * initialized in rtrequest(), so rt_expire is 0. 1153287546eaSitojun */ 1154287546eaSitojun ln->ln_state = ND6_LLINFO_NOSTATE; 1155287546eaSitojun ln->ln_expire = time_second; 1156287546eaSitojun } 1157287546eaSitojun rt->rt_flags |= RTF_LLINFO; 1158287546eaSitojun ln->ln_next = llinfo_nd6.ln_next; 1159287546eaSitojun llinfo_nd6.ln_next = ln; 1160287546eaSitojun ln->ln_prev = &llinfo_nd6; 1161287546eaSitojun ln->ln_next->ln_prev = ln; 1162287546eaSitojun 1163287546eaSitojun /* 1164287546eaSitojun * check if rt_key(rt) is one of my address assigned 1165287546eaSitojun * to the interface. 1166287546eaSitojun */ 1167287546eaSitojun ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, 1168287546eaSitojun &SIN6(rt_key(rt))->sin6_addr); 1169287546eaSitojun if (ifa) { 1170287546eaSitojun caddr_t macp = nd6_ifptomac(ifp); 1171287546eaSitojun ln->ln_expire = 0; 1172287546eaSitojun ln->ln_state = ND6_LLINFO_REACHABLE; 1173f6e55599Sitojun ln->ln_byhint = 0; 1174287546eaSitojun if (macp) { 1175287546eaSitojun Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); 1176287546eaSitojun SDL(gate)->sdl_alen = ifp->if_addrlen; 1177287546eaSitojun } 1178287546eaSitojun if (nd6_useloopback) { 1179fcc641efSmickey rt->rt_ifp = lo0ifp; /*XXX*/ 1180287546eaSitojun /* 1181287546eaSitojun * Make sure rt_ifa be equal to the ifaddr 1182287546eaSitojun * corresponding to the address. 1183287546eaSitojun * We need this because when we refer 1184287546eaSitojun * rt_ifa->ia6_flags in ip6_input, we assume 1185287546eaSitojun * that the rt_ifa points to the address instead 1186287546eaSitojun * of the loopback address. 1187287546eaSitojun */ 1188287546eaSitojun if (ifa != rt->rt_ifa) { 11894f587652Sitojun IFAFREE(rt->rt_ifa); 1190287546eaSitojun ifa->ifa_refcnt++; 1191287546eaSitojun rt->rt_ifa = ifa; 1192287546eaSitojun } 1193287546eaSitojun } 1194f4f4d166Sitojun } else if (rt->rt_flags & RTF_ANNOUNCE) { 1195f4f4d166Sitojun ln->ln_expire = 0; 1196f4f4d166Sitojun ln->ln_state = ND6_LLINFO_REACHABLE; 1197f6e55599Sitojun ln->ln_byhint = 0; 1198f4f4d166Sitojun 1199f4f4d166Sitojun /* join solicited node multicast for proxy ND */ 1200f4f4d166Sitojun if (ifp->if_flags & IFF_MULTICAST) { 1201f4f4d166Sitojun struct in6_addr llsol; 1202f4f4d166Sitojun int error; 1203f4f4d166Sitojun 1204f4f4d166Sitojun llsol = SIN6(rt_key(rt))->sin6_addr; 1205f4f4d166Sitojun llsol.s6_addr16[0] = htons(0xff02); 1206f4f4d166Sitojun llsol.s6_addr16[1] = htons(ifp->if_index); 1207f4f4d166Sitojun llsol.s6_addr32[1] = 0; 1208f4f4d166Sitojun llsol.s6_addr32[2] = htonl(1); 1209f4f4d166Sitojun llsol.s6_addr8[12] = 0xff; 1210f4f4d166Sitojun 1211f4f4d166Sitojun (void)in6_addmulti(&llsol, ifp, &error); 1212f4f4d166Sitojun if (error) 1213f4f4d166Sitojun printf( 1214f4f4d166Sitojun "nd6_rtrequest: could not join solicited node multicast (errno=%d)\n", error); 1215f4f4d166Sitojun } 1216287546eaSitojun } 1217287546eaSitojun break; 1218287546eaSitojun 1219287546eaSitojun case RTM_DELETE: 1220287546eaSitojun if (!ln) 1221287546eaSitojun break; 1222f4f4d166Sitojun /* leave from solicited node multicast for proxy ND */ 1223f4f4d166Sitojun if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && 1224f4f4d166Sitojun (ifp->if_flags & IFF_MULTICAST) != 0) { 1225f4f4d166Sitojun struct in6_addr llsol; 1226f4f4d166Sitojun struct in6_multi *in6m; 1227f4f4d166Sitojun 1228f4f4d166Sitojun llsol = SIN6(rt_key(rt))->sin6_addr; 1229f4f4d166Sitojun llsol.s6_addr16[0] = htons(0xff02); 1230f4f4d166Sitojun llsol.s6_addr16[1] = htons(ifp->if_index); 1231f4f4d166Sitojun llsol.s6_addr32[1] = 0; 1232f4f4d166Sitojun llsol.s6_addr32[2] = htonl(1); 1233f4f4d166Sitojun llsol.s6_addr8[12] = 0xff; 1234f4f4d166Sitojun 1235f4f4d166Sitojun IN6_LOOKUP_MULTI(llsol, ifp, in6m); 1236f4f4d166Sitojun if (in6m) 1237f4f4d166Sitojun in6_delmulti(in6m); 1238f4f4d166Sitojun } 1239287546eaSitojun nd6_inuse--; 1240287546eaSitojun ln->ln_next->ln_prev = ln->ln_prev; 1241287546eaSitojun ln->ln_prev->ln_next = ln->ln_next; 1242287546eaSitojun ln->ln_prev = NULL; 1243287546eaSitojun rt->rt_llinfo = 0; 1244287546eaSitojun rt->rt_flags &= ~RTF_LLINFO; 1245287546eaSitojun if (ln->ln_hold) 1246287546eaSitojun m_freem(ln->ln_hold); 1247287546eaSitojun Free((caddr_t)ln); 1248287546eaSitojun } 1249287546eaSitojun } 1250287546eaSitojun 1251287546eaSitojun void 1252afed035cSitojun nd6_p2p_rtrequest(req, rt, info) 1253287546eaSitojun int req; 1254287546eaSitojun struct rtentry *rt; 1255afed035cSitojun struct rt_addrinfo *info; /* xxx unused */ 1256287546eaSitojun { 1257287546eaSitojun struct sockaddr *gate = rt->rt_gateway; 1258287546eaSitojun static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1259287546eaSitojun struct ifnet *ifp = rt->rt_ifp; 1260287546eaSitojun struct ifaddr *ifa; 1261287546eaSitojun 1262287546eaSitojun if (rt->rt_flags & RTF_GATEWAY) 1263287546eaSitojun return; 1264287546eaSitojun 1265287546eaSitojun switch (req) { 1266287546eaSitojun case RTM_ADD: 1267287546eaSitojun /* 1268287546eaSitojun * There is no backward compatibility :) 1269287546eaSitojun * 1270287546eaSitojun * if ((rt->rt_flags & RTF_HOST) == 0 && 1271287546eaSitojun * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 1272287546eaSitojun * rt->rt_flags |= RTF_CLONING; 1273287546eaSitojun */ 1274287546eaSitojun if (rt->rt_flags & RTF_CLONING) { 1275287546eaSitojun /* 1276287546eaSitojun * Case 1: This route should come from 1277287546eaSitojun * a route to interface. 1278287546eaSitojun */ 1279287546eaSitojun rt_setgate(rt, rt_key(rt), 1280287546eaSitojun (struct sockaddr *)&null_sdl); 1281287546eaSitojun gate = rt->rt_gateway; 1282287546eaSitojun SDL(gate)->sdl_type = ifp->if_type; 1283287546eaSitojun SDL(gate)->sdl_index = ifp->if_index; 1284287546eaSitojun break; 1285287546eaSitojun } 1286287546eaSitojun /* Announce a new entry if requested. */ 1287287546eaSitojun if (rt->rt_flags & RTF_ANNOUNCE) 1288287546eaSitojun nd6_na_output(ifp, 1289287546eaSitojun &SIN6(rt_key(rt))->sin6_addr, 1290287546eaSitojun &SIN6(rt_key(rt))->sin6_addr, 1291287546eaSitojun ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1292f4f4d166Sitojun 1, NULL); 1293287546eaSitojun /* FALLTHROUGH */ 1294287546eaSitojun case RTM_RESOLVE: 1295287546eaSitojun /* 1296287546eaSitojun * check if rt_key(rt) is one of my address assigned 1297287546eaSitojun * to the interface. 1298287546eaSitojun */ 1299287546eaSitojun ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, 1300287546eaSitojun &SIN6(rt_key(rt))->sin6_addr); 1301287546eaSitojun if (ifa) { 1302287546eaSitojun if (nd6_useloopback) { 1303fcc641efSmickey rt->rt_ifp = lo0ifp; /*XXX*/ 1304287546eaSitojun } 1305287546eaSitojun } 1306287546eaSitojun break; 1307287546eaSitojun } 1308287546eaSitojun } 1309287546eaSitojun 1310287546eaSitojun int 1311287546eaSitojun nd6_ioctl(cmd, data, ifp) 1312287546eaSitojun u_long cmd; 1313287546eaSitojun caddr_t data; 1314287546eaSitojun struct ifnet *ifp; 1315287546eaSitojun { 1316287546eaSitojun struct in6_drlist *drl = (struct in6_drlist *)data; 1317287546eaSitojun struct in6_prlist *prl = (struct in6_prlist *)data; 1318287546eaSitojun struct in6_ndireq *ndi = (struct in6_ndireq *)data; 1319287546eaSitojun struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; 1320f4f4d166Sitojun struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; 1321287546eaSitojun struct nd_defrouter *dr, any; 1322287546eaSitojun struct nd_prefix *pr; 1323287546eaSitojun struct rtentry *rt; 1324287546eaSitojun int i = 0, error = 0; 1325287546eaSitojun int s; 1326287546eaSitojun 1327287546eaSitojun switch (cmd) { 1328287546eaSitojun case SIOCGDRLST_IN6: 1329287546eaSitojun bzero(drl, sizeof(*drl)); 1330287546eaSitojun s = splnet(); 1331f4f4d166Sitojun dr = TAILQ_FIRST(&nd_defrouter); 1332287546eaSitojun while (dr && i < DRLSTSIZ) { 1333287546eaSitojun drl->defrouter[i].rtaddr = dr->rtaddr; 1334287546eaSitojun if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { 1335287546eaSitojun /* XXX: need to this hack for KAME stack */ 1336287546eaSitojun drl->defrouter[i].rtaddr.s6_addr16[1] = 0; 1337f6e55599Sitojun } else 1338287546eaSitojun log(LOG_ERR, 1339287546eaSitojun "default router list contains a " 1340287546eaSitojun "non-linklocal address(%s)\n", 1341287546eaSitojun ip6_sprintf(&drl->defrouter[i].rtaddr)); 1342287546eaSitojun 1343287546eaSitojun drl->defrouter[i].flags = dr->flags; 1344287546eaSitojun drl->defrouter[i].rtlifetime = dr->rtlifetime; 1345287546eaSitojun drl->defrouter[i].expire = dr->expire; 1346287546eaSitojun drl->defrouter[i].if_index = dr->ifp->if_index; 1347287546eaSitojun i++; 1348f4f4d166Sitojun dr = TAILQ_NEXT(dr, dr_entry); 1349287546eaSitojun } 1350287546eaSitojun splx(s); 1351287546eaSitojun break; 1352287546eaSitojun case SIOCGPRLST_IN6: 1353f4f4d166Sitojun /* 1354f4f4d166Sitojun * XXX meaning of fields, especialy "raflags", is very 1355f4f4d166Sitojun * differnet between RA prefix list and RR/static prefix list. 1356f4f4d166Sitojun * how about separating ioctls into two? 1357f4f4d166Sitojun */ 1358287546eaSitojun bzero(prl, sizeof(*prl)); 1359287546eaSitojun s = splnet(); 1360287546eaSitojun pr = nd_prefix.lh_first; 1361287546eaSitojun while (pr && i < PRLSTSIZ) { 1362287546eaSitojun struct nd_pfxrouter *pfr; 1363287546eaSitojun int j; 1364287546eaSitojun 1365287546eaSitojun prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; 1366287546eaSitojun prl->prefix[i].raflags = pr->ndpr_raf; 1367287546eaSitojun prl->prefix[i].prefixlen = pr->ndpr_plen; 1368287546eaSitojun prl->prefix[i].vltime = pr->ndpr_vltime; 1369287546eaSitojun prl->prefix[i].pltime = pr->ndpr_pltime; 1370287546eaSitojun prl->prefix[i].if_index = pr->ndpr_ifp->if_index; 1371287546eaSitojun prl->prefix[i].expire = pr->ndpr_expire; 1372287546eaSitojun 1373287546eaSitojun pfr = pr->ndpr_advrtrs.lh_first; 1374287546eaSitojun j = 0; 1375287546eaSitojun while(pfr) { 1376287546eaSitojun if (j < DRLSTSIZ) { 1377287546eaSitojun #define RTRADDR prl->prefix[i].advrtr[j] 1378287546eaSitojun RTRADDR = pfr->router->rtaddr; 1379287546eaSitojun if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) { 1380287546eaSitojun /* XXX: hack for KAME */ 1381287546eaSitojun RTRADDR.s6_addr16[1] = 0; 1382f6e55599Sitojun } else 1383287546eaSitojun log(LOG_ERR, 1384287546eaSitojun "a router(%s) advertises " 1385287546eaSitojun "a prefix with " 1386287546eaSitojun "non-link local address\n", 1387287546eaSitojun ip6_sprintf(&RTRADDR)); 1388287546eaSitojun #undef RTRADDR 1389287546eaSitojun } 1390287546eaSitojun j++; 1391287546eaSitojun pfr = pfr->pfr_next; 1392287546eaSitojun } 1393287546eaSitojun prl->prefix[i].advrtrs = j; 1394f4f4d166Sitojun prl->prefix[i].origin = PR_ORIG_RA; 1395287546eaSitojun 1396287546eaSitojun i++; 1397287546eaSitojun pr = pr->ndpr_next; 1398287546eaSitojun } 1399287546eaSitojun { 1400287546eaSitojun struct rr_prefix *rpp; 1401287546eaSitojun 1402287546eaSitojun for (rpp = LIST_FIRST(&rr_prefix); rpp; 1403287546eaSitojun rpp = LIST_NEXT(rpp, rp_entry)) { 1404287546eaSitojun if (i >= PRLSTSIZ) 1405287546eaSitojun break; 1406287546eaSitojun prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; 1407287546eaSitojun prl->prefix[i].raflags = rpp->rp_raf; 1408287546eaSitojun prl->prefix[i].prefixlen = rpp->rp_plen; 1409287546eaSitojun prl->prefix[i].vltime = rpp->rp_vltime; 1410287546eaSitojun prl->prefix[i].pltime = rpp->rp_pltime; 1411287546eaSitojun prl->prefix[i].if_index = rpp->rp_ifp->if_index; 1412287546eaSitojun prl->prefix[i].expire = rpp->rp_expire; 1413287546eaSitojun prl->prefix[i].advrtrs = 0; 1414f4f4d166Sitojun prl->prefix[i].origin = rpp->rp_origin; 1415287546eaSitojun i++; 1416287546eaSitojun } 1417287546eaSitojun } 1418f4f4d166Sitojun splx(s); 1419287546eaSitojun 1420287546eaSitojun break; 1421287546eaSitojun case SIOCGIFINFO_IN6: 1422cfab95f2Sitojun if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { 1423cfab95f2Sitojun error = EINVAL; 1424cfab95f2Sitojun break; 1425cfab95f2Sitojun } 1426287546eaSitojun ndi->ndi = nd_ifinfo[ifp->if_index]; 1427287546eaSitojun break; 1428d374aaacSitojun case SIOCSIFINFO_FLAGS: 1429d374aaacSitojun /* XXX: almost all other fields of ndi->ndi is unused */ 1430cfab95f2Sitojun if (!nd_ifinfo || i >= nd_ifinfo_indexlim) { 1431cfab95f2Sitojun error = EINVAL; 1432cfab95f2Sitojun break; 1433cfab95f2Sitojun } 1434d374aaacSitojun nd_ifinfo[ifp->if_index].flags = ndi->ndi.flags; 1435d374aaacSitojun break; 1436f4f4d166Sitojun case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ 1437287546eaSitojun /* flush default router list */ 1438287546eaSitojun /* 1439287546eaSitojun * xxx sumikawa: should not delete route if default 1440287546eaSitojun * route equals to the top of default router list 1441287546eaSitojun */ 1442287546eaSitojun bzero(&any, sizeof(any)); 1443287546eaSitojun defrouter_delreq(&any, 0); 1444f4f4d166Sitojun defrouter_select(); 1445287546eaSitojun /* xxx sumikawa: flush prefix list */ 1446287546eaSitojun break; 1447287546eaSitojun case SIOCSPFXFLUSH_IN6: 1448287546eaSitojun { 1449287546eaSitojun /* flush all the prefix advertised by routers */ 1450287546eaSitojun struct nd_prefix *pr, *next; 1451287546eaSitojun 1452287546eaSitojun s = splnet(); 145358aa7d74Sangelos 1454287546eaSitojun for (pr = nd_prefix.lh_first; pr; pr = next) { 1455287546eaSitojun next = pr->ndpr_next; 1456287546eaSitojun if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 1457287546eaSitojun in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 1458287546eaSitojun prelist_remove(pr); 1459287546eaSitojun } 1460287546eaSitojun splx(s); 1461287546eaSitojun break; 1462287546eaSitojun } 1463287546eaSitojun case SIOCSRTRFLUSH_IN6: 1464287546eaSitojun { 1465287546eaSitojun /* flush all the default routers */ 1466287546eaSitojun struct nd_defrouter *dr, *next; 1467287546eaSitojun 1468287546eaSitojun s = splnet(); 1469f4f4d166Sitojun if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { 1470287546eaSitojun /* 1471287546eaSitojun * The first entry of the list may be stored in 1472287546eaSitojun * the routing table, so we'll delete it later. 1473287546eaSitojun */ 1474f4f4d166Sitojun for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = next) { 1475f4f4d166Sitojun next = TAILQ_NEXT(dr, dr_entry); 1476287546eaSitojun defrtrlist_del(dr); 1477287546eaSitojun } 1478f4f4d166Sitojun defrtrlist_del(TAILQ_FIRST(&nd_defrouter)); 1479287546eaSitojun } 1480287546eaSitojun splx(s); 1481287546eaSitojun break; 1482287546eaSitojun } 1483287546eaSitojun case SIOCGNBRINFO_IN6: 1484287546eaSitojun { 1485287546eaSitojun struct llinfo_nd6 *ln; 1486287546eaSitojun struct in6_addr nb_addr = nbi->addr; /* make local for safety */ 1487287546eaSitojun 1488287546eaSitojun /* 1489287546eaSitojun * XXX: KAME specific hack for scoped addresses 1490287546eaSitojun * XXXX: for other scopes than link-local? 1491287546eaSitojun */ 1492287546eaSitojun if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) || 1493287546eaSitojun IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) { 1494287546eaSitojun u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2]; 1495287546eaSitojun 1496287546eaSitojun if (*idp == 0) 1497287546eaSitojun *idp = htons(ifp->if_index); 1498287546eaSitojun } 1499287546eaSitojun 1500287546eaSitojun s = splnet(); 150158aa7d74Sangelos 1502287546eaSitojun if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { 1503287546eaSitojun error = EINVAL; 150491e69634Sitojun splx(s); 1505287546eaSitojun break; 1506287546eaSitojun } 1507287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 1508287546eaSitojun nbi->state = ln->ln_state; 1509287546eaSitojun nbi->asked = ln->ln_asked; 1510287546eaSitojun nbi->isrouter = ln->ln_router; 1511287546eaSitojun nbi->expire = ln->ln_expire; 1512287546eaSitojun splx(s); 1513287546eaSitojun 1514287546eaSitojun break; 1515287546eaSitojun } 1516f4f4d166Sitojun case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ 1517f4f4d166Sitojun ndif->ifindex = nd6_defifindex; 1518f4f4d166Sitojun break; 1519f4f4d166Sitojun case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ 1520f4f4d166Sitojun return(nd6_setdefaultiface(ndif->ifindex)); 1521f4f4d166Sitojun break; 1522287546eaSitojun } 1523287546eaSitojun return(error); 1524287546eaSitojun } 1525287546eaSitojun 1526287546eaSitojun /* 1527287546eaSitojun * Create neighbor cache entry and cache link-layer address, 1528287546eaSitojun * on reception of inbound ND6 packets. (RS/RA/NS/redirect) 1529287546eaSitojun */ 1530287546eaSitojun struct rtentry * 1531287546eaSitojun nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) 1532287546eaSitojun struct ifnet *ifp; 1533287546eaSitojun struct in6_addr *from; 1534287546eaSitojun char *lladdr; 1535287546eaSitojun int lladdrlen; 1536287546eaSitojun int type; /* ICMP6 type */ 1537287546eaSitojun int code; /* type dependent information */ 1538287546eaSitojun { 1539287546eaSitojun struct rtentry *rt = NULL; 1540287546eaSitojun struct llinfo_nd6 *ln = NULL; 1541287546eaSitojun int is_newentry; 1542287546eaSitojun struct sockaddr_dl *sdl = NULL; 1543287546eaSitojun int do_update; 1544287546eaSitojun int olladdr; 1545287546eaSitojun int llchange; 1546287546eaSitojun int newstate = 0; 1547287546eaSitojun long time_second = time.tv_sec; 1548287546eaSitojun 1549287546eaSitojun if (!ifp) 1550287546eaSitojun panic("ifp == NULL in nd6_cache_lladdr"); 1551287546eaSitojun if (!from) 1552287546eaSitojun panic("from == NULL in nd6_cache_lladdr"); 1553287546eaSitojun 1554287546eaSitojun /* nothing must be updated for unspecified address */ 1555287546eaSitojun if (IN6_IS_ADDR_UNSPECIFIED(from)) 1556287546eaSitojun return NULL; 1557287546eaSitojun 1558287546eaSitojun /* 1559287546eaSitojun * Validation about ifp->if_addrlen and lladdrlen must be done in 1560287546eaSitojun * the caller. 1561287546eaSitojun * 1562287546eaSitojun * XXX If the link does not have link-layer adderss, what should 1563287546eaSitojun * we do? (ifp->if_addrlen == 0) 1564287546eaSitojun * Spec says nothing in sections for RA, RS and NA. There's small 1565287546eaSitojun * description on it in NS section (RFC 2461 7.2.3). 1566287546eaSitojun */ 1567287546eaSitojun 1568287546eaSitojun rt = nd6_lookup(from, 0, ifp); 1569287546eaSitojun if (!rt) { 1570287546eaSitojun #if 0 1571287546eaSitojun /* nothing must be done if there's no lladdr */ 1572287546eaSitojun if (!lladdr || !lladdrlen) 1573287546eaSitojun return NULL; 1574287546eaSitojun #endif 1575287546eaSitojun 1576287546eaSitojun rt = nd6_lookup(from, 1, ifp); 1577287546eaSitojun is_newentry = 1; 15780a2c5741Sitojun } else { 15790a2c5741Sitojun /* do nothing if static ndp is set */ 15800a2c5741Sitojun if (rt->rt_flags & RTF_STATIC) 15810a2c5741Sitojun return NULL; 1582287546eaSitojun is_newentry = 0; 15830a2c5741Sitojun } 1584287546eaSitojun 1585287546eaSitojun if (!rt) 1586287546eaSitojun return NULL; 1587287546eaSitojun if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { 1588287546eaSitojun fail: 158929760ae1Sitojun (void)nd6_free(rt); 1590287546eaSitojun return NULL; 1591287546eaSitojun } 1592287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 1593287546eaSitojun if (!ln) 1594287546eaSitojun goto fail; 1595287546eaSitojun if (!rt->rt_gateway) 1596287546eaSitojun goto fail; 1597287546eaSitojun if (rt->rt_gateway->sa_family != AF_LINK) 1598287546eaSitojun goto fail; 1599287546eaSitojun sdl = SDL(rt->rt_gateway); 1600287546eaSitojun 1601287546eaSitojun olladdr = (sdl->sdl_alen) ? 1 : 0; 1602287546eaSitojun if (olladdr && lladdr) { 1603287546eaSitojun if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen)) 1604287546eaSitojun llchange = 1; 1605287546eaSitojun else 1606287546eaSitojun llchange = 0; 1607287546eaSitojun } else 1608287546eaSitojun llchange = 0; 1609287546eaSitojun 1610287546eaSitojun /* 1611287546eaSitojun * newentry olladdr lladdr llchange (*=record) 1612287546eaSitojun * 0 n n -- (1) 1613287546eaSitojun * 0 y n -- (2) 1614287546eaSitojun * 0 n y -- (3) * STALE 1615287546eaSitojun * 0 y y n (4) * 1616287546eaSitojun * 0 y y y (5) * STALE 1617287546eaSitojun * 1 -- n -- (6) NOSTATE(= PASSIVE) 1618287546eaSitojun * 1 -- y -- (7) * STALE 1619287546eaSitojun */ 1620287546eaSitojun 1621287546eaSitojun if (lladdr) { /*(3-5) and (7)*/ 1622287546eaSitojun /* 1623287546eaSitojun * Record source link-layer address 1624287546eaSitojun * XXX is it dependent to ifp->if_type? 1625287546eaSitojun */ 1626287546eaSitojun sdl->sdl_alen = ifp->if_addrlen; 1627287546eaSitojun bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); 1628287546eaSitojun } 1629287546eaSitojun 1630287546eaSitojun if (!is_newentry) { 1631287546eaSitojun if ((!olladdr && lladdr) /*(3)*/ 1632287546eaSitojun || (olladdr && lladdr && llchange)) { /*(5)*/ 1633287546eaSitojun do_update = 1; 1634287546eaSitojun newstate = ND6_LLINFO_STALE; 1635287546eaSitojun } else /*(1-2,4)*/ 1636287546eaSitojun do_update = 0; 1637287546eaSitojun } else { 1638287546eaSitojun do_update = 1; 1639287546eaSitojun if (!lladdr) /*(6)*/ 1640287546eaSitojun newstate = ND6_LLINFO_NOSTATE; 1641287546eaSitojun else /*(7)*/ 1642287546eaSitojun newstate = ND6_LLINFO_STALE; 1643287546eaSitojun } 1644287546eaSitojun 1645287546eaSitojun if (do_update) { 1646287546eaSitojun /* 1647287546eaSitojun * Update the state of the neighbor cache. 1648287546eaSitojun */ 1649287546eaSitojun ln->ln_state = newstate; 1650287546eaSitojun 1651287546eaSitojun if (ln->ln_state == ND6_LLINFO_STALE) { 1652*8a7bb304Sitojun /* 1653*8a7bb304Sitojun * XXX: since nd6_output() below will cause 1654*8a7bb304Sitojun * state tansition to DELAY and reset the timer, 1655*8a7bb304Sitojun * we must set the timer now, although it is actually 1656*8a7bb304Sitojun * meaningless. 1657*8a7bb304Sitojun */ 1658*8a7bb304Sitojun ln->ln_expire = time_second + nd6_gctimer; 1659*8a7bb304Sitojun 1660287546eaSitojun if (ln->ln_hold) { 1661287546eaSitojun #ifdef OLDIP6OUTPUT 1662*8a7bb304Sitojun ln->ln_asked = 0; 1663*8a7bb304Sitojun ln->ln_state = ND6_LLINFO_DELAY; 1664*8a7bb304Sitojun ln->ln_expire = time_second + nd6_delay; 1665287546eaSitojun (*ifp->if_output)(ifp, ln->ln_hold, 1666287546eaSitojun rt_key(rt), rt); 1667287546eaSitojun #else 16686afad192Sitojun /* 16696afad192Sitojun * we assume ifp is not a p2p here, so just 16706afad192Sitojun * set the 2nd argument as the 1st one. 16716afad192Sitojun */ 16726afad192Sitojun nd6_output(ifp, ifp, ln->ln_hold, 1673287546eaSitojun (struct sockaddr_in6 *)rt_key(rt), 1674287546eaSitojun rt); 1675287546eaSitojun #endif 1676*8a7bb304Sitojun ln->ln_hold = NULL; 1677287546eaSitojun } 1678287546eaSitojun } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { 1679287546eaSitojun /* probe right away */ 1680287546eaSitojun ln->ln_expire = time_second; 1681287546eaSitojun } 1682287546eaSitojun } 1683287546eaSitojun 1684287546eaSitojun /* 1685287546eaSitojun * ICMP6 type dependent behavior. 1686287546eaSitojun * 1687287546eaSitojun * NS: clear IsRouter if new entry 1688287546eaSitojun * RS: clear IsRouter 1689287546eaSitojun * RA: set IsRouter if there's lladdr 1690287546eaSitojun * redir: clear IsRouter if new entry 1691287546eaSitojun * 1692287546eaSitojun * RA case, (1): 1693287546eaSitojun * The spec says that we must set IsRouter in the following cases: 1694287546eaSitojun * - If lladdr exist, set IsRouter. This means (1-5). 1695287546eaSitojun * - If it is old entry (!newentry), set IsRouter. This means (7). 1696287546eaSitojun * So, based on the spec, in (1-5) and (7) cases we must set IsRouter. 1697287546eaSitojun * A quetion arises for (1) case. (1) case has no lladdr in the 1698287546eaSitojun * neighbor cache, this is similar to (6). 1699287546eaSitojun * This case is rare but we figured that we MUST NOT set IsRouter. 1700287546eaSitojun * 1701287546eaSitojun * newentry olladdr lladdr llchange NS RS RA redir 1702287546eaSitojun * D R 1703287546eaSitojun * 0 n n -- (1) c ? s 1704287546eaSitojun * 0 y n -- (2) c s s 1705287546eaSitojun * 0 n y -- (3) c s s 1706287546eaSitojun * 0 y y n (4) c s s 1707287546eaSitojun * 0 y y y (5) c s s 1708287546eaSitojun * 1 -- n -- (6) c c c s 1709287546eaSitojun * 1 -- y -- (7) c c s c s 1710287546eaSitojun * 1711287546eaSitojun * (c=clear s=set) 1712287546eaSitojun */ 1713287546eaSitojun switch (type & 0xff) { 1714287546eaSitojun case ND_NEIGHBOR_SOLICIT: 1715287546eaSitojun /* 1716287546eaSitojun * New entry must have is_router flag cleared. 1717287546eaSitojun */ 1718287546eaSitojun if (is_newentry) /*(6-7)*/ 1719287546eaSitojun ln->ln_router = 0; 1720287546eaSitojun break; 1721287546eaSitojun case ND_REDIRECT: 1722287546eaSitojun /* 1723287546eaSitojun * If the icmp is a redirect to a better router, always set the 1724287546eaSitojun * is_router flag. Otherwise, if the entry is newly created, 1725287546eaSitojun * clear the flag. [RFC 2461, sec 8.3] 1726287546eaSitojun */ 1727287546eaSitojun if (code == ND_REDIRECT_ROUTER) 1728287546eaSitojun ln->ln_router = 1; 1729287546eaSitojun else if (is_newentry) /*(6-7)*/ 1730287546eaSitojun ln->ln_router = 0; 1731287546eaSitojun break; 1732287546eaSitojun case ND_ROUTER_SOLICIT: 1733287546eaSitojun /* 1734287546eaSitojun * is_router flag must always be cleared. 1735287546eaSitojun */ 1736287546eaSitojun ln->ln_router = 0; 1737287546eaSitojun break; 1738287546eaSitojun case ND_ROUTER_ADVERT: 1739287546eaSitojun /* 1740287546eaSitojun * Mark an entry with lladdr as a router. 1741287546eaSitojun */ 1742287546eaSitojun if ((!is_newentry && (olladdr || lladdr)) /*(2-5)*/ 1743287546eaSitojun || (is_newentry && lladdr)) { /*(7)*/ 1744287546eaSitojun ln->ln_router = 1; 1745287546eaSitojun } 1746287546eaSitojun break; 1747287546eaSitojun } 1748287546eaSitojun 1749287546eaSitojun return rt; 1750287546eaSitojun } 1751287546eaSitojun 1752287546eaSitojun static void 1753287546eaSitojun nd6_slowtimo(ignored_arg) 1754287546eaSitojun void *ignored_arg; 1755287546eaSitojun { 1756287546eaSitojun int s = splnet(); 1757b3c1e4c1Sitojun int i; 1758b3c1e4c1Sitojun struct nd_ifinfo *nd6if; 1759287546eaSitojun 1760b3c1e4c1Sitojun timeout_set(&nd6_slowtimo_ch, nd6_slowtimo, NULL); 1761b3c1e4c1Sitojun timeout_add(&nd6_slowtimo_ch, ND6_SLOWTIMER_INTERVAL * hz); 1762287546eaSitojun for (i = 1; i < if_index + 1; i++) { 1763cfab95f2Sitojun if (!nd_ifinfo || i >= nd_ifinfo_indexlim) 1764cfab95f2Sitojun continue; 1765287546eaSitojun nd6if = &nd_ifinfo[i]; 1766287546eaSitojun if (nd6if->basereachable && /* already initialized */ 1767287546eaSitojun (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { 1768287546eaSitojun /* 1769287546eaSitojun * Since reachable time rarely changes by router 1770287546eaSitojun * advertisements, we SHOULD insure that a new random 1771287546eaSitojun * value gets recomputed at least once every few hours. 1772287546eaSitojun * (RFC 2461, 6.3.4) 1773287546eaSitojun */ 1774287546eaSitojun nd6if->recalctm = nd6_recalc_reachtm_interval; 1775287546eaSitojun nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable); 1776287546eaSitojun } 1777287546eaSitojun } 1778287546eaSitojun splx(s); 1779287546eaSitojun } 1780287546eaSitojun 1781287546eaSitojun #define senderr(e) { error = (e); goto bad;} 1782287546eaSitojun int 17836afad192Sitojun nd6_output(ifp, origifp, m0, dst, rt0) 1784b3c1e4c1Sitojun struct ifnet *ifp; 17856afad192Sitojun struct ifnet *origifp; 1786287546eaSitojun struct mbuf *m0; 1787287546eaSitojun struct sockaddr_in6 *dst; 1788287546eaSitojun struct rtentry *rt0; 1789287546eaSitojun { 1790b3c1e4c1Sitojun struct mbuf *m = m0; 1791b3c1e4c1Sitojun struct rtentry *rt = rt0; 1792cfb6b8dfSitojun struct sockaddr_in6 *gw6 = NULL; 1793287546eaSitojun struct llinfo_nd6 *ln = NULL; 1794287546eaSitojun int error = 0; 1795287546eaSitojun long time_second = time.tv_sec; 1796287546eaSitojun 1797287546eaSitojun if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) 1798287546eaSitojun goto sendpkt; 1799287546eaSitojun 1800287546eaSitojun /* 1801287546eaSitojun * XXX: we currently do not make neighbor cache on any interface 1802d374aaacSitojun * other than ARCnet, Ethernet, FDDI and GIF. 1803d374aaacSitojun * 18044f2433d9Sitojun * RFC2893 says: 1805d374aaacSitojun * - unidirectional tunnels needs no ND 1806287546eaSitojun */ 1807287546eaSitojun switch (ifp->if_type) { 1808287546eaSitojun case IFT_ARCNET: 1809287546eaSitojun case IFT_ETHER: 1810287546eaSitojun case IFT_FDDI: 1811d374aaacSitojun case IFT_GIF: /* XXX need more cases? */ 1812287546eaSitojun break; 1813287546eaSitojun default: 1814287546eaSitojun goto sendpkt; 1815287546eaSitojun } 1816287546eaSitojun 1817287546eaSitojun /* 1818287546eaSitojun * next hop determination. This routine is derived from ether_outpout. 1819287546eaSitojun */ 1820287546eaSitojun if (rt) { 1821287546eaSitojun if ((rt->rt_flags & RTF_UP) == 0) { 1822287546eaSitojun if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != 1823287546eaSitojun NULL) 1824287546eaSitojun { 1825287546eaSitojun rt->rt_refcnt--; 18266afad192Sitojun if (rt->rt_ifp != ifp) { 18276afad192Sitojun /* XXX: loop care? */ 18286afad192Sitojun return nd6_output(ifp, origifp, m0, 18296afad192Sitojun dst, rt); 18306afad192Sitojun } 1831287546eaSitojun } else 1832287546eaSitojun senderr(EHOSTUNREACH); 1833287546eaSitojun } 1834cfb6b8dfSitojun 1835287546eaSitojun if (rt->rt_flags & RTF_GATEWAY) { 1836cfb6b8dfSitojun gw6 = (struct sockaddr_in6 *)rt->rt_gateway; 1837cfb6b8dfSitojun 1838cfb6b8dfSitojun /* 1839cfb6b8dfSitojun * We skip link-layer address resolution and NUD 1840cfb6b8dfSitojun * if the gateway is not a neighbor from ND point 18414f2433d9Sitojun * of view, regardless the value of the 1842cfb6b8dfSitojun * nd_ifinfo.flags. 1843cfb6b8dfSitojun * The second condition is a bit tricky: we skip 1844cfb6b8dfSitojun * if the gateway is our own address, which is 1845cfb6b8dfSitojun * sometimes used to install a route to a p2p link. 1846cfb6b8dfSitojun */ 1847cfb6b8dfSitojun if (!nd6_is_addr_neighbor(gw6, ifp) || 1848cfb6b8dfSitojun in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { 1849cfb6b8dfSitojun /* 1850cfb6b8dfSitojun * We allow this kind of tricky route only 1851cfb6b8dfSitojun * when the outgoing interface is p2p. 1852cfb6b8dfSitojun * XXX: we may need a more generic rule here. 1853cfb6b8dfSitojun */ 1854cfb6b8dfSitojun if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 1855cfb6b8dfSitojun senderr(EHOSTUNREACH); 1856cfb6b8dfSitojun 1857cfb6b8dfSitojun goto sendpkt; 1858cfb6b8dfSitojun } 1859cfb6b8dfSitojun 1860287546eaSitojun if (rt->rt_gwroute == 0) 1861287546eaSitojun goto lookup; 1862287546eaSitojun if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 1863287546eaSitojun rtfree(rt); rt = rt0; 1864287546eaSitojun lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); 1865287546eaSitojun if ((rt = rt->rt_gwroute) == 0) 1866287546eaSitojun senderr(EHOSTUNREACH); 1867287546eaSitojun } 1868287546eaSitojun } 1869287546eaSitojun } 1870287546eaSitojun 1871287546eaSitojun /* 1872287546eaSitojun * Address resolution or Neighbor Unreachability Detection 1873287546eaSitojun * for the next hop. 1874287546eaSitojun * At this point, the destination of the packet must be a unicast 1875287546eaSitojun * or an anycast address(i.e. not a multicast). 1876287546eaSitojun */ 1877287546eaSitojun 1878287546eaSitojun /* Look up the neighbor cache for the nexthop */ 1879287546eaSitojun if (rt && (rt->rt_flags & RTF_LLINFO) != 0) 1880287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 1881287546eaSitojun else { 1882cfb6b8dfSitojun /* 1883cfb6b8dfSitojun * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), 1884cfb6b8dfSitojun * the condition below is not very efficient. But we believe 1885cfb6b8dfSitojun * it is tolerable, because this should be a rare case. 1886cfb6b8dfSitojun */ 1887cfb6b8dfSitojun if (nd6_is_addr_neighbor(dst, ifp) && 1888cfb6b8dfSitojun (rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) 1889287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 1890287546eaSitojun } 1891287546eaSitojun if (!ln || !rt) { 1892cfb6b8dfSitojun if ((ifp->if_flags & IFF_POINTOPOINT) == 0 && 1893cfb6b8dfSitojun !(nd_ifinfo[ifp->if_index].flags & ND6_IFF_PERFORMNUD)) { 1894cfb6b8dfSitojun log(LOG_DEBUG, 1895cfb6b8dfSitojun "nd6_output: can't allocate llinfo for %s " 1896287546eaSitojun "(ln=%p, rt=%p)\n", 1897287546eaSitojun ip6_sprintf(&dst->sin6_addr), ln, rt); 1898287546eaSitojun senderr(EIO); /* XXX: good error? */ 1899287546eaSitojun } 1900287546eaSitojun 1901cfb6b8dfSitojun goto sendpkt; /* send anyway */ 1902cfb6b8dfSitojun } 1903cfb6b8dfSitojun 1904d374aaacSitojun /* We don't have to do link-layer address resolution on a p2p link. */ 1905d374aaacSitojun if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 1906be4e9e12Sitojun ln->ln_state < ND6_LLINFO_REACHABLE) { 1907d374aaacSitojun ln->ln_state = ND6_LLINFO_STALE; 1908be4e9e12Sitojun ln->ln_expire = time_second + nd6_gctimer; 1909be4e9e12Sitojun } 1910287546eaSitojun 1911287546eaSitojun /* 1912287546eaSitojun * The first time we send a packet to a neighbor whose entry is 1913287546eaSitojun * STALE, we have to change the state to DELAY and a sets a timer to 1914287546eaSitojun * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do 1915287546eaSitojun * neighbor unreachability detection on expiration. 1916287546eaSitojun * (RFC 2461 7.3.3) 1917287546eaSitojun */ 1918287546eaSitojun if (ln->ln_state == ND6_LLINFO_STALE) { 1919287546eaSitojun ln->ln_asked = 0; 1920287546eaSitojun ln->ln_state = ND6_LLINFO_DELAY; 1921287546eaSitojun ln->ln_expire = time_second + nd6_delay; 1922287546eaSitojun } 1923287546eaSitojun 1924287546eaSitojun /* 1925287546eaSitojun * If the neighbor cache entry has a state other than INCOMPLETE 1926287546eaSitojun * (i.e. its link-layer address is already reloved), just 1927287546eaSitojun * send the packet. 1928287546eaSitojun */ 1929287546eaSitojun if (ln->ln_state > ND6_LLINFO_INCOMPLETE) 1930287546eaSitojun goto sendpkt; 1931287546eaSitojun 1932287546eaSitojun /* 1933287546eaSitojun * There is a neighbor cache entry, but no ethernet address 1934287546eaSitojun * response yet. Replace the held mbuf (if any) with this 1935287546eaSitojun * latest one. 1936287546eaSitojun * 1937287546eaSitojun * XXX Does the code conform to rate-limiting rule? 1938287546eaSitojun * (RFC 2461 7.2.2) 1939287546eaSitojun */ 1940efcf292bSitojun if (ln->ln_state == ND6_LLINFO_NOSTATE) 1941287546eaSitojun ln->ln_state = ND6_LLINFO_INCOMPLETE; 1942287546eaSitojun if (ln->ln_hold) 1943287546eaSitojun m_freem(ln->ln_hold); 1944287546eaSitojun ln->ln_hold = m; 1945287546eaSitojun if (ln->ln_expire) { 1946287546eaSitojun if (ln->ln_asked < nd6_mmaxtries && 1947287546eaSitojun ln->ln_expire < time_second) { 1948287546eaSitojun ln->ln_asked++; 1949287546eaSitojun ln->ln_expire = time_second + 1950287546eaSitojun nd_ifinfo[ifp->if_index].retrans / 1000; 1951287546eaSitojun nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); 1952287546eaSitojun } 1953287546eaSitojun } 1954287546eaSitojun return(0); 1955287546eaSitojun 1956287546eaSitojun sendpkt: 19576afad192Sitojun 19586afad192Sitojun #ifdef FAKE_LOOPBACK_IF 19590a2c5741Sitojun if ((ifp->if_flags & IFF_LOOPBACK) != 0) { 19606afad192Sitojun return((*ifp->if_output)(origifp, m, (struct sockaddr *)dst, 19616afad192Sitojun rt)); 19626afad192Sitojun } 19636afad192Sitojun #endif 1964287546eaSitojun return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); 1965287546eaSitojun 1966287546eaSitojun bad: 1967287546eaSitojun if (m) 1968287546eaSitojun m_freem(m); 1969287546eaSitojun return (error); 1970287546eaSitojun } 1971287546eaSitojun #undef senderr 1972287546eaSitojun 1973287546eaSitojun int 1974287546eaSitojun nd6_storelladdr(ifp, rt, m, dst, desten) 1975287546eaSitojun struct ifnet *ifp; 1976287546eaSitojun struct rtentry *rt; 1977287546eaSitojun struct mbuf *m; 1978287546eaSitojun struct sockaddr *dst; 1979287546eaSitojun u_char *desten; 1980287546eaSitojun { 1981287546eaSitojun struct sockaddr_dl *sdl; 1982287546eaSitojun 1983287546eaSitojun if (m->m_flags & M_MCAST) { 1984287546eaSitojun switch (ifp->if_type) { 1985287546eaSitojun case IFT_ETHER: 1986287546eaSitojun case IFT_FDDI: 1987287546eaSitojun ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, 1988287546eaSitojun desten); 1989287546eaSitojun return(1); 1990287546eaSitojun break; 1991287546eaSitojun case IFT_ARCNET: 1992287546eaSitojun *desten = 0; 1993287546eaSitojun return(1); 1994287546eaSitojun default: 19950a2c5741Sitojun m_freem(m); 1996287546eaSitojun return(0); 1997287546eaSitojun } 1998287546eaSitojun } 1999287546eaSitojun 200072e30262Sitojun if (rt == NULL) { 200172e30262Sitojun /* this could happen, if we could not allocate memory */ 20020a2c5741Sitojun m_freem(m); 200372e30262Sitojun return(0); 200472e30262Sitojun } 200572e30262Sitojun if (rt->rt_gateway->sa_family != AF_LINK) { 2006287546eaSitojun printf("nd6_storelladdr: something odd happens\n"); 20070a2c5741Sitojun m_freem(m); 2008287546eaSitojun return(0); 2009287546eaSitojun } 2010287546eaSitojun sdl = SDL(rt->rt_gateway); 2011b4ee66fcSitojun if (sdl->sdl_alen == 0) { 2012bd2806bcSitojun /* this should be impossible, but we bark here for debugging */ 2013b4ee66fcSitojun printf("nd6_storelladdr: sdl_alen == 0\n"); 20140a2c5741Sitojun m_freem(m); 2015b4ee66fcSitojun return(0); 2016b4ee66fcSitojun } 2017287546eaSitojun 2018b4ee66fcSitojun bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 2019287546eaSitojun return(1); 2020287546eaSitojun } 2021