Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 3 Aug 2008 21:41:34 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 146566 for review
Message-ID:  <200808032141.m73LfY1S000919@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=146566

Change 146566 by sam@sam_ebb on 2008/08/03 21:41:34

	Checkpoint h/w crypto support.  This was done to evaluate
	changes in net80211; it doesn't work correctly and is disabled
	by not marking the crypto capability bits.
	
	o fill in key allocator and related driver callbacks
	o fix longstanding bug by switching from clusters to 4k jumbo's
	  for rx dma buffer; also required so we can backload the payload
	  and prepend crypto header on rx (see below)
	o fixup stupid code that does leXtoh/htoleX everywhere instead of
	  doing it once
	o on rx glue the crypto header back into the 802.11 frame using
	  the information passed out of band in the h/w descriptor
	o on rx use ieee80211_find_rxnode_withkey to optimize lookups as
	  we now have key indices on rx for stations operating w/ crypto
	o on tx yank IV out of band to the tx descriptor and squeeze
	  the bits out of the frame to satisfy the hardware
	
	Derived from sephe's dfly code base.

Affected files ...

.. //depot/projects/vap/sys/dev/ral/rt2661.c#39 edit
.. //depot/projects/vap/sys/dev/ral/rt2661reg.h#3 edit
.. //depot/projects/vap/sys/dev/ral/rt2661var.h#14 edit

Differences ...

==== //depot/projects/vap/sys/dev/ral/rt2661.c#39 (text) ====

@@ -118,8 +118,9 @@
 static void		rt2661_scan_end(struct ieee80211com *);
 static void		rt2661_set_channel(struct ieee80211com *);
 static void		rt2661_setup_tx_desc(struct rt2661_softc *,
-			    struct rt2661_tx_desc *, uint32_t, uint16_t, int,
-			    int, const bus_dma_segment_t *, int, int);
+			    struct rt2661_tx_desc *, uint32_t, uint16_t,
+			    const struct ieee80211_key *, const uint8_t *,
+			    int, int, const bus_dma_segment_t *, int, int);
 static int		rt2661_tx_data(struct rt2661_softc *, struct mbuf *,
 			    struct ieee80211_node *, int);
 static int		rt2661_tx_mgt(struct rt2661_softc *, struct mbuf *,
@@ -171,6 +172,17 @@
 			    struct ieee80211vap *);
 static void		rt2661_enable_tsf_sync(struct rt2661_softc *);
 static int		rt2661_get_rssi(struct rt2661_softc *, uint8_t);
+static void		rt2661_reset_keymap(struct rt2661_softc *);
+static int		rt2661_key_alloc(struct ieee80211vap *,
+			    struct ieee80211_key *,
+			    ieee80211_keyix *, ieee80211_keyix *);
+static int		rt2661_key_delete(struct ieee80211vap *,
+			    const struct ieee80211_key *);
+static int		rt2661_key_set(struct ieee80211vap *,
+			    const struct ieee80211_key *,
+			    const u_int8_t mac[IEEE80211_ADDR_LEN]);
+static void		rt2661_key_update_begin(struct ieee80211vap *);
+static void		rt2661_key_update_end(struct ieee80211vap *);
 
 static const struct {
 	uint32_t	reg;
@@ -295,6 +307,20 @@
 		| IEEE80211_C_WME		/* 802.11e */
 #endif
 		;
+#if 0
+	/* set crypto capabilities */
+	ic->ic_cryptocaps =
+		  IEEE80211_CRYPTO_WEP
+		| IEEE80211_CRYPTO_TKIP
+		| IEEE80211_CRYPTO_TKIPMIC
+		| IEEE80211_CRYPTO_AES_CCM
+		;
+#endif
+	ic->ic_max_keyix = RT2661_KEY_MAX;	/* max h/w key index */
+	/*
+	 * Mark key cache slots associated with global keys as in use.
+	 */
+	rt2661_reset_keymap(sc);
 
 	bands = 0;
 	setbit(&bands, IEEE80211_MODE_11B);
@@ -425,6 +451,13 @@
 	vap = &rvp->ral_vap;
 	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
 
+	/* h/w crypto support */
+	vap->iv_key_alloc = rt2661_key_alloc;
+	vap->iv_key_delete = rt2661_key_delete;
+	vap->iv_key_set = rt2661_key_set;
+	vap->iv_key_update_begin = rt2661_key_update_begin;
+	vap->iv_key_update_end = rt2661_key_update_end;
+
 	/* override state transition machine */
 	rvp->ral_newstate = vap->iv_newstate;
 	vap->iv_newstate = rt2661_newstate;
@@ -630,6 +663,21 @@
 		bus_dma_tag_destroy(ring->data_dmat);
 }
 
+static __inline struct mbuf *
+rt2661_alloc_rxmbuf(struct rt2661_softc *sc)
+{
+	struct mbuf *m;
+
+	m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUMPAGESIZE);
+	if (m != NULL) {
+		/* backload payload */
+		m->m_data +=
+		    (MJUMPAGESIZE - IEEE80211_MTU_MAX) &~ (sizeof(long)-1);
+	} else
+		device_printf(sc->sc_dev, "could not allocate rx mbuf\n");
+	return m;
+}
+
 static int
 rt2661_alloc_rx_ring(struct rt2661_softc *sc, struct rt2661_rx_ring *ring,
     int count)
@@ -678,8 +726,9 @@
 	 * Pre-allocate Rx buffers and populate Rx ring.
 	 */
 	error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, 
-	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES,
-	    1, MCLBYTES, 0, NULL, NULL, &ring->data_dmat);
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+	    IEEE80211_MTU_MAX, 1, IEEE80211_MTU_MAX, 0, NULL, NULL,
+	    &ring->data_dmat);
 	if (error != 0) {
 		device_printf(sc->sc_dev, "could not create data DMA tag\n");
 		goto fail;
@@ -695,17 +744,16 @@
 			goto fail;
 		}
 
-		data->m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		data->m = rt2661_alloc_rxmbuf(sc);
 		if (data->m == NULL) {
-			device_printf(sc->sc_dev,
-			    "could not allocate rx mbuf\n");
+			/* NB: msg printed by rt2661_alloc_rxmbuf */
 			error = ENOMEM;
 			goto fail;
 		}
 
 		error = bus_dmamap_load(ring->data_dmat, data->map,
-		    mtod(data->m, void *), MCLBYTES, rt2661_dma_map_addr,
-		    &physaddr, 0);
+		    mtod(data->m, void *), IEEE80211_MTU_MAX,
+		    rt2661_dma_map_addr, &physaddr, 0);
 		if (error != 0) {
 			device_printf(sc->sc_dev,
 			    "could not load rx buf DMA map");
@@ -841,7 +889,231 @@
 	return error;
 }
 
+static __inline int
+rt2661_cipher(const struct ieee80211_key *k)
+{
+	switch (k->wk_cipher->ic_cipher) {
+	case IEEE80211_CIPHER_WEP:
+		return (k->wk_keylen == (40 / NBBY)) ?
+		    RT2661_CIPHER_WEP40 : RT2661_CIPHER_WEP104;
+	case IEEE80211_CIPHER_TKIP:
+		return RT2661_CIPHER_TKIP;
+	case IEEE80211_CIPHER_AES_CCM:
+		return RT2661_CIPHER_AES;
+	}
+	return RT2661_CIPHER_NONE;
+}
+
+static __inline int
+rt2661_ivlen(int cipher)
+{
+	switch (cipher) {
+	case RT2661_CIPHER_WEP40:
+	case RT2661_CIPHER_WEP104:
+		return IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN;
+	case RT2661_CIPHER_TKIP:
+	case RT2661_CIPHER_AES:
+		return IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
+		       IEEE80211_WEP_EXTIVLEN;
+	}
+	return 0;
+}
+
+static void
+rt2661_reset_keymap(struct rt2661_softc *sc)
+{
+	int i;
+
+	memset(sc->sc_keymap, 0, sizeof(sc->sc_keymap));
+	for (i = 0; i < IEEE80211_WEP_NKID; i++)
+		setbit(sc->sc_keymap, i);
+}
+
 /*
+ * Allocate one or more key cache slots for a uniacst key.
+ */
+static int
+rt2661_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k,
+	ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
+{
+#define	N(a)	(sizeof(a)/sizeof(a[0]))
+	struct rt2661_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+	u_int i, keyix;
+
+	if (k->wk_flags & IEEE80211_KEY_GROUP) {
+		if (!(&vap->iv_nw_keys[0] <= k &&
+		      k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
+			/* should not happen */
+			DPRINTF(sc, "%s: bogus group key\n", __func__);
+			return 0;
+		}
+		/*
+		 * XXX we pre-allocate the global keys so
+		 * have no way to check if they've already been allocated.
+		 */
+		*txkeyix = *rxkeyix = k - vap->iv_nw_keys;
+		return 1;
+	}
+
+	for (i = 0; i < N(sc->sc_keymap); i++) {
+		u_int8_t b = sc->sc_keymap[i];
+		if (b != 0xff) {
+			/*
+			 * One or more slots are free.
+			 */
+			keyix = i*NBBY;
+			while (b & 1)
+				keyix++, b >>= 1;
+			setbit(sc->sc_keymap, keyix);
+			DPRINTF(sc, "%s: key %u\n", __func__, keyix);
+			*txkeyix = *rxkeyix = keyix;
+			return 1;
+		}
+	}
+	DPRINTF(sc, "%s: out of space, use s/w crypto\n", __func__);
+	/* force fallback to s/w */
+	k->wk_flags |= IEEE80211_KEY_SWCRYPT;
+	if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP)
+		k->wk_flags |= IEEE80211_KEY_SWMIC;
+	*txkeyix = *rxkeyix = 0;
+	return 1;
+#undef N
+}
+
+/*
+ * Delete an entry in the key cache allocated by ath_key_alloc.
+ */
+static int
+rt2661_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
+{
+	struct rt2661_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+
+	DPRINTF(sc, "%s: delete key %u\n", __func__, k->wk_keyix);
+
+	/* NB: nothing to do for s/w crypto keys */
+	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
+		ieee80211_keyix keyix = k->wk_keyix;
+		uint32_t val;
+
+		KASSERT(keyix < 64, ("keyix %u", keyix));
+
+		if (keyix >= IEEE80211_WEP_NKID) {
+			clrbit(sc->sc_keymap, keyix);
+			if (keyix < 32) {
+				val = RAL_READ(sc, RT2661_SEC_CSR2);
+				val &= ~(1 << keyix);
+				RAL_WRITE(sc, RT2661_SEC_CSR2, val);
+			} else {
+				val = RAL_READ(sc, RT2661_SEC_CSR3);
+				val &= ~(1 << (keyix - 32));
+				RAL_WRITE(sc, RT2661_SEC_CSR3, val);
+			}
+		} else {
+			/*
+			 * NB: don't touch keymap entries for global keys so
+			 * they are never considered for dynamic allocation.
+			 */
+			val = RAL_READ(sc, RT2661_SEC_CSR0);
+			val &= ~(1 << keyix);
+			RAL_WRITE(sc, RT2661_SEC_CSR0, val);
+		}
+	}
+	return 1;
+}
+
+/*
+ * Set the key cache contents for the specified key.  Key cache
+ * slot(s) must already have been allocated by ath_key_alloc.
+ */
+static int
+rt2661_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k,
+	const u_int8_t mac[IEEE80211_ADDR_LEN])
+{
+	struct rt2661_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+	ieee80211_keyix keyix = k->wk_keyix;
+	uint32_t addr, val;
+	int hwcipher;
+
+	DPRINTF(sc, "%s: keyix %u, rxkeyix %u, flags 0x%04x\n", __func__,
+	    keyix, k->wk_rxkeyix, k->wk_flags);
+	KASSERT(keyix < 64, ("keyix %u", keyix));
+
+	/* NB: nothing to do for s/w crypto */
+	if (k->wk_flags & IEEE80211_KEY_SWCRYPT)
+		return 1;
+
+	hwcipher = rt2661_cipher(k);
+	if (keyix >= IEEE80211_WEP_NKID) {
+		uint8_t mac_cipher[IEEE80211_ADDR_LEN + 1];
+
+		/* write key content */
+		addr = RT2661_PAIRWISE_KEY_BASE + (keyix * sizeof(k->wk_key));
+		RAL_WRITE_REGION_1(sc, addr, k->wk_key, sizeof(k->wk_key));
+
+		/* write TA and key cipher */
+		/* NB: slot size is 1 byte bigger than mac+cipher */
+		addr = RT2661_TARGET_ADDR_BASE +
+		    (keyix * (IEEE80211_ADDR_LEN + 2));
+		IEEE80211_ADDR_COPY(mac_cipher, mac);
+		mac_cipher[IEEE80211_ADDR_LEN] = hwcipher;
+		RAL_WRITE_REGION_1(sc, addr, mac_cipher, sizeof(mac_cipher));
+
+		/* enable key slot */
+		if (keyix < 32) {
+			RAL_WRITE(sc, RT2661_SEC_CSR2,
+			    RAL_READ(sc, RT2661_SEC_CSR2) | (1<<keyix));
+		} else {
+			RAL_WRITE(sc, RT2661_SEC_CSR3,
+			    RAL_READ(sc, RT2661_SEC_CSR3) | (1<<(keyix-32)));
+		}
+
+		/* enable pairwise key lookup on rx */
+		RAL_WRITE(sc, RT2661_SEC_CSR4, 1);
+	} else {
+		/* write key content */
+		addr = RT2661_GLOBAL_KEY_BASE + (keyix * sizeof(k->wk_key));
+		RAL_WRITE_REGION_1(sc, addr, k->wk_key, sizeof(k->wk_key));
+
+		/* write key cipher */
+		val = RAL_READ(sc, RT2661_SEC_CSR1);
+		val &= ~(0xf << 4*keyix);
+		val |= hwcipher << 4*keyix;
+		RAL_WRITE(sc, RT2661_SEC_CSR1, val);
+
+		/* enable key slot */
+		RAL_WRITE(sc, RT2661_SEC_CSR0,
+		    RAL_READ(sc, RT2661_SEC_CSR0) | (1<<keyix));
+	}
+	return 1;
+}
+
+/*
+ * Block/unblock tx+rx processing while a key change is done.
+ * We assume the caller serializes key management operations
+ * so we only need to worry about synchronization with other
+ * uses that originate in the driver.
+ */
+static void
+rt2661_key_update_begin(struct ieee80211vap *vap)
+{
+	struct ifnet *ifp = vap->iv_ic->ic_ifp;
+	struct rt2661_softc *sc = ifp->if_softc;
+
+	DPRINTF(sc, "%s:\n", __func__);
+	IF_LOCK(&ifp->if_snd);		/* NB: doesn't block mgmt frames */
+}
+
+static void
+rt2661_key_update_end(struct ieee80211vap *vap)
+{
+	struct ifnet *ifp = vap->iv_ic->ic_ifp;
+	struct rt2661_softc *sc = ifp->if_softc;
+
+	DPRINTF(sc, "%s:\n", __func__);
+	IF_UNLOCK(&ifp->if_snd);
+}
+
+/*
  * Read 16 bits at address 'addr' from the serial EEPROM (either 93C46 or
  * 93C66).
  */
@@ -1026,7 +1298,9 @@
 	struct ieee80211_frame *wh;
 	struct ieee80211_node *ni;
 	struct mbuf *mnew, *m;
-	int error;
+	ieee80211_keyix keyix;
+	int error, ivlen;
+	uint32_t flags;
 
 	bus_dmamap_sync(sc->rxq.desc_dmat, sc->rxq.desc_map,
 	    BUS_DMASYNC_POSTREAD);
@@ -1036,23 +1310,24 @@
 
 		desc = &sc->rxq.desc[sc->rxq.cur];
 		data = &sc->rxq.data[sc->rxq.cur];
+		flags = le32toh(desc->flags);
 
-		if (le32toh(desc->flags) & RT2661_RX_BUSY)
+		if (flags & RT2661_RX_BUSY)
 			break;
 
-		if ((le32toh(desc->flags) & RT2661_RX_PHY_ERROR) ||
-		    (le32toh(desc->flags) & RT2661_RX_CRC_ERROR)) {
+		if (flags & (RT2661_RX_PHY_ERROR | RT2661_RX_CRC_ERROR)) {
 			/*
 			 * This should not happen since we did not request
 			 * to receive those frames when we filled TXRX_CSR0.
 			 */
 			DPRINTFN(sc, 5, "PHY or CRC error flags 0x%08x\n",
-			    le32toh(desc->flags));
+			    flags);
 			ifp->if_ierrors++;
 			goto skip;
 		}
 
-		if ((le32toh(desc->flags) & RT2661_RX_CIPHER_MASK) != 0) {
+		if ((flags & RT2661_RX_CIPHER_MASK) != 0) {
+			DPRINTFN(sc, 5, "cipher error 0x%08x\n", flags);
 			ifp->if_ierrors++;
 			goto skip;
 		}
@@ -1064,8 +1339,9 @@
 		 * mbuf. In the unlikely case that the old mbuf can't be
 		 * reloaded either, explicitly panic.
 		 */
-		mnew = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+		mnew = rt2661_alloc_rxmbuf(sc);
 		if (mnew == NULL) {
+			/* NB: msg printed by rt2661_alloc_rxmbuf */
 			ifp->if_ierrors++;
 			goto skip;
 		}
@@ -1075,14 +1351,14 @@
 		bus_dmamap_unload(sc->rxq.data_dmat, data->map);
 
 		error = bus_dmamap_load(sc->rxq.data_dmat, data->map,
-		    mtod(mnew, void *), MCLBYTES, rt2661_dma_map_addr,
-		    &physaddr, 0);
+		    mtod(mnew, void *), IEEE80211_MTU_MAX,
+		    rt2661_dma_map_addr, &physaddr, 0);
 		if (error != 0) {
 			m_freem(mnew);
 
 			/* try to reload the old mbuf */
 			error = bus_dmamap_load(sc->rxq.data_dmat, data->map,
-			    mtod(data->m, void *), MCLBYTES,
+			    mtod(data->m, void *), IEEE80211_MTU_MAX,
 			    rt2661_dma_map_addr, &physaddr, 0);
 			if (error != 0) {
 				/* very unlikely that it will fail... */
@@ -1103,8 +1379,7 @@
 
 		/* finalize mbuf */
 		m->m_pkthdr.rcvif = ifp;
-		m->m_pkthdr.len = m->m_len =
-		    (le32toh(desc->flags) >> 16) & 0xfff;
+		m->m_pkthdr.len = m->m_len = (flags >> 16) & 0xfff;
 
 		rssi = rt2661_get_rssi(sc, desc->rssi);
 
@@ -1120,19 +1395,48 @@
 			    htole64(((uint64_t)tsf_hi << 32) | tsf_lo);
 			tap->wr_flags = 0;
 			tap->wr_rate = ieee80211_plcp2rate(desc->rate,
-			    (desc->flags & htole32(RT2661_RX_OFDM)) ?
+			    (flags & RT2661_RX_OFDM) ?
 				IEEE80211_T_OFDM : IEEE80211_T_CCK);
 			tap->wr_antsignal = rssi < 0 ? 0 : rssi;
 
 			bpf_mtap2(ifp->if_bpf, tap, sc->sc_rxtap_len, m);
 		}
+
+		wh = mtod(m, struct ieee80211_frame *);
+		if ((wh->i_fc[1] & IEEE80211_FC1_WEP) &&
+		    (ivlen = rt2661_ivlen(RT2661_RX_CIPHER(flags))) != 0) {
+			const int hdrlen = ieee80211_hdrspace(ic, wh);
+			uint8_t *ivp;
+			/*
+			 * Glue crypto header back into place.
+			 */
+			M_PREPEND(m, ivlen, M_NOWAIT);
+			if (m == NULL) {
+				DPRINTFN(sc, 5, "no room for %d bytes of "
+				    "crypto header, cipher %d\n",
+				    ivlen, RT2661_RX_CIPHER(flags));
+				ifp->if_ierrors++;
+				goto skip;
+			}
+			ivp = mtod(m, uint8_t *);
+			memmove(ivp, ivp + ivlen, hdrlen);
+			ivp += hdrlen;
+			memcpy(ivp, desc->iv, ivlen);
+
+			/* recalculate after prepend */
+			wh = mtod(m, struct ieee80211_frame *);
+
+			keyix = RT2661_RX_KEYIX(flags);
+		} else
+			keyix = IEEE80211_KEYIX_NONE;
+		DPRINTFN(sc, 5, "keyix %d\n", keyix);
+
 		sc->sc_flags |= RAL_INPUT_RUNNING;
 		RAL_UNLOCK(sc);
-		wh = mtod(m, struct ieee80211_frame *);
 
 		/* send the frame to the 802.11 layer */
-		ni = ieee80211_find_rxnode(ic,
-		    (struct ieee80211_frame_min *)wh);
+		ni = ieee80211_find_rxnode_withkey(ic,
+		    (struct ieee80211_frame_min *)wh, keyix);
 		if (ni != NULL) {
 			/* Error happened during RSSI conversion. */
 			if (rssi < 0)
@@ -1273,20 +1577,46 @@
 
 static void
 rt2661_setup_tx_desc(struct rt2661_softc *sc, struct rt2661_tx_desc *desc,
-    uint32_t flags, uint16_t xflags, int len, int rate,
-    const bus_dma_segment_t *segs, int nsegs, int ac)
+    uint32_t flags, uint16_t xflags,
+    const struct ieee80211_key *k, const uint8_t *iv,
+    int len, int rate, const bus_dma_segment_t *segs, int nsegs, int ac)
 {
 	struct ifnet *ifp = sc->sc_ifp;
 	struct ieee80211com *ic = ifp->if_l2com;
 	uint16_t plcp_length;
 	int i, remainder;
 
+	/* NB: record packet length first so we can adjust len */
+	flags |= len << 16;
+	if (k != NULL && (k->wk_flags & IEEE80211_KEY_SWENCRYPT) == 0) {
+		const int hwcipher = rt2661_cipher(k);
+		const int ivlen = rt2661_ivlen(hwcipher);
+
+		/* calculate h/w crypto flags */
+		flags |= hwcipher << 29;
+		if ((hwcipher == RT2661_CIPHER_TKIP ||
+		     hwcipher == RT2661_CIPHER_AES) &&
+		    (k->wk_flags & IEEE80211_KEY_SWENMIC) == 0) {
+			flags |= RT2661_TX_HWMIC;
+			len += IEEE80211_WEP_MICLEN;
+		}
+		flags |= k->wk_keyix << 10;
+		if (k->wk_keyix >= IEEE80211_WEP_NKID)
+			flags |= RT2661_TX_PAIRWISE_KEY;
+
+		/* copy in iv+eiv extracted from packet */
+		KASSERT(iv != NULL && ivlen <= 8,
+		    ("iv %p ivlen %d", iv, ivlen));
+		memcpy(desc->iv, iv, ivlen);
+
+		/* adjust length for PLCP calculation below (MIC added above) */
+		len += ivlen;
+	}
+	flags |= RT2661_TX_BUSY | RT2661_TX_VALID;
 	desc->flags = htole32(flags);
-	desc->flags |= htole32(len << 16);
-	desc->flags |= htole32(RT2661_TX_BUSY | RT2661_TX_VALID);
 
+	xflags |= nsegs << 13;
 	desc->xflags = htole16(xflags);
-	desc->xflags |= htole16(nsegs << 13);
 
 	desc->wme = htole16(
 	    RT2661_QID(ac) |
@@ -1298,6 +1628,7 @@
 	 * Remember in which queue this frame was sent. This field is driver
 	 * private data only. It will be made available by the NIC in STA_CSR4
 	 * on Tx interrupts.
+	 * XXX can get this from mbuf
 	 */
 	desc->qid = ac;
 
@@ -1333,6 +1664,28 @@
 	}
 }
 
+static void
+rt2661_extract_iv(struct mbuf *m, const struct ieee80211_key *k,
+    const int hdrlen, uint8_t iv[8])
+{
+	uint8_t *data = mtod(m, uint8_t *);
+	const int hwcipher = rt2661_cipher(k);
+	const int ivlen = rt2661_ivlen(hwcipher);
+	uint8_t *ivp;
+
+	KASSERT(ivlen <= 8, ("ivlen %d", ivlen));
+
+	/*
+	 * Pull IV out of line to tx descriptor and copy
+	 * up the 802.11 header to squeeze out the bits.
+	 */
+	ivp = data + hdrlen;
+	memcpy(ivp, iv, ivlen);
+	memmove(data + ivlen, data, hdrlen);
+	m_adj(m, ivlen);
+	/* XXX MIC trailer */
+}
+
 static int
 rt2661_tx_mgt(struct rt2661_softc *sc, struct mbuf *m0,
     struct ieee80211_node *ni)
@@ -1346,8 +1699,9 @@
 	struct ieee80211_key *k;
 	bus_dma_segment_t segs[RT2661_MAX_SCATTER];
 	uint16_t dur;
-	uint32_t flags = 0;	/* XXX HWSEQ */
+	uint32_t flags, xflags;
 	int nsegs, rate, error;
+	uint8_t iv[8];
 
 	desc = &sc->mgtq.desc[sc->mgtq.cur];
 	data = &sc->mgtq.data[sc->mgtq.cur];
@@ -1356,13 +1710,21 @@
 
 	wh = mtod(m0, struct ieee80211_frame *);
 
+	flags = xflags = 0;
 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
 		k = ieee80211_crypto_encap(ni, m0);
 		if (k == NULL) {
 			m_freem(m0);
 			return ENOBUFS;
 		}
-	}
+		if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
+			const int hdrlen = ieee80211_hdrspace(ic, wh);
+
+			rt2661_extract_iv(m0, k, hdrlen, iv);
+			xflags |= hdrlen;
+		}
+	} else
+		k = NULL;
 
 	error = bus_dmamap_load_mbuf_sg(sc->mgtq.data_dmat, data->map, m0,
 	    segs, &nsegs, 0);
@@ -1403,7 +1765,7 @@
 			flags |= RT2661_TX_TIMESTAMP;
 	}
 
-	rt2661_setup_tx_desc(sc, desc, flags, 0 /* XXX HWSEQ */,
+	rt2661_setup_tx_desc(sc, desc, flags, xflags /* XXX HWSEQ */, k, iv,
 	    m0->m_pkthdr.len, rate, segs, nsegs, RT2661_QID_MGT);
 
 	bus_dmamap_sync(sc->mgtq.data_dmat, data->map, BUS_DMASYNC_PREWRITE);
@@ -1479,8 +1841,8 @@
 	/* ctl frames are not taken into account for amrr */
 	data->rix = IEEE80211_FIXED_RATE_NONE;
 
-	rt2661_setup_tx_desc(sc, desc, flags, 0, mprot->m_pkthdr.len,
-	    protrate, segs, 1, ac);
+	rt2661_setup_tx_desc(sc, desc, flags, 0, NULL, NULL,
+	    mprot->m_pkthdr.len, protrate, segs, 1, ac);
 
 	bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
 	bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE);
@@ -1508,9 +1870,13 @@
 	struct mbuf *mnew;
 	bus_dma_segment_t segs[RT2661_MAX_SCATTER];
 	uint16_t dur;
-	uint32_t flags;
+	uint32_t flags, xflags;
 	int error, nsegs, rate, noack = 0;
+	uint8_t iv[8];
 
+	data = &txq->data[txq->cur];
+	desc = &txq->desc[txq->cur];
+
 	wh = mtod(m0, struct ieee80211_frame *);
 
 	tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)];
@@ -1531,18 +1897,25 @@
 		noack = cap->cap_wmeParams[ac].wmep_noackPolicy;
 	}
 
+	flags = xflags = 0;
 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
 		k = ieee80211_crypto_encap(ni, m0);
 		if (k == NULL) {
 			m_freem(m0);
 			return ENOBUFS;
 		}
+		if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
+			const int hdrlen = ieee80211_hdrspace(ic, wh);
+
+			rt2661_extract_iv(m0, k, hdrlen, iv);
+			xflags |= hdrlen;
+		}
 
 		/* packet header may have moved, reset our local pointer */
 		wh = mtod(m0, struct ieee80211_frame *);
-	}
+	} else
+		k = NULL;
 
-	flags = 0;
 	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
 		int prot = IEEE80211_PROT_NONE;
 		if (m0->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
@@ -1560,9 +1933,6 @@
 		}
 	}
 
-	data = &txq->data[txq->cur];
-	desc = &txq->desc[txq->cur];
-
 	error = bus_dmamap_load_mbuf_sg(txq->data_dmat, data->map, m0, segs,
 	    &nsegs, 0);
 	if (error != 0 && error != EFBIG) {
@@ -1624,8 +1994,8 @@
 		*(uint16_t *)wh->i_dur = htole16(dur);
 	}
 
-	rt2661_setup_tx_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate, segs,
-	    nsegs, ac);
+	rt2661_setup_tx_desc(sc, desc, flags, xflags, k, iv,
+	    m0->m_pkthdr.len, rate, segs, nsegs, ac);
 
 	bus_dmamap_sync(txq->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
 	bus_dmamap_sync(txq->desc_dmat, txq->desc_map, BUS_DMASYNC_PREWRITE);
@@ -2543,6 +2913,9 @@
 		rt2661_reset_tx_ring(sc, &sc->txq[3]);
 		rt2661_reset_tx_ring(sc, &sc->mgtq);
 		rt2661_reset_rx_ring(sc, &sc->rxq);
+
+		/* h/w key table is reset, clear allocation map */
+		rt2661_reset_keymap(sc);
 	}
 }
 
@@ -2759,7 +3132,7 @@
 	rate = IEEE80211_IS_CHAN_5GHZ(ic->ic_bsschan) ? 12 : 2;
 
 	rt2661_setup_tx_desc(sc, &desc, RT2661_TX_TIMESTAMP, RT2661_TX_HWSEQ,
-	    m0->m_pkthdr.len, rate, NULL, 0, RT2661_QID_MGT);
+	    NULL, NULL, m0->m_pkthdr.len, rate, NULL, 0, RT2661_QID_MGT);
 
 	/* copy the first 24 bytes of Tx descriptor into NIC memory */
 	RAL_WRITE_REGION_1(sc, RT2661_HW_BEACON_BASE0, (uint8_t *)&desc, 24);

==== //depot/projects/vap/sys/dev/ral/rt2661reg.h#3 (text) ====

@@ -23,6 +23,12 @@
 #define RT2661_MGT_RING_COUNT	32
 #define RT2661_RX_RING_COUNT	64
 
+#define	RT2661_CIPHER_NONE	0
+#define	RT2661_CIPHER_WEP40	1
+#define	RT2661_CIPHER_WEP104	2
+#define	RT2661_CIPHER_TKIP	3
+#define	RT2661_CIPHER_AES	4
+
 #define RT2661_TX_DESC_SIZE	(sizeof (struct rt2661_tx_desc))
 #define RT2661_TX_DESC_WSIZE	(RT2661_TX_DESC_SIZE / 4)
 #define RT2661_RX_DESC_SIZE	(sizeof (struct rt2661_rx_desc))
@@ -39,6 +45,9 @@
 #define RT2661_MCU_INT_SOURCE_CSR	0x0014
 #define RT2661_MCU_INT_MASK_CSR		0x0018
 #define RT2661_PCI_USEC_CSR		0x001c
+#define	RT2661_GLOBAL_KEY_BASE		0x1000
+#define	RT2661_PAIRWISE_KEY_BASE	0x1200
+#define	RT2661_TARGET_ADDR_BASE		0x1a00
 #define RT2661_H2M_MAILBOX_CSR		0x2100
 #define RT2661_M2H_CMD_DONE_CSR		0x2104
 #define RT2661_HW_BEACON_BASE0		0x2c00
@@ -222,6 +231,8 @@
 #define RT2661_TX_OFDM		(1 << 5)
 #define RT2661_TX_IFS		(1 << 6)
 #define RT2661_TX_LONG_RETRY	(1 << 7)
+#define RT2661_TX_HWMIC		(1 << 8)
+#define RT2661_TX_PAIRWISE_KEY	(1 << 9)
 #define RT2661_TX_BURST		(1 << 28)
 
 	uint16_t	wme;
@@ -240,8 +251,7 @@
 	uint8_t		plcp_length_lo;
 	uint8_t		plcp_length_hi;
 
-	uint32_t	iv;
-	uint32_t	eiv;
+	uint8_t		iv[8];
 
 	uint8_t		offset;
 	uint8_t		qid;
@@ -267,13 +277,14 @@
 #define RT2661_RX_OFDM		(1 << 7)
 #define RT2661_RX_PHY_ERROR	(1 << 8)
 #define RT2661_RX_CIPHER_MASK	0x00000600
+#define	RT2661_RX_KEYIX(f)	(((f) >> 10) & 0x3f)
+#define	RT2661_RX_CIPHER(f)	(((f) >> 29) & 0x7)
 
 	uint8_t		rate;
 	uint8_t		rssi;
 	uint8_t		reserved1;
 	uint8_t		offset;
-	uint32_t	iv;
-	uint32_t	eiv;
+	uint8_t		iv[8];
 	uint32_t	reserved2;
 	uint32_t	physaddr;
 	uint32_t	reserved3[10];
@@ -356,6 +367,9 @@
 	{ RT2661_MAC_CSR13,        0x0000e000 },	\
 	{ RT2661_SEC_CSR0,         0x00000000 },	\
 	{ RT2661_SEC_CSR1,         0x00000000 },	\
+	{ RT2661_SEC_CSR2,         0x00000000 },	\
+	{ RT2661_SEC_CSR3,         0x00000000 },	\
+	{ RT2661_SEC_CSR4,         0x00000000 },	\
 	{ RT2661_SEC_CSR5,         0x00000000 },	\
 	{ RT2661_PHY_CSR1,         0x000023b0 },	\
 	{ RT2661_PHY_CSR5,         0x060a100c },	\

==== //depot/projects/vap/sys/dev/ral/rt2661var.h#14 (text) ====

@@ -17,6 +17,9 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#define	RT2661_KEY_MAX		64
+#define	RT2661_KEYBYTES	(RT2661_KEY_MAX / NBBY)
+
 struct rt2661_rx_radiotap_header {
 	struct ieee80211_radiotap_header wr_ihdr;
 	uint64_t	wr_tsf;
@@ -126,6 +129,7 @@
 #define	RAL_INPUT_RUNNING	0x2
 	int				sc_id;
 	struct ieee80211_channel	*sc_curchan;
+	uint8_t				sc_keymap[RT2661_KEYBYTES];
 
 	uint8_t				rf_rev;
 



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