svn commit: r292175 - head/sys/dev/usb/wlan
Andriy Voskoboinyk
avos at FreeBSD.org
Sun Dec 13 22:00:21 UTC 2015
Author: avos
Date: Sun Dec 13 22:00:19 2015
New Revision: 292175
URL: https://svnweb.freebsd.org/changeset/base/292175
Log:
urtwn: add support for hardware encryption (WEP, TKIP and CCMP)
Tested with:
- RTL8188EU;
- RTL8188CUS;
Modes:
- IBSS mode: TKIP, CCMP (WPA-None);
- STA / HOSTAP modes - WEP (static), TKIP, CCMP;
Reviewed by: kevlo
Approved by: adrian (mentor)
Obtained from: OpenBSD (mostly)
Differential Revision: https://reviews.freebsd.org/D4448
Modified:
head/sys/dev/usb/wlan/if_urtwn.c
head/sys/dev/usb/wlan/if_urtwnreg.h
head/sys/dev/usb/wlan/if_urtwnvar.h
Modified: head/sys/dev/usb/wlan/if_urtwn.c
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwn.c Sun Dec 13 21:50:38 2015 (r292174)
+++ head/sys/dev/usb/wlan/if_urtwn.c Sun Dec 13 22:00:19 2015 (r292175)
@@ -244,6 +244,17 @@ static int urtwn_setup_beacon(struct ur
static void urtwn_update_beacon(struct ieee80211vap *, int);
static int urtwn_tx_beacon(struct urtwn_softc *sc,
struct urtwn_vap *);
+static int urtwn_key_alloc(struct ieee80211vap *,
+ struct ieee80211_key *, ieee80211_keyix *,
+ ieee80211_keyix *);
+static void urtwn_key_set_cb(struct urtwn_softc *,
+ union sec_param *);
+static void urtwn_key_del_cb(struct urtwn_softc *,
+ union sec_param *);
+static int urtwn_key_set(struct ieee80211vap *,
+ const struct ieee80211_key *);
+static int urtwn_key_delete(struct ieee80211vap *,
+ const struct ieee80211_key *);
static void urtwn_tsf_task_adhoc(void *, int);
static void urtwn_tsf_sync_enable(struct urtwn_softc *,
struct ieee80211vap *);
@@ -279,6 +290,8 @@ static int urtwn_mac_init(struct urtwn_
static void urtwn_bb_init(struct urtwn_softc *);
static void urtwn_rf_init(struct urtwn_softc *);
static void urtwn_cam_init(struct urtwn_softc *);
+static int urtwn_cam_write(struct urtwn_softc *, uint32_t,
+ uint32_t);
static void urtwn_pa_bias_init(struct urtwn_softc *);
static void urtwn_rxfilter_init(struct urtwn_softc *);
static void urtwn_edca_init(struct urtwn_softc *);
@@ -500,6 +513,11 @@ urtwn_attach(device_t self)
| IEEE80211_C_WME /* 802.11e */
;
+ ic->ic_cryptocaps =
+ IEEE80211_CRYPTO_WEP |
+ IEEE80211_CRYPTO_TKIP |
+ IEEE80211_CRYPTO_AES_CCM;
+
bands = 0;
setbit(&bands, IEEE80211_MODE_11B);
setbit(&bands, IEEE80211_MODE_11G);
@@ -659,6 +677,9 @@ urtwn_vap_create(struct ieee80211com *ic
uvp->newstate = vap->iv_newstate;
vap->iv_newstate = urtwn_newstate;
vap->iv_update_beacon = urtwn_update_beacon;
+ vap->iv_key_alloc = urtwn_key_alloc;
+ vap->iv_key_set = urtwn_key_set;
+ vap->iv_key_delete = urtwn_key_delete;
if (opmode == IEEE80211_M_IBSS) {
uvp->recv_mgmt = vap->iv_recv_mgmt;
vap->iv_recv_mgmt = urtwn_ibss_recv_mgmt;
@@ -699,7 +720,7 @@ urtwn_rx_frame(struct urtwn_softc *sc, u
struct mbuf *m;
struct r92c_rx_stat *stat;
uint32_t rxdw0, rxdw3;
- uint8_t rate;
+ uint8_t rate, cipher;
int8_t rssi = 0;
int infosz;
@@ -729,6 +750,7 @@ urtwn_rx_frame(struct urtwn_softc *sc, u
}
rate = MS(rxdw3, R92C_RXDW3_RATE);
+ cipher = MS(rxdw0, R92C_RXDW0_CIPHER);
infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8;
/* Get RSSI from PHY status descriptor if present. */
@@ -748,9 +770,14 @@ urtwn_rx_frame(struct urtwn_softc *sc, u
}
/* Finalize mbuf. */
- wh = (struct ieee80211_frame *)((uint8_t *)&stat[1] + infosz);
- memcpy(mtod(m, uint8_t *), wh, pktlen);
- m->m_pkthdr.len = m->m_len = pktlen;
+ memcpy(mtod(m, uint8_t *), (uint8_t *)&stat[1] + infosz, pktlen);
+ m->m_pkthdr.len = m->m_len = pktlen;
+ wh = mtod(m, struct ieee80211_frame *);
+
+ if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
+ cipher != R92C_CAM_ALGO_NONE) {
+ m->m_flags |= M_WEP;
+ }
if (ieee80211_radiotap_active(ic)) {
struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap;
@@ -1862,6 +1889,153 @@ urtwn_tx_beacon(struct urtwn_softc *sc,
return (0);
}
+static int
+urtwn_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
+ ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
+{
+ struct urtwn_softc *sc = vap->iv_ic->ic_softc;
+ uint8_t i;
+
+ if (!(&vap->iv_nw_keys[0] <= k &&
+ k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
+ if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) {
+ URTWN_LOCK(sc);
+ /*
+ * First 4 slots for group keys,
+ * what is left - for pairwise.
+ * XXX incompatible with IBSS RSN.
+ */
+ for (i = IEEE80211_WEP_NKID;
+ i < R92C_CAM_ENTRY_COUNT; i++) {
+ if ((sc->keys_bmap & (1 << i)) == 0) {
+ sc->keys_bmap |= 1 << i;
+ *keyix = i;
+ break;
+ }
+ }
+ URTWN_UNLOCK(sc);
+ if (i == R92C_CAM_ENTRY_COUNT) {
+ device_printf(sc->sc_dev,
+ "%s: no free space in the key table\n",
+ __func__);
+ return 0;
+ }
+ } else
+ *keyix = 0;
+ } else {
+ *keyix = k - vap->iv_nw_keys;
+ }
+ *rxkeyix = *keyix;
+ return 1;
+}
+
+static void
+urtwn_key_set_cb(struct urtwn_softc *sc, union sec_param *data)
+{
+ struct ieee80211_key *k = &data->key;
+ uint8_t algo, keyid;
+ int i, error;
+
+ if (k->wk_keyix < IEEE80211_WEP_NKID)
+ keyid = k->wk_keyix;
+ else
+ keyid = 0;
+
+ /* Map net80211 cipher to HW crypto algorithm. */
+ switch (k->wk_cipher->ic_cipher) {
+ case IEEE80211_CIPHER_WEP:
+ if (k->wk_keylen < 8)
+ algo = R92C_CAM_ALGO_WEP40;
+ else
+ algo = R92C_CAM_ALGO_WEP104;
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ algo = R92C_CAM_ALGO_TKIP;
+ break;
+ case IEEE80211_CIPHER_AES_CCM:
+ algo = R92C_CAM_ALGO_AES;
+ break;
+ default:
+ device_printf(sc->sc_dev, "%s: undefined cipher %d\n",
+ __func__, k->wk_cipher->ic_cipher);
+ return;
+ }
+
+ DPRINTFN(9, "keyix %d, keyid %d, algo %d/%d, flags %04X, len %d, "
+ "macaddr %s\n", k->wk_keyix, keyid, k->wk_cipher->ic_cipher, algo,
+ k->wk_flags, k->wk_keylen, ether_sprintf(k->wk_macaddr));
+
+ /* Write key. */
+ for (i = 0; i < 4; i++) {
+ error = urtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i),
+ LE_READ_4(&k->wk_key[i * 4]));
+ if (error != 0)
+ goto fail;
+ }
+
+ /* Write CTL0 last since that will validate the CAM entry. */
+ error = urtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix),
+ LE_READ_4(&k->wk_macaddr[2]));
+ if (error != 0)
+ goto fail;
+ error = urtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix),
+ SM(R92C_CAM_ALGO, algo) |
+ SM(R92C_CAM_KEYID, keyid) |
+ SM(R92C_CAM_MACLO, LE_READ_2(&k->wk_macaddr[0])) |
+ R92C_CAM_VALID);
+ if (error != 0)
+ goto fail;
+
+ return;
+
+fail:
+ device_printf(sc->sc_dev, "%s fails, error %d\n", __func__, error);
+}
+
+static void
+urtwn_key_del_cb(struct urtwn_softc *sc, union sec_param *data)
+{
+ struct ieee80211_key *k = &data->key;
+ int i;
+
+ DPRINTFN(9, "keyix %d, flags %04X, macaddr %s\n",
+ k->wk_keyix, k->wk_flags, ether_sprintf(k->wk_macaddr));
+
+ urtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), 0);
+ urtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), 0);
+
+ /* Clear key. */
+ for (i = 0; i < 4; i++)
+ urtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), 0);
+ sc->keys_bmap &= ~(1 << k->wk_keyix);
+}
+
+static int
+urtwn_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k)
+{
+ struct urtwn_softc *sc = vap->iv_ic->ic_softc;
+
+ if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
+ /* Not for us. */
+ return (1);
+ }
+
+ return (!urtwn_cmd_sleepable(sc, k, sizeof(*k), urtwn_key_set_cb));
+}
+
+static int
+urtwn_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
+{
+ struct urtwn_softc *sc = vap->iv_ic->ic_softc;
+
+ if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
+ /* Not for us. */
+ return (1);
+ }
+
+ return (!urtwn_cmd_sleepable(sc, k, sizeof(*k), urtwn_key_del_cb));
+}
+
static void
urtwn_tsf_task_adhoc(void *arg, int pending)
{
@@ -2479,6 +2653,26 @@ urtwn_tx_data(struct urtwn_softc *sc, st
txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE);
}
+ if (k != NULL && !(k->wk_flags & IEEE80211_KEY_SWCRYPT)) {
+ uint8_t cipher;
+
+ switch (k->wk_cipher->ic_cipher) {
+ case IEEE80211_CIPHER_WEP:
+ case IEEE80211_CIPHER_TKIP:
+ cipher = R92C_TXDW1_CIPHER_RC4;
+ break;
+ case IEEE80211_CIPHER_AES_CCM:
+ cipher = R92C_TXDW1_CIPHER_AES;
+ break;
+ default:
+ device_printf(sc->sc_dev, "%s: unknown cipher %d\n",
+ __func__, k->wk_cipher->ic_cipher);
+ return (EINVAL);
+ }
+
+ txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher));
+ }
+
if (ieee80211_radiotap_active_vap(vap)) {
struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap;
@@ -3383,6 +3577,23 @@ urtwn_cam_init(struct urtwn_softc *sc)
R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR);
}
+static int
+urtwn_cam_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data)
+{
+ usb_error_t error;
+
+ error = urtwn_write_4(sc, R92C_CAMWRITE, data);
+ if (error != USB_ERR_NORMAL_COMPLETION)
+ return (EIO);
+ error = urtwn_write_4(sc, R92C_CAMCMD,
+ R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE |
+ SM(R92C_CAMCMD_ADDR, addr));
+ if (error != USB_ERR_NORMAL_COMPLETION)
+ return (EIO);
+
+ return (0);
+}
+
static void
urtwn_pa_bias_init(struct urtwn_softc *sc)
{
@@ -4271,6 +4482,18 @@ urtwn_init(struct urtwn_softc *sc)
/* Clear per-station keys table. */
urtwn_cam_init(sc);
+ /* Enable decryption / encryption. */
+ urtwn_write_2(sc, R92C_SECCFG,
+ R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF |
+ R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA |
+ R92C_SECCFG_TXBCKEY_DEF | R92C_SECCFG_RXBCKEY_DEF);
+
+ /*
+ * Install static keys (if any).
+ * Must be called after urtwn_cam_init().
+ */
+ ieee80211_runtask(ic, &sc->cmdq_task);
+
/* Enable hardware sequence numbering. */
urtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff);
Modified: head/sys/dev/usb/wlan/if_urtwnreg.h
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwnreg.h Sun Dec 13 21:50:38 2015 (r292174)
+++ head/sys/dev/usb/wlan/if_urtwnreg.h Sun Dec 13 22:00:19 2015 (r292175)
@@ -557,6 +557,16 @@
#define R92C_CAMCMD_CLR 0x40000000
#define R92C_CAMCMD_POLLING 0x80000000
+/* Bits for R92C_SECCFG. */
+#define R92C_SECCFG_TXUCKEY_DEF 0x0001
+#define R92C_SECCFG_RXUCKEY_DEF 0x0002
+#define R92C_SECCFG_TXENC_ENA 0x0004
+#define R92C_SECCFG_RXDEC_ENA 0x0008
+#define R92C_SECCFG_CMP_A2 0x0010
+#define R92C_SECCFG_TXBCKEY_DEF 0x0040
+#define R92C_SECCFG_RXBCKEY_DEF 0x0080
+#define R88E_SECCFG_CHK_KEYID 0x0100
+
/* Bits for R92C_RXFLTMAP*. */
#define R92C_RXFLTMAP_SUBTYPE(subtype) \
(1 << ((subtype) >> IEEE80211_FC0_SUBTYPE_SHIFT))
@@ -968,6 +978,8 @@ struct r92c_rx_stat {
#define R92C_RXDW0_ICVERR 0x00008000
#define R92C_RXDW0_INFOSZ_M 0x000f0000
#define R92C_RXDW0_INFOSZ_S 16
+#define R92C_RXDW0_CIPHER_M 0x00700000
+#define R92C_RXDW0_CIPHER_S 20
#define R92C_RXDW0_QOS 0x00800000
#define R92C_RXDW0_SHIFT_M 0x03000000
#define R92C_RXDW0_SHIFT_S 24
Modified: head/sys/dev/usb/wlan/if_urtwnvar.h
==============================================================================
--- head/sys/dev/usb/wlan/if_urtwnvar.h Sun Dec 13 21:50:38 2015 (r292174)
+++ head/sys/dev/usb/wlan/if_urtwnvar.h Sun Dec 13 22:00:19 2015 (r292175)
@@ -205,6 +205,7 @@ struct urtwn_softc {
struct callout sc_watchdog_ch;
struct mtx sc_mtx;
+ uint32_t keys_bmap;
struct urtwn_cmdq cmdq[URTWN_CMDQ_SIZE];
struct mtx cmdq_mtx;
More information about the svn-src-head
mailing list