summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstsp <stsp@openbsd.org>2015-03-02 13:47:08 +0000
committerstsp <stsp@openbsd.org>2015-03-02 13:47:08 +0000
commitdd463f29c687b46f3b8f379c8ee269693223931a (patch)
tree4207e86830012432d9f15c6e11317b7b9ceebaee
parentload the correct firmware for 3160/7265 (diff)
downloadwireguard-openbsd-dd463f29c687b46f3b8f379c8ee269693223931a.tar.xz
wireguard-openbsd-dd463f29c687b46f3b8f379c8ee269693223931a.zip
Fix scanning with athn(4) USB devices.
The driver artificially limited the number of slots for nodes in its net80211 node cache to 8, the rationale being the device firmware can only handle 8 associated nodes at a time. But that's not a good reason to only cache 8 of potentially many APs in the area. Instead of crippling upper layer data structures, impose the limit locally by raising an error if more than 8 nodes are trying to associate (which can only happen in hostap mode, and hostap mode seems to be broken anyway). This matches what Linux ath9k does. Also, use a USB-specific scan timeout callback to we can do USB refcounting while scanning. ok mpi@
-rw-r--r--sys/dev/usb/if_athn_usb.c37
-rw-r--r--sys/dev/usb/if_athn_usb.h5
2 files changed, 36 insertions, 6 deletions
diff --git a/sys/dev/usb/if_athn_usb.c b/sys/dev/usb/if_athn_usb.c
index de66c8040fb..b20c3db7d23 100644
--- a/sys/dev/usb/if_athn_usb.c
+++ b/sys/dev/usb/if_athn_usb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_athn_usb.c,v 1.28 2015/03/02 13:13:51 stsp Exp $ */
+/* $OpenBSD: if_athn_usb.c,v 1.29 2015/03/02 13:47:08 stsp Exp $ */
/*-
* Copyright (c) 2011 Damien Bergamini <damien.bergamini@free.fr>
@@ -126,6 +126,7 @@ uint32_t athn_usb_read(struct athn_softc *, uint32_t);
void athn_usb_write(struct athn_softc *, uint32_t, uint32_t);
void athn_usb_write_barrier(struct athn_softc *);
int athn_usb_media_change(struct ifnet *);
+void athn_usb_next_scan(void *);
int athn_usb_newstate(struct ieee80211com *, enum ieee80211_state,
int);
void athn_usb_newstate_cb(struct athn_usb_softc *, void *);
@@ -350,10 +351,7 @@ athn_usb_attachhook(void *xsc)
#endif
ic->ic_newstate = athn_usb_newstate;
ic->ic_media.ifm_change = athn_usb_media_change;
-
- /* Firmware cannot handle more than 8 STAs. */
- if (ic->ic_max_nnodes > AR_USB_MAX_STA)
- ic->ic_max_nnodes = AR_USB_MAX_STA;
+ timeout_set(&sc->scan_to, athn_usb_next_scan, usc);
ops->rx_enable = athn_usb_rx_enable;
splx(s);
@@ -984,6 +982,27 @@ athn_usb_media_change(struct ifnet *ifp)
return (error);
}
+void
+athn_usb_next_scan(void *arg)
+{
+ struct athn_usb_softc *usc = arg;
+ struct athn_softc *sc = &usc->sc_sc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ int s;
+
+ if (usbd_is_dying(usc->sc_udev))
+ return;
+
+ usbd_ref_incr(usc->sc_udev);
+
+ s = splnet();
+ if (ic->ic_state == IEEE80211_S_SCAN)
+ ieee80211_next_scan(&ic->ic_if);
+ splx(s);
+
+ usbd_ref_decr(usc->sc_udev);
+}
+
int
athn_usb_newstate(struct ieee80211com *ic, enum ieee80211_state nstate,
int arg)
@@ -1124,6 +1143,7 @@ athn_usb_node_leave_cb(struct athn_usb_softc *usc, void *arg)
(void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE,
&sta_index, sizeof(sta_index), NULL);
+ usc->nnodes--;
}
int
@@ -1191,6 +1211,10 @@ athn_usb_create_node(struct athn_usb_softc *usc, struct ieee80211_node *ni)
struct ar_htc_target_rate rate;
int error;
+ /* Firmware cannot handle more than 8 STAs. */
+ if (usc->nnodes > AR_USB_MAX_STA)
+ return ENOBUFS;
+
an->sta_index = IEEE80211_AID(ni->ni_associd);
/* Create node entry on target. */
@@ -1207,6 +1231,7 @@ athn_usb_create_node(struct athn_usb_softc *usc, struct ieee80211_node *ni)
&sta, sizeof(sta), NULL);
if (error != 0)
return (error);
+ usc->nnodes++;
/* Setup supported rates. */
memset(&rate, 0, sizeof(rate));
@@ -2240,6 +2265,7 @@ athn_usb_init(struct ifnet *ifp)
&sta, sizeof(sta), NULL);
if (error != 0)
goto fail;
+ usc->nnodes++;
/* Update target capabilities. */
memset(&hic, 0, sizeof(hic));
@@ -2322,6 +2348,7 @@ athn_usb_stop(struct ifnet *ifp)
sta_index = 0;
(void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE,
&sta_index, sizeof(sta_index), NULL);
+ usc->nnodes--;
(void)athn_usb_wmi_cmd(usc, AR_WMI_CMD_DISABLE_INTR);
(void)athn_usb_wmi_cmd(usc, AR_WMI_CMD_DRAIN_TXQ_ALL);
diff --git a/sys/dev/usb/if_athn_usb.h b/sys/dev/usb/if_athn_usb.h
index ccbd0633d9b..78cf8cfe885 100644
--- a/sys/dev/usb/if_athn_usb.h
+++ b/sys/dev/usb/if_athn_usb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_athn_usb.h,v 1.4 2013/04/15 09:23:01 mglocker Exp $ */
+/* $OpenBSD: if_athn_usb.h,v 1.5 2015/03/02 13:47:08 stsp Exp $ */
/*-
* Copyright (c) 2011 Damien Bergamini <damien.bergamini@free.fr>
@@ -458,4 +458,7 @@ struct athn_usb_softc {
uint8_t ep_uapsd;
uint8_t ep_mgmt;
uint8_t ep_data[EDCA_NUM_AC];
+
+ /* Firmware cannot handle more than 8 STAs. */
+ uint8_t nnodes;
};