mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
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.
This commit is contained in:
parent
abc1515601
commit
5dbbb84e42
2 changed files with 72 additions and 60 deletions
|
|
@ -173,6 +173,8 @@ static void rsu_scan_end(struct ieee80211com *);
|
|||
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 ieee80211vap *, enum ieee80211_state, int);
|
|||
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
|
||||
|
|
@ -721,6 +732,24 @@ rsu_set_channel(struct ieee80211com *ic __unused)
|
|||
/* We are unable to switch channels, yet. */
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
@ -1323,31 +1352,36 @@ rsu_delete_key(struct rsu_softc *sc, const struct ieee80211_key *k)
|
|||
#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, struct ieee80211_node *ni)
|
|||
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_t code, uint8_t *buf, int len)
|
|||
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;
|
||||
RSU_UNLOCK(sc);
|
||||
ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
|
||||
RSU_LOCK(sc);
|
||||
"%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;
|
||||
}
|
||||
sc->sc_scan_pass = 0;
|
||||
if (vap != NULL) {
|
||||
RSU_UNLOCK(sc);
|
||||
ieee80211_scan_done(vap);
|
||||
RSU_LOCK(sc);
|
||||
}
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue