Blame view

net/mac80211/wpa.c 14.4 KB
f0706e828   Jiri Benc   [MAC80211]: Add m...
1
2
  /*
   * Copyright 2002-2004, Instant802 Networks, Inc.
765cb46a3   Jouni Malinen   mac80211: 802.11w...
3
   * Copyright 2008, Jouni Malinen <j@w1.fi>
f0706e828   Jiri Benc   [MAC80211]: Add m...
4
5
6
7
8
9
10
11
   *
   * 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>
f0706e828   Jiri Benc   [MAC80211]: Add m...
12
13
  #include <linux/skbuff.h>
  #include <linux/compiler.h>
f14df8049   Harvey Harrison   mac80211: remove ...
14
  #include <linux/ieee80211.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/gfp.h>
f14df8049   Harvey Harrison   mac80211: remove ...
16
  #include <asm/unaligned.h>
f0706e828   Jiri Benc   [MAC80211]: Add m...
17
  #include <net/mac80211.h>
eb063c170   Johannes Berg   [MAC80211]: refac...
18

f0706e828   Jiri Benc   [MAC80211]: Add m...
19
20
21
22
  #include "ieee80211_i.h"
  #include "michael.h"
  #include "tkip.h"
  #include "aes_ccm.h"
765cb46a3   Jouni Malinen   mac80211: 802.11w...
23
  #include "aes_cmac.h"
f0706e828   Jiri Benc   [MAC80211]: Add m...
24
  #include "wpa.h"
9ae54c846   Johannes Berg   mac80211: split i...
25
  ieee80211_tx_result
5cf121c3c   Johannes Berg   mac80211: split i...
26
  ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
f0706e828   Jiri Benc   [MAC80211]: Add m...
27
  {
8e8862b79   Harvey Harrison   mac80211: remove ...
28
  	u8 *data, *key, *mic, key_offset;
f0706e828   Jiri Benc   [MAC80211]: Add m...
29
  	size_t data_len;
8e8862b79   Harvey Harrison   mac80211: remove ...
30
31
  	unsigned int hdrlen;
  	struct ieee80211_hdr *hdr;
f0706e828   Jiri Benc   [MAC80211]: Add m...
32
  	struct sk_buff *skb = tx->skb;
813d76694   Johannes Berg   mac80211: move co...
33
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
f0706e828   Jiri Benc   [MAC80211]: Add m...
34
  	int authenticator;
23c0752a2   Johannes Berg   mac80211: clean u...
35
  	int tail;
f0706e828   Jiri Benc   [MAC80211]: Add m...
36

c34498b9e   Harvey Harrison   mac80211: wpa.c r...
37
  	hdr = (struct ieee80211_hdr *)skb->data;
97359d123   Johannes Berg   mac80211: use cip...
38
39
  	if (!tx->key || tx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
  	    skb->len < 24 || !ieee80211_is_data_present(hdr->frame_control))
9ae54c846   Johannes Berg   mac80211: split i...
40
  		return TX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
41

8e8862b79   Harvey Harrison   mac80211: remove ...
42
43
  	hdrlen = ieee80211_hdrlen(hdr->frame_control);
  	if (skb->len < hdrlen)
9ae54c846   Johannes Berg   mac80211: split i...
44
  		return TX_DROP;
f0706e828   Jiri Benc   [MAC80211]: Add m...
45

8e8862b79   Harvey Harrison   mac80211: remove ...
46
47
  	data = skb->data + hdrlen;
  	data_len = skb->len - hdrlen;
813d76694   Johannes Berg   mac80211: move co...
48
  	if (info->control.hw_key &&
5cf121c3c   Johannes Berg   mac80211: split i...
49
  	    !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
813d76694   Johannes Berg   mac80211: move co...
50
51
  	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
  		/* hwaccel - with no need for SW-generated MMIC */
9ae54c846   Johannes Berg   mac80211: split i...
52
  		return TX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
53
  	}
23c0752a2   Johannes Berg   mac80211: clean u...
54
  	tail = MICHAEL_MIC_LEN;
813d76694   Johannes Berg   mac80211: move co...
55
  	if (!info->control.hw_key)
23c0752a2   Johannes Berg   mac80211: clean u...
56
57
58
59
60
  		tail += TKIP_ICV_LEN;
  
  	if (WARN_ON(skb_tailroom(skb) < tail ||
  		    skb_headroom(skb) < TKIP_IV_LEN))
  		return TX_DROP;
f0706e828   Jiri Benc   [MAC80211]: Add m...
61
62
63
64
65
66
  
  #if 0
  	authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
  #else
  	authenticator = 1;
  #endif
ffd7891dc   Luis R. Rodriguez   mac80211: Let dri...
67
68
69
70
  	key_offset = authenticator ?
  		NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY :
  		NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
  	key = &tx->key->conf.key[key_offset];
f0706e828   Jiri Benc   [MAC80211]: Add m...
71
  	mic = skb_put(skb, MICHAEL_MIC_LEN);
8e8862b79   Harvey Harrison   mac80211: remove ...
72
  	michael_mic(key, hdr, data, data_len, mic);
f0706e828   Jiri Benc   [MAC80211]: Add m...
73

9ae54c846   Johannes Berg   mac80211: split i...
74
  	return TX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
75
  }
9ae54c846   Johannes Berg   mac80211: split i...
76
  ieee80211_rx_result
5cf121c3c   Johannes Berg   mac80211: split i...
77
  ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
f0706e828   Jiri Benc   [MAC80211]: Add m...
78
  {
8e8862b79   Harvey Harrison   mac80211: remove ...
79
  	u8 *data, *key = NULL, key_offset;
f0706e828   Jiri Benc   [MAC80211]: Add m...
80
  	size_t data_len;
8e8862b79   Harvey Harrison   mac80211: remove ...
81
  	unsigned int hdrlen;
f0706e828   Jiri Benc   [MAC80211]: Add m...
82
83
  	u8 mic[MICHAEL_MIC_LEN];
  	struct sk_buff *skb = rx->skb;
eb9fb5b88   Johannes Berg   mac80211: trim RX...
84
85
  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
f0706e828   Jiri Benc   [MAC80211]: Add m...
86
  	int authenticator = 1, wpa_test = 0;
c6a1fa12d   Johannes Berg   mac80211: minor c...
87
  	/* No way to verify the MIC if the hardware stripped it */
eb9fb5b88   Johannes Berg   mac80211: trim RX...
88
  	if (status->flag & RX_FLAG_MMIC_STRIPPED)
9ae54c846   Johannes Berg   mac80211: split i...
89
  		return RX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
90

97359d123   Johannes Berg   mac80211: use cip...
91
  	if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
c34498b9e   Harvey Harrison   mac80211: wpa.c r...
92
93
  	    !ieee80211_has_protected(hdr->frame_control) ||
  	    !ieee80211_is_data_present(hdr->frame_control))
9ae54c846   Johannes Berg   mac80211: split i...
94
  		return RX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
95

8e8862b79   Harvey Harrison   mac80211: remove ...
96
97
  	hdrlen = ieee80211_hdrlen(hdr->frame_control);
  	if (skb->len < hdrlen + MICHAEL_MIC_LEN)
e4c26add8   Johannes Berg   mac80211: split R...
98
  		return RX_DROP_UNUSABLE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
99

8e8862b79   Harvey Harrison   mac80211: remove ...
100
101
  	data = skb->data + hdrlen;
  	data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
f0706e828   Jiri Benc   [MAC80211]: Add m...
102
103
104
105
106
107
  
  #if 0
  	authenticator = fc & IEEE80211_FCTL_TODS; /* FIX */
  #else
  	authenticator = 1;
  #endif
ffd7891dc   Luis R. Rodriguez   mac80211: Let dri...
108
109
110
111
  	key_offset = authenticator ?
  		NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY :
  		NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
  	key = &rx->key->conf.key[key_offset];
8e8862b79   Harvey Harrison   mac80211: remove ...
112
  	michael_mic(key, hdr, data, data_len, mic);
f0706e828   Jiri Benc   [MAC80211]: Add m...
113
  	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
554891e63   Johannes Berg   mac80211: move pa...
114
  		if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
e4c26add8   Johannes Berg   mac80211: split R...
115
  			return RX_DROP_UNUSABLE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
116

f698d856f   Jasper Bryant-Greene   replace net_devic...
117
  		mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
e6d6e3420   Johannes Berg   cfg80211: use pro...
118
119
  						(void *) skb->data, NULL,
  						GFP_ATOMIC);
e4c26add8   Johannes Berg   mac80211: split R...
120
  		return RX_DROP_UNUSABLE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
121
  	}
f0706e828   Jiri Benc   [MAC80211]: Add m...
122
123
  	/* remove Michael MIC from payload */
  	skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
50741ae05   Johannes Berg   [PATCH] mac80211:...
124
  	/* update IV in key information to be able to detect replays */
b0f76b335   Harvey Harrison   mac80211: add a s...
125
126
  	rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
  	rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
50741ae05   Johannes Berg   [PATCH] mac80211:...
127

9ae54c846   Johannes Berg   mac80211: split i...
128
  	return RX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
129
  }
e039fa4a4   Johannes Berg   mac80211: move TX...
130
  static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
f0706e828   Jiri Benc   [MAC80211]: Add m...
131
132
133
  {
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
  	struct ieee80211_key *key = tx->key;
e039fa4a4   Johannes Berg   mac80211: move TX...
134
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
d5184cacf   Harvey Harrison   mac80211: wpa.c u...
135
136
  	unsigned int hdrlen;
  	int len, tail;
f0706e828   Jiri Benc   [MAC80211]: Add m...
137
  	u8 *pos;
813d76694   Johannes Berg   mac80211: move co...
138
139
140
  	if (info->control.hw_key &&
  	    !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
  		/* hwaccel - with no need for software-generated IV */
23c0752a2   Johannes Berg   mac80211: clean u...
141
  		return 0;
e039fa4a4   Johannes Berg   mac80211: move TX...
142
  	}
d5184cacf   Harvey Harrison   mac80211: wpa.c u...
143
  	hdrlen = ieee80211_hdrlen(hdr->frame_control);
f0706e828   Jiri Benc   [MAC80211]: Add m...
144
  	len = skb->len - hdrlen;
813d76694   Johannes Berg   mac80211: move co...
145
  	if (info->control.hw_key)
23c0752a2   Johannes Berg   mac80211: clean u...
146
  		tail = 0;
11a843b7e   Johannes Berg   [MAC80211]: rewor...
147
  	else
23c0752a2   Johannes Berg   mac80211: clean u...
148
149
150
151
152
  		tail = TKIP_ICV_LEN;
  
  	if (WARN_ON(skb_tailroom(skb) < tail ||
  		    skb_headroom(skb) < TKIP_IV_LEN))
  		return -1;
f0706e828   Jiri Benc   [MAC80211]: Add m...
153
154
155
156
157
158
  
  	pos = skb_push(skb, TKIP_IV_LEN);
  	memmove(pos, pos + TKIP_IV_LEN, hdrlen);
  	pos += hdrlen;
  
  	/* Increase IV for the frame */
b0f76b335   Harvey Harrison   mac80211: add a s...
159
160
161
  	key->u.tkip.tx.iv16++;
  	if (key->u.tkip.tx.iv16 == 0)
  		key->u.tkip.tx.iv32++;
f0706e828   Jiri Benc   [MAC80211]: Add m...
162

813d76694   Johannes Berg   mac80211: move co...
163
  	pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16);
f0706e828   Jiri Benc   [MAC80211]: Add m...
164

813d76694   Johannes Berg   mac80211: move co...
165
166
  	/* hwaccel - with software IV */
  	if (info->control.hw_key)
f0706e828   Jiri Benc   [MAC80211]: Add m...
167
  		return 0;
f0706e828   Jiri Benc   [MAC80211]: Add m...
168
169
170
171
172
  
  	/* Add room for ICV */
  	skb_put(skb, TKIP_ICV_LEN);
  
  	hdr = (struct ieee80211_hdr *) skb->data;
3473187d2   John W. Linville   mac80211: remove ...
173
174
  	return ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
  					   key, pos, len, hdr->addr2);
f0706e828   Jiri Benc   [MAC80211]: Add m...
175
  }
9ae54c846   Johannes Berg   mac80211: split i...
176
  ieee80211_tx_result
5cf121c3c   Johannes Berg   mac80211: split i...
177
  ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
f0706e828   Jiri Benc   [MAC80211]: Add m...
178
  {
f0706e828   Jiri Benc   [MAC80211]: Add m...
179
  	struct sk_buff *skb = tx->skb;
f0706e828   Jiri Benc   [MAC80211]: Add m...
180

5cf121c3c   Johannes Berg   mac80211: split i...
181
  	ieee80211_tx_set_protected(tx);
f0706e828   Jiri Benc   [MAC80211]: Add m...
182

2de8e0d99   Johannes Berg   mac80211: rewrite...
183
184
185
186
  	do {
  		if (tkip_encrypt_skb(tx, skb) < 0)
  			return TX_DROP;
  	} while ((skb = skb->next));
f0706e828   Jiri Benc   [MAC80211]: Add m...
187

9ae54c846   Johannes Berg   mac80211: split i...
188
  	return TX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
189
  }
9ae54c846   Johannes Berg   mac80211: split i...
190
  ieee80211_rx_result
5cf121c3c   Johannes Berg   mac80211: split i...
191
  ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
f0706e828   Jiri Benc   [MAC80211]: Add m...
192
193
  {
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
f0706e828   Jiri Benc   [MAC80211]: Add m...
194
195
196
  	int hdrlen, res, hwaccel = 0, wpa_test = 0;
  	struct ieee80211_key *key = rx->key;
  	struct sk_buff *skb = rx->skb;
eb9fb5b88   Johannes Berg   mac80211: trim RX...
197
  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
f0706e828   Jiri Benc   [MAC80211]: Add m...
198

d5184cacf   Harvey Harrison   mac80211: wpa.c u...
199
  	hdrlen = ieee80211_hdrlen(hdr->frame_control);
f0706e828   Jiri Benc   [MAC80211]: Add m...
200

c34498b9e   Harvey Harrison   mac80211: wpa.c r...
201
  	if (!ieee80211_is_data(hdr->frame_control))
9ae54c846   Johannes Berg   mac80211: split i...
202
  		return RX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
203
204
  
  	if (!rx->sta || skb->len - hdrlen < 12)
e4c26add8   Johannes Berg   mac80211: split R...
205
  		return RX_DROP_UNUSABLE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
206

dc1580ddf   Johannes Berg   mac80211: remove ...
207
208
209
210
211
212
  	/*
  	 * 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)
f0706e828   Jiri Benc   [MAC80211]: Add m...
213
  		hwaccel = 1;
f0706e828   Jiri Benc   [MAC80211]: Add m...
214
215
216
  
  	res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
  					  key, skb->data + hdrlen,
17741cdc2   Johannes Berg   mac80211: share S...
217
  					  skb->len - hdrlen, rx->sta->sta.addr,
9ae4fda33   Emmanuel Grumbach   mac80211: allows ...
218
  					  hdr->addr1, hwaccel, rx->queue,
5cf121c3c   Johannes Berg   mac80211: split i...
219
220
  					  &rx->tkip_iv32,
  					  &rx->tkip_iv16);
f4ea83dd7   Johannes Berg   mac80211: rework ...
221
  	if (res != TKIP_DECRYPT_OK || wpa_test)
e4c26add8   Johannes Berg   mac80211: split R...
222
  		return RX_DROP_UNUSABLE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
223
224
225
226
227
228
229
  
  	/* 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);
9ae54c846   Johannes Berg   mac80211: split i...
230
  	return RX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
231
  }
feccb4669   Harvey Harrison   mac80211: pass sc...
232
  static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *scratch,
f0706e828   Jiri Benc   [MAC80211]: Add m...
233
234
  				int encrypted)
  {
f14df8049   Harvey Harrison   mac80211: remove ...
235
  	__le16 mask_fc;
fb7333367   Jouni Malinen   mac80211: 802.11w...
236
  	int a4_included, mgmt;
f14df8049   Harvey Harrison   mac80211: remove ...
237
  	u8 qos_tid;
feccb4669   Harvey Harrison   mac80211: pass sc...
238
  	u8 *b_0, *aad;
f14df8049   Harvey Harrison   mac80211: remove ...
239
240
241
  	u16 data_len, len_a;
  	unsigned int hdrlen;
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
f0706e828   Jiri Benc   [MAC80211]: Add m...
242

feccb4669   Harvey Harrison   mac80211: pass sc...
243
244
  	b_0 = scratch + 3 * AES_BLOCK_LEN;
  	aad = scratch + 4 * AES_BLOCK_LEN;
f14df8049   Harvey Harrison   mac80211: remove ...
245
  	/*
fb7333367   Jouni Malinen   mac80211: 802.11w...
246
  	 * Mask FC: zero subtype b4 b5 b6 (if not mgmt)
f14df8049   Harvey Harrison   mac80211: remove ...
247
248
  	 * Retry, PwrMgt, MoreData; set Protected
  	 */
fb7333367   Jouni Malinen   mac80211: 802.11w...
249
  	mgmt = ieee80211_is_mgmt(hdr->frame_control);
f14df8049   Harvey Harrison   mac80211: remove ...
250
  	mask_fc = hdr->frame_control;
fb7333367   Jouni Malinen   mac80211: 802.11w...
251
  	mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY |
f14df8049   Harvey Harrison   mac80211: remove ...
252
  				IEEE80211_FCTL_PM | IEEE80211_FCTL_MOREDATA);
fb7333367   Jouni Malinen   mac80211: 802.11w...
253
254
  	if (!mgmt)
  		mask_fc &= ~cpu_to_le16(0x0070);
f14df8049   Harvey Harrison   mac80211: remove ...
255
256
257
258
259
  	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);
f0706e828   Jiri Benc   [MAC80211]: Add m...
260

f14df8049   Harvey Harrison   mac80211: remove ...
261
262
263
264
265
266
267
268
269
270
  	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 */
f0706e828   Jiri Benc   [MAC80211]: Add m...
271
  	b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
fb7333367   Jouni Malinen   mac80211: 802.11w...
272
273
274
275
  	/* Nonce: Nonce Flags | A2 | PN
  	 * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
  	 */
  	b_0[1] = qos_tid | (mgmt << 4);
73e1f7c82   Harvey Harrison   mac80211: use sym...
276
  	memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
f0706e828   Jiri Benc   [MAC80211]: Add m...
277
278
  	memcpy(&b_0[8], pn, CCMP_PN_LEN);
  	/* l(m) */
f14df8049   Harvey Harrison   mac80211: remove ...
279
  	put_unaligned_be16(data_len, &b_0[14]);
f0706e828   Jiri Benc   [MAC80211]: Add m...
280
281
282
  
  	/* AAD (extra authenticate-only data) / masked 802.11 header
  	 * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
f14df8049   Harvey Harrison   mac80211: remove ...
283
284
  	put_unaligned_be16(len_a, &aad[0]);
  	put_unaligned(mask_fc, (__le16 *)&aad[2]);
73e1f7c82   Harvey Harrison   mac80211: use sym...
285
  	memcpy(&aad[4], &hdr->addr1, 3 * ETH_ALEN);
f0706e828   Jiri Benc   [MAC80211]: Add m...
286
287
288
289
  
  	/* Mask Seq#, leave Frag# */
  	aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
  	aad[23] = 0;
f14df8049   Harvey Harrison   mac80211: remove ...
290

f0706e828   Jiri Benc   [MAC80211]: Add m...
291
  	if (a4_included) {
73e1f7c82   Harvey Harrison   mac80211: use sym...
292
  		memcpy(&aad[24], hdr->addr4, ETH_ALEN);
f14df8049   Harvey Harrison   mac80211: remove ...
293
  		aad[30] = qos_tid;
f0706e828   Jiri Benc   [MAC80211]: Add m...
294
  		aad[31] = 0;
f14df8049   Harvey Harrison   mac80211: remove ...
295
  	} else {
73e1f7c82   Harvey Harrison   mac80211: use sym...
296
  		memset(&aad[24], 0, ETH_ALEN + IEEE80211_QOS_CTL_LEN);
f14df8049   Harvey Harrison   mac80211: remove ...
297
  		aad[24] = qos_tid;
f0706e828   Jiri Benc   [MAC80211]: Add m...
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
  	}
  }
  
  
  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];
  }
c6a1fa12d   Johannes Berg   mac80211: minor c...
313
  static inline void ccmp_hdr2pn(u8 *pn, u8 *hdr)
f0706e828   Jiri Benc   [MAC80211]: Add m...
314
315
316
317
318
319
320
  {
  	pn[0] = hdr[7];
  	pn[1] = hdr[6];
  	pn[2] = hdr[5];
  	pn[3] = hdr[4];
  	pn[4] = hdr[1];
  	pn[5] = hdr[0];
f0706e828   Jiri Benc   [MAC80211]: Add m...
321
  }
e039fa4a4   Johannes Berg   mac80211: move TX...
322
  static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
f0706e828   Jiri Benc   [MAC80211]: Add m...
323
324
325
  {
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
  	struct ieee80211_key *key = tx->key;
e039fa4a4   Johannes Berg   mac80211: move TX...
326
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
23c0752a2   Johannes Berg   mac80211: clean u...
327
  	int hdrlen, len, tail;
feccb4669   Harvey Harrison   mac80211: pass sc...
328
  	u8 *pos, *pn;
f0706e828   Jiri Benc   [MAC80211]: Add m...
329
  	int i;
813d76694   Johannes Berg   mac80211: move co...
330
331
332
333
334
335
  	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
  		 */
23c0752a2   Johannes Berg   mac80211: clean u...
336
  		return 0;
e039fa4a4   Johannes Berg   mac80211: move TX...
337
  	}
d5184cacf   Harvey Harrison   mac80211: wpa.c u...
338
  	hdrlen = ieee80211_hdrlen(hdr->frame_control);
f0706e828   Jiri Benc   [MAC80211]: Add m...
339
  	len = skb->len - hdrlen;
813d76694   Johannes Berg   mac80211: move co...
340
  	if (info->control.hw_key)
23c0752a2   Johannes Berg   mac80211: clean u...
341
  		tail = 0;
11a843b7e   Johannes Berg   [MAC80211]: rewor...
342
  	else
23c0752a2   Johannes Berg   mac80211: clean u...
343
344
345
346
347
  		tail = CCMP_MIC_LEN;
  
  	if (WARN_ON(skb_tailroom(skb) < tail ||
  		    skb_headroom(skb) < CCMP_HDR_LEN))
  		return -1;
f0706e828   Jiri Benc   [MAC80211]: Add m...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
  
  	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;
  	}
8f20fc249   Johannes Berg   [MAC80211]: embed...
362
  	ccmp_pn2hdr(pos, pn, key->conf.keyidx);
f0706e828   Jiri Benc   [MAC80211]: Add m...
363

813d76694   Johannes Berg   mac80211: move co...
364
365
  	/* hwaccel - with software CCMP header */
  	if (info->control.hw_key)
f0706e828   Jiri Benc   [MAC80211]: Add m...
366
  		return 0;
f0706e828   Jiri Benc   [MAC80211]: Add m...
367
368
  
  	pos += CCMP_HDR_LEN;
feccb4669   Harvey Harrison   mac80211: pass sc...
369
370
  	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,
f0706e828   Jiri Benc   [MAC80211]: Add m...
371
372
373
374
  				  pos, skb_put(skb, CCMP_MIC_LEN));
  
  	return 0;
  }
9ae54c846   Johannes Berg   mac80211: split i...
375
  ieee80211_tx_result
5cf121c3c   Johannes Berg   mac80211: split i...
376
  ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
f0706e828   Jiri Benc   [MAC80211]: Add m...
377
  {
f0706e828   Jiri Benc   [MAC80211]: Add m...
378
  	struct sk_buff *skb = tx->skb;
f0706e828   Jiri Benc   [MAC80211]: Add m...
379

5cf121c3c   Johannes Berg   mac80211: split i...
380
  	ieee80211_tx_set_protected(tx);
f0706e828   Jiri Benc   [MAC80211]: Add m...
381

2de8e0d99   Johannes Berg   mac80211: rewrite...
382
383
384
385
  	do {
  		if (ccmp_encrypt_skb(tx, skb) < 0)
  			return TX_DROP;
  	} while ((skb = skb->next));
f0706e828   Jiri Benc   [MAC80211]: Add m...
386

9ae54c846   Johannes Berg   mac80211: split i...
387
  	return TX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
388
  }
9ae54c846   Johannes Berg   mac80211: split i...
389
  ieee80211_rx_result
5cf121c3c   Johannes Berg   mac80211: split i...
390
  ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
f0706e828   Jiri Benc   [MAC80211]: Add m...
391
  {
c34498b9e   Harvey Harrison   mac80211: wpa.c r...
392
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
f0706e828   Jiri Benc   [MAC80211]: Add m...
393
394
395
  	int hdrlen;
  	struct ieee80211_key *key = rx->key;
  	struct sk_buff *skb = rx->skb;
eb9fb5b88   Johannes Berg   mac80211: trim RX...
396
  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
f0706e828   Jiri Benc   [MAC80211]: Add m...
397
398
  	u8 pn[CCMP_PN_LEN];
  	int data_len;
9190252c9   Jouni Malinen   mac80211: Use a s...
399
  	int queue;
f0706e828   Jiri Benc   [MAC80211]: Add m...
400

d5184cacf   Harvey Harrison   mac80211: wpa.c u...
401
  	hdrlen = ieee80211_hdrlen(hdr->frame_control);
f0706e828   Jiri Benc   [MAC80211]: Add m...
402

fb7333367   Jouni Malinen   mac80211: 802.11w...
403
404
  	if (!ieee80211_is_data(hdr->frame_control) &&
  	    !ieee80211_is_robust_mgmt_frame(hdr))
9ae54c846   Johannes Berg   mac80211: split i...
405
  		return RX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
406
407
408
  
  	data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
  	if (!rx->sta || data_len < 0)
e4c26add8   Johannes Berg   mac80211: split R...
409
  		return RX_DROP_UNUSABLE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
410

c6a1fa12d   Johannes Berg   mac80211: minor c...
411
  	ccmp_hdr2pn(pn, skb->data + hdrlen);
f0706e828   Jiri Benc   [MAC80211]: Add m...
412

9190252c9   Jouni Malinen   mac80211: Use a s...
413
414
415
416
  	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) {
f0706e828   Jiri Benc   [MAC80211]: Add m...
417
  		key->u.ccmp.replays++;
e4c26add8   Johannes Berg   mac80211: split R...
418
  		return RX_DROP_UNUSABLE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
419
  	}
eb9fb5b88   Johannes Berg   mac80211: trim RX...
420
  	if (!(status->flag & RX_FLAG_DECRYPTED)) {
7848ba7d7   Johannes Berg   [MAC80211]: rewor...
421
  		/* hardware didn't decrypt/verify MIC */
feccb4669   Harvey Harrison   mac80211: pass sc...
422
  		ccmp_special_blocks(skb, pn, key->u.ccmp.rx_crypto_buf, 1);
f0706e828   Jiri Benc   [MAC80211]: Add m...
423
424
  
  		if (ieee80211_aes_ccm_decrypt(
feccb4669   Harvey Harrison   mac80211: pass sc...
425
  			    key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf,
f0706e828   Jiri Benc   [MAC80211]: Add m...
426
427
  			    skb->data + hdrlen + CCMP_HDR_LEN, data_len,
  			    skb->data + skb->len - CCMP_MIC_LEN,
c6a1fa12d   Johannes Berg   mac80211: minor c...
428
  			    skb->data + hdrlen + CCMP_HDR_LEN))
e4c26add8   Johannes Berg   mac80211: split R...
429
  			return RX_DROP_UNUSABLE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
430
  	}
9190252c9   Jouni Malinen   mac80211: Use a s...
431
  	memcpy(key->u.ccmp.rx_pn[queue], pn, CCMP_PN_LEN);
f0706e828   Jiri Benc   [MAC80211]: Add m...
432
433
434
435
436
  
  	/* 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);
9ae54c846   Johannes Berg   mac80211: split i...
437
  	return RX_CONTINUE;
f0706e828   Jiri Benc   [MAC80211]: Add m...
438
  }
765cb46a3   Jouni Malinen   mac80211: 802.11w...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  
  
  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;
813d76694   Johannes Berg   mac80211: move co...
474
  	if (info->control.hw_key)
765cb46a3   Jouni Malinen   mac80211: 802.11w...
475
  		return 0;
765cb46a3   Jouni Malinen   mac80211: 802.11w...
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  
  	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;
eb9fb5b88   Johannes Berg   mac80211: trim RX...
511
  	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
765cb46a3   Jouni Malinen   mac80211: 802.11w...
512
513
514
515
516
517
518
  	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;
765cb46a3   Jouni Malinen   mac80211: 802.11w...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
  	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;
  	}
eb9fb5b88   Johannes Berg   mac80211: trim RX...
534
  	if (!(status->flag & RX_FLAG_DECRYPTED)) {
765cb46a3   Jouni Malinen   mac80211: 802.11w...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
  		/* 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;
  }