wpa.c 15.3 KB
Newer Older
1 2
/*
 * Copyright 2002-2004, Instant802 Networks, Inc.
3
 * Copyright 2008, Jouni Malinen <j@w1.fi>
4 5 6 7 8 9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/skbuff.h>
#include <linux/compiler.h>
14
#include <linux/ieee80211.h>
15
#include <linux/gfp.h>
16
#include <asm/unaligned.h>
17
#include <net/mac80211.h>
J
Johannes Berg 已提交
18

19 20 21 22
#include "ieee80211_i.h"
#include "michael.h"
#include "tkip.h"
#include "aes_ccm.h"
23
#include "aes_cmac.h"
24 25
#include "wpa.h"

26
ieee80211_tx_result
27
ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
28
{
29
	u8 *data, *key, *mic;
30
	size_t data_len;
31 32
	unsigned int hdrlen;
	struct ieee80211_hdr *hdr;
33
	struct sk_buff *skb = tx->skb;
34
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
35
	int tail;
36

37
	hdr = (struct ieee80211_hdr *)skb->data;
38 39
	if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
	    skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control))
40
		return TX_CONTINUE;
41

42 43
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
	if (skb->len < hdrlen)
44
		return TX_DROP;
45

46 47 48
	data = skb->data + hdrlen;
	data_len = skb->len - hdrlen;

49 50 51 52 53
	if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE)) {
		/* Need to use software crypto for the test */
		info->control.hw_key = NULL;
	}

54
	if (info->control.hw_key &&
55
	    !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
56 57
	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
		/* hwaccel - with no need for SW-generated MMIC */
58
		return TX_CONTINUE;
59 60
	}

61
	tail = MICHAEL_MIC_LEN;
62
	if (!info->control.hw_key)
63 64 65 66 67
		tail += TKIP_ICV_LEN;

	if (WARN_ON(skb_tailroom(skb) < tail ||
		    skb_headroom(skb) < TKIP_IV_LEN))
		return TX_DROP;
68

69
	key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY];
70
	mic = skb_put(skb, MICHAEL_MIC_LEN);
71
	michael_mic(key, hdr, data, data_len, mic);
72 73
	if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE))
		mic[0]++;
74

75
	return TX_CONTINUE;
76 77 78
}


79
ieee80211_rx_result
80
ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
81
{
82
	u8 *data, *key = NULL;
83
	size_t data_len;
84
	unsigned int hdrlen;
85 86
	u8 mic[MICHAEL_MIC_LEN];
	struct sk_buff *skb = rx->skb;
J
Johannes Berg 已提交
87 88
	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
89

90 91 92 93 94
	/*
	 * it makes no sense to check for MIC errors on anything other
	 * than data frames.
	 */
	if (!ieee80211_is_data_present(hdr->frame_control))
95
		return RX_CONTINUE;
96

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
	/*
	 * No way to verify the MIC if the hardware stripped it or
	 * the IV with the key index. In this case we have solely rely
	 * on the driver to set RX_FLAG_MMIC_ERROR in the event of a
	 * MIC failure report.
	 */
	if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) {
		if (status->flag & RX_FLAG_MMIC_ERROR)
			goto mic_fail;

		if (!(status->flag & RX_FLAG_IV_STRIPPED))
			goto update_iv;

		return RX_CONTINUE;
	}

	/*
	 * Some hardware seems to generate Michael MIC failure reports; even
	 * though, the frame was not encrypted with TKIP and therefore has no
	 * MIC. Ignore the flag them to avoid triggering countermeasures.
	 */
118
	if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
119
	    !(status->flag & RX_FLAG_DECRYPTED))
120
		return RX_CONTINUE;
121

122 123 124 125 126 127 128 129 130 131 132 133 134
	if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) {
		/*
		 * APs with pairwise keys should never receive Michael MIC
		 * errors for non-zero keyidx because these are reserved for
		 * group keys and only the AP is sending real multicast
		 * frames in the BSS. (
		 */
		return RX_DROP_UNUSABLE;
	}

	if (status->flag & RX_FLAG_MMIC_ERROR)
		goto mic_fail;

135 136
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
	if (skb->len < hdrlen + MICHAEL_MIC_LEN)
J
Johannes Berg 已提交
137
		return RX_DROP_UNUSABLE;
138

139 140
	data = skb->data + hdrlen;
	data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
141
	key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
142
	michael_mic(key, hdr, data, data_len, mic);
143 144
	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0)
		goto mic_fail;
145 146 147 148

	/* remove Michael MIC from payload */
	skb_trim(skb, skb->len - MICHAEL_MIC_LEN);

149
update_iv:
150
	/* update IV in key information to be able to detect replays */
151 152
	rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
	rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
153

154
	return RX_CONTINUE;
155 156

mic_fail:
157 158 159 160 161 162 163
	/*
	 * In some cases the key can be unset - e.g. a multicast packet, in
	 * a driver that supports HW encryption. Send up the key idx only if
	 * the key is set.
	 */
	mac80211_ev_michael_mic_failure(rx->sdata,
					rx->key ? rx->key->conf.keyidx : -1,
164 165
					(void *) skb->data, NULL, GFP_ATOMIC);
	return RX_DROP_UNUSABLE;
166 167 168
}


169
static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
170 171 172
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	struct ieee80211_key *key = tx->key;
173
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
174
	unsigned long flags;
175 176
	unsigned int hdrlen;
	int len, tail;
177 178
	u8 *pos;

179 180 181
	if (info->control.hw_key &&
	    !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
		/* hwaccel - with no need for software-generated IV */
182
		return 0;
183 184
	}

185
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
186 187
	len = skb->len - hdrlen;

188
	if (info->control.hw_key)
189
		tail = 0;
J
Johannes Berg 已提交
190
	else
191 192 193 194 195
		tail = TKIP_ICV_LEN;

	if (WARN_ON(skb_tailroom(skb) < tail ||
		    skb_headroom(skb) < TKIP_IV_LEN))
		return -1;
196 197 198 199 200 201

	pos = skb_push(skb, TKIP_IV_LEN);
	memmove(pos, pos + TKIP_IV_LEN, hdrlen);
	pos += hdrlen;

	/* Increase IV for the frame */
202
	spin_lock_irqsave(&key->u.tkip.txlock, flags);
203 204 205
	key->u.tkip.tx.iv16++;
	if (key->u.tkip.tx.iv16 == 0)
		key->u.tkip.tx.iv32++;
206 207
	pos = ieee80211_tkip_add_iv(pos, key);
	spin_unlock_irqrestore(&key->u.tkip.txlock, flags);
208

209 210
	/* hwaccel - with software IV */
	if (info->control.hw_key)
211 212 213 214 215
		return 0;

	/* Add room for ICV */
	skb_put(skb, TKIP_ICV_LEN);

216
	return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
217
					   key, skb, pos, len);
218 219 220
}


221
ieee80211_tx_result
222
ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
223 224 225
{
	struct sk_buff *skb = tx->skb;

226
	ieee80211_tx_set_protected(tx);
227

J
Johannes Berg 已提交
228 229 230 231
	do {
		if (tkip_encrypt_skb(tx, skb) < 0)
			return TX_DROP;
	} while ((skb = skb->next));
232

233
	return TX_CONTINUE;
234 235 236
}


237
ieee80211_rx_result
238
ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
239 240
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
241
	int hdrlen, res, hwaccel = 0;
242 243
	struct ieee80211_key *key = rx->key;
	struct sk_buff *skb = rx->skb;
J
Johannes Berg 已提交
244
	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
245

246
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
247

248
	if (!ieee80211_is_data(hdr->frame_control))
249
		return RX_CONTINUE;
250 251

	if (!rx->sta || skb->len - hdrlen < 12)
J
Johannes Berg 已提交
252
		return RX_DROP_UNUSABLE;
253

254 255 256 257 258 259
	/*
	 * Let TKIP code verify IV, but skip decryption.
	 * In the case where hardware checks the IV as well,
	 * we don't even get here, see ieee80211_rx_h_decrypt()
	 */
	if (status->flag & RX_FLAG_DECRYPTED)
260 261 262 263
		hwaccel = 1;

	res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
					  key, skb->data + hdrlen,
264
					  skb->len - hdrlen, rx->sta->sta.addr,
265
					  hdr->addr1, hwaccel, rx->queue,
266 267
					  &rx->tkip_iv32,
					  &rx->tkip_iv16);
268
	if (res != TKIP_DECRYPT_OK)
J
Johannes Berg 已提交
269
		return RX_DROP_UNUSABLE;
270 271 272 273 274 275 276 277

	/* Trim ICV */
	skb_trim(skb, skb->len - TKIP_ICV_LEN);

	/* Remove IV */
	memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
	skb_pull(skb, TKIP_IV_LEN);

278
	return RX_CONTINUE;
279 280 281
}


282
static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
283 284
				int encrypted)
{
285
	__le16 mask_fc;
286
	int a4_included, mgmt;
287
	u8 qos_tid;
288
	u8 *b_0, *aad;
289 290 291
	u16 data_len, len_a;
	unsigned int hdrlen;
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
292

293 294 295
	b_0 = scratch + 3 * AES_BLOCK_LEN;
	aad = scratch + 4 * AES_BLOCK_LEN;

296
	/*
297
	 * Mask FC: zero subtype b4 b5 b6 (if not mgmt)
298 299
	 * Retry, PwrMgt, MoreData; set Protected
	 */
300
	mgmt = ieee80211_is_mgmt(hdr->frame_control);
301
	mask_fc = hdr->frame_control;
302
	mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY |
303
				IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA);
304 305
	if (!mgmt)
		mask_fc &= ~cpu_to_le16(0x0070);
306 307 308 309 310
	mask_fc |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);

	hdrlen = ieee80211_hdrlen(hdr->frame_control);
	len_a = hdrlen - 2;
	a4_included = ieee80211_has_a4(hdr->frame_control);
311

312 313 314 315 316 317 318 319 320 321
	if (ieee80211_is_data_qos(hdr->frame_control))
		qos_tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
	else
		qos_tid = 0;

	data_len = skb->len - hdrlen - CCMP_HDR_LEN;
	if (encrypted)
		data_len -= CCMP_MIC_LEN;

	/* First block, b_0 */
322
	b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
323 324 325 326
	/* Nonce: Nonce Flags | A2 | PN
	 * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
	 */
	b_0[1] = qos_tid | (mgmt << 4);
327
	memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
328 329
	memcpy(&b_0[8], pn, CCMP_PN_LEN);
	/* l(m) */
330
	put_unaligned_be16(data_len, &b_0[14]);
331 332 333

	/* AAD (extra authenticate-only data) / masked 802.11 header
	 * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
334 335
	put_unaligned_be16(len_a, &aad[0]);
	put_unaligned(mask_fc, (__le16 *)&aad[2]);
336
	memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
337 338 339 340

	/* Mask Seq#, leave Frag# */
	aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
	aad[23] = 0;
341

342
	if (a4_included) {
343
		memcpy(&aad[24], hdr->addr4, ETH_ALEN);
344
		aad[30] = qos_tid;
345
		aad[31] = 0;
346
	} else {
347
		memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN);
348
		aad[24] = qos_tid;
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
	}
}


static inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id)
{
	hdr[0] = pn[5];
	hdr[1] = pn[4];
	hdr[2] = 0;
	hdr[3] = 0x20 | (key_id << 6);
	hdr[4] = pn[3];
	hdr[5] = pn[2];
	hdr[6] = pn[1];
	hdr[7] = pn[0];
}


J
Johannes Berg 已提交
366
static inline void ccmp_hdr2pn(u8 *pn, u8 *hdr)
367 368 369 370 371 372 373 374 375 376
{
	pn[0] = hdr[7];
	pn[1] = hdr[6];
	pn[2] = hdr[5];
	pn[3] = hdr[4];
	pn[4] = hdr[1];
	pn[5] = hdr[0];
}


377
static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
378 379 380
{
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
	struct ieee80211_key *key = tx->key;
381
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
382
	int hdrlen, len, tail;
383
	u8 *pos, *pn;
384 385
	int i;

386 387 388 389 390 391
	if (info->control.hw_key &&
	    !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
		/*
		 * hwaccel has no need for preallocated room for CCMP
		 * header or MIC fields
		 */
392
		return 0;
393 394
	}

395
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
396 397
	len = skb->len - hdrlen;

398
	if (info->control.hw_key)
399
		tail = 0;
J
Johannes Berg 已提交
400
	else
401 402 403 404 405
		tail = CCMP_MIC_LEN;

	if (WARN_ON(skb_tailroom(skb) < tail ||
		    skb_headroom(skb) < CCMP_HDR_LEN))
		return -1;
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420

	pos = skb_push(skb, CCMP_HDR_LEN);
	memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
	hdr = (struct ieee80211_hdr *) pos;
	pos += hdrlen;

	/* PN = PN + 1 */
	pn = key->u.ccmp.tx_pn;

	for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
		pn[i]++;
		if (pn[i])
			break;
	}

421
	ccmp_pn2hdr(pos, pn, key->conf.keyidx);
422

423 424
	/* hwaccel - with software CCMP header */
	if (info->control.hw_key)
425 426 427
		return 0;

	pos += CCMP_HDR_LEN;
428 429
	ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0);
	ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, key->u.ccmp.tx_crypto_buf, pos, len,
430 431 432 433 434 435
				  pos, skb_put(skb, CCMP_MIC_LEN));

	return 0;
}


436
ieee80211_tx_result
437
ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
438 439 440
{
	struct sk_buff *skb = tx->skb;

441
	ieee80211_tx_set_protected(tx);
442

J
Johannes Berg 已提交
443 444 445 446
	do {
		if (ccmp_encrypt_skb(tx, skb) < 0)
			return TX_DROP;
	} while ((skb = skb->next));
447

448
	return TX_CONTINUE;
449 450 451
}


452
ieee80211_rx_result
453
ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
454
{
455
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
456 457 458
	int hdrlen;
	struct ieee80211_key *key = rx->key;
	struct sk_buff *skb = rx->skb;
J
Johannes Berg 已提交
459
	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
460 461
	u8 pn[CCMP_PN_LEN];
	int data_len;
462
	int queue;
463

464
	hdrlen = ieee80211_hdrlen(hdr->frame_control);
465

466 467
	if (!ieee80211_is_data(hdr->frame_control) &&
	    !ieee80211_is_robust_mgmt_frame(hdr))
468
		return RX_CONTINUE;
469 470 471

	data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
	if (!rx->sta || data_len < 0)
J
Johannes Berg 已提交
472
		return RX_DROP_UNUSABLE;
473

J
Johannes Berg 已提交
474
	ccmp_hdr2pn(pn, skb->data + hdrlen);
475

476 477 478 479
	queue = ieee80211_is_mgmt(hdr->frame_control) ?
		NUM_RX_DATA_QUEUES : rx->queue;

	if (memcmp(pn, key->u.ccmp.rx_pn[queue], CCMP_PN_LEN) <= 0) {
480
		key->u.ccmp.replays++;
J
Johannes Berg 已提交
481
		return RX_DROP_UNUSABLE;
482 483
	}

J
Johannes Berg 已提交
484
	if (!(status->flag & RX_FLAG_DECRYPTED)) {
485
		/* hardware didn't decrypt/verify MIC */
486
		ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1);
487 488

		if (ieee80211_aes_ccm_decrypt(
489
			    key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf,
490 491
			    skb->data + hdrlen + CCMP_HDR_LEN, data_len,
			    skb->data + skb->len - CCMP_MIC_LEN,
J
Johannes Berg 已提交
492
			    skb->data + hdrlen + CCMP_HDR_LEN))
J
Johannes Berg 已提交
493
			return RX_DROP_UNUSABLE;
494 495
	}

496
	memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN);
497 498 499 500 501 502

	/* Remove CCMP header and MIC */
	skb_trim(skb, skb->len - CCMP_MIC_LEN);
	memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
	skb_pull(skb, CCMP_HDR_LEN);

503
	return RX_CONTINUE;
504
}
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540


static void bip_aad(struct sk_buff *skb, u8 *aad)
{
	/* BIP AAD: FC(masked) || A1 || A2 || A3 */

	/* FC type/subtype */
	aad[0] = skb->data[0];
	/* Mask FC Retry, PwrMgt, MoreData flags to zero */
	aad[1] = skb->data[1] & ~(BIT(4) | BIT(5) | BIT(6));
	/* A1 || A2 || A3 */
	memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN);
}


static inline void bip_ipn_swap(u8 *d, const u8 *s)
{
	*d++ = s[5];
	*d++ = s[4];
	*d++ = s[3];
	*d++ = s[2];
	*d++ = s[1];
	*d = s[0];
}


ieee80211_tx_result
ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx)
{
	struct sk_buff *skb = tx->skb;
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct ieee80211_key *key = tx->key;
	struct ieee80211_mmie *mmie;
	u8 *pn, aad[20];
	int i;

541
	if (info->control.hw_key)
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
		return 0;

	if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie)))
		return TX_DROP;

	mmie = (struct ieee80211_mmie *) skb_put(skb, sizeof(*mmie));
	mmie->element_id = WLAN_EID_MMIE;
	mmie->length = sizeof(*mmie) - 2;
	mmie->key_id = cpu_to_le16(key->conf.keyidx);

	/* PN = PN + 1 */
	pn = key->u.aes_cmac.tx_pn;

	for (i = sizeof(key->u.aes_cmac.tx_pn) - 1; i >= 0; i--) {
		pn[i]++;
		if (pn[i])
			break;
	}
	bip_ipn_swap(mmie->sequence_number, pn);

	bip_aad(skb, aad);

	/*
	 * MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64)
	 */
	ieee80211_aes_cmac(key->u.aes_cmac.tfm, key->u.aes_cmac.tx_crypto_buf,
			   aad, skb->data + 24, skb->len - 24, mmie->mic);

	return TX_CONTINUE;
}


ieee80211_rx_result
ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx)
{
	struct sk_buff *skb = rx->skb;
J
Johannes Berg 已提交
578
	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
	struct ieee80211_key *key = rx->key;
	struct ieee80211_mmie *mmie;
	u8 aad[20], mic[8], ipn[6];
	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;

	if (!ieee80211_is_mgmt(hdr->frame_control))
		return RX_CONTINUE;

	if (skb->len < 24 + sizeof(*mmie))
		return RX_DROP_UNUSABLE;

	mmie = (struct ieee80211_mmie *)
		(skb->data + skb->len - sizeof(*mmie));
	if (mmie->element_id != WLAN_EID_MMIE ||
	    mmie->length != sizeof(*mmie) - 2)
		return RX_DROP_UNUSABLE; /* Invalid MMIE */

	bip_ipn_swap(ipn, mmie->sequence_number);

	if (memcmp(ipn, key->u.aes_cmac.rx_pn, 6) <= 0) {
		key->u.aes_cmac.replays++;
		return RX_DROP_UNUSABLE;
	}

J
Johannes Berg 已提交
603
	if (!(status->flag & RX_FLAG_DECRYPTED)) {
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
		/* hardware didn't decrypt/verify MIC */
		bip_aad(skb, aad);
		ieee80211_aes_cmac(key->u.aes_cmac.tfm,
				   key->u.aes_cmac.rx_crypto_buf, aad,
				   skb->data + 24, skb->len - 24, mic);
		if (memcmp(mic, mmie->mic, sizeof(mmie->mic)) != 0) {
			key->u.aes_cmac.icverrors++;
			return RX_DROP_UNUSABLE;
		}
	}

	memcpy(key->u.aes_cmac.rx_pn, ipn, 6);

	/* Remove MMIE */
	skb_trim(skb, skb->len - sizeof(*mmie));

	return RX_CONTINUE;
}