]>
Commit | Line | Data |
---|---|---|
2d73f0a8 JM |
1 | /* |
2 | * Received Data frame processing | |
3 | * Copyright (c) 2010, Jouni Malinen <j@w1.fi> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
15 | #include "utils/includes.h" | |
16 | ||
17 | #include "utils/common.h" | |
8672562b JM |
18 | #include "crypto/aes_wrap.h" |
19 | #include "crypto/crypto.h" | |
2d73f0a8 | 20 | #include "common/ieee802_11_defs.h" |
32234bba JM |
21 | #include "common/eapol_common.h" |
22 | #include "common/wpa_common.h" | |
4d9f9ee7 | 23 | #include "rsn_supp/wpa_ie.h" |
2d73f0a8 JM |
24 | #include "wlantest.h" |
25 | ||
26 | ||
27 | static const char * data_stype(u16 stype) | |
28 | { | |
29 | switch (stype) { | |
30 | case WLAN_FC_STYPE_DATA: | |
31 | return "DATA"; | |
32 | case WLAN_FC_STYPE_DATA_CFACK: | |
33 | return "DATA-CFACK"; | |
34 | case WLAN_FC_STYPE_DATA_CFPOLL: | |
35 | return "DATA-CFPOLL"; | |
36 | case WLAN_FC_STYPE_DATA_CFACKPOLL: | |
37 | return "DATA-CFACKPOLL"; | |
38 | case WLAN_FC_STYPE_NULLFUNC: | |
39 | return "NULLFUNC"; | |
40 | case WLAN_FC_STYPE_CFACK: | |
41 | return "CFACK"; | |
42 | case WLAN_FC_STYPE_CFPOLL: | |
43 | return "CFPOLL"; | |
44 | case WLAN_FC_STYPE_CFACKPOLL: | |
45 | return "CFACKPOLL"; | |
46 | case WLAN_FC_STYPE_QOS_DATA: | |
47 | return "QOSDATA"; | |
48 | case WLAN_FC_STYPE_QOS_DATA_CFACK: | |
49 | return "QOSDATA-CFACK"; | |
50 | case WLAN_FC_STYPE_QOS_DATA_CFPOLL: | |
51 | return "QOSDATA-CFPOLL"; | |
52 | case WLAN_FC_STYPE_QOS_DATA_CFACKPOLL: | |
53 | return "QOSDATA-CFACKPOLL"; | |
54 | case WLAN_FC_STYPE_QOS_NULL: | |
55 | return "QOS-NULL"; | |
56 | case WLAN_FC_STYPE_QOS_CFPOLL: | |
57 | return "QOS-CFPOLL"; | |
58 | case WLAN_FC_STYPE_QOS_CFACKPOLL: | |
59 | return "QOS-CFACKPOLL"; | |
60 | } | |
61 | return "??"; | |
62 | } | |
63 | ||
64 | ||
53650bca JM |
65 | static int check_mic(const u8 *kck, int ver, const u8 *data, size_t len) |
66 | { | |
67 | u8 *buf; | |
68 | int ret = -1; | |
69 | struct ieee802_1x_hdr *hdr; | |
70 | struct wpa_eapol_key *key; | |
71 | u8 rx_mic[16]; | |
72 | ||
73 | buf = os_malloc(len); | |
74 | if (buf == NULL) | |
75 | return -1; | |
76 | os_memcpy(buf, data, len); | |
77 | hdr = (struct ieee802_1x_hdr *) buf; | |
78 | key = (struct wpa_eapol_key *) (hdr + 1); | |
79 | ||
80 | os_memcpy(rx_mic, key->key_mic, 16); | |
81 | os_memset(key->key_mic, 0, 16); | |
82 | ||
83 | if (wpa_eapol_key_mic(kck, ver, buf, len, key->key_mic) == 0 && | |
84 | os_memcmp(rx_mic, key->key_mic, 16) == 0) | |
85 | ret = 0; | |
86 | ||
87 | os_free(buf); | |
88 | ||
89 | return ret; | |
90 | } | |
91 | ||
92 | ||
32234bba JM |
93 | static void rx_data_eapol_key_1_of_4(struct wlantest *wt, const u8 *dst, |
94 | const u8 *src, const u8 *data, size_t len) | |
95 | { | |
53650bca JM |
96 | struct wlantest_bss *bss; |
97 | struct wlantest_sta *sta; | |
98 | const struct ieee802_1x_hdr *eapol; | |
99 | const struct wpa_eapol_key *hdr; | |
100 | ||
32234bba JM |
101 | wpa_printf(MSG_DEBUG, "EAPOL-Key 1/4 " MACSTR " -> " MACSTR, |
102 | MAC2STR(src), MAC2STR(dst)); | |
53650bca JM |
103 | bss = bss_get(wt, src); |
104 | if (bss == NULL) | |
105 | return; | |
106 | sta = sta_get(bss, dst); | |
107 | if (sta == NULL) | |
108 | return; | |
109 | ||
110 | eapol = (const struct ieee802_1x_hdr *) data; | |
111 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
112 | os_memcpy(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN); | |
113 | } | |
114 | ||
115 | ||
d06df64d JM |
116 | static int try_pmk(struct wlantest_bss *bss, struct wlantest_sta *sta, |
117 | u16 ver, const u8 *data, size_t len, | |
118 | struct wlantest_pmk *pmk) | |
119 | { | |
120 | struct wpa_ptk ptk; | |
121 | size_t ptk_len = 48; /* FIX: 64 for TKIP */ | |
122 | wpa_pmk_to_ptk(pmk->pmk, sizeof(pmk->pmk), | |
123 | "Pairwise key expansion", | |
124 | bss->bssid, sta->addr, sta->anonce, sta->snonce, | |
125 | (u8 *) &ptk, ptk_len, | |
126 | 0 /* FIX: SHA256 based on AKM */); | |
c09caa58 | 127 | if (check_mic(ptk.kck, ver, data, len) < 0) |
d06df64d JM |
128 | return -1; |
129 | ||
c09caa58 JM |
130 | wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID " MACSTR, |
131 | MAC2STR(sta->addr), MAC2STR(bss->bssid)); | |
d06df64d | 132 | os_memcpy(&sta->ptk, &ptk, sizeof(ptk)); |
c09caa58 JM |
133 | wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16); |
134 | wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16); | |
135 | wpa_hexdump(MSG_DEBUG, "PTK:TK1", sta->ptk.tk1, 16); | |
136 | if (ptk_len > 48) | |
137 | wpa_hexdump(MSG_DEBUG, "PTK:TK2", sta->ptk.u.tk2, 16); | |
d06df64d | 138 | sta->ptk_set = 1; |
2edd5c23 JM |
139 | os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods)); |
140 | os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds)); | |
d06df64d JM |
141 | return 0; |
142 | } | |
143 | ||
144 | ||
145 | static void derive_ptk(struct wlantest *wt, struct wlantest_bss *bss, | |
146 | struct wlantest_sta *sta, u16 ver, | |
147 | const u8 *data, size_t len) | |
53650bca JM |
148 | { |
149 | struct wlantest_pmk *pmk; | |
150 | ||
151 | dl_list_for_each(pmk, &bss->pmk, struct wlantest_pmk, list) { | |
d06df64d JM |
152 | if (try_pmk(bss, sta, ver, data, len, pmk) == 0) |
153 | return; | |
154 | } | |
155 | ||
156 | dl_list_for_each(pmk, &wt->pmk, struct wlantest_pmk, list) { | |
157 | if (try_pmk(bss, sta, ver, data, len, pmk) == 0) | |
158 | return; | |
53650bca | 159 | } |
32234bba JM |
160 | } |
161 | ||
162 | ||
163 | static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst, | |
164 | const u8 *src, const u8 *data, size_t len) | |
165 | { | |
53650bca JM |
166 | struct wlantest_bss *bss; |
167 | struct wlantest_sta *sta; | |
168 | const struct ieee802_1x_hdr *eapol; | |
169 | const struct wpa_eapol_key *hdr; | |
f0a78297 JM |
170 | const u8 *key_data; |
171 | u16 key_info, key_data_len; | |
172 | struct wpa_eapol_ie_parse ie; | |
53650bca | 173 | |
32234bba JM |
174 | wpa_printf(MSG_DEBUG, "EAPOL-Key 2/4 " MACSTR " -> " MACSTR, |
175 | MAC2STR(src), MAC2STR(dst)); | |
53650bca JM |
176 | bss = bss_get(wt, dst); |
177 | if (bss == NULL) | |
178 | return; | |
179 | sta = sta_get(bss, src); | |
180 | if (sta == NULL) | |
181 | return; | |
182 | ||
183 | eapol = (const struct ieee802_1x_hdr *) data; | |
184 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
185 | os_memcpy(sta->snonce, hdr->key_nonce, WPA_NONCE_LEN); | |
186 | key_info = WPA_GET_BE16(hdr->key_info); | |
f0a78297 | 187 | key_data_len = WPA_GET_BE16(hdr->key_data_length); |
d06df64d | 188 | derive_ptk(wt, bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, data, len); |
f0a78297 JM |
189 | |
190 | if (!sta->ptk_set) { | |
191 | wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 2/4"); | |
192 | return; | |
193 | } | |
194 | ||
195 | if (check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK, | |
196 | data, len) < 0) { | |
197 | wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 2/4 MIC"); | |
198 | return; | |
199 | } | |
200 | wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 2/4"); | |
201 | ||
202 | key_data = (const u8 *) (hdr + 1); | |
203 | ||
204 | if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) { | |
205 | wpa_printf(MSG_INFO, "Failed to parse EAPOL-Key Key Data"); | |
206 | return; | |
207 | } | |
208 | ||
209 | if (ie.wpa_ie) { | |
210 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - WPA IE", | |
211 | ie.wpa_ie, ie.wpa_ie_len); | |
212 | } | |
213 | ||
214 | if (ie.rsn_ie) { | |
215 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - RSN IE", | |
216 | ie.rsn_ie, ie.rsn_ie_len); | |
217 | } | |
32234bba JM |
218 | } |
219 | ||
220 | ||
8672562b JM |
221 | static u8 * decrypt_eapol_key_data_rc4(const u8 *kek, |
222 | const struct wpa_eapol_key *hdr, | |
223 | size_t *len) | |
224 | { | |
225 | u8 ek[32], *buf; | |
226 | u16 keydatalen = WPA_GET_BE16(hdr->key_data_length); | |
227 | ||
228 | buf = os_malloc(keydatalen); | |
229 | if (buf == NULL) | |
230 | return NULL; | |
231 | ||
232 | os_memcpy(ek, hdr->key_iv, 16); | |
233 | os_memcpy(ek + 16, kek, 16); | |
234 | os_memcpy(buf, hdr + 1, keydatalen); | |
235 | if (rc4_skip(ek, 32, 256, buf, keydatalen)) { | |
236 | wpa_printf(MSG_INFO, "RC4 failed"); | |
237 | os_free(buf); | |
238 | return NULL; | |
239 | } | |
240 | ||
241 | *len = keydatalen; | |
242 | return buf; | |
243 | } | |
244 | ||
245 | ||
246 | static u8 * decrypt_eapol_key_data_aes(const u8 *kek, | |
247 | const struct wpa_eapol_key *hdr, | |
248 | size_t *len) | |
249 | { | |
250 | u8 *buf; | |
251 | u16 keydatalen = WPA_GET_BE16(hdr->key_data_length); | |
252 | ||
253 | if (keydatalen % 8) { | |
254 | wpa_printf(MSG_INFO, "Unsupported AES-WRAP len %d", | |
255 | keydatalen); | |
256 | return NULL; | |
257 | } | |
258 | keydatalen -= 8; /* AES-WRAP adds 8 bytes */ | |
259 | buf = os_malloc(keydatalen); | |
260 | if (buf == NULL) | |
261 | return NULL; | |
262 | if (aes_unwrap(kek, keydatalen / 8, (u8 *) (hdr + 1), buf)) { | |
263 | os_free(buf); | |
264 | wpa_printf(MSG_INFO, "AES unwrap failed - " | |
265 | "could not decrypt EAPOL-Key key data"); | |
266 | return NULL; | |
267 | } | |
268 | ||
269 | *len = keydatalen; | |
270 | return buf; | |
271 | } | |
272 | ||
273 | ||
274 | static u8 * decrypt_eapol_key_data(const u8 *kek, u16 ver, | |
275 | const struct wpa_eapol_key *hdr, | |
276 | size_t *len) | |
277 | { | |
278 | switch (ver) { | |
279 | case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4: | |
280 | return decrypt_eapol_key_data_rc4(kek, hdr, len); | |
281 | case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES: | |
282 | case WPA_KEY_INFO_TYPE_AES_128_CMAC: | |
283 | return decrypt_eapol_key_data_aes(kek, hdr, len); | |
284 | default: | |
285 | wpa_printf(MSG_INFO, "Unsupported EAPOL-Key Key Descriptor " | |
286 | "Version %u", ver); | |
287 | return NULL; | |
288 | } | |
289 | } | |
290 | ||
291 | ||
2edd5c23 JM |
292 | static void learn_kde_keys(struct wlantest_bss *bss, u8 *buf, size_t len, |
293 | const u8 *rsc) | |
4d9f9ee7 JM |
294 | { |
295 | struct wpa_eapol_ie_parse ie; | |
296 | ||
297 | if (wpa_supplicant_parse_ies(buf, len, &ie) < 0) { | |
298 | wpa_printf(MSG_INFO, "Failed to parse EAPOL-Key Key Data"); | |
299 | return; | |
300 | } | |
301 | ||
302 | if (ie.wpa_ie) { | |
303 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - WPA IE", | |
304 | ie.wpa_ie, ie.wpa_ie_len); | |
305 | } | |
306 | ||
307 | if (ie.rsn_ie) { | |
308 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - RSN IE", | |
309 | ie.rsn_ie, ie.rsn_ie_len); | |
310 | } | |
311 | ||
312 | if (ie.gtk) { | |
313 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - GTK KDE", | |
314 | ie.gtk, ie.gtk_len); | |
315 | if (ie.gtk_len >= 2 && ie.gtk_len <= 2 + 32) { | |
316 | int id; | |
317 | id = ie.gtk[0] & 0x03; | |
c09caa58 | 318 | wpa_printf(MSG_DEBUG, "GTK KeyID=%u tx=%u", |
4d9f9ee7 JM |
319 | id, !!(ie.gtk[0] & 0x04)); |
320 | if ((ie.gtk[0] & 0xf8) || ie.gtk[1]) | |
321 | wpa_printf(MSG_INFO, "GTK KDE: Reserved field " | |
322 | "set: %02x %02x", | |
323 | ie.gtk[0], ie.gtk[1]); | |
324 | wpa_hexdump(MSG_DEBUG, "GTK", ie.gtk + 2, | |
325 | ie.gtk_len - 2); | |
326 | bss->gtk_len[id] = ie.gtk_len - 2; | |
327 | os_memcpy(bss->gtk[id], ie.gtk + 2, ie.gtk_len - 2); | |
2edd5c23 JM |
328 | bss->rsc[id][0] = rsc[5]; |
329 | bss->rsc[id][1] = rsc[4]; | |
330 | bss->rsc[id][2] = rsc[3]; | |
331 | bss->rsc[id][3] = rsc[2]; | |
332 | bss->rsc[id][4] = rsc[1]; | |
333 | bss->rsc[id][5] = rsc[0]; | |
334 | wpa_hexdump(MSG_DEBUG, "RSC", bss->rsc[id], 6); | |
4d9f9ee7 JM |
335 | } else { |
336 | wpa_printf(MSG_INFO, "Invalid GTK KDE length %u", | |
337 | (unsigned) ie.gtk_len); | |
338 | } | |
339 | } | |
340 | ||
341 | if (ie.igtk) { | |
342 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - IGTK KDE", | |
343 | ie.igtk, ie.igtk_len); | |
344 | if (ie.igtk_len == 24) { | |
345 | u16 id; | |
346 | id = WPA_GET_LE16(ie.igtk); | |
347 | if (id > 5) { | |
348 | wpa_printf(MSG_INFO, "Unexpected IGTK KeyID " | |
349 | "%u", id); | |
350 | } else { | |
c09caa58 JM |
351 | wpa_printf(MSG_DEBUG, "IGTK KeyID %u", id); |
352 | wpa_hexdump(MSG_DEBUG, "IPN", ie.igtk + 2, 6); | |
353 | wpa_hexdump(MSG_DEBUG, "IGTK", ie.igtk + 8, | |
354 | 16); | |
4d9f9ee7 JM |
355 | os_memcpy(bss->igtk[id], ie.igtk + 8, 16); |
356 | bss->igtk_set[id] = 1; | |
357 | } | |
358 | } else { | |
359 | wpa_printf(MSG_INFO, "Invalid IGTK KDE length %u", | |
360 | (unsigned) ie.igtk_len); | |
361 | } | |
362 | } | |
363 | } | |
364 | ||
365 | ||
32234bba JM |
366 | static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst, |
367 | const u8 *src, const u8 *data, size_t len) | |
368 | { | |
53650bca JM |
369 | struct wlantest_bss *bss; |
370 | struct wlantest_sta *sta; | |
371 | const struct ieee802_1x_hdr *eapol; | |
372 | const struct wpa_eapol_key *hdr; | |
8672562b | 373 | const u8 *key_data; |
53650bca | 374 | int recalc = 0; |
5db8cf31 | 375 | u16 key_info, ver; |
8672562b JM |
376 | u8 *decrypted; |
377 | size_t decrypted_len = 0; | |
53650bca | 378 | |
32234bba JM |
379 | wpa_printf(MSG_DEBUG, "EAPOL-Key 3/4 " MACSTR " -> " MACSTR, |
380 | MAC2STR(src), MAC2STR(dst)); | |
53650bca JM |
381 | bss = bss_get(wt, src); |
382 | if (bss == NULL) | |
383 | return; | |
384 | sta = sta_get(bss, dst); | |
385 | if (sta == NULL) | |
386 | return; | |
387 | ||
388 | eapol = (const struct ieee802_1x_hdr *) data; | |
389 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
390 | key_info = WPA_GET_BE16(hdr->key_info); | |
8672562b | 391 | |
53650bca JM |
392 | if (os_memcmp(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN) != 0) { |
393 | wpa_printf(MSG_INFO, "EAPOL-Key ANonce mismatch between 1/4 " | |
394 | "and 3/4"); | |
395 | recalc = 1; | |
396 | } | |
397 | os_memcpy(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN); | |
398 | if (recalc) { | |
d06df64d | 399 | derive_ptk(wt, bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, |
53650bca JM |
400 | data, len); |
401 | } | |
402 | ||
403 | if (!sta->ptk_set) { | |
404 | wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 3/4"); | |
405 | return; | |
406 | } | |
407 | ||
408 | if (check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK, | |
409 | data, len) < 0) { | |
410 | wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 3/4 MIC"); | |
411 | return; | |
412 | } | |
413 | wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 3/4"); | |
414 | ||
8672562b JM |
415 | key_data = (const u8 *) (hdr + 1); |
416 | /* TODO: handle WPA without EncrKeyData bit */ | |
417 | if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { | |
418 | wpa_printf(MSG_INFO, "EAPOL-Key 3/4 without EncrKeyData bit"); | |
419 | return; | |
420 | } | |
421 | ver = key_info & WPA_KEY_INFO_TYPE_MASK; | |
422 | decrypted = decrypt_eapol_key_data(sta->ptk.kek, ver, hdr, | |
423 | &decrypted_len); | |
424 | if (decrypted == NULL) { | |
425 | wpa_printf(MSG_INFO, "Failed to decrypt EAPOL-Key Key Data"); | |
426 | return; | |
427 | } | |
428 | wpa_hexdump(MSG_DEBUG, "Decrypted EAPOL-Key Key Data", | |
429 | decrypted, decrypted_len); | |
2edd5c23 | 430 | learn_kde_keys(bss, decrypted, decrypted_len, hdr->key_rsc); |
8672562b | 431 | os_free(decrypted); |
32234bba JM |
432 | } |
433 | ||
434 | ||
435 | static void rx_data_eapol_key_4_of_4(struct wlantest *wt, const u8 *dst, | |
436 | const u8 *src, const u8 *data, size_t len) | |
437 | { | |
53650bca JM |
438 | struct wlantest_bss *bss; |
439 | struct wlantest_sta *sta; | |
440 | const struct ieee802_1x_hdr *eapol; | |
441 | const struct wpa_eapol_key *hdr; | |
442 | u16 key_info; | |
443 | ||
32234bba JM |
444 | wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR, |
445 | MAC2STR(src), MAC2STR(dst)); | |
53650bca JM |
446 | bss = bss_get(wt, dst); |
447 | if (bss == NULL) | |
448 | return; | |
449 | sta = sta_get(bss, src); | |
450 | if (sta == NULL) | |
451 | return; | |
452 | ||
453 | eapol = (const struct ieee802_1x_hdr *) data; | |
454 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
455 | key_info = WPA_GET_BE16(hdr->key_info); | |
456 | ||
457 | if (!sta->ptk_set) { | |
458 | wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 4/4"); | |
459 | return; | |
460 | } | |
461 | ||
462 | if (sta->ptk_set && | |
463 | check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK, | |
464 | data, len) < 0) { | |
465 | wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 4/4 MIC"); | |
466 | return; | |
467 | } | |
468 | wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 4/4"); | |
32234bba JM |
469 | } |
470 | ||
471 | ||
472 | static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst, | |
473 | const u8 *src, const u8 *data, size_t len) | |
474 | { | |
5db8cf31 JM |
475 | struct wlantest_bss *bss; |
476 | struct wlantest_sta *sta; | |
477 | const struct ieee802_1x_hdr *eapol; | |
478 | const struct wpa_eapol_key *hdr; | |
479 | const u8 *key_data; | |
480 | u16 key_info, ver; | |
481 | u8 *decrypted; | |
482 | size_t decrypted_len = 0; | |
483 | ||
32234bba JM |
484 | wpa_printf(MSG_DEBUG, "EAPOL-Key 1/2 " MACSTR " -> " MACSTR, |
485 | MAC2STR(src), MAC2STR(dst)); | |
5db8cf31 JM |
486 | bss = bss_get(wt, src); |
487 | if (bss == NULL) | |
488 | return; | |
489 | sta = sta_get(bss, dst); | |
490 | if (sta == NULL) | |
491 | return; | |
492 | ||
493 | eapol = (const struct ieee802_1x_hdr *) data; | |
494 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
495 | key_info = WPA_GET_BE16(hdr->key_info); | |
496 | ||
497 | if (!sta->ptk_set) { | |
498 | wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 1/2"); | |
499 | return; | |
500 | } | |
501 | ||
502 | if (sta->ptk_set && | |
503 | check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK, | |
504 | data, len) < 0) { | |
505 | wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 1/2 MIC"); | |
506 | return; | |
507 | } | |
508 | wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 1/2"); | |
509 | ||
510 | key_data = (const u8 *) (hdr + 1); | |
511 | /* TODO: handle WPA without EncrKeyData bit */ | |
512 | if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { | |
513 | wpa_printf(MSG_INFO, "EAPOL-Key 1/2 without EncrKeyData bit"); | |
514 | return; | |
515 | } | |
516 | ver = key_info & WPA_KEY_INFO_TYPE_MASK; | |
517 | decrypted = decrypt_eapol_key_data(sta->ptk.kek, ver, hdr, | |
518 | &decrypted_len); | |
519 | if (decrypted == NULL) { | |
520 | wpa_printf(MSG_INFO, "Failed to decrypt EAPOL-Key Key Data"); | |
521 | return; | |
522 | } | |
523 | wpa_hexdump(MSG_DEBUG, "Decrypted EAPOL-Key Key Data", | |
524 | decrypted, decrypted_len); | |
525 | learn_kde_keys(bss, decrypted, decrypted_len, hdr->key_rsc); | |
526 | os_free(decrypted); | |
32234bba JM |
527 | } |
528 | ||
529 | ||
530 | static void rx_data_eapol_key_2_of_2(struct wlantest *wt, const u8 *dst, | |
531 | const u8 *src, const u8 *data, size_t len) | |
532 | { | |
5db8cf31 JM |
533 | struct wlantest_bss *bss; |
534 | struct wlantest_sta *sta; | |
535 | const struct ieee802_1x_hdr *eapol; | |
536 | const struct wpa_eapol_key *hdr; | |
537 | u16 key_info; | |
538 | ||
32234bba JM |
539 | wpa_printf(MSG_DEBUG, "EAPOL-Key 2/2 " MACSTR " -> " MACSTR, |
540 | MAC2STR(src), MAC2STR(dst)); | |
5db8cf31 JM |
541 | bss = bss_get(wt, dst); |
542 | if (bss == NULL) | |
543 | return; | |
544 | sta = sta_get(bss, src); | |
545 | if (sta == NULL) | |
546 | return; | |
547 | ||
548 | eapol = (const struct ieee802_1x_hdr *) data; | |
549 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
550 | key_info = WPA_GET_BE16(hdr->key_info); | |
551 | ||
552 | if (!sta->ptk_set) { | |
553 | wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 2/2"); | |
554 | return; | |
555 | } | |
556 | ||
557 | if (sta->ptk_set && | |
558 | check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK, | |
559 | data, len) < 0) { | |
560 | wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 2/2 MIC"); | |
561 | return; | |
562 | } | |
563 | wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 2/2"); | |
32234bba JM |
564 | } |
565 | ||
566 | ||
567 | static void rx_data_eapol_key(struct wlantest *wt, const u8 *dst, | |
568 | const u8 *src, const u8 *data, size_t len, | |
569 | int prot) | |
570 | { | |
53650bca | 571 | const struct ieee802_1x_hdr *eapol; |
32234bba | 572 | const struct wpa_eapol_key *hdr; |
8672562b | 573 | const u8 *key_data; |
32234bba JM |
574 | u16 key_info, key_length, ver, key_data_length; |
575 | ||
53650bca JM |
576 | eapol = (const struct ieee802_1x_hdr *) data; |
577 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
578 | ||
579 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key", | |
580 | (const u8 *) hdr, len - sizeof(*eapol)); | |
32234bba JM |
581 | if (len < sizeof(*hdr)) { |
582 | wpa_printf(MSG_INFO, "Too short EAPOL-Key frame from " MACSTR, | |
583 | MAC2STR(src)); | |
584 | return; | |
585 | } | |
32234bba JM |
586 | |
587 | if (hdr->type == EAPOL_KEY_TYPE_RC4) { | |
588 | /* TODO: EAPOL-Key RC4 for WEP */ | |
589 | return; | |
590 | } | |
591 | ||
592 | if (hdr->type != EAPOL_KEY_TYPE_RSN && | |
593 | hdr->type != EAPOL_KEY_TYPE_WPA) { | |
594 | wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key type %u", | |
595 | hdr->type); | |
596 | return; | |
597 | } | |
598 | ||
599 | key_info = WPA_GET_BE16(hdr->key_info); | |
600 | key_length = WPA_GET_BE16(hdr->key_length); | |
601 | key_data_length = WPA_GET_BE16(hdr->key_data_length); | |
8672562b JM |
602 | key_data = (const u8 *) (hdr + 1); |
603 | if (key_data + key_data_length > data + len) { | |
604 | wpa_printf(MSG_INFO, "Truncated EAPOL-Key from " MACSTR, | |
605 | MAC2STR(src)); | |
606 | return; | |
607 | } | |
608 | if (key_data + key_data_length < data + len) { | |
609 | wpa_hexdump(MSG_DEBUG, "Extra data after EAPOL-Key Key Data " | |
610 | "field", key_data + key_data_length, | |
611 | data + len - key_data - key_data_length); | |
612 | } | |
613 | ||
614 | ||
32234bba JM |
615 | ver = key_info & WPA_KEY_INFO_TYPE_MASK; |
616 | wpa_printf(MSG_DEBUG, "EAPOL-Key ver=%u %c idx=%u%s%s%s%s%s%s%s%s " | |
617 | "datalen=%u", | |
618 | ver, key_info & WPA_KEY_INFO_KEY_TYPE ? 'P' : 'G', | |
619 | (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> | |
620 | WPA_KEY_INFO_KEY_INDEX_SHIFT, | |
621 | (key_info & WPA_KEY_INFO_INSTALL) ? " Install" : "", | |
622 | (key_info & WPA_KEY_INFO_ACK) ? " ACK" : "", | |
623 | (key_info & WPA_KEY_INFO_MIC) ? " MIC" : "", | |
624 | (key_info & WPA_KEY_INFO_SECURE) ? " Secure" : "", | |
625 | (key_info & WPA_KEY_INFO_ERROR) ? " Error" : "", | |
626 | (key_info & WPA_KEY_INFO_REQUEST) ? " Request" : "", | |
627 | (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) ? " Encr" : "", | |
628 | (key_info & WPA_KEY_INFO_SMK_MESSAGE) ? " SMK" : "", | |
629 | key_data_length); | |
630 | ||
631 | if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && | |
632 | ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && | |
633 | ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { | |
634 | wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key Key Descriptor " | |
635 | "Version %u", ver); | |
636 | return; | |
637 | } | |
638 | ||
639 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Replay Counter", | |
640 | hdr->replay_counter, WPA_REPLAY_COUNTER_LEN); | |
641 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Nonce", | |
642 | hdr->key_nonce, WPA_NONCE_LEN); | |
643 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key IV", | |
644 | hdr->key_iv, 16); | |
645 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key RSC", | |
2edd5c23 | 646 | hdr->key_rsc, WPA_KEY_RSC_LEN); |
32234bba JM |
647 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key MIC", |
648 | hdr->key_mic, 16); | |
8672562b JM |
649 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data", |
650 | key_data, key_data_length); | |
32234bba JM |
651 | |
652 | if (key_info & (WPA_KEY_INFO_ERROR | WPA_KEY_INFO_REQUEST)) | |
653 | return; | |
654 | ||
655 | if (key_info & WPA_KEY_INFO_SMK_MESSAGE) | |
656 | return; | |
657 | ||
658 | if (key_info & WPA_KEY_INFO_KEY_TYPE) { | |
659 | /* 4-Way Handshake */ | |
660 | switch (key_info & (WPA_KEY_INFO_SECURE | | |
661 | WPA_KEY_INFO_MIC | | |
662 | WPA_KEY_INFO_ACK | | |
663 | WPA_KEY_INFO_INSTALL)) { | |
664 | case WPA_KEY_INFO_ACK: | |
665 | rx_data_eapol_key_1_of_4(wt, dst, src, data, len); | |
666 | break; | |
667 | case WPA_KEY_INFO_MIC: | |
668 | rx_data_eapol_key_2_of_4(wt, dst, src, data, len); | |
669 | break; | |
670 | case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | | |
671 | WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL: | |
672 | rx_data_eapol_key_3_of_4(wt, dst, src, data, len); | |
673 | break; | |
674 | case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC: | |
675 | rx_data_eapol_key_4_of_4(wt, dst, src, data, len); | |
676 | break; | |
677 | default: | |
678 | wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame"); | |
679 | break; | |
680 | } | |
681 | } else { | |
682 | /* Group Key Handshake */ | |
683 | switch (key_info & (WPA_KEY_INFO_SECURE | | |
684 | WPA_KEY_INFO_MIC | | |
685 | WPA_KEY_INFO_ACK)) { | |
686 | case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | | |
687 | WPA_KEY_INFO_ACK: | |
688 | rx_data_eapol_key_1_of_2(wt, dst, src, data, len); | |
689 | break; | |
690 | case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC: | |
691 | rx_data_eapol_key_2_of_2(wt, dst, src, data, len); | |
692 | break; | |
693 | default: | |
694 | wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame"); | |
695 | break; | |
696 | } | |
697 | } | |
698 | } | |
699 | ||
700 | ||
701 | static void rx_data_eapol(struct wlantest *wt, const u8 *dst, const u8 *src, | |
702 | const u8 *data, size_t len, int prot) | |
703 | { | |
704 | const struct ieee802_1x_hdr *hdr; | |
705 | u16 length; | |
706 | const u8 *p; | |
707 | ||
708 | wpa_hexdump(MSG_EXCESSIVE, "EAPOL", data, len); | |
709 | if (len < sizeof(*hdr)) { | |
710 | wpa_printf(MSG_INFO, "Too short EAPOL frame from " MACSTR, | |
711 | MAC2STR(src)); | |
712 | return; | |
713 | } | |
714 | ||
715 | hdr = (const struct ieee802_1x_hdr *) data; | |
716 | length = be_to_host16(hdr->length); | |
717 | wpa_printf(MSG_DEBUG, "RX EAPOL: " MACSTR " -> " MACSTR "%s ver=%u " | |
718 | "type=%u len=%u", | |
719 | MAC2STR(src), MAC2STR(dst), prot ? " Prot" : "", | |
720 | hdr->version, hdr->type, length); | |
721 | if (sizeof(*hdr) + length > len) { | |
722 | wpa_printf(MSG_INFO, "Truncated EAPOL frame from " MACSTR, | |
723 | MAC2STR(src)); | |
724 | return; | |
725 | } | |
726 | ||
727 | if (sizeof(*hdr) + length < len) { | |
728 | wpa_printf(MSG_INFO, "EAPOL frame with %d extra bytes", | |
729 | (int) (len - sizeof(*hdr) - length)); | |
730 | } | |
731 | p = (const u8 *) (hdr + 1); | |
732 | ||
733 | switch (hdr->type) { | |
734 | case IEEE802_1X_TYPE_EAP_PACKET: | |
735 | wpa_hexdump(MSG_MSGDUMP, "EAPOL - EAP packet", p, length); | |
736 | break; | |
737 | case IEEE802_1X_TYPE_EAPOL_START: | |
738 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Start", p, length); | |
739 | break; | |
740 | case IEEE802_1X_TYPE_EAPOL_LOGOFF: | |
741 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Logoff", p, length); | |
742 | break; | |
743 | case IEEE802_1X_TYPE_EAPOL_KEY: | |
53650bca JM |
744 | rx_data_eapol_key(wt, dst, src, data, sizeof(*hdr) + length, |
745 | prot); | |
32234bba JM |
746 | break; |
747 | case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: | |
748 | wpa_hexdump(MSG_MSGDUMP, "EAPOL - Encapsulated ASF alert", | |
749 | p, length); | |
750 | break; | |
751 | default: | |
752 | wpa_hexdump(MSG_MSGDUMP, "Unknown EAPOL payload", p, length); | |
753 | break; | |
754 | } | |
755 | } | |
756 | ||
757 | ||
758 | static void rx_data_eth(struct wlantest *wt, const u8 *dst, const u8 *src, | |
759 | u16 ethertype, const u8 *data, size_t len, int prot) | |
760 | { | |
761 | if (ethertype == ETH_P_PAE) | |
762 | rx_data_eapol(wt, dst, src, data, len, prot); | |
763 | } | |
764 | ||
765 | ||
766 | static void rx_data_process(struct wlantest *wt, const u8 *dst, const u8 *src, | |
767 | const u8 *data, size_t len, int prot) | |
768 | { | |
4bc82fc7 JM |
769 | if (len == 0) |
770 | return; | |
771 | ||
32234bba JM |
772 | if (len >= 8 && os_memcmp(data, "\xaa\xaa\x03\x00\x00\x00", 6) == 0) { |
773 | rx_data_eth(wt, dst, src, WPA_GET_BE16(data + 6), | |
774 | data + 8, len - 8, prot); | |
775 | return; | |
776 | } | |
777 | ||
4bc82fc7 | 778 | wpa_hexdump(MSG_DEBUG, "Unrecognized LLC", data, len > 8 ? 8 : len); |
32234bba JM |
779 | } |
780 | ||
781 | ||
d318c534 JM |
782 | static void rx_data_bss_prot_group(struct wlantest *wt, |
783 | const struct ieee80211_hdr *hdr, | |
784 | const u8 *qos, const u8 *dst, const u8 *src, | |
785 | const u8 *data, size_t len) | |
786 | { | |
787 | struct wlantest_bss *bss; | |
788 | int keyid; | |
07d0a5be JM |
789 | u8 *decrypted; |
790 | size_t dlen; | |
2edd5c23 | 791 | u8 pn[6]; |
d318c534 JM |
792 | |
793 | bss = bss_get(wt, hdr->addr2); | |
794 | if (bss == NULL) | |
795 | return; | |
796 | if (len < 4) { | |
797 | wpa_printf(MSG_INFO, "Too short group addressed data frame"); | |
798 | return; | |
799 | } | |
800 | ||
801 | keyid = data[3] >> 6; | |
802 | if (bss->gtk_len[keyid] == 0) { | |
803 | wpa_printf(MSG_MSGDUMP, "No GTK known to decrypt the frame " | |
804 | "(A2=" MACSTR " KeyID=%d)", | |
805 | MAC2STR(hdr->addr2), keyid); | |
806 | return; | |
807 | } | |
808 | ||
2edd5c23 JM |
809 | ccmp_get_pn(pn, data); |
810 | if (os_memcmp(pn, bss->rsc[keyid], 6) <= 0) { | |
811 | wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: SA=" MACSTR, | |
812 | MAC2STR(hdr->addr2)); | |
813 | wpa_hexdump(MSG_INFO, "RX PN", pn, 6); | |
814 | wpa_hexdump(MSG_INFO, "RSC", bss->rsc[keyid], 6); | |
815 | } | |
816 | ||
07d0a5be JM |
817 | /* TODO: TKIP */ |
818 | ||
819 | decrypted = ccmp_decrypt(bss->gtk[keyid], hdr, data, len, &dlen); | |
2edd5c23 | 820 | if (decrypted) { |
07d0a5be | 821 | rx_data_process(wt, dst, src, decrypted, dlen, 1); |
2edd5c23 JM |
822 | os_memcpy(bss->rsc[keyid], pn, 6); |
823 | } | |
07d0a5be | 824 | os_free(decrypted); |
d318c534 JM |
825 | } |
826 | ||
827 | ||
32234bba JM |
828 | static void rx_data_bss_prot(struct wlantest *wt, |
829 | const struct ieee80211_hdr *hdr, const u8 *qos, | |
830 | const u8 *dst, const u8 *src, const u8 *data, | |
831 | size_t len) | |
832 | { | |
d318c534 JM |
833 | struct wlantest_bss *bss; |
834 | struct wlantest_sta *sta; | |
835 | int keyid; | |
836 | u16 fc = le_to_host16(hdr->frame_control); | |
837 | u8 *decrypted; | |
838 | size_t dlen; | |
2edd5c23 JM |
839 | int tid; |
840 | u8 pn[6], *rsc; | |
d318c534 JM |
841 | |
842 | if (hdr->addr1[0] & 0x01) { | |
843 | rx_data_bss_prot_group(wt, hdr, qos, dst, src, data, len); | |
844 | return; | |
845 | } | |
846 | ||
847 | if (fc & WLAN_FC_TODS) { | |
848 | bss = bss_get(wt, hdr->addr1); | |
849 | if (bss == NULL) | |
850 | return; | |
851 | sta = sta_get(bss, hdr->addr2); | |
852 | } else { | |
853 | bss = bss_get(wt, hdr->addr2); | |
854 | if (bss == NULL) | |
855 | return; | |
856 | sta = sta_get(bss, hdr->addr1); | |
857 | } | |
858 | if (sta == NULL || !sta->ptk_set) { | |
859 | wpa_printf(MSG_MSGDUMP, "No PTK known to decrypt the frame"); | |
860 | return; | |
861 | } | |
862 | ||
863 | if (len < 4) { | |
864 | wpa_printf(MSG_INFO, "Too short encrypted data frame"); | |
865 | return; | |
866 | } | |
867 | ||
868 | keyid = data[3] >> 6; | |
869 | if (keyid != 0) { | |
870 | wpa_printf(MSG_INFO, "Unexpected non-zero KeyID %d in " | |
871 | "individually addressed Data frame from " MACSTR, | |
872 | keyid, MAC2STR(hdr->addr2)); | |
873 | } | |
874 | ||
2edd5c23 JM |
875 | if (qos) |
876 | tid = qos[0] & 0x0f; | |
877 | else | |
878 | tid = 0; | |
879 | if (fc & WLAN_FC_TODS) | |
880 | rsc = sta->rsc_tods[tid]; | |
881 | else | |
882 | rsc = sta->rsc_fromds[tid]; | |
883 | ||
884 | ||
885 | ccmp_get_pn(pn, data); | |
886 | if (os_memcmp(pn, rsc, 6) <= 0) { | |
887 | wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: SA=" MACSTR, | |
888 | MAC2STR(hdr->addr2)); | |
889 | wpa_hexdump(MSG_INFO, "RX PN", pn, 6); | |
890 | wpa_hexdump(MSG_INFO, "RSC", rsc, 6); | |
891 | } | |
892 | ||
d318c534 JM |
893 | /* TODO: TKIP */ |
894 | ||
895 | decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data, len, &dlen); | |
2edd5c23 | 896 | if (decrypted) { |
d318c534 | 897 | rx_data_process(wt, dst, src, decrypted, dlen, 1); |
2edd5c23 JM |
898 | os_memcpy(rsc, pn, 6); |
899 | } | |
d318c534 | 900 | os_free(decrypted); |
32234bba JM |
901 | } |
902 | ||
903 | ||
904 | static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr, | |
905 | const u8 *qos, const u8 *dst, const u8 *src, | |
906 | const u8 *data, size_t len) | |
907 | { | |
908 | u16 fc = le_to_host16(hdr->frame_control); | |
909 | int prot = !!(fc & WLAN_FC_ISWEP); | |
910 | ||
911 | if (qos) { | |
912 | u8 ack = (qos[0] & 0x60) >> 5; | |
913 | wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR | |
914 | " len=%u%s tid=%u%s%s", | |
915 | MAC2STR(src), MAC2STR(dst), (unsigned int) len, | |
916 | prot ? " Prot" : "", qos[0] & 0x0f, | |
917 | (qos[0] & 0x10) ? " EOSP" : "", | |
918 | ack == 0 ? "" : | |
919 | (ack == 1 ? " NoAck" : | |
920 | (ack == 2 ? " NoExpAck" : " BA"))); | |
921 | } else { | |
922 | wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR | |
923 | " len=%u%s", | |
924 | MAC2STR(src), MAC2STR(dst), (unsigned int) len, | |
925 | prot ? " Prot" : ""); | |
926 | } | |
927 | ||
928 | if (prot) | |
929 | rx_data_bss_prot(wt, hdr, qos, dst, src, data, len); | |
930 | else | |
931 | rx_data_process(wt, dst, src, data, len, 0); | |
932 | } | |
933 | ||
934 | ||
2d73f0a8 JM |
935 | void rx_data(struct wlantest *wt, const u8 *data, size_t len) |
936 | { | |
937 | const struct ieee80211_hdr *hdr; | |
32234bba JM |
938 | u16 fc, stype; |
939 | size_t hdrlen; | |
940 | const u8 *qos = NULL; | |
2d73f0a8 JM |
941 | |
942 | if (len < 24) | |
943 | return; | |
944 | ||
945 | hdr = (const struct ieee80211_hdr *) data; | |
946 | fc = le_to_host16(hdr->frame_control); | |
32234bba JM |
947 | stype = WLAN_FC_GET_STYPE(fc); |
948 | hdrlen = 24; | |
949 | if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == | |
950 | (WLAN_FC_TODS | WLAN_FC_FROMDS)) | |
951 | hdrlen += ETH_ALEN; | |
952 | if (stype & 0x08) { | |
953 | qos = data + hdrlen; | |
954 | hdrlen += 2; | |
955 | } | |
956 | if (len < hdrlen) | |
957 | return; | |
2d73f0a8 JM |
958 | wt->rx_data++; |
959 | ||
960 | switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) { | |
961 | case 0: | |
962 | wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s IBSS DA=" MACSTR " SA=" | |
963 | MACSTR " BSSID=" MACSTR, | |
964 | data_stype(WLAN_FC_GET_STYPE(fc)), | |
965 | fc & WLAN_FC_PWRMGT ? " PwrMgt" : "", | |
966 | fc & WLAN_FC_ISWEP ? " Prot" : "", | |
967 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | |
968 | MAC2STR(hdr->addr3)); | |
969 | break; | |
970 | case WLAN_FC_FROMDS: | |
971 | wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s FromDS DA=" MACSTR | |
972 | " BSSID=" MACSTR " SA=" MACSTR, | |
973 | data_stype(WLAN_FC_GET_STYPE(fc)), | |
974 | fc & WLAN_FC_PWRMGT ? " PwrMgt" : "", | |
975 | fc & WLAN_FC_ISWEP ? " Prot" : "", | |
976 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | |
977 | MAC2STR(hdr->addr3)); | |
32234bba JM |
978 | rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2, |
979 | data + hdrlen, len - hdrlen); | |
2d73f0a8 JM |
980 | break; |
981 | case WLAN_FC_TODS: | |
982 | wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s ToDS BSSID=" MACSTR | |
983 | " SA=" MACSTR " DA=" MACSTR, | |
984 | data_stype(WLAN_FC_GET_STYPE(fc)), | |
985 | fc & WLAN_FC_PWRMGT ? " PwrMgt" : "", | |
986 | fc & WLAN_FC_ISWEP ? " Prot" : "", | |
987 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | |
988 | MAC2STR(hdr->addr3)); | |
32234bba JM |
989 | rx_data_bss(wt, hdr, qos, hdr->addr3, hdr->addr2, |
990 | data + hdrlen, len - hdrlen); | |
2d73f0a8 JM |
991 | break; |
992 | case WLAN_FC_TODS | WLAN_FC_FROMDS: | |
993 | wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s WDS RA=" MACSTR " TA=" | |
994 | MACSTR " DA=" MACSTR " SA=" MACSTR, | |
995 | data_stype(WLAN_FC_GET_STYPE(fc)), | |
996 | fc & WLAN_FC_PWRMGT ? " PwrMgt" : "", | |
997 | fc & WLAN_FC_ISWEP ? " Prot" : "", | |
998 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | |
999 | MAC2STR(hdr->addr3), | |
1000 | MAC2STR((const u8 *) (hdr + 1))); | |
1001 | break; | |
1002 | } | |
1003 | } |