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 175
	unsigned int hdrlen;
	int len, tail;
176 177
	u8 *pos;

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

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

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

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

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

	/* Increase IV for the frame */
201 202 203
	key->u.tkip.tx.iv16++;
	if (key->u.tkip.tx.iv16 == 0)
		key->u.tkip.tx.iv32++;
204

205
	pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16);
206

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

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

	hdr = (struct ieee80211_hdr *) skb->data;
215 216
	return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
					   key, pos, len, hdr->addr2);
217 218 219
}


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

225
	ieee80211_tx_set_protected(tx);
226

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

232
	return TX_CONTINUE;
233 234 235
}


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

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

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

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

253 254 255 256 257 258
	/*
	 * 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)
259 260 261 262
		hwaccel = 1;

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

	/* 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);

277
	return RX_CONTINUE;
278 279 280
}


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

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

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

311 312 313 314 315 316 317 318 319 320
	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 */
321
	b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
322 323 324 325
	/* Nonce: Nonce Flags | A2 | PN
	 * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
	 */
	b_0[1] = qos_tid | (mgmt << 4);
326
	memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
327 328
	memcpy(&b_0[8], pn, CCMP_PN_LEN);
	/* l(m) */
329
	put_unaligned_be16(data_len, &b_0[14]);
330 331 332

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

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

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


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 已提交
365
static inline void ccmp_hdr2pn(u8 *pn, u8 *hdr)
366 367 368 369 370 371 372 373 374 375
{
	pn[0] = hdr[7];
	pn[1] = hdr[6];
	pn[2] = hdr[5];
	pn[3] = hdr[4];
	pn[4] = hdr[1];
	pn[5] = hdr[0];
}


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

385 386 387 388 389 390
	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
		 */
391
		return 0;
392 393
	}

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

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

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

	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;
	}

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

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

	pos += CCMP_HDR_LEN;
427 428
	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,
429 430 431 432 433 434
				  pos, skb_put(skb, CCMP_MIC_LEN));

	return 0;
}


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

440
	ieee80211_tx_set_protected(tx);
441

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

447
	return TX_CONTINUE;
448 449 450
}


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

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

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

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

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

475 476 477 478
	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) {
479
		key->u.ccmp.replays++;
J
Johannes Berg 已提交
480
		return RX_DROP_UNUSABLE;
481 482
	}

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

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

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

	/* 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);

502
	return RX_CONTINUE;
503
}
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


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;

540
	if (info->control.hw_key)
541 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
		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 已提交
577
	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
	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 已提交
602
	if (!(status->flag & RX_FLAG_DECRYPTED)) {
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
		/* 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;
}