Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 Jul 2008 16:24:39 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 146211 for review
Message-ID:  <200807291624.m6TGOdLq042163@repoman.freebsd.org>

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

Change 146211 by sam@sam_ebb on 2008/07/29 16:24:34

	Changes to support devices that require the phase 1 ttak:
	o add new key flags IEEE80211_KEY_CIPHER[01] for use by cipher
	  modules (and drivers)
	o change TKIP to use IEEE80211_KEY_CIPHER0 to calculate the phase 1
	  ttak on transmit and pre-calculate the initial receive hash
	  on key change; this enables use by devices such as the Intel 4965

Affected files ...

.. //depot/projects/vap/sys/net80211/ieee80211_crypto.h#19 edit
.. //depot/projects/vap/sys/net80211/ieee80211_crypto_tkip.c#14 edit

Differences ...

==== //depot/projects/vap/sys/net80211/ieee80211_crypto.h#19 (text+ko) ====

@@ -83,6 +83,8 @@
 #define	IEEE80211_KEY_SWENMIC	0x0040	/* host-based enmic */
 #define	IEEE80211_KEY_SWDEMIC	0x0080	/* host-based demic */
 #define	IEEE80211_KEY_DEVKEY	0x0100	/* device key request completed */
+#define	IEEE80211_KEY_CIPHER0	0x1000	/* cipher-specific action 0 */
+#define	IEEE80211_KEY_CIPHER1	0x2000	/* cipher-specific action 1 */
 	ieee80211_keyix	wk_keyix;	/* h/w key index */
 	ieee80211_keyix	wk_rxkeyix;	/* optional h/w rx key index */
 	uint8_t		wk_key[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];

==== //depot/projects/vap/sys/net80211/ieee80211_crypto_tkip.c#14 (text+ko) ====

@@ -96,10 +96,14 @@
 static	void michael_mic(struct tkip_ctx *, const u8 *key,
 		struct mbuf *m, u_int off, size_t data_len,
 		u8 mic[IEEE80211_WEP_MICLEN]);
-static	int tkip_encrypt(struct tkip_ctx *, struct ieee80211_key *,
-		struct mbuf *, int hdr_len);
-static	int tkip_decrypt(struct tkip_ctx *, struct ieee80211_key *,
-		struct mbuf *, int hdr_len);
+
+static	void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA,
+		u32 IV32);
+static	void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
+		u16 IV16);
+static	void wep_encrypt(u8 *key, struct mbuf *m0, u_int off, size_t data_len,
+		uint8_t icv[IEEE80211_WEP_CRCLEN]);
+static	int wep_decrypt(u8 *key, struct mbuf *m, u_int off, size_t data_len);
 
 /* number of references from net80211 layer */
 static	int nrefs = 0;
@@ -144,6 +148,20 @@
 		return 0;
 	}
 	k->wk_keytsc = 1;		/* TSC starts at 1 */
+	if (k->wk_flags & IEEE80211_KEY_CIPHER0) {
+		/*
+		 * We're responsible for Phase 1 calcs for transmit but
+		 * for receive the hardware needs an initial value
+		 * pre-calculated.
+		 *
+		 * NB: this only works for unicast keys
+		 * NB: we assume the rsc is the same for all tid's
+		 */
+		KASSERT((k->wk_flags & IEEE80211_KEY_SWDECRYPT) == 0,
+		    ("CIPHER0+SWDECRYPT not supported"));
+		tkip_mixing_phase1(ctx->rx_ttak, k->wk_key, k->wk_macaddr,
+		    (u32)(k->wk_keyrsc[0] >> 16));
+	}
 	return 1;
 }
 
@@ -196,10 +214,33 @@
 	/*
 	 * Finally, do software encrypt if neeed.
 	 */
-	if (k->wk_flags & IEEE80211_KEY_SWENCRYPT) {
-		if (!tkip_encrypt(ctx, k, m, hdrlen))
-			return 0;
-		/* NB: tkip_encrypt handles wk_keytsc */
+	if (k->wk_flags & (IEEE80211_KEY_SWENCRYPT | IEEE80211_KEY_CIPHER0)) {
+		struct ieee80211_frame *wh;
+
+		wh = mtod(m, struct ieee80211_frame *);
+		if (!ctx->tx_phase1_done) {
+			tkip_mixing_phase1(ctx->tx_ttak, k->wk_key,
+			     wh->i_addr2, (u32)(k->wk_keytsc >> 16));
+			ctx->tx_phase1_done = 1;
+		}
+		if (k->wk_flags & IEEE80211_KEY_SWENCRYPT) {
+			uint8_t icv[IEEE80211_WEP_CRCLEN];
+
+			tkip_mixing_phase2(ctx->tx_rc4key, k->wk_key,
+			     ctx->tx_ttak, (u16) k->wk_keytsc);
+
+			vap->iv_stats.is_crypto_tkip++;
+
+			wep_encrypt(ctx->tx_rc4key,
+				m, hdrlen + tkip.ic_header,
+				m->m_pkthdr.len - (hdrlen + tkip.ic_header),
+				icv);
+			/* XXX check return */
+			(void) m_append(m, IEEE80211_WEP_CRCLEN, icv);
+		}
+		k->wk_keytsc++;
+		if ((u16)(k->wk_keytsc) == 0)
+			ctx->tx_phase1_done = 0;
 	} else
 		k->wk_keytsc++;
 
@@ -302,9 +343,46 @@
 	 * If so we just strip the header; otherwise we need to
 	 * handle the decrypt in software.
 	 */
-	if ((k->wk_flags & IEEE80211_KEY_SWDECRYPT) &&
-	    !tkip_decrypt(ctx, k, m, hdrlen))
-		return 0;
+	if (k->wk_flags & IEEE80211_KEY_SWDECRYPT) {
+		u32 iv32;
+
+		/* NB: already verified header and left seq # in rx_rsc */
+		iv32 = (u32) (ctx->rx_rsc >> 16);
+
+		if (iv32 != (u32)(k->wk_keyrsc[tid] >> 16) ||
+		    !ctx->rx_phase1_done) {
+			tkip_mixing_phase1(ctx->rx_ttak, k->wk_key,
+				wh->i_addr2, iv32);
+			ctx->rx_phase1_done = 1;
+		}
+
+		tkip_mixing_phase2(ctx->rx_rc4key, k->wk_key,
+		    ctx->rx_ttak, (u16) ctx->rx_rsc);
+
+		vap->iv_stats.is_crypto_tkip++;
+
+		/*
+		 * NB: m is unstripped; deduct headers + ICV
+		 *     to get payload
+		 */
+		if (wep_decrypt(ctx->rx_rc4key,
+			m, hdrlen + tkip.ic_header,
+			m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) {
+			if (iv32 != (u32)(k->wk_keyrsc[tid] >> 16)) {
+				/*
+				 * Previously cached Phase1 result was
+				 * already lost, so it needs to be
+				 * recalculated for the next packet.
+				 */
+				ctx->rx_phase1_done = 0;
+			}
+			IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO,
+			    wh->i_addr2,
+			    "%s", "TKIP ICV mismatch on decrypt");
+			vap->iv_stats.is_rx_tkipicv++;
+			return 0;
+		}
+	}
 
 	/*
 	 * Copy up 802.11 header and strip crypto bits.
@@ -509,7 +587,8 @@
 
 #define PHASE1_LOOP_COUNT 8
 
-static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
+static void
+tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32)
 {
 	int i, j;
 
@@ -901,78 +980,6 @@
 	put_le32(mic + 4, r);
 }
 
-static int
-tkip_encrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
-	struct mbuf *m, int hdrlen)
-{
-	struct ieee80211_frame *wh;
-	uint8_t icv[IEEE80211_WEP_CRCLEN];
-
-	ctx->tc_vap->iv_stats.is_crypto_tkip++;
-
-	wh = mtod(m, struct ieee80211_frame *);
-	if (!ctx->tx_phase1_done) {
-		tkip_mixing_phase1(ctx->tx_ttak, key->wk_key, wh->i_addr2,
-				   (u32)(key->wk_keytsc >> 16));
-		ctx->tx_phase1_done = 1;
-	}
-	tkip_mixing_phase2(ctx->tx_rc4key, key->wk_key, ctx->tx_ttak,
-		(u16) key->wk_keytsc);
-
-	wep_encrypt(ctx->tx_rc4key,
-		m, hdrlen + tkip.ic_header,
-		m->m_pkthdr.len - (hdrlen + tkip.ic_header),
-		icv);
-	(void) m_append(m, IEEE80211_WEP_CRCLEN, icv);	/* XXX check return */
-
-	key->wk_keytsc++;
-	if ((u16)(key->wk_keytsc) == 0)
-		ctx->tx_phase1_done = 0;
-	return 1;
-}
-
-static int
-tkip_decrypt(struct tkip_ctx *ctx, struct ieee80211_key *key,
-	struct mbuf *m, int hdrlen)
-{
-	struct ieee80211_frame *wh;
-	struct ieee80211vap *vap = ctx->tc_vap;
-	u32 iv32;
-	u16 iv16;
-	u8 tid;
-
-	vap->iv_stats.is_crypto_tkip++;
-
-	wh = mtod(m, struct ieee80211_frame *);
-	/* NB: tkip_decap already verified header and left seq in rx_rsc */
-	iv16 = (u16) ctx->rx_rsc;
-	iv32 = (u32) (ctx->rx_rsc >> 16);
-
-	tid = ieee80211_gettid(wh);
-	if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16) || !ctx->rx_phase1_done) {
-		tkip_mixing_phase1(ctx->rx_ttak, key->wk_key,
-			wh->i_addr2, iv32);
-		ctx->rx_phase1_done = 1;
-	}
-	tkip_mixing_phase2(ctx->rx_rc4key, key->wk_key, ctx->rx_ttak, iv16);
-
-	/* NB: m is unstripped; deduct headers + ICV to get payload */
-	if (wep_decrypt(ctx->rx_rc4key,
-		m, hdrlen + tkip.ic_header,
-	        m->m_pkthdr.len - (hdrlen + tkip.ic_header + tkip.ic_trailer))) {
-		if (iv32 != (u32)(key->wk_keyrsc[tid] >> 16)) {
-			/* Previously cached Phase1 result was already lost, so
-			 * it needs to be recalculated for the next packet. */
-			ctx->rx_phase1_done = 0;
-		}
-		IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
-		    "%s", "TKIP ICV mismatch on decrypt");
-		vap->iv_stats.is_rx_tkipicv++;
-		return 0;
-	}
-	return 1;
-}
-
 /*
  * Module glue.
  */



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