svn commit: r309586 - head/sys/dev/usb/wlan
Andriy Voskoboinyk
avos at FreeBSD.org
Tue Dec 6 00:13:50 UTC 2016
Author: avos
Date: Tue Dec 6 00:13:49 2016
New Revision: 309586
URL: https://svnweb.freebsd.org/changeset/base/309586
Log:
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
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 Tue Dec 6 00:12:09 2016 (r309585)
+++ head/sys/dev/usb/wlan/if_rsu.c Tue Dec 6 00:13:49 2016 (r309586)
@@ -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", &rs
#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 *
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,
/* 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, e
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, e
}
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, e
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 @@ rsu_rx_copy_to_mbuf(struct rsu_softc *sc
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, struc
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, struc
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, struc
/* 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, struc
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, struc
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, struc
}
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]);
Modified: head/sys/dev/usb/wlan/if_rsureg.h
==============================================================================
--- head/sys/dev/usb/wlan/if_rsureg.h Tue Dec 6 00:12:09 2016 (r309585)
+++ head/sys/dev/usb/wlan/if_rsureg.h Tue Dec 6 00:13:49 2016 (r309586)
@@ -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];
More information about the svn-src-all
mailing list