Pull up following revision(s) (requested by ozaki-r in ticket #842): sys/netinet6/mld6.c: revision 1.93-1.99 sys/netinet6/in6_var.h: revision 1.99,1.100 sys/netinet6/in6.c: revision 1.267,1.268 sys/netinet6/nd6.c: revision 1.249 Don't hold softnet_lock in mld_timeo Then we can get rid of remaining abuses of mutex_owned(softnet_lock). Release in6_multilock on callout_halt of mld_timeo to avoid a deadlock Improve atomicity of in6_leavegroup and in6_delmulti Avoid NULL pointer dereference on imm->i6mm_maddr Make a refcount decrement and a removal from a list of an item atomic in6m_refcount of an in6m can be incremented if the in6m is on the list (if_multiaddrs) in in6_addmulti or mld_input. So we must avoid such an increment when we try to destroy an in6m. To this end we must make an in6m_refcount decrement and a removal of an in6m from if_multiaddrs atomic. Make a deletion of in6m in nd6_rtrequest atomic Move LIST_REMOVE mld_stoptimer releases in6_multilock temporarily, so we must LIST_REMOVE first. Avoid double LIST_REMOVE which corrupts lists Mark in6m as used for non-DIAGNOSTIC builds.diff -r1.245.2.10 -r1.245.2.11 src/sys/netinet6/in6.c
(martin)
--- src/sys/netinet6/in6.c 2018/04/08 06:09:12 1.245.2.10
+++ src/sys/netinet6/in6.c 2018/06/07 17:48:31 1.245.2.11
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: in6.c,v 1.245.2.10 2018/04/08 06:09:12 snj Exp $ */ | 1 | /* $NetBSD: in6.c,v 1.245.2.11 2018/06/07 17:48:31 martin Exp $ */ | |
2 | /* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */ | 2 | /* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 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 | |
@@ -52,27 +52,27 @@ | @@ -52,27 +52,27 @@ | |||
52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 52 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
53 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 53 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
54 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 54 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
55 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 55 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
56 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 56 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
57 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 57 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
58 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 58 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
59 | * SUCH DAMAGE. | 59 | * SUCH DAMAGE. | |
60 | * | 60 | * | |
61 | * @(#)in.c 8.2 (Berkeley) 11/15/93 | 61 | * @(#)in.c 8.2 (Berkeley) 11/15/93 | |
62 | */ | 62 | */ | |
63 | 63 | |||
64 | #include <sys/cdefs.h> | 64 | #include <sys/cdefs.h> | |
65 | __KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.245.2.10 2018/04/08 06:09:12 snj Exp $"); | 65 | __KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.245.2.11 2018/06/07 17:48:31 martin Exp $"); | |
66 | 66 | |||
67 | #ifdef _KERNEL_OPT | 67 | #ifdef _KERNEL_OPT | |
68 | #include "opt_inet.h" | 68 | #include "opt_inet.h" | |
69 | #include "opt_compat_netbsd.h" | 69 | #include "opt_compat_netbsd.h" | |
70 | #include "opt_net_mpsafe.h" | 70 | #include "opt_net_mpsafe.h" | |
71 | #endif | 71 | #endif | |
72 | 72 | |||
73 | #include <sys/param.h> | 73 | #include <sys/param.h> | |
74 | #include <sys/ioctl.h> | 74 | #include <sys/ioctl.h> | |
75 | #include <sys/errno.h> | 75 | #include <sys/errno.h> | |
76 | #include <sys/malloc.h> | 76 | #include <sys/malloc.h> | |
77 | #include <sys/socket.h> | 77 | #include <sys/socket.h> | |
78 | #include <sys/socketvar.h> | 78 | #include <sys/socketvar.h> | |
@@ -1397,29 +1397,31 @@ in6_purgeaddr(struct ifaddr *ifa) | @@ -1397,29 +1397,31 @@ in6_purgeaddr(struct ifaddr *ifa) | |||
1397 | 1397 | |||
1398 | /* Delete any network route. */ | 1398 | /* Delete any network route. */ | |
1399 | in6_ifremprefix(ia); | 1399 | in6_ifremprefix(ia); | |
1400 | 1400 | |||
1401 | /* Remove ownaddr's loopback rtentry, if it exists. */ | 1401 | /* Remove ownaddr's loopback rtentry, if it exists. */ | |
1402 | in6_ifremlocal(&(ia->ia_ifa)); | 1402 | in6_ifremlocal(&(ia->ia_ifa)); | |
1403 | 1403 | |||
1404 | /* | 1404 | /* | |
1405 | * leave from multicast groups we have joined for the interface | 1405 | * leave from multicast groups we have joined for the interface | |
1406 | */ | 1406 | */ | |
1407 | again: | 1407 | again: | |
1408 | mutex_enter(&in6_ifaddr_lock); | 1408 | mutex_enter(&in6_ifaddr_lock); | |
1409 | while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { | 1409 | while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { | |
1410 | struct in6_multi *in6m __diagused = imm->i6mm_maddr; | |||
1411 | KASSERT(in6m == NULL || in6m->in6m_ifp == ifp); | |||
1410 | LIST_REMOVE(imm, i6mm_chain); | 1412 | LIST_REMOVE(imm, i6mm_chain); | |
1411 | mutex_exit(&in6_ifaddr_lock); | 1413 | mutex_exit(&in6_ifaddr_lock); | |
1412 | KASSERT(imm->i6mm_maddr->in6m_ifp == ifp); | 1414 | ||
1413 | in6_leavegroup(imm); | 1415 | in6_leavegroup(imm); | |
1414 | goto again; | 1416 | goto again; | |
1415 | } | 1417 | } | |
1416 | mutex_exit(&in6_ifaddr_lock); | 1418 | mutex_exit(&in6_ifaddr_lock); | |
1417 | 1419 | |||
1418 | in6_unlink_ifa(ia, ifp); | 1420 | in6_unlink_ifa(ia, ifp); | |
1419 | } | 1421 | } | |
1420 | 1422 | |||
1421 | static void | 1423 | static void | |
1422 | in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) | 1424 | in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) | |
1423 | { | 1425 | { | |
1424 | int s = splsoftnet(); | 1426 | int s = splsoftnet(); | |
1425 | 1427 |
--- src/sys/netinet6/in6_var.h 2017/03/02 09:48:20 1.97
+++ src/sys/netinet6/in6_var.h 2018/06/07 17:48:31 1.97.6.1
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: in6_var.h,v 1.97 2017/03/02 09:48:20 ozaki-r Exp $ */ | 1 | /* $NetBSD: in6_var.h,v 1.97.6.1 2018/06/07 17:48:31 martin Exp $ */ | |
2 | /* $KAME: in6_var.h,v 1.81 2002/06/08 11:16:51 itojun Exp $ */ | 2 | /* $KAME: in6_var.h,v 1.81 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 | |
@@ -681,26 +681,29 @@ do { \ | @@ -681,26 +681,29 @@ do { \ | |||
681 | 681 | |||
682 | void in6_init(void); | 682 | void in6_init(void); | |
683 | 683 | |||
684 | void in6_multi_lock(int); | 684 | void in6_multi_lock(int); | |
685 | void in6_multi_unlock(void); | 685 | void in6_multi_unlock(void); | |
686 | bool in6_multi_locked(int); | 686 | bool in6_multi_locked(int); | |
687 | struct in6_multi * | 687 | struct in6_multi * | |
688 | in6_lookup_multi(const struct in6_addr *, const struct ifnet *); | 688 | in6_lookup_multi(const struct in6_addr *, const struct ifnet *); | |
689 | bool in6_multi_group(const struct in6_addr *, const struct ifnet *); | 689 | bool in6_multi_group(const struct in6_addr *, const struct ifnet *); | |
690 | void in6_purge_multi(struct ifnet *); | 690 | void in6_purge_multi(struct ifnet *); | |
691 | struct in6_multi *in6_addmulti(struct in6_addr *, struct ifnet *, | 691 | struct in6_multi *in6_addmulti(struct in6_addr *, struct ifnet *, | |
692 | int *, int); | 692 | int *, int); | |
693 | void in6_delmulti(struct in6_multi *); | 693 | void in6_delmulti(struct in6_multi *); | |
694 | void in6_delmulti_locked(struct in6_multi *); | |||
695 | void in6_lookup_and_delete_multi(const struct in6_addr *, | |||
696 | const struct ifnet *); | |||
694 | struct in6_multi_mship *in6_joingroup(struct ifnet *, struct in6_addr *, | 697 | struct in6_multi_mship *in6_joingroup(struct ifnet *, struct in6_addr *, | |
695 | int *, int); | 698 | int *, int); | |
696 | int in6_leavegroup(struct in6_multi_mship *); | 699 | int in6_leavegroup(struct in6_multi_mship *); | |
697 | int in6_mask2len(struct in6_addr *, u_char *); | 700 | int in6_mask2len(struct in6_addr *, u_char *); | |
698 | int in6_control(struct socket *, u_long, void *, struct ifnet *); | 701 | int in6_control(struct socket *, u_long, void *, struct ifnet *); | |
699 | int in6_update_ifa(struct ifnet *, struct in6_aliasreq *, int); | 702 | int in6_update_ifa(struct ifnet *, struct in6_aliasreq *, int); | |
700 | void in6_purgeaddr(struct ifaddr *); | 703 | void in6_purgeaddr(struct ifaddr *); | |
701 | void in6_purgeif(struct ifnet *); | 704 | void in6_purgeif(struct ifnet *); | |
702 | void in6_setmaxmtu (void); | 705 | void in6_setmaxmtu (void); | |
703 | int in6_if2idlen (struct ifnet *); | 706 | int in6_if2idlen (struct ifnet *); | |
704 | void *in6_domifattach(struct ifnet *); | 707 | void *in6_domifattach(struct ifnet *); | |
705 | void in6_domifdetach(struct ifnet *, void *); | 708 | void in6_domifdetach(struct ifnet *, void *); | |
706 | void in6_ifremlocal(struct ifaddr *); | 709 | void in6_ifremlocal(struct ifaddr *); |
--- src/sys/netinet6/mld6.c 2018/01/02 10:20:34 1.89.2.1
+++ src/sys/netinet6/mld6.c 2018/06/07 17:48:31 1.89.2.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: mld6.c,v 1.89.2.1 2018/01/02 10:20:34 snj Exp $ */ | 1 | /* $NetBSD: mld6.c,v 1.89.2.2 2018/06/07 17:48:31 martin Exp $ */ | |
2 | /* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $ */ | 2 | /* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (C) 1998 WIDE Project. | 5 | * Copyright (C) 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 | |
@@ -92,27 +92,27 @@ | @@ -92,27 +92,27 @@ | |||
92 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 92 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
93 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 93 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
94 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 94 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
95 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 95 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
96 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 96 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
97 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 97 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
98 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 98 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
99 | * SUCH DAMAGE. | 99 | * SUCH DAMAGE. | |
100 | * | 100 | * | |
101 | * @(#)igmp.c 8.1 (Berkeley) 7/19/93 | 101 | * @(#)igmp.c 8.1 (Berkeley) 7/19/93 | |
102 | */ | 102 | */ | |
103 | 103 | |||
104 | #include <sys/cdefs.h> | 104 | #include <sys/cdefs.h> | |
105 | __KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.89.2.1 2018/01/02 10:20:34 snj Exp $"); | 105 | __KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.89.2.2 2018/06/07 17:48:31 martin Exp $"); | |
106 | 106 | |||
107 | #ifdef _KERNEL_OPT | 107 | #ifdef _KERNEL_OPT | |
108 | #include "opt_inet.h" | 108 | #include "opt_inet.h" | |
109 | #include "opt_net_mpsafe.h" | 109 | #include "opt_net_mpsafe.h" | |
110 | #endif | 110 | #endif | |
111 | 111 | |||
112 | #include <sys/param.h> | 112 | #include <sys/param.h> | |
113 | #include <sys/systm.h> | 113 | #include <sys/systm.h> | |
114 | #include <sys/mbuf.h> | 114 | #include <sys/mbuf.h> | |
115 | #include <sys/socket.h> | 115 | #include <sys/socket.h> | |
116 | #include <sys/socketvar.h> | 116 | #include <sys/socketvar.h> | |
117 | #include <sys/syslog.h> | 117 | #include <sys/syslog.h> | |
118 | #include <sys/sysctl.h> | 118 | #include <sys/sysctl.h> | |
@@ -215,62 +215,59 @@ mld_starttimer(struct in6_multi *in6m) | @@ -215,62 +215,59 @@ mld_starttimer(struct in6_multi *in6m) | |||
215 | * The caller must ensure in6m won't be freed while releasing the lock. | 215 | * The caller must ensure in6m won't be freed while releasing the lock. | |
216 | */ | 216 | */ | |
217 | static void | 217 | static void | |
218 | mld_stoptimer(struct in6_multi *in6m) | 218 | mld_stoptimer(struct in6_multi *in6m) | |
219 | { | 219 | { | |
220 | 220 | |||
221 | KASSERT(rw_write_held(&in6_multilock)); | 221 | KASSERT(rw_write_held(&in6_multilock)); | |
222 | 222 | |||
223 | if (in6m->in6m_timer == IN6M_TIMER_UNDEF) | 223 | if (in6m->in6m_timer == IN6M_TIMER_UNDEF) | |
224 | return; | 224 | return; | |
225 | 225 | |||
226 | rw_exit(&in6_multilock); | 226 | rw_exit(&in6_multilock); | |
227 | 227 | |||
228 | if (mutex_owned(softnet_lock)) | 228 | callout_halt(&in6m->in6m_timer_ch, NULL); | |
229 | callout_halt(&in6m->in6m_timer_ch, softnet_lock); | |||
230 | else | |||
231 | callout_halt(&in6m->in6m_timer_ch, NULL); | |||
232 | 229 | |||
233 | rw_enter(&in6_multilock, RW_WRITER); | 230 | rw_enter(&in6_multilock, RW_WRITER); | |
234 | 231 | |||
235 | in6m->in6m_timer = IN6M_TIMER_UNDEF; | 232 | in6m->in6m_timer = IN6M_TIMER_UNDEF; | |
236 | } | 233 | } | |
237 | 234 | |||
238 | static void | 235 | static void | |
239 | mld_timeo(void *arg) | 236 | mld_timeo(void *arg) | |
240 | { | 237 | { | |
241 | struct in6_multi *in6m = arg; | 238 | struct in6_multi *in6m = arg; | |
242 | 239 | |||
243 | KASSERT(in6m->in6m_refcount > 0); | 240 | KASSERT(in6m->in6m_refcount > 0); | |
244 | 241 | |||
245 | SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); | 242 | KERNEL_LOCK_UNLESS_NET_MPSAFE(); | |
246 | rw_enter(&in6_multilock, RW_WRITER); | 243 | rw_enter(&in6_multilock, RW_WRITER); | |
247 | if (in6m->in6m_timer == IN6M_TIMER_UNDEF) | 244 | if (in6m->in6m_timer == IN6M_TIMER_UNDEF) | |
248 | goto out; | 245 | goto out; | |
249 | 246 | |||
250 | in6m->in6m_timer = IN6M_TIMER_UNDEF; | 247 | in6m->in6m_timer = IN6M_TIMER_UNDEF; | |
251 | 248 | |||
252 | switch (in6m->in6m_state) { | 249 | switch (in6m->in6m_state) { | |
253 | case MLD_REPORTPENDING: | 250 | case MLD_REPORTPENDING: | |
254 | mld_start_listening(in6m); | 251 | mld_start_listening(in6m); | |
255 | break; | 252 | break; | |
256 | default: | 253 | default: | |
257 | mld_sendpkt(in6m, MLD_LISTENER_REPORT, NULL); | 254 | mld_sendpkt(in6m, MLD_LISTENER_REPORT, NULL); | |
258 | break; | 255 | break; | |
259 | } | 256 | } | |
260 | 257 | |||
261 | out: | 258 | out: | |
262 | rw_exit(&in6_multilock); | 259 | rw_exit(&in6_multilock); | |
263 | SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); | 260 | KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); | |
264 | } | 261 | } | |
265 | 262 | |||
266 | static u_long | 263 | static u_long | |
267 | mld_timerresid(struct in6_multi *in6m) | 264 | mld_timerresid(struct in6_multi *in6m) | |
268 | { | 265 | { | |
269 | struct timeval now, diff; | 266 | struct timeval now, diff; | |
270 | 267 | |||
271 | microtime(&now); | 268 | microtime(&now); | |
272 | 269 | |||
273 | if (now.tv_sec > in6m->in6m_timer_expire.tv_sec || | 270 | if (now.tv_sec > in6m->in6m_timer_expire.tv_sec || | |
274 | (now.tv_sec == in6m->in6m_timer_expire.tv_sec && | 271 | (now.tv_sec == in6m->in6m_timer_expire.tv_sec && | |
275 | now.tv_usec > in6m->in6m_timer_expire.tv_usec)) { | 272 | now.tv_usec > in6m->in6m_timer_expire.tv_usec)) { | |
276 | return (0); | 273 | return (0); | |
@@ -776,129 +773,154 @@ out: | @@ -776,129 +773,154 @@ out: | |||
776 | rw_exit(&in6_multilock); | 773 | rw_exit(&in6_multilock); | |
777 | return in6m; | 774 | return in6m; | |
778 | } | 775 | } | |
779 | 776 | |||
780 | static void | 777 | static void | |
781 | in6m_destroy(struct in6_multi *in6m) | 778 | in6m_destroy(struct in6_multi *in6m) | |
782 | { | 779 | { | |
783 | struct sockaddr_in6 sin6; | 780 | struct sockaddr_in6 sin6; | |
784 | 781 | |||
785 | KASSERT(rw_write_held(&in6_multilock)); | 782 | KASSERT(rw_write_held(&in6_multilock)); | |
786 | KASSERT(in6m->in6m_refcount == 0); | 783 | KASSERT(in6m->in6m_refcount == 0); | |
787 | 784 | |||
788 | /* | 785 | /* | |
789 | * No remaining claims to this record; let MLD6 know | 786 | * Unlink from list if it's listed. This must be done before | |
790 | * that we are leaving the multicast group. | 787 | * mld_stop_listening because it releases in6_multilock and that allows | |
788 | * someone to look up the removing in6m from the list and add a | |||
789 | * reference to the entry unexpectedly. | |||
791 | */ | 790 | */ | |
792 | mld_stop_listening(in6m); | 791 | if (in6_lookup_multi(&in6m->in6m_addr, in6m->in6m_ifp) != NULL) | |
792 | LIST_REMOVE(in6m, in6m_entry); | |||
793 | 793 | |||
794 | /* | 794 | /* | |
795 | * Unlink from list. | 795 | * No remaining claims to this record; let MLD6 know | |
796 | * that we are leaving the multicast group. | |||
796 | */ | 797 | */ | |
797 | LIST_REMOVE(in6m, in6m_entry); | 798 | mld_stop_listening(in6m); | |
798 | 799 | |||
799 | /* | 800 | /* | |
800 | * Delete all references of this multicasting group from | 801 | * Delete all references of this multicasting group from | |
801 | * the membership arrays | 802 | * the membership arrays | |
802 | */ | 803 | */ | |
803 | in6_purge_mcast_references(in6m); | 804 | in6_purge_mcast_references(in6m); | |
804 | 805 | |||
805 | /* | 806 | /* | |
806 | * Notify the network driver to update its multicast | 807 | * Notify the network driver to update its multicast | |
807 | * reception filter. | 808 | * reception filter. | |
808 | */ | 809 | */ | |
809 | sockaddr_in6_init(&sin6, &in6m->in6m_addr, 0, 0, 0); | 810 | sockaddr_in6_init(&sin6, &in6m->in6m_addr, 0, 0, 0); | |
810 | if_mcast_op(in6m->in6m_ifp, SIOCDELMULTI, sin6tosa(&sin6)); | 811 | if_mcast_op(in6m->in6m_ifp, SIOCDELMULTI, sin6tosa(&sin6)); | |
811 | 812 | |||
812 | /* Tell mld_timeo we're halting the timer */ | 813 | /* Tell mld_timeo we're halting the timer */ | |
813 | in6m->in6m_timer = IN6M_TIMER_UNDEF; | 814 | in6m->in6m_timer = IN6M_TIMER_UNDEF; | |
814 | if (mutex_owned(softnet_lock)) | 815 | ||
815 | callout_halt(&in6m->in6m_timer_ch, softnet_lock); | 816 | rw_exit(&in6_multilock); | |
816 | else | 817 | callout_halt(&in6m->in6m_timer_ch, NULL); | |
817 | callout_halt(&in6m->in6m_timer_ch, NULL); | |||
818 | callout_destroy(&in6m->in6m_timer_ch); | 818 | callout_destroy(&in6m->in6m_timer_ch); | |
819 | 819 | |||
820 | free(in6m, M_IPMADDR); | 820 | free(in6m, M_IPMADDR); | |
821 | rw_enter(&in6_multilock, RW_WRITER); | |||
821 | } | 822 | } | |
822 | 823 | |||
823 | /* | 824 | /* | |
824 | * Delete a multicast address record. | 825 | * Delete a multicast address record. | |
825 | */ | 826 | */ | |
826 | void | 827 | void | |
827 | in6_delmulti(struct in6_multi *in6m) | 828 | in6_delmulti_locked(struct in6_multi *in6m) | |
828 | { | 829 | { | |
829 | 830 | |||
831 | KASSERT(rw_write_held(&in6_multilock)); | |||
830 | KASSERT(in6m->in6m_refcount > 0); | 832 | KASSERT(in6m->in6m_refcount > 0); | |
831 | 833 | |||
832 | rw_enter(&in6_multilock, RW_WRITER); | |||
833 | /* | 834 | /* | |
834 | * The caller should have a reference to in6m. So we don't need to care | 835 | * The caller should have a reference to in6m. So we don't need to care | |
835 | * of releasing the lock in mld_stoptimer. | 836 | * of releasing the lock in mld_stoptimer. | |
836 | */ | 837 | */ | |
837 | mld_stoptimer(in6m); | 838 | mld_stoptimer(in6m); | |
838 | if (--in6m->in6m_refcount == 0) | 839 | if (--in6m->in6m_refcount == 0) | |
839 | in6m_destroy(in6m); | 840 | in6m_destroy(in6m); | |
841 | } | |||
842 | ||||
843 | void | |||
844 | in6_delmulti(struct in6_multi *in6m) | |||
845 | { | |||
846 | ||||
847 | rw_enter(&in6_multilock, RW_WRITER); | |||
848 | in6_delmulti_locked(in6m); | |||
840 | rw_exit(&in6_multilock); | 849 | rw_exit(&in6_multilock); | |
841 | } | 850 | } | |
842 | 851 | |||
843 | /* | 852 | /* | |
844 | * Look up the in6_multi record for a given IP6 multicast address | 853 | * Look up the in6_multi record for a given IP6 multicast address | |
845 | * on a given interface. If no matching record is found, "in6m" | 854 | * on a given interface. If no matching record is found, "in6m" | |
846 | * returns NULL. | 855 | * returns NULL. | |
847 | */ | 856 | */ | |
848 | struct in6_multi * | 857 | struct in6_multi * | |
849 | in6_lookup_multi(const struct in6_addr *addr, const struct ifnet *ifp) | 858 | in6_lookup_multi(const struct in6_addr *addr, const struct ifnet *ifp) | |
850 | { | 859 | { | |
851 | struct in6_multi *in6m; | 860 | struct in6_multi *in6m; | |
852 | 861 | |||
853 | KASSERT(rw_lock_held(&in6_multilock)); | 862 | KASSERT(rw_lock_held(&in6_multilock)); | |
854 | 863 | |||
855 | LIST_FOREACH(in6m, &ifp->if_multiaddrs, in6m_entry) { | 864 | LIST_FOREACH(in6m, &ifp->if_multiaddrs, in6m_entry) { | |
856 | if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, addr)) | 865 | if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, addr)) | |
857 | break; | 866 | break; | |
858 | } | 867 | } | |
859 | return in6m; | 868 | return in6m; | |
860 | } | 869 | } | |
861 | 870 | |||
871 | void | |||
872 | in6_lookup_and_delete_multi(const struct in6_addr *addr, | |||
873 | const struct ifnet *ifp) | |||
874 | { | |||
875 | struct in6_multi *in6m; | |||
876 | ||||
877 | rw_enter(&in6_multilock, RW_WRITER); | |||
878 | in6m = in6_lookup_multi(addr, ifp); | |||
879 | if (in6m != NULL) | |||
880 | in6_delmulti_locked(in6m); | |||
881 | rw_exit(&in6_multilock); | |||
882 | } | |||
883 | ||||
862 | bool | 884 | bool | |
863 | in6_multi_group(const struct in6_addr *addr, const struct ifnet *ifp) | 885 | in6_multi_group(const struct in6_addr *addr, const struct ifnet *ifp) | |
864 | { | 886 | { | |
865 | bool ingroup; | 887 | bool ingroup; | |
866 | 888 | |||
867 | rw_enter(&in6_multilock, RW_READER); | 889 | rw_enter(&in6_multilock, RW_READER); | |
868 | ingroup = in6_lookup_multi(addr, ifp) != NULL; | 890 | ingroup = in6_lookup_multi(addr, ifp) != NULL; | |
869 | rw_exit(&in6_multilock); | 891 | rw_exit(&in6_multilock); | |
870 | 892 | |||
871 | return ingroup; | 893 | return ingroup; | |
872 | } | 894 | } | |
873 | 895 | |||
874 | /* | 896 | /* | |
875 | * Purge in6_multi records associated to the interface. | 897 | * Purge in6_multi records associated to the interface. | |
876 | */ | 898 | */ | |
877 | void | 899 | void | |
878 | in6_purge_multi(struct ifnet *ifp) | 900 | in6_purge_multi(struct ifnet *ifp) | |
879 | { | 901 | { | |
880 | struct in6_multi *in6m, *next; | 902 | struct in6_multi *in6m, *next; | |
881 | 903 | |||
882 | rw_enter(&in6_multilock, RW_WRITER); | 904 | rw_enter(&in6_multilock, RW_WRITER); | |
883 | LIST_FOREACH_SAFE(in6m, &ifp->if_multiaddrs, in6m_entry, next) { | 905 | LIST_FOREACH_SAFE(in6m, &ifp->if_multiaddrs, in6m_entry, next) { | |
906 | LIST_REMOVE(in6m, in6m_entry); | |||
884 | /* | 907 | /* | |
885 | * Normally multicast addresses are already purged at this | 908 | * Normally multicast addresses are already purged at this | |
886 | * point. Remaining references aren't accessible via ifp, | 909 | * point. Remaining references aren't accessible via ifp, | |
887 | * so what we can do here is to prevent ifp from being | 910 | * so what we can do here is to prevent ifp from being | |
888 | * accessed via in6m by removing it from the list of ifp. | 911 | * accessed via in6m by removing it from the list of ifp. | |
889 | */ | 912 | */ | |
890 | mld_stoptimer(in6m); | 913 | mld_stoptimer(in6m); | |
891 | LIST_REMOVE(in6m, in6m_entry); | |||
892 | } | 914 | } | |
893 | rw_exit(&in6_multilock); | 915 | rw_exit(&in6_multilock); | |
894 | } | 916 | } | |
895 | 917 | |||
896 | void | 918 | void | |
897 | in6_multi_lock(int op) | 919 | in6_multi_lock(int op) | |
898 | { | 920 | { | |
899 | 921 | |||
900 | rw_enter(&in6_multilock, op); | 922 | rw_enter(&in6_multilock, op); | |
901 | } | 923 | } | |
902 | 924 | |||
903 | void | 925 | void | |
904 | in6_multi_unlock(void) | 926 | in6_multi_unlock(void) | |
@@ -937,32 +959,33 @@ in6_joingroup(struct ifnet *ifp, struct | @@ -937,32 +959,33 @@ in6_joingroup(struct ifnet *ifp, struct | |||
937 | if (!imm->i6mm_maddr) { | 959 | if (!imm->i6mm_maddr) { | |
938 | /* *errorp is already set */ | 960 | /* *errorp is already set */ | |
939 | free(imm, M_IPMADDR); | 961 | free(imm, M_IPMADDR); | |
940 | return NULL; | 962 | return NULL; | |
941 | } | 963 | } | |
942 | return imm; | 964 | return imm; | |
943 | } | 965 | } | |
944 | 966 | |||
945 | int | 967 | int | |
946 | in6_leavegroup(struct in6_multi_mship *imm) | 968 | in6_leavegroup(struct in6_multi_mship *imm) | |
947 | { | 969 | { | |
948 | struct in6_multi *in6m; | 970 | struct in6_multi *in6m; | |
949 | 971 | |||
950 | rw_enter(&in6_multilock, RW_READER); | 972 | rw_enter(&in6_multilock, RW_WRITER); | |
951 | in6m = imm->i6mm_maddr; | 973 | in6m = imm->i6mm_maddr; | |
952 | rw_exit(&in6_multilock); | 974 | imm->i6mm_maddr = NULL; | |
953 | if (in6m != NULL) { | 975 | if (in6m != NULL) { | |
954 | in6_delmulti(in6m); | 976 | in6_delmulti_locked(in6m); | |
955 | } | 977 | } | |
978 | rw_exit(&in6_multilock); | |||
956 | free(imm, M_IPMADDR); | 979 | free(imm, M_IPMADDR); | |
957 | return 0; | 980 | return 0; | |
958 | } | 981 | } | |
959 | 982 | |||
960 | /* | 983 | /* | |
961 | * DEPRECATED: keep it just to avoid breaking old sysctl users. | 984 | * DEPRECATED: keep it just to avoid breaking old sysctl users. | |
962 | */ | 985 | */ | |
963 | static int | 986 | static int | |
964 | in6_mkludge_sysctl(SYSCTLFN_ARGS) | 987 | in6_mkludge_sysctl(SYSCTLFN_ARGS) | |
965 | { | 988 | { | |
966 | 989 | |||
967 | if (namelen != 1) | 990 | if (namelen != 1) | |
968 | return EINVAL; | 991 | return EINVAL; |
--- src/sys/netinet6/nd6.c 2018/03/13 13:27:10 1.232.2.7
+++ src/sys/netinet6/nd6.c 2018/06/07 17:48:31 1.232.2.8
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: nd6.c,v 1.232.2.7 2018/03/13 13:27:10 martin Exp $ */ | 1 | /* $NetBSD: nd6.c,v 1.232.2.8 2018/06/07 17:48:31 martin 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.232.2.7 2018/03/13 13:27:10 martin Exp $"); | 34 | __KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.8 2018/06/07 17:48:31 martin 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> | |
@@ -1597,38 +1597,34 @@ nd6_rtrequest(int req, struct rtentry *r | @@ -1597,38 +1597,34 @@ nd6_rtrequest(int req, struct rtentry *r | |||
1597 | * If we have too many cache entries, initiate immediate | 1597 | * If we have too many cache entries, initiate immediate | |
1598 | * purging for some entries. | 1598 | * purging for some entries. | |
1599 | */ | 1599 | */ | |
1600 | if (rt->rt_ifp != NULL) | 1600 | if (rt->rt_ifp != NULL) | |
1601 | nd6_gc_neighbors(LLTABLE6(rt->rt_ifp), NULL); | 1601 | nd6_gc_neighbors(LLTABLE6(rt->rt_ifp), NULL); | |
1602 | break; | 1602 | break; | |
1603 | } | 1603 | } | |
1604 | 1604 | |||
1605 | case RTM_DELETE: | 1605 | case RTM_DELETE: | |
1606 | /* leave from solicited node multicast for proxy ND */ | 1606 | /* leave from solicited node multicast for proxy ND */ | |
1607 | if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && | 1607 | if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && | |
1608 | (ifp->if_flags & IFF_MULTICAST) != 0) { | 1608 | (ifp->if_flags & IFF_MULTICAST) != 0) { | |
1609 | struct in6_addr llsol; | 1609 | struct in6_addr llsol; | |
1610 | struct in6_multi *in6m; | |||
1611 | 1610 | |||
1612 | llsol = satocsin6(rt_getkey(rt))->sin6_addr; | 1611 | llsol = satocsin6(rt_getkey(rt))->sin6_addr; | |
1613 | llsol.s6_addr32[0] = htonl(0xff020000); | 1612 | llsol.s6_addr32[0] = htonl(0xff020000); | |
1614 | llsol.s6_addr32[1] = 0; | 1613 | llsol.s6_addr32[1] = 0; | |
1615 | llsol.s6_addr32[2] = htonl(1); | 1614 | llsol.s6_addr32[2] = htonl(1); | |
1616 | llsol.s6_addr8[12] = 0xff; | 1615 | llsol.s6_addr8[12] = 0xff; | |
1617 | if (in6_setscope(&llsol, ifp, NULL) == 0) { | 1616 | if (in6_setscope(&llsol, ifp, NULL) == 0) | |
1618 | in6m = in6_lookup_multi(&llsol, ifp); | 1617 | in6_lookup_and_delete_multi(&llsol, ifp); | |
1619 | if (in6m) | |||
1620 | in6_delmulti(in6m); | |||
1621 | } | |||
1622 | } | 1618 | } | |
1623 | break; | 1619 | break; | |
1624 | } | 1620 | } | |
1625 | } | 1621 | } | |
1626 | 1622 | |||
1627 | int | 1623 | int | |
1628 | nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) | 1624 | nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) | |
1629 | { | 1625 | { | |
1630 | struct in6_drlist *drl = (struct in6_drlist *)data; | 1626 | struct in6_drlist *drl = (struct in6_drlist *)data; | |
1631 | struct in6_oprlist *oprl = (struct in6_oprlist *)data; | 1627 | struct in6_oprlist *oprl = (struct in6_oprlist *)data; | |
1632 | struct in6_ndireq *ndi = (struct in6_ndireq *)data; | 1628 | struct in6_ndireq *ndi = (struct in6_ndireq *)data; | |
1633 | struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; | 1629 | struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; | |
1634 | struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; | 1630 | struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; |