2 * Received Management frame processing
3 * Copyright (c) 2010, 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/ieee802_11_defs.h"
13 #include "common/ieee802_11_common.h"
14 #include "crypto/aes_wrap.h"
18 static const char * mgmt_stype(u16 stype
)
21 case WLAN_FC_STYPE_ASSOC_REQ
:
23 case WLAN_FC_STYPE_ASSOC_RESP
:
25 case WLAN_FC_STYPE_REASSOC_REQ
:
27 case WLAN_FC_STYPE_REASSOC_RESP
:
28 return "REASSOC-RESP";
29 case WLAN_FC_STYPE_PROBE_REQ
:
31 case WLAN_FC_STYPE_PROBE_RESP
:
33 case WLAN_FC_STYPE_BEACON
:
35 case WLAN_FC_STYPE_ATIM
:
37 case WLAN_FC_STYPE_DISASSOC
:
39 case WLAN_FC_STYPE_AUTH
:
41 case WLAN_FC_STYPE_DEAUTH
:
43 case WLAN_FC_STYPE_ACTION
:
50 static void rx_mgmt_beacon(struct wlantest
*wt
, const u8
*data
, size_t len
)
52 const struct ieee80211_mgmt
*mgmt
;
53 struct wlantest_bss
*bss
;
54 struct ieee802_11_elems elems
;
56 mgmt
= (const struct ieee80211_mgmt
*) data
;
57 bss
= bss_get(wt
, mgmt
->bssid
);
60 if (bss
->proberesp_seen
)
61 return; /* do not override with Beacon data */
62 bss
->capab_info
= le_to_host16(mgmt
->u
.beacon
.capab_info
);
63 if (ieee802_11_parse_elems(mgmt
->u
.beacon
.variable
,
64 len
- (mgmt
->u
.beacon
.variable
- data
),
65 &elems
, 0) == ParseFailed
) {
66 if (bss
->parse_error_reported
)
68 add_note(wt
, MSG_INFO
, "Invalid IEs in a Beacon frame from "
69 MACSTR
, MAC2STR(mgmt
->sa
));
70 bss
->parse_error_reported
= 1;
74 bss_update(wt
, bss
, &elems
);
78 static void rx_mgmt_probe_resp(struct wlantest
*wt
, const u8
*data
, size_t len
)
80 const struct ieee80211_mgmt
*mgmt
;
81 struct wlantest_bss
*bss
;
82 struct ieee802_11_elems elems
;
84 mgmt
= (const struct ieee80211_mgmt
*) data
;
85 bss
= bss_get(wt
, mgmt
->bssid
);
89 bss
->counters
[WLANTEST_BSS_COUNTER_PROBE_RESPONSE
]++;
90 bss
->capab_info
= le_to_host16(mgmt
->u
.probe_resp
.capab_info
);
91 if (ieee802_11_parse_elems(mgmt
->u
.probe_resp
.variable
,
92 len
- (mgmt
->u
.probe_resp
.variable
- data
),
93 &elems
, 0) == ParseFailed
) {
94 if (bss
->parse_error_reported
)
96 add_note(wt
, MSG_INFO
, "Invalid IEs in a Probe Response frame "
97 "from " MACSTR
, MAC2STR(mgmt
->sa
));
98 bss
->parse_error_reported
= 1;
102 bss_update(wt
, bss
, &elems
);
106 static void rx_mgmt_auth(struct wlantest
*wt
, const u8
*data
, size_t len
)
108 const struct ieee80211_mgmt
*mgmt
;
109 struct wlantest_bss
*bss
;
110 struct wlantest_sta
*sta
;
111 u16 alg
, trans
, status
;
113 mgmt
= (const struct ieee80211_mgmt
*) data
;
114 bss
= bss_get(wt
, mgmt
->bssid
);
117 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
118 sta
= sta_get(bss
, mgmt
->da
);
120 sta
= sta_get(bss
, mgmt
->sa
);
125 add_note(wt
, MSG_INFO
, "Too short Authentication frame from "
126 MACSTR
, MAC2STR(mgmt
->sa
));
130 alg
= le_to_host16(mgmt
->u
.auth
.auth_alg
);
131 trans
= le_to_host16(mgmt
->u
.auth
.auth_transaction
);
132 status
= le_to_host16(mgmt
->u
.auth
.status_code
);
134 wpa_printf(MSG_DEBUG
, "AUTH " MACSTR
" -> " MACSTR
135 " (alg=%u trans=%u status=%u)",
136 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), alg
, trans
, status
);
138 if (alg
== 0 && trans
== 2 && status
== 0) {
139 if (sta
->state
== STATE1
) {
140 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
141 " moved to State 2 with " MACSTR
,
142 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
147 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
148 sta
->counters
[WLANTEST_STA_COUNTER_AUTH_RX
]++;
150 sta
->counters
[WLANTEST_STA_COUNTER_AUTH_TX
]++;
154 static void deauth_all_stas(struct wlantest
*wt
, struct wlantest_bss
*bss
)
156 struct wlantest_sta
*sta
;
157 dl_list_for_each(sta
, &bss
->sta
, struct wlantest_sta
, list
) {
158 if (sta
->state
== STATE1
)
160 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
161 " moved to State 1 with " MACSTR
,
162 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
168 static void tdls_link_down(struct wlantest
*wt
, struct wlantest_bss
*bss
,
169 struct wlantest_sta
*sta
)
171 struct wlantest_tdls
*tdls
;
172 dl_list_for_each(tdls
, &bss
->tdls
, struct wlantest_tdls
, list
) {
173 if ((tdls
->init
== sta
|| tdls
->resp
== sta
) && tdls
->link_up
)
175 add_note(wt
, MSG_DEBUG
, "TDLS: Set link down based on "
176 "STA deauth/disassoc");
183 static void rx_mgmt_deauth(struct wlantest
*wt
, const u8
*data
, size_t len
,
186 const struct ieee80211_mgmt
*mgmt
;
187 struct wlantest_bss
*bss
;
188 struct wlantest_sta
*sta
;
191 mgmt
= (const struct ieee80211_mgmt
*) data
;
192 bss
= bss_get(wt
, mgmt
->bssid
);
195 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
196 sta
= sta_get(bss
, mgmt
->da
);
198 sta
= sta_get(bss
, mgmt
->sa
);
201 add_note(wt
, MSG_INFO
, "Too short Deauthentication frame from "
202 MACSTR
, MAC2STR(mgmt
->sa
));
206 reason
= le_to_host16(mgmt
->u
.deauth
.reason_code
);
207 wpa_printf(MSG_DEBUG
, "DEAUTH " MACSTR
" -> " MACSTR
208 " (reason=%u) (valid=%d)",
209 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
211 wpa_hexdump(MSG_MSGDUMP
, "DEAUTH payload", data
+ 24, len
- 24);
214 if (valid
&& mgmt
->da
[0] == 0xff)
215 deauth_all_stas(wt
, bss
);
219 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
220 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DEAUTH_RX
:
221 WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX
]++;
222 if (sta
->pwrmgt
&& !sta
->pspoll
)
223 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_ASLEEP
]++;
225 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_AWAKE
]++;
227 fc
= le_to_host16(mgmt
->frame_control
);
228 if (!(fc
& WLAN_FC_ISWEP
) && reason
== 6)
229 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_RC6
]++;
230 else if (!(fc
& WLAN_FC_ISWEP
) && reason
== 7)
231 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_RC7
]++;
233 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DEAUTH_TX
:
234 WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX
]++;
237 add_note(wt
, MSG_INFO
, "Do not change STA " MACSTR
" State "
238 "since Disassociation frame was not protected "
239 "correctly", MAC2STR(sta
->addr
));
243 if (sta
->state
!= STATE1
) {
244 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
245 " moved to State 1 with " MACSTR
,
246 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
249 tdls_link_down(wt
, bss
, sta
);
253 static void rx_mgmt_assoc_req(struct wlantest
*wt
, const u8
*data
, size_t len
)
255 const struct ieee80211_mgmt
*mgmt
;
256 struct wlantest_bss
*bss
;
257 struct wlantest_sta
*sta
;
258 struct ieee802_11_elems elems
;
260 mgmt
= (const struct ieee80211_mgmt
*) data
;
261 bss
= bss_get(wt
, mgmt
->bssid
);
264 sta
= sta_get(bss
, mgmt
->sa
);
269 add_note(wt
, MSG_INFO
, "Too short Association Request frame "
270 "from " MACSTR
, MAC2STR(mgmt
->sa
));
274 wpa_printf(MSG_DEBUG
, "ASSOCREQ " MACSTR
" -> " MACSTR
275 " (capab=0x%x listen_int=%u)",
276 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
277 le_to_host16(mgmt
->u
.assoc_req
.capab_info
),
278 le_to_host16(mgmt
->u
.assoc_req
.listen_interval
));
280 sta
->counters
[WLANTEST_STA_COUNTER_ASSOCREQ_TX
]++;
282 if (ieee802_11_parse_elems(mgmt
->u
.assoc_req
.variable
,
283 len
- (mgmt
->u
.assoc_req
.variable
- data
),
284 &elems
, 0) == ParseFailed
) {
285 add_note(wt
, MSG_INFO
, "Invalid IEs in Association Request "
286 "frame from " MACSTR
, MAC2STR(mgmt
->sa
));
290 sta
->assocreq_capab_info
= le_to_host16(mgmt
->u
.assoc_req
.capab_info
);
291 sta
->assocreq_listen_int
=
292 le_to_host16(mgmt
->u
.assoc_req
.listen_interval
);
293 os_free(sta
->assocreq_ies
);
294 sta
->assocreq_ies_len
= len
- (mgmt
->u
.assoc_req
.variable
- data
);
295 sta
->assocreq_ies
= os_malloc(sta
->assocreq_ies_len
);
296 if (sta
->assocreq_ies
)
297 os_memcpy(sta
->assocreq_ies
, mgmt
->u
.assoc_req
.variable
,
298 sta
->assocreq_ies_len
);
300 sta_update_assoc(sta
, &elems
);
304 static void rx_mgmt_assoc_resp(struct wlantest
*wt
, const u8
*data
, size_t len
)
306 const struct ieee80211_mgmt
*mgmt
;
307 struct wlantest_bss
*bss
;
308 struct wlantest_sta
*sta
;
309 u16 capab
, status
, aid
;
311 mgmt
= (const struct ieee80211_mgmt
*) data
;
312 bss
= bss_get(wt
, mgmt
->bssid
);
315 sta
= sta_get(bss
, mgmt
->da
);
320 add_note(wt
, MSG_INFO
, "Too short Association Response frame "
321 "from " MACSTR
, MAC2STR(mgmt
->sa
));
325 capab
= le_to_host16(mgmt
->u
.assoc_resp
.capab_info
);
326 status
= le_to_host16(mgmt
->u
.assoc_resp
.status_code
);
327 aid
= le_to_host16(mgmt
->u
.assoc_resp
.aid
);
329 wpa_printf(MSG_DEBUG
, "ASSOCRESP " MACSTR
" -> " MACSTR
330 " (capab=0x%x status=%u aid=%u)",
331 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), capab
, status
,
334 if (status
== WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
) {
335 struct ieee802_11_elems elems
;
336 const u8
*ies
= mgmt
->u
.assoc_resp
.variable
;
337 size_t ies_len
= len
- (mgmt
->u
.assoc_resp
.variable
- data
);
338 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) ==
340 add_note(wt
, MSG_INFO
, "Failed to parse IEs in "
341 "AssocResp from " MACSTR
,
343 } else if (elems
.timeout_int
== NULL
||
344 elems
.timeout_int_len
!= 5 ||
345 elems
.timeout_int
[0] !=
346 WLAN_TIMEOUT_ASSOC_COMEBACK
) {
347 add_note(wt
, MSG_INFO
, "No valid Timeout Interval IE "
348 "with Assoc Comeback time in AssocResp "
349 "(status=30) from " MACSTR
,
353 WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK
]++;
360 if ((aid
& 0xc000) != 0xc000) {
361 add_note(wt
, MSG_DEBUG
, "Two MSBs of the AID were not set to 1 "
362 "in Association Response from " MACSTR
,
365 sta
->aid
= aid
& 0xc000;
367 if (sta
->state
< STATE2
) {
368 add_note(wt
, MSG_DEBUG
,
369 "STA " MACSTR
" was not in State 2 when "
370 "getting associated", MAC2STR(sta
->addr
));
373 if (sta
->state
< STATE3
) {
374 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
375 " moved to State 3 with " MACSTR
,
376 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
382 static void rx_mgmt_reassoc_req(struct wlantest
*wt
, const u8
*data
,
385 const struct ieee80211_mgmt
*mgmt
;
386 struct wlantest_bss
*bss
;
387 struct wlantest_sta
*sta
;
388 struct ieee802_11_elems elems
;
390 mgmt
= (const struct ieee80211_mgmt
*) data
;
391 bss
= bss_get(wt
, mgmt
->bssid
);
394 sta
= sta_get(bss
, mgmt
->sa
);
398 if (len
< 24 + 4 + ETH_ALEN
) {
399 add_note(wt
, MSG_INFO
, "Too short Reassociation Request frame "
400 "from " MACSTR
, MAC2STR(mgmt
->sa
));
404 wpa_printf(MSG_DEBUG
, "REASSOCREQ " MACSTR
" -> " MACSTR
405 " (capab=0x%x listen_int=%u current_ap=" MACSTR
")",
406 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
407 le_to_host16(mgmt
->u
.reassoc_req
.capab_info
),
408 le_to_host16(mgmt
->u
.reassoc_req
.listen_interval
),
409 MAC2STR(mgmt
->u
.reassoc_req
.current_ap
));
411 sta
->counters
[WLANTEST_STA_COUNTER_REASSOCREQ_TX
]++;
413 if (ieee802_11_parse_elems(mgmt
->u
.reassoc_req
.variable
,
414 len
- (mgmt
->u
.reassoc_req
.variable
- data
),
415 &elems
, 0) == ParseFailed
) {
416 add_note(wt
, MSG_INFO
, "Invalid IEs in Reassociation Request "
417 "frame from " MACSTR
, MAC2STR(mgmt
->sa
));
421 sta
->assocreq_capab_info
=
422 le_to_host16(mgmt
->u
.reassoc_req
.capab_info
);
423 sta
->assocreq_listen_int
=
424 le_to_host16(mgmt
->u
.reassoc_req
.listen_interval
);
425 os_free(sta
->assocreq_ies
);
426 sta
->assocreq_ies_len
= len
- (mgmt
->u
.reassoc_req
.variable
- data
);
427 sta
->assocreq_ies
= os_malloc(sta
->assocreq_ies_len
);
428 if (sta
->assocreq_ies
)
429 os_memcpy(sta
->assocreq_ies
, mgmt
->u
.reassoc_req
.variable
,
430 sta
->assocreq_ies_len
);
432 sta_update_assoc(sta
, &elems
);
436 static void rx_mgmt_reassoc_resp(struct wlantest
*wt
, const u8
*data
,
439 const struct ieee80211_mgmt
*mgmt
;
440 struct wlantest_bss
*bss
;
441 struct wlantest_sta
*sta
;
442 u16 capab
, status
, aid
;
444 mgmt
= (const struct ieee80211_mgmt
*) data
;
445 bss
= bss_get(wt
, mgmt
->bssid
);
448 sta
= sta_get(bss
, mgmt
->da
);
453 add_note(wt
, MSG_INFO
, "Too short Reassociation Response frame "
454 "from " MACSTR
, MAC2STR(mgmt
->sa
));
458 capab
= le_to_host16(mgmt
->u
.reassoc_resp
.capab_info
);
459 status
= le_to_host16(mgmt
->u
.reassoc_resp
.status_code
);
460 aid
= le_to_host16(mgmt
->u
.reassoc_resp
.aid
);
462 wpa_printf(MSG_DEBUG
, "REASSOCRESP " MACSTR
" -> " MACSTR
463 " (capab=0x%x status=%u aid=%u)",
464 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), capab
, status
,
467 if (status
== WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
) {
468 struct ieee802_11_elems elems
;
469 const u8
*ies
= mgmt
->u
.reassoc_resp
.variable
;
470 size_t ies_len
= len
- (mgmt
->u
.reassoc_resp
.variable
- data
);
471 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) ==
473 add_note(wt
, MSG_INFO
, "Failed to parse IEs in "
474 "ReassocResp from " MACSTR
,
476 } else if (elems
.timeout_int
== NULL
||
477 elems
.timeout_int_len
!= 5 ||
478 elems
.timeout_int
[0] !=
479 WLAN_TIMEOUT_ASSOC_COMEBACK
) {
480 add_note(wt
, MSG_INFO
, "No valid Timeout Interval IE "
481 "with Assoc Comeback time in ReassocResp "
482 "(status=30) from " MACSTR
,
486 WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK
]++;
493 if ((aid
& 0xc000) != 0xc000) {
494 add_note(wt
, MSG_DEBUG
, "Two MSBs of the AID were not set to 1 "
495 "in Reassociation Response from " MACSTR
,
498 sta
->aid
= aid
& 0xc000;
500 if (sta
->state
< STATE2
) {
501 add_note(wt
, MSG_DEBUG
,
502 "STA " MACSTR
" was not in State 2 when "
503 "getting associated", MAC2STR(sta
->addr
));
506 if (sta
->state
< STATE3
) {
507 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
508 " moved to State 3 with " MACSTR
,
509 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
515 static void disassoc_all_stas(struct wlantest
*wt
, struct wlantest_bss
*bss
)
517 struct wlantest_sta
*sta
;
518 dl_list_for_each(sta
, &bss
->sta
, struct wlantest_sta
, list
) {
519 if (sta
->state
<= STATE2
)
521 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
522 " moved to State 2 with " MACSTR
,
523 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
529 static void rx_mgmt_disassoc(struct wlantest
*wt
, const u8
*data
, size_t len
,
532 const struct ieee80211_mgmt
*mgmt
;
533 struct wlantest_bss
*bss
;
534 struct wlantest_sta
*sta
;
537 mgmt
= (const struct ieee80211_mgmt
*) data
;
538 bss
= bss_get(wt
, mgmt
->bssid
);
541 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
542 sta
= sta_get(bss
, mgmt
->da
);
544 sta
= sta_get(bss
, mgmt
->sa
);
547 add_note(wt
, MSG_INFO
, "Too short Disassociation frame from "
548 MACSTR
, MAC2STR(mgmt
->sa
));
552 reason
= le_to_host16(mgmt
->u
.disassoc
.reason_code
);
553 wpa_printf(MSG_DEBUG
, "DISASSOC " MACSTR
" -> " MACSTR
554 " (reason=%u) (valid=%d)",
555 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
557 wpa_hexdump(MSG_MSGDUMP
, "DISASSOC payload", data
+ 24, len
- 24);
560 if (valid
&& mgmt
->da
[0] == 0xff)
561 disassoc_all_stas(wt
, bss
);
565 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
566 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DISASSOC_RX
:
567 WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX
]++;
568 if (sta
->pwrmgt
&& !sta
->pspoll
)
570 WLANTEST_STA_COUNTER_DISASSOC_RX_ASLEEP
]++;
573 WLANTEST_STA_COUNTER_DISASSOC_RX_AWAKE
]++;
575 fc
= le_to_host16(mgmt
->frame_control
);
576 if (!(fc
& WLAN_FC_ISWEP
) && reason
== 6)
577 sta
->counters
[WLANTEST_STA_COUNTER_DISASSOC_RX_RC6
]++;
578 else if (!(fc
& WLAN_FC_ISWEP
) && reason
== 7)
579 sta
->counters
[WLANTEST_STA_COUNTER_DISASSOC_RX_RC7
]++;
581 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DISASSOC_TX
:
582 WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX
]++;
585 add_note(wt
, MSG_INFO
, "Do not change STA " MACSTR
" State "
586 "since Disassociation frame was not protected "
587 "correctly", MAC2STR(sta
->addr
));
591 if (sta
->state
< STATE2
) {
592 add_note(wt
, MSG_DEBUG
,
593 "STA " MACSTR
" was not in State 2 or 3 "
594 "when getting disassociated", MAC2STR(sta
->addr
));
597 if (sta
->state
> STATE2
) {
598 add_note(wt
, MSG_DEBUG
, "STA " MACSTR
599 " moved to State 2 with " MACSTR
,
600 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
603 tdls_link_down(wt
, bss
, sta
);
607 static void rx_mgmt_action_sa_query_req(struct wlantest
*wt
,
608 struct wlantest_sta
*sta
,
609 const struct ieee80211_mgmt
*mgmt
,
610 size_t len
, int valid
)
615 rx_id
= (const u8
*) mgmt
->u
.action
.u
.sa_query_req
.trans_id
;
616 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
617 id
= sta
->ap_sa_query_tr
;
619 id
= sta
->sta_sa_query_tr
;
620 add_note(wt
, MSG_INFO
, "SA Query Request " MACSTR
" -> " MACSTR
621 " (trans_id=%02x%02x)%s",
622 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), rx_id
[0], rx_id
[1],
623 valid
? "" : " (invalid protection)");
624 os_memcpy(id
, mgmt
->u
.action
.u
.sa_query_req
.trans_id
, 2);
625 if (os_memcmp(mgmt
->sa
, sta
->addr
, ETH_ALEN
) == 0)
626 sta
->counters
[valid
?
627 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX
:
628 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX
]++;
630 sta
->counters
[valid
?
631 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX
:
632 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX
]++;
636 static void rx_mgmt_action_sa_query_resp(struct wlantest
*wt
,
637 struct wlantest_sta
*sta
,
638 const struct ieee80211_mgmt
*mgmt
,
639 size_t len
, int valid
)
645 rx_id
= (const u8
*) mgmt
->u
.action
.u
.sa_query_resp
.trans_id
;
646 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
647 id
= sta
->sta_sa_query_tr
;
649 id
= sta
->ap_sa_query_tr
;
650 match
= os_memcmp(rx_id
, id
, 2) == 0;
651 add_note(wt
, MSG_INFO
, "SA Query Response " MACSTR
" -> " MACSTR
652 " (trans_id=%02x%02x; %s)%s",
653 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), rx_id
[0], rx_id
[1],
654 match
? "match" : "mismatch",
655 valid
? "" : " (invalid protection)");
656 if (os_memcmp(mgmt
->sa
, sta
->addr
, ETH_ALEN
) == 0)
657 sta
->counters
[(valid
&& match
) ?
658 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX
:
659 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX
]++;
661 sta
->counters
[(valid
&& match
) ?
662 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX
:
663 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX
]++;
667 static void rx_mgmt_action_sa_query(struct wlantest
*wt
,
668 struct wlantest_sta
*sta
,
669 const struct ieee80211_mgmt
*mgmt
,
670 size_t len
, int valid
)
672 if (len
< 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
) {
673 add_note(wt
, MSG_INFO
, "Too short SA Query frame from " MACSTR
,
678 if (len
> 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
) {
679 size_t elen
= len
- (24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
);
680 add_note(wt
, MSG_INFO
, "Unexpected %u octets of extra data at "
681 "the end of SA Query frame from " MACSTR
,
682 (unsigned) elen
, MAC2STR(mgmt
->sa
));
683 wpa_hexdump(MSG_INFO
, "SA Query extra data",
684 ((const u8
*) mgmt
) + len
- elen
, elen
);
687 switch (mgmt
->u
.action
.u
.sa_query_req
.action
) {
688 case WLAN_SA_QUERY_REQUEST
:
689 rx_mgmt_action_sa_query_req(wt
, sta
, mgmt
, len
, valid
);
691 case WLAN_SA_QUERY_RESPONSE
:
692 rx_mgmt_action_sa_query_resp(wt
, sta
, mgmt
, len
, valid
);
695 add_note(wt
, MSG_INFO
, "Unexpected SA Query action value %u "
697 mgmt
->u
.action
.u
.sa_query_req
.action
,
703 static void rx_mgmt_action(struct wlantest
*wt
, const u8
*data
, size_t len
,
706 const struct ieee80211_mgmt
*mgmt
;
707 struct wlantest_bss
*bss
;
708 struct wlantest_sta
*sta
;
710 mgmt
= (const struct ieee80211_mgmt
*) data
;
711 if (mgmt
->da
[0] & 0x01) {
712 add_note(wt
, MSG_DEBUG
, "Group addressed Action frame: DA="
713 MACSTR
" SA=" MACSTR
" BSSID=" MACSTR
715 MAC2STR(mgmt
->da
), MAC2STR(mgmt
->sa
),
716 MAC2STR(mgmt
->bssid
), mgmt
->u
.action
.category
);
717 return; /* Ignore group addressed Action frames for now */
719 bss
= bss_get(wt
, mgmt
->bssid
);
722 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
723 sta
= sta_get(bss
, mgmt
->da
);
725 sta
= sta_get(bss
, mgmt
->sa
);
730 add_note(wt
, MSG_INFO
, "Too short Action frame from " MACSTR
,
735 wpa_printf(MSG_DEBUG
, "ACTION " MACSTR
" -> " MACSTR
736 " (category=%u) (valid=%d)",
737 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
738 mgmt
->u
.action
.category
, valid
);
739 wpa_hexdump(MSG_MSGDUMP
, "ACTION payload", data
+ 24, len
- 24);
741 if (mgmt
->u
.action
.category
!= WLAN_ACTION_PUBLIC
&&
742 sta
->state
< STATE3
) {
743 add_note(wt
, MSG_INFO
, "Action frame sent when STA is not in "
744 "State 3 (SA=" MACSTR
" DATA=" MACSTR
")",
745 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
748 switch (mgmt
->u
.action
.category
) {
749 case WLAN_ACTION_SA_QUERY
:
750 rx_mgmt_action_sa_query(wt
, sta
, mgmt
, len
, valid
);
756 static int check_mmie_mic(const u8
*igtk
, size_t igtk_len
,
757 const u8
*data
, size_t len
)
762 const struct ieee80211_hdr
*hdr
;
767 else if (igtk_len
== 16)
772 if (len
< 24 || len
- 24 < mic_len
)
775 buf
= os_malloc(len
+ 20 - 24);
779 /* BIP AAD: FC(masked) A1 A2 A3 */
780 hdr
= (const struct ieee80211_hdr
*) data
;
781 fc
= le_to_host16(hdr
->frame_control
);
782 fc
&= ~(WLAN_FC_RETRY
| WLAN_FC_PWRMGT
| WLAN_FC_MOREDATA
);
783 WPA_PUT_LE16(buf
, fc
);
784 os_memcpy(buf
+ 2, hdr
->addr1
, 3 * ETH_ALEN
);
786 /* Frame body with MMIE MIC masked to zero */
787 os_memcpy(buf
+ 20, data
+ 24, len
- 24 - mic_len
);
788 os_memset(buf
+ 20 + len
- 24 - mic_len
, 0, mic_len
);
790 wpa_hexdump(MSG_MSGDUMP
, "BIP: AAD|Body(masked)", buf
, len
+ 20 - 24);
791 /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
793 ret
= omac1_aes_256(igtk
, buf
, len
+ 20 - 24, mic
);
795 ret
= omac1_aes_128(igtk
, buf
, len
+ 20 - 24, mic
);
803 if (os_memcmp(data
+ len
- mic_len
, mic
, mic_len
) != 0)
810 static int check_bip(struct wlantest
*wt
, const u8
*data
, size_t len
)
812 const struct ieee80211_mgmt
*mgmt
;
816 struct wlantest_bss
*bss
;
819 mgmt
= (const struct ieee80211_mgmt
*) data
;
820 fc
= le_to_host16(mgmt
->frame_control
);
821 stype
= WLAN_FC_GET_STYPE(fc
);
823 if (stype
== WLAN_FC_STYPE_ACTION
) {
826 if (mgmt
->u
.action
.category
== WLAN_ACTION_PUBLIC
)
827 return 0; /* Not a robust management frame */
830 bss
= bss_get(wt
, mgmt
->bssid
);
832 return 0; /* No key known yet */
834 mic_len
= bss
->igtk_len
[4] == 32 || bss
->igtk_len
[5] == 32 ? 16 : 8;
836 if (len
< 24 + 10 + mic_len
||
837 data
[len
- (10 + mic_len
)] != WLAN_EID_MMIE
||
838 data
[len
- (10 + mic_len
- 1)] != 8 + mic_len
) {
840 if (bss
->rsn_capab
& WPA_CAPABILITY_MFPC
) {
841 add_note(wt
, MSG_INFO
, "Robust group-addressed "
842 "management frame sent without BIP by "
843 MACSTR
, MAC2STR(mgmt
->sa
));
844 bss
->counters
[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE
]++;
850 mmie
= data
+ len
- (8 + mic_len
);
851 keyid
= WPA_GET_LE16(mmie
);
852 if (keyid
& 0xf000) {
853 add_note(wt
, MSG_INFO
, "MMIE KeyID reserved bits not zero "
854 "(%04x) from " MACSTR
, keyid
, MAC2STR(mgmt
->sa
));
857 if (keyid
< 4 || keyid
> 5) {
858 add_note(wt
, MSG_INFO
, "Unexpected MMIE KeyID %u from " MACSTR
,
859 keyid
, MAC2STR(mgmt
->sa
));
860 bss
->counters
[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE
]++;
863 wpa_printf(MSG_DEBUG
, "MMIE KeyID %u", keyid
);
864 wpa_hexdump(MSG_MSGDUMP
, "MMIE IPN", mmie
+ 2, 6);
865 wpa_hexdump(MSG_MSGDUMP
, "MMIE MIC", mmie
+ 8, mic_len
);
867 if (!bss
->igtk_len
[keyid
]) {
868 add_note(wt
, MSG_DEBUG
, "No IGTK known to validate BIP frame");
872 if (os_memcmp(mmie
+ 2, bss
->ipn
[keyid
], 6) <= 0) {
873 add_note(wt
, MSG_INFO
, "BIP replay detected: SA=" MACSTR
,
875 wpa_hexdump(MSG_INFO
, "RX IPN", mmie
+ 2, 6);
876 wpa_hexdump(MSG_INFO
, "Last RX IPN", bss
->ipn
[keyid
], 6);
879 if (check_mmie_mic(bss
->igtk
[keyid
], bss
->igtk_len
[keyid
], data
, len
) <
881 add_note(wt
, MSG_INFO
, "Invalid MMIE MIC in a frame from "
882 MACSTR
, MAC2STR(mgmt
->sa
));
883 bss
->counters
[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE
]++;
887 add_note(wt
, MSG_DEBUG
, "Valid MMIE MIC");
888 os_memcpy(bss
->ipn
[keyid
], mmie
+ 2, 6);
889 bss
->counters
[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE
]++;
891 if (stype
== WLAN_FC_STYPE_DEAUTH
)
892 bss
->counters
[WLANTEST_BSS_COUNTER_BIP_DEAUTH
]++;
893 else if (stype
== WLAN_FC_STYPE_DISASSOC
)
894 bss
->counters
[WLANTEST_BSS_COUNTER_BIP_DISASSOC
]++;
900 static u8
* mgmt_ccmp_decrypt(struct wlantest
*wt
, const u8
*data
, size_t len
,
903 struct wlantest_bss
*bss
;
904 struct wlantest_sta
*sta
;
905 const struct ieee80211_hdr
*hdr
;
907 u8
*decrypted
, *frame
= NULL
;
910 hdr
= (const struct ieee80211_hdr
*) data
;
911 bss
= bss_get(wt
, hdr
->addr3
);
914 if (os_memcmp(hdr
->addr1
, hdr
->addr3
, ETH_ALEN
) == 0)
915 sta
= sta_get(bss
, hdr
->addr2
);
917 sta
= sta_get(bss
, hdr
->addr1
);
918 if (sta
== NULL
|| !sta
->ptk_set
) {
919 add_note(wt
, MSG_MSGDUMP
, "No PTK known to decrypt the frame");
926 if (!(data
[24 + 3] & 0x20)) {
927 add_note(wt
, MSG_INFO
, "Expected CCMP frame from " MACSTR
928 " did not have ExtIV bit set to 1",
929 MAC2STR(hdr
->addr2
));
933 if (data
[24 + 2] != 0 || (data
[24 + 3] & 0x1f) != 0) {
934 add_note(wt
, MSG_INFO
, "CCMP mgmt frame from " MACSTR
" used "
935 "non-zero reserved bit", MAC2STR(hdr
->addr2
));
938 keyid
= data
[24 + 3] >> 6;
940 add_note(wt
, MSG_INFO
, "Unexpected non-zero KeyID %d in "
941 "individually addressed Management frame from "
942 MACSTR
, keyid
, MAC2STR(hdr
->addr2
));
945 if (os_memcmp(hdr
->addr1
, hdr
->addr3
, ETH_ALEN
) == 0)
946 rsc
= sta
->rsc_tods
[16];
948 rsc
= sta
->rsc_fromds
[16];
950 ccmp_get_pn(pn
, data
+ 24);
951 if (os_memcmp(pn
, rsc
, 6) <= 0) {
952 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
953 add_note(wt
, MSG_INFO
, "CCMP/TKIP replay detected: A1=" MACSTR
954 " A2=" MACSTR
" A3=" MACSTR
" seq=%u frag=%u%s",
955 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
957 WLAN_GET_SEQ_SEQ(seq_ctrl
),
958 WLAN_GET_SEQ_FRAG(seq_ctrl
),
959 (le_to_host16(hdr
->frame_control
) & WLAN_FC_RETRY
) ?
961 wpa_hexdump(MSG_INFO
, "RX PN", pn
, 6);
962 wpa_hexdump(MSG_INFO
, "RSC", rsc
, 6);
965 decrypted
= ccmp_decrypt(sta
->ptk
.tk1
, hdr
, data
+ 24, len
- 24, dlen
);
967 os_memcpy(rsc
, pn
, 6);
968 frame
= os_malloc(24 + *dlen
);
970 os_memcpy(frame
, data
, 24);
971 os_memcpy(frame
+ 24, decrypted
, *dlen
);
982 static int check_mgmt_ccmp(struct wlantest
*wt
, const u8
*data
, size_t len
)
984 const struct ieee80211_mgmt
*mgmt
;
986 struct wlantest_bss
*bss
;
987 struct wlantest_sta
*sta
;
989 mgmt
= (const struct ieee80211_mgmt
*) data
;
990 fc
= le_to_host16(mgmt
->frame_control
);
992 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACTION
) {
994 mgmt
->u
.action
.category
== WLAN_ACTION_PUBLIC
)
995 return 0; /* Not a robust management frame */
998 bss
= bss_get(wt
, mgmt
->bssid
);
1001 if (os_memcmp(mgmt
->da
, mgmt
->bssid
, ETH_ALEN
) == 0)
1002 sta
= sta_get(bss
, mgmt
->sa
);
1004 sta
= sta_get(bss
, mgmt
->da
);
1008 if ((sta
->rsn_capab
& WPA_CAPABILITY_MFPC
) &&
1009 (sta
->state
== STATE3
||
1010 WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACTION
)) {
1011 add_note(wt
, MSG_INFO
, "Robust individually-addressed "
1012 "management frame sent without CCMP by "
1013 MACSTR
, MAC2STR(mgmt
->sa
));
1021 void rx_mgmt(struct wlantest
*wt
, const u8
*data
, size_t len
)
1023 const struct ieee80211_hdr
*hdr
;
1026 u8
*decrypted
= NULL
;
1032 hdr
= (const struct ieee80211_hdr
*) data
;
1033 fc
= le_to_host16(hdr
->frame_control
);
1035 stype
= WLAN_FC_GET_STYPE(fc
);
1037 if ((hdr
->addr1
[0] & 0x01) &&
1038 (stype
== WLAN_FC_STYPE_DEAUTH
||
1039 stype
== WLAN_FC_STYPE_DISASSOC
||
1040 stype
== WLAN_FC_STYPE_ACTION
)) {
1041 if (check_bip(wt
, data
, len
) < 0)
1045 wpa_printf((stype
== WLAN_FC_STYPE_BEACON
||
1046 stype
== WLAN_FC_STYPE_PROBE_RESP
||
1047 stype
== WLAN_FC_STYPE_PROBE_REQ
) ?
1048 MSG_EXCESSIVE
: MSG_MSGDUMP
,
1049 "MGMT %s%s%s DA=" MACSTR
" SA=" MACSTR
" BSSID=" MACSTR
,
1051 fc
& WLAN_FC_PWRMGT
? " PwrMgt" : "",
1052 fc
& WLAN_FC_ISWEP
? " Prot" : "",
1053 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
1054 MAC2STR(hdr
->addr3
));
1056 if ((fc
& WLAN_FC_ISWEP
) &&
1057 !(hdr
->addr1
[0] & 0x01) &&
1058 (stype
== WLAN_FC_STYPE_DEAUTH
||
1059 stype
== WLAN_FC_STYPE_DISASSOC
||
1060 stype
== WLAN_FC_STYPE_ACTION
)) {
1061 decrypted
= mgmt_ccmp_decrypt(wt
, data
, len
, &dlen
);
1063 write_pcap_decrypted(wt
, decrypted
, dlen
, NULL
, 0);
1070 if (!(fc
& WLAN_FC_ISWEP
) &&
1071 !(hdr
->addr1
[0] & 0x01) &&
1072 (stype
== WLAN_FC_STYPE_DEAUTH
||
1073 stype
== WLAN_FC_STYPE_DISASSOC
||
1074 stype
== WLAN_FC_STYPE_ACTION
)) {
1075 if (check_mgmt_ccmp(wt
, data
, len
) < 0)
1080 case WLAN_FC_STYPE_BEACON
:
1081 rx_mgmt_beacon(wt
, data
, len
);
1083 case WLAN_FC_STYPE_PROBE_RESP
:
1084 rx_mgmt_probe_resp(wt
, data
, len
);
1086 case WLAN_FC_STYPE_AUTH
:
1087 rx_mgmt_auth(wt
, data
, len
);
1089 case WLAN_FC_STYPE_DEAUTH
:
1090 rx_mgmt_deauth(wt
, data
, len
, valid
);
1092 case WLAN_FC_STYPE_ASSOC_REQ
:
1093 rx_mgmt_assoc_req(wt
, data
, len
);
1095 case WLAN_FC_STYPE_ASSOC_RESP
:
1096 rx_mgmt_assoc_resp(wt
, data
, len
);
1098 case WLAN_FC_STYPE_REASSOC_REQ
:
1099 rx_mgmt_reassoc_req(wt
, data
, len
);
1101 case WLAN_FC_STYPE_REASSOC_RESP
:
1102 rx_mgmt_reassoc_resp(wt
, data
, len
);
1104 case WLAN_FC_STYPE_DISASSOC
:
1105 rx_mgmt_disassoc(wt
, data
, len
, valid
);
1107 case WLAN_FC_STYPE_ACTION
:
1108 rx_mgmt_action(wt
, data
, len
, valid
);
1114 wt
->last_mgmt_valid
= valid
;
1118 static void rx_mgmt_deauth_ack(struct wlantest
*wt
,
1119 const struct ieee80211_hdr
*hdr
)
1121 const struct ieee80211_mgmt
*mgmt
;
1122 struct wlantest_bss
*bss
;
1123 struct wlantest_sta
*sta
;
1125 mgmt
= (const struct ieee80211_mgmt
*) hdr
;
1126 bss
= bss_get(wt
, mgmt
->bssid
);
1129 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
1130 sta
= sta_get(bss
, mgmt
->da
);
1132 sta
= sta_get(bss
, mgmt
->sa
);
1136 add_note(wt
, MSG_DEBUG
, "DEAUTH from " MACSTR
" acknowledged by "
1137 MACSTR
, MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
1138 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
1140 c
= wt
->last_mgmt_valid
?
1141 WLANTEST_STA_COUNTER_VALID_DEAUTH_RX_ACK
:
1142 WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX_ACK
;
1148 static void rx_mgmt_disassoc_ack(struct wlantest
*wt
,
1149 const struct ieee80211_hdr
*hdr
)
1151 const struct ieee80211_mgmt
*mgmt
;
1152 struct wlantest_bss
*bss
;
1153 struct wlantest_sta
*sta
;
1155 mgmt
= (const struct ieee80211_mgmt
*) hdr
;
1156 bss
= bss_get(wt
, mgmt
->bssid
);
1159 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
1160 sta
= sta_get(bss
, mgmt
->da
);
1162 sta
= sta_get(bss
, mgmt
->sa
);
1166 add_note(wt
, MSG_DEBUG
, "DISASSOC from " MACSTR
" acknowledged by "
1167 MACSTR
, MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
1168 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
1170 c
= wt
->last_mgmt_valid
?
1171 WLANTEST_STA_COUNTER_VALID_DISASSOC_RX_ACK
:
1172 WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX_ACK
;
1178 void rx_mgmt_ack(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
)
1181 fc
= le_to_host16(hdr
->frame_control
);
1182 stype
= WLAN_FC_GET_STYPE(fc
);
1184 wpa_printf(MSG_MSGDUMP
, "MGMT ACK: stype=%u a1=" MACSTR
" a2=" MACSTR
1186 stype
, MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
1187 MAC2STR(hdr
->addr3
));
1190 case WLAN_FC_STYPE_DEAUTH
:
1191 rx_mgmt_deauth_ack(wt
, hdr
);
1193 case WLAN_FC_STYPE_DISASSOC
:
1194 rx_mgmt_disassoc_ack(wt
, hdr
);