1*f4f4d166Sitojun /* $OpenBSD: nd6.c,v 1.7 2000/02/28 11:55:22 itojun Exp $ */ 2*f4f4d166Sitojun /* $KAME: nd6.c,v 1.41 2000/02/24 16:34:50 itojun 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> 43287546eaSitojun #include <sys/malloc.h> 44287546eaSitojun #include <sys/mbuf.h> 45287546eaSitojun #include <sys/socket.h> 46287546eaSitojun #include <sys/sockio.h> 47287546eaSitojun #include <sys/time.h> 48287546eaSitojun #include <sys/kernel.h> 49*f4f4d166Sitojun #include <sys/protosw.h> 50287546eaSitojun #include <sys/errno.h> 51287546eaSitojun #include <sys/ioctl.h> 52287546eaSitojun #include <sys/syslog.h> 53287546eaSitojun #include <sys/queue.h> 543c4c637fSangelos #include <dev/rndvar.h> 55287546eaSitojun 56287546eaSitojun #include <net/if.h> 57287546eaSitojun #include <net/if_dl.h> 58287546eaSitojun #include <net/if_types.h> 59287546eaSitojun #include <net/if_atm.h> 60287546eaSitojun #include <net/route.h> 61287546eaSitojun 62287546eaSitojun #include <netinet/in.h> 63287546eaSitojun #include <netinet/if_ether.h> 6458aa7d74Sangelos 65287546eaSitojun #include <netinet6/in6_var.h> 66fa86ee14Sitojun #include <netinet/ip6.h> 67287546eaSitojun #include <netinet6/ip6_var.h> 68287546eaSitojun #include <netinet6/nd6.h> 69287546eaSitojun #include <netinet6/in6_prefix.h> 70fa86ee14Sitojun #include <netinet/icmp6.h> 71287546eaSitojun 72287546eaSitojun #include "loop.h" 7358aa7d74Sangelos 74287546eaSitojun extern struct ifnet loif[NLOOP]; 75287546eaSitojun 76287546eaSitojun #include <net/net_osdep.h> 77287546eaSitojun 78287546eaSitojun #define ND6_SLOWTIMER_INTERVAL (60 * 60) /* 1 hour */ 79287546eaSitojun #define ND6_RECALC_REACHTM_INTERVAL (60 * 120) /* 2 hours */ 80287546eaSitojun 81287546eaSitojun #define SIN6(s) ((struct sockaddr_in6 *)s) 82287546eaSitojun #define SDL(s) ((struct sockaddr_dl *)s) 83287546eaSitojun 84287546eaSitojun /* timer values */ 85287546eaSitojun int nd6_prune = 1; /* walk list every 1 seconds */ 86287546eaSitojun int nd6_delay = 5; /* delay first probe time 5 second */ 87287546eaSitojun int nd6_umaxtries = 3; /* maximum unicast query */ 88287546eaSitojun int nd6_mmaxtries = 3; /* maximum multicast query */ 89287546eaSitojun int nd6_useloopback = 1; /* use loopback interface for local traffic */ 90287546eaSitojun 91287546eaSitojun /* preventing too many loops in ND option parsing */ 92287546eaSitojun int nd6_maxndopt = 10; /* max # of ND options allowed */ 93287546eaSitojun 94287546eaSitojun /* for debugging? */ 95287546eaSitojun static int nd6_inuse, nd6_allocated; 96287546eaSitojun 97287546eaSitojun struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; 98287546eaSitojun struct nd_ifinfo *nd_ifinfo = NULL; 99*f4f4d166Sitojun struct nd_drhead nd_defrouter; 100287546eaSitojun struct nd_prhead nd_prefix = { 0 }; 101287546eaSitojun 102287546eaSitojun int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; 103287546eaSitojun static struct sockaddr_in6 all1_sa; 104287546eaSitojun 105287546eaSitojun static void nd6_slowtimo __P((void *)); 106287546eaSitojun 107287546eaSitojun void 108287546eaSitojun nd6_init() 109287546eaSitojun { 110287546eaSitojun static int nd6_init_done = 0; 111287546eaSitojun int i; 112287546eaSitojun 113287546eaSitojun if (nd6_init_done) { 114287546eaSitojun log(LOG_NOTICE, "nd6_init called more than once(ignored)\n"); 115287546eaSitojun return; 116287546eaSitojun } 117287546eaSitojun 118287546eaSitojun all1_sa.sin6_family = AF_INET6; 119287546eaSitojun all1_sa.sin6_len = sizeof(struct sockaddr_in6); 120287546eaSitojun for (i = 0; i < sizeof(all1_sa.sin6_addr); i++) 121287546eaSitojun all1_sa.sin6_addr.s6_addr[i] = 0xff; 122287546eaSitojun 123*f4f4d166Sitojun /* initialization of the default router list */ 124*f4f4d166Sitojun TAILQ_INIT(&nd_defrouter); 125*f4f4d166Sitojun 126287546eaSitojun nd6_init_done = 1; 127287546eaSitojun 128287546eaSitojun /* start timer */ 129287546eaSitojun timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); 130287546eaSitojun } 131287546eaSitojun 132287546eaSitojun void 133287546eaSitojun nd6_ifattach(ifp) 134287546eaSitojun struct ifnet *ifp; 135287546eaSitojun { 136287546eaSitojun static size_t if_indexlim = 8; 137287546eaSitojun 138287546eaSitojun /* 139287546eaSitojun * We have some arrays that should be indexed by if_index. 140287546eaSitojun * since if_index will grow dynamically, they should grow too. 141287546eaSitojun */ 142287546eaSitojun if (nd_ifinfo == NULL || if_index >= if_indexlim) { 143287546eaSitojun size_t n; 144287546eaSitojun caddr_t q; 145287546eaSitojun 146287546eaSitojun while (if_index >= if_indexlim) 147287546eaSitojun if_indexlim <<= 1; 148287546eaSitojun 149287546eaSitojun /* grow nd_ifinfo */ 150287546eaSitojun n = if_indexlim * sizeof(struct nd_ifinfo); 151287546eaSitojun q = (caddr_t)malloc(n, M_IP6NDP, M_WAITOK); 152287546eaSitojun bzero(q, n); 153287546eaSitojun if (nd_ifinfo) { 154287546eaSitojun bcopy((caddr_t)nd_ifinfo, q, n/2); 155287546eaSitojun free((caddr_t)nd_ifinfo, M_IP6NDP); 156287546eaSitojun } 157287546eaSitojun nd_ifinfo = (struct nd_ifinfo *)q; 158287546eaSitojun } 159287546eaSitojun 160287546eaSitojun #define ND nd_ifinfo[ifp->if_index] 161287546eaSitojun ND.linkmtu = ifindex2ifnet[ifp->if_index]->if_mtu; 162287546eaSitojun ND.chlim = IPV6_DEFHLIM; 163287546eaSitojun ND.basereachable = REACHABLE_TIME; 164287546eaSitojun ND.reachable = ND_COMPUTE_RTIME(ND.basereachable); 165287546eaSitojun ND.retrans = RETRANS_TIMER; 166287546eaSitojun ND.receivedra = 0; 167287546eaSitojun nd6_setmtu(ifp); 168287546eaSitojun #undef ND 169287546eaSitojun } 170287546eaSitojun 171287546eaSitojun /* 172287546eaSitojun * Reset ND level link MTU. This function is called when the physical MTU 173287546eaSitojun * changes, which means we might have to adjust the ND level MTU. 174287546eaSitojun */ 175287546eaSitojun void 176287546eaSitojun nd6_setmtu(ifp) 177287546eaSitojun struct ifnet *ifp; 178287546eaSitojun { 179287546eaSitojun #define MIN(a,b) ((a) < (b) ? (a) : (b)) 180287546eaSitojun struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index]; 181287546eaSitojun u_long oldmaxmtu = ndi->maxmtu; 182287546eaSitojun u_long oldlinkmtu = ndi->linkmtu; 183287546eaSitojun 184287546eaSitojun switch(ifp->if_type) { 185287546eaSitojun case IFT_ARCNET: /* XXX MTU handling needs more work */ 186287546eaSitojun ndi->maxmtu = MIN(60480, ifp->if_mtu); 187287546eaSitojun break; 188287546eaSitojun case IFT_ETHER: 189287546eaSitojun ndi->maxmtu = MIN(ETHERMTU, ifp->if_mtu); 190287546eaSitojun break; 191287546eaSitojun case IFT_ATM: 192287546eaSitojun ndi->maxmtu = MIN(ATMMTU, ifp->if_mtu); 193287546eaSitojun break; 194287546eaSitojun default: 195287546eaSitojun ndi->maxmtu = ifp->if_mtu; 196287546eaSitojun break; 197287546eaSitojun } 198287546eaSitojun 199287546eaSitojun if (oldmaxmtu != ndi->maxmtu) { 200287546eaSitojun /* 201287546eaSitojun * If the ND level MTU is not set yet, or if the maxmtu 202287546eaSitojun * is reset to a smaller value than the ND level MTU, 203287546eaSitojun * also reset the ND level MTU. 204287546eaSitojun */ 205287546eaSitojun if (ndi->linkmtu == 0 || 206287546eaSitojun ndi->maxmtu < ndi->linkmtu) { 207287546eaSitojun ndi->linkmtu = ndi->maxmtu; 208287546eaSitojun /* also adjust in6_maxmtu if necessary. */ 209287546eaSitojun if (oldlinkmtu == 0) { 210287546eaSitojun /* 211287546eaSitojun * XXX: the case analysis is grotty, but 212287546eaSitojun * it is not efficient to call in6_setmaxmtu() 213287546eaSitojun * here when we are during the initialization 214287546eaSitojun * procedure. 215287546eaSitojun */ 216287546eaSitojun if (in6_maxmtu < ndi->linkmtu) 217287546eaSitojun in6_maxmtu = ndi->linkmtu; 218287546eaSitojun } 219287546eaSitojun else 220287546eaSitojun in6_setmaxmtu(); 221287546eaSitojun } 222287546eaSitojun } 223287546eaSitojun #undef MIN 224287546eaSitojun } 225287546eaSitojun 226287546eaSitojun void 227287546eaSitojun nd6_option_init(opt, icmp6len, ndopts) 228287546eaSitojun void *opt; 229287546eaSitojun int icmp6len; 230287546eaSitojun union nd_opts *ndopts; 231287546eaSitojun { 232287546eaSitojun bzero(ndopts, sizeof(*ndopts)); 233287546eaSitojun ndopts->nd_opts_search = (struct nd_opt_hdr *)opt; 234287546eaSitojun ndopts->nd_opts_last 235287546eaSitojun = (struct nd_opt_hdr *)(((u_char *)opt) + icmp6len); 236287546eaSitojun 237287546eaSitojun if (icmp6len == 0) { 238287546eaSitojun ndopts->nd_opts_done = 1; 239287546eaSitojun ndopts->nd_opts_search = NULL; 240287546eaSitojun } 241287546eaSitojun } 242287546eaSitojun 243287546eaSitojun /* 244287546eaSitojun * Take one ND option. 245287546eaSitojun */ 246287546eaSitojun struct nd_opt_hdr * 247287546eaSitojun nd6_option(ndopts) 248287546eaSitojun union nd_opts *ndopts; 249287546eaSitojun { 250287546eaSitojun struct nd_opt_hdr *nd_opt; 251287546eaSitojun int olen; 252287546eaSitojun 253287546eaSitojun if (!ndopts) 254287546eaSitojun panic("ndopts == NULL in nd6_option\n"); 255287546eaSitojun if (!ndopts->nd_opts_last) 256287546eaSitojun panic("uninitialized ndopts in nd6_option\n"); 257287546eaSitojun if (!ndopts->nd_opts_search) 258287546eaSitojun return NULL; 259287546eaSitojun if (ndopts->nd_opts_done) 260287546eaSitojun return NULL; 261287546eaSitojun 262287546eaSitojun nd_opt = ndopts->nd_opts_search; 263287546eaSitojun 264287546eaSitojun olen = nd_opt->nd_opt_len << 3; 265287546eaSitojun if (olen == 0) { 266287546eaSitojun /* 267287546eaSitojun * Message validation requires that all included 268287546eaSitojun * options have a length that is greater than zero. 269287546eaSitojun */ 270287546eaSitojun bzero(ndopts, sizeof(*ndopts)); 271287546eaSitojun return NULL; 272287546eaSitojun } 273287546eaSitojun 274287546eaSitojun ndopts->nd_opts_search = (struct nd_opt_hdr *)((caddr_t)nd_opt + olen); 275287546eaSitojun if (!(ndopts->nd_opts_search < ndopts->nd_opts_last)) { 276287546eaSitojun ndopts->nd_opts_done = 1; 277287546eaSitojun ndopts->nd_opts_search = NULL; 278287546eaSitojun } 279287546eaSitojun return nd_opt; 280287546eaSitojun } 281287546eaSitojun 282287546eaSitojun /* 283287546eaSitojun * Parse multiple ND options. 284287546eaSitojun * This function is much easier to use, for ND routines that do not need 285287546eaSitojun * multiple options of the same type. 286287546eaSitojun */ 287287546eaSitojun int 288287546eaSitojun nd6_options(ndopts) 289287546eaSitojun union nd_opts *ndopts; 290287546eaSitojun { 291287546eaSitojun struct nd_opt_hdr *nd_opt; 292287546eaSitojun int i = 0; 293287546eaSitojun 294287546eaSitojun if (!ndopts) 295287546eaSitojun panic("ndopts == NULL in nd6_options\n"); 296287546eaSitojun if (!ndopts->nd_opts_last) 297287546eaSitojun panic("uninitialized ndopts in nd6_options\n"); 298287546eaSitojun if (!ndopts->nd_opts_search) 299287546eaSitojun return 0; 300287546eaSitojun 301287546eaSitojun while (1) { 302287546eaSitojun nd_opt = nd6_option(ndopts); 303287546eaSitojun if (!nd_opt && !ndopts->nd_opts_last) { 304287546eaSitojun /* 305287546eaSitojun * Message validation requires that all included 306287546eaSitojun * options have a length that is greater than zero. 307287546eaSitojun */ 308287546eaSitojun bzero(ndopts, sizeof(*ndopts)); 309287546eaSitojun return -1; 310287546eaSitojun } 311287546eaSitojun 312287546eaSitojun if (!nd_opt) 313287546eaSitojun goto skip1; 314287546eaSitojun 315287546eaSitojun switch (nd_opt->nd_opt_type) { 316287546eaSitojun case ND_OPT_SOURCE_LINKADDR: 317287546eaSitojun case ND_OPT_TARGET_LINKADDR: 318287546eaSitojun case ND_OPT_MTU: 319287546eaSitojun case ND_OPT_REDIRECTED_HEADER: 320287546eaSitojun if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { 321287546eaSitojun printf("duplicated ND6 option found " 322287546eaSitojun "(type=%d)\n", nd_opt->nd_opt_type); 323287546eaSitojun /* XXX bark? */ 324287546eaSitojun } else { 325287546eaSitojun ndopts->nd_opt_array[nd_opt->nd_opt_type] 326287546eaSitojun = nd_opt; 327287546eaSitojun } 328287546eaSitojun break; 329287546eaSitojun case ND_OPT_PREFIX_INFORMATION: 330287546eaSitojun if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) { 331287546eaSitojun ndopts->nd_opt_array[nd_opt->nd_opt_type] 332287546eaSitojun = nd_opt; 333287546eaSitojun } 334287546eaSitojun ndopts->nd_opts_pi_end = 335287546eaSitojun (struct nd_opt_prefix_info *)nd_opt; 336287546eaSitojun break; 337287546eaSitojun default: 338287546eaSitojun /* 339287546eaSitojun * Unknown options must be silently ignored, 340287546eaSitojun * to accomodate future extension to the protocol. 341287546eaSitojun */ 342287546eaSitojun log(LOG_INFO, 343287546eaSitojun "nd6_options: unsupported option %d - " 344287546eaSitojun "option ignored\n", nd_opt->nd_opt_type); 345287546eaSitojun } 346287546eaSitojun 347287546eaSitojun skip1: 348287546eaSitojun i++; 349287546eaSitojun if (i > nd6_maxndopt) { 350287546eaSitojun icmp6stat.icp6s_nd_toomanyopt++; 351287546eaSitojun printf("too many loop in nd opt\n"); 352287546eaSitojun break; 353287546eaSitojun } 354287546eaSitojun 355287546eaSitojun if (ndopts->nd_opts_done) 356287546eaSitojun break; 357287546eaSitojun } 358287546eaSitojun 359287546eaSitojun return 0; 360287546eaSitojun } 361287546eaSitojun 362287546eaSitojun /* 363287546eaSitojun * ND6 timer routine to expire default route list and prefix list 364287546eaSitojun */ 365287546eaSitojun void 366287546eaSitojun nd6_timer(ignored_arg) 367287546eaSitojun void *ignored_arg; 368287546eaSitojun { 369287546eaSitojun int s; 370287546eaSitojun register struct llinfo_nd6 *ln; 371287546eaSitojun register struct nd_defrouter *dr; 372287546eaSitojun register struct nd_prefix *pr; 373287546eaSitojun long time_second = time.tv_sec; 374287546eaSitojun 375287546eaSitojun s = splnet(); 37658aa7d74Sangelos 377287546eaSitojun timeout(nd6_timer, (caddr_t)0, nd6_prune * hz); 378287546eaSitojun 379287546eaSitojun ln = llinfo_nd6.ln_next; 380287546eaSitojun /* XXX BSD/OS separates this code -- itojun */ 381287546eaSitojun while (ln && ln != &llinfo_nd6) { 382287546eaSitojun struct rtentry *rt; 383287546eaSitojun struct ifnet *ifp; 384287546eaSitojun struct sockaddr_in6 *dst; 385287546eaSitojun struct llinfo_nd6 *next = ln->ln_next; 386287546eaSitojun 387287546eaSitojun if ((rt = ln->ln_rt) == NULL) { 388287546eaSitojun ln = next; 389287546eaSitojun continue; 390287546eaSitojun } 391287546eaSitojun if ((ifp = rt->rt_ifp) == NULL) { 392287546eaSitojun ln = next; 393287546eaSitojun continue; 394287546eaSitojun } 395287546eaSitojun dst = (struct sockaddr_in6 *)rt_key(rt); 396287546eaSitojun 397287546eaSitojun if (ln->ln_expire > time_second) { 398287546eaSitojun ln = next; 399287546eaSitojun continue; 400287546eaSitojun } 401287546eaSitojun 402287546eaSitojun /* sanity check */ 403287546eaSitojun if (!rt) 404287546eaSitojun panic("rt=0 in nd6_timer(ln=%p)\n", ln); 405287546eaSitojun if (!dst) 406287546eaSitojun panic("dst=0 in nd6_timer(ln=%p)\n", ln); 407287546eaSitojun 408287546eaSitojun switch (ln->ln_state) { 409287546eaSitojun case ND6_LLINFO_INCOMPLETE: 410287546eaSitojun if (ln->ln_asked < nd6_mmaxtries) { 411287546eaSitojun ln->ln_asked++; 412287546eaSitojun ln->ln_expire = time_second + 413287546eaSitojun nd_ifinfo[ifp->if_index].retrans / 1000; 414287546eaSitojun nd6_ns_output(ifp, NULL, &dst->sin6_addr, 415287546eaSitojun ln, 0); 416287546eaSitojun } else { 417287546eaSitojun struct mbuf *m = ln->ln_hold; 418287546eaSitojun if (m) { 419287546eaSitojun if (rt->rt_ifp) { 420287546eaSitojun /* 421287546eaSitojun * Fake rcvif to make ICMP error 422287546eaSitojun * more helpful in diagnosing 423287546eaSitojun * for the receiver. 424287546eaSitojun * XXX: should we consider 425287546eaSitojun * older rcvif? 426287546eaSitojun */ 427287546eaSitojun m->m_pkthdr.rcvif = rt->rt_ifp; 428287546eaSitojun } 429287546eaSitojun icmp6_error(m, ICMP6_DST_UNREACH, 430287546eaSitojun ICMP6_DST_UNREACH_ADDR, 0); 431287546eaSitojun ln->ln_hold = NULL; 432287546eaSitojun } 433287546eaSitojun nd6_free(rt); 434287546eaSitojun } 435287546eaSitojun break; 436287546eaSitojun case ND6_LLINFO_REACHABLE: 437*f4f4d166Sitojun if (ln->ln_expire) 438287546eaSitojun ln->ln_state = ND6_LLINFO_STALE; 439287546eaSitojun break; 440287546eaSitojun /* 441287546eaSitojun * ND6_LLINFO_STALE state requires nothing for timer 442287546eaSitojun * routine. 443287546eaSitojun */ 444287546eaSitojun case ND6_LLINFO_DELAY: 445287546eaSitojun ln->ln_asked = 1; 446287546eaSitojun ln->ln_state = ND6_LLINFO_PROBE; 447287546eaSitojun ln->ln_expire = time_second + 448287546eaSitojun nd_ifinfo[ifp->if_index].retrans / 1000; 449287546eaSitojun nd6_ns_output(ifp, &dst->sin6_addr, &dst->sin6_addr, 450287546eaSitojun ln, 0); 451287546eaSitojun break; 452287546eaSitojun 453287546eaSitojun case ND6_LLINFO_PROBE: 454287546eaSitojun if (ln->ln_asked < nd6_umaxtries) { 455287546eaSitojun ln->ln_asked++; 456287546eaSitojun ln->ln_expire = time_second + 457287546eaSitojun nd_ifinfo[ifp->if_index].retrans / 1000; 458287546eaSitojun nd6_ns_output(ifp, &dst->sin6_addr, 459287546eaSitojun &dst->sin6_addr, ln, 0); 460287546eaSitojun } else { 461287546eaSitojun nd6_free(rt); 462287546eaSitojun } 463287546eaSitojun break; 464287546eaSitojun case ND6_LLINFO_WAITDELETE: 465287546eaSitojun nd6_free(rt); 466287546eaSitojun break; 467287546eaSitojun } 468287546eaSitojun ln = next; 469287546eaSitojun } 470287546eaSitojun 471287546eaSitojun /* expire */ 472*f4f4d166Sitojun dr = TAILQ_FIRST(&nd_defrouter); 473287546eaSitojun while (dr) { 474287546eaSitojun if (dr->expire && dr->expire < time_second) { 475287546eaSitojun struct nd_defrouter *t; 476*f4f4d166Sitojun t = TAILQ_NEXT(dr, dr_entry); 477287546eaSitojun defrtrlist_del(dr); 478287546eaSitojun dr = t; 479287546eaSitojun } else 480*f4f4d166Sitojun dr = TAILQ_NEXT(dr, dr_entry); 481287546eaSitojun } 482287546eaSitojun pr = nd_prefix.lh_first; 483287546eaSitojun while (pr) { 484287546eaSitojun struct in6_ifaddr *ia6; 485287546eaSitojun struct in6_addrlifetime *lt6; 486287546eaSitojun 487287546eaSitojun if (IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 488287546eaSitojun ia6 = NULL; 489287546eaSitojun else 490287546eaSitojun ia6 = in6ifa_ifpwithaddr(pr->ndpr_ifp, &pr->ndpr_addr); 491287546eaSitojun 492287546eaSitojun if (ia6) { 493287546eaSitojun /* check address lifetime */ 494287546eaSitojun lt6 = &ia6->ia6_lifetime; 495287546eaSitojun if (lt6->ia6t_preferred && lt6->ia6t_preferred < time_second) 496287546eaSitojun ia6->ia6_flags |= IN6_IFF_DEPRECATED; 497287546eaSitojun if (lt6->ia6t_expire && lt6->ia6t_expire < time_second) { 498287546eaSitojun if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 499287546eaSitojun in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 500287546eaSitojun /* xxx ND_OPT_PI_FLAG_ONLINK processing */ 501287546eaSitojun } 502287546eaSitojun } 503287546eaSitojun 504287546eaSitojun /* 505287546eaSitojun * check prefix lifetime. 506287546eaSitojun * since pltime is just for autoconf, pltime processing for 507287546eaSitojun * prefix is not necessary. 508287546eaSitojun * 509287546eaSitojun * we offset expire time by NDPR_KEEP_EXPIRE, so that we 510287546eaSitojun * can use the old prefix information to validate the 511287546eaSitojun * next prefix information to come. See prelist_update() 512287546eaSitojun * for actual validation. 513287546eaSitojun */ 514287546eaSitojun if (pr->ndpr_expire 515287546eaSitojun && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { 516287546eaSitojun struct nd_prefix *t; 517287546eaSitojun t = pr->ndpr_next; 518287546eaSitojun 519287546eaSitojun /* 520287546eaSitojun * address expiration and prefix expiration are 521287546eaSitojun * separate. NEVER perform in6_ifdel here. 522287546eaSitojun */ 523287546eaSitojun 524287546eaSitojun prelist_remove(pr); 525287546eaSitojun pr = t; 526287546eaSitojun } else 527287546eaSitojun pr = pr->ndpr_next; 528287546eaSitojun } 529287546eaSitojun splx(s); 530287546eaSitojun } 531287546eaSitojun 53222770369Sitojun /* 53322770369Sitojun * Nuke neighbor cache/prefix/default router management table, right before 53422770369Sitojun * ifp goes away. 53522770369Sitojun */ 53622770369Sitojun void 53722770369Sitojun nd6_purge(ifp) 53822770369Sitojun struct ifnet *ifp; 53922770369Sitojun { 54022770369Sitojun struct llinfo_nd6 *ln, *nln; 54122770369Sitojun struct nd_defrouter *dr, *ndr, drany; 54222770369Sitojun struct nd_prefix *pr, *npr; 54322770369Sitojun 54422770369Sitojun /* Nuke default router list entries toward ifp */ 545*f4f4d166Sitojun if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { 54622770369Sitojun /* 54722770369Sitojun * The first entry of the list may be stored in 54822770369Sitojun * the routing table, so we'll delete it later. 54922770369Sitojun */ 550*f4f4d166Sitojun for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = ndr) { 551*f4f4d166Sitojun ndr = TAILQ_NEXT(dr, dr_entry); 55222770369Sitojun if (dr->ifp == ifp) 55322770369Sitojun defrtrlist_del(dr); 55422770369Sitojun } 555*f4f4d166Sitojun dr = TAILQ_FIRST(&nd_defrouter); 55622770369Sitojun if (dr->ifp == ifp) 55722770369Sitojun defrtrlist_del(dr); 55822770369Sitojun } 55922770369Sitojun 56022770369Sitojun /* Nuke prefix list entries toward ifp */ 56122770369Sitojun for (pr = nd_prefix.lh_first; pr; pr = npr) { 56222770369Sitojun npr = pr->ndpr_next; 56322770369Sitojun if (pr->ndpr_ifp == ifp) { 56422770369Sitojun if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 56522770369Sitojun in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 56622770369Sitojun prelist_remove(pr); 56722770369Sitojun } 56822770369Sitojun } 56922770369Sitojun 570*f4f4d166Sitojun /* cancel default outgoing interface setting */ 571*f4f4d166Sitojun if (nd6_defifindex == ifp->if_index) 572*f4f4d166Sitojun nd6_setdefaultiface(0); 573*f4f4d166Sitojun 57422770369Sitojun /* refresh default router list */ 57522770369Sitojun bzero(&drany, sizeof(drany)); 57622770369Sitojun defrouter_delreq(&drany, 0); 577*f4f4d166Sitojun defrouter_select(); 57822770369Sitojun 57922770369Sitojun /* 58022770369Sitojun * Nuke neighbor cache entries for the ifp. 58122770369Sitojun * Note that rt->rt_ifp may not be the same as ifp, 58222770369Sitojun * due to KAME goto ours hack. See RTM_RESOLVE case in 58322770369Sitojun * nd6_rtrequest(), and ip6_input(). 58422770369Sitojun */ 58522770369Sitojun ln = llinfo_nd6.ln_next; 58622770369Sitojun while (ln && ln != &llinfo_nd6) { 58722770369Sitojun struct rtentry *rt; 58822770369Sitojun struct sockaddr_dl *sdl; 58922770369Sitojun 59022770369Sitojun nln = ln->ln_next; 59122770369Sitojun rt = ln->ln_rt; 59222770369Sitojun if (rt && rt->rt_gateway && 59322770369Sitojun rt->rt_gateway->sa_family == AF_LINK) { 59422770369Sitojun sdl = (struct sockaddr_dl *)rt->rt_gateway; 59522770369Sitojun if (sdl->sdl_index == ifp->if_index) 59622770369Sitojun nd6_free(rt); 59722770369Sitojun } 59822770369Sitojun ln = nln; 59922770369Sitojun } 60022770369Sitojun 60122770369Sitojun /* 60222770369Sitojun * Neighbor cache entry for interface route will be retained 60322770369Sitojun * with ND6_LLINFO_WAITDELETE state, by nd6_free(). Nuke it. 60422770369Sitojun */ 60522770369Sitojun ln = llinfo_nd6.ln_next; 60622770369Sitojun while (ln && ln != &llinfo_nd6) { 60722770369Sitojun struct rtentry *rt; 60822770369Sitojun struct sockaddr_dl *sdl; 60922770369Sitojun 61022770369Sitojun nln = ln->ln_next; 61122770369Sitojun rt = ln->ln_rt; 61222770369Sitojun if (rt && rt->rt_gateway && 61322770369Sitojun rt->rt_gateway->sa_family == AF_LINK) { 61422770369Sitojun sdl = (struct sockaddr_dl *)rt->rt_gateway; 61522770369Sitojun if (sdl->sdl_index == ifp->if_index) { 61622770369Sitojun rtrequest(RTM_DELETE, rt_key(rt), 61722770369Sitojun (struct sockaddr *)0, rt_mask(rt), 0, 61822770369Sitojun (struct rtentry **)0); 61922770369Sitojun } 62022770369Sitojun } 62122770369Sitojun ln = nln; 62222770369Sitojun } 62322770369Sitojun } 62422770369Sitojun 625287546eaSitojun struct rtentry * 626287546eaSitojun nd6_lookup(addr6, create, ifp) 627287546eaSitojun struct in6_addr *addr6; 628287546eaSitojun int create; 629287546eaSitojun struct ifnet *ifp; 630287546eaSitojun { 631287546eaSitojun struct rtentry *rt; 632287546eaSitojun struct sockaddr_in6 sin6; 633287546eaSitojun 634287546eaSitojun bzero(&sin6, sizeof(sin6)); 635287546eaSitojun sin6.sin6_len = sizeof(struct sockaddr_in6); 636287546eaSitojun sin6.sin6_family = AF_INET6; 637287546eaSitojun sin6.sin6_addr = *addr6; 63858aa7d74Sangelos rt = rtalloc1((struct sockaddr *)&sin6, create); 639287546eaSitojun if (rt && (rt->rt_flags & RTF_LLINFO) == 0) { 640287546eaSitojun /* 641287546eaSitojun * This is the case for the default route. 642287546eaSitojun * If we want to create a neighbor cache for the address, we 643287546eaSitojun * should free the route for the destination and allocate an 644287546eaSitojun * interface route. 645287546eaSitojun */ 646287546eaSitojun if (create) { 647287546eaSitojun RTFREE(rt); 648287546eaSitojun rt = 0; 649287546eaSitojun } 650287546eaSitojun } 651287546eaSitojun if (!rt) { 652287546eaSitojun if (create && ifp) { 653287546eaSitojun /* 654287546eaSitojun * If no route is available and create is set, 655287546eaSitojun * we allocate a host route for the destination 656287546eaSitojun * and treat it like an interface route. 657287546eaSitojun * This hack is necessary for a neighbor which can't 658287546eaSitojun * be covered by our own prefix. 659287546eaSitojun */ 660287546eaSitojun struct ifaddr *ifa = 661287546eaSitojun ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); 662287546eaSitojun if (ifa == NULL) 663287546eaSitojun return(NULL); 664287546eaSitojun 665287546eaSitojun /* 666287546eaSitojun * Create a new route. RTF_LLINFO is necessary 667287546eaSitojun * to create a Neighbor Cache entry for the 668287546eaSitojun * destination in nd6_rtrequest which will be 669287546eaSitojun * called in rtequest via ifa->ifa_rtrequest. 670287546eaSitojun */ 671287546eaSitojun if (rtrequest(RTM_ADD, (struct sockaddr *)&sin6, 672287546eaSitojun ifa->ifa_addr, 673287546eaSitojun (struct sockaddr *)&all1_sa, 674287546eaSitojun (ifa->ifa_flags | 675287546eaSitojun RTF_HOST | RTF_LLINFO) & ~RTF_CLONING, 676287546eaSitojun &rt)) 677287546eaSitojun log(LOG_ERR, 678287546eaSitojun "nd6_lookup: failed to add route for a " 679287546eaSitojun "neighbor(%s)\n", ip6_sprintf(addr6)); 680287546eaSitojun if (rt == NULL) 681287546eaSitojun return(NULL); 682287546eaSitojun if (rt->rt_llinfo) { 683287546eaSitojun struct llinfo_nd6 *ln = 684287546eaSitojun (struct llinfo_nd6 *)rt->rt_llinfo; 685287546eaSitojun ln->ln_state = ND6_LLINFO_NOSTATE; 686287546eaSitojun } 687287546eaSitojun } 688287546eaSitojun else 689287546eaSitojun return(NULL); 690287546eaSitojun } 691287546eaSitojun rt->rt_refcnt--; 692287546eaSitojun /* 693287546eaSitojun * Validation for the entry. 694287546eaSitojun * XXX: we can't use rt->rt_ifp to check for the interface, since 695287546eaSitojun * it might be the loopback interface if the entry is for our 696287546eaSitojun * own address on a non-loopback interface. Instead, we should 697287546eaSitojun * use rt->rt_ifa->ifa_ifp, which would specify the REAL interface. 698287546eaSitojun */ 699287546eaSitojun if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || 700287546eaSitojun rt->rt_gateway->sa_family != AF_LINK || 701287546eaSitojun (ifp && rt->rt_ifa->ifa_ifp != ifp)) { 702287546eaSitojun if (create) { 703287546eaSitojun log(LOG_DEBUG, "nd6_lookup: failed to lookup %s (if = %s)\n", 704287546eaSitojun ip6_sprintf(addr6), ifp ? if_name(ifp) : "unspec"); 705287546eaSitojun /* xxx more logs... kazu */ 706287546eaSitojun } 707287546eaSitojun return(0); 708287546eaSitojun } 709287546eaSitojun return(rt); 710287546eaSitojun } 711287546eaSitojun 712287546eaSitojun /* 713287546eaSitojun * Detect if a given IPv6 address identifies a neighbor on a given link. 714287546eaSitojun * XXX: should take care of the destination of a p2p link? 715287546eaSitojun */ 716287546eaSitojun int 717287546eaSitojun nd6_is_addr_neighbor(addr, ifp) 718287546eaSitojun struct in6_addr *addr; 719287546eaSitojun struct ifnet *ifp; 720287546eaSitojun { 721287546eaSitojun register struct ifaddr *ifa; 722287546eaSitojun int i; 723287546eaSitojun 724287546eaSitojun #define IFADDR6(a) ((((struct in6_ifaddr *)(a))->ia_addr).sin6_addr) 725287546eaSitojun #define IFMASK6(a) ((((struct in6_ifaddr *)(a))->ia_prefixmask).sin6_addr) 726287546eaSitojun 727287546eaSitojun /* A link-local address is always a neighbor. */ 728287546eaSitojun if (IN6_IS_ADDR_LINKLOCAL(addr)) 729287546eaSitojun return(1); 730287546eaSitojun 731287546eaSitojun /* 732287546eaSitojun * If the address matches one of our addresses, 733287546eaSitojun * it should be a neighbor. 734287546eaSitojun */ 735287546eaSitojun for (ifa = ifp->if_addrlist.tqh_first; 736287546eaSitojun ifa; 737287546eaSitojun ifa = ifa->ifa_list.tqe_next) 738287546eaSitojun { 739287546eaSitojun if (ifa->ifa_addr->sa_family != AF_INET6) 740287546eaSitojun next: continue; 741287546eaSitojun 742287546eaSitojun for (i = 0; i < 4; i++) { 743287546eaSitojun if ((IFADDR6(ifa).s6_addr32[i] ^ addr->s6_addr32[i]) & 744287546eaSitojun IFMASK6(ifa).s6_addr32[i]) 745287546eaSitojun goto next; 746287546eaSitojun } 747287546eaSitojun return(1); 748287546eaSitojun } 749287546eaSitojun 750287546eaSitojun /* 751287546eaSitojun * Even if the address matches none of our addresses, it might be 752287546eaSitojun * in the neighbor cache. 753287546eaSitojun */ 754287546eaSitojun if (nd6_lookup(addr, 0, ifp)) 755287546eaSitojun return(1); 756287546eaSitojun 757287546eaSitojun return(0); 758287546eaSitojun #undef IFADDR6 759287546eaSitojun #undef IFMASK6 760287546eaSitojun } 761287546eaSitojun 762287546eaSitojun /* 763287546eaSitojun * Free an nd6 llinfo entry. 764287546eaSitojun */ 765287546eaSitojun void 766287546eaSitojun nd6_free(rt) 767287546eaSitojun struct rtentry *rt; 768287546eaSitojun { 769287546eaSitojun struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; 770287546eaSitojun struct sockaddr_dl *sdl; 771*f4f4d166Sitojun struct in6_addr in6 = ((struct sockaddr_in6 *)rt_key(rt))->sin6_addr; 772287546eaSitojun struct nd_defrouter *dr; 773287546eaSitojun 774287546eaSitojun /* 775*f4f4d166Sitojun * Clear all destination cache entries for the neighbor. 776*f4f4d166Sitojun * XXX: is it better to restrict this to hosts? 777287546eaSitojun */ 778*f4f4d166Sitojun pfctlinput(PRC_HOSTDEAD, rt_key(rt)); 779*f4f4d166Sitojun 780*f4f4d166Sitojun if (!ip6_forwarding && ip6_accept_rtadv) { /* XXX: too restrictive? */ 781*f4f4d166Sitojun int s; 782*f4f4d166Sitojun s = splnet(); 783*f4f4d166Sitojun dr = defrouter_lookup(&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, 784*f4f4d166Sitojun rt->rt_ifp); 785*f4f4d166Sitojun if (ln->ln_router || dr) { 786*f4f4d166Sitojun /* 787*f4f4d166Sitojun * rt6_flush must be called whether or not the neighbor 788*f4f4d166Sitojun * is in the Default Router List. 789*f4f4d166Sitojun * See a corresponding comment in nd6_na_input(). 790*f4f4d166Sitojun */ 791*f4f4d166Sitojun rt6_flush(&in6, rt->rt_ifp); 792*f4f4d166Sitojun } 793*f4f4d166Sitojun 794*f4f4d166Sitojun if (dr) { 795*f4f4d166Sitojun /* 796*f4f4d166Sitojun * Unreachablity of a router might affect the default 797*f4f4d166Sitojun * router selection and on-link detection of advertised 798*f4f4d166Sitojun * prefixes. 799*f4f4d166Sitojun */ 800*f4f4d166Sitojun 801*f4f4d166Sitojun /* 802*f4f4d166Sitojun * Temporarily fake the state to choose a new default 803*f4f4d166Sitojun * router and to perform on-link determination of 804*f4f4d166Sitojun * prefixes coreectly. 805*f4f4d166Sitojun * Below the state will be set correctly, 806*f4f4d166Sitojun * or the entry itself will be deleted. 807*f4f4d166Sitojun */ 808*f4f4d166Sitojun ln->ln_state = ND6_LLINFO_INCOMPLETE; 809*f4f4d166Sitojun 810*f4f4d166Sitojun if (dr == TAILQ_FIRST(&nd_defrouter)) { 811*f4f4d166Sitojun /* 812*f4f4d166Sitojun * It is used as the current default router, 813*f4f4d166Sitojun * so we have to move it to the end of the 814*f4f4d166Sitojun * list and choose a new one. 815*f4f4d166Sitojun * XXX: it is not very efficient if this is 816*f4f4d166Sitojun * the only router. 817*f4f4d166Sitojun */ 818*f4f4d166Sitojun TAILQ_REMOVE(&nd_defrouter, dr, dr_entry); 819*f4f4d166Sitojun TAILQ_INSERT_TAIL(&nd_defrouter, dr, dr_entry); 820*f4f4d166Sitojun 821*f4f4d166Sitojun defrouter_select(); 822*f4f4d166Sitojun } 823*f4f4d166Sitojun pfxlist_onlink_check(); 824287546eaSitojun } 825287546eaSitojun splx(s); 826287546eaSitojun } 827287546eaSitojun 828287546eaSitojun if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) && 829287546eaSitojun sdl->sdl_family == AF_LINK) { 830287546eaSitojun sdl->sdl_alen = 0; 831287546eaSitojun ln->ln_state = ND6_LLINFO_WAITDELETE; 832287546eaSitojun ln->ln_asked = 0; 833287546eaSitojun rt->rt_flags &= ~RTF_REJECT; 834287546eaSitojun return; 835287546eaSitojun } 836*f4f4d166Sitojun 837*f4f4d166Sitojun rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, 838*f4f4d166Sitojun rt_mask(rt), 0, (struct rtentry **)0); 839287546eaSitojun } 840287546eaSitojun 841287546eaSitojun /* 842287546eaSitojun * Upper-layer reachability hint for Neighbor Unreachability Detection. 843287546eaSitojun * 844287546eaSitojun * XXX cost-effective metods? 845287546eaSitojun */ 846287546eaSitojun void 847287546eaSitojun nd6_nud_hint(rt, dst6) 848287546eaSitojun struct rtentry *rt; 849287546eaSitojun struct in6_addr *dst6; 850287546eaSitojun { 851287546eaSitojun struct llinfo_nd6 *ln; 852287546eaSitojun long time_second = time.tv_sec; 853287546eaSitojun 854287546eaSitojun /* 855287546eaSitojun * If the caller specified "rt", use that. Otherwise, resolve the 856287546eaSitojun * routing table by supplied "dst6". 857287546eaSitojun */ 858287546eaSitojun if (!rt) { 859287546eaSitojun if (!dst6) 860287546eaSitojun return; 861287546eaSitojun if (!(rt = nd6_lookup(dst6, 0, NULL))) 862287546eaSitojun return; 863287546eaSitojun } 864287546eaSitojun 865287546eaSitojun if ((rt->rt_flags & RTF_GATEWAY) 866287546eaSitojun || (rt->rt_flags & RTF_LLINFO) == 0 867287546eaSitojun || !rt->rt_llinfo 868287546eaSitojun || !rt->rt_gateway 869287546eaSitojun || rt->rt_gateway->sa_family != AF_LINK) { 870287546eaSitojun /* This is not a host route. */ 871287546eaSitojun return; 872287546eaSitojun } 873287546eaSitojun 874287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 875287546eaSitojun if (ln->ln_state == ND6_LLINFO_INCOMPLETE) 876287546eaSitojun return; 877287546eaSitojun 878287546eaSitojun ln->ln_state = ND6_LLINFO_REACHABLE; 879287546eaSitojun if (ln->ln_expire) 880287546eaSitojun ln->ln_expire = time_second + 881287546eaSitojun nd_ifinfo[rt->rt_ifp->if_index].reachable; 882287546eaSitojun } 883287546eaSitojun 884287546eaSitojun #ifdef OLDIP6OUTPUT 885287546eaSitojun /* 886287546eaSitojun * Resolve an IP6 address into an ethernet address. If success, 887287546eaSitojun * desten is filled in. If there is no entry in ndptab, 888287546eaSitojun * set one up and multicast a solicitation for the IP6 address. 889287546eaSitojun * Hold onto this mbuf and resend it once the address 890287546eaSitojun * is finally resolved. A return value of 1 indicates 891287546eaSitojun * that desten has been filled in and the packet should be sent 892287546eaSitojun * normally; a 0 return indicates that the packet has been 893287546eaSitojun * taken over here, either now or for later transmission. 894287546eaSitojun */ 895287546eaSitojun int 896287546eaSitojun nd6_resolve(ifp, rt, m, dst, desten) 897287546eaSitojun struct ifnet *ifp; 898287546eaSitojun struct rtentry *rt; 899287546eaSitojun struct mbuf *m; 900287546eaSitojun struct sockaddr *dst; 901287546eaSitojun u_char *desten; 902287546eaSitojun { 903287546eaSitojun struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL; 904287546eaSitojun struct sockaddr_dl *sdl; 905287546eaSitojun long time_second = time.tv_sec; 906287546eaSitojun 907287546eaSitojun if (m->m_flags & M_MCAST) { 908287546eaSitojun switch (ifp->if_type) { 909287546eaSitojun case IFT_ETHER: 910287546eaSitojun case IFT_FDDI: 911287546eaSitojun ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, 912287546eaSitojun desten); 913287546eaSitojun return(1); 914287546eaSitojun break; 915287546eaSitojun case IFT_ARCNET: 916287546eaSitojun *desten = 0; 917287546eaSitojun return(1); 918287546eaSitojun break; 919287546eaSitojun default: 920287546eaSitojun return(0); 921287546eaSitojun } 922287546eaSitojun } 923287546eaSitojun if (rt && (rt->rt_flags & RTF_LLINFO) != 0) 924287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 925287546eaSitojun else { 926287546eaSitojun if ((rt = nd6_lookup(&(SIN6(dst)->sin6_addr), 1, ifp)) != NULL) 927287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 928287546eaSitojun } 929287546eaSitojun if (!ln || !rt) { 930287546eaSitojun log(LOG_DEBUG, "nd6_resolve: can't allocate llinfo for %s\n", 931287546eaSitojun ip6_sprintf(&(SIN6(dst)->sin6_addr))); 932287546eaSitojun m_freem(m); 933287546eaSitojun return(0); 934287546eaSitojun } 935287546eaSitojun sdl = SDL(rt->rt_gateway); 936287546eaSitojun /* 937287546eaSitojun * Ckeck the address family and length is valid, the address 938287546eaSitojun * is resolved; otherwise, try to resolve. 939287546eaSitojun */ 940287546eaSitojun if (ln->ln_state >= ND6_LLINFO_REACHABLE 941287546eaSitojun && sdl->sdl_family == AF_LINK 942287546eaSitojun && sdl->sdl_alen != 0) { 943287546eaSitojun bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 944287546eaSitojun if (ln->ln_state == ND6_LLINFO_STALE) { 945287546eaSitojun ln->ln_asked = 0; 946287546eaSitojun ln->ln_state = ND6_LLINFO_DELAY; 947287546eaSitojun ln->ln_expire = time_second + nd6_delay; 948287546eaSitojun } 949287546eaSitojun return(1); 950287546eaSitojun } 951287546eaSitojun /* 952287546eaSitojun * There is an ndp entry, but no ethernet address 953287546eaSitojun * response yet. Replace the held mbuf with this 954287546eaSitojun * latest one. 955287546eaSitojun * 956287546eaSitojun * XXX Does the code conform to rate-limiting rule? 957287546eaSitojun * (RFC 2461 7.2.2) 958287546eaSitojun */ 959287546eaSitojun if (ln->ln_state == ND6_LLINFO_WAITDELETE || 960287546eaSitojun ln->ln_state == ND6_LLINFO_NOSTATE) 961287546eaSitojun ln->ln_state = ND6_LLINFO_INCOMPLETE; 962287546eaSitojun if (ln->ln_hold) 963287546eaSitojun m_freem(ln->ln_hold); 964287546eaSitojun ln->ln_hold = m; 965287546eaSitojun if (ln->ln_expire) { 966287546eaSitojun rt->rt_flags &= ~RTF_REJECT; 967287546eaSitojun if (ln->ln_asked < nd6_mmaxtries && 968287546eaSitojun ln->ln_expire < time_second) { 969287546eaSitojun ln->ln_asked++; 970287546eaSitojun ln->ln_expire = time_second + 971287546eaSitojun nd_ifinfo[ifp->if_index].retrans / 1000; 972287546eaSitojun nd6_ns_output(ifp, NULL, &(SIN6(dst)->sin6_addr), 973287546eaSitojun ln, 0); 974287546eaSitojun } 975287546eaSitojun } 976287546eaSitojun return(0); 977287546eaSitojun } 978287546eaSitojun #endif /* OLDIP6OUTPUT */ 979287546eaSitojun 980287546eaSitojun void 981287546eaSitojun nd6_rtrequest(req, rt, sa) 982287546eaSitojun int req; 983287546eaSitojun struct rtentry *rt; 984287546eaSitojun struct sockaddr *sa; /* xxx unused */ 985287546eaSitojun { 986287546eaSitojun struct sockaddr *gate = rt->rt_gateway; 987287546eaSitojun struct llinfo_nd6 *ln = (struct llinfo_nd6 *)rt->rt_llinfo; 988287546eaSitojun static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 989287546eaSitojun struct ifnet *ifp = rt->rt_ifp; 990287546eaSitojun struct ifaddr *ifa; 991287546eaSitojun long time_second = time.tv_sec; 992287546eaSitojun 993287546eaSitojun if (rt->rt_flags & RTF_GATEWAY) 994287546eaSitojun return; 995287546eaSitojun 996287546eaSitojun switch (req) { 997287546eaSitojun case RTM_ADD: 998287546eaSitojun /* 999287546eaSitojun * There is no backward compatibility :) 1000287546eaSitojun * 1001287546eaSitojun * if ((rt->rt_flags & RTF_HOST) == 0 && 1002287546eaSitojun * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 1003287546eaSitojun * rt->rt_flags |= RTF_CLONING; 1004287546eaSitojun */ 1005*f4f4d166Sitojun if (rt->rt_flags & (RTF_CLONING | RTF_LLINFO)) { 1006287546eaSitojun /* 1007287546eaSitojun * Case 1: This route should come from 1008287546eaSitojun * a route to interface. RTF_LLINFO flag is set 1009287546eaSitojun * for a host route whose destination should be 1010287546eaSitojun * treated as on-link. 1011287546eaSitojun */ 1012287546eaSitojun rt_setgate(rt, rt_key(rt), 1013287546eaSitojun (struct sockaddr *)&null_sdl); 1014287546eaSitojun gate = rt->rt_gateway; 1015287546eaSitojun SDL(gate)->sdl_type = ifp->if_type; 1016287546eaSitojun SDL(gate)->sdl_index = ifp->if_index; 1017287546eaSitojun if (ln) 1018287546eaSitojun ln->ln_expire = time_second; 1019287546eaSitojun #if 1 1020287546eaSitojun if (ln && ln->ln_expire == 0) { 1021287546eaSitojun /* cludge for desktops */ 1022287546eaSitojun #if 0 1023287546eaSitojun printf("nd6_request: time.tv_sec is zero; " 1024287546eaSitojun "treat it as 1\n"); 1025287546eaSitojun #endif 1026287546eaSitojun ln->ln_expire = 1; 1027287546eaSitojun } 1028287546eaSitojun #endif 1029287546eaSitojun if (rt->rt_flags & RTF_CLONING) 1030287546eaSitojun break; 1031287546eaSitojun } 1032*f4f4d166Sitojun /* 1033*f4f4d166Sitojun * In IPv4 code, we try to annonuce new RTF_ANNOUNCE entry here. 1034*f4f4d166Sitojun * We don't do that here since llinfo is not ready yet. 1035*f4f4d166Sitojun * 1036*f4f4d166Sitojun * There are also couple of other things to be discussed: 1037*f4f4d166Sitojun * - unsolicited NA code needs improvement beforehand 1038*f4f4d166Sitojun * - RFC2461 says we MAY send multicast unsolicited NA 1039*f4f4d166Sitojun * (7.2.6 paragraph 4), however, it also says that we 1040*f4f4d166Sitojun * SHOULD provide a mechanism to prevent multicast NA storm. 1041*f4f4d166Sitojun * we don't have anything like it right now. 1042*f4f4d166Sitojun * note that the mechanism need a mutual agreement 1043*f4f4d166Sitojun * between proxies, which means that we need to implement 1044*f4f4d166Sitojun * a new protocol, or new kludge. 1045*f4f4d166Sitojun * - from RFC2461 6.2.4, host MUST NOT send unsolicited NA. 1046*f4f4d166Sitojun * we need to check ip6forwarding before sending it. 1047*f4f4d166Sitojun * (or should we allow proxy ND configuration only for 1048*f4f4d166Sitojun * routers? there's no mention about proxy ND from hosts) 1049*f4f4d166Sitojun */ 1050*f4f4d166Sitojun #if 0 1051*f4f4d166Sitojun /* XXX it does not work */ 1052287546eaSitojun if (rt->rt_flags & RTF_ANNOUNCE) 1053287546eaSitojun nd6_na_output(ifp, 1054287546eaSitojun &SIN6(rt_key(rt))->sin6_addr, 1055287546eaSitojun &SIN6(rt_key(rt))->sin6_addr, 1056287546eaSitojun ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1057*f4f4d166Sitojun 1, NULL); 1058*f4f4d166Sitojun #endif 1059287546eaSitojun /* FALLTHROUGH */ 1060287546eaSitojun case RTM_RESOLVE: 1061287546eaSitojun if (gate->sa_family != AF_LINK || 1062287546eaSitojun gate->sa_len < sizeof(null_sdl)) { 1063287546eaSitojun log(LOG_DEBUG, "nd6_rtrequest: bad gateway value\n"); 1064287546eaSitojun break; 1065287546eaSitojun } 1066287546eaSitojun SDL(gate)->sdl_type = ifp->if_type; 1067287546eaSitojun SDL(gate)->sdl_index = ifp->if_index; 1068287546eaSitojun if (ln != 0) 1069287546eaSitojun break; /* This happens on a route change */ 1070287546eaSitojun /* 1071287546eaSitojun * Case 2: This route may come from cloning, or a manual route 1072287546eaSitojun * add with a LL address. 1073287546eaSitojun */ 1074287546eaSitojun R_Malloc(ln, struct llinfo_nd6 *, sizeof(*ln)); 1075287546eaSitojun rt->rt_llinfo = (caddr_t)ln; 1076287546eaSitojun if (!ln) { 1077287546eaSitojun log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); 1078287546eaSitojun break; 1079287546eaSitojun } 1080287546eaSitojun nd6_inuse++; 1081287546eaSitojun nd6_allocated++; 1082287546eaSitojun Bzero(ln, sizeof(*ln)); 1083287546eaSitojun ln->ln_rt = rt; 1084287546eaSitojun /* this is required for "ndp" command. - shin */ 1085287546eaSitojun if (req == RTM_ADD) { 1086287546eaSitojun /* 1087287546eaSitojun * gate should have some valid AF_LINK entry, 1088287546eaSitojun * and ln->ln_expire should have some lifetime 1089287546eaSitojun * which is specified by ndp command. 1090287546eaSitojun */ 1091287546eaSitojun ln->ln_state = ND6_LLINFO_REACHABLE; 1092287546eaSitojun } else { 1093287546eaSitojun /* 1094287546eaSitojun * When req == RTM_RESOLVE, rt is created and 1095287546eaSitojun * initialized in rtrequest(), so rt_expire is 0. 1096287546eaSitojun */ 1097287546eaSitojun ln->ln_state = ND6_LLINFO_NOSTATE; 1098287546eaSitojun ln->ln_expire = time_second; 1099287546eaSitojun } 1100287546eaSitojun rt->rt_flags |= RTF_LLINFO; 1101287546eaSitojun ln->ln_next = llinfo_nd6.ln_next; 1102287546eaSitojun llinfo_nd6.ln_next = ln; 1103287546eaSitojun ln->ln_prev = &llinfo_nd6; 1104287546eaSitojun ln->ln_next->ln_prev = ln; 1105287546eaSitojun 1106287546eaSitojun /* 1107287546eaSitojun * check if rt_key(rt) is one of my address assigned 1108287546eaSitojun * to the interface. 1109287546eaSitojun */ 1110287546eaSitojun ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, 1111287546eaSitojun &SIN6(rt_key(rt))->sin6_addr); 1112287546eaSitojun if (ifa) { 1113287546eaSitojun caddr_t macp = nd6_ifptomac(ifp); 1114287546eaSitojun ln->ln_expire = 0; 1115287546eaSitojun ln->ln_state = ND6_LLINFO_REACHABLE; 1116287546eaSitojun if (macp) { 1117287546eaSitojun Bcopy(macp, LLADDR(SDL(gate)), ifp->if_addrlen); 1118287546eaSitojun SDL(gate)->sdl_alen = ifp->if_addrlen; 1119287546eaSitojun } 1120287546eaSitojun if (nd6_useloopback) { 1121287546eaSitojun rt->rt_ifp = &loif[0]; /*XXX*/ 1122287546eaSitojun /* 1123287546eaSitojun * Make sure rt_ifa be equal to the ifaddr 1124287546eaSitojun * corresponding to the address. 1125287546eaSitojun * We need this because when we refer 1126287546eaSitojun * rt_ifa->ia6_flags in ip6_input, we assume 1127287546eaSitojun * that the rt_ifa points to the address instead 1128287546eaSitojun * of the loopback address. 1129287546eaSitojun */ 1130287546eaSitojun if (ifa != rt->rt_ifa) { 1131287546eaSitojun rt->rt_ifa->ifa_refcnt--; 1132287546eaSitojun ifa->ifa_refcnt++; 1133287546eaSitojun rt->rt_ifa = ifa; 1134287546eaSitojun } 1135287546eaSitojun } 1136*f4f4d166Sitojun } else if (rt->rt_flags & RTF_ANNOUNCE) { 1137*f4f4d166Sitojun ln->ln_expire = 0; 1138*f4f4d166Sitojun ln->ln_state = ND6_LLINFO_REACHABLE; 1139*f4f4d166Sitojun 1140*f4f4d166Sitojun /* join solicited node multicast for proxy ND */ 1141*f4f4d166Sitojun if (ifp->if_flags & IFF_MULTICAST) { 1142*f4f4d166Sitojun struct in6_addr llsol; 1143*f4f4d166Sitojun int error; 1144*f4f4d166Sitojun 1145*f4f4d166Sitojun llsol = SIN6(rt_key(rt))->sin6_addr; 1146*f4f4d166Sitojun llsol.s6_addr16[0] = htons(0xff02); 1147*f4f4d166Sitojun llsol.s6_addr16[1] = htons(ifp->if_index); 1148*f4f4d166Sitojun llsol.s6_addr32[1] = 0; 1149*f4f4d166Sitojun llsol.s6_addr32[2] = htonl(1); 1150*f4f4d166Sitojun llsol.s6_addr8[12] = 0xff; 1151*f4f4d166Sitojun 1152*f4f4d166Sitojun (void)in6_addmulti(&llsol, ifp, &error); 1153*f4f4d166Sitojun if (error) 1154*f4f4d166Sitojun printf( 1155*f4f4d166Sitojun "nd6_rtrequest: could not join solicited node multicast (errno=%d)\n", error); 1156*f4f4d166Sitojun } 1157287546eaSitojun } 1158287546eaSitojun break; 1159287546eaSitojun 1160287546eaSitojun case RTM_DELETE: 1161287546eaSitojun if (!ln) 1162287546eaSitojun break; 1163*f4f4d166Sitojun /* leave from solicited node multicast for proxy ND */ 1164*f4f4d166Sitojun if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && 1165*f4f4d166Sitojun (ifp->if_flags & IFF_MULTICAST) != 0) { 1166*f4f4d166Sitojun struct in6_addr llsol; 1167*f4f4d166Sitojun struct in6_multi *in6m; 1168*f4f4d166Sitojun 1169*f4f4d166Sitojun llsol = SIN6(rt_key(rt))->sin6_addr; 1170*f4f4d166Sitojun llsol.s6_addr16[0] = htons(0xff02); 1171*f4f4d166Sitojun llsol.s6_addr16[1] = htons(ifp->if_index); 1172*f4f4d166Sitojun llsol.s6_addr32[1] = 0; 1173*f4f4d166Sitojun llsol.s6_addr32[2] = htonl(1); 1174*f4f4d166Sitojun llsol.s6_addr8[12] = 0xff; 1175*f4f4d166Sitojun 1176*f4f4d166Sitojun IN6_LOOKUP_MULTI(llsol, ifp, in6m); 1177*f4f4d166Sitojun if (in6m) 1178*f4f4d166Sitojun in6_delmulti(in6m); 1179*f4f4d166Sitojun } 1180287546eaSitojun nd6_inuse--; 1181287546eaSitojun ln->ln_next->ln_prev = ln->ln_prev; 1182287546eaSitojun ln->ln_prev->ln_next = ln->ln_next; 1183287546eaSitojun ln->ln_prev = NULL; 1184287546eaSitojun rt->rt_llinfo = 0; 1185287546eaSitojun rt->rt_flags &= ~RTF_LLINFO; 1186287546eaSitojun if (ln->ln_hold) 1187287546eaSitojun m_freem(ln->ln_hold); 1188287546eaSitojun Free((caddr_t)ln); 1189287546eaSitojun } 1190287546eaSitojun } 1191287546eaSitojun 1192287546eaSitojun void 1193287546eaSitojun nd6_p2p_rtrequest(req, rt, sa) 1194287546eaSitojun int req; 1195287546eaSitojun struct rtentry *rt; 1196287546eaSitojun struct sockaddr *sa; /* xxx unused */ 1197287546eaSitojun { 1198287546eaSitojun struct sockaddr *gate = rt->rt_gateway; 1199287546eaSitojun static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 1200287546eaSitojun struct ifnet *ifp = rt->rt_ifp; 1201287546eaSitojun struct ifaddr *ifa; 1202287546eaSitojun 1203287546eaSitojun if (rt->rt_flags & RTF_GATEWAY) 1204287546eaSitojun return; 1205287546eaSitojun 1206287546eaSitojun switch (req) { 1207287546eaSitojun case RTM_ADD: 1208287546eaSitojun /* 1209287546eaSitojun * There is no backward compatibility :) 1210287546eaSitojun * 1211287546eaSitojun * if ((rt->rt_flags & RTF_HOST) == 0 && 1212287546eaSitojun * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) 1213287546eaSitojun * rt->rt_flags |= RTF_CLONING; 1214287546eaSitojun */ 1215287546eaSitojun if (rt->rt_flags & RTF_CLONING) { 1216287546eaSitojun /* 1217287546eaSitojun * Case 1: This route should come from 1218287546eaSitojun * a route to interface. 1219287546eaSitojun */ 1220287546eaSitojun rt_setgate(rt, rt_key(rt), 1221287546eaSitojun (struct sockaddr *)&null_sdl); 1222287546eaSitojun gate = rt->rt_gateway; 1223287546eaSitojun SDL(gate)->sdl_type = ifp->if_type; 1224287546eaSitojun SDL(gate)->sdl_index = ifp->if_index; 1225287546eaSitojun break; 1226287546eaSitojun } 1227287546eaSitojun /* Announce a new entry if requested. */ 1228287546eaSitojun if (rt->rt_flags & RTF_ANNOUNCE) 1229287546eaSitojun nd6_na_output(ifp, 1230287546eaSitojun &SIN6(rt_key(rt))->sin6_addr, 1231287546eaSitojun &SIN6(rt_key(rt))->sin6_addr, 1232287546eaSitojun ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1233*f4f4d166Sitojun 1, NULL); 1234287546eaSitojun /* FALLTHROUGH */ 1235287546eaSitojun case RTM_RESOLVE: 1236287546eaSitojun /* 1237287546eaSitojun * check if rt_key(rt) is one of my address assigned 1238287546eaSitojun * to the interface. 1239287546eaSitojun */ 1240287546eaSitojun ifa = (struct ifaddr *)in6ifa_ifpwithaddr(rt->rt_ifp, 1241287546eaSitojun &SIN6(rt_key(rt))->sin6_addr); 1242287546eaSitojun if (ifa) { 1243287546eaSitojun if (nd6_useloopback) { 1244287546eaSitojun rt->rt_ifp = &loif[0]; /*XXX*/ 1245287546eaSitojun } 1246287546eaSitojun } 1247287546eaSitojun break; 1248287546eaSitojun } 1249287546eaSitojun } 1250287546eaSitojun 1251287546eaSitojun int 1252287546eaSitojun nd6_ioctl(cmd, data, ifp) 1253287546eaSitojun u_long cmd; 1254287546eaSitojun caddr_t data; 1255287546eaSitojun struct ifnet *ifp; 1256287546eaSitojun { 1257287546eaSitojun struct in6_drlist *drl = (struct in6_drlist *)data; 1258287546eaSitojun struct in6_prlist *prl = (struct in6_prlist *)data; 1259287546eaSitojun struct in6_ndireq *ndi = (struct in6_ndireq *)data; 1260287546eaSitojun struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; 1261*f4f4d166Sitojun struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; 1262287546eaSitojun struct nd_defrouter *dr, any; 1263287546eaSitojun struct nd_prefix *pr; 1264287546eaSitojun struct rtentry *rt; 1265287546eaSitojun int i = 0, error = 0; 1266287546eaSitojun int s; 1267287546eaSitojun 1268287546eaSitojun switch (cmd) { 1269287546eaSitojun case SIOCGDRLST_IN6: 1270287546eaSitojun bzero(drl, sizeof(*drl)); 1271287546eaSitojun s = splnet(); 1272*f4f4d166Sitojun dr = TAILQ_FIRST(&nd_defrouter); 1273287546eaSitojun while (dr && i < DRLSTSIZ) { 1274287546eaSitojun drl->defrouter[i].rtaddr = dr->rtaddr; 1275287546eaSitojun if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { 1276287546eaSitojun /* XXX: need to this hack for KAME stack */ 1277287546eaSitojun drl->defrouter[i].rtaddr.s6_addr16[1] = 0; 1278287546eaSitojun } 1279287546eaSitojun else 1280287546eaSitojun log(LOG_ERR, 1281287546eaSitojun "default router list contains a " 1282287546eaSitojun "non-linklocal address(%s)\n", 1283287546eaSitojun ip6_sprintf(&drl->defrouter[i].rtaddr)); 1284287546eaSitojun 1285287546eaSitojun drl->defrouter[i].flags = dr->flags; 1286287546eaSitojun drl->defrouter[i].rtlifetime = dr->rtlifetime; 1287287546eaSitojun drl->defrouter[i].expire = dr->expire; 1288287546eaSitojun drl->defrouter[i].if_index = dr->ifp->if_index; 1289287546eaSitojun i++; 1290*f4f4d166Sitojun dr = TAILQ_NEXT(dr, dr_entry); 1291287546eaSitojun } 1292287546eaSitojun splx(s); 1293287546eaSitojun break; 1294287546eaSitojun case SIOCGPRLST_IN6: 1295*f4f4d166Sitojun /* 1296*f4f4d166Sitojun * XXX meaning of fields, especialy "raflags", is very 1297*f4f4d166Sitojun * differnet between RA prefix list and RR/static prefix list. 1298*f4f4d166Sitojun * how about separating ioctls into two? 1299*f4f4d166Sitojun */ 1300287546eaSitojun bzero(prl, sizeof(*prl)); 1301287546eaSitojun s = splnet(); 1302287546eaSitojun pr = nd_prefix.lh_first; 1303287546eaSitojun while (pr && i < PRLSTSIZ) { 1304287546eaSitojun struct nd_pfxrouter *pfr; 1305287546eaSitojun int j; 1306287546eaSitojun 1307287546eaSitojun prl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; 1308287546eaSitojun prl->prefix[i].raflags = pr->ndpr_raf; 1309287546eaSitojun prl->prefix[i].prefixlen = pr->ndpr_plen; 1310287546eaSitojun prl->prefix[i].vltime = pr->ndpr_vltime; 1311287546eaSitojun prl->prefix[i].pltime = pr->ndpr_pltime; 1312287546eaSitojun prl->prefix[i].if_index = pr->ndpr_ifp->if_index; 1313287546eaSitojun prl->prefix[i].expire = pr->ndpr_expire; 1314287546eaSitojun 1315287546eaSitojun pfr = pr->ndpr_advrtrs.lh_first; 1316287546eaSitojun j = 0; 1317287546eaSitojun while(pfr) { 1318287546eaSitojun if (j < DRLSTSIZ) { 1319287546eaSitojun #define RTRADDR prl->prefix[i].advrtr[j] 1320287546eaSitojun RTRADDR = pfr->router->rtaddr; 1321287546eaSitojun if (IN6_IS_ADDR_LINKLOCAL(&RTRADDR)) { 1322287546eaSitojun /* XXX: hack for KAME */ 1323287546eaSitojun RTRADDR.s6_addr16[1] = 0; 1324287546eaSitojun } 1325287546eaSitojun else 1326287546eaSitojun log(LOG_ERR, 1327287546eaSitojun "a router(%s) advertises " 1328287546eaSitojun "a prefix with " 1329287546eaSitojun "non-link local address\n", 1330287546eaSitojun ip6_sprintf(&RTRADDR)); 1331287546eaSitojun #undef RTRADDR 1332287546eaSitojun } 1333287546eaSitojun j++; 1334287546eaSitojun pfr = pfr->pfr_next; 1335287546eaSitojun } 1336287546eaSitojun prl->prefix[i].advrtrs = j; 1337*f4f4d166Sitojun prl->prefix[i].origin = PR_ORIG_RA; 1338287546eaSitojun 1339287546eaSitojun i++; 1340287546eaSitojun pr = pr->ndpr_next; 1341287546eaSitojun } 1342287546eaSitojun { 1343287546eaSitojun struct rr_prefix *rpp; 1344287546eaSitojun 1345287546eaSitojun for (rpp = LIST_FIRST(&rr_prefix); rpp; 1346287546eaSitojun rpp = LIST_NEXT(rpp, rp_entry)) { 1347287546eaSitojun if (i >= PRLSTSIZ) 1348287546eaSitojun break; 1349287546eaSitojun prl->prefix[i].prefix = rpp->rp_prefix.sin6_addr; 1350287546eaSitojun prl->prefix[i].raflags = rpp->rp_raf; 1351287546eaSitojun prl->prefix[i].prefixlen = rpp->rp_plen; 1352287546eaSitojun prl->prefix[i].vltime = rpp->rp_vltime; 1353287546eaSitojun prl->prefix[i].pltime = rpp->rp_pltime; 1354287546eaSitojun prl->prefix[i].if_index = rpp->rp_ifp->if_index; 1355287546eaSitojun prl->prefix[i].expire = rpp->rp_expire; 1356287546eaSitojun prl->prefix[i].advrtrs = 0; 1357*f4f4d166Sitojun prl->prefix[i].origin = rpp->rp_origin; 1358287546eaSitojun i++; 1359287546eaSitojun } 1360287546eaSitojun } 1361*f4f4d166Sitojun splx(s); 1362287546eaSitojun 1363287546eaSitojun break; 1364287546eaSitojun case SIOCGIFINFO_IN6: 1365287546eaSitojun ndi->ndi = nd_ifinfo[ifp->if_index]; 1366287546eaSitojun break; 1367*f4f4d166Sitojun case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ 1368287546eaSitojun /* flush default router list */ 1369287546eaSitojun /* 1370287546eaSitojun * xxx sumikawa: should not delete route if default 1371287546eaSitojun * route equals to the top of default router list 1372287546eaSitojun */ 1373287546eaSitojun bzero(&any, sizeof(any)); 1374287546eaSitojun defrouter_delreq(&any, 0); 1375*f4f4d166Sitojun defrouter_select(); 1376287546eaSitojun /* xxx sumikawa: flush prefix list */ 1377287546eaSitojun break; 1378287546eaSitojun case SIOCSPFXFLUSH_IN6: 1379287546eaSitojun { 1380287546eaSitojun /* flush all the prefix advertised by routers */ 1381287546eaSitojun struct nd_prefix *pr, *next; 1382287546eaSitojun 1383287546eaSitojun s = splnet(); 138458aa7d74Sangelos 1385287546eaSitojun for (pr = nd_prefix.lh_first; pr; pr = next) { 1386287546eaSitojun next = pr->ndpr_next; 1387287546eaSitojun if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) 1388287546eaSitojun in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); 1389287546eaSitojun prelist_remove(pr); 1390287546eaSitojun } 1391287546eaSitojun splx(s); 1392287546eaSitojun break; 1393287546eaSitojun } 1394287546eaSitojun case SIOCSRTRFLUSH_IN6: 1395287546eaSitojun { 1396287546eaSitojun /* flush all the default routers */ 1397287546eaSitojun struct nd_defrouter *dr, *next; 1398287546eaSitojun 1399287546eaSitojun s = splnet(); 1400*f4f4d166Sitojun if ((dr = TAILQ_FIRST(&nd_defrouter)) != NULL) { 1401287546eaSitojun /* 1402287546eaSitojun * The first entry of the list may be stored in 1403287546eaSitojun * the routing table, so we'll delete it later. 1404287546eaSitojun */ 1405*f4f4d166Sitojun for (dr = TAILQ_NEXT(dr, dr_entry); dr; dr = next) { 1406*f4f4d166Sitojun next = TAILQ_NEXT(dr, dr_entry); 1407287546eaSitojun defrtrlist_del(dr); 1408287546eaSitojun } 1409*f4f4d166Sitojun defrtrlist_del(TAILQ_FIRST(&nd_defrouter)); 1410287546eaSitojun } 1411287546eaSitojun splx(s); 1412287546eaSitojun break; 1413287546eaSitojun } 1414287546eaSitojun case SIOCGNBRINFO_IN6: 1415287546eaSitojun { 1416287546eaSitojun struct llinfo_nd6 *ln; 1417287546eaSitojun struct in6_addr nb_addr = nbi->addr; /* make local for safety */ 1418287546eaSitojun 1419287546eaSitojun /* 1420287546eaSitojun * XXX: KAME specific hack for scoped addresses 1421287546eaSitojun * XXXX: for other scopes than link-local? 1422287546eaSitojun */ 1423287546eaSitojun if (IN6_IS_ADDR_LINKLOCAL(&nbi->addr) || 1424287546eaSitojun IN6_IS_ADDR_MC_LINKLOCAL(&nbi->addr)) { 1425287546eaSitojun u_int16_t *idp = (u_int16_t *)&nb_addr.s6_addr[2]; 1426287546eaSitojun 1427287546eaSitojun if (*idp == 0) 1428287546eaSitojun *idp = htons(ifp->if_index); 1429287546eaSitojun } 1430287546eaSitojun 1431287546eaSitojun s = splnet(); 143258aa7d74Sangelos 1433287546eaSitojun if ((rt = nd6_lookup(&nb_addr, 0, ifp)) == NULL) { 1434287546eaSitojun error = EINVAL; 143591e69634Sitojun splx(s); 1436287546eaSitojun break; 1437287546eaSitojun } 1438287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 1439287546eaSitojun nbi->state = ln->ln_state; 1440287546eaSitojun nbi->asked = ln->ln_asked; 1441287546eaSitojun nbi->isrouter = ln->ln_router; 1442287546eaSitojun nbi->expire = ln->ln_expire; 1443287546eaSitojun splx(s); 1444287546eaSitojun 1445287546eaSitojun break; 1446287546eaSitojun } 1447*f4f4d166Sitojun case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ 1448*f4f4d166Sitojun ndif->ifindex = nd6_defifindex; 1449*f4f4d166Sitojun break; 1450*f4f4d166Sitojun case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ 1451*f4f4d166Sitojun return(nd6_setdefaultiface(ndif->ifindex)); 1452*f4f4d166Sitojun break; 1453287546eaSitojun } 1454287546eaSitojun return(error); 1455287546eaSitojun } 1456287546eaSitojun 1457287546eaSitojun /* 1458287546eaSitojun * Create neighbor cache entry and cache link-layer address, 1459287546eaSitojun * on reception of inbound ND6 packets. (RS/RA/NS/redirect) 1460287546eaSitojun */ 1461287546eaSitojun struct rtentry * 1462287546eaSitojun nd6_cache_lladdr(ifp, from, lladdr, lladdrlen, type, code) 1463287546eaSitojun struct ifnet *ifp; 1464287546eaSitojun struct in6_addr *from; 1465287546eaSitojun char *lladdr; 1466287546eaSitojun int lladdrlen; 1467287546eaSitojun int type; /* ICMP6 type */ 1468287546eaSitojun int code; /* type dependent information */ 1469287546eaSitojun { 1470287546eaSitojun struct rtentry *rt = NULL; 1471287546eaSitojun struct llinfo_nd6 *ln = NULL; 1472287546eaSitojun int is_newentry; 1473287546eaSitojun struct sockaddr_dl *sdl = NULL; 1474287546eaSitojun int do_update; 1475287546eaSitojun int olladdr; 1476287546eaSitojun int llchange; 1477287546eaSitojun int newstate = 0; 1478287546eaSitojun long time_second = time.tv_sec; 1479287546eaSitojun 1480287546eaSitojun if (!ifp) 1481287546eaSitojun panic("ifp == NULL in nd6_cache_lladdr"); 1482287546eaSitojun if (!from) 1483287546eaSitojun panic("from == NULL in nd6_cache_lladdr"); 1484287546eaSitojun 1485287546eaSitojun /* nothing must be updated for unspecified address */ 1486287546eaSitojun if (IN6_IS_ADDR_UNSPECIFIED(from)) 1487287546eaSitojun return NULL; 1488287546eaSitojun 1489287546eaSitojun /* 1490287546eaSitojun * Validation about ifp->if_addrlen and lladdrlen must be done in 1491287546eaSitojun * the caller. 1492287546eaSitojun * 1493287546eaSitojun * XXX If the link does not have link-layer adderss, what should 1494287546eaSitojun * we do? (ifp->if_addrlen == 0) 1495287546eaSitojun * Spec says nothing in sections for RA, RS and NA. There's small 1496287546eaSitojun * description on it in NS section (RFC 2461 7.2.3). 1497287546eaSitojun */ 1498287546eaSitojun 1499287546eaSitojun rt = nd6_lookup(from, 0, ifp); 1500287546eaSitojun if (!rt) { 1501287546eaSitojun #if 0 1502287546eaSitojun /* nothing must be done if there's no lladdr */ 1503287546eaSitojun if (!lladdr || !lladdrlen) 1504287546eaSitojun return NULL; 1505287546eaSitojun #endif 1506287546eaSitojun 1507287546eaSitojun rt = nd6_lookup(from, 1, ifp); 1508287546eaSitojun is_newentry = 1; 1509287546eaSitojun } else 1510287546eaSitojun is_newentry = 0; 1511287546eaSitojun 1512287546eaSitojun if (!rt) 1513287546eaSitojun return NULL; 1514287546eaSitojun if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { 1515287546eaSitojun fail: 1516287546eaSitojun nd6_free(rt); 1517287546eaSitojun return NULL; 1518287546eaSitojun } 1519287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 1520287546eaSitojun if (!ln) 1521287546eaSitojun goto fail; 1522287546eaSitojun if (!rt->rt_gateway) 1523287546eaSitojun goto fail; 1524287546eaSitojun if (rt->rt_gateway->sa_family != AF_LINK) 1525287546eaSitojun goto fail; 1526287546eaSitojun sdl = SDL(rt->rt_gateway); 1527287546eaSitojun 1528287546eaSitojun olladdr = (sdl->sdl_alen) ? 1 : 0; 1529287546eaSitojun if (olladdr && lladdr) { 1530287546eaSitojun if (bcmp(lladdr, LLADDR(sdl), ifp->if_addrlen)) 1531287546eaSitojun llchange = 1; 1532287546eaSitojun else 1533287546eaSitojun llchange = 0; 1534287546eaSitojun } else 1535287546eaSitojun llchange = 0; 1536287546eaSitojun 1537287546eaSitojun /* 1538287546eaSitojun * newentry olladdr lladdr llchange (*=record) 1539287546eaSitojun * 0 n n -- (1) 1540287546eaSitojun * 0 y n -- (2) 1541287546eaSitojun * 0 n y -- (3) * STALE 1542287546eaSitojun * 0 y y n (4) * 1543287546eaSitojun * 0 y y y (5) * STALE 1544287546eaSitojun * 1 -- n -- (6) NOSTATE(= PASSIVE) 1545287546eaSitojun * 1 -- y -- (7) * STALE 1546287546eaSitojun */ 1547287546eaSitojun 1548287546eaSitojun if (lladdr) { /*(3-5) and (7)*/ 1549287546eaSitojun /* 1550287546eaSitojun * Record source link-layer address 1551287546eaSitojun * XXX is it dependent to ifp->if_type? 1552287546eaSitojun */ 1553287546eaSitojun sdl->sdl_alen = ifp->if_addrlen; 1554287546eaSitojun bcopy(lladdr, LLADDR(sdl), ifp->if_addrlen); 1555287546eaSitojun } 1556287546eaSitojun 1557287546eaSitojun if (!is_newentry) { 1558287546eaSitojun if ((!olladdr && lladdr) /*(3)*/ 1559287546eaSitojun || (olladdr && lladdr && llchange)) { /*(5)*/ 1560287546eaSitojun do_update = 1; 1561287546eaSitojun newstate = ND6_LLINFO_STALE; 1562287546eaSitojun } else /*(1-2,4)*/ 1563287546eaSitojun do_update = 0; 1564287546eaSitojun } else { 1565287546eaSitojun do_update = 1; 1566287546eaSitojun if (!lladdr) /*(6)*/ 1567287546eaSitojun newstate = ND6_LLINFO_NOSTATE; 1568287546eaSitojun else /*(7)*/ 1569287546eaSitojun newstate = ND6_LLINFO_STALE; 1570287546eaSitojun } 1571287546eaSitojun 1572287546eaSitojun if (do_update) { 1573287546eaSitojun /* 1574287546eaSitojun * Update the state of the neighbor cache. 1575287546eaSitojun */ 1576287546eaSitojun ln->ln_state = newstate; 1577287546eaSitojun 1578287546eaSitojun if (ln->ln_state == ND6_LLINFO_STALE) { 1579287546eaSitojun rt->rt_flags &= ~RTF_REJECT; 1580287546eaSitojun if (ln->ln_hold) { 1581287546eaSitojun #ifdef OLDIP6OUTPUT 1582287546eaSitojun (*ifp->if_output)(ifp, ln->ln_hold, 1583287546eaSitojun rt_key(rt), rt); 1584287546eaSitojun #else 1585287546eaSitojun nd6_output(ifp, ln->ln_hold, 1586287546eaSitojun (struct sockaddr_in6 *)rt_key(rt), 1587287546eaSitojun rt); 1588287546eaSitojun #endif 1589287546eaSitojun ln->ln_hold = 0; 1590287546eaSitojun } 1591287546eaSitojun } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { 1592287546eaSitojun /* probe right away */ 1593287546eaSitojun ln->ln_expire = time_second; 1594287546eaSitojun } 1595287546eaSitojun } 1596287546eaSitojun 1597287546eaSitojun /* 1598287546eaSitojun * ICMP6 type dependent behavior. 1599287546eaSitojun * 1600287546eaSitojun * NS: clear IsRouter if new entry 1601287546eaSitojun * RS: clear IsRouter 1602287546eaSitojun * RA: set IsRouter if there's lladdr 1603287546eaSitojun * redir: clear IsRouter if new entry 1604287546eaSitojun * 1605287546eaSitojun * RA case, (1): 1606287546eaSitojun * The spec says that we must set IsRouter in the following cases: 1607287546eaSitojun * - If lladdr exist, set IsRouter. This means (1-5). 1608287546eaSitojun * - If it is old entry (!newentry), set IsRouter. This means (7). 1609287546eaSitojun * So, based on the spec, in (1-5) and (7) cases we must set IsRouter. 1610287546eaSitojun * A quetion arises for (1) case. (1) case has no lladdr in the 1611287546eaSitojun * neighbor cache, this is similar to (6). 1612287546eaSitojun * This case is rare but we figured that we MUST NOT set IsRouter. 1613287546eaSitojun * 1614287546eaSitojun * newentry olladdr lladdr llchange NS RS RA redir 1615287546eaSitojun * D R 1616287546eaSitojun * 0 n n -- (1) c ? s 1617287546eaSitojun * 0 y n -- (2) c s s 1618287546eaSitojun * 0 n y -- (3) c s s 1619287546eaSitojun * 0 y y n (4) c s s 1620287546eaSitojun * 0 y y y (5) c s s 1621287546eaSitojun * 1 -- n -- (6) c c c s 1622287546eaSitojun * 1 -- y -- (7) c c s c s 1623287546eaSitojun * 1624287546eaSitojun * (c=clear s=set) 1625287546eaSitojun */ 1626287546eaSitojun switch (type & 0xff) { 1627287546eaSitojun case ND_NEIGHBOR_SOLICIT: 1628287546eaSitojun /* 1629287546eaSitojun * New entry must have is_router flag cleared. 1630287546eaSitojun */ 1631287546eaSitojun if (is_newentry) /*(6-7)*/ 1632287546eaSitojun ln->ln_router = 0; 1633287546eaSitojun break; 1634287546eaSitojun case ND_REDIRECT: 1635287546eaSitojun /* 1636287546eaSitojun * If the icmp is a redirect to a better router, always set the 1637287546eaSitojun * is_router flag. Otherwise, if the entry is newly created, 1638287546eaSitojun * clear the flag. [RFC 2461, sec 8.3] 1639287546eaSitojun * 1640287546eaSitojun */ 1641287546eaSitojun if (code == ND_REDIRECT_ROUTER) 1642287546eaSitojun ln->ln_router = 1; 1643287546eaSitojun else if (is_newentry) /*(6-7)*/ 1644287546eaSitojun ln->ln_router = 0; 1645287546eaSitojun break; 1646287546eaSitojun case ND_ROUTER_SOLICIT: 1647287546eaSitojun /* 1648287546eaSitojun * is_router flag must always be cleared. 1649287546eaSitojun */ 1650287546eaSitojun ln->ln_router = 0; 1651287546eaSitojun break; 1652287546eaSitojun case ND_ROUTER_ADVERT: 1653287546eaSitojun /* 1654287546eaSitojun * Mark an entry with lladdr as a router. 1655287546eaSitojun */ 1656287546eaSitojun if ((!is_newentry && (olladdr || lladdr)) /*(2-5)*/ 1657287546eaSitojun || (is_newentry && lladdr)) { /*(7)*/ 1658287546eaSitojun ln->ln_router = 1; 1659287546eaSitojun } 1660287546eaSitojun break; 1661287546eaSitojun } 1662287546eaSitojun 1663287546eaSitojun return rt; 1664287546eaSitojun } 1665287546eaSitojun 1666287546eaSitojun static void 1667287546eaSitojun nd6_slowtimo(ignored_arg) 1668287546eaSitojun void *ignored_arg; 1669287546eaSitojun { 1670287546eaSitojun int s = splnet(); 1671287546eaSitojun register int i; 1672287546eaSitojun register struct nd_ifinfo *nd6if; 1673287546eaSitojun 1674287546eaSitojun timeout(nd6_slowtimo, (caddr_t)0, ND6_SLOWTIMER_INTERVAL * hz); 1675287546eaSitojun for (i = 1; i < if_index + 1; i++) { 1676287546eaSitojun nd6if = &nd_ifinfo[i]; 1677287546eaSitojun if (nd6if->basereachable && /* already initialized */ 1678287546eaSitojun (nd6if->recalctm -= ND6_SLOWTIMER_INTERVAL) <= 0) { 1679287546eaSitojun /* 1680287546eaSitojun * Since reachable time rarely changes by router 1681287546eaSitojun * advertisements, we SHOULD insure that a new random 1682287546eaSitojun * value gets recomputed at least once every few hours. 1683287546eaSitojun * (RFC 2461, 6.3.4) 1684287546eaSitojun */ 1685287546eaSitojun nd6if->recalctm = nd6_recalc_reachtm_interval; 1686287546eaSitojun nd6if->reachable = ND_COMPUTE_RTIME(nd6if->basereachable); 1687287546eaSitojun } 1688287546eaSitojun } 1689287546eaSitojun splx(s); 1690287546eaSitojun } 1691287546eaSitojun 1692287546eaSitojun #define senderr(e) { error = (e); goto bad;} 1693287546eaSitojun int 1694287546eaSitojun nd6_output(ifp, m0, dst, rt0) 1695287546eaSitojun register struct ifnet *ifp; 1696287546eaSitojun struct mbuf *m0; 1697287546eaSitojun struct sockaddr_in6 *dst; 1698287546eaSitojun struct rtentry *rt0; 1699287546eaSitojun { 1700287546eaSitojun register struct mbuf *m = m0; 1701287546eaSitojun register struct rtentry *rt = rt0; 1702287546eaSitojun struct llinfo_nd6 *ln = NULL; 1703287546eaSitojun int error = 0; 1704287546eaSitojun long time_second = time.tv_sec; 1705287546eaSitojun 1706287546eaSitojun if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) 1707287546eaSitojun goto sendpkt; 1708287546eaSitojun 1709287546eaSitojun /* 1710287546eaSitojun * XXX: we currently do not make neighbor cache on any interface 1711287546eaSitojun * other than ARCnet, Ethernet and FDDI. 1712287546eaSitojun */ 1713287546eaSitojun switch (ifp->if_type) { 1714287546eaSitojun case IFT_ARCNET: 1715287546eaSitojun case IFT_ETHER: 1716287546eaSitojun case IFT_FDDI: 1717287546eaSitojun break; 1718287546eaSitojun default: 1719287546eaSitojun goto sendpkt; 1720287546eaSitojun } 1721287546eaSitojun 1722287546eaSitojun /* 1723287546eaSitojun * next hop determination. This routine is derived from ether_outpout. 1724287546eaSitojun */ 1725287546eaSitojun if (rt) { 1726287546eaSitojun if ((rt->rt_flags & RTF_UP) == 0) { 1727287546eaSitojun if ((rt0 = rt = rtalloc1((struct sockaddr *)dst, 1)) != 1728287546eaSitojun NULL) 1729287546eaSitojun { 1730287546eaSitojun rt->rt_refcnt--; 1731287546eaSitojun if (rt->rt_ifp != ifp) 1732287546eaSitojun return nd6_output(ifp, m0, dst, rt); /* XXX: loop care? */ 1733287546eaSitojun } else 1734287546eaSitojun senderr(EHOSTUNREACH); 1735287546eaSitojun } 1736287546eaSitojun if (rt->rt_flags & RTF_GATEWAY) { 1737287546eaSitojun if (rt->rt_gwroute == 0) 1738287546eaSitojun goto lookup; 1739287546eaSitojun if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 1740287546eaSitojun rtfree(rt); rt = rt0; 1741287546eaSitojun lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); 1742287546eaSitojun if ((rt = rt->rt_gwroute) == 0) 1743287546eaSitojun senderr(EHOSTUNREACH); 1744287546eaSitojun } 1745287546eaSitojun } 1746287546eaSitojun if (rt->rt_flags & RTF_REJECT) 1747287546eaSitojun senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 1748287546eaSitojun } 1749287546eaSitojun 1750287546eaSitojun /* 1751287546eaSitojun * Address resolution or Neighbor Unreachability Detection 1752287546eaSitojun * for the next hop. 1753287546eaSitojun * At this point, the destination of the packet must be a unicast 1754287546eaSitojun * or an anycast address(i.e. not a multicast). 1755287546eaSitojun */ 1756287546eaSitojun 1757287546eaSitojun /* Look up the neighbor cache for the nexthop */ 1758287546eaSitojun if (rt && (rt->rt_flags & RTF_LLINFO) != 0) 1759287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 1760287546eaSitojun else { 1761287546eaSitojun if ((rt = nd6_lookup(&dst->sin6_addr, 1, ifp)) != NULL) 1762287546eaSitojun ln = (struct llinfo_nd6 *)rt->rt_llinfo; 1763287546eaSitojun } 1764287546eaSitojun if (!ln || !rt) { 1765287546eaSitojun log(LOG_DEBUG, "nd6_output: can't allocate llinfo for %s " 1766287546eaSitojun "(ln=%p, rt=%p)\n", 1767287546eaSitojun ip6_sprintf(&dst->sin6_addr), ln, rt); 1768287546eaSitojun senderr(EIO); /* XXX: good error? */ 1769287546eaSitojun } 1770287546eaSitojun 1771287546eaSitojun 1772287546eaSitojun /* 1773287546eaSitojun * The first time we send a packet to a neighbor whose entry is 1774287546eaSitojun * STALE, we have to change the state to DELAY and a sets a timer to 1775287546eaSitojun * expire in DELAY_FIRST_PROBE_TIME seconds to ensure do 1776287546eaSitojun * neighbor unreachability detection on expiration. 1777287546eaSitojun * (RFC 2461 7.3.3) 1778287546eaSitojun */ 1779287546eaSitojun if (ln->ln_state == ND6_LLINFO_STALE) { 1780287546eaSitojun ln->ln_asked = 0; 1781287546eaSitojun ln->ln_state = ND6_LLINFO_DELAY; 1782287546eaSitojun ln->ln_expire = time_second + nd6_delay; 1783287546eaSitojun } 1784287546eaSitojun 1785287546eaSitojun /* 1786287546eaSitojun * If the neighbor cache entry has a state other than INCOMPLETE 1787287546eaSitojun * (i.e. its link-layer address is already reloved), just 1788287546eaSitojun * send the packet. 1789287546eaSitojun */ 1790287546eaSitojun if (ln->ln_state > ND6_LLINFO_INCOMPLETE) 1791287546eaSitojun goto sendpkt; 1792287546eaSitojun 1793287546eaSitojun /* 1794287546eaSitojun * There is a neighbor cache entry, but no ethernet address 1795287546eaSitojun * response yet. Replace the held mbuf (if any) with this 1796287546eaSitojun * latest one. 1797287546eaSitojun * 1798287546eaSitojun * XXX Does the code conform to rate-limiting rule? 1799287546eaSitojun * (RFC 2461 7.2.2) 1800287546eaSitojun */ 1801287546eaSitojun if (ln->ln_state == ND6_LLINFO_WAITDELETE || 1802287546eaSitojun ln->ln_state == ND6_LLINFO_NOSTATE) 1803287546eaSitojun ln->ln_state = ND6_LLINFO_INCOMPLETE; 1804287546eaSitojun if (ln->ln_hold) 1805287546eaSitojun m_freem(ln->ln_hold); 1806287546eaSitojun ln->ln_hold = m; 1807287546eaSitojun if (ln->ln_expire) { 1808287546eaSitojun rt->rt_flags &= ~RTF_REJECT; 1809287546eaSitojun if (ln->ln_asked < nd6_mmaxtries && 1810287546eaSitojun ln->ln_expire < time_second) { 1811287546eaSitojun ln->ln_asked++; 1812287546eaSitojun ln->ln_expire = time_second + 1813287546eaSitojun nd_ifinfo[ifp->if_index].retrans / 1000; 1814287546eaSitojun nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0); 1815287546eaSitojun } 1816287546eaSitojun } 1817287546eaSitojun return(0); 1818287546eaSitojun 1819287546eaSitojun sendpkt: 1820287546eaSitojun return((*ifp->if_output)(ifp, m, (struct sockaddr *)dst, rt)); 1821287546eaSitojun 1822287546eaSitojun bad: 1823287546eaSitojun if (m) 1824287546eaSitojun m_freem(m); 1825287546eaSitojun return (error); 1826287546eaSitojun } 1827287546eaSitojun #undef senderr 1828287546eaSitojun 1829287546eaSitojun int 1830287546eaSitojun nd6_storelladdr(ifp, rt, m, dst, desten) 1831287546eaSitojun struct ifnet *ifp; 1832287546eaSitojun struct rtentry *rt; 1833287546eaSitojun struct mbuf *m; 1834287546eaSitojun struct sockaddr *dst; 1835287546eaSitojun u_char *desten; 1836287546eaSitojun { 1837287546eaSitojun struct sockaddr_dl *sdl; 1838287546eaSitojun 1839287546eaSitojun if (m->m_flags & M_MCAST) { 1840287546eaSitojun switch (ifp->if_type) { 1841287546eaSitojun case IFT_ETHER: 1842287546eaSitojun case IFT_FDDI: 1843287546eaSitojun ETHER_MAP_IPV6_MULTICAST(&SIN6(dst)->sin6_addr, 1844287546eaSitojun desten); 1845287546eaSitojun return(1); 1846287546eaSitojun break; 1847287546eaSitojun case IFT_ARCNET: 1848287546eaSitojun *desten = 0; 1849287546eaSitojun return(1); 1850287546eaSitojun default: 1851287546eaSitojun return(0); 1852287546eaSitojun } 1853287546eaSitojun } 1854287546eaSitojun 1855287546eaSitojun if (rt == NULL || 1856287546eaSitojun rt->rt_gateway->sa_family != AF_LINK) { 1857287546eaSitojun printf("nd6_storelladdr: something odd happens\n"); 1858287546eaSitojun return(0); 1859287546eaSitojun } 1860287546eaSitojun sdl = SDL(rt->rt_gateway); 1861287546eaSitojun if (sdl->sdl_alen != 0) 1862287546eaSitojun bcopy(LLADDR(sdl), desten, sdl->sdl_alen); 1863287546eaSitojun 1864287546eaSitojun return(1); 1865287546eaSitojun } 1866