Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 27 Nov 2016 12:03:35 +0000 (UTC)
From:      Andriy Voskoboinyk <avos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r309210 - head/sys/dev/usb/wlan
Message-ID:  <201611271203.uARC3ZLe068129@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: avos
Date: Sun Nov 27 12:03:34 2016
New Revision: 309210
URL: https://svnweb.freebsd.org/changeset/base/309210

Log:
  rsu: various scanning fixes.
  
  - Set IEEE80211_FEXT_SCAN_OFFLOAD flag; firmware can send null data
  frames when associated.
  - Check IEEE80211_SCAN_ACTIVE scan flag instead of IEEE80211_F_ASCAN
  ic flag; the last is never set since r170530.
  - Eliminate software scan (net80211) <-> site_survey (driver) race:
   * override ic_scan_curchan and ic_scan_mindwell pointers so net80211
  will not try to finish scanning automatically;
   * inform net80211 about current status via ieee80211_cancel_scan()
  and ieee80211_scan_done();
   * remove corresponding workaround from rsu_join_bss().
  
  Now the driver can associate to an AP with hidden SSID.
  
  Tested with Asus USB-N10.

Modified:
  head/sys/dev/usb/wlan/if_rsu.c
  head/sys/dev/usb/wlan/if_rsureg.h

Modified: head/sys/dev/usb/wlan/if_rsu.c
==============================================================================
--- head/sys/dev/usb/wlan/if_rsu.c	Sun Nov 27 09:20:58 2016	(r309209)
+++ head/sys/dev/usb/wlan/if_rsu.c	Sun Nov 27 12:03:34 2016	(r309210)
@@ -173,6 +173,8 @@ static void	rsu_scan_end(struct ieee8021
 static void	rsu_getradiocaps(struct ieee80211com *, int, int *,
 		    struct ieee80211_channel[]);
 static void	rsu_set_channel(struct ieee80211com *);
+static void	rsu_scan_curchan(struct ieee80211_scan_state *, unsigned long);
+static void	rsu_scan_mindwell(struct ieee80211_scan_state *);
 static void	rsu_update_mcast(struct ieee80211com *);
 static int	rsu_alloc_rx_list(struct rsu_softc *);
 static void	rsu_free_rx_list(struct rsu_softc *);
@@ -203,7 +205,8 @@ static int	rsu_newstate(struct ieee80211
 static void	rsu_set_key(struct rsu_softc *, const struct ieee80211_key *);
 static void	rsu_delete_key(struct rsu_softc *, const struct ieee80211_key *);
 #endif
-static int	rsu_site_survey(struct rsu_softc *, struct ieee80211vap *);
+static int	rsu_site_survey(struct rsu_softc *,
+		    struct ieee80211_scan_ssid *);
 static int	rsu_join_bss(struct rsu_softc *, struct ieee80211_node *);
 static int	rsu_disconnect(struct rsu_softc *);
 static int	rsu_hwrssi_to_rssi(struct rsu_softc *, int hw_rssi);
@@ -537,6 +540,7 @@ rsu_attach(device_t self)
 		ic->ic_txstream = sc->sc_ntxstream;
 		ic->ic_rxstream = sc->sc_nrxstream;
 	}
+	ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD;
 
 	rsu_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans,
 	    ic->ic_channels);
@@ -547,6 +551,8 @@ rsu_attach(device_t self)
 	ic->ic_scan_end = rsu_scan_end;
 	ic->ic_getradiocaps = rsu_getradiocaps;
 	ic->ic_set_channel = rsu_set_channel;
+	ic->ic_scan_curchan = rsu_scan_curchan;
+	ic->ic_scan_mindwell = rsu_scan_mindwell;
 	ic->ic_vap_create = rsu_vap_create;
 	ic->ic_vap_delete = rsu_vap_delete;
 	ic->ic_update_mcast = rsu_update_mcast;
@@ -680,16 +686,21 @@ static void
 rsu_scan_start(struct ieee80211com *ic)
 {
 	struct rsu_softc *sc = ic->ic_softc;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
+	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
 	int error;
 
 	/* Scanning is done by the firmware. */
 	RSU_LOCK(sc);
-	/* XXX TODO: force awake if in in network-sleep? */
-	error = rsu_site_survey(sc, TAILQ_FIRST(&ic->ic_vaps));
+	sc->sc_active_scan = !!(ss->ss_flags & IEEE80211_SCAN_ACTIVE);
+	/* XXX TODO: force awake if in network-sleep? */
+	error = rsu_site_survey(sc, ss->ss_nssid > 0 ? &ss->ss_ssid[0] : NULL);
 	RSU_UNLOCK(sc);
-	if (error != 0)
+	if (error != 0) {
 		device_printf(sc->sc_dev,
 		    "could not send site survey command\n");
+		ieee80211_cancel_scan(vap);
+	}
 }
 
 static void
@@ -722,6 +733,24 @@ rsu_set_channel(struct ieee80211com *ic 
 }
 
 static void
+rsu_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
+{
+	/* Scan is done in rsu_scan_start(). */
+}
+
+/**
+ * Called by the net80211 framework to indicate
+ * the minimum dwell time has been met, terminate the scan.
+ * We don't actually terminate the scan as the firmware will notify
+ * us when it's finished and we have no way to interrupt it.
+ */
+static void
+rsu_scan_mindwell(struct ieee80211_scan_state *ss)
+{
+	/* NB: don't try to abort scan; wait for firmware to finish */
+}
+
+static void
 rsu_update_mcast(struct ieee80211com *ic)
 {
         /* XXX do nothing?  */
@@ -1323,31 +1352,36 @@ rsu_delete_key(struct rsu_softc *sc, con
 #endif
 
 static int
-rsu_site_survey(struct rsu_softc *sc, struct ieee80211vap *vap)
+rsu_site_survey(struct rsu_softc *sc, struct ieee80211_scan_ssid *ssid)
 {
 	struct r92s_fw_cmd_sitesurvey cmd;
-	struct ieee80211com *ic = &sc->sc_ic;
-	int r;
 
 	RSU_ASSERT_LOCKED(sc);
 
 	memset(&cmd, 0, sizeof(cmd));
-	if ((ic->ic_flags & IEEE80211_F_ASCAN) || sc->sc_scan_pass == 1)
+	/* TODO: passive channels? */
+	if (sc->sc_active_scan)
 		cmd.active = htole32(1);
 	cmd.limit = htole32(48);
-	if (sc->sc_scan_pass == 1 && vap->iv_des_nssid > 0) {
-		/* Do a directed scan for second pass. */
-		cmd.ssidlen = htole32(vap->iv_des_ssid[0].len);
-		memcpy(cmd.ssid, vap->iv_des_ssid[0].ssid,
-		    vap->iv_des_ssid[0].len);
-
+	
+	if (ssid != NULL) {
+		sc->sc_extra_scan = 1;
+		cmd.ssidlen = htole32(ssid->len);
+		memcpy(cmd.ssid, ssid->ssid, ssid->len);
 	}
-	DPRINTF("sending site survey command, pass=%d\n", sc->sc_scan_pass);
-	r = rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd));
-	if (r == 0) {
-		sc->sc_scanning = 1;
+#ifdef USB_DEBUG
+	if (rsu_debug & (RSU_DEBUG_SCAN | RSU_DEBUG_FWCMD)) {
+		device_printf(sc->sc_dev,
+		    "sending site survey command, active %d",
+		    le32toh(cmd.active));
+		if (ssid != NULL) {
+			printf(", ssid: ");
+			ieee80211_print_essid(cmd.ssid, le32toh(cmd.ssidlen));
+		}
+		printf("\n");
 	}
-	return (r);
+#endif
+	return (rsu_fw_cmd(sc, R92S_CMD_SITE_SURVEY, &cmd, sizeof(cmd)));
 }
 
 static int
@@ -1362,28 +1396,9 @@ rsu_join_bss(struct rsu_softc *sc, struc
 	uint8_t *frm;
 	uint8_t opmode;
 	int error;
-	int cnt;
-	char *msg = "rsujoin";
 
 	RSU_ASSERT_LOCKED(sc);
 
-	/*
-	 * Until net80211 scanning doesn't automatically finish
-	 * before we tell it to, let's just wait until any pending
-	 * scan is done.
-	 *
-	 * XXX TODO: yes, this releases and re-acquires the lock.
-	 * We should re-verify the state whenever we re-attempt this!
-	 */
-	cnt = 0;
-	while (sc->sc_scanning && cnt < 10) {
-		device_printf(sc->sc_dev,
-		    "%s: still scanning! (attempt %d)\n",
-		    __func__, cnt);
-		msleep(msg, &sc->sc_mtx, 0, msg, hz / 2);
-		cnt++;
-	}
-
 	/* Let the FW decide the opmode based on the capinfo field. */
 	opmode = NDIS802_11AUTOUNKNOWN;
 	RSU_DPRINTF(sc, RSU_DEBUG_RESET,
@@ -1634,26 +1649,24 @@ rsu_rx_event(struct rsu_softc *sc, uint8
 		break;
 	case R92S_EVT_SURVEY_DONE:
 		RSU_DPRINTF(sc, RSU_DEBUG_SCAN,
-		    "%s: site survey pass %d done, found %d BSS\n",
-		    __func__, sc->sc_scan_pass, le32toh(*(uint32_t *)buf));
-		sc->sc_scanning = 0;
-		if (vap->iv_state != IEEE80211_S_SCAN)
-			break;	/* Ignore if not scanning. */
-
-		/*
-		 * XXX TODO: This needs to be done without a transition to
-		 * the SCAN state again.  Grr.
-		 */
-		if (sc->sc_scan_pass == 0 && vap->iv_des_nssid != 0) {
-			/* Schedule a directed scan for hidden APs. */
-			/* XXX bad! */
-			sc->sc_scan_pass = 1;
+		    "%s: %s scan done, found %d BSS\n",
+		    __func__, sc->sc_extra_scan ? "direct" : "broadcast",
+		    le32toh(*(uint32_t *)buf));
+		if (sc->sc_extra_scan == 1) {
+			/* Send broadcast probe request. */
+			sc->sc_extra_scan = 0;
+			if (vap != NULL && rsu_site_survey(sc, NULL) != 0) {
+				RSU_UNLOCK(sc);
+				ieee80211_cancel_scan(vap);
+				RSU_LOCK(sc);
+			}
+			break;
+		}
+		if (vap != NULL) {
 			RSU_UNLOCK(sc);
-			ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
+			ieee80211_scan_done(vap);
 			RSU_LOCK(sc);
-			break;
 		}
-		sc->sc_scan_pass = 0;
 		break;
 	case R92S_EVT_JOIN_BSS:
 		if (vap->iv_state == IEEE80211_S_AUTH)
@@ -2920,12 +2933,11 @@ rsu_init(struct rsu_softc *sc)
 		goto fail;
 	}
 
-	sc->sc_scan_pass = 0;
+	sc->sc_extra_scan = 0;
 	usbd_transfer_start(sc->sc_xfer[RSU_BULK_RX]);
 
 	/* We're ready to go. */
 	sc->sc_running = 1;
-	sc->sc_scanning = 0;
 	return;
 fail:
 	/* Need to stop all failed transfers, if any */

Modified: head/sys/dev/usb/wlan/if_rsureg.h
==============================================================================
--- head/sys/dev/usb/wlan/if_rsureg.h	Sun Nov 27 09:20:58 2016	(r309209)
+++ head/sys/dev/usb/wlan/if_rsureg.h	Sun Nov 27 12:03:34 2016	(r309210)
@@ -768,8 +768,8 @@ struct rsu_softc {
 
 	u_int				sc_running:1,
 					sc_calibrating:1,
-					sc_scanning:1,
-					sc_scan_pass:1;
+					sc_active_scan:1,
+					sc_extra_scan:1;
 	u_int				cut;
 	uint8_t				sc_rftype;
 	int8_t				sc_nrxstream;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201611271203.uARC3ZLe068129>