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;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to