Thu Jun 7 17:48:31 2018 UTC ()
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.


(martin)
diff -r1.245.2.10 -r1.245.2.11 src/sys/netinet6/in6.c
diff -r1.97 -r1.97.6.1 src/sys/netinet6/in6_var.h
diff -r1.89.2.1 -r1.89.2.2 src/sys/netinet6/mld6.c
diff -r1.232.2.7 -r1.232.2.8 src/sys/netinet6/nd6.c

cvs diff -r1.245.2.10 -r1.245.2.11 src/sys/netinet6/in6.c (expand / switch to unified diff)

--- 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
1421static void 1423static void
1422in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) 1424in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
1423{ 1425{
1424 int s = splsoftnet(); 1426 int s = splsoftnet();
1425 1427

cvs diff -r1.97 -r1.97.6.1 src/sys/netinet6/in6_var.h (expand / switch to unified diff)

--- 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
682void in6_init(void); 682void in6_init(void);
683 683
684void in6_multi_lock(int); 684void in6_multi_lock(int);
685void in6_multi_unlock(void); 685void in6_multi_unlock(void);
686bool in6_multi_locked(int); 686bool in6_multi_locked(int);
687struct in6_multi * 687struct in6_multi *
688 in6_lookup_multi(const struct in6_addr *, const struct ifnet *); 688 in6_lookup_multi(const struct in6_addr *, const struct ifnet *);
689bool in6_multi_group(const struct in6_addr *, const struct ifnet *); 689bool in6_multi_group(const struct in6_addr *, const struct ifnet *);
690void in6_purge_multi(struct ifnet *); 690void in6_purge_multi(struct ifnet *);
691struct in6_multi *in6_addmulti(struct in6_addr *, struct ifnet *, 691struct in6_multi *in6_addmulti(struct in6_addr *, struct ifnet *,
692 int *, int); 692 int *, int);
693void in6_delmulti(struct in6_multi *); 693void in6_delmulti(struct in6_multi *);
 694void in6_delmulti_locked(struct in6_multi *);
 695void in6_lookup_and_delete_multi(const struct in6_addr *,
 696 const struct ifnet *);
694struct in6_multi_mship *in6_joingroup(struct ifnet *, struct in6_addr *, 697struct in6_multi_mship *in6_joingroup(struct ifnet *, struct in6_addr *,
695 int *, int); 698 int *, int);
696int in6_leavegroup(struct in6_multi_mship *); 699int in6_leavegroup(struct in6_multi_mship *);
697int in6_mask2len(struct in6_addr *, u_char *); 700int in6_mask2len(struct in6_addr *, u_char *);
698int in6_control(struct socket *, u_long, void *, struct ifnet *); 701int in6_control(struct socket *, u_long, void *, struct ifnet *);
699int in6_update_ifa(struct ifnet *, struct in6_aliasreq *, int); 702int in6_update_ifa(struct ifnet *, struct in6_aliasreq *, int);
700void in6_purgeaddr(struct ifaddr *); 703void in6_purgeaddr(struct ifaddr *);
701void in6_purgeif(struct ifnet *); 704void in6_purgeif(struct ifnet *);
702void in6_setmaxmtu (void); 705void in6_setmaxmtu (void);
703int in6_if2idlen (struct ifnet *); 706int in6_if2idlen (struct ifnet *);
704void *in6_domifattach(struct ifnet *); 707void *in6_domifattach(struct ifnet *);
705void in6_domifdetach(struct ifnet *, void *); 708void in6_domifdetach(struct ifnet *, void *);
706void in6_ifremlocal(struct ifaddr *); 709void in6_ifremlocal(struct ifaddr *);

cvs diff -r1.89.2.1 -r1.89.2.2 src/sys/netinet6/mld6.c (expand / switch to unified diff)

--- 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 */
217static void 217static void
218mld_stoptimer(struct in6_multi *in6m) 218mld_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
238static void 235static void
239mld_timeo(void *arg) 236mld_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
261out: 258out:
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
266static u_long 263static u_long
267mld_timerresid(struct in6_multi *in6m) 264mld_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
780static void 777static void
781in6m_destroy(struct in6_multi *in6m) 778in6m_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 */
826void 827void
827in6_delmulti(struct in6_multi *in6m) 828in6_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
 843void
 844in6_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 */
848struct in6_multi * 857struct in6_multi *
849in6_lookup_multi(const struct in6_addr *addr, const struct ifnet *ifp) 858in6_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
 871void
 872in6_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
862bool 884bool
863in6_multi_group(const struct in6_addr *addr, const struct ifnet *ifp) 885in6_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 */
877void 899void
878in6_purge_multi(struct ifnet *ifp) 900in6_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
896void 918void
897in6_multi_lock(int op) 919in6_multi_lock(int op)
898{ 920{
899 921
900 rw_enter(&in6_multilock, op); 922 rw_enter(&in6_multilock, op);
901} 923}
902 924
903void 925void
904in6_multi_unlock(void) 926in6_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
945int 967int
946in6_leavegroup(struct in6_multi_mship *imm) 968in6_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 */
963static int 986static int
964in6_mkludge_sysctl(SYSCTLFN_ARGS) 987in6_mkludge_sysctl(SYSCTLFN_ARGS)
965{ 988{
966 989
967 if (namelen != 1) 990 if (namelen != 1)
968 return EINVAL; 991 return EINVAL;

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

--- 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
1627int 1623int
1628nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) 1624nd6_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;