Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 3 Oct 2015 20:49:08 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r288633 - head/sys/dev/usb/wlan
Message-ID:  <201510032049.t93Kn8cB006360@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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:	<s3erios@gmail.com>
  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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201510032049.t93Kn8cB006360>