From owner-svn-src-all@freebsd.org  Sun Jan 27 12:39:37 2019
Return-Path: <owner-svn-src-all@freebsd.org>
Delivered-To: svn-src-all@mailman.ysv.freebsd.org
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1])
 by mailman.ysv.freebsd.org (Postfix) with ESMTP id B9EE314A9AE7;
 Sun, 27 Jan 2019 12:39:36 +0000 (UTC)
 (envelope-from avos@FreeBSD.org)
Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org
 [IPv6:2610:1c1:1:606c::19:3])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 server-signature RSA-PSS (4096 bits)
 client-signature RSA-PSS (4096 bits) client-digest SHA256)
 (Client CN "mxrelay.nyi.freebsd.org",
 Issuer "Let's Encrypt Authority X3" (verified OK))
 by mx1.freebsd.org (Postfix) with ESMTPS id 600B295D89;
 Sun, 27 Jan 2019 12:39:36 +0000 (UTC)
 (envelope-from avos@FreeBSD.org)
Received: from repo.freebsd.org (repo.freebsd.org
 [IPv6:2610:1c1:1:6068::e6a:0])
 (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
 (Client did not present a certificate)
 by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4829580E7;
 Sun, 27 Jan 2019 12:39:36 +0000 (UTC)
 (envelope-from avos@FreeBSD.org)
Received: from repo.freebsd.org ([127.0.1.37])
 by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x0RCdatM079132;
 Sun, 27 Jan 2019 12:39:36 GMT (envelope-from avos@FreeBSD.org)
Received: (from avos@localhost)
 by repo.freebsd.org (8.15.2/8.15.2/Submit) id x0RCdZHN079127;
 Sun, 27 Jan 2019 12:39:35 GMT (envelope-from avos@FreeBSD.org)
Message-Id: <201901271239.x0RCdZHN079127@repo.freebsd.org>
X-Authentication-Warning: repo.freebsd.org: avos set sender to
 avos@FreeBSD.org using -f
From: Andriy Voskoboinyk <avos@FreeBSD.org>
Date: Sun, 27 Jan 2019 12:39:35 +0000 (UTC)
To: src-committers@freebsd.org, svn-src-all@freebsd.org,
 svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject: svn commit: r343488 - stable/12/sys/net80211
X-SVN-Group: stable-12
X-SVN-Commit-Author: avos
X-SVN-Commit-Paths: stable/12/sys/net80211
X-SVN-Commit-Revision: 343488
X-SVN-Commit-Repository: base
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Rspamd-Queue-Id: 600B295D89
X-Spamd-Bar: --
Authentication-Results: mx1.freebsd.org
X-Spamd-Result: default: False [-2.95 / 15.00];
 local_wl_from(0.00)[FreeBSD.org];
 NEURAL_HAM_MEDIUM(-1.00)[-0.998,0];
 NEURAL_HAM_LONG(-1.00)[-0.999,0];
 NEURAL_HAM_SHORT(-0.96)[-0.957,0];
 ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]
X-BeenThere: svn-src-all@freebsd.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: "SVN commit messages for the entire src tree \(except for &quot;
 user&quot; and &quot; projects&quot; \)" <svn-src-all.freebsd.org>
List-Unsubscribe: <https://lists.freebsd.org/mailman/options/svn-src-all>,
 <mailto:svn-src-all-request@freebsd.org?subject=unsubscribe>
List-Archive: <http://lists.freebsd.org/pipermail/svn-src-all/>
List-Post: <mailto:svn-src-all@freebsd.org>
List-Help: <mailto:svn-src-all-request@freebsd.org?subject=help>
List-Subscribe: <https://lists.freebsd.org/mailman/listinfo/svn-src-all>,
 <mailto:svn-src-all-request@freebsd.org?subject=subscribe>
X-List-Received-Date: Sun, 27 Jan 2019 12:39:37 -0000

Author: avos
Date: Sun Jan 27 12:39:35 2019
New Revision: 343488
URL: https://svnweb.freebsd.org/changeset/base/343488

Log:
  MFC r343213:
  net80211: resolve ioctl <-> detach race for ieee80211com structure
  
  Since r287197 ieee80211com is a part of drivers softc; as a result,
  after detach all pointers to it (iv_ic, ni_ic) are invalid. Most
  possible users (tasks, interrupt handlers) are blocked / removed
  when device is stopped; however, ioctl handlers were not tracked
  and may crash if ieee80211com structure is accessed.
  
  Since ieee80211com pointer access from ieee80211vap structure is not
  protected by lock (constant after interface creation) and used in
  many other places just use reference counting for ioctl handlers;
  on detach set 'detached' flag and wait until reference counter goes to 0.
  
  For KBI stability the last element of iv_spare[] array was reused.

Modified:
  stable/12/sys/net80211/ieee80211.c
  stable/12/sys/net80211/ieee80211_freebsd.c
  stable/12/sys/net80211/ieee80211_freebsd.h
  stable/12/sys/net80211/ieee80211_ioctl.c
  stable/12/sys/net80211/ieee80211_var.h
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/net80211/ieee80211.c
==============================================================================
--- stable/12/sys/net80211/ieee80211.c	Sun Jan 27 11:52:16 2019	(r343487)
+++ stable/12/sys/net80211/ieee80211.c	Sun Jan 27 12:39:35 2019	(r343488)
@@ -405,8 +405,10 @@ ieee80211_ifdetach(struct ieee80211com *ic)
 	 * The VAP is responsible for setting and clearing
 	 * the VIMAGE context.
 	 */
-	while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL)
+	while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL) {
+		ieee80211_com_vdetach(vap);
 		ieee80211_vap_destroy(vap);
+	}
 	ieee80211_waitfor_parent(ic);
 
 	ieee80211_sysctl_detach(ic);

Modified: stable/12/sys/net80211/ieee80211_freebsd.c
==============================================================================
--- stable/12/sys/net80211/ieee80211_freebsd.c	Sun Jan 27 11:52:16 2019	(r343487)
+++ stable/12/sys/net80211/ieee80211_freebsd.c	Sun Jan 27 12:39:35 2019	(r343488)
@@ -307,6 +307,55 @@ ieee80211_sysctl_vdetach(struct ieee80211vap *vap)
 	}
 }
 
+#define	MS(_v, _f)	(((_v) & _f##_M) >> _f##_S)
+int
+ieee80211_com_vincref(struct ieee80211vap *vap)
+{
+	uint32_t ostate;
+
+	ostate = atomic_fetchadd_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
+
+	if (ostate & IEEE80211_COM_DETACHED) {
+		atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
+		return (ENETDOWN);
+	}
+
+	if (MS(ostate, IEEE80211_COM_REF) == IEEE80211_COM_REF_MAX) {
+		atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
+		return (EOVERFLOW);
+	}
+
+	return (0);
+}
+
+void
+ieee80211_com_vdecref(struct ieee80211vap *vap)
+{
+	uint32_t ostate;
+
+	ostate = atomic_fetchadd_32(&vap->iv_com_state, -IEEE80211_COM_REF_ADD);
+
+	KASSERT(MS(ostate, IEEE80211_COM_REF) != 0,
+	    ("com reference counter underflow"));
+
+	(void) ostate;
+}
+
+void
+ieee80211_com_vdetach(struct ieee80211vap *vap)
+{
+	int sleep_time;
+
+	sleep_time = msecs_to_ticks(250);
+	if (sleep_time == 0)
+		sleep_time = 1;
+
+	atomic_set_32(&vap->iv_com_state, IEEE80211_COM_DETACHED);
+	while (MS(atomic_load_32(&vap->iv_com_state), IEEE80211_COM_REF) != 0)
+		pause("comref", sleep_time);
+}
+#undef	MS
+
 int
 ieee80211_node_dectestref(struct ieee80211_node *ni)
 {

Modified: stable/12/sys/net80211/ieee80211_freebsd.h
==============================================================================
--- stable/12/sys/net80211/ieee80211_freebsd.h	Sun Jan 27 11:52:16 2019	(r343487)
+++ stable/12/sys/net80211/ieee80211_freebsd.h	Sun Jan 27 12:39:35 2019	(r343488)
@@ -224,6 +224,11 @@ typedef struct mtx ieee80211_rt_lock_t;
  */
 #include <machine/atomic.h>
 
+struct ieee80211vap;
+int	ieee80211_com_vincref(struct ieee80211vap *);
+void	ieee80211_com_vdecref(struct ieee80211vap *);
+void	ieee80211_com_vdetach(struct ieee80211vap *);
+
 #define ieee80211_node_initref(_ni) \
 	do { ((_ni)->ni_refcnt = 1); } while (0)
 #define ieee80211_node_incref(_ni) \
@@ -235,7 +240,6 @@ int	ieee80211_node_dectestref(struct ieee80211_node *n
 #define	ieee80211_node_refcnt(_ni)	(_ni)->ni_refcnt
 
 struct ifqueue;
-struct ieee80211vap;
 void	ieee80211_drain_ifq(struct ifqueue *);
 void	ieee80211_flush_ifq(struct ifqueue *, struct ieee80211vap *);
 

Modified: stable/12/sys/net80211/ieee80211_ioctl.c
==============================================================================
--- stable/12/sys/net80211/ieee80211_ioctl.c	Sun Jan 27 11:52:16 2019	(r343487)
+++ stable/12/sys/net80211/ieee80211_ioctl.c	Sun Jan 27 12:39:35 2019	(r343488)
@@ -3480,10 +3480,14 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
 {
 	struct ieee80211vap *vap = ifp->if_softc;
 	struct ieee80211com *ic = vap->iv_ic;
-	int error = 0, wait = 0;
+	int error = 0, wait = 0, ic_used;
 	struct ifreq *ifr;
 	struct ifaddr *ifa;			/* XXX */
 
+	ic_used = (cmd != SIOCSIFMTU && cmd != SIOCG80211STATS);
+	if (ic_used && (error = ieee80211_com_vincref(vap)) != 0)
+		return (error);
+
 	switch (cmd) {
 	case SIOCSIFFLAGS:
 		IEEE80211_LOCK(ic);
@@ -3620,5 +3624,9 @@ ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t
 		error = ether_ioctl(ifp, cmd, data);
 		break;
 	}
+
+	if (ic_used)
+		ieee80211_com_vdecref(vap);
+
 	return (error);
 }

Modified: stable/12/sys/net80211/ieee80211_var.h
==============================================================================
--- stable/12/sys/net80211/ieee80211_var.h	Sun Jan 27 11:52:16 2019	(r343487)
+++ stable/12/sys/net80211/ieee80211_var.h	Sun Jan 27 12:39:35 2019	(r343488)
@@ -562,7 +562,9 @@ struct ieee80211vap {
 				    const struct wmeParams *wme_params);
 	struct task		iv_wme_task;	/* deferred VAP WME update */
 
-	uint64_t		iv_spare[6];
+	uint64_t		iv_spare[5];
+	uint32_t		iv_com_state;	/* com usage / detached flag */
+	uint32_t		iv_spare1;
 };
 MALLOC_DECLARE(M_80211_VAP);
 
@@ -684,6 +686,12 @@ MALLOC_DECLARE(M_80211_VAP);
 #define	IEEE80211_FVHT_USEVHT160	0x000000010	/* CONF: Use VHT160 */
 #define	IEEE80211_VFHT_BITS \
 	"\20\1VHT\2VHT40\3VHT80\4VHT80P80\5VHT160"
+
+#define	IEEE80211_COM_DETACHED	0x00000001	/* ieee80211_ifdetach called */
+#define	IEEE80211_COM_REF_ADD	0x00000002	/* add / remove reference */
+#define	IEEE80211_COM_REF_M	0xfffffffe	/* reference counter bits */
+#define	IEEE80211_COM_REF_S	1
+#define	IEEE80211_COM_REF_MAX	(IEEE80211_COM_REF_M >> IEEE80211_COM_REF_S)
 
 int	ic_printf(struct ieee80211com *, const char *, ...) __printflike(2, 3);
 void	ieee80211_ifattach(struct ieee80211com *);