From owner-svn-src-all@freebsd.org Sat Oct 3 20:49:09 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 77887A0E46E; Sat, 3 Oct 2015 20:49:09 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::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 68B571BD1; Sat, 3 Oct 2015 20:49:09 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t93Kn9PT006363; Sat, 3 Oct 2015 20:49:09 GMT (envelope-from adrian@FreeBSD.org) Received: (from adrian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t93Kn8cB006360; Sat, 3 Oct 2015 20:49:08 GMT (envelope-from adrian@FreeBSD.org) Message-Id: <201510032049.t93Kn8cB006360@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: adrian set sender to adrian@FreeBSD.org using -f From: Adrian Chadd Date: Sat, 3 Oct 2015 20:49:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r288633 - 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: Sat, 03 Oct 2015 20:49:09 -0000 Author: adrian Date: Sat Oct 3 20:49:08 2015 New Revision: 288633 URL: https://svnweb.freebsd.org/changeset/base/288633 Log: rum(4): add support for hardware encryption (WEP, TKIP and CCMP). This diff includes: * Transmitter Addresses, Keys and TKIP MIC addition to the Security Key Table. * Proper SEC Control Registers initialization and maintenance. * Additional flags and values in TX descriptor, which are required for encryption support. * Error checking in RX path. Tested: * Tested on WUSB54GC, STA (WEP, TKIP, CCMP), HOSTAP (CCMP) and IBSS (CCMP, WPA-None) modes. * rum0: MAC/BBP RT2573 (rev 0x2573a), RF RT2528, STA mode (CCMP+TKIP) Submitted by: Differential Revision: https://reviews.freebsd.org/D3640 Modified: head/sys/dev/usb/wlan/if_rum.c head/sys/dev/usb/wlan/if_rumreg.h head/sys/dev/usb/wlan/if_rumvar.h Modified: head/sys/dev/usb/wlan/if_rum.c ============================================================================== --- head/sys/dev/usb/wlan/if_rum.c Sat Oct 3 20:45:43 2015 (r288632) +++ head/sys/dev/usb/wlan/if_rum.c Sat Oct 3 20:49:08 2015 (r288633) @@ -166,9 +166,13 @@ static void rum_setup_tx_list(struct ru static void rum_unsetup_tx_list(struct rum_softc *); static int rum_newstate(struct ieee80211vap *, enum ieee80211_state, int); +static uint8_t rum_crypto_mode(struct rum_softc *, u_int, int); static void rum_setup_tx_desc(struct rum_softc *, - struct rum_tx_desc *, uint32_t, uint16_t, int, - int); + struct rum_tx_desc *, struct ieee80211_key *, + uint32_t, uint8_t, int, int, int); +static uint32_t rum_tx_crypto_flags(struct rum_softc *, + struct ieee80211_node *, + const struct ieee80211_key *); static int rum_tx_mgt(struct rum_softc *, struct mbuf *, struct ieee80211_node *); static int rum_tx_raw(struct rum_softc *, struct mbuf *, @@ -219,6 +223,7 @@ static const char *rum_get_rf(int); static void rum_read_eeprom(struct rum_softc *); static int rum_bbp_wakeup(struct rum_softc *); static int rum_bbp_init(struct rum_softc *); +static void rum_clr_shkey_regs(struct rum_softc *); static int rum_init(struct rum_softc *); static void rum_stop(struct rum_softc *); static void rum_load_microcode(struct rum_softc *, const uint8_t *, @@ -230,6 +235,24 @@ static int rum_alloc_beacon(struct rum_ static void rum_update_beacon_cb(struct rum_softc *, union sec_param *, uint8_t, uint8_t); static void rum_update_beacon(struct ieee80211vap *, int); +static int rum_common_key_set(struct rum_softc *, + struct ieee80211_key *, uint16_t); +static void rum_group_key_set_cb(struct rum_softc *, + union sec_param *, uint8_t, uint8_t); +static void rum_group_key_del_cb(struct rum_softc *, + union sec_param *, uint8_t, uint8_t); +static void rum_pair_key_set_cb(struct rum_softc *, + union sec_param *, uint8_t, uint8_t); +static void rum_pair_key_del_cb(struct rum_softc *, + union sec_param *, uint8_t, uint8_t); +static int rum_key_alloc(struct ieee80211vap *, + struct ieee80211_key *, ieee80211_keyix *, + ieee80211_keyix *); +static int rum_key_set(struct ieee80211vap *, + const struct ieee80211_key *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static int rum_key_delete(struct ieee80211vap *, + const struct ieee80211_key *); static int rum_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); static void rum_scan_start(struct ieee80211com *); @@ -258,9 +281,9 @@ static const struct { { RT2573_MAC_CSR10, 0x00000718 }, { RT2573_MAC_CSR12, 0x00000004 }, { RT2573_MAC_CSR13, 0x00007f00 }, - { RT2573_SEC_CSR0, 0x00000000 }, - { RT2573_SEC_CSR1, 0x00000000 }, - { RT2573_SEC_CSR5, 0x00000000 }, + { RT2573_SEC_CSR2, 0x00000000 }, + { RT2573_SEC_CSR3, 0x00000000 }, + { RT2573_SEC_CSR4, 0x00000000 }, { RT2573_PHY_CSR1, 0x000023b0 }, { RT2573_PHY_CSR5, 0x00040a06 }, { RT2573_PHY_CSR6, 0x00080606 }, @@ -504,6 +527,12 @@ rum_attach(device_t self) | IEEE80211_C_WPA /* 802.11i */ ; + ic->ic_cryptocaps = + IEEE80211_CRYPTO_WEP | + IEEE80211_CRYPTO_AES_CCM | + IEEE80211_CRYPTO_TKIPMIC | + IEEE80211_CRYPTO_TKIP; + bands = 0; setbit(&bands, IEEE80211_MODE_11B); setbit(&bands, IEEE80211_MODE_11G); @@ -620,7 +649,11 @@ rum_vap_create(struct ieee80211com *ic, /* override state transition machine */ rvp->newstate = vap->iv_newstate; vap->iv_newstate = rum_newstate; + vap->iv_key_alloc = rum_key_alloc; + vap->iv_key_set = rum_key_set; + vap->iv_key_delete = rum_key_delete; vap->iv_update_beacon = rum_update_beacon; + vap->iv_max_aid = RT2573_ADDR_MAX; usb_callout_init_mtx(&rvp->ratectl_ch, &sc->sc_mtx, 0); TASK_INIT(&rvp->ratectl_task, 0, rum_ratectl_task, rvp); @@ -971,6 +1004,21 @@ rum_bulk_read_callback(struct usb_xfer * counter_u64_add(ic->ic_ierrors, 1); goto tr_setup; } + if ((flags & RT2573_RX_DEC_MASK) != RT2573_RX_DEC_OK) { + switch (flags & RT2573_RX_DEC_MASK) { + case RT2573_RX_IV_ERROR: + DPRINTFN(5, "IV/EIV error\n"); + break; + case RT2573_RX_MIC_ERROR: + DPRINTFN(5, "MIC error\n"); + break; + case RT2573_RX_KEY_ERROR: + DPRINTFN(5, "Key error\n"); + break; + } + counter_u64_add(ic->ic_ierrors, 1); + goto tr_setup; + } m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) { @@ -983,6 +1031,13 @@ rum_bulk_read_callback(struct usb_xfer * wh = mtod(m, struct ieee80211_frame_min *); + if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && + (flags & RT2573_RX_CIP_MASK) != + RT2573_RX_CIP_MODE(RT2573_MODE_NOSEC)) { + wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; + m->m_flags |= M_WEP; + } + /* finalize mbuf */ m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff; @@ -1061,22 +1116,45 @@ rum_plcp_signal(int rate) return 0xff; /* XXX unsupported/unknown rate */ } +/* + * Map net80211 cipher to RT2573 security mode. + */ +static uint8_t +rum_crypto_mode(struct rum_softc *sc, u_int cipher, int keylen) +{ + switch (cipher) { + case IEEE80211_CIPHER_WEP: + return (keylen < 8 ? RT2573_MODE_WEP40 : RT2573_MODE_WEP104); + case IEEE80211_CIPHER_TKIP: + return RT2573_MODE_TKIP; + case IEEE80211_CIPHER_AES_CCM: + return RT2573_MODE_AES_CCMP; + default: + device_printf(sc->sc_dev, "unknown cipher %d\n", cipher); + return 0; + } +} + static void rum_setup_tx_desc(struct rum_softc *sc, struct rum_tx_desc *desc, - uint32_t flags, uint16_t xflags, int len, int rate) + struct ieee80211_key *k, uint32_t flags, uint8_t xflags, int hdrlen, + int len, int rate) { struct ieee80211com *ic = &sc->sc_ic; uint16_t plcp_length; int remainder; - desc->flags = htole32(flags); - desc->flags |= htole32(RT2573_TX_VALID); - desc->flags |= htole32(len << 16); + flags |= RT2573_TX_VALID; + flags |= len << 16; - desc->xflags = htole16(xflags); + if (k != NULL && !(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { + const struct ieee80211_cipher *cip = k->wk_cipher; - desc->wme = htole16(RT2573_QID(0) | RT2573_AIFSN(2) | - RT2573_LOGCWMIN(4) | RT2573_LOGCWMAX(10)); + len += cip->ic_header + cip->ic_trailer + cip->ic_miclen; + + desc->eiv = 0; /* for WEP */ + cip->ic_setiv(k, (uint8_t *)&desc->iv); + } /* setup PLCP fields */ desc->plcp_signal = rum_plcp_signal(rate); @@ -1084,7 +1162,7 @@ rum_setup_tx_desc(struct rum_softc *sc, len += IEEE80211_CRC_LEN; if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_OFDM) { - desc->flags |= htole32(RT2573_TX_OFDM); + flags |= RT2573_TX_OFDM; plcp_length = len & 0xfff; desc->plcp_length_hi = plcp_length >> 6; @@ -1104,6 +1182,13 @@ rum_setup_tx_desc(struct rum_softc *sc, if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) desc->plcp_signal |= 0x08; } + + desc->flags = htole32(flags); + desc->hdrlen = hdrlen; + desc->xflags = xflags; + + desc->wme = htole16(RT2573_QID(0) | RT2573_AIFSN(2) | + RT2573_LOGCWMIN(4) | RT2573_LOGCWMAX(10)); } static int @@ -1149,7 +1234,8 @@ rum_sendprot(struct rum_softc *sc, data->m = mprot; data->ni = ieee80211_ref_node(ni); data->rate = protrate; - rum_setup_tx_desc(sc, &data->desc, flags, 0, mprot->m_pkthdr.len, protrate); + rum_setup_tx_desc(sc, &data->desc, NULL, flags, 0, 0, + mprot->m_pkthdr.len, protrate); STAILQ_INSERT_TAIL(&sc->tx_q, data, next); usbd_transfer_start(sc->sc_xfer[RUM_BULK_WR]); @@ -1157,6 +1243,40 @@ rum_sendprot(struct rum_softc *sc, return 0; } +static uint32_t +rum_tx_crypto_flags(struct rum_softc *sc, struct ieee80211_node *ni, + const struct ieee80211_key *k) +{ + struct ieee80211vap *vap = ni->ni_vap; + u_int cipher; + uint32_t flags = 0; + uint8_t mode, pos; + + if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { + cipher = k->wk_cipher->ic_cipher; + pos = k->wk_keyix; + mode = rum_crypto_mode(sc, cipher, k->wk_keylen); + if (mode == 0) + return 0; + + flags |= RT2573_TX_CIP_MODE(mode); + + /* Do not trust GROUP flag */ + if (!(k >= &vap->iv_nw_keys[0] && + k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) + flags |= RT2573_TX_KEY_PAIR; + else + pos += 0 * RT2573_SKEY_MAX; /* vap id */ + + flags |= RT2573_TX_KEY_ID(pos); + + if (cipher == IEEE80211_CIPHER_TKIP) + flags |= RT2573_TX_TKIPMIC; + } + + return flags; +} + static int rum_tx_mgt(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni) { @@ -1165,9 +1285,10 @@ rum_tx_mgt(struct rum_softc *sc, struct struct rum_tx_data *data; struct ieee80211_frame *wh; const struct ieee80211_txparam *tp; - struct ieee80211_key *k; + struct ieee80211_key *k = NULL; uint32_t flags = 0; uint16_t dur; + int hdrlen; RUM_LOCK_ASSERT(sc); @@ -1176,9 +1297,15 @@ rum_tx_mgt(struct rum_softc *sc, struct sc->tx_nfree--; wh = mtod(m0, struct ieee80211_frame *); + hdrlen = ieee80211_anyhdrsize(wh); + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { - k = ieee80211_crypto_encap(ni, m0); + k = ieee80211_crypto_get_txkey(ni, m0); if (k == NULL) + return (ENOENT); + + if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) && + !k->wk_cipher->ic_encap(k, m0)) return (ENOBUFS); wh = mtod(m0, struct ieee80211_frame *); @@ -1200,11 +1327,15 @@ rum_tx_mgt(struct rum_softc *sc, struct flags |= RT2573_TX_TIMESTAMP; } + if (k != NULL) + flags |= rum_tx_crypto_flags(sc, ni, k); + data->m = m0; data->ni = ni; data->rate = tp->mgmtrate; - rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, tp->mgmtrate); + rum_setup_tx_desc(sc, &data->desc, k, flags, 0, hdrlen, + m0->m_pkthdr.len, tp->mgmtrate); DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, tp->mgmtrate); @@ -1253,7 +1384,8 @@ rum_tx_raw(struct rum_softc *sc, struct data->rate = rate; /* XXX need to setup descriptor ourself */ - rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, rate); + rum_setup_tx_desc(sc, &data->desc, NULL, flags, 0, 0, m0->m_pkthdr.len, + rate); DPRINTFN(10, "sending raw frame len=%u rate=%u\n", m0->m_pkthdr.len, rate); @@ -1272,14 +1404,15 @@ rum_tx_data(struct rum_softc *sc, struct struct rum_tx_data *data; struct ieee80211_frame *wh; const struct ieee80211_txparam *tp; - struct ieee80211_key *k; + struct ieee80211_key *k = NULL; uint32_t flags = 0; uint16_t dur; - int error, rate; + int error, hdrlen, rate; RUM_LOCK_ASSERT(sc); wh = mtod(m0, struct ieee80211_frame *); + hdrlen = ieee80211_anyhdrsize(wh); tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; if (IEEE80211_IS_MULTICAST(wh->i_addr1)) @@ -1290,10 +1423,15 @@ rum_tx_data(struct rum_softc *sc, struct rate = ni->ni_txrate; if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { - k = ieee80211_crypto_encap(ni, m0); + k = ieee80211_crypto_get_txkey(ni, m0); if (k == NULL) { m_freem(m0); - return ENOBUFS; + return (ENOENT); + } + if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) && + !k->wk_cipher->ic_encap(k, m0)) { + m_freem(m0); + return (ENOBUFS); } /* packet header may have moved, reset our local pointer */ @@ -1317,6 +1455,9 @@ rum_tx_data(struct rum_softc *sc, struct } } + if (k != NULL) + flags |= rum_tx_crypto_flags(sc, ni, k); + data = STAILQ_FIRST(&sc->tx_free); STAILQ_REMOVE_HEAD(&sc->tx_free, next); sc->tx_nfree--; @@ -1334,7 +1475,8 @@ rum_tx_data(struct rum_softc *sc, struct USETW(wh->i_dur, dur); } - rum_setup_tx_desc(sc, &data->desc, flags, 0, m0->m_pkthdr.len, rate); + rum_setup_tx_desc(sc, &data->desc, k, flags, 0, hdrlen, + m0->m_pkthdr.len, rate); DPRINTFN(10, "sending frame len=%d rate=%d\n", m0->m_pkthdr.len + (int)RT2573_TX_DESC_SIZE, rate); @@ -2087,6 +2229,14 @@ rum_bbp_init(struct rum_softc *sc) return 0; } +static void +rum_clr_shkey_regs(struct rum_softc *sc) +{ + rum_write(sc, RT2573_SEC_CSR0, 0); + rum_write(sc, RT2573_SEC_CSR1, 0); + rum_write(sc, RT2573_SEC_CSR5, 0); +} + static int rum_init(struct rum_softc *sc) { @@ -2124,6 +2274,12 @@ rum_init(struct rum_softc *sc) /* clear STA registers */ rum_read_multi(sc, RT2573_STA_CSR0, sc->sta, sizeof sc->sta); + /* clear security registers (if required) */ + if (sc->sc_clr_shkeys == 0) { + rum_clr_shkey_regs(sc); + sc->sc_clr_shkeys = 1; + } + rum_set_macaddr(sc, vap ? vap->iv_myaddr : ic->ic_macaddr); /* initialize ASIC */ @@ -2241,8 +2397,8 @@ rum_set_beacon(struct rum_softc *sc, str return EINVAL; tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_bsschan)]; - rum_setup_tx_desc(sc, &desc, RT2573_TX_TIMESTAMP, RT2573_TX_HWSEQ, - m->m_pkthdr.len, tp->mgmtrate); + rum_setup_tx_desc(sc, &desc, NULL, RT2573_TX_TIMESTAMP, + RT2573_TX_HWSEQ, 0, m->m_pkthdr.len, tp->mgmtrate); /* copy the Tx descriptor into NIC memory */ if (rum_write_multi(sc, RT2573_HW_BCN_BASE(0), (uint8_t *)&desc, @@ -2330,6 +2486,216 @@ rum_update_beacon(struct ieee80211vap *v } static int +rum_common_key_set(struct rum_softc *sc, struct ieee80211_key *k, + uint16_t base) +{ + + if (rum_write_multi(sc, base, k->wk_key, k->wk_keylen)) + return EIO; + + if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { + if (rum_write_multi(sc, base + IEEE80211_KEYBUF_SIZE, + k->wk_txmic, 8)) + return EIO; + if (rum_write_multi(sc, base + IEEE80211_KEYBUF_SIZE + 8, + k->wk_rxmic, 8)) + return EIO; + } + + return 0; +} + +static void +rum_group_key_set_cb(struct rum_softc *sc, union sec_param *data, + uint8_t rn_id, uint8_t rvp_id) +{ + struct ieee80211_key *k = &data->key; + uint8_t mode; + + if (sc->sc_clr_shkeys == 0) { + rum_clr_shkey_regs(sc); + sc->sc_clr_shkeys = 1; + } + + mode = rum_crypto_mode(sc, k->wk_cipher->ic_cipher, k->wk_keylen); + if (mode == 0) + goto print_err; + + DPRINTFN(1, "setting group key %d for vap %d, mode %d " + "(tx %s, rx %s)\n", k->wk_keyix, rvp_id, mode, + (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", + (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); + + /* Install the key. */ + if (rum_common_key_set(sc, k, RT2573_SKEY(rvp_id, k->wk_keyix)) != 0) + goto print_err; + + /* Set cipher mode. */ + if (rum_modbits(sc, rvp_id < 2 ? RT2573_SEC_CSR1 : RT2573_SEC_CSR5, + mode << (rvp_id % 2 + k->wk_keyix) * RT2573_SKEY_MAX, + RT2573_MODE_MASK << (rvp_id % 2 + k->wk_keyix) * RT2573_SKEY_MAX) + != 0) + goto print_err; + + /* Mark this key as valid. */ + if (rum_setbits(sc, RT2573_SEC_CSR0, + 1 << (rvp_id * RT2573_SKEY_MAX + k->wk_keyix)) != 0) + goto print_err; + + return; + +print_err: + device_printf(sc->sc_dev, "%s: cannot set group key %d for vap %d\n", + __func__, k->wk_keyix, rvp_id); +} + +static void +rum_group_key_del_cb(struct rum_softc *sc, union sec_param *data, + uint8_t rn_id, uint8_t rvp_id) +{ + struct ieee80211_key *k = &data->key; + + DPRINTF("%s: removing group key %d for vap %d\n", __func__, + k->wk_keyix, rvp_id); + rum_clrbits(sc, + rvp_id < 2 ? RT2573_SEC_CSR1 : RT2573_SEC_CSR5, + RT2573_MODE_MASK << (rvp_id % 2 + k->wk_keyix) * RT2573_SKEY_MAX); + rum_clrbits(sc, RT2573_SEC_CSR0, + rvp_id * RT2573_SKEY_MAX + k->wk_keyix); +} + +static void +rum_pair_key_set_cb(struct rum_softc *sc, union sec_param *data, uint8_t rn_id, + uint8_t rvp_id) +{ + struct ieee80211_key *k = &data->key; + uint8_t buf[IEEE80211_ADDR_LEN + 1]; + uint8_t mode; + + mode = rum_crypto_mode(sc, k->wk_cipher->ic_cipher, k->wk_keylen); + if (mode == 0) + goto print_err; + + DPRINTFN(1, "setting pairwise key %d for vap %d, mode %d " + "(tx %s, rx %s)\n", k->wk_keyix, rvp_id, mode, + (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", + (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); + + /* Install the key. */ + if (rum_common_key_set(sc, k, RT2573_PKEY(k->wk_keyix)) != 0) + goto print_err; + + IEEE80211_ADDR_COPY(buf, k->wk_macaddr); + buf[IEEE80211_ADDR_LEN] = mode; + + /* Set transmitter address and cipher mode. */ + if (rum_write_multi(sc, RT2573_ADDR_ENTRY(k->wk_keyix), + buf, sizeof buf) != 0) + goto print_err; + + /* Enable key table lookup for this vap. */ + if (sc->vap_key_count[rvp_id]++ == 0) + if (rum_setbits(sc, RT2573_SEC_CSR4, 1 << rvp_id) != 0) + goto print_err; + + /* Mark this key as valid. */ + if (rum_setbits(sc, + k->wk_keyix < 32 ? RT2573_SEC_CSR2 : RT2573_SEC_CSR3, + 1 << (k->wk_keyix % 32)) != 0) + goto print_err; + + return; + +print_err: + device_printf(sc->sc_dev, + "%s: cannot set pairwise key %d, vap %d\n", __func__, k->wk_keyix, + rvp_id); +} + +static void +rum_pair_key_del_cb(struct rum_softc *sc, union sec_param *data, uint8_t rn_id, + uint8_t rvp_id) +{ + struct ieee80211_key *k = &data->key; + + DPRINTF("%s: removing key %d\n", __func__, k->wk_keyix); + rum_clrbits(sc, (k->wk_keyix < 32) ? RT2573_SEC_CSR2 : RT2573_SEC_CSR3, + 1 << (k->wk_keyix % 32)); + sc->keys_bmap &= ~(1 << k->wk_keyix); + if (--sc->vap_key_count[rvp_id] == 0) + rum_clrbits(sc, RT2573_SEC_CSR4, 1 << rvp_id); +} + +static int +rum_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, + ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) +{ + struct rum_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)) { + RUM_LOCK(sc); + for (i = 0; i < RT2573_ADDR_MAX; i++) { + if ((sc->keys_bmap & (1 << i)) == 0) { + sc->keys_bmap |= 1 << i; + *keyix = i; + break; + } + } + RUM_UNLOCK(sc); + if (i == RT2573_ADDR_MAX) { + 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 int +rum_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, + const uint8_t mac[IEEE80211_ADDR_LEN]) +{ + struct rum_softc *sc = vap->iv_ic->ic_softc; + int group; + + if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { + /* Not for us. */ + return 1; + } + + group = k >= &vap->iv_nw_keys[0] && k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]; + + return !rum_cmd_sleepable(sc, k, sizeof(*k), 0, 0, + group ? rum_group_key_set_cb : rum_pair_key_set_cb); +} + +static int +rum_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + struct rum_softc *sc = vap->iv_ic->ic_softc; + int group; + + if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { + /* Not for us. */ + return 1; + } + + group = k >= &vap->iv_nw_keys[0] && k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]; + + return !rum_cmd_sleepable(sc, k, sizeof(*k), 0, 0, + group ? rum_group_key_del_cb : rum_pair_key_del_cb); +} + +static int rum_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, const struct ieee80211_bpf_params *params) { Modified: head/sys/dev/usb/wlan/if_rumreg.h ============================================================================== --- head/sys/dev/usb/wlan/if_rumreg.h Sat Oct 3 20:45:43 2015 (r288632) +++ head/sys/dev/usb/wlan/if_rumreg.h Sat Oct 3 20:49:08 2015 (r288633) @@ -34,13 +34,34 @@ #define RT2573_WRITE_LED 0x0a /* - * Control and status registers. + * WME registers. */ #define RT2573_AIFSN_CSR 0x0400 #define RT2573_CWMIN_CSR 0x0404 #define RT2573_CWMAX_CSR 0x0408 #define RT2573_MCU_CODE_BASE 0x0800 + +/* + * H/w encryption/decryption support + */ +#define KEY_SIZE (IEEE80211_KEYBUF_SIZE + IEEE80211_MICBUF_SIZE) +#define RT2573_ADDR_MAX 64 +#define RT2573_SKEY_MAX 4 + +#define RT2573_SKEY(vap, kidx) (0x1000 + ((vap) * RT2573_SKEY_MAX + \ + (kidx)) * KEY_SIZE) +#define RT2573_PKEY(id) (0x1200 + (id) * KEY_SIZE) + +#define RT2573_ADDR_ENTRY(id) (0x1a00 + (id) * 8) + +/* + * Shared memory area + */ #define RT2573_HW_BCN_BASE(id) (0x2400 + (id) * 0x100) + +/* + * Control and status registers. + */ #define RT2573_MAC_CSR0 0x3000 #define RT2573_MAC_CSR1 0x3004 #define RT2573_MAC_CSR2 0x3008 @@ -95,6 +116,16 @@ #define RT2573_STA_CSR5 0x30d4 +/* possible values for register RT2573_ADDR_MODE */ +#define RT2573_MODE_MASK 0x7 +#define RT2573_MODE_NOSEC 0 +#define RT2573_MODE_WEP40 1 +#define RT2573_MODE_WEP104 2 +#define RT2573_MODE_TKIP 3 +#define RT2573_MODE_AES_CCMP 4 +#define RT2573_MODE_CKIP40 5 +#define RT2573_MODE_CKIP104 6 + /* possible flags for register RT2573_MAC_CSR1 */ #define RT2573_RESET_ASIC (1 << 0) #define RT2573_RESET_BBP (1 << 1) @@ -178,6 +209,10 @@ struct rum_tx_desc { #define RT2573_TX_OFDM (1 << 5) #define RT2573_TX_IFS_SIFS (1 << 6) #define RT2573_TX_LONG_RETRY (1 << 7) +#define RT2573_TX_TKIPMIC (1 << 8) +#define RT2573_TX_KEY_PAIR (1 << 9) +#define RT2573_TX_KEY_ID(id) (((id) & 0x3f) << 10) +#define RT2573_TX_CIP_MODE(m) ((m) << 29) uint16_t wme; #define RT2573_QID(v) (v) @@ -185,8 +220,9 @@ struct rum_tx_desc { #define RT2573_LOGCWMIN(v) ((v) << 8) #define RT2573_LOGCWMAX(v) ((v) << 12) - uint16_t xflags; -#define RT2573_TX_HWSEQ (1 << 12) + uint8_t hdrlen; + uint8_t xflags; +#define RT2573_TX_HWSEQ (1 << 4) uint8_t plcp_signal; uint8_t plcp_service; @@ -210,9 +246,25 @@ struct rum_rx_desc { uint32_t flags; #define RT2573_RX_BUSY (1 << 0) #define RT2573_RX_DROP (1 << 1) +#define RT2573_RX_UC2ME (1 << 2) +#define RT2573_RX_MC (1 << 3) +#define RT2573_RX_BC (1 << 4) +#define RT2573_RX_MYBSS (1 << 5) #define RT2573_RX_CRC_ERROR (1 << 6) #define RT2573_RX_OFDM (1 << 7) +#define RT2573_RX_DEC_MASK (3 << 8) +#define RT2573_RX_DEC_OK (0 << 8) + +#define RT2573_RX_IV_ERROR (1 << 8) +#define RT2573_RX_MIC_ERROR (2 << 8) +#define RT2573_RX_KEY_ERROR (3 << 8) + +#define RT2573_RX_KEY_PAIR (1 << 28) + +#define RT2573_RX_CIP_MASK (7 << 29) +#define RT2573_RX_CIP_MODE(m) ((m) << 29) + uint8_t rate; uint8_t rssi; uint8_t reserved1; Modified: head/sys/dev/usb/wlan/if_rumvar.h ============================================================================== --- head/sys/dev/usb/wlan/if_rumvar.h Sat Oct 3 20:45:43 2015 (r288632) +++ head/sys/dev/usb/wlan/if_rumvar.h Sat Oct 3 20:49:08 2015 (r288633) @@ -136,10 +136,14 @@ struct rum_softc { uint32_t rf_regs[4]; uint8_t txpow[44]; u_int sc_detached:1, - sc_running:1; + sc_running:1, + sc_clr_shkeys:1; uint8_t sc_bssid[IEEE80211_ADDR_LEN]; + uint8_t vap_key_count[1]; + uint64_t keys_bmap; + struct { uint8_t val; uint8_t reg;