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 wpa_printf(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
->capab_info
= le_to_host16(mgmt
->u
.probe_resp
.capab_info
);
90 if (ieee802_11_parse_elems(mgmt
->u
.probe_resp
.variable
,
91 len
- (mgmt
->u
.probe_resp
.variable
- data
),
92 &elems
, 0) == ParseFailed
) {
93 if (bss
->parse_error_reported
)
95 wpa_printf(MSG_INFO
, "Invalid IEs in a Probe Response frame "
96 "from " MACSTR
, MAC2STR(mgmt
->sa
));
97 bss
->parse_error_reported
= 1;
101 bss_update(wt
, bss
, &elems
);
105 static void rx_mgmt_auth(struct wlantest
*wt
, const u8
*data
, size_t len
)
107 const struct ieee80211_mgmt
*mgmt
;
108 struct wlantest_bss
*bss
;
109 struct wlantest_sta
*sta
;
110 u16 alg
, trans
, status
;
112 mgmt
= (const struct ieee80211_mgmt
*) data
;
113 bss
= bss_get(wt
, mgmt
->bssid
);
116 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
117 sta
= sta_get(bss
, mgmt
->da
);
119 sta
= sta_get(bss
, mgmt
->sa
);
124 wpa_printf(MSG_INFO
, "Too short Authentication frame from "
125 MACSTR
, MAC2STR(mgmt
->sa
));
129 alg
= le_to_host16(mgmt
->u
.auth
.auth_alg
);
130 trans
= le_to_host16(mgmt
->u
.auth
.auth_transaction
);
131 status
= le_to_host16(mgmt
->u
.auth
.status_code
);
133 wpa_printf(MSG_DEBUG
, "AUTH " MACSTR
" -> " MACSTR
134 " (alg=%u trans=%u status=%u)",
135 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), alg
, trans
, status
);
137 if (alg
== 0 && trans
== 2 && status
== 0) {
138 if (sta
->state
== STATE1
) {
139 wpa_printf(MSG_DEBUG
, "STA " MACSTR
140 " moved to State 2 with " MACSTR
,
141 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
146 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
147 sta
->counters
[WLANTEST_STA_COUNTER_AUTH_RX
]++;
149 sta
->counters
[WLANTEST_STA_COUNTER_AUTH_TX
]++;
153 static void deauth_all_stas(struct wlantest_bss
*bss
)
155 struct wlantest_sta
*sta
;
156 dl_list_for_each(sta
, &bss
->sta
, struct wlantest_sta
, list
) {
157 if (sta
->state
== STATE1
)
159 wpa_printf(MSG_DEBUG
, "STA " MACSTR
160 " moved to State 1 with " MACSTR
,
161 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
167 static void tdls_link_down(struct wlantest_bss
*bss
, struct wlantest_sta
*sta
)
169 struct wlantest_tdls
*tdls
;
170 dl_list_for_each(tdls
, &bss
->tdls
, struct wlantest_tdls
, list
) {
171 if ((tdls
->init
== sta
|| tdls
->resp
== sta
) && tdls
->link_up
)
173 wpa_printf(MSG_DEBUG
, "TDLS: Set link down based on "
174 "STA deauth/disassoc");
181 static void rx_mgmt_deauth(struct wlantest
*wt
, const u8
*data
, size_t len
,
184 const struct ieee80211_mgmt
*mgmt
;
185 struct wlantest_bss
*bss
;
186 struct wlantest_sta
*sta
;
189 mgmt
= (const struct ieee80211_mgmt
*) data
;
190 bss
= bss_get(wt
, mgmt
->bssid
);
193 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
194 sta
= sta_get(bss
, mgmt
->da
);
196 sta
= sta_get(bss
, mgmt
->sa
);
199 wpa_printf(MSG_INFO
, "Too short Deauthentication frame from "
200 MACSTR
, MAC2STR(mgmt
->sa
));
204 reason
= le_to_host16(mgmt
->u
.deauth
.reason_code
);
205 wpa_printf(MSG_DEBUG
, "DEAUTH " MACSTR
" -> " MACSTR
206 " (reason=%u) (valid=%d)",
207 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
209 wpa_hexdump(MSG_MSGDUMP
, "DEAUTH payload", data
+ 24, len
- 24);
212 if (valid
&& mgmt
->da
[0] == 0xff)
213 deauth_all_stas(bss
);
217 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
218 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DEAUTH_RX
:
219 WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX
]++;
220 if (sta
->pwrmgt
&& !sta
->pspoll
)
221 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_ASLEEP
]++;
223 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_AWAKE
]++;
225 fc
= le_to_host16(mgmt
->frame_control
);
226 if (!(fc
& WLAN_FC_ISWEP
) && reason
== 6)
227 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_RC6
]++;
228 else if (!(fc
& WLAN_FC_ISWEP
) && reason
== 7)
229 sta
->counters
[WLANTEST_STA_COUNTER_DEAUTH_RX_RC7
]++;
231 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DEAUTH_TX
:
232 WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX
]++;
235 wpa_printf(MSG_INFO
, "Do not change STA " MACSTR
" State "
236 "since Disassociation frame was not protected "
237 "correctly", MAC2STR(sta
->addr
));
241 if (sta
->state
!= STATE1
) {
242 wpa_printf(MSG_DEBUG
, "STA " MACSTR
243 " moved to State 1 with " MACSTR
,
244 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
247 tdls_link_down(bss
, sta
);
251 static void rx_mgmt_assoc_req(struct wlantest
*wt
, const u8
*data
, size_t len
)
253 const struct ieee80211_mgmt
*mgmt
;
254 struct wlantest_bss
*bss
;
255 struct wlantest_sta
*sta
;
256 struct ieee802_11_elems elems
;
258 mgmt
= (const struct ieee80211_mgmt
*) data
;
259 bss
= bss_get(wt
, mgmt
->bssid
);
262 sta
= sta_get(bss
, mgmt
->sa
);
267 wpa_printf(MSG_INFO
, "Too short Association Request frame "
268 "from " MACSTR
, MAC2STR(mgmt
->sa
));
272 wpa_printf(MSG_DEBUG
, "ASSOCREQ " MACSTR
" -> " MACSTR
273 " (capab=0x%x listen_int=%u)",
274 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
275 le_to_host16(mgmt
->u
.assoc_req
.capab_info
),
276 le_to_host16(mgmt
->u
.assoc_req
.listen_interval
));
278 sta
->counters
[WLANTEST_STA_COUNTER_ASSOCREQ_TX
]++;
280 if (ieee802_11_parse_elems(mgmt
->u
.assoc_req
.variable
,
281 len
- (mgmt
->u
.assoc_req
.variable
- data
),
282 &elems
, 0) == ParseFailed
) {
283 wpa_printf(MSG_INFO
, "Invalid IEs in Association Request "
284 "frame from " MACSTR
, MAC2STR(mgmt
->sa
));
288 sta
->assocreq_capab_info
= le_to_host16(mgmt
->u
.assoc_req
.capab_info
);
289 sta
->assocreq_listen_int
=
290 le_to_host16(mgmt
->u
.assoc_req
.listen_interval
);
291 os_free(sta
->assocreq_ies
);
292 sta
->assocreq_ies_len
= len
- (mgmt
->u
.assoc_req
.variable
- data
);
293 sta
->assocreq_ies
= os_malloc(sta
->assocreq_ies_len
);
294 if (sta
->assocreq_ies
)
295 os_memcpy(sta
->assocreq_ies
, mgmt
->u
.assoc_req
.variable
,
296 sta
->assocreq_ies_len
);
298 sta_update_assoc(sta
, &elems
);
302 static void rx_mgmt_assoc_resp(struct wlantest
*wt
, const u8
*data
, size_t len
)
304 const struct ieee80211_mgmt
*mgmt
;
305 struct wlantest_bss
*bss
;
306 struct wlantest_sta
*sta
;
307 u16 capab
, status
, aid
;
309 mgmt
= (const struct ieee80211_mgmt
*) data
;
310 bss
= bss_get(wt
, mgmt
->bssid
);
313 sta
= sta_get(bss
, mgmt
->da
);
318 wpa_printf(MSG_INFO
, "Too short Association Response frame "
319 "from " MACSTR
, MAC2STR(mgmt
->sa
));
323 capab
= le_to_host16(mgmt
->u
.assoc_resp
.capab_info
);
324 status
= le_to_host16(mgmt
->u
.assoc_resp
.status_code
);
325 aid
= le_to_host16(mgmt
->u
.assoc_resp
.aid
);
327 wpa_printf(MSG_DEBUG
, "ASSOCRESP " MACSTR
" -> " MACSTR
328 " (capab=0x%x status=%u aid=%u)",
329 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), capab
, status
,
332 if (status
== WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
) {
333 struct ieee802_11_elems elems
;
334 const u8
*ies
= mgmt
->u
.assoc_resp
.variable
;
335 size_t ies_len
= len
- (mgmt
->u
.assoc_resp
.variable
- data
);
336 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) ==
338 wpa_printf(MSG_INFO
, "Failed to parse IEs in "
339 "AssocResp from " MACSTR
,
341 } else if (elems
.timeout_int
== NULL
||
342 elems
.timeout_int_len
!= 5 ||
343 elems
.timeout_int
[0] !=
344 WLAN_TIMEOUT_ASSOC_COMEBACK
) {
345 wpa_printf(MSG_INFO
, "No valid Timeout Interval IE "
346 "with Assoc Comeback time in AssocResp "
347 "(status=30) from " MACSTR
,
351 WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK
]++;
358 if ((aid
& 0xc000) != 0xc000) {
359 wpa_printf(MSG_DEBUG
, "Two MSBs of the AID were not set to 1 "
360 "in Association Response from " MACSTR
,
363 sta
->aid
= aid
& 0xc000;
365 if (sta
->state
< STATE2
) {
366 wpa_printf(MSG_DEBUG
, "STA " MACSTR
" was not in State 2 when "
367 "getting associated", MAC2STR(sta
->addr
));
370 if (sta
->state
< STATE3
) {
371 wpa_printf(MSG_DEBUG
, "STA " MACSTR
372 " moved to State 3 with " MACSTR
,
373 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
379 static void rx_mgmt_reassoc_req(struct wlantest
*wt
, const u8
*data
,
382 const struct ieee80211_mgmt
*mgmt
;
383 struct wlantest_bss
*bss
;
384 struct wlantest_sta
*sta
;
385 struct ieee802_11_elems elems
;
387 mgmt
= (const struct ieee80211_mgmt
*) data
;
388 bss
= bss_get(wt
, mgmt
->bssid
);
391 sta
= sta_get(bss
, mgmt
->sa
);
395 if (len
< 24 + 4 + ETH_ALEN
) {
396 wpa_printf(MSG_INFO
, "Too short Reassociation Request frame "
397 "from " MACSTR
, MAC2STR(mgmt
->sa
));
401 wpa_printf(MSG_DEBUG
, "REASSOCREQ " MACSTR
" -> " MACSTR
402 " (capab=0x%x listen_int=%u current_ap=" MACSTR
")",
403 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
404 le_to_host16(mgmt
->u
.reassoc_req
.capab_info
),
405 le_to_host16(mgmt
->u
.reassoc_req
.listen_interval
),
406 MAC2STR(mgmt
->u
.reassoc_req
.current_ap
));
408 sta
->counters
[WLANTEST_STA_COUNTER_REASSOCREQ_TX
]++;
410 if (ieee802_11_parse_elems(mgmt
->u
.reassoc_req
.variable
,
411 len
- (mgmt
->u
.reassoc_req
.variable
- data
),
412 &elems
, 0) == ParseFailed
) {
413 wpa_printf(MSG_INFO
, "Invalid IEs in Reassociation Request "
414 "frame from " MACSTR
, MAC2STR(mgmt
->sa
));
418 sta
->assocreq_capab_info
=
419 le_to_host16(mgmt
->u
.reassoc_req
.capab_info
);
420 sta
->assocreq_listen_int
=
421 le_to_host16(mgmt
->u
.reassoc_req
.listen_interval
);
422 os_free(sta
->assocreq_ies
);
423 sta
->assocreq_ies_len
= len
- (mgmt
->u
.reassoc_req
.variable
- data
);
424 sta
->assocreq_ies
= os_malloc(sta
->assocreq_ies_len
);
425 if (sta
->assocreq_ies
)
426 os_memcpy(sta
->assocreq_ies
, mgmt
->u
.reassoc_req
.variable
,
427 sta
->assocreq_ies_len
);
429 sta_update_assoc(sta
, &elems
);
433 static void rx_mgmt_reassoc_resp(struct wlantest
*wt
, const u8
*data
,
436 const struct ieee80211_mgmt
*mgmt
;
437 struct wlantest_bss
*bss
;
438 struct wlantest_sta
*sta
;
439 u16 capab
, status
, aid
;
441 mgmt
= (const struct ieee80211_mgmt
*) data
;
442 bss
= bss_get(wt
, mgmt
->bssid
);
445 sta
= sta_get(bss
, mgmt
->da
);
450 wpa_printf(MSG_INFO
, "Too short Reassociation Response frame "
451 "from " MACSTR
, MAC2STR(mgmt
->sa
));
455 capab
= le_to_host16(mgmt
->u
.reassoc_resp
.capab_info
);
456 status
= le_to_host16(mgmt
->u
.reassoc_resp
.status_code
);
457 aid
= le_to_host16(mgmt
->u
.reassoc_resp
.aid
);
459 wpa_printf(MSG_DEBUG
, "REASSOCRESP " MACSTR
" -> " MACSTR
460 " (capab=0x%x status=%u aid=%u)",
461 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), capab
, status
,
464 if (status
== WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
) {
465 struct ieee802_11_elems elems
;
466 const u8
*ies
= mgmt
->u
.reassoc_resp
.variable
;
467 size_t ies_len
= len
- (mgmt
->u
.reassoc_resp
.variable
- data
);
468 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) ==
470 wpa_printf(MSG_INFO
, "Failed to parse IEs in "
471 "ReassocResp from " MACSTR
,
473 } else if (elems
.timeout_int
== NULL
||
474 elems
.timeout_int_len
!= 5 ||
475 elems
.timeout_int
[0] !=
476 WLAN_TIMEOUT_ASSOC_COMEBACK
) {
477 wpa_printf(MSG_INFO
, "No valid Timeout Interval IE "
478 "with Assoc Comeback time in ReassocResp "
479 "(status=30) from " MACSTR
,
483 WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK
]++;
490 if ((aid
& 0xc000) != 0xc000) {
491 wpa_printf(MSG_DEBUG
, "Two MSBs of the AID were not set to 1 "
492 "in Reassociation Response from " MACSTR
,
495 sta
->aid
= aid
& 0xc000;
497 if (sta
->state
< STATE2
) {
498 wpa_printf(MSG_DEBUG
, "STA " MACSTR
" was not in State 2 when "
499 "getting associated", MAC2STR(sta
->addr
));
502 if (sta
->state
< STATE3
) {
503 wpa_printf(MSG_DEBUG
, "STA " MACSTR
504 " moved to State 3 with " MACSTR
,
505 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
511 static void disassoc_all_stas(struct wlantest_bss
*bss
)
513 struct wlantest_sta
*sta
;
514 dl_list_for_each(sta
, &bss
->sta
, struct wlantest_sta
, list
) {
515 if (sta
->state
<= STATE2
)
517 wpa_printf(MSG_DEBUG
, "STA " MACSTR
518 " moved to State 2 with " MACSTR
,
519 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
525 static void rx_mgmt_disassoc(struct wlantest
*wt
, const u8
*data
, size_t len
,
528 const struct ieee80211_mgmt
*mgmt
;
529 struct wlantest_bss
*bss
;
530 struct wlantest_sta
*sta
;
533 mgmt
= (const struct ieee80211_mgmt
*) data
;
534 bss
= bss_get(wt
, mgmt
->bssid
);
537 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
538 sta
= sta_get(bss
, mgmt
->da
);
540 sta
= sta_get(bss
, mgmt
->sa
);
543 wpa_printf(MSG_INFO
, "Too short Disassociation frame from "
544 MACSTR
, MAC2STR(mgmt
->sa
));
548 reason
= le_to_host16(mgmt
->u
.disassoc
.reason_code
);
549 wpa_printf(MSG_DEBUG
, "DISASSOC " MACSTR
" -> " MACSTR
550 " (reason=%u) (valid=%d)",
551 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
553 wpa_hexdump(MSG_MSGDUMP
, "DISASSOC payload", data
+ 24, len
- 24);
556 if (valid
&& mgmt
->da
[0] == 0xff)
557 disassoc_all_stas(bss
);
561 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
562 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DISASSOC_RX
:
563 WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX
]++;
564 if (sta
->pwrmgt
&& !sta
->pspoll
)
566 WLANTEST_STA_COUNTER_DISASSOC_RX_ASLEEP
]++;
569 WLANTEST_STA_COUNTER_DISASSOC_RX_AWAKE
]++;
571 fc
= le_to_host16(mgmt
->frame_control
);
572 if (!(fc
& WLAN_FC_ISWEP
) && reason
== 6)
573 sta
->counters
[WLANTEST_STA_COUNTER_DISASSOC_RX_RC6
]++;
574 else if (!(fc
& WLAN_FC_ISWEP
) && reason
== 7)
575 sta
->counters
[WLANTEST_STA_COUNTER_DISASSOC_RX_RC7
]++;
577 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DISASSOC_TX
:
578 WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX
]++;
581 wpa_printf(MSG_INFO
, "Do not change STA " MACSTR
" State "
582 "since Disassociation frame was not protected "
583 "correctly", MAC2STR(sta
->addr
));
587 if (sta
->state
< STATE2
) {
588 wpa_printf(MSG_DEBUG
, "STA " MACSTR
" was not in State 2 or 3 "
589 "when getting disassociated", MAC2STR(sta
->addr
));
592 if (sta
->state
> STATE2
) {
593 wpa_printf(MSG_DEBUG
, "STA " MACSTR
594 " moved to State 2 with " MACSTR
,
595 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
598 tdls_link_down(bss
, sta
);
602 static void rx_mgmt_action_sa_query_req(struct wlantest
*wt
,
603 struct wlantest_sta
*sta
,
604 const struct ieee80211_mgmt
*mgmt
,
605 size_t len
, int valid
)
610 rx_id
= (const u8
*) mgmt
->u
.action
.u
.sa_query_req
.trans_id
;
611 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
612 id
= sta
->ap_sa_query_tr
;
614 id
= sta
->sta_sa_query_tr
;
615 wpa_printf(MSG_INFO
, "SA Query Request " MACSTR
" -> " MACSTR
616 " (trans_id=%02x%02x)%s",
617 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), rx_id
[0], rx_id
[1],
618 valid
? "" : " (invalid protection)");
619 os_memcpy(id
, mgmt
->u
.action
.u
.sa_query_req
.trans_id
, 2);
620 if (os_memcmp(mgmt
->sa
, sta
->addr
, ETH_ALEN
) == 0)
621 sta
->counters
[valid
?
622 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX
:
623 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX
]++;
625 sta
->counters
[valid
?
626 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX
:
627 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX
]++;
631 static void rx_mgmt_action_sa_query_resp(struct wlantest
*wt
,
632 struct wlantest_sta
*sta
,
633 const struct ieee80211_mgmt
*mgmt
,
634 size_t len
, int valid
)
640 rx_id
= (const u8
*) mgmt
->u
.action
.u
.sa_query_resp
.trans_id
;
641 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
642 id
= sta
->sta_sa_query_tr
;
644 id
= sta
->ap_sa_query_tr
;
645 match
= os_memcmp(rx_id
, id
, 2) == 0;
646 wpa_printf(MSG_INFO
, "SA Query Response " MACSTR
" -> " MACSTR
647 " (trans_id=%02x%02x; %s)%s",
648 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), rx_id
[0], rx_id
[1],
649 match
? "match" : "mismatch",
650 valid
? "" : " (invalid protection)");
651 if (os_memcmp(mgmt
->sa
, sta
->addr
, ETH_ALEN
) == 0)
652 sta
->counters
[(valid
&& match
) ?
653 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX
:
654 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX
]++;
656 sta
->counters
[(valid
&& match
) ?
657 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX
:
658 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX
]++;
662 static void rx_mgmt_action_sa_query(struct wlantest
*wt
,
663 struct wlantest_sta
*sta
,
664 const struct ieee80211_mgmt
*mgmt
,
665 size_t len
, int valid
)
667 if (len
< 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
) {
668 wpa_printf(MSG_INFO
, "Too short SA Query frame from " MACSTR
,
673 if (len
> 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
) {
674 size_t elen
= len
- (24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
);
675 wpa_printf(MSG_INFO
, "Unexpected %u octets of extra data at "
676 "the end of SA Query frame from " MACSTR
,
677 (unsigned) elen
, MAC2STR(mgmt
->sa
));
678 wpa_hexdump(MSG_INFO
, "SA Query extra data",
679 ((const u8
*) mgmt
) + len
- elen
, elen
);
682 switch (mgmt
->u
.action
.u
.sa_query_req
.action
) {
683 case WLAN_SA_QUERY_REQUEST
:
684 rx_mgmt_action_sa_query_req(wt
, sta
, mgmt
, len
, valid
);
686 case WLAN_SA_QUERY_RESPONSE
:
687 rx_mgmt_action_sa_query_resp(wt
, sta
, mgmt
, len
, valid
);
690 wpa_printf(MSG_INFO
, "Unexpected SA Query action value %u "
692 mgmt
->u
.action
.u
.sa_query_req
.action
,
698 static void rx_mgmt_action(struct wlantest
*wt
, const u8
*data
, size_t len
,
701 const struct ieee80211_mgmt
*mgmt
;
702 struct wlantest_bss
*bss
;
703 struct wlantest_sta
*sta
;
705 mgmt
= (const struct ieee80211_mgmt
*) data
;
706 if (mgmt
->da
[0] & 0x01) {
707 wpa_printf(MSG_DEBUG
, "Group addressed Action frame: DA="
708 MACSTR
" SA=" MACSTR
" BSSID=" MACSTR
710 MAC2STR(mgmt
->da
), MAC2STR(mgmt
->sa
),
711 MAC2STR(mgmt
->bssid
), mgmt
->u
.action
.category
);
712 return; /* Ignore group addressed Action frames for now */
714 bss
= bss_get(wt
, mgmt
->bssid
);
717 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
718 sta
= sta_get(bss
, mgmt
->da
);
720 sta
= sta_get(bss
, mgmt
->sa
);
725 wpa_printf(MSG_INFO
, "Too short Action frame from "
726 MACSTR
, MAC2STR(mgmt
->sa
));
730 wpa_printf(MSG_DEBUG
, "ACTION " MACSTR
" -> " MACSTR
731 " (category=%u) (valid=%d)",
732 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
733 mgmt
->u
.action
.category
, valid
);
734 wpa_hexdump(MSG_MSGDUMP
, "ACTION payload", data
+ 24, len
- 24);
736 if (mgmt
->u
.action
.category
!= WLAN_ACTION_PUBLIC
&&
737 sta
->state
< STATE3
) {
738 wpa_printf(MSG_INFO
, "Action frame sent when STA is not in "
739 "State 3 (SA=" MACSTR
" DATA=" MACSTR
")",
740 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
743 switch (mgmt
->u
.action
.category
) {
744 case WLAN_ACTION_SA_QUERY
:
745 rx_mgmt_action_sa_query(wt
, sta
, mgmt
, len
, valid
);
751 static int check_mmie_mic(const u8
*igtk
, const u8
*data
, size_t len
)
756 const struct ieee80211_hdr
*hdr
;
758 buf
= os_malloc(len
+ 20 - 24);
762 /* BIP AAD: FC(masked) A1 A2 A3 */
763 hdr
= (const struct ieee80211_hdr
*) data
;
764 fc
= le_to_host16(hdr
->frame_control
);
765 fc
&= ~(WLAN_FC_RETRY
| WLAN_FC_PWRMGT
| WLAN_FC_MOREDATA
);
766 WPA_PUT_LE16(buf
, fc
);
767 os_memcpy(buf
+ 2, hdr
->addr1
, 3 * ETH_ALEN
);
769 /* Frame body with MMIE MIC masked to zero */
770 os_memcpy(buf
+ 20, data
+ 24, len
- 24 - 8);
771 os_memset(buf
+ 20 + len
- 24 - 8, 0, 8);
773 wpa_hexdump(MSG_MSGDUMP
, "BIP: AAD|Body(masked)", buf
, len
+ 20 - 24);
774 /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
775 if (omac1_aes_128(igtk
, buf
, len
+ 20 - 24, mic
) < 0) {
782 if (os_memcmp(data
+ len
- 8, mic
, 8) != 0)
789 static int check_bip(struct wlantest
*wt
, const u8
*data
, size_t len
)
791 const struct ieee80211_mgmt
*mgmt
;
795 struct wlantest_bss
*bss
;
797 mgmt
= (const struct ieee80211_mgmt
*) data
;
798 fc
= le_to_host16(mgmt
->frame_control
);
799 stype
= WLAN_FC_GET_STYPE(fc
);
801 if (stype
== WLAN_FC_STYPE_ACTION
) {
804 if (mgmt
->u
.action
.category
== WLAN_ACTION_PUBLIC
)
805 return 0; /* Not a robust management frame */
808 bss
= bss_get(wt
, mgmt
->bssid
);
810 return 0; /* No key known yet */
812 if (len
< 24 + 18 || data
[len
- 18] != WLAN_EID_MMIE
||
813 data
[len
- 17] != 16) {
815 if (bss
->rsn_capab
& WPA_CAPABILITY_MFPC
) {
816 wpa_printf(MSG_INFO
, "Robust group-addressed "
817 "management frame sent without BIP by "
818 MACSTR
, MAC2STR(mgmt
->sa
));
819 bss
->counters
[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE
]++;
825 mmie
= data
+ len
- 16;
826 keyid
= WPA_GET_LE16(mmie
);
827 if (keyid
& 0xf000) {
828 wpa_printf(MSG_INFO
, "MMIE KeyID reserved bits not zero "
829 "(%04x) from " MACSTR
, keyid
, MAC2STR(mgmt
->sa
));
832 if (keyid
< 4 || keyid
> 5) {
833 wpa_printf(MSG_INFO
, "Unexpected MMIE KeyID %u from " MACSTR
,
834 keyid
, MAC2STR(mgmt
->sa
));
835 bss
->counters
[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE
]++;
838 wpa_printf(MSG_DEBUG
, "MMIE KeyID %u", keyid
);
839 wpa_hexdump(MSG_MSGDUMP
, "MMIE IPN", mmie
+ 2, 6);
840 wpa_hexdump(MSG_MSGDUMP
, "MMIE MIC", mmie
+ 8, 8);
842 if (!bss
->igtk_set
[keyid
]) {
843 wpa_printf(MSG_DEBUG
, "No IGTK known to validate BIP frame");
847 if (os_memcmp(mmie
+ 2, bss
->ipn
[keyid
], 6) <= 0) {
848 wpa_printf(MSG_INFO
, "BIP replay detected: SA=" MACSTR
,
850 wpa_hexdump(MSG_INFO
, "RX IPN", mmie
+ 2, 6);
851 wpa_hexdump(MSG_INFO
, "Last RX IPN", bss
->ipn
[keyid
], 6);
854 if (check_mmie_mic(bss
->igtk
[keyid
], data
, len
) < 0) {
855 wpa_printf(MSG_INFO
, "Invalid MMIE MIC in a frame from "
856 MACSTR
, MAC2STR(mgmt
->sa
));
857 bss
->counters
[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE
]++;
861 wpa_printf(MSG_DEBUG
, "Valid MMIE MIC");
862 os_memcpy(bss
->ipn
[keyid
], mmie
+ 2, 6);
863 bss
->counters
[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE
]++;
865 if (stype
== WLAN_FC_STYPE_DEAUTH
)
866 bss
->counters
[WLANTEST_BSS_COUNTER_BIP_DEAUTH
]++;
867 else if (stype
== WLAN_FC_STYPE_DISASSOC
)
868 bss
->counters
[WLANTEST_BSS_COUNTER_BIP_DISASSOC
]++;
874 static u8
* mgmt_ccmp_decrypt(struct wlantest
*wt
, const u8
*data
, size_t len
,
877 struct wlantest_bss
*bss
;
878 struct wlantest_sta
*sta
;
879 const struct ieee80211_hdr
*hdr
;
881 u8
*decrypted
, *frame
= NULL
;
884 hdr
= (const struct ieee80211_hdr
*) data
;
885 bss
= bss_get(wt
, hdr
->addr3
);
888 if (os_memcmp(hdr
->addr1
, hdr
->addr3
, ETH_ALEN
) == 0)
889 sta
= sta_get(bss
, hdr
->addr2
);
891 sta
= sta_get(bss
, hdr
->addr1
);
892 if (sta
== NULL
|| !sta
->ptk_set
) {
893 wpa_printf(MSG_MSGDUMP
, "No PTK known to decrypt the frame");
900 if (!(data
[24 + 3] & 0x20)) {
901 wpa_printf(MSG_INFO
, "Expected CCMP frame from " MACSTR
902 " did not have ExtIV bit set to 1",
903 MAC2STR(hdr
->addr2
));
907 if (data
[24 + 2] != 0 || (data
[24 + 3] & 0x1f) != 0) {
908 wpa_printf(MSG_INFO
, "CCMP mgmt frame from " MACSTR
" used "
909 "non-zero reserved bit", MAC2STR(hdr
->addr2
));
912 keyid
= data
[24 + 3] >> 6;
914 wpa_printf(MSG_INFO
, "Unexpected non-zero KeyID %d in "
915 "individually addressed Management frame from "
916 MACSTR
, keyid
, MAC2STR(hdr
->addr2
));
919 if (os_memcmp(hdr
->addr1
, hdr
->addr3
, ETH_ALEN
) == 0)
920 rsc
= sta
->rsc_tods
[16];
922 rsc
= sta
->rsc_fromds
[16];
924 ccmp_get_pn(pn
, data
+ 24);
925 if (os_memcmp(pn
, rsc
, 6) <= 0) {
926 u16 seq_ctrl
= le_to_host16(hdr
->seq_ctrl
);
927 wpa_printf(MSG_INFO
, "CCMP/TKIP replay detected: A1=" MACSTR
928 " A2=" MACSTR
" A3=" MACSTR
" seq=%u frag=%u",
929 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
931 WLAN_GET_SEQ_SEQ(seq_ctrl
),
932 WLAN_GET_SEQ_FRAG(seq_ctrl
));
933 wpa_hexdump(MSG_INFO
, "RX PN", pn
, 6);
934 wpa_hexdump(MSG_INFO
, "RSC", rsc
, 6);
937 decrypted
= ccmp_decrypt(sta
->ptk
.tk1
, hdr
, data
+ 24, len
- 24, dlen
);
939 os_memcpy(rsc
, pn
, 6);
940 frame
= os_malloc(24 + *dlen
);
942 os_memcpy(frame
, data
, 24);
943 os_memcpy(frame
+ 24, decrypted
, *dlen
);
954 static int check_mgmt_ccmp(struct wlantest
*wt
, const u8
*data
, size_t len
)
956 const struct ieee80211_mgmt
*mgmt
;
958 struct wlantest_bss
*bss
;
959 struct wlantest_sta
*sta
;
961 mgmt
= (const struct ieee80211_mgmt
*) data
;
962 fc
= le_to_host16(mgmt
->frame_control
);
964 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACTION
) {
966 mgmt
->u
.action
.category
== WLAN_ACTION_PUBLIC
)
967 return 0; /* Not a robust management frame */
970 bss
= bss_get(wt
, mgmt
->bssid
);
973 if (os_memcmp(mgmt
->da
, mgmt
->bssid
, ETH_ALEN
) == 0)
974 sta
= sta_get(bss
, mgmt
->sa
);
976 sta
= sta_get(bss
, mgmt
->da
);
980 if ((sta
->rsn_capab
& WPA_CAPABILITY_MFPC
) &&
981 (sta
->state
== STATE3
||
982 WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACTION
)) {
983 wpa_printf(MSG_INFO
, "Robust individually-addressed "
984 "management frame sent without CCMP by "
985 MACSTR
, MAC2STR(mgmt
->sa
));
993 void rx_mgmt(struct wlantest
*wt
, const u8
*data
, size_t len
)
995 const struct ieee80211_hdr
*hdr
;
998 u8
*decrypted
= NULL
;
1004 hdr
= (const struct ieee80211_hdr
*) data
;
1005 fc
= le_to_host16(hdr
->frame_control
);
1007 stype
= WLAN_FC_GET_STYPE(fc
);
1009 if ((hdr
->addr1
[0] & 0x01) &&
1010 (stype
== WLAN_FC_STYPE_DEAUTH
||
1011 stype
== WLAN_FC_STYPE_DISASSOC
||
1012 stype
== WLAN_FC_STYPE_ACTION
)) {
1013 if (check_bip(wt
, data
, len
) < 0)
1017 wpa_printf((stype
== WLAN_FC_STYPE_BEACON
||
1018 stype
== WLAN_FC_STYPE_PROBE_RESP
||
1019 stype
== WLAN_FC_STYPE_PROBE_REQ
) ?
1020 MSG_EXCESSIVE
: MSG_MSGDUMP
,
1021 "MGMT %s%s%s DA=" MACSTR
" SA=" MACSTR
" BSSID=" MACSTR
,
1023 fc
& WLAN_FC_PWRMGT
? " PwrMgt" : "",
1024 fc
& WLAN_FC_ISWEP
? " Prot" : "",
1025 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
1026 MAC2STR(hdr
->addr3
));
1028 if ((fc
& WLAN_FC_ISWEP
) &&
1029 !(hdr
->addr1
[0] & 0x01) &&
1030 (stype
== WLAN_FC_STYPE_DEAUTH
||
1031 stype
== WLAN_FC_STYPE_DISASSOC
||
1032 stype
== WLAN_FC_STYPE_ACTION
)) {
1033 decrypted
= mgmt_ccmp_decrypt(wt
, data
, len
, &dlen
);
1035 write_pcap_decrypted(wt
, decrypted
, dlen
, NULL
, 0);
1042 if (!(fc
& WLAN_FC_ISWEP
) &&
1043 !(hdr
->addr1
[0] & 0x01) &&
1044 (stype
== WLAN_FC_STYPE_DEAUTH
||
1045 stype
== WLAN_FC_STYPE_DISASSOC
||
1046 stype
== WLAN_FC_STYPE_ACTION
)) {
1047 if (check_mgmt_ccmp(wt
, data
, len
) < 0)
1052 case WLAN_FC_STYPE_BEACON
:
1053 rx_mgmt_beacon(wt
, data
, len
);
1055 case WLAN_FC_STYPE_PROBE_RESP
:
1056 rx_mgmt_probe_resp(wt
, data
, len
);
1058 case WLAN_FC_STYPE_AUTH
:
1059 rx_mgmt_auth(wt
, data
, len
);
1061 case WLAN_FC_STYPE_DEAUTH
:
1062 rx_mgmt_deauth(wt
, data
, len
, valid
);
1064 case WLAN_FC_STYPE_ASSOC_REQ
:
1065 rx_mgmt_assoc_req(wt
, data
, len
);
1067 case WLAN_FC_STYPE_ASSOC_RESP
:
1068 rx_mgmt_assoc_resp(wt
, data
, len
);
1070 case WLAN_FC_STYPE_REASSOC_REQ
:
1071 rx_mgmt_reassoc_req(wt
, data
, len
);
1073 case WLAN_FC_STYPE_REASSOC_RESP
:
1074 rx_mgmt_reassoc_resp(wt
, data
, len
);
1076 case WLAN_FC_STYPE_DISASSOC
:
1077 rx_mgmt_disassoc(wt
, data
, len
, valid
);
1079 case WLAN_FC_STYPE_ACTION
:
1080 rx_mgmt_action(wt
, data
, len
, valid
);
1086 wt
->last_mgmt_valid
= valid
;
1090 static void rx_mgmt_deauth_ack(struct wlantest
*wt
,
1091 const struct ieee80211_hdr
*hdr
)
1093 const struct ieee80211_mgmt
*mgmt
;
1094 struct wlantest_bss
*bss
;
1095 struct wlantest_sta
*sta
;
1097 mgmt
= (const struct ieee80211_mgmt
*) hdr
;
1098 bss
= bss_get(wt
, mgmt
->bssid
);
1101 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
1102 sta
= sta_get(bss
, mgmt
->da
);
1104 sta
= sta_get(bss
, mgmt
->sa
);
1108 wpa_printf(MSG_DEBUG
, "DEAUTH from " MACSTR
" acknowledged by " MACSTR
,
1109 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
1110 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
1112 c
= wt
->last_mgmt_valid
?
1113 WLANTEST_STA_COUNTER_VALID_DEAUTH_RX_ACK
:
1114 WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX_ACK
;
1120 static void rx_mgmt_disassoc_ack(struct wlantest
*wt
,
1121 const struct ieee80211_hdr
*hdr
)
1123 const struct ieee80211_mgmt
*mgmt
;
1124 struct wlantest_bss
*bss
;
1125 struct wlantest_sta
*sta
;
1127 mgmt
= (const struct ieee80211_mgmt
*) hdr
;
1128 bss
= bss_get(wt
, mgmt
->bssid
);
1131 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
1132 sta
= sta_get(bss
, mgmt
->da
);
1134 sta
= sta_get(bss
, mgmt
->sa
);
1138 wpa_printf(MSG_DEBUG
, "DISASSOC from " MACSTR
" acknowledged by "
1139 MACSTR
, MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
1140 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0) {
1142 c
= wt
->last_mgmt_valid
?
1143 WLANTEST_STA_COUNTER_VALID_DISASSOC_RX_ACK
:
1144 WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX_ACK
;
1150 void rx_mgmt_ack(struct wlantest
*wt
, const struct ieee80211_hdr
*hdr
)
1153 fc
= le_to_host16(hdr
->frame_control
);
1154 stype
= WLAN_FC_GET_STYPE(fc
);
1156 wpa_printf(MSG_MSGDUMP
, "MGMT ACK: stype=%u a1=" MACSTR
" a2=" MACSTR
1158 stype
, MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
1159 MAC2STR(hdr
->addr3
));
1162 case WLAN_FC_STYPE_DEAUTH
:
1163 rx_mgmt_deauth_ack(wt
, hdr
);
1165 case WLAN_FC_STYPE_DISASSOC
:
1166 rx_mgmt_disassoc_ack(wt
, hdr
);