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];
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to