rsu: add hardware crypto support (WEP, TKIP and CCMP).

This change includes firmware commands for key setup +
some additional checking via CAMREAD / CAMWRITE registers.
Nothing (except rsu_delete_key() for pairwise keys) is deferred;
to ensure that things are done in order rsu_set_key() will wait
until key deletion task will be finished.

Tested with Asus USB-N10 (all ciphers).

Differences from initial (reviewed) patch:
- Pause AC queues before disassociation - since CMD_DISCONNECT clears
crypto state all pending frames must be processed / dropped before it.
- Check sc_running flag before trying to set static keys.
- Clear key index from bitmap even when firmware command fails
(it will be invalidated via CAMWRITE anyway).

Reviewed by:	adrian, kevlo
Tested by:	kevlo
Differential Revision:	https://reviews.freebsd.org/D8706
This commit is contained in:
Andriy Voskoboinyk 2016-12-06 00:13:49 +00:00
parent 00aa064f30
commit 31847d9434
2 changed files with 495 additions and 46 deletions

View File

@ -22,8 +22,8 @@ __FBSDID("$FreeBSD$");
* Driver for Realtek RTL8188SU/RTL8191SU/RTL8192SU.
*
* TODO:
* o h/w crypto
* o hostap / ibss / mesh
* o tx a-mpdu
* o monitor / hostap / ibss / mesh
* o power-save operation
*/
@ -102,6 +102,7 @@ TUNABLE_INT("hw.usb.rsu.enable_11n", &rsu_enable_11n);
#define RSU_DEBUG_FW 0x00000100
#define RSU_DEBUG_FWDBG 0x00000200
#define RSU_DEBUG_AMPDU 0x00000400
#define RSU_DEBUG_KEY 0x00000800
static const STRUCT_USB_HOST_ID rsu_devs[] = {
#define RSU_HT_NOT_SUPPORTED 0
@ -202,10 +203,25 @@ static int rsu_fw_cmd(struct rsu_softc *, uint8_t, void *, int);
static void rsu_calib_task(void *, int);
static void rsu_tx_task(void *, int);
static int rsu_newstate(struct ieee80211vap *, enum ieee80211_state, int);
#ifdef notyet
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_key_alloc(struct ieee80211vap *, struct ieee80211_key *,
ieee80211_keyix *, ieee80211_keyix *);
static int rsu_process_key(struct ieee80211vap *,
const struct ieee80211_key *, int);
static int rsu_key_set(struct ieee80211vap *,
const struct ieee80211_key *);
static int rsu_key_delete(struct ieee80211vap *,
const struct ieee80211_key *);
static int rsu_cam_read(struct rsu_softc *, uint8_t, uint32_t *);
static void rsu_cam_write(struct rsu_softc *, uint8_t, uint32_t);
static int rsu_key_check(struct rsu_softc *, ieee80211_keyix, int);
static uint8_t rsu_crypto_mode(struct rsu_softc *, u_int, int);
static int rsu_set_key_group(struct rsu_softc *,
const struct ieee80211_key *);
static int rsu_set_key_pair(struct rsu_softc *,
const struct ieee80211_key *);
static int rsu_reinit_static_keys(struct rsu_softc *);
static int rsu_delete_key(struct rsu_softc *sc, ieee80211_keyix);
static void rsu_delete_key_pair_cb(void *, int);
static int rsu_site_survey(struct rsu_softc *,
struct ieee80211_scan_ssid *);
static int rsu_join_bss(struct rsu_softc *, struct ieee80211_node *);
@ -437,8 +453,10 @@ rsu_attach(device_t self)
mtx_init(&sc->sc_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK,
MTX_DEF);
RSU_DELKEY_BMAP_LOCK_INIT(sc);
TIMEOUT_TASK_INIT(taskqueue_thread, &sc->calib_task, 0,
rsu_calib_task, sc);
TASK_INIT(&sc->del_key_task, 0, rsu_delete_key_pair_cb, sc);
TASK_INIT(&sc->tx_task, 0, rsu_tx_task, sc);
mbufq_init(&sc->sc_snd, ifqmaxlen);
@ -524,6 +542,11 @@ rsu_attach(device_t self)
IEEE80211_C_SHSLOT | /* Short slot time supported. */
IEEE80211_C_WPA; /* WPA/RSN. */
ic->ic_cryptocaps =
IEEE80211_CRYPTO_WEP |
IEEE80211_CRYPTO_TKIP |
IEEE80211_CRYPTO_AES_CCM;
/* Check if HT support is present. */
if (sc->sc_ht) {
device_printf(sc->sc_dev, "%s: enabling 11n\n", __func__);
@ -608,8 +631,10 @@ rsu_detach(device_t self)
ieee80211_ifdetach(ic);
taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task);
taskqueue_drain(taskqueue_thread, &sc->del_key_task);
taskqueue_drain(taskqueue_thread, &sc->tx_task);
RSU_DELKEY_BMAP_LOCK_DESTROY(sc);
mtx_destroy(&sc->sc_mtx);
return (0);
@ -662,6 +687,9 @@ rsu_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit,
/* override state transition machine */
uvp->newstate = vap->iv_newstate;
vap->iv_newstate = rsu_newstate;
vap->iv_key_alloc = rsu_key_alloc;
vap->iv_key_set = rsu_key_set;
vap->iv_key_delete = rsu_key_delete;
/* Limits from the r92su driver */
vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_16;
@ -1335,12 +1363,20 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
RSU_LOCK(sc);
/* Stop calibration. */
sc->sc_calibrating = 0;
/* Pause Tx for AC queues. */
rsu_write_1(sc, R92S_TXPAUSE, R92S_TXPAUSE_AC);
usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(10));
RSU_UNLOCK(sc);
taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task);
taskqueue_drain(taskqueue_thread, &sc->tx_task);
/* Disassociate from our current BSS. */
RSU_LOCK(sc);
/* Disassociate from our current BSS. */
rsu_disconnect(sc);
/* Reinstall static keys. */
if (sc->sc_running)
rsu_reinit_static_keys(sc);
} else
RSU_LOCK(sc);
switch (nstate) {
@ -1358,6 +1394,9 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
}
break;
case IEEE80211_S_RUN:
/* Flush all AC queues. */
rsu_write_1(sc, R92S_TXPAUSE, 0);
ni = ieee80211_ref_node(vap->iv_bss);
rs = &ni->ni_rates;
/* Indicate highest supported rate. */
@ -1380,46 +1419,365 @@ rsu_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
return (uvp->newstate(vap, nstate, arg));
}
#ifdef notyet
static int
rsu_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
{
struct rsu_softc *sc = vap->iv_ic->ic_softc;
int is_checked = 0;
if (&vap->iv_nw_keys[0] <= k &&
k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) {
*keyix = k - vap->iv_nw_keys;
} else {
if (vap->iv_opmode != IEEE80211_M_STA) {
*keyix = 0;
/* TODO: obtain keyix from node id */
is_checked = 1;
k->wk_flags |= IEEE80211_KEY_SWCRYPT;
} else
*keyix = R92S_MACID_BSS;
}
if (!is_checked) {
RSU_LOCK(sc);
if (isset(sc->keys_bmap, *keyix)) {
device_printf(sc->sc_dev,
"%s: key slot %d is already used!\n",
__func__, *keyix);
RSU_UNLOCK(sc);
return (0);
}
setbit(sc->keys_bmap, *keyix);
RSU_UNLOCK(sc);
}
*rxkeyix = *keyix;
return (1);
}
static int
rsu_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k,
int set)
{
struct rsu_softc *sc = vap->iv_ic->ic_softc;
int ret;
if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
/* Not for us. */
return (1);
}
/* Handle group keys. */
if (&vap->iv_nw_keys[0] <= k &&
k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) {
KASSERT(k->wk_keyix < nitems(sc->group_keys),
("keyix %d > %d\n", k->wk_keyix, nitems(sc->group_keys)));
RSU_LOCK(sc);
sc->group_keys[k->wk_keyix] = (set ? k : NULL);
if (!sc->sc_running) {
/* Static keys will be set during device startup. */
RSU_UNLOCK(sc);
return (1);
}
if (set)
ret = rsu_set_key_group(sc, k);
else
ret = rsu_delete_key(sc, k->wk_keyix);
RSU_UNLOCK(sc);
return (!ret);
}
if (set) {
/* wait for pending key removal */
taskqueue_drain(taskqueue_thread, &sc->del_key_task);
RSU_LOCK(sc);
ret = rsu_set_key_pair(sc, k);
RSU_UNLOCK(sc);
} else {
RSU_DELKEY_BMAP_LOCK(sc);
setbit(sc->free_keys_bmap, k->wk_keyix);
RSU_DELKEY_BMAP_UNLOCK(sc);
/* workaround ieee80211_node_delucastkey() locking */
taskqueue_enqueue(taskqueue_thread, &sc->del_key_task);
ret = 0; /* fake success */
}
return (!ret);
}
static int
rsu_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
{
return (rsu_process_key(vap, k, 1));
}
static int
rsu_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
{
return (rsu_process_key(vap, k, 0));
}
static int
rsu_cam_read(struct rsu_softc *sc, uint8_t addr, uint32_t *val)
{
int ntries;
rsu_write_4(sc, R92S_CAMCMD,
R92S_CAMCMD_POLLING | SM(R92S_CAMCMD_ADDR, addr));
for (ntries = 0; ntries < 10; ntries++) {
if (!(rsu_read_4(sc, R92S_CAMCMD) & R92S_CAMCMD_POLLING))
break;
usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(1));
}
if (ntries == 10) {
device_printf(sc->sc_dev,
"%s: cannot read CAM entry at address %02X\n",
__func__, addr);
return (ETIMEDOUT);
}
*val = rsu_read_4(sc, R92S_CAMREAD);
return (0);
}
static void
rsu_set_key(struct rsu_softc *sc, const struct ieee80211_key *k)
rsu_cam_write(struct rsu_softc *sc, uint8_t addr, uint32_t data)
{
rsu_write_4(sc, R92S_CAMWRITE, data);
rsu_write_4(sc, R92S_CAMCMD,
R92S_CAMCMD_POLLING | R92S_CAMCMD_WRITE |
SM(R92S_CAMCMD_ADDR, addr));
}
static int
rsu_key_check(struct rsu_softc *sc, ieee80211_keyix keyix, int is_valid)
{
uint32_t val;
int error, ntries;
for (ntries = 0; ntries < 20; ntries++) {
usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(1));
error = rsu_cam_read(sc, R92S_CAM_CTL0(keyix), &val);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: cannot check key status!\n", __func__);
return (error);
}
if (((val & R92S_CAM_VALID) == 0) ^ is_valid)
break;
}
if (ntries == 20) {
device_printf(sc->sc_dev,
"%s: key %d is %s marked as valid, rejecting request\n",
__func__, keyix, is_valid ? "not" : "still");
return (EIO);
}
return (0);
}
/*
* Map net80211 cipher to RTL8712 security mode.
*/
static uint8_t
rsu_crypto_mode(struct rsu_softc *sc, u_int cipher, int keylen)
{
switch (cipher) {
case IEEE80211_CIPHER_WEP:
return keylen < 8 ? R92S_KEY_ALGO_WEP40 : R92S_KEY_ALGO_WEP104;
case IEEE80211_CIPHER_TKIP:
return R92S_KEY_ALGO_TKIP;
case IEEE80211_CIPHER_AES_CCM:
return R92S_KEY_ALGO_AES;
default:
device_printf(sc->sc_dev, "unknown cipher %d\n", cipher);
return R92S_KEY_ALGO_INVALID;
}
}
static int
rsu_set_key_group(struct rsu_softc *sc, const struct ieee80211_key *k)
{
struct r92s_fw_cmd_set_key key;
uint8_t algo;
int error;
RSU_ASSERT_LOCKED(sc);
/* Map net80211 cipher to HW crypto algorithm. */
algo = rsu_crypto_mode(sc, k->wk_cipher->ic_cipher, k->wk_keylen);
if (algo == R92S_KEY_ALGO_INVALID)
return (EINVAL);
memset(&key, 0, sizeof(key));
/* Map net80211 cipher to HW crypto algorithm. */
switch (k->wk_cipher->ic_cipher) {
case IEEE80211_CIPHER_WEP:
if (k->wk_keylen < 8)
key.algo = R92S_KEY_ALGO_WEP40;
else
key.algo = R92S_KEY_ALGO_WEP104;
break;
case IEEE80211_CIPHER_TKIP:
key.algo = R92S_KEY_ALGO_TKIP;
break;
case IEEE80211_CIPHER_AES_CCM:
key.algo = R92S_KEY_ALGO_AES;
break;
default:
return;
}
key.id = k->wk_keyix;
key.algo = algo;
key.cam_id = k->wk_keyix;
key.grpkey = (k->wk_flags & IEEE80211_KEY_GROUP) != 0;
memcpy(key.key, k->wk_key, MIN(k->wk_keylen, sizeof(key.key)));
(void)rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key));
RSU_DPRINTF(sc, RSU_DEBUG_KEY | RSU_DEBUG_FWCMD,
"%s: keyix %u, group %u, algo %u/%u, flags %04X, len %u, "
"macaddr %s\n", __func__, key.cam_id, key.grpkey,
k->wk_cipher->ic_cipher, key.algo, k->wk_flags, k->wk_keylen,
ether_sprintf(k->wk_macaddr));
error = rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key));
if (error != 0) {
device_printf(sc->sc_dev,
"%s: cannot send firmware command, error %d\n",
__func__, error);
return (error);
}
return (rsu_key_check(sc, k->wk_keyix, 1));
}
static int
rsu_set_key_pair(struct rsu_softc *sc, const struct ieee80211_key *k)
{
struct r92s_fw_cmd_set_key_mac key;
uint8_t algo;
int error;
RSU_ASSERT_LOCKED(sc);
if (!sc->sc_running)
return (ESHUTDOWN);
/* Map net80211 cipher to HW crypto algorithm. */
algo = rsu_crypto_mode(sc, k->wk_cipher->ic_cipher, k->wk_keylen);
if (algo == R92S_KEY_ALGO_INVALID)
return (EINVAL);
memset(&key, 0, sizeof(key));
key.algo = algo;
memcpy(key.macaddr, k->wk_macaddr, sizeof(key.macaddr));
memcpy(key.key, k->wk_key, MIN(k->wk_keylen, sizeof(key.key)));
RSU_DPRINTF(sc, RSU_DEBUG_KEY | RSU_DEBUG_FWCMD,
"%s: keyix %u, algo %u/%u, flags %04X, len %u, macaddr %s\n",
__func__, k->wk_keyix, k->wk_cipher->ic_cipher, key.algo,
k->wk_flags, k->wk_keylen, ether_sprintf(key.macaddr));
error = rsu_fw_cmd(sc, R92S_CMD_SET_STA_KEY, &key, sizeof(key));
if (error != 0) {
device_printf(sc->sc_dev,
"%s: cannot send firmware command, error %d\n",
__func__, error);
return (error);
}
return (rsu_key_check(sc, k->wk_keyix, 1));
}
static int
rsu_reinit_static_keys(struct rsu_softc *sc)
{
int i, error;
for (i = 0; i < nitems(sc->group_keys); i++) {
if (sc->group_keys[i] != NULL) {
error = rsu_set_key_group(sc, sc->group_keys[i]);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: failed to set static key %d, "
"error %d\n", __func__, i, error);
return (error);
}
}
}
return (0);
}
static int
rsu_delete_key(struct rsu_softc *sc, ieee80211_keyix keyix)
{
struct r92s_fw_cmd_set_key key;
uint32_t val;
int error;
RSU_ASSERT_LOCKED(sc);
if (!sc->sc_running)
return (0);
/* check if it was automatically removed by firmware */
error = rsu_cam_read(sc, R92S_CAM_CTL0(keyix), &val);
if (error == 0 && (val & R92S_CAM_VALID) == 0) {
RSU_DPRINTF(sc, RSU_DEBUG_KEY,
"%s: key %u does not exist\n", __func__, keyix);
clrbit(sc->keys_bmap, keyix);
return (0);
}
memset(&key, 0, sizeof(key));
key.cam_id = keyix;
RSU_DPRINTF(sc, RSU_DEBUG_KEY | RSU_DEBUG_FWCMD,
"%s: removing key %u\n", __func__, key.cam_id);
error = rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key));
if (error != 0) {
device_printf(sc->sc_dev,
"%s: cannot send firmware command, error %d\n",
__func__, error);
goto finish;
}
usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(5));
/*
* Clear 'valid' bit manually (cannot be done via firmware command).
* Used for key check + when firmware command cannot be sent.
*/
finish:
rsu_cam_write(sc, R92S_CAM_CTL0(keyix), 0);
clrbit(sc->keys_bmap, keyix);
return (rsu_key_check(sc, keyix, 0));
}
static void
rsu_delete_key(struct rsu_softc *sc, const struct ieee80211_key *k)
rsu_delete_key_pair_cb(void *arg, int pending __unused)
{
struct r92s_fw_cmd_set_key key;
struct rsu_softc *sc = arg;
int i;
memset(&key, 0, sizeof(key));
key.id = k->wk_keyix;
(void)rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, sizeof(key));
RSU_DELKEY_BMAP_LOCK(sc);
for (i = IEEE80211_WEP_NKID; i < R92S_CAM_ENTRY_LIMIT; i++) {
if (isset(sc->free_keys_bmap, i)) {
RSU_DELKEY_BMAP_UNLOCK(sc);
RSU_LOCK(sc);
RSU_DPRINTF(sc, RSU_DEBUG_KEY,
"%s: calling rsu_delete_key() with keyix = %d\n",
__func__, i);
(void) rsu_delete_key(sc, i);
RSU_UNLOCK(sc);
RSU_DELKEY_BMAP_LOCK(sc);
clrbit(sc->free_keys_bmap, i);
/* bmap can be changed */
i = IEEE80211_WEP_NKID - 1;
continue;
}
}
RSU_DELKEY_BMAP_UNLOCK(sc);
}
#endif
static int
rsu_site_survey(struct rsu_softc *sc, struct ieee80211_scan_ssid *ssid)
@ -1834,9 +2192,10 @@ rsu_rx_copy_to_mbuf(struct rsu_softc *sc, struct r92s_rx_stat *stat,
int pktlen;
rxdw0 = le32toh(stat->rxdw0);
if (__predict_false(rxdw0 & R92S_RXDW0_CRCERR)) {
if (__predict_false(rxdw0 & (R92S_RXDW0_CRCERR | R92S_RXDW0_ICVERR))) {
RSU_DPRINTF(sc, RSU_DEBUG_RX,
"%s: RX flags error (CRC)\n", __func__);
"%s: RX flags error (%s)\n", __func__,
rxdw0 & R92S_RXDW0_CRCERR ? "CRC" : "ICV");
goto fail;
}
@ -1871,7 +2230,7 @@ rsu_rx_frame(struct rsu_softc *sc, struct mbuf *m, int8_t *rssi_p)
struct ieee80211_frame_min *wh;
struct r92s_rx_stat *stat;
uint32_t rxdw0, rxdw3;
uint8_t rate;
uint8_t cipher, rate;
int infosz;
stat = mtod(m, struct r92s_rx_stat *);
@ -1879,6 +2238,7 @@ rsu_rx_frame(struct rsu_softc *sc, struct mbuf *m, int8_t *rssi_p)
rxdw3 = le32toh(stat->rxdw3);
rate = MS(rxdw3, R92S_RXDW3_RATE);
cipher = MS(rxdw0, R92S_RXDW0_CIPHER);
infosz = MS(rxdw0, R92S_RXDW0_INFOSZ) * 8;
/* Get RSSI from PHY status descriptor if present. */
@ -1930,6 +2290,10 @@ rsu_rx_frame(struct rsu_softc *sc, struct mbuf *m, int8_t *rssi_p)
/* Drop descriptor. */
m_adj(m, sizeof(*stat) + infosz);
wh = mtod(m, struct ieee80211_frame_min *);
if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
cipher != R92S_KEY_ALGO_NONE) {
m->m_flags |= M_WEP;
}
RSU_DPRINTF(sc, RSU_DEBUG_RX,
"%s: Rx frame len %d, rate %d, infosz %d\n",
@ -2225,7 +2589,7 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
struct ieee80211_frame *wh;
struct ieee80211_key *k = NULL;
struct r92s_tx_desc *txd;
uint8_t type;
uint8_t type, cipher;
int prio = 0;
uint8_t which;
int hasqos;
@ -2298,8 +2662,7 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
SM(R92S_TXDW1_MACID, R92S_MACID_BSS) | SM(R92S_TXDW1_QSEL, qid));
if (!hasqos)
txd->txdw1 |= htole32(R92S_TXDW1_NONQOS);
#ifdef notyet
if (k != NULL) {
if (k != NULL && !(k->wk_flags & IEEE80211_KEY_SWENCRYPT)) {
switch (k->wk_cipher->ic_cipher) {
case IEEE80211_CIPHER_WEP:
cipher = R92S_TXDW1_CIPHER_WEP;
@ -2315,9 +2678,8 @@ rsu_tx_start(struct rsu_softc *sc, struct ieee80211_node *ni,
}
txd->txdw1 |= htole32(
SM(R92S_TXDW1_CIPHER, cipher) |
SM(R92S_TXDW1_KEYIDX, k->k_id));
SM(R92S_TXDW1_KEYIDX, k->wk_keyix));
}
#endif
/* XXX todo: set AGGEN bit if appropriate? */
txd->txdw2 |= htole32(R92S_TXDW2_BK);
if (IEEE80211_IS_MULTICAST(wh->i_addr1))
@ -3021,12 +3383,16 @@ rsu_init(struct rsu_softc *sc)
/* Set PS mode fully active */
error = rsu_set_fw_power_state(sc, RSU_PWR_ACTIVE);
if (error != 0) {
device_printf(sc->sc_dev, "could not set PS mode\n");
goto fail;
}
/* Install static keys (if any). */
error = rsu_reinit_static_keys(sc);
if (error != 0)
goto fail;
sc->sc_extra_scan = 0;
usbd_transfer_start(sc->sc_xfer[RSU_BULK_RX]);
@ -3054,6 +3420,13 @@ rsu_stop(struct rsu_softc *sc)
/* Power off adapter. */
rsu_power_off(sc);
/*
* CAM is not accessible after shutdown;
* all entries are marked (by firmware?) as invalid.
*/
memset(sc->free_keys_bmap, 0, sizeof(sc->free_keys_bmap));
memset(sc->keys_bmap, 0, sizeof(sc->keys_bmap));
for (i = 0; i < RSU_N_TRANSFER; i++)
usbd_transfer_stop(sc->sc_xfer[i]);

View File

@ -43,6 +43,7 @@
#define R92S_CMDCTRL 0x0040
#define R92S_CR (R92S_CMDCTRL + 0x000)
#define R92S_TXPAUSE (R92S_CMDCTRL + 0x002)
#define R92S_TCR (R92S_CMDCTRL + 0x004)
#define R92S_RCR (R92S_CMDCTRL + 0x008)
@ -55,6 +56,11 @@
#define R92S_GPIO_IO_SEL (R92S_GP + 0x00e)
#define R92S_MAC_PINMUX_CTRL (R92S_GP + 0x011)
#define R92S_SECURITY 0x0240
#define R92S_CAMCMD (R92S_SECURITY + 0x000)
#define R92S_CAMWRITE (R92S_SECURITY + 0x004)
#define R92S_CAMREAD (R92S_SECURITY + 0x008)
#define R92S_IOCMD_CTRL 0x0370
#define R92S_IOCMD_DATA 0x0374
@ -105,6 +111,24 @@
/* Bits for R92S_CR. */
#define R92S_CR_TXDMA_EN 0x10
/* Bits for R92S_TXPAUSE. */
#define R92S_TXPAUSE_VO 0x01
#define R92S_TXPAUSE_VI 0x02
#define R92S_TXPAUSE_BE 0x04
#define R92S_TXPAUSE_BK 0x08
#define R92S_TXPAUSE_MGT 0x10
#define R92S_TXPAUSE_HIGH 0x20
#define R92S_TXPAUSE_HCCA 0x40
/* Shortcuts. */
#define R92S_TXPAUSE_AC \
(R92S_TXPAUSE_VO | R92S_TXPAUSE_VI | \
R92S_TXPAUSE_BE | R92S_TXPAUSE_BK)
#define R92S_TXPAUSE_ALL \
(R92S_TXPAUSE_AC | R92S_TXPAUSE_MGT | \
R92S_TXPAUSE_HIGH | R92S_TXPAUSE_HCCA | 0x80)
/* Bits for R92S_TCR. */
#define R92S_TCR_IMEM_CODE_DONE 0x01
#define R92S_TCR_IMEM_CHK_RPT 0x02
@ -126,6 +150,32 @@
#define R92S_GPIOSEL_GPIO_WLANDBG 3
#define R92S_GPIOMUX_EN 0x08
/* Bits for R92S_CAMCMD. */
#define R92S_CAMCMD_ADDR_M 0x000000ff
#define R92S_CAMCMD_ADDR_S 0
#define R92S_CAMCMD_READ 0x00000000
#define R92S_CAMCMD_WRITE 0x00010000
#define R92S_CAMCMD_POLLING 0x80000000
/*
* CAM entries.
*/
#define R92S_CAM_ENTRY_LIMIT 32
#define R92S_CAM_ENTRY_BYTES howmany(R92S_CAM_ENTRY_LIMIT, NBBY)
#define R92S_CAM_CTL0(entry) ((entry) * 8 + 0)
#define R92S_CAM_CTL1(entry) ((entry) * 8 + 1)
#define R92S_CAM_KEY(entry, i) ((entry) * 8 + 2 + (i))
/* Bits for R92S_CAM_CTL0(i). */
#define R92S_CAM_KEYID_M 0x00000003
#define R92S_CAM_KEYID_S 0
#define R92S_CAM_ALGO_M 0x0000001c
#define R92S_CAM_ALGO_S 2
#define R92S_CAM_VALID 0x00008000
#define R92S_CAM_MACLO_M 0xffff0000
#define R92S_CAM_MACLO_S 16
/* Bits for R92S_IOCMD_CTRL. */
#define R92S_IOCMD_CLASS_M 0xff000000
#define R92S_IOCMD_CLASS_S 24
@ -391,10 +441,18 @@ struct r92s_fw_cmd_set_key {
#define R92S_KEY_ALGO_TKIP_MMIC 3
#define R92S_KEY_ALGO_AES 4
#define R92S_KEY_ALGO_WEP104 5
#define R92S_KEY_ALGO_INVALID 0xff /* for rsu_crypto_mode() only */
uint8_t id;
uint8_t cam_id;
uint8_t grpkey;
uint8_t key[16];
uint8_t key[IEEE80211_KEYBUF_SIZE];
} __packed;
/* Structure for R92S_CMD_SET_STA_KEY. */
struct r92s_fw_cmd_set_key_mac {
uint8_t macaddr[IEEE80211_ADDR_LEN];
uint8_t algo;
uint8_t key[IEEE80211_KEYBUF_SIZE];
} __packed;
/* Structures for R92S_EVENT_SURVEY/R92S_CMD_JOIN_BSS. */
@ -497,7 +555,7 @@ struct r92s_event_join_bss {
struct ndis_wlan_bssid_ex bss;
} __packed;
#define R92S_MACID_BSS 5
#define R92S_MACID_BSS 5 /* XXX hardcoded somewhere */
/* Rx MAC descriptor. */
struct r92s_rx_stat {
@ -505,8 +563,11 @@ struct r92s_rx_stat {
#define R92S_RXDW0_PKTLEN_M 0x00003fff
#define R92S_RXDW0_PKTLEN_S 0
#define R92S_RXDW0_CRCERR 0x00004000
#define R92S_RXDW0_ICVERR 0x00008000
#define R92S_RXDW0_INFOSZ_M 0x000f0000
#define R92S_RXDW0_INFOSZ_S 16
#define R92S_RXDW0_CIPHER_M 0x00700000
#define R92S_RXDW0_CIPHER_S 20
#define R92S_RXDW0_QOS 0x00800000
#define R92S_RXDW0_SHIFT_M 0x03000000
#define R92S_RXDW0_SHIFT_S 24
@ -581,6 +642,7 @@ struct r92s_tx_desc {
#define R92S_TXDW1_KEYIDX_S 17
#define R92S_TXDW1_CIPHER_M 0x00c00000
#define R92S_TXDW1_CIPHER_S 22
#define R92S_TXDW1_CIPHER_NONE 0
#define R92S_TXDW1_CIPHER_WEP 1
#define R92S_TXDW1_CIPHER_TKIP 2
#define R92S_TXDW1_CIPHER_AES 3
@ -728,6 +790,13 @@ struct rsu_vap {
#define RSU_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
#define RSU_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
#define RSU_DELKEY_BMAP_LOCK_INIT(_sc) \
mtx_init(&(_sc)->free_keys_bmap_mtx, "bmap lock", NULL, MTX_DEF)
#define RSU_DELKEY_BMAP_LOCK(_sc) mtx_lock(&(_sc)->free_keys_bmap_mtx)
#define RSU_DELKEY_BMAP_UNLOCK(_sc) mtx_unlock(&(_sc)->free_keys_bmap_mtx)
#define RSU_DELKEY_BMAP_LOCK_DESTROY(_sc) \
mtx_destroy(&(_sc)->free_keys_bmap_mtx)
struct rsu_softc {
struct ieee80211com sc_ic;
struct mbufq sc_snd;
@ -762,6 +831,13 @@ struct rsu_softc {
STAILQ_HEAD(, rsu_data) sc_tx_inactive;
STAILQ_HEAD(, rsu_data) sc_tx_pending[RSU_N_TRANSFER];
struct task del_key_task;
uint8_t keys_bmap[R92S_CAM_ENTRY_BYTES];
const struct ieee80211_key *group_keys[IEEE80211_WEP_NKID];
struct mtx free_keys_bmap_mtx;
uint8_t free_keys_bmap[R92S_CAM_ENTRY_BYTES];
union {
struct rsu_rx_radiotap_header th;
uint8_t pad[64];