Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9184d934 authored by Zhu Yi's avatar Zhu Yi Committed by John W. Linville
Browse files

[PATCH] ieee80211: Add TKIP crypt->build_iv



This patch adds ieee80211 TKIP build_iv() method to support hardwares
that can do TKIP encryption but relies on ieee80211 layer to build
the IV. It also changes the build_iv() interface to return the key
if possible after the IV is built (this is required by TKIP).

Signed-off-by: default avatarZhu Yi <yi.zhu@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 41a25c61
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -47,7 +47,8 @@ struct ieee80211_crypto_ops {
	/* deinitialize crypto context and free allocated private data */
	void (*deinit) (void *priv);

	int (*build_iv) (struct sk_buff * skb, int hdr_len, void *priv);
	int (*build_iv) (struct sk_buff * skb, int hdr_len,
			 u8 *key, int keylen, void *priv);

	/* encrypt/decrypt return < 0 on error or >= 0 on success. The return
	 * value from decrypt_mpdu is passed as the keyidx value for
+6 −2
Original line number Diff line number Diff line
@@ -190,7 +190,8 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm,
	ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
}

static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv)
static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len,
			      u8 *aeskey, int keylen, void *priv)
{
	struct ieee80211_ccmp_data *key = priv;
	int i;
@@ -199,6 +200,9 @@ static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv)
	if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len)
		return -1;

	if (aeskey != NULL && keylen >= CCMP_TK_LEN)
		memcpy(aeskey, key->key, CCMP_TK_LEN);

	pos = skb_push(skb, CCMP_HDR_LEN);
	memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
	pos += hdr_len;
@@ -238,7 +242,7 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
		return -1;

	data_len = skb->len - hdr_len;
	len = ieee80211_ccmp_hdr(skb, hdr_len, priv);
	len = ieee80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv);
	if (len < 0)
		return -1;

+27 −26
Original line number Diff line number Diff line
@@ -270,34 +270,33 @@ static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
#endif
}

static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv)
static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
			      u8 * rc4key, int keylen, void *priv)
{
	struct ieee80211_tkip_data *tkey = priv;
	int len;
	u8 *rc4key, *pos, *icv;
	u8 *pos;
	struct ieee80211_hdr_4addr *hdr;
	u32 crc;

	hdr = (struct ieee80211_hdr_4addr *)skb->data;

	if (skb_headroom(skb) < 8 || skb->len < hdr_len)
		return NULL;
		return -1;

	if (rc4key == NULL || keylen < 16)
		return -1;

	if (!tkey->tx_phase1_done) {
		tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
				   tkey->tx_iv32);
		tkey->tx_phase1_done = 1;
	}
	rc4key = kmalloc(16, GFP_ATOMIC);
	if (!rc4key)
		return NULL;
	tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);

	len = skb->len - hdr_len;
	pos = skb_push(skb, 8);
	memmove(pos, pos + 8, hdr_len);
	pos += hdr_len;
	icv = skb_put(skb, 4);

	*pos++ = *rc4key;
	*pos++ = *(rc4key + 1);
@@ -308,28 +307,28 @@ static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv)
	*pos++ = (tkey->tx_iv32 >> 16) & 0xff;
	*pos++ = (tkey->tx_iv32 >> 24) & 0xff;

	crc = ~crc32_le(~0, pos, len);
	icv[0] = crc;
	icv[1] = crc >> 8;
	icv[2] = crc >> 16;
	icv[3] = crc >> 24;
	tkey->tx_iv16++;
	if (tkey->tx_iv16 == 0) {
		tkey->tx_phase1_done = 0;
		tkey->tx_iv32++;
	}

	return rc4key;
	return 8;
}

static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
{
	struct ieee80211_tkip_data *tkey = priv;
	int len;
	const u8 *rc4key;
	u8 *pos;
	u8 rc4key[16], *pos, *icv;
	u32 crc;
	struct scatterlist sg;

	if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
		if (net_ratelimit()) {
			struct ieee80211_hdr_4addr *hdr =
			    (struct ieee80211_hdr_4addr *)skb->data;
			printk(KERN_DEBUG "TKIP countermeasures: dropped "
			printk(KERN_DEBUG ": TKIP countermeasures: dropped "
			       "TX packet to " MAC_FMT "\n",
			       MAC_ARG(hdr->addr1));
		}
@@ -342,22 +341,23 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
	len = skb->len - hdr_len;
	pos = skb->data + hdr_len;

	rc4key = ieee80211_tkip_hdr(skb, hdr_len, priv);
	if (!rc4key)
	if ((ieee80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
		return -1;

	icv = skb_put(skb, 4);

	crc = ~crc32_le(~0, pos, len);
	icv[0] = crc;
	icv[1] = crc >> 8;
	icv[2] = crc >> 16;
	icv[3] = crc >> 24;

	crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
	sg.page = virt_to_page(pos);
	sg.offset = offset_in_page(pos);
	sg.length = len + 4;
	crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4);

	tkey->tx_iv16++;
	if (tkey->tx_iv16 == 0) {
		tkey->tx_phase1_done = 0;
		tkey->tx_iv32++;
	}

	return 0;
}

@@ -378,7 +378,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)

	if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
		if (net_ratelimit()) {
			printk(KERN_DEBUG "TKIP countermeasures: dropped "
			printk(KERN_DEBUG ": TKIP countermeasures: dropped "
			       "received packet from " MAC_FMT "\n",
			       MAC_ARG(hdr->addr2));
		}
@@ -694,6 +694,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
	.name = "TKIP",
	.init = ieee80211_tkip_init,
	.deinit = ieee80211_tkip_deinit,
	.build_iv = ieee80211_tkip_hdr,
	.encrypt_mpdu = ieee80211_tkip_encrypt,
	.decrypt_mpdu = ieee80211_tkip_decrypt,
	.encrypt_msdu = ieee80211_michael_mic_add,
+3 −2
Original line number Diff line number Diff line
@@ -76,7 +76,8 @@ static void prism2_wep_deinit(void *priv)
}

/* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */
static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv)
static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len,
			       u8 *key, int keylen, void *priv)
{
	struct prism2_wep_data *wep = priv;
	u32 klen, len;
@@ -131,7 +132,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
		return -1;
	
	/* add the IV to the frame */
	if (prism2_wep_build_iv(skb, hdr_len, priv))
	if (prism2_wep_build_iv(skb, hdr_len, NULL, 0, priv))
		return -1;
	
	/* Copy the IV into the first 3 bytes of the key */
+3 −1
Original line number Diff line number Diff line
@@ -470,6 +470,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
			atomic_inc(&crypt->refcnt);
			if (crypt->ops->build_iv)
				crypt->ops->build_iv(skb_frag, hdr_len,
				      ieee->sec.keys[ieee->sec.active_key],
				      ieee->sec.key_sizes[ieee->sec.active_key],
				      crypt->priv);
			atomic_dec(&crypt->refcnt);
		}