From owner-svn-src-all@freebsd.org Sun Dec 13 22:00:21 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 78641A43580; Sun, 13 Dec 2015 22:00:21 +0000 (UTC) (envelope-from avos@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 3797E1139; Sun, 13 Dec 2015 22:00:21 +0000 (UTC) (envelope-from avos@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tBDM0K89098745; Sun, 13 Dec 2015 22:00:20 GMT (envelope-from avos@FreeBSD.org) Received: (from avos@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tBDM0KZ2098742; Sun, 13 Dec 2015 22:00:20 GMT (envelope-from avos@FreeBSD.org) Message-Id: <201512132200.tBDM0KZ2098742@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: avos set sender to avos@FreeBSD.org using -f From: Andriy Voskoboinyk Date: Sun, 13 Dec 2015 22:00:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r292175 - head/sys/dev/usb/wlan X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 13 Dec 2015 22:00:21 -0000 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;