Index: head/sys/dev/usb/wlan/if_rsu.c =================================================================== --- head/sys/dev/usb/wlan/if_rsu.c +++ head/sys/dev/usb/wlan/if_rsu.c @@ -22,8 +22,8 @@ * 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 @@ #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 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 @@ 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 @@ 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 @@ 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 @@ /* 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_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 @@ } 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 @@ 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) { - struct r92s_fw_cmd_set_key key; - memset(&key, 0, sizeof(key)); - /* Map net80211 cipher to HW crypto algorithm. */ - switch (k->wk_cipher->ic_cipher) { + 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: - if (k->wk_keylen < 8) - key.algo = R92S_KEY_ALGO_WEP40; - else - key.algo = R92S_KEY_ALGO_WEP104; - break; + return keylen < 8 ? R92S_KEY_ALGO_WEP40 : R92S_KEY_ALGO_WEP104; case IEEE80211_CIPHER_TKIP: - key.algo = R92S_KEY_ALGO_TKIP; - break; + return R92S_KEY_ALGO_TKIP; case IEEE80211_CIPHER_AES_CCM: - key.algo = R92S_KEY_ALGO_AES; - break; + return R92S_KEY_ALGO_AES; default: - return; + device_printf(sc->sc_dev, "unknown cipher %d\n", cipher); + return R92S_KEY_ALGO_INVALID; } - key.id = k->wk_keyix; +} + +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)); + 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 void -rsu_delete_key(struct rsu_softc *sc, const struct ieee80211_key *k) +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.id = k->wk_keyix; - (void)rsu_fw_cmd(sc, R92S_CMD_SET_KEY, &key, 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_pair_cb(void *arg, int pending __unused) +{ + struct rsu_softc *sc = arg; + int i; + + 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ } 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 @@ /* 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 @@ /* 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]); Index: head/sys/dev/usb/wlan/if_rsureg.h =================================================================== --- head/sys/dev/usb/wlan/if_rsureg.h +++ head/sys/dev/usb/wlan/if_rsureg.h @@ -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 @@ #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 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 @@ #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 @@ #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 @@ #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 @@ 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];