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 "common/wpa_common.h"
16 #include "crypto/aes.h"
17 #include "crypto/aes_siv.h"
18 #include "crypto/aes_wrap.h"
22 static const char * mgmt_stype(u16 stype
)
25 case WLAN_FC_STYPE_ASSOC_REQ
:
27 case WLAN_FC_STYPE_ASSOC_RESP
:
29 case WLAN_FC_STYPE_REASSOC_REQ
:
31 case WLAN_FC_STYPE_REASSOC_RESP
:
32 return "REASSOC-RESP";
33 case WLAN_FC_STYPE_PROBE_REQ
:
35 case WLAN_FC_STYPE_PROBE_RESP
:
37 case WLAN_FC_STYPE_BEACON
:
39 case WLAN_FC_STYPE_ATIM
:
41 case WLAN_FC_STYPE_DISASSOC
:
43 case WLAN_FC_STYPE_AUTH
:
45 case WLAN_FC_STYPE_DEAUTH
:
47 case WLAN_FC_STYPE_ACTION
:
54 static void rx_mgmt_beacon(struct wlantest
*wt
, const u8
*data
, size_t len
)
56 const struct ieee80211_mgmt
*mgmt
;
57 struct wlantest_bss
*bss
;
58 struct ieee802_11_elems elems
;
61 mgmt
= (const struct ieee80211_mgmt
*) data
;
62 offset
= mgmt
->u
.beacon
.variable
- data
;
65 bss
= bss_get(wt
, mgmt
->bssid
);
68 if (bss
->proberesp_seen
)
69 return; /* do not override with Beacon data */
70 bss
->capab_info
= le_to_host16(mgmt
->u
.beacon
.capab_info
);
71 if (ieee802_11_parse_elems(mgmt
->u
.beacon
.variable
, len
- offset
,
72 &elems
, 0) == ParseFailed
) {
73 if (bss
->parse_error_reported
)
75 add_note(wt
, MSG_INFO
, "Invalid IEs in a Beacon frame from "
76 MACSTR
, MAC2STR(mgmt
->sa
));
77 bss
->parse_error_reported
= 1;
81 bss_update(wt
, bss
, &elems
);
85 static void rx_mgmt_probe_resp(struct wlantest
*wt
, const u8
*data
, size_t len
)
87 const struct ieee80211_mgmt
*mgmt
;
88 struct wlantest_bss
*bss
;
89 struct ieee802_11_elems elems
;
92 mgmt
= (const struct ieee80211_mgmt
*) data
;
93 offset
= mgmt
->u
.probe_resp
.variable
- data
;
96 bss
= bss_get(wt
, mgmt
->bssid
);
100 bss
->counters
[WLANTEST_BSS_COUNTER_PROBE_RESPONSE
]++;
101 bss
->capab_info
= le_to_host16(mgmt
->u
.probe_resp
.capab_info
);
102 if (ieee802_11_parse_elems(mgmt
->u
.probe_resp
.variable
, len
- offset
,
103 &elems
, 0) == ParseFailed
) {
104 if (bss
->parse_error_reported
)
106 add_note(wt
, MSG_INFO
, "Invalid IEs in a Probe Response frame "
107 "from " MACSTR
, MAC2STR(mgmt
->sa
));
108 bss
->parse_error_reported
= 1;
112 bss_update(wt
, bss
, &elems
);
116 static void process_fils_auth(struct wlantest
*wt
, struct wlantest_bss
*bss
,
117 struct wlantest_sta
*sta
,
118 const struct ieee80211_mgmt
*mgmt
, size_t len
)
120 struct ieee802_11_elems elems
;
122 struct wpa_ie_data data
;
124 if (sta
->auth_alg
!= WLAN_AUTH_FILS_SK
||
125 len
< IEEE80211_HDRLEN
+ sizeof(mgmt
->u
.auth
))
128 trans
= le_to_host16(mgmt
->u
.auth
.auth_transaction
);
130 if (ieee802_11_parse_elems(mgmt
->u
.auth
.variable
,
131 len
- IEEE80211_HDRLEN
-
132 sizeof(mgmt
->u
.auth
), &elems
, 0) ==
138 add_note(wt
, MSG_INFO
,
139 "FILS Authentication frame missing RSNE");
142 if (wpa_parse_wpa_ie_rsn(elems
.rsn_ie
- 2,
143 elems
.rsn_ie_len
+ 2, &data
) < 0) {
144 add_note(wt
, MSG_INFO
,
145 "Invalid RSNE in FILS Authentication frame");
148 sta
->key_mgmt
= data
.key_mgmt
;
149 sta
->pairwise_cipher
= data
.pairwise_cipher
;
152 if (!elems
.fils_nonce
) {
153 add_note(wt
, MSG_INFO
,
154 "FILS Authentication frame missing nonce");
158 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
159 os_memcpy(sta
->anonce
, elems
.fils_nonce
, FILS_NONCE_LEN
);
161 os_memcpy(sta
->snonce
, elems
.fils_nonce
, FILS_NONCE_LEN
);
165 static void rx_mgmt_auth(struct wlantest
*wt
, const u8
*data
, size_t len
)
167 const struct ieee80211_mgmt
*mgmt
;
168 struct wlantest_bss
*bss
;
169 struct wlantest_sta
*sta
;
170 u16 alg
, trans
, status
;
172 mgmt
= (const struct ieee80211_mgmt
*) data
;
173 bss
= bss_get(wt
, mgmt
->bssid
);
176 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
177 sta
= sta_get(bss
, mgmt
->da
);
179 sta
= sta_get(bss
, mgmt
->sa
);
184 add_note(wt
, MSG_INFO
, "Too short Authentication frame from "
185 MACSTR
, MAC2STR(mgmt
->sa
));
189 alg
= le_to_host16(mgmt
->u
.auth
.auth_alg
);
191 trans
= le_to_host16(mgmt
->u
.auth
.auth_transaction
);
192 status
= le_to_host16(mgmt
->u
.auth
.status_code
);
194 wpa_printf(MSG_DEBUG
, "AUTH " MACSTR
" -> " MACSTR
195 " (alg=%u trans=%u status=%u)",
196 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), alg
, trans
, status
);
198 if (alg
== 0 && trans
== 2 && status
== 0) {
199 if (sta
->state
== STATE1
) {
200 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
201 " moved to State 2 with " MACSTR
,
202 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
207 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
208 sta
->counters
[WLANTEST_STA_COUNTER_AUTH_RX
]++;
210 sta
->counters
[WLANTEST_STA_COUNTER_AUTH_TX
]++;
212 process_fils_auth(wt
, bss
, sta
, mgmt
, len
);
216 static void deauth_all_stas(struct wlantest
*wt
, struct wlantest_bss
*bss
)
218 struct wlantest_sta
*sta
;
219 dl_list_for_each(sta
, &bss
->sta
, struct wlantest_sta
, list
) {
220 if (sta
->state
== STATE1
)
222 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
223 " moved to State 1 with " MACSTR
,
224 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
230 static void tdls_link_down(struct wlantest
*wt
, struct wlantest_bss
*bss
,
231 struct wlantest_sta
*sta
)
233 struct wlantest_tdls
*tdls
;
234 dl_list_for_each(tdls
, &bss
->tdls
, struct wlantest_tdls
, list
) {
235 if ((tdls
->init
== sta
|| tdls
->resp
== sta
) && tdls
->link_up
)
237 add_note(wt
, MSG_DEBUG
, "TDLS: Set link down based on "
238 "STA deauth/disassoc");
245 static void rx_mgmt_deauth(struct wlantest
*wt
, const u8
*data
, size_t len
,
248 const struct ieee80211_mgmt
*mgmt
;
249 struct wlantest_bss
*bss
;
250 struct wlantest_sta
*sta
;
253 mgmt
= (const struct ieee80211_mgmt
*) data
;
254 bss
= bss_get(wt
, mgmt
->bssid
);
257 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
258 sta
= sta_get(bss
, mgmt
->da
);
260 sta
= sta_get(bss
, mgmt
->sa
);
263 add_note(wt
, MSG_INFO
, "Too short Deauthentication frame from "
264 MACSTR
, MAC2STR(mgmt
->sa
));
268 reason
= le_to_host16(mgmt
->u
.deauth
.reason_code
);
269 wpa_printf(MSG_DEBUG
, "DEAUTH " MACSTR
" -> " MACSTR
270 " (reason=%u) (valid=%d)",
271 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
273 wpa_hexdump(MSG_MSGDUMP
, "DEAUTH payload", data
+ 24, len
- 24);
276 if (valid
&& mgmt
->da
[0] == 0xff)
277 deauth_all_stas(wt
, bss
);
281 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
282 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DEAUTH_RX
:
283 WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX
]++;
284 if (sta
->pwrmgt
&& !sta
->pspoll
)
285 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_ASLEEP
]++;
287 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_AWAKE
]++;
289 fc
= le_to_host16(mgmt
->frame_control
);
290 if (!(fc
& WLAN_FC_ISWEP
) && reason
== 6)
291 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_RC6
]++;
292 else if (!(fc
& WLAN_FC_ISWEP
) && reason
== 7)
293 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_RC7
]++;
295 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DEAUTH_TX
:
296 WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX
]++;
299 add_note(wt
, MSG_INFO
, "Do not change STA " MACSTR
" State "
300 "since Disassociation frame was not protected "
301 "correctly", MAC2STR(sta
->addr
));
305 if (sta
->state
!= STATE1
) {
306 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
307 " moved to State 1 with " MACSTR
,
308 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
311 tdls_link_down(wt
, bss
, sta
);
315 static const u8
* get_fils_session(const u8
*ies
, size_t ies_len
)
320 end
= ((const u8
*) ie
) + ies_len
;
321 while (ie
+ 1 < end
) {
322 if (ie
+ 2 + ie
[1] > end
)
324 if (ie
[0] == WLAN_EID_EXTENSION
&&
325 ie
[1] >= 1 + FILS_SESSION_LEN
&&
326 ie
[2] == WLAN_EID_EXT_FILS_SESSION
)
334 static int try_rmsk(struct wlantest
*wt
, struct wlantest_bss
*bss
,
335 struct wlantest_sta
*sta
, struct wlantest_pmk
*pmk
,
336 const u8
*frame_start
, const u8
*frame_ad
,
337 const u8
*frame_ad_end
, const u8
*encr_end
)
340 u8 pmk_buf
[PMK_LEN_MAX
];
342 u8 ick
[FILS_ICK_MAX_LEN
];
348 if (fils_rmsk_to_pmk(sta
->key_mgmt
, pmk
->pmk
, pmk
->pmk_len
,
349 sta
->snonce
, sta
->anonce
, NULL
, 0,
350 pmk_buf
, &pmk_len
) < 0)
353 if (fils_pmk_to_ptk(pmk_buf
, pmk_len
, sta
->addr
, bss
->bssid
,
354 sta
->snonce
, sta
->anonce
, NULL
, 0,
356 sta
->key_mgmt
, sta
->pairwise_cipher
,
360 /* Check AES-SIV decryption with the derived key */
362 /* AES-SIV AAD vectors */
364 /* The STA's MAC address */
366 aad_len
[0] = ETH_ALEN
;
369 aad_len
[1] = ETH_ALEN
;
370 /* The STA's nonce */
371 aad
[2] = sta
->snonce
;
372 aad_len
[2] = FILS_NONCE_LEN
;
374 aad
[3] = sta
->anonce
;
375 aad_len
[3] = FILS_NONCE_LEN
;
377 * The (Re)Association Request frame from the Capability Information
378 * field to the FILS Session element (both inclusive).
381 aad_len
[4] = frame_ad_end
- frame_ad
;
383 if (encr_end
- frame_ad_end
< AES_BLOCK_SIZE
||
384 encr_end
- frame_ad_end
> sizeof(buf
))
386 if (aes_siv_decrypt(ptk
.kek
, ptk
.kek_len
,
387 frame_ad_end
, encr_end
- frame_ad_end
,
388 5, aad
, aad_len
, buf
) < 0) {
389 wpa_printf(MSG_DEBUG
,
390 "FILS: Derived PTK did not match AES-SIV data");
394 add_note(wt
, MSG_DEBUG
, "Derived FILS PTK");
395 os_memcpy(&sta
->ptk
, &ptk
, sizeof(ptk
));
397 sta
->counters
[WLANTEST_STA_COUNTER_PTK_LEARNED
]++;
398 wpa_hexdump(MSG_DEBUG
, "FILS: Decrypted Association Request elements",
399 buf
, encr_end
- frame_ad_end
- AES_BLOCK_SIZE
);
401 if (wt
->write_pcap_dumper
|| wt
->pcapng
) {
402 write_pcap_decrypted(wt
, frame_start
,
403 frame_ad_end
- frame_start
,
405 encr_end
- frame_ad_end
- AES_BLOCK_SIZE
);
412 static void derive_fils_keys(struct wlantest
*wt
, struct wlantest_bss
*bss
,
413 struct wlantest_sta
*sta
, const u8
*frame_start
,
414 const u8
*frame_ad
, const u8
*frame_ad_end
,
417 struct wlantest_pmk
*pmk
;
419 wpa_printf(MSG_DEBUG
, "Trying to derive PTK for " MACSTR
420 " from FILS rMSK", MAC2STR(sta
->addr
));
422 dl_list_for_each(pmk
, &bss
->pmk
, struct wlantest_pmk
,
424 wpa_printf(MSG_DEBUG
, "Try per-BSS PMK");
425 if (try_rmsk(wt
, bss
, sta
, pmk
, frame_start
, frame_ad
,
426 frame_ad_end
, encr_end
) == 0)
430 dl_list_for_each(pmk
, &wt
->pmk
, struct wlantest_pmk
, list
) {
431 wpa_printf(MSG_DEBUG
, "Try global PMK");
432 if (try_rmsk(wt
, bss
, sta
, pmk
, frame_start
, frame_ad
,
433 frame_ad_end
, encr_end
) == 0)
439 static void rx_mgmt_assoc_req(struct wlantest
*wt
, const u8
*data
, size_t len
)
441 const struct ieee80211_mgmt
*mgmt
;
442 struct wlantest_bss
*bss
;
443 struct wlantest_sta
*sta
;
444 struct ieee802_11_elems elems
;
448 mgmt
= (const struct ieee80211_mgmt
*) data
;
449 bss
= bss_get(wt
, mgmt
->bssid
);
452 sta
= sta_get(bss
, mgmt
->sa
);
457 add_note(wt
, MSG_INFO
, "Too short Association Request frame "
458 "from " MACSTR
, MAC2STR(mgmt
->sa
));
462 wpa_printf(MSG_DEBUG
, "ASSOCREQ " MACSTR
" -> " MACSTR
463 " (capab=0x%x listen_int=%u)",
464 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
465 le_to_host16(mgmt
->u
.assoc_req
.capab_info
),
466 le_to_host16(mgmt
->u
.assoc_req
.listen_interval
));
468 sta
->counters
[WLANTEST_STA_COUNTER_ASSOCREQ_TX
]++;
470 ie
= mgmt
->u
.assoc_req
.variable
;
471 ie_len
= len
- (mgmt
->u
.assoc_req
.variable
- data
);
473 if (sta
->auth_alg
== WLAN_AUTH_FILS_SK
) {
474 const u8
*session
, *frame_ad
, *frame_ad_end
, *encr_end
;
476 session
= get_fils_session(ie
, ie_len
);
478 frame_ad
= (const u8
*) &mgmt
->u
.assoc_req
.capab_info
;
479 frame_ad_end
= session
+ 2 + session
[1];
480 encr_end
= data
+ len
;
481 derive_fils_keys(wt
, bss
, sta
, data
, frame_ad
,
482 frame_ad_end
, encr_end
);
483 ie_len
= session
- ie
;
487 if (ieee802_11_parse_elems(ie
, ie_len
, &elems
, 0) == ParseFailed
) {
488 add_note(wt
, MSG_INFO
, "Invalid IEs in Association Request "
489 "frame from " MACSTR
, MAC2STR(mgmt
->sa
));
493 sta
->assocreq_capab_info
= le_to_host16(mgmt
->u
.assoc_req
.capab_info
);
494 sta
->assocreq_listen_int
=
495 le_to_host16(mgmt
->u
.assoc_req
.listen_interval
);
496 os_free(sta
->assocreq_ies
);
497 sta
->assocreq_ies_len
= len
- (mgmt
->u
.assoc_req
.variable
- data
);
498 sta
->assocreq_ies
= os_malloc(sta
->assocreq_ies_len
);
499 if (sta
->assocreq_ies
)
500 os_memcpy(sta
->assocreq_ies
, mgmt
->u
.assoc_req
.variable
,
501 sta
->assocreq_ies_len
);
503 sta_update_assoc(sta
, &elems
);
507 static void decrypt_fils_assoc_resp(struct wlantest
*wt
,
508 struct wlantest_bss
*bss
,
509 struct wlantest_sta
*sta
,
510 const u8
*frame_start
, const u8
*frame_ad
,
511 const u8
*frame_ad_end
, const u8
*encr_end
)
520 /* Check AES-SIV decryption with the derived key */
522 /* AES-SIV AAD vectors */
526 aad_len
[0] = ETH_ALEN
;
527 /* The STA's MAC address */
529 aad_len
[1] = ETH_ALEN
;
531 aad
[2] = sta
->anonce
;
532 aad_len
[2] = FILS_NONCE_LEN
;
533 /* The STA's nonce */
534 aad
[3] = sta
->snonce
;
535 aad_len
[3] = FILS_NONCE_LEN
;
537 * The (Re)Association Response frame from the Capability Information
538 * field to the FILS Session element (both inclusive).
541 aad_len
[4] = frame_ad_end
- frame_ad
;
543 if (encr_end
- frame_ad_end
< AES_BLOCK_SIZE
||
544 encr_end
- frame_ad_end
> sizeof(buf
))
546 if (aes_siv_decrypt(sta
->ptk
.kek
, sta
->ptk
.kek_len
,
547 frame_ad_end
, encr_end
- frame_ad_end
,
548 5, aad
, aad_len
, buf
) < 0) {
549 wpa_printf(MSG_DEBUG
,
550 "FILS: Derived PTK did not match AES-SIV data");
554 wpa_hexdump(MSG_DEBUG
, "FILS: Decrypted Association Response elements",
555 buf
, encr_end
- frame_ad_end
- AES_BLOCK_SIZE
);
557 if (wt
->write_pcap_dumper
|| wt
->pcapng
) {
558 write_pcap_decrypted(wt
, frame_start
,
559 frame_ad_end
- frame_start
,
561 encr_end
- frame_ad_end
- AES_BLOCK_SIZE
);
566 static void rx_mgmt_assoc_resp(struct wlantest
*wt
, const u8
*data
, size_t len
)
568 const struct ieee80211_mgmt
*mgmt
;
569 struct wlantest_bss
*bss
;
570 struct wlantest_sta
*sta
;
571 u16 capab
, status
, aid
;
574 struct wpa_ft_ies parse
;
576 mgmt
= (const struct ieee80211_mgmt
*) data
;
577 bss
= bss_get(wt
, mgmt
->bssid
);
580 sta
= sta_get(bss
, mgmt
->da
);
585 add_note(wt
, MSG_INFO
, "Too short Association Response frame "
586 "from " MACSTR
, MAC2STR(mgmt
->sa
));
590 ies
= mgmt
->u
.assoc_resp
.variable
;
591 ies_len
= len
- (mgmt
->u
.assoc_resp
.variable
- data
);
593 capab
= le_to_host16(mgmt
->u
.assoc_resp
.capab_info
);
594 status
= le_to_host16(mgmt
->u
.assoc_resp
.status_code
);
595 aid
= le_to_host16(mgmt
->u
.assoc_resp
.aid
);
597 wpa_printf(MSG_DEBUG
, "ASSOCRESP " MACSTR
" -> " MACSTR
598 " (capab=0x%x status=%u aid=%u)",
599 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), capab
, status
,
602 if (sta
->auth_alg
== WLAN_AUTH_FILS_SK
) {
603 const u8
*session
, *frame_ad
, *frame_ad_end
, *encr_end
;
605 session
= get_fils_session(ies
, ies_len
);
607 frame_ad
= (const u8
*) &mgmt
->u
.assoc_resp
.capab_info
;
608 frame_ad_end
= session
+ 2 + session
[1];
609 encr_end
= data
+ len
;
610 decrypt_fils_assoc_resp(wt
, bss
, sta
, data
, frame_ad
,
611 frame_ad_end
, encr_end
);
612 ies_len
= session
- ies
;
616 if (status
== WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
) {
617 struct ieee802_11_elems elems
;
618 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) ==
620 add_note(wt
, MSG_INFO
, "Failed to parse IEs in "
621 "AssocResp from " MACSTR
,
623 } else if (elems
.timeout_int
== NULL
||
624 elems
.timeout_int
[0] !=
625 WLAN_TIMEOUT_ASSOC_COMEBACK
) {
626 add_note(wt
, MSG_INFO
, "No valid Timeout Interval IE "
627 "with Assoc Comeback time in AssocResp "
628 "(status=30) from " MACSTR
,
632 WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK
]++;
639 if ((aid
& 0xc000) != 0xc000) {
640 add_note(wt
, MSG_DEBUG
, "Two MSBs of the AID were not set to 1 "
641 "in Association Response from " MACSTR
,
644 sta
->aid
= aid
& 0xc000;
646 if (sta
->state
< STATE2
) {
647 add_note(wt
, MSG_DEBUG
,
648 "STA " MACSTR
" was not in State 2 when "
649 "getting associated", MAC2STR(sta
->addr
));
652 if (sta
->state
< STATE3
) {
653 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
654 " moved to State 3 with " MACSTR
,
655 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
659 if (wpa_ft_parse_ies(ies
, ies_len
, &parse
, 0) == 0) {
661 os_memcpy(bss
->r0kh_id
, parse
.r0kh_id
,
663 bss
->r0kh_id_len
= parse
.r0kh_id_len
;
666 os_memcpy(bss
->r1kh_id
, parse
.r1kh_id
, FT_R1KH_ID_LEN
);
671 static void rx_mgmt_reassoc_req(struct wlantest
*wt
, const u8
*data
,
674 const struct ieee80211_mgmt
*mgmt
;
675 struct wlantest_bss
*bss
;
676 struct wlantest_sta
*sta
;
677 struct ieee802_11_elems elems
;
681 mgmt
= (const struct ieee80211_mgmt
*) data
;
682 bss
= bss_get(wt
, mgmt
->bssid
);
685 sta
= sta_get(bss
, mgmt
->sa
);
689 if (len
< 24 + 4 + ETH_ALEN
) {
690 add_note(wt
, MSG_INFO
, "Too short Reassociation Request frame "
691 "from " MACSTR
, MAC2STR(mgmt
->sa
));
695 wpa_printf(MSG_DEBUG
, "REASSOCREQ " MACSTR
" -> " MACSTR
696 " (capab=0x%x listen_int=%u current_ap=" MACSTR
")",
697 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
698 le_to_host16(mgmt
->u
.reassoc_req
.capab_info
),
699 le_to_host16(mgmt
->u
.reassoc_req
.listen_interval
),
700 MAC2STR(mgmt
->u
.reassoc_req
.current_ap
));
702 sta
->counters
[WLANTEST_STA_COUNTER_REASSOCREQ_TX
]++;
704 ie
= mgmt
->u
.reassoc_req
.variable
;
705 ie_len
= len
- (mgmt
->u
.reassoc_req
.variable
- data
);
707 if (sta
->auth_alg
== WLAN_AUTH_FILS_SK
) {
708 const u8
*session
, *frame_ad
, *frame_ad_end
, *encr_end
;
710 session
= get_fils_session(ie
, ie_len
);
712 frame_ad
= (const u8
*) &mgmt
->u
.reassoc_req
.capab_info
;
713 frame_ad_end
= session
+ 2 + session
[1];
714 encr_end
= data
+ len
;
715 derive_fils_keys(wt
, bss
, sta
, data
, frame_ad
,
716 frame_ad_end
, encr_end
);
717 ie_len
= session
- ie
;
721 if (ieee802_11_parse_elems(ie
, ie_len
, &elems
, 0) == ParseFailed
) {
722 add_note(wt
, MSG_INFO
, "Invalid IEs in Reassociation Request "
723 "frame from " MACSTR
, MAC2STR(mgmt
->sa
));
727 sta
->assocreq_capab_info
=
728 le_to_host16(mgmt
->u
.reassoc_req
.capab_info
);
729 sta
->assocreq_listen_int
=
730 le_to_host16(mgmt
->u
.reassoc_req
.listen_interval
);
731 os_free(sta
->assocreq_ies
);
732 sta
->assocreq_ies_len
= len
- (mgmt
->u
.reassoc_req
.variable
- data
);
733 sta
->assocreq_ies
= os_malloc(sta
->assocreq_ies_len
);
734 if (sta
->assocreq_ies
)
735 os_memcpy(sta
->assocreq_ies
, mgmt
->u
.reassoc_req
.variable
,
736 sta
->assocreq_ies_len
);
738 sta_update_assoc(sta
, &elems
);
742 static void rx_mgmt_reassoc_resp(struct wlantest
*wt
, const u8
*data
,
745 const struct ieee80211_mgmt
*mgmt
;
746 struct wlantest_bss
*bss
;
747 struct wlantest_sta
*sta
;
748 u16 capab
, status
, aid
;
752 mgmt
= (const struct ieee80211_mgmt
*) data
;
753 bss
= bss_get(wt
, mgmt
->bssid
);
756 sta
= sta_get(bss
, mgmt
->da
);
761 add_note(wt
, MSG_INFO
, "Too short Reassociation Response frame "
762 "from " MACSTR
, MAC2STR(mgmt
->sa
));
766 ies
= mgmt
->u
.reassoc_resp
.variable
;
767 ies_len
= len
- (mgmt
->u
.reassoc_resp
.variable
- data
);
769 capab
= le_to_host16(mgmt
->u
.reassoc_resp
.capab_info
);
770 status
= le_to_host16(mgmt
->u
.reassoc_resp
.status_code
);
771 aid
= le_to_host16(mgmt
->u
.reassoc_resp
.aid
);
773 wpa_printf(MSG_DEBUG
, "REASSOCRESP " MACSTR
" -> " MACSTR
774 " (capab=0x%x status=%u aid=%u)",
775 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), capab
, status
,
778 if (sta
->auth_alg
== WLAN_AUTH_FILS_SK
) {
779 const u8
*session
, *frame_ad
, *frame_ad_end
, *encr_end
;
781 session
= get_fils_session(ies
, ies_len
);
783 frame_ad
= (const u8
*)
784 &mgmt
->u
.reassoc_resp
.capab_info
;
785 frame_ad_end
= session
+ 2 + session
[1];
786 encr_end
= data
+ len
;
787 decrypt_fils_assoc_resp(wt
, bss
, sta
, data
, frame_ad
,
788 frame_ad_end
, encr_end
);
789 ies_len
= session
- ies
;
793 if (status
== WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
) {
794 struct ieee802_11_elems elems
;
796 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) ==
798 add_note(wt
, MSG_INFO
, "Failed to parse IEs in "
799 "ReassocResp from " MACSTR
,
801 } else if (elems
.timeout_int
== NULL
||
802 elems
.timeout_int
[0] !=
803 WLAN_TIMEOUT_ASSOC_COMEBACK
) {
804 add_note(wt
, MSG_INFO
, "No valid Timeout Interval IE "
805 "with Assoc Comeback time in ReassocResp "
806 "(status=30) from " MACSTR
,
810 WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK
]++;
817 if ((aid
& 0xc000) != 0xc000) {
818 add_note(wt
, MSG_DEBUG
, "Two MSBs of the AID were not set to 1 "
819 "in Reassociation Response from " MACSTR
,
822 sta
->aid
= aid
& 0xc000;
824 if (sta
->state
< STATE2
) {
825 add_note(wt
, MSG_DEBUG
,
826 "STA " MACSTR
" was not in State 2 when "
827 "getting associated", MAC2STR(sta
->addr
));
830 if (sta
->state
< STATE3
) {
831 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
832 " moved to State 3 with " MACSTR
,
833 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
839 static void disassoc_all_stas(struct wlantest
*wt
, struct wlantest_bss
*bss
)
841 struct wlantest_sta
*sta
;
842 dl_list_for_each(sta
, &bss
->sta
, struct wlantest_sta
, list
) {
843 if (sta
->state
<= STATE2
)
845 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
846 " moved to State 2 with " MACSTR
,
847 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
853 static void rx_mgmt_disassoc(struct wlantest
*wt
, const u8
*data
, size_t len
,
856 const struct ieee80211_mgmt
*mgmt
;
857 struct wlantest_bss
*bss
;
858 struct wlantest_sta
*sta
;
861 mgmt
= (const struct ieee80211_mgmt
*) data
;
862 bss
= bss_get(wt
, mgmt
->bssid
);
865 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
866 sta
= sta_get(bss
, mgmt
->da
);
868 sta
= sta_get(bss
, mgmt
->sa
);
871 add_note(wt
, MSG_INFO
, "Too short Disassociation frame from "
872 MACSTR
, MAC2STR(mgmt
->sa
));
876 reason
= le_to_host16(mgmt
->u
.disassoc
.reason_code
);
877 wpa_printf(MSG_DEBUG
, "DISASSOC " MACSTR
" -> " MACSTR
878 " (reason=%u) (valid=%d)",
879 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
881 wpa_hexdump(MSG_MSGDUMP
, "DISASSOC payload", data
+ 24, len
- 24);
884 if (valid
&& mgmt
->da
[0] == 0xff)
885 disassoc_all_stas(wt
, bss
);
889 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
890 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DISASSOC_RX
:
891 WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX
]++;
892 if (sta
->pwrmgt
&& !sta
->pspoll
)
894 WLANTEST_STA_COUNTER_DISASSOC_RX_ASLEEP
]++;
897 WLANTEST_STA_COUNTER_DISASSOC_RX_AWAKE
]++;
899 fc
= le_to_host16(mgmt
->frame_control
);
900 if (!(fc
& WLAN_FC_ISWEP
) && reason
== 6)
901 sta
->counters
[WLANTEST_STA_COUNTER_DISASSOC_RX_RC6
]++;
902 else if (!(fc
& WLAN_FC_ISWEP
) && reason
== 7)
903 sta
->counters
[WLANTEST_STA_COUNTER_DISASSOC_RX_RC7
]++;
905 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DISASSOC_TX
:
906 WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX
]++;
909 add_note(wt
, MSG_INFO
, "Do not change STA " MACSTR
" State "
910 "since Disassociation frame was not protected "
911 "correctly", MAC2STR(sta
->addr
));
915 if (sta
->state
< STATE2
) {
916 add_note(wt
, MSG_DEBUG
,
917 "STA " MACSTR
" was not in State 2 or 3 "
918 "when getting disassociated", MAC2STR(sta
->addr
));
921 if (sta
->state
> STATE2
) {
922 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
923 " moved to State 2 with " MACSTR
,
924 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
927 tdls_link_down(wt
, bss
, sta
);
931 static void rx_mgmt_action_sa_query_req(struct wlantest
*wt
,
932 struct wlantest_sta
*sta
,
933 const struct ieee80211_mgmt
*mgmt
,
934 size_t len
, int valid
)
939 rx_id
= (const u8
*) mgmt
->u
.action
.u
.sa_query_req
.trans_id
;
940 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
941 id
= sta
->ap_sa_query_tr
;
943 id
= sta
->sta_sa_query_tr
;
944 add_note(wt
, MSG_INFO
, "SA Query Request " MACSTR
" -> " MACSTR
945 " (trans_id=%02x%02x)%s",
946 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), rx_id
[0], rx_id
[1],
947 valid
? "" : " (invalid protection)");
948 os_memcpy(id
, mgmt
->u
.action
.u
.sa_query_req
.trans_id
, 2);
949 if (os_memcmp(mgmt
->sa
, sta
->addr
, ETH_ALEN
) == 0)
950 sta
->counters
[valid
?
951 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX
:
952 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX
]++;
954 sta
->counters
[valid
?
955 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX
:
956 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX
]++;
960 static void rx_mgmt_action_sa_query_resp(struct wlantest
*wt
,
961 struct wlantest_sta
*sta
,
962 const struct ieee80211_mgmt
*mgmt
,
963 size_t len
, int valid
)
969 rx_id
= (const u8
*) mgmt
->u
.action
.u
.sa_query_resp
.trans_id
;
970 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
971 id
= sta
->sta_sa_query_tr
;
973 id
= sta
->ap_sa_query_tr
;
974 match
= os_memcmp(rx_id
, id
, 2) == 0;
975 add_note(wt
, MSG_INFO
, "SA Query Response " MACSTR
" -> " MACSTR
976 " (trans_id=%02x%02x; %s)%s",
977 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), rx_id
[0], rx_id
[1],
978 match
? "match" : "mismatch",
979 valid
? "" : " (invalid protection)");
980 if (os_memcmp(mgmt
->sa
, sta
->addr
, ETH_ALEN
) == 0)
981 sta
->counters
[(valid
&& match
) ?
982 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX
:
983 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX
]++;
985 sta
->counters
[(valid
&& match
) ?
986 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX
:
987 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX
]++;
991 static void rx_mgmt_action_sa_query(struct wlantest
*wt
,
992 struct wlantest_sta
*sta
,
993 const struct ieee80211_mgmt
*mgmt
,
994 size_t len
, int valid
)
996 if (len
< 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
) {
997 add_note(wt
, MSG_INFO
, "Too short SA Query frame from " MACSTR
,
1002 if (len
> 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
) {
1003 size_t elen
= len
- (24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
);
1004 add_note(wt
, MSG_INFO
, "Unexpected %u octets of extra data at "
1005 "the end of SA Query frame from " MACSTR
,
1006 (unsigned) elen
, MAC2STR(mgmt
->sa
));
1007 wpa_hexdump(MSG_INFO
, "SA Query extra data",
1008 ((const u8
*) mgmt
) + len
- elen
, elen
);
1011 switch (mgmt
->u
.action
.u
.sa_query_req
.action
) {
1012 case WLAN_SA_QUERY_REQUEST
:
1013 rx_mgmt_action_sa_query_req(wt
, sta
, mgmt
, len
, valid
);
1015 case WLAN_SA_QUERY_RESPONSE
:
1016 rx_mgmt_action_sa_query_resp(wt
, sta
, mgmt
, len
, valid
);
1019 add_note(wt
, MSG_INFO
, "Unexpected SA Query action value %u "
1021 mgmt
->u
.action
.u
.sa_query_req
.action
,
1027 static void rx_mgmt_action(struct wlantest
*wt
, const u8
*data
, size_t len
,
1030 const struct ieee80211_mgmt
*mgmt
;
1031 struct wlantest_bss
*bss
;
1032 struct wlantest_sta
*sta
;
1034 mgmt
= (const struct ieee80211_mgmt
*) data
;
1035 if (mgmt
->da
[0] & 0x01) {
1036 add_note(wt
, MSG_DEBUG
, "Group addressed Action frame: DA="
1037 MACSTR
" SA=" MACSTR
" BSSID=" MACSTR
1039 MAC2STR(mgmt
->da
), MAC2STR(mgmt
->sa
),
1040 MAC2STR(mgmt
->bssid
), mgmt
->u
.action
.category
);
1041 return; /* Ignore group addressed Action frames for now */
1043 bss
= bss_get(wt
, mgmt
->bssid
);
1046 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
1047 sta
= sta_get(bss
, mgmt
->da
);
1049 sta
= sta_get(bss
, mgmt
->sa
);
1054 add_note(wt
, MSG_INFO
, "Too short Action frame from " MACSTR
,
1059 wpa_printf(MSG_DEBUG
, "ACTION " MACSTR
" -> " MACSTR
1060 " (category=%u) (valid=%d)",
1061 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
1062 mgmt
->u
.action
.category
, valid
);
1063 wpa_hexdump(MSG_MSGDUMP
, "ACTION payload", data
+ 24, len
- 24);
1065 if (mgmt
->u
.action
.category
!= WLAN_ACTION_PUBLIC
&&
1066 sta
->state
< STATE3
) {
1067 add_note(wt
, MSG_INFO
, "Action frame sent when STA is not in "
1068 "State 3 (SA=" MACSTR
" DATA=" MACSTR
")",
1069 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
1072 switch (mgmt
->u
.action
.category
) {
1073 case WLAN_ACTION_SA_QUERY
:
1074 rx_mgmt_action_sa_query(wt
, sta
, mgmt
, len
, valid
);
1080 static int check_mmie_mic(unsigned int mgmt_group_cipher
,
1081 const u8
*igtk
, size_t igtk_len
,
1082 const u8
*data
, size_t len
)
1087 const struct ieee80211_hdr
*hdr
;
1090 if (!mgmt_group_cipher
|| igtk_len
< 16)
1092 mic_len
= mgmt_group_cipher
== WPA_CIPHER_AES_128_CMAC
? 8 : 16;
1094 if (len
< 24 || len
- 24 < mic_len
)
1097 buf
= os_malloc(len
+ 20 - 24);
1101 /* BIP AAD: FC(masked) A1 A2 A3 */
1102 hdr
= (const struct ieee80211_hdr
*) data
;
1103 fc
= le_to_host16(hdr
->frame_control
);
1104 fc
&= ~(WLAN_FC_RETRY
| WLAN_FC_PWRMGT
| WLAN_FC_MOREDATA
);
1105 WPA_PUT_LE16(buf
, fc
);
1106 os_memcpy(buf
+ 2, hdr
->addr1
, 3 * ETH_ALEN
);
1108 /* Frame body with MMIE MIC masked to zero */
1109 os_memcpy(buf
+ 20, data
+ 24, len
- 24 - mic_len
);
1110 os_memset(buf
+ 20 + len
- 24 - mic_len
, 0, mic_len
);
1112 wpa_hexdump(MSG_MSGDUMP
, "BIP: AAD|Body(masked)", buf
, len
+ 20 - 24);
1113 /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
1114 if (mgmt_group_cipher
== WPA_CIPHER_AES_128_CMAC
) {
1115 ret
= omac1_aes_128(igtk
, buf
, len
+ 20 - 24, mic
);
1116 } else if (mgmt_group_cipher
== WPA_CIPHER_BIP_CMAC_256
) {
1117 ret
= omac1_aes_256(igtk
, buf
, len
+ 20 - 24, mic
);
1118 } else if (mgmt_group_cipher
== WPA_CIPHER_BIP_GMAC_128
||
1119 mgmt_group_cipher
== WPA_CIPHER_BIP_GMAC_256
) {
1120 u8 nonce
[12], *npos
;
1123 ipn
= data
+ len
- mic_len
- 6;
1125 /* Nonce: A2 | IPN */
1126 os_memcpy(nonce
, hdr
->addr2
, ETH_ALEN
);
1127 npos
= nonce
+ ETH_ALEN
;
1135 ret
= aes_gmac(igtk
, igtk_len
, nonce
, sizeof(nonce
),
1136 buf
, len
+ 20 - 24, mic
);
1147 if (os_memcmp(data
+ len
- mic_len
, mic
, mic_len
) != 0)
1154 static int check_bip(struct wlantest
*wt
, const u8
*data
, size_t len
)
1156 const struct ieee80211_mgmt
*mgmt
;
1160 struct wlantest_bss
*bss
;
1163 mgmt
= (const struct ieee80211_mgmt
*) data
;
1164 fc
= le_to_host16(mgmt
->frame_control
);
1165 stype
= WLAN_FC_GET_STYPE(fc
);
1167 if (stype
== WLAN_FC_STYPE_ACTION
) {
1170 if (mgmt
->u
.action
.category
== WLAN_ACTION_PUBLIC
)
1171 return 0; /* Not a robust management frame */
1174 bss
= bss_get(wt
, mgmt
->bssid
);
1176 return 0; /* No key known yet */
1178 mic_len
= bss
->mgmt_group_cipher
== WPA_CIPHER_AES_128_CMAC
? 8 : 16;
1180 if (len
< 24 + 10 + mic_len
||
1181 data
[len
- (10 + mic_len
)] != WLAN_EID_MMIE
||
1182 data
[len
- (10 + mic_len
- 1)] != 8 + mic_len
) {
1184 if (bss
->rsn_capab
& WPA_CAPABILITY_MFPC
) {
1185 add_note(wt
, MSG_INFO
, "Robust group-addressed "
1186 "management frame sent without BIP by "
1187 MACSTR
, MAC2STR(mgmt
->sa
));
1188 bss
->counters
[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE
]++;
1194 mmie
= data
+ len
- (8 + mic_len
);
1195 keyid
= WPA_GET_LE16(mmie
);
1196 if (keyid
& 0xf000) {
1197 add_note(wt
, MSG_INFO
, "MMIE KeyID reserved bits not zero "
1198 "(%04x) from " MACSTR
, keyid
, MAC2STR(mgmt
->sa
));
1201 if (keyid
< 4 || keyid
> 5) {
1202 add_note(wt
, MSG_INFO
, "Unexpected MMIE KeyID %u from " MACSTR
,
1203 keyid
, MAC2STR(mgmt
->sa
));
1204 bss
->counters
[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE
]++;
1207 wpa_printf(MSG_DEBUG
, "MMIE KeyID %u", keyid
);
1208 wpa_hexdump(MSG_MSGDUMP
, "MMIE IPN", mmie
+ 2, 6);
1209 wpa_hexdump(MSG_MSGDUMP
, "MMIE MIC", mmie
+ 8, mic_len
);
1211 if (!bss
->igtk_len
[keyid
]) {
1212 add_note(wt
, MSG_DEBUG
, "No IGTK known to validate BIP frame");
1216 if (os_memcmp(mmie
+ 2, bss
->ipn
[keyid
], 6) <= 0) {
1217 add_note(wt
, MSG_INFO
, "BIP replay detected: SA=" MACSTR
,
1219 wpa_hexdump(MSG_INFO
, "RX IPN", mmie
+ 2, 6);
1220 wpa_hexdump(MSG_INFO
, "Last RX IPN", bss
->ipn
[keyid
], 6);
1223 if (check_mmie_mic(bss
->mgmt_group_cipher
, bss
->igtk
[keyid
],
1224 bss
->igtk_len
[keyid
], data
, len
) < 0) {
1225 add_note(wt
, MSG_INFO
, "Invalid MMIE MIC in a frame from "
1226 MACSTR
, MAC2STR(mgmt
->sa
));
1227 bss
->counters
[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE
]++;
1231 add_note(wt
, MSG_DEBUG
, "Valid MMIE MIC");
1232 os_memcpy(bss
->ipn
[keyid
], mmie
+ 2, 6);
1233 bss
->counters
[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE
]++;
1235 if (stype
== WLAN_FC_STYPE_DEAUTH
)
1236 bss
->counters
[WLANTEST_BSS_COUNTER_BIP_DEAUTH
]++;
1237 else if (stype
== WLAN_FC_STYPE_DISASSOC
)
1238 bss
->counters
[WLANTEST_BSS_COUNTER_BIP_DISASSOC
]++;
1244 static u8
* mgmt_ccmp_decrypt(struct wlantest
*wt
, const u8
*data
, size_t len
,
1247 struct wlantest_bss
*bss
;
1248 struct wlantest_sta
*sta
;
1249 const struct ieee80211_hdr
*hdr
;
1251 u8
*decrypted
, *frame
= NULL
;
1254 hdr
= (const struct ieee80211_hdr
*) data
;
1255 bss
= bss_get(wt
, hdr
->addr3
);
1258 if (os_memcmp(hdr
->addr1
, hdr
->addr3
, ETH_ALEN
) == 0)
1259 sta
= sta_get(bss
, hdr
->addr2
);
1261 sta
= sta_get(bss
, hdr
->addr1
);
1262 if (sta
== NULL
|| !sta
->ptk_set
) {
1263 add_note(wt
, MSG_MSGDUMP
, "No PTK known to decrypt the frame");
1270 if (!(data
[24 + 3] & 0x20)) {
1271 add_note(wt
, MSG_INFO
, "Expected CCMP frame from " MACSTR
1272 " did not have ExtIV bit set to 1",
1273 MAC2STR(hdr
->addr2
));
1277 if (data
[24 + 2] != 0 || (data
[24 + 3] & 0x1f) != 0) {
1278 add_note(wt
, MSG_INFO
, "CCMP mgmt frame from " MACSTR
" used "
1279 "non-zero reserved bit", MAC2STR(hdr
->addr2
));
1282 keyid
= data
[24 + 3] >> 6;
1284 add_note(wt
, MSG_INFO
, "Unexpected non-zero KeyID %d in "
1285 "individually addressed Management frame from "
1286 MACSTR
, keyid
, MAC2STR(hdr
->addr2
));
1289 if (os_memcmp(hdr
->addr1
, hdr
->addr3
, ETH_ALEN
) == 0)
1290 rsc
= sta
->rsc_tods
[16];
1292 rsc
= sta
->rsc_fromds
[16];
1294 ccmp_get_pn(pn
, data
+ 24);
1295 if (os_memcmp(pn
, rsc
, 6) <= 0) {
1296 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
1297 add_note(wt
, MSG_INFO
, "CCMP/TKIP replay detected: A1=" MACSTR
1298 " A2=" MACSTR
" A3=" MACSTR
" seq=%u frag=%u%s",
1299 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
1300 MAC2STR(hdr
->addr3
),
1301 WLAN_GET_SEQ_SEQ(seq_ctrl
),
1302 WLAN_GET_SEQ_FRAG(seq_ctrl
),
1303 (le_to_host16(hdr
->frame_control
) & WLAN_FC_RETRY
) ?
1305 wpa_hexdump(MSG_INFO
, "RX PN", pn
, 6);
1306 wpa_hexdump(MSG_INFO
, "RSC", rsc
, 6);
1309 decrypted
= ccmp_decrypt(sta
->ptk
.tk
, hdr
, data
+ 24, len
- 24, dlen
);
1311 os_memcpy(rsc
, pn
, 6);
1312 frame
= os_malloc(24 + *dlen
);
1314 os_memcpy(frame
, data
, 24);
1315 os_memcpy(frame
+ 24, decrypted
, *dlen
);
1319 /* Assume the frame was corrupted and there was no FCS to check.
1320 * Allow retry of this particular frame to be processed so that
1321 * it could end up getting decrypted if it was received without
1323 sta
->allow_duplicate
= 1;
1332 static int check_mgmt_ccmp(struct wlantest
*wt
, const u8
*data
, size_t len
)
1334 const struct ieee80211_mgmt
*mgmt
;
1336 struct wlantest_bss
*bss
;
1337 struct wlantest_sta
*sta
;
1339 mgmt
= (const struct ieee80211_mgmt
*) data
;
1340 fc
= le_to_host16(mgmt
->frame_control
);
1342 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACTION
) {
1344 mgmt
->u
.action
.category
== WLAN_ACTION_PUBLIC
)
1345 return 0; /* Not a robust management frame */
1348 bss
= bss_get(wt
, mgmt
->bssid
);
1351 if (os_memcmp(mgmt
->da
, mgmt
->bssid
, ETH_ALEN
) == 0)
1352 sta
= sta_get(bss
, mgmt
->sa
);
1354 sta
= sta_get(bss
, mgmt
->da
);
1358 if ((sta
->rsn_capab
& WPA_CAPABILITY_MFPC
) &&
1359 (sta
->state
== STATE3
||
1360 WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACTION
)) {
1361 add_note(wt
, MSG_INFO
, "Robust individually-addressed "
1362 "management frame sent without CCMP by "
1363 MACSTR
, MAC2STR(mgmt
->sa
));
1371 void rx_mgmt(struct wlantest
*wt
, const u8
*data
, size_t len
)
1373 const struct ieee80211_hdr
*hdr
;
1376 u8
*decrypted
= NULL
;
1382 hdr
= (const struct ieee80211_hdr
*) data
;
1383 fc
= le_to_host16(hdr
->frame_control
);
1385 stype
= WLAN_FC_GET_STYPE(fc
);
1387 if ((hdr
->addr1
[0] & 0x01) &&
1388 (stype
== WLAN_FC_STYPE_DEAUTH
||
1389 stype
== WLAN_FC_STYPE_DISASSOC
||
1390 stype
== WLAN_FC_STYPE_ACTION
)) {
1391 if (check_bip(wt
, data
, len
) < 0)
1395 wpa_printf((stype
== WLAN_FC_STYPE_BEACON
||
1396 stype
== WLAN_FC_STYPE_PROBE_RESP
||
1397 stype
== WLAN_FC_STYPE_PROBE_REQ
) ?
1398 MSG_EXCESSIVE
: MSG_MSGDUMP
,
1399 "MGMT %s%s%s DA=" MACSTR
" SA=" MACSTR
" BSSID=" MACSTR
,
1401 fc
& WLAN_FC_PWRMGT
? " PwrMgt" : "",
1402 fc
& WLAN_FC_ISWEP
? " Prot" : "",
1403 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
1404 MAC2STR(hdr
->addr3
));
1406 if ((fc
& WLAN_FC_ISWEP
) &&
1407 !(hdr
->addr1
[0] & 0x01) &&
1408 (stype
== WLAN_FC_STYPE_DEAUTH
||
1409 stype
== WLAN_FC_STYPE_DISASSOC
||
1410 stype
== WLAN_FC_STYPE_ACTION
)) {
1411 decrypted
= mgmt_ccmp_decrypt(wt
, data
, len
, &dlen
);
1413 write_pcap_decrypted(wt
, decrypted
, dlen
, NULL
, 0);
1420 if (!(fc
& WLAN_FC_ISWEP
) &&
1421 !(hdr
->addr1
[0] & 0x01) &&
1422 (stype
== WLAN_FC_STYPE_DEAUTH
||
1423 stype
== WLAN_FC_STYPE_DISASSOC
||
1424 stype
== WLAN_FC_STYPE_ACTION
)) {
1425 if (check_mgmt_ccmp(wt
, data
, len
) < 0)
1430 case WLAN_FC_STYPE_BEACON
:
1431 rx_mgmt_beacon(wt
, data
, len
);
1433 case WLAN_FC_STYPE_PROBE_RESP
:
1434 rx_mgmt_probe_resp(wt
, data
, len
);
1436 case WLAN_FC_STYPE_AUTH
:
1437 rx_mgmt_auth(wt
, data
, len
);
1439 case WLAN_FC_STYPE_DEAUTH
:
1440 rx_mgmt_deauth(wt
, data
, len
, valid
);
1442 case WLAN_FC_STYPE_ASSOC_REQ
:
1443 rx_mgmt_assoc_req(wt
, data
, len
);
1445 case WLAN_FC_STYPE_ASSOC_RESP
:
1446 rx_mgmt_assoc_resp(wt
, data
, len
);
1448 case WLAN_FC_STYPE_REASSOC_REQ
:
1449 rx_mgmt_reassoc_req(wt
, data
, len
);
1451 case WLAN_FC_STYPE_REASSOC_RESP
:
1452 rx_mgmt_reassoc_resp(wt
, data
, len
);
1454 case WLAN_FC_STYPE_DISASSOC
:
1455 rx_mgmt_disassoc(wt
, data
, len
, valid
);
1457 case WLAN_FC_STYPE_ACTION
:
1458 rx_mgmt_action(wt
, data
, len
, valid
);
1464 wt
->last_mgmt_valid
= valid
;
1468 static void rx_mgmt_deauth_ack(struct wlantest
*wt
,
1469 const struct ieee80211_hdr
*hdr
)
1471 const struct ieee80211_mgmt
*mgmt
;
1472 struct wlantest_bss
*bss
;
1473 struct wlantest_sta
*sta
;
1475 mgmt
= (const struct ieee80211_mgmt
*) hdr
;
1476 bss
= bss_get(wt
, mgmt
->bssid
);
1479 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
1480 sta
= sta_get(bss
, mgmt
->da
);
1482 sta
= sta_get(bss
, mgmt
->sa
);
1486 add_note(wt
, MSG_DEBUG
, "DEAUTH from " MACSTR
" acknowledged by "
1487 MACSTR
, MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
1488 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
1490 c
= wt
->last_mgmt_valid
?
1491 WLANTEST_STA_COUNTER_VALID_DEAUTH_RX_ACK
:
1492 WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX_ACK
;
1498 static void rx_mgmt_disassoc_ack(struct wlantest
*wt
,
1499 const struct ieee80211_hdr
*hdr
)
1501 const struct ieee80211_mgmt
*mgmt
;
1502 struct wlantest_bss
*bss
;
1503 struct wlantest_sta
*sta
;
1505 mgmt
= (const struct ieee80211_mgmt
*) hdr
;
1506 bss
= bss_get(wt
, mgmt
->bssid
);
1509 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
1510 sta
= sta_get(bss
, mgmt
->da
);
1512 sta
= sta_get(bss
, mgmt
->sa
);
1516 add_note(wt
, MSG_DEBUG
, "DISASSOC from " MACSTR
" acknowledged by "
1517 MACSTR
, MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
1518 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
1520 c
= wt
->last_mgmt_valid
?
1521 WLANTEST_STA_COUNTER_VALID_DISASSOC_RX_ACK
:
1522 WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX_ACK
;
1528 void rx_mgmt_ack(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
)
1531 fc
= le_to_host16(hdr
->frame_control
);
1532 stype
= WLAN_FC_GET_STYPE(fc
);
1534 wpa_printf(MSG_MSGDUMP
, "MGMT ACK: stype=%u a1=" MACSTR
" a2=" MACSTR
1536 stype
, MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
1537 MAC2STR(hdr
->addr3
));
1540 case WLAN_FC_STYPE_DEAUTH
:
1541 rx_mgmt_deauth_ack(wt
, hdr
);
1543 case WLAN_FC_STYPE_DISASSOC
:
1544 rx_mgmt_disassoc_ack(wt
, hdr
);