2 * Received Management frame processing
3 * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
9 #include "utils/includes.h"
11 #include "utils/common.h"
12 #include "common/defs.h"
13 #include "common/ieee802_11_defs.h"
14 #include "common/ieee802_11_common.h"
15 #include "crypto/aes_wrap.h"
19 static const char * mgmt_stype(u16 stype)
22 case WLAN_FC_STYPE_ASSOC_REQ:
24 case WLAN_FC_STYPE_ASSOC_RESP:
26 case WLAN_FC_STYPE_REASSOC_REQ:
28 case WLAN_FC_STYPE_REASSOC_RESP:
29 return "REASSOC-RESP";
30 case WLAN_FC_STYPE_PROBE_REQ:
32 case WLAN_FC_STYPE_PROBE_RESP:
34 case WLAN_FC_STYPE_BEACON:
36 case WLAN_FC_STYPE_ATIM:
38 case WLAN_FC_STYPE_DISASSOC:
40 case WLAN_FC_STYPE_AUTH:
42 case WLAN_FC_STYPE_DEAUTH:
44 case WLAN_FC_STYPE_ACTION:
51 static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
53 const struct ieee80211_mgmt *mgmt;
54 struct wlantest_bss *bss;
55 struct ieee802_11_elems elems;
57 mgmt = (const struct ieee80211_mgmt *) data;
58 bss = bss_get(wt, mgmt->bssid);
61 if (bss->proberesp_seen)
62 return; /* do not override with Beacon data */
63 bss->capab_info = le_to_host16(mgmt->u.beacon.capab_info);
64 if (ieee802_11_parse_elems(mgmt->u.beacon.variable,
65 len - (mgmt->u.beacon.variable - data),
66 &elems, 0) == ParseFailed) {
67 if (bss->parse_error_reported)
69 add_note(wt, MSG_INFO, "Invalid IEs in a Beacon frame from "
70 MACSTR, MAC2STR(mgmt->sa));
71 bss->parse_error_reported = 1;
75 bss_update(wt, bss, &elems);
79 static void rx_mgmt_probe_resp(struct wlantest *wt, const u8 *data, size_t len)
81 const struct ieee80211_mgmt *mgmt;
82 struct wlantest_bss *bss;
83 struct ieee802_11_elems elems;
85 mgmt = (const struct ieee80211_mgmt *) data;
86 bss = bss_get(wt, mgmt->bssid);
90 bss->counters[WLANTEST_BSS_COUNTER_PROBE_RESPONSE]++;
91 bss->capab_info = le_to_host16(mgmt->u.probe_resp.capab_info);
92 if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
93 len - (mgmt->u.probe_resp.variable - data),
94 &elems, 0) == ParseFailed) {
95 if (bss->parse_error_reported)
97 add_note(wt, MSG_INFO, "Invalid IEs in a Probe Response frame "
98 "from " MACSTR, MAC2STR(mgmt->sa));
99 bss->parse_error_reported = 1;
103 bss_update(wt, bss, &elems);
107 static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
109 const struct ieee80211_mgmt *mgmt;
110 struct wlantest_bss *bss;
111 struct wlantest_sta *sta;
112 u16 alg, trans, status;
114 mgmt = (const struct ieee80211_mgmt *) data;
115 bss = bss_get(wt, mgmt->bssid);
118 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
119 sta = sta_get(bss, mgmt->da);
121 sta = sta_get(bss, mgmt->sa);
126 add_note(wt, MSG_INFO, "Too short Authentication frame from "
127 MACSTR, MAC2STR(mgmt->sa));
131 alg = le_to_host16(mgmt->u.auth.auth_alg);
132 trans = le_to_host16(mgmt->u.auth.auth_transaction);
133 status = le_to_host16(mgmt->u.auth.status_code);
135 wpa_printf(MSG_DEBUG, "AUTH " MACSTR " -> " MACSTR
136 " (alg=%u trans=%u status=%u)",
137 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), alg, trans, status);
139 if (alg == 0 && trans == 2 && status == 0) {
140 if (sta->state == STATE1) {
141 add_note(wt, MSG_DEBUG, "STA " MACSTR
142 " moved to State 2 with " MACSTR,
143 MAC2STR(sta->addr), MAC2STR(bss->bssid));
148 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
149 sta->counters[WLANTEST_STA_COUNTER_AUTH_RX]++;
151 sta->counters[WLANTEST_STA_COUNTER_AUTH_TX]++;
155 static void deauth_all_stas(struct wlantest *wt, struct wlantest_bss *bss)
157 struct wlantest_sta *sta;
158 dl_list_for_each(sta, &bss->sta, struct wlantest_sta, list) {
159 if (sta->state == STATE1)
161 add_note(wt, MSG_DEBUG, "STA " MACSTR
162 " moved to State 1 with " MACSTR,
163 MAC2STR(sta->addr), MAC2STR(bss->bssid));
169 static void tdls_link_down(struct wlantest *wt, struct wlantest_bss *bss,
170 struct wlantest_sta *sta)
172 struct wlantest_tdls *tdls;
173 dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) {
174 if ((tdls->init == sta || tdls->resp == sta) && tdls->link_up)
176 add_note(wt, MSG_DEBUG, "TDLS: Set link down based on "
177 "STA deauth/disassoc");
184 static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len,
187 const struct ieee80211_mgmt *mgmt;
188 struct wlantest_bss *bss;
189 struct wlantest_sta *sta;
192 mgmt = (const struct ieee80211_mgmt *) data;
193 bss = bss_get(wt, mgmt->bssid);
196 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
197 sta = sta_get(bss, mgmt->da);
199 sta = sta_get(bss, mgmt->sa);
202 add_note(wt, MSG_INFO, "Too short Deauthentication frame from "
203 MACSTR, MAC2STR(mgmt->sa));
207 reason = le_to_host16(mgmt->u.deauth.reason_code);
208 wpa_printf(MSG_DEBUG, "DEAUTH " MACSTR " -> " MACSTR
209 " (reason=%u) (valid=%d)",
210 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
212 wpa_hexdump(MSG_MSGDUMP, "DEAUTH payload", data + 24, len - 24);
215 if (valid && mgmt->da[0] == 0xff)
216 deauth_all_stas(wt, bss);
220 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
221 sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DEAUTH_RX :
222 WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX]++;
223 if (sta->pwrmgt && !sta->pspoll)
224 sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_ASLEEP]++;
226 sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_AWAKE]++;
228 fc = le_to_host16(mgmt->frame_control);
229 if (!(fc & WLAN_FC_ISWEP) && reason == 6)
230 sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_RC6]++;
231 else if (!(fc & WLAN_FC_ISWEP) && reason == 7)
232 sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_RC7]++;
234 sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DEAUTH_TX :
235 WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX]++;
238 add_note(wt, MSG_INFO, "Do not change STA " MACSTR " State "
239 "since Disassociation frame was not protected "
240 "correctly", MAC2STR(sta->addr));
244 if (sta->state != STATE1) {
245 add_note(wt, MSG_DEBUG, "STA " MACSTR
246 " moved to State 1 with " MACSTR,
247 MAC2STR(sta->addr), MAC2STR(bss->bssid));
250 tdls_link_down(wt, bss, sta);
254 static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len)
256 const struct ieee80211_mgmt *mgmt;
257 struct wlantest_bss *bss;
258 struct wlantest_sta *sta;
259 struct ieee802_11_elems elems;
261 mgmt = (const struct ieee80211_mgmt *) data;
262 bss = bss_get(wt, mgmt->bssid);
265 sta = sta_get(bss, mgmt->sa);
270 add_note(wt, MSG_INFO, "Too short Association Request frame "
271 "from " MACSTR, MAC2STR(mgmt->sa));
275 wpa_printf(MSG_DEBUG, "ASSOCREQ " MACSTR " -> " MACSTR
276 " (capab=0x%x listen_int=%u)",
277 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
278 le_to_host16(mgmt->u.assoc_req.capab_info),
279 le_to_host16(mgmt->u.assoc_req.listen_interval));
281 sta->counters[WLANTEST_STA_COUNTER_ASSOCREQ_TX]++;
283 if (ieee802_11_parse_elems(mgmt->u.assoc_req.variable,
284 len - (mgmt->u.assoc_req.variable - data),
285 &elems, 0) == ParseFailed) {
286 add_note(wt, MSG_INFO, "Invalid IEs in Association Request "
287 "frame from " MACSTR, MAC2STR(mgmt->sa));
291 sta->assocreq_capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
292 sta->assocreq_listen_int =
293 le_to_host16(mgmt->u.assoc_req.listen_interval);
294 os_free(sta->assocreq_ies);
295 sta->assocreq_ies_len = len - (mgmt->u.assoc_req.variable - data);
296 sta->assocreq_ies = os_malloc(sta->assocreq_ies_len);
297 if (sta->assocreq_ies)
298 os_memcpy(sta->assocreq_ies, mgmt->u.assoc_req.variable,
299 sta->assocreq_ies_len);
301 sta_update_assoc(sta, &elems);
305 static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
307 const struct ieee80211_mgmt *mgmt;
308 struct wlantest_bss *bss;
309 struct wlantest_sta *sta;
310 u16 capab, status, aid;
312 mgmt = (const struct ieee80211_mgmt *) data;
313 bss = bss_get(wt, mgmt->bssid);
316 sta = sta_get(bss, mgmt->da);
321 add_note(wt, MSG_INFO, "Too short Association Response frame "
322 "from " MACSTR, MAC2STR(mgmt->sa));
326 capab = le_to_host16(mgmt->u.assoc_resp.capab_info);
327 status = le_to_host16(mgmt->u.assoc_resp.status_code);
328 aid = le_to_host16(mgmt->u.assoc_resp.aid);
330 wpa_printf(MSG_DEBUG, "ASSOCRESP " MACSTR " -> " MACSTR
331 " (capab=0x%x status=%u aid=%u)",
332 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
335 if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
336 struct ieee802_11_elems elems;
337 const u8 *ies = mgmt->u.assoc_resp.variable;
338 size_t ies_len = len - (mgmt->u.assoc_resp.variable - data);
339 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
341 add_note(wt, MSG_INFO, "Failed to parse IEs in "
342 "AssocResp from " MACSTR,
344 } else if (elems.timeout_int == NULL ||
345 elems.timeout_int_len != 5 ||
346 elems.timeout_int[0] !=
347 WLAN_TIMEOUT_ASSOC_COMEBACK) {
348 add_note(wt, MSG_INFO, "No valid Timeout Interval IE "
349 "with Assoc Comeback time in AssocResp "
350 "(status=30) from " MACSTR,
354 WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK]++;
361 if ((aid & 0xc000) != 0xc000) {
362 add_note(wt, MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
363 "in Association Response from " MACSTR,
366 sta->aid = aid & 0xc000;
368 if (sta->state < STATE2) {
369 add_note(wt, MSG_DEBUG,
370 "STA " MACSTR " was not in State 2 when "
371 "getting associated", MAC2STR(sta->addr));
374 if (sta->state < STATE3) {
375 add_note(wt, MSG_DEBUG, "STA " MACSTR
376 " moved to State 3 with " MACSTR,
377 MAC2STR(sta->addr), MAC2STR(bss->bssid));
383 static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
386 const struct ieee80211_mgmt *mgmt;
387 struct wlantest_bss *bss;
388 struct wlantest_sta *sta;
389 struct ieee802_11_elems elems;
391 mgmt = (const struct ieee80211_mgmt *) data;
392 bss = bss_get(wt, mgmt->bssid);
395 sta = sta_get(bss, mgmt->sa);
399 if (len < 24 + 4 + ETH_ALEN) {
400 add_note(wt, MSG_INFO, "Too short Reassociation Request frame "
401 "from " MACSTR, MAC2STR(mgmt->sa));
405 wpa_printf(MSG_DEBUG, "REASSOCREQ " MACSTR " -> " MACSTR
406 " (capab=0x%x listen_int=%u current_ap=" MACSTR ")",
407 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
408 le_to_host16(mgmt->u.reassoc_req.capab_info),
409 le_to_host16(mgmt->u.reassoc_req.listen_interval),
410 MAC2STR(mgmt->u.reassoc_req.current_ap));
412 sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX]++;
414 if (ieee802_11_parse_elems(mgmt->u.reassoc_req.variable,
415 len - (mgmt->u.reassoc_req.variable - data),
416 &elems, 0) == ParseFailed) {
417 add_note(wt, MSG_INFO, "Invalid IEs in Reassociation Request "
418 "frame from " MACSTR, MAC2STR(mgmt->sa));
422 sta->assocreq_capab_info =
423 le_to_host16(mgmt->u.reassoc_req.capab_info);
424 sta->assocreq_listen_int =
425 le_to_host16(mgmt->u.reassoc_req.listen_interval);
426 os_free(sta->assocreq_ies);
427 sta->assocreq_ies_len = len - (mgmt->u.reassoc_req.variable - data);
428 sta->assocreq_ies = os_malloc(sta->assocreq_ies_len);
429 if (sta->assocreq_ies)
430 os_memcpy(sta->assocreq_ies, mgmt->u.reassoc_req.variable,
431 sta->assocreq_ies_len);
433 sta_update_assoc(sta, &elems);
437 static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
440 const struct ieee80211_mgmt *mgmt;
441 struct wlantest_bss *bss;
442 struct wlantest_sta *sta;
443 u16 capab, status, aid;
445 mgmt = (const struct ieee80211_mgmt *) data;
446 bss = bss_get(wt, mgmt->bssid);
449 sta = sta_get(bss, mgmt->da);
454 add_note(wt, MSG_INFO, "Too short Reassociation Response frame "
455 "from " MACSTR, MAC2STR(mgmt->sa));
459 capab = le_to_host16(mgmt->u.reassoc_resp.capab_info);
460 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
461 aid = le_to_host16(mgmt->u.reassoc_resp.aid);
463 wpa_printf(MSG_DEBUG, "REASSOCRESP " MACSTR " -> " MACSTR
464 " (capab=0x%x status=%u aid=%u)",
465 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
468 if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
469 struct ieee802_11_elems elems;
470 const u8 *ies = mgmt->u.reassoc_resp.variable;
471 size_t ies_len = len - (mgmt->u.reassoc_resp.variable - data);
472 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
474 add_note(wt, MSG_INFO, "Failed to parse IEs in "
475 "ReassocResp from " MACSTR,
477 } else if (elems.timeout_int == NULL ||
478 elems.timeout_int_len != 5 ||
479 elems.timeout_int[0] !=
480 WLAN_TIMEOUT_ASSOC_COMEBACK) {
481 add_note(wt, MSG_INFO, "No valid Timeout Interval IE "
482 "with Assoc Comeback time in ReassocResp "
483 "(status=30) from " MACSTR,
487 WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK]++;
494 if ((aid & 0xc000) != 0xc000) {
495 add_note(wt, MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
496 "in Reassociation Response from " MACSTR,
499 sta->aid = aid & 0xc000;
501 if (sta->state < STATE2) {
502 add_note(wt, MSG_DEBUG,
503 "STA " MACSTR " was not in State 2 when "
504 "getting associated", MAC2STR(sta->addr));
507 if (sta->state < STATE3) {
508 add_note(wt, MSG_DEBUG, "STA " MACSTR
509 " moved to State 3 with " MACSTR,
510 MAC2STR(sta->addr), MAC2STR(bss->bssid));
516 static void disassoc_all_stas(struct wlantest *wt, struct wlantest_bss *bss)
518 struct wlantest_sta *sta;
519 dl_list_for_each(sta, &bss->sta, struct wlantest_sta, list) {
520 if (sta->state <= STATE2)
522 add_note(wt, MSG_DEBUG, "STA " MACSTR
523 " moved to State 2 with " MACSTR,
524 MAC2STR(sta->addr), MAC2STR(bss->bssid));
530 static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len,
533 const struct ieee80211_mgmt *mgmt;
534 struct wlantest_bss *bss;
535 struct wlantest_sta *sta;
538 mgmt = (const struct ieee80211_mgmt *) data;
539 bss = bss_get(wt, mgmt->bssid);
542 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
543 sta = sta_get(bss, mgmt->da);
545 sta = sta_get(bss, mgmt->sa);
548 add_note(wt, MSG_INFO, "Too short Disassociation frame from "
549 MACSTR, MAC2STR(mgmt->sa));
553 reason = le_to_host16(mgmt->u.disassoc.reason_code);
554 wpa_printf(MSG_DEBUG, "DISASSOC " MACSTR " -> " MACSTR
555 " (reason=%u) (valid=%d)",
556 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
558 wpa_hexdump(MSG_MSGDUMP, "DISASSOC payload", data + 24, len - 24);
561 if (valid && mgmt->da[0] == 0xff)
562 disassoc_all_stas(wt, bss);
566 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
567 sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DISASSOC_RX :
568 WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX]++;
569 if (sta->pwrmgt && !sta->pspoll)
571 WLANTEST_STA_COUNTER_DISASSOC_RX_ASLEEP]++;
574 WLANTEST_STA_COUNTER_DISASSOC_RX_AWAKE]++;
576 fc = le_to_host16(mgmt->frame_control);
577 if (!(fc & WLAN_FC_ISWEP) && reason == 6)
578 sta->counters[WLANTEST_STA_COUNTER_DISASSOC_RX_RC6]++;
579 else if (!(fc & WLAN_FC_ISWEP) && reason == 7)
580 sta->counters[WLANTEST_STA_COUNTER_DISASSOC_RX_RC7]++;
582 sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DISASSOC_TX :
583 WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX]++;
586 add_note(wt, MSG_INFO, "Do not change STA " MACSTR " State "
587 "since Disassociation frame was not protected "
588 "correctly", MAC2STR(sta->addr));
592 if (sta->state < STATE2) {
593 add_note(wt, MSG_DEBUG,
594 "STA " MACSTR " was not in State 2 or 3 "
595 "when getting disassociated", MAC2STR(sta->addr));
598 if (sta->state > STATE2) {
599 add_note(wt, MSG_DEBUG, "STA " MACSTR
600 " moved to State 2 with " MACSTR,
601 MAC2STR(sta->addr), MAC2STR(bss->bssid));
604 tdls_link_down(wt, bss, sta);
608 static void rx_mgmt_action_sa_query_req(struct wlantest *wt,
609 struct wlantest_sta *sta,
610 const struct ieee80211_mgmt *mgmt,
611 size_t len, int valid)
616 rx_id = (const u8 *) mgmt->u.action.u.sa_query_req.trans_id;
617 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
618 id = sta->ap_sa_query_tr;
620 id = sta->sta_sa_query_tr;
621 add_note(wt, MSG_INFO, "SA Query Request " MACSTR " -> " MACSTR
622 " (trans_id=%02x%02x)%s",
623 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1],
624 valid ? "" : " (invalid protection)");
625 os_memcpy(id, mgmt->u.action.u.sa_query_req.trans_id, 2);
626 if (os_memcmp(mgmt->sa, sta->addr, ETH_ALEN) == 0)
627 sta->counters[valid ?
628 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX :
629 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX]++;
631 sta->counters[valid ?
632 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX :
633 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX]++;
637 static void rx_mgmt_action_sa_query_resp(struct wlantest *wt,
638 struct wlantest_sta *sta,
639 const struct ieee80211_mgmt *mgmt,
640 size_t len, int valid)
646 rx_id = (const u8 *) mgmt->u.action.u.sa_query_resp.trans_id;
647 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
648 id = sta->sta_sa_query_tr;
650 id = sta->ap_sa_query_tr;
651 match = os_memcmp(rx_id, id, 2) == 0;
652 add_note(wt, MSG_INFO, "SA Query Response " MACSTR " -> " MACSTR
653 " (trans_id=%02x%02x; %s)%s",
654 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1],
655 match ? "match" : "mismatch",
656 valid ? "" : " (invalid protection)");
657 if (os_memcmp(mgmt->sa, sta->addr, ETH_ALEN) == 0)
658 sta->counters[(valid && match) ?
659 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX :
660 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX]++;
662 sta->counters[(valid && match) ?
663 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX :
664 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX]++;
668 static void rx_mgmt_action_sa_query(struct wlantest *wt,
669 struct wlantest_sta *sta,
670 const struct ieee80211_mgmt *mgmt,
671 size_t len, int valid)
673 if (len < 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN) {
674 add_note(wt, MSG_INFO, "Too short SA Query frame from " MACSTR,
679 if (len > 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN) {
680 size_t elen = len - (24 + 2 + WLAN_SA_QUERY_TR_ID_LEN);
681 add_note(wt, MSG_INFO, "Unexpected %u octets of extra data at "
682 "the end of SA Query frame from " MACSTR,
683 (unsigned) elen, MAC2STR(mgmt->sa));
684 wpa_hexdump(MSG_INFO, "SA Query extra data",
685 ((const u8 *) mgmt) + len - elen, elen);
688 switch (mgmt->u.action.u.sa_query_req.action) {
689 case WLAN_SA_QUERY_REQUEST:
690 rx_mgmt_action_sa_query_req(wt, sta, mgmt, len, valid);
692 case WLAN_SA_QUERY_RESPONSE:
693 rx_mgmt_action_sa_query_resp(wt, sta, mgmt, len, valid);
696 add_note(wt, MSG_INFO, "Unexpected SA Query action value %u "
698 mgmt->u.action.u.sa_query_req.action,
704 static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
707 const struct ieee80211_mgmt *mgmt;
708 struct wlantest_bss *bss;
709 struct wlantest_sta *sta;
711 mgmt = (const struct ieee80211_mgmt *) data;
712 if (mgmt->da[0] & 0x01) {
713 add_note(wt, MSG_DEBUG, "Group addressed Action frame: DA="
714 MACSTR " SA=" MACSTR " BSSID=" MACSTR
716 MAC2STR(mgmt->da), MAC2STR(mgmt->sa),
717 MAC2STR(mgmt->bssid), mgmt->u.action.category);
718 return; /* Ignore group addressed Action frames for now */
720 bss = bss_get(wt, mgmt->bssid);
723 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
724 sta = sta_get(bss, mgmt->da);
726 sta = sta_get(bss, mgmt->sa);
731 add_note(wt, MSG_INFO, "Too short Action frame from " MACSTR,
736 wpa_printf(MSG_DEBUG, "ACTION " MACSTR " -> " MACSTR
737 " (category=%u) (valid=%d)",
738 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
739 mgmt->u.action.category, valid);
740 wpa_hexdump(MSG_MSGDUMP, "ACTION payload", data + 24, len - 24);
742 if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
743 sta->state < STATE3) {
744 add_note(wt, MSG_INFO, "Action frame sent when STA is not in "
745 "State 3 (SA=" MACSTR " DATA=" MACSTR ")",
746 MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
749 switch (mgmt->u.action.category) {
750 case WLAN_ACTION_SA_QUERY:
751 rx_mgmt_action_sa_query(wt, sta, mgmt, len, valid);
757 static int check_mmie_mic(unsigned int mgmt_group_cipher,
758 const u8 *igtk, size_t igtk_len,
759 const u8 *data, size_t len)
764 const struct ieee80211_hdr *hdr;
767 if (!mgmt_group_cipher || igtk_len < 16)
769 mic_len = mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ? 8 : 16;
771 if (len < 24 || len - 24 < mic_len)
774 buf = os_malloc(len + 20 - 24);
778 /* BIP AAD: FC(masked) A1 A2 A3 */
779 hdr = (const struct ieee80211_hdr *) data;
780 fc = le_to_host16(hdr->frame_control);
781 fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
782 WPA_PUT_LE16(buf, fc);
783 os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
785 /* Frame body with MMIE MIC masked to zero */
786 os_memcpy(buf + 20, data + 24, len - 24 - mic_len);
787 os_memset(buf + 20 + len - 24 - mic_len, 0, mic_len);
789 wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, len + 20 - 24);
790 /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
791 if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
792 ret = omac1_aes_128(igtk, buf, len + 20 - 24, mic);
793 } else if (mgmt_group_cipher == WPA_CIPHER_BIP_CMAC_256) {
794 ret = omac1_aes_256(igtk, buf, len + 20 - 24, mic);
795 } else if (mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_128 ||
796 mgmt_group_cipher == WPA_CIPHER_BIP_GMAC_256) {
800 ipn = data + len - mic_len - 6;
802 /* Nonce: A2 | IPN */
803 os_memcpy(nonce, hdr->addr2, ETH_ALEN);
804 npos = nonce + ETH_ALEN;
812 ret = aes_gmac(igtk, igtk_len, nonce, sizeof(nonce),
813 buf, len + 20 - 24, mic);
824 if (os_memcmp(data + len - mic_len, mic, mic_len) != 0)
831 static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
833 const struct ieee80211_mgmt *mgmt;
837 struct wlantest_bss *bss;
840 mgmt = (const struct ieee80211_mgmt *) data;
841 fc = le_to_host16(mgmt->frame_control);
842 stype = WLAN_FC_GET_STYPE(fc);
844 if (stype == WLAN_FC_STYPE_ACTION) {
847 if (mgmt->u.action.category == WLAN_ACTION_PUBLIC)
848 return 0; /* Not a robust management frame */
851 bss = bss_get(wt, mgmt->bssid);
853 return 0; /* No key known yet */
855 mic_len = bss->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC ? 8 : 16;
857 if (len < 24 + 10 + mic_len ||
858 data[len - (10 + mic_len)] != WLAN_EID_MMIE ||
859 data[len - (10 + mic_len - 1)] != 8 + mic_len) {
861 if (bss->rsn_capab & WPA_CAPABILITY_MFPC) {
862 add_note(wt, MSG_INFO, "Robust group-addressed "
863 "management frame sent without BIP by "
864 MACSTR, MAC2STR(mgmt->sa));
865 bss->counters[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE]++;
871 mmie = data + len - (8 + mic_len);
872 keyid = WPA_GET_LE16(mmie);
873 if (keyid & 0xf000) {
874 add_note(wt, MSG_INFO, "MMIE KeyID reserved bits not zero "
875 "(%04x) from " MACSTR, keyid, MAC2STR(mgmt->sa));
878 if (keyid < 4 || keyid > 5) {
879 add_note(wt, MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR,
880 keyid, MAC2STR(mgmt->sa));
881 bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
884 wpa_printf(MSG_DEBUG, "MMIE KeyID %u", keyid);
885 wpa_hexdump(MSG_MSGDUMP, "MMIE IPN", mmie + 2, 6);
886 wpa_hexdump(MSG_MSGDUMP, "MMIE MIC", mmie + 8, mic_len);
888 if (!bss->igtk_len[keyid]) {
889 add_note(wt, MSG_DEBUG, "No IGTK known to validate BIP frame");
893 if (os_memcmp(mmie + 2, bss->ipn[keyid], 6) <= 0) {
894 add_note(wt, MSG_INFO, "BIP replay detected: SA=" MACSTR,
896 wpa_hexdump(MSG_INFO, "RX IPN", mmie + 2, 6);
897 wpa_hexdump(MSG_INFO, "Last RX IPN", bss->ipn[keyid], 6);
900 if (check_mmie_mic(bss->mgmt_group_cipher, bss->igtk[keyid],
901 bss->igtk_len[keyid], data, len) < 0) {
902 add_note(wt, MSG_INFO, "Invalid MMIE MIC in a frame from "
903 MACSTR, MAC2STR(mgmt->sa));
904 bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
908 add_note(wt, MSG_DEBUG, "Valid MMIE MIC");
909 os_memcpy(bss->ipn[keyid], mmie + 2, 6);
910 bss->counters[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE]++;
912 if (stype == WLAN_FC_STYPE_DEAUTH)
913 bss->counters[WLANTEST_BSS_COUNTER_BIP_DEAUTH]++;
914 else if (stype == WLAN_FC_STYPE_DISASSOC)
915 bss->counters[WLANTEST_BSS_COUNTER_BIP_DISASSOC]++;
921 static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
924 struct wlantest_bss *bss;
925 struct wlantest_sta *sta;
926 const struct ieee80211_hdr *hdr;
928 u8 *decrypted, *frame = NULL;
931 hdr = (const struct ieee80211_hdr *) data;
932 bss = bss_get(wt, hdr->addr3);
935 if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
936 sta = sta_get(bss, hdr->addr2);
938 sta = sta_get(bss, hdr->addr1);
939 if (sta == NULL || !sta->ptk_set) {
940 add_note(wt, MSG_MSGDUMP, "No PTK known to decrypt the frame");
947 if (!(data[24 + 3] & 0x20)) {
948 add_note(wt, MSG_INFO, "Expected CCMP frame from " MACSTR
949 " did not have ExtIV bit set to 1",
950 MAC2STR(hdr->addr2));
954 if (data[24 + 2] != 0 || (data[24 + 3] & 0x1f) != 0) {
955 add_note(wt, MSG_INFO, "CCMP mgmt frame from " MACSTR " used "
956 "non-zero reserved bit", MAC2STR(hdr->addr2));
959 keyid = data[24 + 3] >> 6;
961 add_note(wt, MSG_INFO, "Unexpected non-zero KeyID %d in "
962 "individually addressed Management frame from "
963 MACSTR, keyid, MAC2STR(hdr->addr2));
966 if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
967 rsc = sta->rsc_tods[16];
969 rsc = sta->rsc_fromds[16];
971 ccmp_get_pn(pn, data + 24);
972 if (os_memcmp(pn, rsc, 6) <= 0) {
973 u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
974 add_note(wt, MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
975 " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u%s",
976 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
978 WLAN_GET_SEQ_SEQ(seq_ctrl),
979 WLAN_GET_SEQ_FRAG(seq_ctrl),
980 (le_to_host16(hdr->frame_control) & WLAN_FC_RETRY) ?
982 wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
983 wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
986 decrypted = ccmp_decrypt(sta->ptk.tk, hdr, data + 24, len - 24, dlen);
988 os_memcpy(rsc, pn, 6);
989 frame = os_malloc(24 + *dlen);
991 os_memcpy(frame, data, 24);
992 os_memcpy(frame + 24, decrypted, *dlen);
1003 static int check_mgmt_ccmp(struct wlantest *wt, const u8 *data, size_t len)
1005 const struct ieee80211_mgmt *mgmt;
1007 struct wlantest_bss *bss;
1008 struct wlantest_sta *sta;
1010 mgmt = (const struct ieee80211_mgmt *) data;
1011 fc = le_to_host16(mgmt->frame_control);
1013 if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
1015 mgmt->u.action.category == WLAN_ACTION_PUBLIC)
1016 return 0; /* Not a robust management frame */
1019 bss = bss_get(wt, mgmt->bssid);
1022 if (os_memcmp(mgmt->da, mgmt->bssid, ETH_ALEN) == 0)
1023 sta = sta_get(bss, mgmt->sa);
1025 sta = sta_get(bss, mgmt->da);
1029 if ((sta->rsn_capab & WPA_CAPABILITY_MFPC) &&
1030 (sta->state == STATE3 ||
1031 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION)) {
1032 add_note(wt, MSG_INFO, "Robust individually-addressed "
1033 "management frame sent without CCMP by "
1034 MACSTR, MAC2STR(mgmt->sa));
1042 void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
1044 const struct ieee80211_hdr *hdr;
1047 u8 *decrypted = NULL;
1053 hdr = (const struct ieee80211_hdr *) data;
1054 fc = le_to_host16(hdr->frame_control);
1056 stype = WLAN_FC_GET_STYPE(fc);
1058 if ((hdr->addr1[0] & 0x01) &&
1059 (stype == WLAN_FC_STYPE_DEAUTH ||
1060 stype == WLAN_FC_STYPE_DISASSOC ||
1061 stype == WLAN_FC_STYPE_ACTION)) {
1062 if (check_bip(wt, data, len) < 0)
1066 wpa_printf((stype == WLAN_FC_STYPE_BEACON ||
1067 stype == WLAN_FC_STYPE_PROBE_RESP ||
1068 stype == WLAN_FC_STYPE_PROBE_REQ) ?
1069 MSG_EXCESSIVE : MSG_MSGDUMP,
1070 "MGMT %s%s%s DA=" MACSTR " SA=" MACSTR " BSSID=" MACSTR,
1072 fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
1073 fc & WLAN_FC_ISWEP ? " Prot" : "",
1074 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
1075 MAC2STR(hdr->addr3));
1077 if ((fc & WLAN_FC_ISWEP) &&
1078 !(hdr->addr1[0] & 0x01) &&
1079 (stype == WLAN_FC_STYPE_DEAUTH ||
1080 stype == WLAN_FC_STYPE_DISASSOC ||
1081 stype == WLAN_FC_STYPE_ACTION)) {
1082 decrypted = mgmt_ccmp_decrypt(wt, data, len, &dlen);
1084 write_pcap_decrypted(wt, decrypted, dlen, NULL, 0);
1091 if (!(fc & WLAN_FC_ISWEP) &&
1092 !(hdr->addr1[0] & 0x01) &&
1093 (stype == WLAN_FC_STYPE_DEAUTH ||
1094 stype == WLAN_FC_STYPE_DISASSOC ||
1095 stype == WLAN_FC_STYPE_ACTION)) {
1096 if (check_mgmt_ccmp(wt, data, len) < 0)
1101 case WLAN_FC_STYPE_BEACON:
1102 rx_mgmt_beacon(wt, data, len);
1104 case WLAN_FC_STYPE_PROBE_RESP:
1105 rx_mgmt_probe_resp(wt, data, len);
1107 case WLAN_FC_STYPE_AUTH:
1108 rx_mgmt_auth(wt, data, len);
1110 case WLAN_FC_STYPE_DEAUTH:
1111 rx_mgmt_deauth(wt, data, len, valid);
1113 case WLAN_FC_STYPE_ASSOC_REQ:
1114 rx_mgmt_assoc_req(wt, data, len);
1116 case WLAN_FC_STYPE_ASSOC_RESP:
1117 rx_mgmt_assoc_resp(wt, data, len);
1119 case WLAN_FC_STYPE_REASSOC_REQ:
1120 rx_mgmt_reassoc_req(wt, data, len);
1122 case WLAN_FC_STYPE_REASSOC_RESP:
1123 rx_mgmt_reassoc_resp(wt, data, len);
1125 case WLAN_FC_STYPE_DISASSOC:
1126 rx_mgmt_disassoc(wt, data, len, valid);
1128 case WLAN_FC_STYPE_ACTION:
1129 rx_mgmt_action(wt, data, len, valid);
1135 wt->last_mgmt_valid = valid;
1139 static void rx_mgmt_deauth_ack(struct wlantest *wt,
1140 const struct ieee80211_hdr *hdr)
1142 const struct ieee80211_mgmt *mgmt;
1143 struct wlantest_bss *bss;
1144 struct wlantest_sta *sta;
1146 mgmt = (const struct ieee80211_mgmt *) hdr;
1147 bss = bss_get(wt, mgmt->bssid);
1150 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
1151 sta = sta_get(bss, mgmt->da);
1153 sta = sta_get(bss, mgmt->sa);
1157 add_note(wt, MSG_DEBUG, "DEAUTH from " MACSTR " acknowledged by "
1158 MACSTR, MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
1159 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
1161 c = wt->last_mgmt_valid ?
1162 WLANTEST_STA_COUNTER_VALID_DEAUTH_RX_ACK :
1163 WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX_ACK;
1169 static void rx_mgmt_disassoc_ack(struct wlantest *wt,
1170 const struct ieee80211_hdr *hdr)
1172 const struct ieee80211_mgmt *mgmt;
1173 struct wlantest_bss *bss;
1174 struct wlantest_sta *sta;
1176 mgmt = (const struct ieee80211_mgmt *) hdr;
1177 bss = bss_get(wt, mgmt->bssid);
1180 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
1181 sta = sta_get(bss, mgmt->da);
1183 sta = sta_get(bss, mgmt->sa);
1187 add_note(wt, MSG_DEBUG, "DISASSOC from " MACSTR " acknowledged by "
1188 MACSTR, MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
1189 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
1191 c = wt->last_mgmt_valid ?
1192 WLANTEST_STA_COUNTER_VALID_DISASSOC_RX_ACK :
1193 WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX_ACK;
1199 void rx_mgmt_ack(struct wlantest *wt, const struct ieee80211_hdr *hdr)
1202 fc = le_to_host16(hdr->frame_control);
1203 stype = WLAN_FC_GET_STYPE(fc);
1205 wpa_printf(MSG_MSGDUMP, "MGMT ACK: stype=%u a1=" MACSTR " a2=" MACSTR
1207 stype, MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
1208 MAC2STR(hdr->addr3));
1211 case WLAN_FC_STYPE_DEAUTH:
1212 rx_mgmt_deauth_ack(wt, hdr);
1214 case WLAN_FC_STYPE_DISASSOC:
1215 rx_mgmt_disassoc_ack(wt, hdr);