Sun Sep 1 18:54:38 2019 UTC ()
inet6: Send RTM_MISS when we fail to resolve an address.

Takes the same approach as when adding a new address - we no longer
announce the new lladdr right away but we announce the result.
This will either be RTM_ADD or RTM_MISS.
RTM_DELETE is only sent if we have a lladdr assigned OR gc'ed.

This results in less messages via route(4) and tells us when a new
lladdr has been added (RTM_ADD), changed (RTM_CHANGE), deleted (RTM_DELETED)
or has failed to been resolved (RTM_MISS). The latter case can be
interpreted as unreachable.


(roy)
diff -r1.251 -r1.252 src/sys/net/rtsock.c
diff -r1.261 -r1.262 src/sys/netinet6/nd6.c
diff -r1.171 -r1.172 src/sys/netinet6/nd6_nbr.c

cvs diff -r1.251 -r1.252 src/sys/net/rtsock.c (expand / switch to unified diff)

--- src/sys/net/rtsock.c 2019/08/22 21:14:45 1.251
+++ src/sys/net/rtsock.c 2019/09/01 18:54:38 1.252
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: rtsock.c,v 1.251 2019/08/22 21:14:45 roy Exp $ */ 1/* $NetBSD: rtsock.c,v 1.252 2019/09/01 18:54:38 roy Exp $ */
2 2
3/* 3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -51,27 +51,27 @@ @@ -51,27 +51,27 @@
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE. 58 * SUCH DAMAGE.
59 * 59 *
60 * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 60 * @(#)rtsock.c 8.7 (Berkeley) 10/12/95
61 */ 61 */
62 62
63#include <sys/cdefs.h> 63#include <sys/cdefs.h>
64__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.251 2019/08/22 21:14:45 roy Exp $"); 64__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.252 2019/09/01 18:54:38 roy Exp $");
65 65
66#ifdef _KERNEL_OPT 66#ifdef _KERNEL_OPT
67#include "opt_inet.h" 67#include "opt_inet.h"
68#include "opt_compat_netbsd.h" 68#include "opt_compat_netbsd.h"
69#endif 69#endif
70 70
71#include <sys/param.h> 71#include <sys/param.h>
72#include <sys/systm.h> 72#include <sys/systm.h>
73#include <sys/proc.h> 73#include <sys/proc.h>
74#include <sys/socket.h> 74#include <sys/socket.h>
75#include <sys/socketvar.h> 75#include <sys/socketvar.h>
76#include <sys/domain.h> 76#include <sys/domain.h>
77#include <sys/protosw.h> 77#include <sys/protosw.h>
@@ -142,41 +142,41 @@ if_addrflags(struct ifaddr *ifa) @@ -142,41 +142,41 @@ if_addrflags(struct ifaddr *ifa)
142 142
143 143
144/* 144/*
145 * Send a routing message as mimicing that a cloned route is added. 145 * Send a routing message as mimicing that a cloned route is added.
146 */ 146 */
147void 147void
148rt_clonedmsg(int type, const struct sockaddr *dst, const uint8_t *lladdr, 148rt_clonedmsg(int type, const struct sockaddr *dst, const uint8_t *lladdr,
149 const struct ifnet *ifp) 149 const struct ifnet *ifp)
150{ 150{
151 struct rt_addrinfo info; 151 struct rt_addrinfo info;
152 /* Mimic flags exactly */ 152 /* Mimic flags exactly */
153#define RTF_LLINFO 0x400 153#define RTF_LLINFO 0x400
154#define RTF_CLONED 0x2000 154#define RTF_CLONED 0x2000
155 int flags = RTF_HOST | RTF_DONE | RTF_LLINFO | RTF_CLONED; 155 int flags = RTF_DONE;
156 union { 156 union {
157 struct sockaddr sa; 157 struct sockaddr sa;
158 struct sockaddr_storage ss; 158 struct sockaddr_storage ss;
159 struct sockaddr_dl sdl; 159 struct sockaddr_dl sdl;
160 } u; 160 } u;
161 uint8_t namelen = strlen(ifp->if_xname); 
162 uint8_t addrlen = ifp->if_addrlen; 
163 161
164 if (type != RTM_DELETE) 162 if (type != RTM_MISS)
 163 flags |= RTF_HOST | RTF_CLONED | RTF_LLINFO;
 164 if (type == RTM_ADD || type == RTM_CHANGE)
165 flags |= RTF_UP; 165 flags |= RTF_UP;
166 memset(&info, 0, sizeof(info)); 166 memset(&info, 0, sizeof(info));
167 info.rti_info[RTAX_DST] = dst; 167 info.rti_info[RTAX_DST] = dst;
168 sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type, 168 sockaddr_dl_init(&u.sdl, sizeof(u.ss), ifp->if_index, ifp->if_type,
169 NULL, namelen, lladdr, addrlen); 169 NULL, 0, lladdr, ifp->if_addrlen);
170 info.rti_info[RTAX_GATEWAY] = &u.sa; 170 info.rti_info[RTAX_GATEWAY] = &u.sa;
171 171
172 rt_missmsg(type, &info, flags, 0); 172 rt_missmsg(type, &info, flags, 0);
173#undef RTF_LLINFO 173#undef RTF_LLINFO
174#undef RTF_CLONED 174#undef RTF_CLONED
175} 175}
176 176
177 177
178/* 178/*
179 * The remaining code implements the routing-table sysctl node. It is 179 * The remaining code implements the routing-table sysctl node. It is
180 * compiled only for the non-COMPAT case. 180 * compiled only for the non-COMPAT case.
181 */ 181 */
182 182

cvs diff -r1.261 -r1.262 src/sys/netinet6/nd6.c (expand / switch to unified diff)

--- src/sys/netinet6/nd6.c 2019/08/31 01:49:45 1.261
+++ src/sys/netinet6/nd6.c 2019/09/01 18:54:38 1.262
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: nd6.c,v 1.261 2019/08/31 01:49:45 roy Exp $ */ 1/* $NetBSD: nd6.c,v 1.262 2019/09/01 18:54:38 roy Exp $ */
2/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ 2/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
3 3
4/* 4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
@@ -21,27 +21,27 @@ @@ -21,27 +21,27 @@
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.261 2019/08/31 01:49:45 roy Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.262 2019/09/01 18:54:38 roy Exp $");
35 35
36#ifdef _KERNEL_OPT 36#ifdef _KERNEL_OPT
37#include "opt_net_mpsafe.h" 37#include "opt_net_mpsafe.h"
38#endif 38#endif
39 39
40#include "bridge.h" 40#include "bridge.h"
41#include "carp.h" 41#include "carp.h"
42 42
43#include <sys/param.h> 43#include <sys/param.h>
44#include <sys/systm.h> 44#include <sys/systm.h>
45#include <sys/callout.h> 45#include <sys/callout.h>
46#include <sys/kmem.h> 46#include <sys/kmem.h>
47#include <sys/mbuf.h> 47#include <sys/mbuf.h>
@@ -451,71 +451,76 @@ nd6_llinfo_get_holdsrc(struct llentry *l @@ -451,71 +451,76 @@ nd6_llinfo_get_holdsrc(struct llentry *l
451 src = NULL; 451 src = NULL;
452 452
453 return src; 453 return src;
454} 454}
455 455
456static void 456static void
457nd6_llinfo_timer(void *arg) 457nd6_llinfo_timer(void *arg)
458{ 458{
459 struct llentry *ln = arg; 459 struct llentry *ln = arg;
460 struct ifnet *ifp; 460 struct ifnet *ifp;
461 struct nd_ifinfo *ndi = NULL; 461 struct nd_ifinfo *ndi = NULL;
462 bool send_ns = false; 462 bool send_ns = false;
463 const struct in6_addr *daddr6 = NULL; 463 const struct in6_addr *daddr6 = NULL;
 464 const struct in6_addr *taddr6 = &ln->r_l3addr.addr6;
 465 struct sockaddr_in6 sin6;
464 466
465 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 467 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
466 468
467 LLE_WLOCK(ln); 469 LLE_WLOCK(ln);
468 if ((ln->la_flags & LLE_LINKED) == 0) 470 if ((ln->la_flags & LLE_LINKED) == 0)
469 goto out; 471 goto out;
470 if (ln->ln_ntick > 0) { 472 if (ln->ln_ntick > 0) {
471 nd6_llinfo_settimer(ln, ln->ln_ntick); 473 nd6_llinfo_settimer(ln, ln->ln_ntick);
472 goto out; 474 goto out;
473 } 475 }
474 476
475 
476 ifp = ln->lle_tbl->llt_ifp; 477 ifp = ln->lle_tbl->llt_ifp;
477 KASSERT(ifp != NULL); 478 KASSERT(ifp != NULL);
478 479
479 ndi = ND_IFINFO(ifp); 480 ndi = ND_IFINFO(ifp);
480 481
481 switch (ln->ln_state) { 482 switch (ln->ln_state) {
482 case ND6_LLINFO_INCOMPLETE: 483 case ND6_LLINFO_INCOMPLETE:
483 if (ln->ln_asked < nd6_mmaxtries) { 484 if (ln->ln_asked < nd6_mmaxtries) {
484 ln->ln_asked++; 485 ln->ln_asked++;
485 send_ns = true; 486 send_ns = true;
486 } else { 487 break;
487 struct mbuf *m = ln->ln_hold; 488 }
488 if (m) { 
489 struct mbuf *m0; 
490 489
491 /* 490 if (ln->ln_hold) {
492 * assuming every packet in ln_hold has 491 struct mbuf *m = ln->ln_hold, *m0;
493 * the same IP header 492
494 */ 493 /*
495 m0 = m->m_nextpkt; 494 * assuming every packet in ln_hold has
496 m->m_nextpkt = NULL; 495 * the same IP header
497 ln->ln_hold = m0; 496 */
498 clear_llinfo_pqueue(ln); 497 m0 = m->m_nextpkt;
499 } 498 m->m_nextpkt = NULL;
500 LLE_REMREF(ln); 499 ln->ln_hold = m0;
501 nd6_free(ln, 0); 500 clear_llinfo_pqueue(ln);
502 ln = NULL; 501
503 if (m != NULL) { 502 icmp6_error2(m, ICMP6_DST_UNREACH,
504 icmp6_error2(m, ICMP6_DST_UNREACH, 503 ICMP6_DST_UNREACH_ADDR, 0, ifp);
505 ICMP6_DST_UNREACH_ADDR, 0, ifp); 
506 } 
507 } 504 }
 505
 506 sockaddr_in6_init(&sin6, taddr6, 0, 0, 0);
 507 rt_clonedmsg(RTM_MISS, sin6tosa(&sin6), NULL, ifp);
 508
 509 LLE_REMREF(ln);
 510 nd6_free(ln, 0);
 511 ln = NULL;
508 break; 512 break;
 513
509 case ND6_LLINFO_REACHABLE: 514 case ND6_LLINFO_REACHABLE:
510 if (!ND6_LLINFO_PERMANENT(ln)) { 515 if (!ND6_LLINFO_PERMANENT(ln)) {
511 ln->ln_state = ND6_LLINFO_STALE; 516 ln->ln_state = ND6_LLINFO_STALE;
512 nd6_llinfo_settimer(ln, nd6_gctimer * hz); 517 nd6_llinfo_settimer(ln, nd6_gctimer * hz);
513 } 518 }
514 break; 519 break;
515 520
516 case ND6_LLINFO_PURGE: 521 case ND6_LLINFO_PURGE:
517 case ND6_LLINFO_STALE: 522 case ND6_LLINFO_STALE:
518 /* Garbage Collection(RFC 2461 5.3) */ 523 /* Garbage Collection(RFC 2461 5.3) */
519 if (!ND6_LLINFO_PERMANENT(ln)) { 524 if (!ND6_LLINFO_PERMANENT(ln)) {
520 LLE_REMREF(ln); 525 LLE_REMREF(ln);
521 nd6_free(ln, 1); 526 nd6_free(ln, 1);
@@ -540,27 +545,26 @@ nd6_llinfo_timer(void *arg) @@ -540,27 +545,26 @@ nd6_llinfo_timer(void *arg)
540 ln->ln_asked++; 545 ln->ln_asked++;
541 daddr6 = &ln->r_l3addr.addr6; 546 daddr6 = &ln->r_l3addr.addr6;
542 send_ns = true; 547 send_ns = true;
543 } else { 548 } else {
544 LLE_REMREF(ln); 549 LLE_REMREF(ln);
545 nd6_free(ln, 0); 550 nd6_free(ln, 0);
546 ln = NULL; 551 ln = NULL;
547 } 552 }
548 break; 553 break;
549 } 554 }
550 555
551 if (send_ns) { 556 if (send_ns) {
552 struct in6_addr src, *psrc; 557 struct in6_addr src, *psrc;
553 const struct in6_addr *taddr6 = &ln->r_l3addr.addr6; 
554 558
555 nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); 559 nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000);
556 psrc = nd6_llinfo_get_holdsrc(ln, &src); 560 psrc = nd6_llinfo_get_holdsrc(ln, &src);
557 LLE_FREE_LOCKED(ln); 561 LLE_FREE_LOCKED(ln);
558 ln = NULL; 562 ln = NULL;
559 nd6_ns_output(ifp, daddr6, taddr6, psrc, NULL); 563 nd6_ns_output(ifp, daddr6, taddr6, psrc, NULL);
560 } 564 }
561 565
562out: 566out:
563 if (ln != NULL) 567 if (ln != NULL)
564 LLE_FREE_LOCKED(ln); 568 LLE_FREE_LOCKED(ln);
565 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 569 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
566} 570}
@@ -1181,28 +1185,26 @@ nd6_is_addr_neighbor(const struct sockad @@ -1181,28 +1185,26 @@ nd6_is_addr_neighbor(const struct sockad
1181} 1185}
1182 1186
1183/* 1187/*
1184 * Free an nd6 llinfo entry. 1188 * Free an nd6 llinfo entry.
1185 * Since the function would cause significant changes in the kernel, DO NOT 1189 * Since the function would cause significant changes in the kernel, DO NOT
1186 * make it global, unless you have a strong reason for the change, and are sure 1190 * make it global, unless you have a strong reason for the change, and are sure
1187 * that the change is safe. 1191 * that the change is safe.
1188 */ 1192 */
1189static void 1193static void
1190nd6_free(struct llentry *ln, int gc) 1194nd6_free(struct llentry *ln, int gc)
1191{ 1195{
1192 struct ifnet *ifp; 1196 struct ifnet *ifp;
1193 struct in6_addr *in6; 1197 struct in6_addr *in6;
1194 struct sockaddr_in6 sin6; 
1195 const char *lladdr; 
1196 1198
1197 KASSERT(ln != NULL); 1199 KASSERT(ln != NULL);
1198 LLE_WLOCK_ASSERT(ln); 1200 LLE_WLOCK_ASSERT(ln);
1199 1201
1200 ifp = ln->lle_tbl->llt_ifp; 1202 ifp = ln->lle_tbl->llt_ifp;
1201 in6 = &ln->r_l3addr.addr6; 1203 in6 = &ln->r_l3addr.addr6;
1202 /* 1204 /*
1203 * we used to have pfctlinput(PRC_HOSTDEAD) here. 1205 * we used to have pfctlinput(PRC_HOSTDEAD) here.
1204 * even though it is not harmful, it was not really necessary. 1206 * even though it is not harmful, it was not really necessary.
1205 */ 1207 */
1206 1208
1207 if (!ip6_forwarding && ln->ln_router) { 1209 if (!ip6_forwarding && ln->ln_router) {
1208 if (ln->ln_state == ND6_LLINFO_STALE && gc) { 1210 if (ln->ln_state == ND6_LLINFO_STALE && gc) {
@@ -1272,29 +1274,35 @@ nd6_free(struct llentry *ln, int gc) @@ -1272,29 +1274,35 @@ nd6_free(struct llentry *ln, int gc)
1272#ifdef __FreeBSD__ 1274#ifdef __FreeBSD__
1273 /* 1275 /*
1274 * If this entry was added by an on-link redirect, remove the 1276 * If this entry was added by an on-link redirect, remove the
1275 * corresponding host route. 1277 * corresponding host route.
1276 */ 1278 */
1277 if (ln->la_flags & LLE_REDIRECT) 1279 if (ln->la_flags & LLE_REDIRECT)
1278 nd6_free_redirect(ln); 1280 nd6_free_redirect(ln);
1279#endif 1281#endif
1280 1282
1281 ND6_UNLOCK(); 1283 ND6_UNLOCK();
1282 LLE_WLOCK(ln); 1284 LLE_WLOCK(ln);
1283 } 1285 }
1284 1286
1285 sockaddr_in6_init(&sin6, in6, 0, 0, 0); 1287 if (ln->la_flags & LLE_VALID || gc) {
1286 lladdr = ln->la_flags & LLE_VALID ? (const char *)&ln->ll_addr : NULL; 1288 struct sockaddr_in6 sin6;
1287 rt_clonedmsg(RTM_DELETE, sin6tosa(&sin6), lladdr, ifp); 1289 const char *lladdr;
 1290
 1291 sockaddr_in6_init(&sin6, in6, 0, 0, 0);
 1292 lladdr = ln->la_flags & LLE_VALID ?
 1293 (const char *)&ln->ll_addr : NULL;
 1294 rt_clonedmsg(RTM_DELETE, sin6tosa(&sin6), lladdr, ifp);
 1295 }
1288 1296
1289 /* 1297 /*
1290 * Save to unlock. We still hold an extra reference and will not 1298 * Save to unlock. We still hold an extra reference and will not
1291 * free(9) in llentry_free() if someone else holds one as well. 1299 * free(9) in llentry_free() if someone else holds one as well.
1292 */ 1300 */
1293 LLE_WUNLOCK(ln); 1301 LLE_WUNLOCK(ln);
1294 IF_AFDATA_LOCK(ifp); 1302 IF_AFDATA_LOCK(ifp);
1295 LLE_WLOCK(ln); 1303 LLE_WLOCK(ln);
1296 1304
1297 lltable_free_entry(LLTABLE6(ifp), ln); 1305 lltable_free_entry(LLTABLE6(ifp), ln);
1298 1306
1299 IF_AFDATA_UNLOCK(ifp); 1307 IF_AFDATA_UNLOCK(ifp);
1300} 1308}
@@ -2208,27 +2216,27 @@ nd6_cache_lladdr( @@ -2208,27 +2216,27 @@ nd6_cache_lladdr(
2208 ln->ln_router = 0; 2216 ln->ln_router = 0;
2209 break; 2217 break;
2210 case ND_ROUTER_ADVERT: 2218 case ND_ROUTER_ADVERT:
2211 /* 2219 /*
2212 * Mark an entry with lladdr as a router. 2220 * Mark an entry with lladdr as a router.
2213 */ 2221 */
2214 if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */ 2222 if ((!is_newentry && (olladdr || lladdr)) || /* (2-5) */
2215 (is_newentry && lladdr)) { /* (7) */ 2223 (is_newentry && lladdr)) { /* (7) */
2216 ln->ln_router = 1; 2224 ln->ln_router = 1;
2217 } 2225 }
2218 break; 2226 break;
2219 } 2227 }
2220 2228
2221 if (do_update) { 2229 if (do_update && lladdr != NULL) {
2222 struct sockaddr_in6 sin6; 2230 struct sockaddr_in6 sin6;
2223 2231
2224 sockaddr_in6_init(&sin6, from, 0, 0, 0); 2232 sockaddr_in6_init(&sin6, from, 0, 0, 0);
2225 rt_clonedmsg(is_newentry ? RTM_ADD : RTM_CHANGE, 2233 rt_clonedmsg(is_newentry ? RTM_ADD : RTM_CHANGE,
2226 sin6tosa(&sin6), lladdr, ifp); 2234 sin6tosa(&sin6), lladdr, ifp);
2227 } 2235 }
2228 2236
2229 if (ln != NULL) { 2237 if (ln != NULL) {
2230 router = ln->ln_router; 2238 router = ln->ln_router;
2231 LLE_WUNLOCK(ln); 2239 LLE_WUNLOCK(ln);
2232 } 2240 }
2233 2241
2234 /* 2242 /*
@@ -2324,47 +2332,41 @@ nd6_resolve(struct ifnet *ifp, const str @@ -2324,47 +2332,41 @@ nd6_resolve(struct ifnet *ifp, const str
2324 if (ln != NULL && (ln->la_flags & LLE_VALID) != 0 && 2332 if (ln != NULL && (ln->la_flags & LLE_VALID) != 0 &&
2325 ln->ln_state == ND6_LLINFO_REACHABLE) { 2333 ln->ln_state == ND6_LLINFO_REACHABLE) {
2326 /* Fast path */ 2334 /* Fast path */
2327 memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); 2335 memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen));
2328 LLE_RUNLOCK(ln); 2336 LLE_RUNLOCK(ln);
2329 return 0; 2337 return 0;
2330 } 2338 }
2331 if (ln != NULL) 2339 if (ln != NULL)
2332 LLE_RUNLOCK(ln); 2340 LLE_RUNLOCK(ln);
2333 2341
2334 /* Slow path */ 2342 /* Slow path */
2335 ln = nd6_lookup(&dst->sin6_addr, ifp, true); 2343 ln = nd6_lookup(&dst->sin6_addr, ifp, true);
2336 if (ln == NULL && nd6_is_addr_neighbor(dst, ifp)) { 2344 if (ln == NULL && nd6_is_addr_neighbor(dst, ifp)) {
2337 struct sockaddr_in6 sin6; 
2338 /* 2345 /*
2339 * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), 2346 * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
2340 * the condition below is not very efficient. But we believe 2347 * the condition below is not very efficient. But we believe
2341 * it is tolerable, because this should be a rare case. 2348 * it is tolerable, because this should be a rare case.
2342 */ 2349 */
2343 ln = nd6_create(&dst->sin6_addr, ifp); 2350 ln = nd6_create(&dst->sin6_addr, ifp);
2344 if (ln == NULL) { 2351 if (ln == NULL) {
2345 char ip6buf[INET6_ADDRSTRLEN]; 2352 char ip6buf[INET6_ADDRSTRLEN];
2346 log(LOG_DEBUG, 2353 log(LOG_DEBUG,
2347 "%s: can't allocate llinfo for %s " 2354 "%s: can't allocate llinfo for %s "
2348 "(ln=%p, rt=%p)\n", __func__, 2355 "(ln=%p, rt=%p)\n", __func__,
2349 IN6_PRINT(ip6buf, &dst->sin6_addr), ln, rt); 2356 IN6_PRINT(ip6buf, &dst->sin6_addr), ln, rt);
2350 m_freem(m); 2357 m_freem(m);
2351 return ENOBUFS; 2358 return ENOBUFS;
2352 } 2359 }
2353 
2354 sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); 
2355 if (rt != NULL) 
2356 rt_clonedmsg(RTM_ADD, sin6tosa(&sin6), NULL, ifp); 
2357 
2358 created = true; 2360 created = true;
2359 } 2361 }
2360 2362
2361 if (ln == NULL) { 2363 if (ln == NULL) {
2362 m_freem(m); 2364 m_freem(m);
2363 return ENETDOWN; /* better error? */ 2365 return ENETDOWN; /* better error? */
2364 } 2366 }
2365 2367
2366 LLE_WLOCK_ASSERT(ln); 2368 LLE_WLOCK_ASSERT(ln);
2367 2369
2368 /* We don't have to do link-layer address resolution on a p2p link. */ 2370 /* We don't have to do link-layer address resolution on a p2p link. */
2369 if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && 2371 if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
2370 ln->ln_state < ND6_LLINFO_REACHABLE) { 2372 ln->ln_state < ND6_LLINFO_REACHABLE) {
@@ -2429,32 +2431,29 @@ nd6_resolve(struct ifnet *ifp, const str @@ -2429,32 +2431,29 @@ nd6_resolve(struct ifnet *ifp, const str
2429 } 2431 }
2430 2432
2431 /* 2433 /*
2432 * If there has been no NS for the neighbor after entering the 2434 * If there has been no NS for the neighbor after entering the
2433 * INCOMPLETE state, send the first solicitation. 2435 * INCOMPLETE state, send the first solicitation.
2434 */ 2436 */
2435 if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) { 2437 if (!ND6_LLINFO_PERMANENT(ln) && ln->ln_asked == 0) {
2436 struct in6_addr src, *psrc; 2438 struct in6_addr src, *psrc;
2437 2439
2438 ln->ln_asked++; 2440 ln->ln_asked++;
2439 nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans * hz / 1000); 2441 nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans * hz / 1000);
2440 psrc = nd6_llinfo_get_holdsrc(ln, &src); 2442 psrc = nd6_llinfo_get_holdsrc(ln, &src);
2441 LLE_WUNLOCK(ln); 2443 LLE_WUNLOCK(ln);
2442 ln = NULL; 
2443 nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, NULL); 2444 nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, NULL);
2444 } else { 2445 } else
2445 /* We did the lookup so we need to do the unlock here. */ 
2446 LLE_WUNLOCK(ln); 2446 LLE_WUNLOCK(ln);
2447 } 
2448 2447
2449 if (created) 2448 if (created)
2450 nd6_gc_neighbors(LLTABLE6(ifp), &dst->sin6_addr); 2449 nd6_gc_neighbors(LLTABLE6(ifp), &dst->sin6_addr);
2451 2450
2452 return EWOULDBLOCK; 2451 return EWOULDBLOCK;
2453} 2452}
2454 2453
2455int 2454int
2456nd6_need_cache(struct ifnet *ifp) 2455nd6_need_cache(struct ifnet *ifp)
2457{ 2456{
2458 /* 2457 /*
2459 * XXX: we currently do not make neighbor cache on any interface 2458 * XXX: we currently do not make neighbor cache on any interface
2460 * other than ARCnet, Ethernet, FDDI and GIF. 2459 * other than ARCnet, Ethernet, FDDI and GIF.

cvs diff -r1.171 -r1.172 src/sys/netinet6/nd6_nbr.c (expand / switch to unified diff)

--- src/sys/netinet6/nd6_nbr.c 2019/08/30 08:40:25 1.171
+++ src/sys/netinet6/nd6_nbr.c 2019/09/01 18:54:38 1.172
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: nd6_nbr.c,v 1.171 2019/08/30 08:40:25 roy Exp $ */ 1/* $NetBSD: nd6_nbr.c,v 1.172 2019/09/01 18:54:38 roy Exp $ */
2/* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */ 2/* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */
3 3
4/* 4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
@@ -21,27 +21,27 @@ @@ -21,27 +21,27 @@
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE. 30 * SUCH DAMAGE.
31 */ 31 */
32 32
33#include <sys/cdefs.h> 33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.171 2019/08/30 08:40:25 roy Exp $"); 34__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.172 2019/09/01 18:54:38 roy Exp $");
35 35
36#ifdef _KERNEL_OPT 36#ifdef _KERNEL_OPT
37#include "opt_inet.h" 37#include "opt_inet.h"
38#include "opt_net_mpsafe.h" 38#include "opt_net_mpsafe.h"
39#endif 39#endif
40 40
41#include <sys/param.h> 41#include <sys/param.h>
42#include <sys/systm.h> 42#include <sys/systm.h>
43#include <sys/kmem.h> 43#include <sys/kmem.h>
44#include <sys/mbuf.h> 44#include <sys/mbuf.h>
45#include <sys/socket.h> 45#include <sys/socket.h>
46#include <sys/socketvar.h> 46#include <sys/socketvar.h>
47#include <sys/sockio.h> 47#include <sys/sockio.h>
@@ -595,33 +595,33 @@ nd6_ns_output(struct ifnet *ifp, const s @@ -595,33 +595,33 @@ nd6_ns_output(struct ifnet *ifp, const s
595void 595void
596nd6_na_input(struct mbuf *m, int off, int icmp6len) 596nd6_na_input(struct mbuf *m, int off, int icmp6len)
597{ 597{
598 struct ifnet *ifp; 598 struct ifnet *ifp;
599 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 599 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
600 struct nd_neighbor_advert *nd_na; 600 struct nd_neighbor_advert *nd_na;
601 struct in6_addr saddr6 = ip6->ip6_src; 601 struct in6_addr saddr6 = ip6->ip6_src;
602 struct in6_addr daddr6 = ip6->ip6_dst; 602 struct in6_addr daddr6 = ip6->ip6_dst;
603 struct in6_addr taddr6; 603 struct in6_addr taddr6;
604 int flags; 604 int flags;
605 int is_router; 605 int is_router;
606 int is_solicited; 606 int is_solicited;
607 int is_override; 607 int is_override;
 608 int rt_cmd;
608 char *lladdr = NULL; 609 char *lladdr = NULL;
609 int lladdrlen = 0; 610 int lladdrlen = 0;
610 struct ifaddr *ifa; 611 struct ifaddr *ifa;
611 struct llentry *ln = NULL; 612 struct llentry *ln = NULL;
612 union nd_opts ndopts; 613 union nd_opts ndopts;
613 struct sockaddr_in6 ssin6; 614 struct sockaddr_in6 ssin6;
614 bool rt_announce; 
615 bool checklink = false; 615 bool checklink = false;
616 struct psref psref; 616 struct psref psref;
617 struct psref psref_ia; 617 struct psref psref_ia;
618 char ip6buf[INET6_ADDRSTRLEN], ip6buf2[INET6_ADDRSTRLEN]; 618 char ip6buf[INET6_ADDRSTRLEN], ip6buf2[INET6_ADDRSTRLEN];
619 619
620 ifp = m_get_rcvif_psref(m, &psref); 620 ifp = m_get_rcvif_psref(m, &psref);
621 if (ifp == NULL) 621 if (ifp == NULL)
622 goto freeit; 622 goto freeit;
623 623
624 if (ip6->ip6_hlim != 255) { 624 if (ip6->ip6_hlim != 255) {
625 nd6log(LOG_ERR, 625 nd6log(LOG_ERR,
626 "invalid hlim (%d) from %s to %s on %s\n", 626 "invalid hlim (%d) from %s to %s on %s\n",
627 ip6->ip6_hlim, IN6_PRINT(ip6buf, &ip6->ip6_src), 627 ip6->ip6_hlim, IN6_PRINT(ip6buf, &ip6->ip6_src),
@@ -725,41 +725,41 @@ nd6_na_input(struct mbuf *m, int off, in @@ -725,41 +725,41 @@ nd6_na_input(struct mbuf *m, int off, in
725 nd6log(LOG_INFO, "ND packet from non-neighbor %s on %s\n", 725 nd6log(LOG_INFO, "ND packet from non-neighbor %s on %s\n",
726 IN6_PRINT(ip6buf, &saddr6), if_name(ifp)); 726 IN6_PRINT(ip6buf, &saddr6), if_name(ifp));
727 goto bad; 727 goto bad;
728 } 728 }
729 729
730 /* 730 /*
731 * If no neighbor cache entry is found, NA SHOULD silently be 731 * If no neighbor cache entry is found, NA SHOULD silently be
732 * discarded. 732 * discarded.
733 */ 733 */
734 ln = nd6_lookup(&taddr6, ifp, true); 734 ln = nd6_lookup(&taddr6, ifp, true);
735 if (ln == NULL) 735 if (ln == NULL)
736 goto freeit; 736 goto freeit;
737 737
738 rt_announce = false; 738 rt_cmd = 0;
739 if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { 739 if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
740 /* 740 /*
741 * If the link-layer has address, and no lladdr option came, 741 * If the link-layer has address, and no lladdr option came,
742 * discard the packet. 742 * discard the packet.
743 */ 743 */
744 if (ifp->if_addrlen && !lladdr) 744 if (ifp->if_addrlen && !lladdr)
745 goto freeit; 745 goto freeit;
746 746
747 /* 747 /*
748 * Record link-layer address, and update the state. 748 * Record link-layer address, and update the state.
749 */ 749 */
750 memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); 750 memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen);
751 ln->la_flags |= LLE_VALID; 751 ln->la_flags |= LLE_VALID;
752 rt_announce = true; 752 rt_cmd = RTM_ADD;
753 if (is_solicited) { 753 if (is_solicited) {
754 ln->ln_state = ND6_LLINFO_REACHABLE; 754 ln->ln_state = ND6_LLINFO_REACHABLE;
755 ln->ln_byhint = 0; 755 ln->ln_byhint = 0;
756 if (!ND6_LLINFO_PERMANENT(ln)) { 756 if (!ND6_LLINFO_PERMANENT(ln)) {
757 nd6_llinfo_settimer(ln, 757 nd6_llinfo_settimer(ln,
758 ND_IFINFO(ln->lle_tbl->llt_ifp)->reachable * hz); 758 ND_IFINFO(ln->lle_tbl->llt_ifp)->reachable * hz);
759 } 759 }
760 } else { 760 } else {
761 ln->ln_state = ND6_LLINFO_STALE; 761 ln->ln_state = ND6_LLINFO_STALE;
762 nd6_llinfo_settimer(ln, nd6_gctimer * hz); 762 nd6_llinfo_settimer(ln, nd6_gctimer * hz);
763 } 763 }
764 if ((ln->ln_router = is_router) != 0) { 764 if ((ln->ln_router = is_router) != 0) {
765 /* 765 /*
@@ -770,32 +770,34 @@ nd6_na_input(struct mbuf *m, int off, in @@ -770,32 +770,34 @@ nd6_na_input(struct mbuf *m, int off, in
770 checklink = true; 770 checklink = true;
771 } 771 }
772 } else { 772 } else {
773 bool llchange; 773 bool llchange;
774 774
775 /* 775 /*
776 * Check if the link-layer address has changed or not. 776 * Check if the link-layer address has changed or not.
777 */ 777 */
778 if (lladdr == NULL) 778 if (lladdr == NULL)
779 llchange = false; 779 llchange = false;
780 else { 780 else {
781 if (ln->la_flags & LLE_VALID) { 781 if (ln->la_flags & LLE_VALID) {
782 if (memcmp(lladdr, &ln->ll_addr, ifp->if_addrlen)) 782 if (memcmp(lladdr, &ln->ll_addr, ifp->if_addrlen))
783 llchange = rt_announce = true; 783 llchange = true;
784 else 784 else
785 llchange = false; 785 llchange = false;
786 } else 786 } else
787 llchange = rt_announce = true; 787 llchange = true;
788 } 788 }
 789 if (llchange)
 790 rt_cmd = RTM_CHANGE;
789 791
790 /* 792 /*
791 * This is VERY complex. Look at it with care. 793 * This is VERY complex. Look at it with care.
792 * 794 *
793 * override solicit lladdr llchange action 795 * override solicit lladdr llchange action
794 * (L: record lladdr) 796 * (L: record lladdr)
795 * 797 *
796 * 0 0 n -- (2c) 798 * 0 0 n -- (2c)
797 * 0 0 y n (2b) L 799 * 0 0 y n (2b) L
798 * 0 0 y y (1) REACHABLE->STALE 800 * 0 0 y y (1) REACHABLE->STALE
799 * 0 1 n -- (2c) *->REACHABLE 801 * 0 1 n -- (2c) *->REACHABLE
800 * 0 1 y n (2b) L *->REACHABLE 802 * 0 1 y n (2b) L *->REACHABLE
801 * 0 1 y y (1) REACHABLE->STALE 803 * 0 1 y y (1) REACHABLE->STALE
@@ -872,31 +874,31 @@ nd6_na_input(struct mbuf *m, int off, in @@ -872,31 +874,31 @@ nd6_na_input(struct mbuf *m, int off, in
872 nd6_rt_flush(&ip6->ip6_src, ln->lle_tbl->llt_ifp); 874 nd6_rt_flush(&ip6->ip6_src, ln->lle_tbl->llt_ifp);
873 } 875 }
874 ND6_UNLOCK(); 876 ND6_UNLOCK();
875 } 877 }
876 ln->ln_router = is_router; 878 ln->ln_router = is_router;
877 } 879 }
878 /* 880 /*
879 * XXX: does this matter? 881 * XXX: does this matter?
880 * rt->rt_flags &= ~RTF_REJECT; 882 * rt->rt_flags &= ~RTF_REJECT;
881 */ 883 */
882 ln->ln_asked = 0; 884 ln->ln_asked = 0;
883 nd6_llinfo_release_pkts(ln, ifp); 885 nd6_llinfo_release_pkts(ln, ifp);
884 886
885 if (rt_announce) { 887 if (rt_cmd != 0) {
886 struct sockaddr_in6 sin6; 888 struct sockaddr_in6 sin6;
887 889
888 sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); 890 sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0);
889 rt_clonedmsg(RTM_CHANGE, sin6tosa(&sin6), 891 rt_clonedmsg(rt_cmd, sin6tosa(&sin6),
890 (char *)&ln->ll_addr, ln->lle_tbl->llt_ifp); 892 (char *)&ln->ll_addr, ln->lle_tbl->llt_ifp);
891 } 893 }
892 894
893 freeit: 895 freeit:
894 if (ln != NULL) 896 if (ln != NULL)
895 LLE_WUNLOCK(ln); 897 LLE_WUNLOCK(ln);
896 898
897 if (checklink) { 899 if (checklink) {
898 ND6_WLOCK(); 900 ND6_WLOCK();
899 nd6_pfxlist_onlink_check(); 901 nd6_pfxlist_onlink_check();
900 ND6_UNLOCK(); 902 ND6_UNLOCK();
901 } 903 }
902 904