]>
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" | |
18 | #include "common/ieee802_11_defs.h" | |
32234bba JM |
19 | #include "common/eapol_common.h" |
20 | #include "common/wpa_common.h" | |
2d73f0a8 JM |
21 | #include "wlantest.h" |
22 | ||
23 | ||
24 | static const char * data_stype(u16 stype) | |
25 | { | |
26 | switch (stype) { | |
27 | case WLAN_FC_STYPE_DATA: | |
28 | return "DATA"; | |
29 | case WLAN_FC_STYPE_DATA_CFACK: | |
30 | return "DATA-CFACK"; | |
31 | case WLAN_FC_STYPE_DATA_CFPOLL: | |
32 | return "DATA-CFPOLL"; | |
33 | case WLAN_FC_STYPE_DATA_CFACKPOLL: | |
34 | return "DATA-CFACKPOLL"; | |
35 | case WLAN_FC_STYPE_NULLFUNC: | |
36 | return "NULLFUNC"; | |
37 | case WLAN_FC_STYPE_CFACK: | |
38 | return "CFACK"; | |
39 | case WLAN_FC_STYPE_CFPOLL: | |
40 | return "CFPOLL"; | |
41 | case WLAN_FC_STYPE_CFACKPOLL: | |
42 | return "CFACKPOLL"; | |
43 | case WLAN_FC_STYPE_QOS_DATA: | |
44 | return "QOSDATA"; | |
45 | case WLAN_FC_STYPE_QOS_DATA_CFACK: | |
46 | return "QOSDATA-CFACK"; | |
47 | case WLAN_FC_STYPE_QOS_DATA_CFPOLL: | |
48 | return "QOSDATA-CFPOLL"; | |
49 | case WLAN_FC_STYPE_QOS_DATA_CFACKPOLL: | |
50 | return "QOSDATA-CFACKPOLL"; | |
51 | case WLAN_FC_STYPE_QOS_NULL: | |
52 | return "QOS-NULL"; | |
53 | case WLAN_FC_STYPE_QOS_CFPOLL: | |
54 | return "QOS-CFPOLL"; | |
55 | case WLAN_FC_STYPE_QOS_CFACKPOLL: | |
56 | return "QOS-CFACKPOLL"; | |
57 | } | |
58 | return "??"; | |
59 | } | |
60 | ||
61 | ||
53650bca JM |
62 | static int check_mic(const u8 *kck, int ver, const u8 *data, size_t len) |
63 | { | |
64 | u8 *buf; | |
65 | int ret = -1; | |
66 | struct ieee802_1x_hdr *hdr; | |
67 | struct wpa_eapol_key *key; | |
68 | u8 rx_mic[16]; | |
69 | ||
70 | buf = os_malloc(len); | |
71 | if (buf == NULL) | |
72 | return -1; | |
73 | os_memcpy(buf, data, len); | |
74 | hdr = (struct ieee802_1x_hdr *) buf; | |
75 | key = (struct wpa_eapol_key *) (hdr + 1); | |
76 | ||
77 | os_memcpy(rx_mic, key->key_mic, 16); | |
78 | os_memset(key->key_mic, 0, 16); | |
79 | ||
80 | if (wpa_eapol_key_mic(kck, ver, buf, len, key->key_mic) == 0 && | |
81 | os_memcmp(rx_mic, key->key_mic, 16) == 0) | |
82 | ret = 0; | |
83 | ||
84 | os_free(buf); | |
85 | ||
86 | return ret; | |
87 | } | |
88 | ||
89 | ||
32234bba JM |
90 | static void rx_data_eapol_key_1_of_4(struct wlantest *wt, const u8 *dst, |
91 | const u8 *src, const u8 *data, size_t len) | |
92 | { | |
53650bca JM |
93 | struct wlantest_bss *bss; |
94 | struct wlantest_sta *sta; | |
95 | const struct ieee802_1x_hdr *eapol; | |
96 | const struct wpa_eapol_key *hdr; | |
97 | ||
32234bba JM |
98 | wpa_printf(MSG_DEBUG, "EAPOL-Key 1/4 " MACSTR " -> " MACSTR, |
99 | MAC2STR(src), MAC2STR(dst)); | |
53650bca JM |
100 | bss = bss_get(wt, src); |
101 | if (bss == NULL) | |
102 | return; | |
103 | sta = sta_get(bss, dst); | |
104 | if (sta == NULL) | |
105 | return; | |
106 | ||
107 | eapol = (const struct ieee802_1x_hdr *) data; | |
108 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
109 | os_memcpy(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN); | |
110 | } | |
111 | ||
112 | ||
113 | static void derive_ptk(struct wlantest_bss *bss, struct wlantest_sta *sta, | |
114 | u16 ver, const u8 *data, size_t len) | |
115 | { | |
116 | struct wlantest_pmk *pmk; | |
117 | ||
118 | dl_list_for_each(pmk, &bss->pmk, struct wlantest_pmk, list) { | |
119 | struct wpa_ptk ptk; | |
120 | size_t ptk_len = 48; /* FIX: 64 for TKIP */ | |
121 | wpa_pmk_to_ptk(pmk->pmk, sizeof(pmk->pmk), | |
122 | "Pairwise key expansion", | |
123 | bss->bssid, sta->addr, sta->anonce, sta->snonce, | |
124 | (u8 *) &ptk, ptk_len, | |
125 | 0 /* FIX: SHA256 based on AKM */); | |
126 | if (check_mic(ptk.kck, ver, | |
127 | data, len) < 0) | |
128 | continue; | |
129 | ||
130 | wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID " | |
131 | MACSTR ")", | |
132 | MAC2STR(sta->addr), MAC2STR(bss->bssid)); | |
133 | os_memcpy(&sta->ptk, &ptk, sizeof(ptk)); | |
134 | sta->ptk_set = 1; | |
135 | break; | |
136 | } | |
32234bba JM |
137 | } |
138 | ||
139 | ||
140 | static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst, | |
141 | const u8 *src, const u8 *data, size_t len) | |
142 | { | |
53650bca JM |
143 | struct wlantest_bss *bss; |
144 | struct wlantest_sta *sta; | |
145 | const struct ieee802_1x_hdr *eapol; | |
146 | const struct wpa_eapol_key *hdr; | |
147 | u16 key_info; | |
148 | ||
32234bba JM |
149 | wpa_printf(MSG_DEBUG, "EAPOL-Key 2/4 " MACSTR " -> " MACSTR, |
150 | MAC2STR(src), MAC2STR(dst)); | |
53650bca JM |
151 | bss = bss_get(wt, dst); |
152 | if (bss == NULL) | |
153 | return; | |
154 | sta = sta_get(bss, src); | |
155 | if (sta == NULL) | |
156 | return; | |
157 | ||
158 | eapol = (const struct ieee802_1x_hdr *) data; | |
159 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
160 | os_memcpy(sta->snonce, hdr->key_nonce, WPA_NONCE_LEN); | |
161 | key_info = WPA_GET_BE16(hdr->key_info); | |
162 | derive_ptk(bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, data, len); | |
32234bba JM |
163 | } |
164 | ||
165 | ||
166 | static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst, | |
167 | const u8 *src, const u8 *data, size_t len) | |
168 | { | |
53650bca JM |
169 | struct wlantest_bss *bss; |
170 | struct wlantest_sta *sta; | |
171 | const struct ieee802_1x_hdr *eapol; | |
172 | const struct wpa_eapol_key *hdr; | |
173 | int recalc = 0; | |
174 | u16 key_info; | |
175 | ||
32234bba JM |
176 | wpa_printf(MSG_DEBUG, "EAPOL-Key 3/4 " MACSTR " -> " MACSTR, |
177 | MAC2STR(src), MAC2STR(dst)); | |
53650bca JM |
178 | bss = bss_get(wt, src); |
179 | if (bss == NULL) | |
180 | return; | |
181 | sta = sta_get(bss, dst); | |
182 | if (sta == NULL) | |
183 | return; | |
184 | ||
185 | eapol = (const struct ieee802_1x_hdr *) data; | |
186 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
187 | key_info = WPA_GET_BE16(hdr->key_info); | |
188 | if (os_memcmp(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN) != 0) { | |
189 | wpa_printf(MSG_INFO, "EAPOL-Key ANonce mismatch between 1/4 " | |
190 | "and 3/4"); | |
191 | recalc = 1; | |
192 | } | |
193 | os_memcpy(sta->anonce, hdr->key_nonce, WPA_NONCE_LEN); | |
194 | if (recalc) { | |
195 | derive_ptk(bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, | |
196 | data, len); | |
197 | } | |
198 | ||
199 | if (!sta->ptk_set) { | |
200 | wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 3/4"); | |
201 | return; | |
202 | } | |
203 | ||
204 | if (check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK, | |
205 | data, len) < 0) { | |
206 | wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 3/4 MIC"); | |
207 | return; | |
208 | } | |
209 | wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 3/4"); | |
210 | ||
211 | /* TODO: decrypt Key Data and store GTK, IGTK */ | |
32234bba JM |
212 | } |
213 | ||
214 | ||
215 | static void rx_data_eapol_key_4_of_4(struct wlantest *wt, const u8 *dst, | |
216 | const u8 *src, const u8 *data, size_t len) | |
217 | { | |
53650bca JM |
218 | struct wlantest_bss *bss; |
219 | struct wlantest_sta *sta; | |
220 | const struct ieee802_1x_hdr *eapol; | |
221 | const struct wpa_eapol_key *hdr; | |
222 | u16 key_info; | |
223 | ||
32234bba JM |
224 | wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR, |
225 | MAC2STR(src), MAC2STR(dst)); | |
53650bca JM |
226 | bss = bss_get(wt, dst); |
227 | if (bss == NULL) | |
228 | return; | |
229 | sta = sta_get(bss, src); | |
230 | if (sta == NULL) | |
231 | return; | |
232 | ||
233 | eapol = (const struct ieee802_1x_hdr *) data; | |
234 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
235 | key_info = WPA_GET_BE16(hdr->key_info); | |
236 | ||
237 | if (!sta->ptk_set) { | |
238 | wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 4/4"); | |
239 | return; | |
240 | } | |
241 | ||
242 | if (sta->ptk_set && | |
243 | check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK, | |
244 | data, len) < 0) { | |
245 | wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 4/4 MIC"); | |
246 | return; | |
247 | } | |
248 | wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 4/4"); | |
32234bba JM |
249 | } |
250 | ||
251 | ||
252 | static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst, | |
253 | const u8 *src, const u8 *data, size_t len) | |
254 | { | |
255 | wpa_printf(MSG_DEBUG, "EAPOL-Key 1/2 " MACSTR " -> " MACSTR, | |
256 | MAC2STR(src), MAC2STR(dst)); | |
257 | } | |
258 | ||
259 | ||
260 | static void rx_data_eapol_key_2_of_2(struct wlantest *wt, const u8 *dst, | |
261 | const u8 *src, const u8 *data, size_t len) | |
262 | { | |
263 | wpa_printf(MSG_DEBUG, "EAPOL-Key 2/2 " MACSTR " -> " MACSTR, | |
264 | MAC2STR(src), MAC2STR(dst)); | |
265 | } | |
266 | ||
267 | ||
268 | static void rx_data_eapol_key(struct wlantest *wt, const u8 *dst, | |
269 | const u8 *src, const u8 *data, size_t len, | |
270 | int prot) | |
271 | { | |
53650bca | 272 | const struct ieee802_1x_hdr *eapol; |
32234bba JM |
273 | const struct wpa_eapol_key *hdr; |
274 | u16 key_info, key_length, ver, key_data_length; | |
275 | ||
53650bca JM |
276 | eapol = (const struct ieee802_1x_hdr *) data; |
277 | hdr = (const struct wpa_eapol_key *) (eapol + 1); | |
278 | ||
279 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key", | |
280 | (const u8 *) hdr, len - sizeof(*eapol)); | |
32234bba JM |
281 | if (len < sizeof(*hdr)) { |
282 | wpa_printf(MSG_INFO, "Too short EAPOL-Key frame from " MACSTR, | |
283 | MAC2STR(src)); | |
284 | return; | |
285 | } | |
32234bba JM |
286 | |
287 | if (hdr->type == EAPOL_KEY_TYPE_RC4) { | |
288 | /* TODO: EAPOL-Key RC4 for WEP */ | |
289 | return; | |
290 | } | |
291 | ||
292 | if (hdr->type != EAPOL_KEY_TYPE_RSN && | |
293 | hdr->type != EAPOL_KEY_TYPE_WPA) { | |
294 | wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key type %u", | |
295 | hdr->type); | |
296 | return; | |
297 | } | |
298 | ||
299 | key_info = WPA_GET_BE16(hdr->key_info); | |
300 | key_length = WPA_GET_BE16(hdr->key_length); | |
301 | key_data_length = WPA_GET_BE16(hdr->key_data_length); | |
302 | ver = key_info & WPA_KEY_INFO_TYPE_MASK; | |
303 | wpa_printf(MSG_DEBUG, "EAPOL-Key ver=%u %c idx=%u%s%s%s%s%s%s%s%s " | |
304 | "datalen=%u", | |
305 | ver, key_info & WPA_KEY_INFO_KEY_TYPE ? 'P' : 'G', | |
306 | (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >> | |
307 | WPA_KEY_INFO_KEY_INDEX_SHIFT, | |
308 | (key_info & WPA_KEY_INFO_INSTALL) ? " Install" : "", | |
309 | (key_info & WPA_KEY_INFO_ACK) ? " ACK" : "", | |
310 | (key_info & WPA_KEY_INFO_MIC) ? " MIC" : "", | |
311 | (key_info & WPA_KEY_INFO_SECURE) ? " Secure" : "", | |
312 | (key_info & WPA_KEY_INFO_ERROR) ? " Error" : "", | |
313 | (key_info & WPA_KEY_INFO_REQUEST) ? " Request" : "", | |
314 | (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) ? " Encr" : "", | |
315 | (key_info & WPA_KEY_INFO_SMK_MESSAGE) ? " SMK" : "", | |
316 | key_data_length); | |
317 | ||
318 | if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && | |
319 | ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && | |
320 | ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { | |
321 | wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key Key Descriptor " | |
322 | "Version %u", ver); | |
323 | return; | |
324 | } | |
325 | ||
326 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Replay Counter", | |
327 | hdr->replay_counter, WPA_REPLAY_COUNTER_LEN); | |
328 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Nonce", | |
329 | hdr->key_nonce, WPA_NONCE_LEN); | |
330 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key IV", | |
331 | hdr->key_iv, 16); | |
332 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key RSC", | |
333 | hdr->key_nonce, WPA_KEY_RSC_LEN); | |
334 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key MIC", | |
335 | hdr->key_mic, 16); | |
336 | ||
337 | if (key_info & (WPA_KEY_INFO_ERROR | WPA_KEY_INFO_REQUEST)) | |
338 | return; | |
339 | ||
340 | if (key_info & WPA_KEY_INFO_SMK_MESSAGE) | |
341 | return; | |
342 | ||
343 | if (key_info & WPA_KEY_INFO_KEY_TYPE) { | |
344 | /* 4-Way Handshake */ | |
345 | switch (key_info & (WPA_KEY_INFO_SECURE | | |
346 | WPA_KEY_INFO_MIC | | |
347 | WPA_KEY_INFO_ACK | | |
348 | WPA_KEY_INFO_INSTALL)) { | |
349 | case WPA_KEY_INFO_ACK: | |
350 | rx_data_eapol_key_1_of_4(wt, dst, src, data, len); | |
351 | break; | |
352 | case WPA_KEY_INFO_MIC: | |
353 | rx_data_eapol_key_2_of_4(wt, dst, src, data, len); | |
354 | break; | |
355 | case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | | |
356 | WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL: | |
357 | rx_data_eapol_key_3_of_4(wt, dst, src, data, len); | |
358 | break; | |
359 | case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC: | |
360 | rx_data_eapol_key_4_of_4(wt, dst, src, data, len); | |
361 | break; | |
362 | default: | |
363 | wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame"); | |
364 | break; | |
365 | } | |
366 | } else { | |
367 | /* Group Key Handshake */ | |
368 | switch (key_info & (WPA_KEY_INFO_SECURE | | |
369 | WPA_KEY_INFO_MIC | | |
370 | WPA_KEY_INFO_ACK)) { | |
371 | case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | | |
372 | WPA_KEY_INFO_ACK: | |
373 | rx_data_eapol_key_1_of_2(wt, dst, src, data, len); | |
374 | break; | |
375 | case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC: | |
376 | rx_data_eapol_key_2_of_2(wt, dst, src, data, len); | |
377 | break; | |
378 | default: | |
379 | wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame"); | |
380 | break; | |
381 | } | |
382 | } | |
383 | } | |
384 | ||
385 | ||
386 | static void rx_data_eapol(struct wlantest *wt, const u8 *dst, const u8 *src, | |
387 | const u8 *data, size_t len, int prot) | |
388 | { | |
389 | const struct ieee802_1x_hdr *hdr; | |
390 | u16 length; | |
391 | const u8 *p; | |
392 | ||
393 | wpa_hexdump(MSG_EXCESSIVE, "EAPOL", data, len); | |
394 | if (len < sizeof(*hdr)) { | |
395 | wpa_printf(MSG_INFO, "Too short EAPOL frame from " MACSTR, | |
396 | MAC2STR(src)); | |
397 | return; | |
398 | } | |
399 | ||
400 | hdr = (const struct ieee802_1x_hdr *) data; | |
401 | length = be_to_host16(hdr->length); | |
402 | wpa_printf(MSG_DEBUG, "RX EAPOL: " MACSTR " -> " MACSTR "%s ver=%u " | |
403 | "type=%u len=%u", | |
404 | MAC2STR(src), MAC2STR(dst), prot ? " Prot" : "", | |
405 | hdr->version, hdr->type, length); | |
406 | if (sizeof(*hdr) + length > len) { | |
407 | wpa_printf(MSG_INFO, "Truncated EAPOL frame from " MACSTR, | |
408 | MAC2STR(src)); | |
409 | return; | |
410 | } | |
411 | ||
412 | if (sizeof(*hdr) + length < len) { | |
413 | wpa_printf(MSG_INFO, "EAPOL frame with %d extra bytes", | |
414 | (int) (len - sizeof(*hdr) - length)); | |
415 | } | |
416 | p = (const u8 *) (hdr + 1); | |
417 | ||
418 | switch (hdr->type) { | |
419 | case IEEE802_1X_TYPE_EAP_PACKET: | |
420 | wpa_hexdump(MSG_MSGDUMP, "EAPOL - EAP packet", p, length); | |
421 | break; | |
422 | case IEEE802_1X_TYPE_EAPOL_START: | |
423 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Start", p, length); | |
424 | break; | |
425 | case IEEE802_1X_TYPE_EAPOL_LOGOFF: | |
426 | wpa_hexdump(MSG_MSGDUMP, "EAPOL-Logoff", p, length); | |
427 | break; | |
428 | case IEEE802_1X_TYPE_EAPOL_KEY: | |
53650bca JM |
429 | rx_data_eapol_key(wt, dst, src, data, sizeof(*hdr) + length, |
430 | prot); | |
32234bba JM |
431 | break; |
432 | case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT: | |
433 | wpa_hexdump(MSG_MSGDUMP, "EAPOL - Encapsulated ASF alert", | |
434 | p, length); | |
435 | break; | |
436 | default: | |
437 | wpa_hexdump(MSG_MSGDUMP, "Unknown EAPOL payload", p, length); | |
438 | break; | |
439 | } | |
440 | } | |
441 | ||
442 | ||
443 | static void rx_data_eth(struct wlantest *wt, const u8 *dst, const u8 *src, | |
444 | u16 ethertype, const u8 *data, size_t len, int prot) | |
445 | { | |
446 | if (ethertype == ETH_P_PAE) | |
447 | rx_data_eapol(wt, dst, src, data, len, prot); | |
448 | } | |
449 | ||
450 | ||
451 | static void rx_data_process(struct wlantest *wt, const u8 *dst, const u8 *src, | |
452 | const u8 *data, size_t len, int prot) | |
453 | { | |
4bc82fc7 JM |
454 | if (len == 0) |
455 | return; | |
456 | ||
32234bba JM |
457 | if (len >= 8 && os_memcmp(data, "\xaa\xaa\x03\x00\x00\x00", 6) == 0) { |
458 | rx_data_eth(wt, dst, src, WPA_GET_BE16(data + 6), | |
459 | data + 8, len - 8, prot); | |
460 | return; | |
461 | } | |
462 | ||
4bc82fc7 | 463 | wpa_hexdump(MSG_DEBUG, "Unrecognized LLC", data, len > 8 ? 8 : len); |
32234bba JM |
464 | } |
465 | ||
466 | ||
467 | static void rx_data_bss_prot(struct wlantest *wt, | |
468 | const struct ieee80211_hdr *hdr, const u8 *qos, | |
469 | const u8 *dst, const u8 *src, const u8 *data, | |
470 | size_t len) | |
471 | { | |
472 | /* TODO: Try to decrypt and if success, call rx_data_process() with | |
473 | * prot = 1 */ | |
474 | } | |
475 | ||
476 | ||
477 | static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr, | |
478 | const u8 *qos, const u8 *dst, const u8 *src, | |
479 | const u8 *data, size_t len) | |
480 | { | |
481 | u16 fc = le_to_host16(hdr->frame_control); | |
482 | int prot = !!(fc & WLAN_FC_ISWEP); | |
483 | ||
484 | if (qos) { | |
485 | u8 ack = (qos[0] & 0x60) >> 5; | |
486 | wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR | |
487 | " len=%u%s tid=%u%s%s", | |
488 | MAC2STR(src), MAC2STR(dst), (unsigned int) len, | |
489 | prot ? " Prot" : "", qos[0] & 0x0f, | |
490 | (qos[0] & 0x10) ? " EOSP" : "", | |
491 | ack == 0 ? "" : | |
492 | (ack == 1 ? " NoAck" : | |
493 | (ack == 2 ? " NoExpAck" : " BA"))); | |
494 | } else { | |
495 | wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR | |
496 | " len=%u%s", | |
497 | MAC2STR(src), MAC2STR(dst), (unsigned int) len, | |
498 | prot ? " Prot" : ""); | |
499 | } | |
500 | ||
501 | if (prot) | |
502 | rx_data_bss_prot(wt, hdr, qos, dst, src, data, len); | |
503 | else | |
504 | rx_data_process(wt, dst, src, data, len, 0); | |
505 | } | |
506 | ||
507 | ||
2d73f0a8 JM |
508 | void rx_data(struct wlantest *wt, const u8 *data, size_t len) |
509 | { | |
510 | const struct ieee80211_hdr *hdr; | |
32234bba JM |
511 | u16 fc, stype; |
512 | size_t hdrlen; | |
513 | const u8 *qos = NULL; | |
2d73f0a8 JM |
514 | |
515 | if (len < 24) | |
516 | return; | |
517 | ||
518 | hdr = (const struct ieee80211_hdr *) data; | |
519 | fc = le_to_host16(hdr->frame_control); | |
32234bba JM |
520 | stype = WLAN_FC_GET_STYPE(fc); |
521 | hdrlen = 24; | |
522 | if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == | |
523 | (WLAN_FC_TODS | WLAN_FC_FROMDS)) | |
524 | hdrlen += ETH_ALEN; | |
525 | if (stype & 0x08) { | |
526 | qos = data + hdrlen; | |
527 | hdrlen += 2; | |
528 | } | |
529 | if (len < hdrlen) | |
530 | return; | |
2d73f0a8 JM |
531 | wt->rx_data++; |
532 | ||
533 | switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) { | |
534 | case 0: | |
535 | wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s IBSS DA=" MACSTR " SA=" | |
536 | MACSTR " BSSID=" MACSTR, | |
537 | data_stype(WLAN_FC_GET_STYPE(fc)), | |
538 | fc & WLAN_FC_PWRMGT ? " PwrMgt" : "", | |
539 | fc & WLAN_FC_ISWEP ? " Prot" : "", | |
540 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | |
541 | MAC2STR(hdr->addr3)); | |
542 | break; | |
543 | case WLAN_FC_FROMDS: | |
544 | wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s FromDS DA=" MACSTR | |
545 | " BSSID=" MACSTR " SA=" MACSTR, | |
546 | data_stype(WLAN_FC_GET_STYPE(fc)), | |
547 | fc & WLAN_FC_PWRMGT ? " PwrMgt" : "", | |
548 | fc & WLAN_FC_ISWEP ? " Prot" : "", | |
549 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | |
550 | MAC2STR(hdr->addr3)); | |
32234bba JM |
551 | rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2, |
552 | data + hdrlen, len - hdrlen); | |
2d73f0a8 JM |
553 | break; |
554 | case WLAN_FC_TODS: | |
555 | wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s ToDS BSSID=" MACSTR | |
556 | " SA=" MACSTR " DA=" MACSTR, | |
557 | data_stype(WLAN_FC_GET_STYPE(fc)), | |
558 | fc & WLAN_FC_PWRMGT ? " PwrMgt" : "", | |
559 | fc & WLAN_FC_ISWEP ? " Prot" : "", | |
560 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | |
561 | MAC2STR(hdr->addr3)); | |
32234bba JM |
562 | rx_data_bss(wt, hdr, qos, hdr->addr3, hdr->addr2, |
563 | data + hdrlen, len - hdrlen); | |
2d73f0a8 JM |
564 | break; |
565 | case WLAN_FC_TODS | WLAN_FC_FROMDS: | |
566 | wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s WDS RA=" MACSTR " TA=" | |
567 | MACSTR " DA=" MACSTR " SA=" MACSTR, | |
568 | data_stype(WLAN_FC_GET_STYPE(fc)), | |
569 | fc & WLAN_FC_PWRMGT ? " PwrMgt" : "", | |
570 | fc & WLAN_FC_ISWEP ? " Prot" : "", | |
571 | MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), | |
572 | MAC2STR(hdr->addr3), | |
573 | MAC2STR((const u8 *) (hdr + 1))); | |
574 | break; | |
575 | } | |
576 | } |