2 * Received Management frame processing
3 * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
15 #include "utils/includes.h"
17 #include "utils/common.h"
18 #include "common/ieee802_11_defs.h"
19 #include "common/ieee802_11_common.h"
20 #include "crypto/aes_wrap.h"
24 static const char * mgmt_stype(u16 stype
)
27 case WLAN_FC_STYPE_ASSOC_REQ
:
29 case WLAN_FC_STYPE_ASSOC_RESP
:
31 case WLAN_FC_STYPE_REASSOC_REQ
:
33 case WLAN_FC_STYPE_REASSOC_RESP
:
34 return "REASSOC-RESP";
35 case WLAN_FC_STYPE_PROBE_REQ
:
37 case WLAN_FC_STYPE_PROBE_RESP
:
39 case WLAN_FC_STYPE_BEACON
:
41 case WLAN_FC_STYPE_ATIM
:
43 case WLAN_FC_STYPE_DISASSOC
:
45 case WLAN_FC_STYPE_AUTH
:
47 case WLAN_FC_STYPE_DEAUTH
:
49 case WLAN_FC_STYPE_ACTION
:
56 static void rx_mgmt_beacon(struct wlantest
*wt
, const u8
*data
, size_t len
)
58 const struct ieee80211_mgmt
*mgmt
;
59 struct wlantest_bss
*bss
;
60 struct ieee802_11_elems elems
;
62 mgmt
= (const struct ieee80211_mgmt
*) data
;
63 bss
= bss_get(wt
, mgmt
->bssid
);
66 if (bss
->proberesp_seen
)
67 return; /* do not override with Beacon data */
68 bss
->capab_info
= le_to_host16(mgmt
->u
.beacon
.capab_info
);
69 if (ieee802_11_parse_elems(mgmt
->u
.beacon
.variable
,
70 len
- (mgmt
->u
.beacon
.variable
- data
),
71 &elems
, 0) == ParseFailed
) {
72 if (bss
->parse_error_reported
)
74 wpa_printf(MSG_INFO
, "Invalid IEs in a Beacon frame from "
75 MACSTR
, MAC2STR(mgmt
->sa
));
76 bss
->parse_error_reported
= 1;
80 bss_update(wt
, bss
, &elems
);
84 static void rx_mgmt_probe_resp(struct wlantest
*wt
, const u8
*data
, size_t len
)
86 const struct ieee80211_mgmt
*mgmt
;
87 struct wlantest_bss
*bss
;
88 struct ieee802_11_elems elems
;
90 mgmt
= (const struct ieee80211_mgmt
*) data
;
91 bss
= bss_get(wt
, mgmt
->bssid
);
95 bss
->capab_info
= le_to_host16(mgmt
->u
.probe_resp
.capab_info
);
96 if (ieee802_11_parse_elems(mgmt
->u
.probe_resp
.variable
,
97 len
- (mgmt
->u
.probe_resp
.variable
- data
),
98 &elems
, 0) == ParseFailed
) {
99 if (bss
->parse_error_reported
)
101 wpa_printf(MSG_INFO
, "Invalid IEs in a Probe Response frame "
102 "from " MACSTR
, MAC2STR(mgmt
->sa
));
103 bss
->parse_error_reported
= 1;
107 bss_update(wt
, bss
, &elems
);
111 static void rx_mgmt_auth(struct wlantest
*wt
, const u8
*data
, size_t len
)
113 const struct ieee80211_mgmt
*mgmt
;
114 struct wlantest_bss
*bss
;
115 struct wlantest_sta
*sta
;
116 u16 alg
, trans
, status
;
118 mgmt
= (const struct ieee80211_mgmt
*) data
;
119 bss
= bss_get(wt
, mgmt
->bssid
);
122 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
123 sta
= sta_get(bss
, mgmt
->da
);
125 sta
= sta_get(bss
, mgmt
->sa
);
130 wpa_printf(MSG_INFO
, "Too short Authentication frame from "
131 MACSTR
, MAC2STR(mgmt
->sa
));
135 alg
= le_to_host16(mgmt
->u
.auth
.auth_alg
);
136 trans
= le_to_host16(mgmt
->u
.auth
.auth_transaction
);
137 status
= le_to_host16(mgmt
->u
.auth
.status_code
);
139 wpa_printf(MSG_DEBUG
, "AUTH " MACSTR
" -> " MACSTR
140 " (alg=%u trans=%u status=%u)",
141 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), alg
, trans
, status
);
143 if (alg
== 0 && trans
== 2 && status
== 0) {
144 if (sta
->state
== STATE1
) {
145 wpa_printf(MSG_DEBUG
, "STA " MACSTR
146 " moved to State 2 with " MACSTR
,
147 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
152 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
153 sta
->counters
[WLANTEST_STA_COUNTER_AUTH_RX
]++;
155 sta
->counters
[WLANTEST_STA_COUNTER_AUTH_TX
]++;
159 static void deauth_all_stas(struct wlantest_bss
*bss
)
161 struct wlantest_sta
*sta
;
162 dl_list_for_each(sta
, &bss
->sta
, struct wlantest_sta
, list
) {
163 if (sta
->state
== STATE1
)
165 wpa_printf(MSG_DEBUG
, "STA " MACSTR
166 " moved to State 1 with " MACSTR
,
167 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
173 static void rx_mgmt_deauth(struct wlantest
*wt
, const u8
*data
, size_t len
,
176 const struct ieee80211_mgmt
*mgmt
;
177 struct wlantest_bss
*bss
;
178 struct wlantest_sta
*sta
;
180 mgmt
= (const struct ieee80211_mgmt
*) data
;
181 bss
= bss_get(wt
, mgmt
->bssid
);
184 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
185 sta
= sta_get(bss
, mgmt
->da
);
187 sta
= sta_get(bss
, mgmt
->sa
);
190 wpa_printf(MSG_INFO
, "Too short Deauthentication frame from "
191 MACSTR
, MAC2STR(mgmt
->sa
));
195 wpa_printf(MSG_DEBUG
, "DEAUTH " MACSTR
" -> " MACSTR
196 " (reason=%u) (valid=%d)",
197 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
198 le_to_host16(mgmt
->u
.deauth
.reason_code
), valid
);
199 wpa_hexdump(MSG_MSGDUMP
, "DEAUTH payload", data
+ 24, len
- 24);
202 if (valid
&& mgmt
->da
[0] == 0xff)
203 deauth_all_stas(bss
);
207 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
208 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DEAUTH_RX
:
209 WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX
]++;
211 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DEAUTH_TX
:
212 WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX
]++;
215 wpa_printf(MSG_INFO
, "Do not change STA " MACSTR
" State "
216 "since Disassociation frame was not protected "
217 "correctly", MAC2STR(sta
->addr
));
221 if (sta
->state
!= STATE1
) {
222 wpa_printf(MSG_DEBUG
, "STA " MACSTR
223 " moved to State 1 with " MACSTR
,
224 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
230 static void rx_mgmt_assoc_req(struct wlantest
*wt
, const u8
*data
, size_t len
)
232 const struct ieee80211_mgmt
*mgmt
;
233 struct wlantest_bss
*bss
;
234 struct wlantest_sta
*sta
;
235 struct ieee802_11_elems elems
;
237 mgmt
= (const struct ieee80211_mgmt
*) data
;
238 bss
= bss_get(wt
, mgmt
->bssid
);
241 sta
= sta_get(bss
, mgmt
->sa
);
246 wpa_printf(MSG_INFO
, "Too short Association Request frame "
247 "from " MACSTR
, MAC2STR(mgmt
->sa
));
251 wpa_printf(MSG_DEBUG
, "ASSOCREQ " MACSTR
" -> " MACSTR
252 " (capab=0x%x listen_int=%u)",
253 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
254 le_to_host16(mgmt
->u
.assoc_req
.capab_info
),
255 le_to_host16(mgmt
->u
.assoc_req
.listen_interval
));
257 sta
->counters
[WLANTEST_STA_COUNTER_ASSOCREQ_TX
]++;
259 if (ieee802_11_parse_elems(mgmt
->u
.assoc_req
.variable
,
260 len
- (mgmt
->u
.assoc_req
.variable
- data
),
261 &elems
, 0) == ParseFailed
) {
262 wpa_printf(MSG_INFO
, "Invalid IEs in Association Request "
263 "frame from " MACSTR
, MAC2STR(mgmt
->sa
));
267 sta
->assocreq_capab_info
= le_to_host16(mgmt
->u
.assoc_req
.capab_info
);
268 sta
->assocreq_listen_int
=
269 le_to_host16(mgmt
->u
.assoc_req
.listen_interval
);
270 os_free(sta
->assocreq_ies
);
271 sta
->assocreq_ies_len
= len
- (mgmt
->u
.assoc_req
.variable
- data
);
272 sta
->assocreq_ies
= os_malloc(sta
->assocreq_ies_len
);
273 if (sta
->assocreq_ies
)
274 os_memcpy(sta
->assocreq_ies
, mgmt
->u
.assoc_req
.variable
,
275 sta
->assocreq_ies_len
);
277 sta_update_assoc(sta
, &elems
);
281 static void rx_mgmt_assoc_resp(struct wlantest
*wt
, const u8
*data
, size_t len
)
283 const struct ieee80211_mgmt
*mgmt
;
284 struct wlantest_bss
*bss
;
285 struct wlantest_sta
*sta
;
286 u16 capab
, status
, aid
;
288 mgmt
= (const struct ieee80211_mgmt
*) data
;
289 bss
= bss_get(wt
, mgmt
->bssid
);
292 sta
= sta_get(bss
, mgmt
->da
);
297 wpa_printf(MSG_INFO
, "Too short Association Response frame "
298 "from " MACSTR
, MAC2STR(mgmt
->sa
));
302 capab
= le_to_host16(mgmt
->u
.assoc_resp
.capab_info
);
303 status
= le_to_host16(mgmt
->u
.assoc_resp
.status_code
);
304 aid
= le_to_host16(mgmt
->u
.assoc_resp
.aid
);
306 wpa_printf(MSG_DEBUG
, "ASSOCRESP " MACSTR
" -> " MACSTR
307 " (capab=0x%x status=%u aid=%u)",
308 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), capab
, status
,
311 if (status
== WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
) {
312 struct ieee802_11_elems elems
;
313 const u8
*ies
= mgmt
->u
.assoc_resp
.variable
;
314 size_t ies_len
= len
- (mgmt
->u
.assoc_resp
.variable
- data
);
315 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) ==
317 wpa_printf(MSG_INFO
, "Failed to parse IEs in "
318 "AssocResp from " MACSTR
,
320 } else if (elems
.timeout_int
== 0 ||
321 elems
.timeout_int_len
!= 5) {
322 wpa_printf(MSG_INFO
, "No valid Timeout Interval IE in "
323 "AssocResp (status=30) from " MACSTR
,
327 WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK
]++;
334 if ((aid
& 0xc000) != 0xc000) {
335 wpa_printf(MSG_DEBUG
, "Two MSBs of the AID were not set to 1 "
336 "in Association Response from " MACSTR
,
339 sta
->aid
= aid
& 0xc000;
341 if (sta
->state
< STATE2
) {
342 wpa_printf(MSG_DEBUG
, "STA " MACSTR
" was not in State 2 when "
343 "getting associated", MAC2STR(sta
->addr
));
346 if (sta
->state
< STATE3
) {
347 wpa_printf(MSG_DEBUG
, "STA " MACSTR
348 " moved to State 3 with " MACSTR
,
349 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
355 static void rx_mgmt_reassoc_req(struct wlantest
*wt
, const u8
*data
,
358 const struct ieee80211_mgmt
*mgmt
;
359 struct wlantest_bss
*bss
;
360 struct wlantest_sta
*sta
;
361 struct ieee802_11_elems elems
;
363 mgmt
= (const struct ieee80211_mgmt
*) data
;
364 bss
= bss_get(wt
, mgmt
->bssid
);
367 sta
= sta_get(bss
, mgmt
->sa
);
371 if (len
< 24 + 4 + ETH_ALEN
) {
372 wpa_printf(MSG_INFO
, "Too short Reassociation Request frame "
373 "from " MACSTR
, MAC2STR(mgmt
->sa
));
377 wpa_printf(MSG_DEBUG
, "REASSOCREQ " MACSTR
" -> " MACSTR
378 " (capab=0x%x listen_int=%u current_ap=" MACSTR
")",
379 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
380 le_to_host16(mgmt
->u
.reassoc_req
.capab_info
),
381 le_to_host16(mgmt
->u
.reassoc_req
.listen_interval
),
382 MAC2STR(mgmt
->u
.reassoc_req
.current_ap
));
384 sta
->counters
[WLANTEST_STA_COUNTER_REASSOCREQ_TX
]++;
386 if (ieee802_11_parse_elems(mgmt
->u
.reassoc_req
.variable
,
387 len
- (mgmt
->u
.reassoc_req
.variable
- data
),
388 &elems
, 0) == ParseFailed
) {
389 wpa_printf(MSG_INFO
, "Invalid IEs in Reassociation Request "
390 "frame from " MACSTR
, MAC2STR(mgmt
->sa
));
394 sta
->assocreq_capab_info
=
395 le_to_host16(mgmt
->u
.reassoc_req
.capab_info
);
396 sta
->assocreq_listen_int
=
397 le_to_host16(mgmt
->u
.reassoc_req
.listen_interval
);
398 os_free(sta
->assocreq_ies
);
399 sta
->assocreq_ies_len
= len
- (mgmt
->u
.reassoc_req
.variable
- data
);
400 sta
->assocreq_ies
= os_malloc(sta
->assocreq_ies_len
);
401 if (sta
->assocreq_ies
)
402 os_memcpy(sta
->assocreq_ies
, mgmt
->u
.reassoc_req
.variable
,
403 sta
->assocreq_ies_len
);
405 sta_update_assoc(sta
, &elems
);
409 static void rx_mgmt_reassoc_resp(struct wlantest
*wt
, const u8
*data
,
412 const struct ieee80211_mgmt
*mgmt
;
413 struct wlantest_bss
*bss
;
414 struct wlantest_sta
*sta
;
415 u16 capab
, status
, aid
;
417 mgmt
= (const struct ieee80211_mgmt
*) data
;
418 bss
= bss_get(wt
, mgmt
->bssid
);
421 sta
= sta_get(bss
, mgmt
->da
);
426 wpa_printf(MSG_INFO
, "Too short Reassociation Response frame "
427 "from " MACSTR
, MAC2STR(mgmt
->sa
));
431 capab
= le_to_host16(mgmt
->u
.reassoc_resp
.capab_info
);
432 status
= le_to_host16(mgmt
->u
.reassoc_resp
.status_code
);
433 aid
= le_to_host16(mgmt
->u
.reassoc_resp
.aid
);
435 wpa_printf(MSG_DEBUG
, "REASSOCRESP " MACSTR
" -> " MACSTR
436 " (capab=0x%x status=%u aid=%u)",
437 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), capab
, status
,
440 if (status
== WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY
) {
441 struct ieee802_11_elems elems
;
442 const u8
*ies
= mgmt
->u
.reassoc_resp
.variable
;
443 size_t ies_len
= len
- (mgmt
->u
.reassoc_resp
.variable
- data
);
444 if (ieee802_11_parse_elems(ies
, ies_len
, &elems
, 0) ==
446 wpa_printf(MSG_INFO
, "Failed to parse IEs in "
447 "ReassocResp from " MACSTR
,
449 } else if (elems
.timeout_int
== 0 ||
450 elems
.timeout_int_len
!= 5) {
451 wpa_printf(MSG_INFO
, "No valid Timeout Interval IE in "
452 "ReassocResp (status=30) from " MACSTR
,
456 WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK
]++;
463 if ((aid
& 0xc000) != 0xc000) {
464 wpa_printf(MSG_DEBUG
, "Two MSBs of the AID were not set to 1 "
465 "in Reassociation Response from " MACSTR
,
468 sta
->aid
= aid
& 0xc000;
470 if (sta
->state
< STATE2
) {
471 wpa_printf(MSG_DEBUG
, "STA " MACSTR
" was not in State 2 when "
472 "getting associated", MAC2STR(sta
->addr
));
475 if (sta
->state
< STATE3
) {
476 wpa_printf(MSG_DEBUG
, "STA " MACSTR
477 " moved to State 3 with " MACSTR
,
478 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
484 static void disassoc_all_stas(struct wlantest_bss
*bss
)
486 struct wlantest_sta
*sta
;
487 dl_list_for_each(sta
, &bss
->sta
, struct wlantest_sta
, list
) {
488 if (sta
->state
<= STATE2
)
490 wpa_printf(MSG_DEBUG
, "STA " MACSTR
491 " moved to State 2 with " MACSTR
,
492 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
498 static void rx_mgmt_disassoc(struct wlantest
*wt
, const u8
*data
, size_t len
,
501 const struct ieee80211_mgmt
*mgmt
;
502 struct wlantest_bss
*bss
;
503 struct wlantest_sta
*sta
;
505 mgmt
= (const struct ieee80211_mgmt
*) data
;
506 bss
= bss_get(wt
, mgmt
->bssid
);
509 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
510 sta
= sta_get(bss
, mgmt
->da
);
512 sta
= sta_get(bss
, mgmt
->sa
);
515 wpa_printf(MSG_INFO
, "Too short Disassociation frame from "
516 MACSTR
, MAC2STR(mgmt
->sa
));
520 wpa_printf(MSG_DEBUG
, "DISASSOC " MACSTR
" -> " MACSTR
521 " (reason=%u) (valid=%d)",
522 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
523 le_to_host16(mgmt
->u
.disassoc
.reason_code
), valid
);
524 wpa_hexdump(MSG_MSGDUMP
, "DISASSOC payload", data
+ 24, len
- 24);
527 if (valid
&& mgmt
->da
[0] == 0xff)
528 disassoc_all_stas(bss
);
532 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
533 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DISASSOC_RX
:
534 WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX
]++;
536 sta
->counters
[valid
? WLANTEST_STA_COUNTER_VALID_DISASSOC_TX
:
537 WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX
]++;
540 wpa_printf(MSG_INFO
, "Do not change STA " MACSTR
" State "
541 "since Disassociation frame was not protected "
542 "correctly", MAC2STR(sta
->addr
));
546 if (sta
->state
< STATE2
) {
547 wpa_printf(MSG_DEBUG
, "STA " MACSTR
" was not in State 2 or 3 "
548 "when getting disassociated", MAC2STR(sta
->addr
));
551 if (sta
->state
> STATE2
) {
552 wpa_printf(MSG_DEBUG
, "STA " MACSTR
553 " moved to State 2 with " MACSTR
,
554 MAC2STR(sta
->addr
), MAC2STR(bss
->bssid
));
560 static void rx_mgmt_action_sa_query_req(struct wlantest
*wt
,
561 struct wlantest_sta
*sta
,
562 const struct ieee80211_mgmt
*mgmt
,
563 size_t len
, int valid
)
568 rx_id
= (const u8
*) mgmt
->u
.action
.u
.sa_query_req
.trans_id
;
569 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
570 id
= sta
->ap_sa_query_tr
;
572 id
= sta
->sta_sa_query_tr
;
573 wpa_printf(MSG_INFO
, "SA Query Request " MACSTR
" -> " MACSTR
574 " (trans_id=%02x%02x)%s",
575 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), rx_id
[0], rx_id
[1],
576 valid
? "" : " (invalid protection)");
577 os_memcpy(id
, mgmt
->u
.action
.u
.sa_query_req
.trans_id
, 2);
578 if (os_memcmp(mgmt
->sa
, sta
->addr
, ETH_ALEN
) == 0)
579 sta
->counters
[valid
?
580 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX
:
581 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX
]++;
583 sta
->counters
[valid
?
584 WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX
:
585 WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX
]++;
589 static void rx_mgmt_action_sa_query_resp(struct wlantest
*wt
,
590 struct wlantest_sta
*sta
,
591 const struct ieee80211_mgmt
*mgmt
,
592 size_t len
, int valid
)
598 rx_id
= (const u8
*) mgmt
->u
.action
.u
.sa_query_resp
.trans_id
;
599 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
600 id
= sta
->sta_sa_query_tr
;
602 id
= sta
->ap_sa_query_tr
;
603 match
= os_memcmp(rx_id
, id
, 2) == 0;
604 wpa_printf(MSG_INFO
, "SA Query Response " MACSTR
" -> " MACSTR
605 " (trans_id=%02x%02x; %s)%s",
606 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
), rx_id
[0], rx_id
[1],
607 match
? "match" : "mismatch",
608 valid
? "" : " (invalid protection)");
609 if (os_memcmp(mgmt
->sa
, sta
->addr
, ETH_ALEN
) == 0)
610 sta
->counters
[(valid
&& match
) ?
611 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX
:
612 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX
]++;
614 sta
->counters
[(valid
&& match
) ?
615 WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX
:
616 WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX
]++;
620 static void rx_mgmt_action_sa_query(struct wlantest
*wt
,
621 struct wlantest_sta
*sta
,
622 const struct ieee80211_mgmt
*mgmt
,
623 size_t len
, int valid
)
625 if (len
< 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
) {
626 wpa_printf(MSG_INFO
, "Too short SA Query frame from " MACSTR
,
631 if (len
> 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
) {
632 size_t elen
= len
- (24 + 2 + WLAN_SA_QUERY_TR_ID_LEN
);
633 wpa_printf(MSG_INFO
, "Unexpected %u octets of extra data at "
634 "the end of SA Query frame from " MACSTR
,
635 (unsigned) elen
, MAC2STR(mgmt
->sa
));
636 wpa_hexdump(MSG_INFO
, "SA Query extra data",
637 ((const u8
*) mgmt
) + len
- elen
, elen
);
640 switch (mgmt
->u
.action
.u
.sa_query_req
.action
) {
641 case WLAN_SA_QUERY_REQUEST
:
642 rx_mgmt_action_sa_query_req(wt
, sta
, mgmt
, len
, valid
);
644 case WLAN_SA_QUERY_RESPONSE
:
645 rx_mgmt_action_sa_query_resp(wt
, sta
, mgmt
, len
, valid
);
648 wpa_printf(MSG_INFO
, "Unexpected SA Query action value %u "
650 mgmt
->u
.action
.u
.sa_query_req
.action
,
656 static void rx_mgmt_action(struct wlantest
*wt
, const u8
*data
, size_t len
,
659 const struct ieee80211_mgmt
*mgmt
;
660 struct wlantest_bss
*bss
;
661 struct wlantest_sta
*sta
;
663 mgmt
= (const struct ieee80211_mgmt
*) data
;
664 if (mgmt
->da
[0] & 0x01) {
665 wpa_printf(MSG_DEBUG
, "Group addressed Action frame: DA="
666 MACSTR
" SA=" MACSTR
" BSSID=" MACSTR
668 MAC2STR(mgmt
->da
), MAC2STR(mgmt
->sa
),
669 MAC2STR(mgmt
->bssid
), mgmt
->u
.action
.category
);
670 return; /* Ignore group addressed Action frames for now */
672 bss
= bss_get(wt
, mgmt
->bssid
);
675 if (os_memcmp(mgmt
->sa
, mgmt
->bssid
, ETH_ALEN
) == 0)
676 sta
= sta_get(bss
, mgmt
->da
);
678 sta
= sta_get(bss
, mgmt
->sa
);
683 wpa_printf(MSG_INFO
, "Too short Action frame from "
684 MACSTR
, MAC2STR(mgmt
->sa
));
688 wpa_printf(MSG_DEBUG
, "ACTION " MACSTR
" -> " MACSTR
689 " (category=%u) (valid=%d)",
690 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
),
691 mgmt
->u
.action
.category
, valid
);
692 wpa_hexdump(MSG_MSGDUMP
, "ACTION payload", data
+ 24, len
- 24);
694 if (mgmt
->u
.action
.category
!= WLAN_ACTION_PUBLIC
&&
695 sta
->state
< STATE3
) {
696 wpa_printf(MSG_INFO
, "Action frame sent when STA is not in "
697 "State 3 (SA=" MACSTR
" DATA=" MACSTR
")",
698 MAC2STR(mgmt
->sa
), MAC2STR(mgmt
->da
));
701 switch (mgmt
->u
.action
.category
) {
702 case WLAN_ACTION_SA_QUERY
:
703 rx_mgmt_action_sa_query(wt
, sta
, mgmt
, len
, valid
);
709 static int check_mmie_mic(const u8
*igtk
, const u8
*data
, size_t len
)
714 const struct ieee80211_hdr
*hdr
;
716 buf
= os_malloc(len
+ 20 - 24);
720 /* BIP AAD: FC(masked) A1 A2 A3 */
721 hdr
= (const struct ieee80211_hdr
*) data
;
722 fc
= le_to_host16(hdr
->frame_control
);
723 fc
&= ~(WLAN_FC_RETRY
| WLAN_FC_PWRMGT
| WLAN_FC_MOREDATA
);
724 WPA_PUT_LE16(buf
, fc
);
725 os_memcpy(buf
+ 2, hdr
->addr1
, 3 * ETH_ALEN
);
727 /* Frame body with MMIE MIC masked to zero */
728 os_memcpy(buf
+ 20, data
+ 24, len
- 24 - 8);
729 os_memset(buf
+ 20 + len
- 24 - 8, 0, 8);
731 wpa_hexdump(MSG_MSGDUMP
, "BIP: AAD|Body(masked)", buf
, len
+ 20 - 24);
732 /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
733 if (omac1_aes_128(igtk
, buf
, len
+ 20 - 24, mic
) < 0) {
740 if (os_memcmp(data
+ len
- 8, mic
, 8) != 0)
747 static int check_bip(struct wlantest
*wt
, const u8
*data
, size_t len
)
749 const struct ieee80211_mgmt
*mgmt
;
753 struct wlantest_bss
*bss
;
755 mgmt
= (const struct ieee80211_mgmt
*) data
;
756 fc
= le_to_host16(mgmt
->frame_control
);
757 stype
= WLAN_FC_GET_STYPE(fc
);
759 if (stype
== WLAN_FC_STYPE_ACTION
) {
762 if (mgmt
->u
.action
.category
== WLAN_ACTION_PUBLIC
)
763 return 0; /* Not a robust management frame */
766 bss
= bss_get(wt
, mgmt
->bssid
);
768 return 0; /* No key known yet */
770 if (len
< 24 + 18 || data
[len
- 18] != WLAN_EID_MMIE
||
771 data
[len
- 17] != 16) {
773 if (bss
->rsn_capab
& WPA_CAPABILITY_MFPC
) {
774 wpa_printf(MSG_INFO
, "Robust group-addressed "
775 "management frame sent without BIP by "
776 MACSTR
, MAC2STR(mgmt
->sa
));
777 bss
->counters
[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE
]++;
783 mmie
= data
+ len
- 16;
784 keyid
= WPA_GET_LE16(mmie
);
785 if (keyid
& 0xf000) {
786 wpa_printf(MSG_INFO
, "MMIE KeyID reserved bits not zero "
787 "(%04x) from " MACSTR
, keyid
, MAC2STR(mgmt
->sa
));
790 if (keyid
< 4 || keyid
> 5) {
791 wpa_printf(MSG_INFO
, "Unexpected MMIE KeyID %u from " MACSTR
,
792 keyid
, MAC2STR(mgmt
->sa
));
793 bss
->counters
[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE
]++;
796 wpa_printf(MSG_DEBUG
, "MMIE KeyID %u", keyid
);
797 wpa_hexdump(MSG_MSGDUMP
, "MMIE IPN", mmie
+ 2, 6);
798 wpa_hexdump(MSG_MSGDUMP
, "MMIE MIC", mmie
+ 8, 8);
800 if (!bss
->igtk_set
[keyid
]) {
801 wpa_printf(MSG_DEBUG
, "No IGTK known to validate BIP frame");
805 if (os_memcmp(mmie
+ 2, bss
->ipn
[keyid
], 6) <= 0) {
806 wpa_printf(MSG_INFO
, "BIP replay detected: SA=" MACSTR
,
808 wpa_hexdump(MSG_INFO
, "RX IPN", mmie
+ 2, 6);
809 wpa_hexdump(MSG_INFO
, "Last RX IPN", bss
->ipn
[keyid
], 6);
812 if (check_mmie_mic(bss
->igtk
[keyid
], data
, len
) < 0) {
813 wpa_printf(MSG_INFO
, "Invalid MMIE MIC in a frame from "
814 MACSTR
, MAC2STR(mgmt
->sa
));
815 bss
->counters
[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE
]++;
819 wpa_printf(MSG_DEBUG
, "Valid MMIE MIC");
820 os_memcpy(bss
->ipn
[keyid
], mmie
+ 2, 6);
821 bss
->counters
[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE
]++;
823 if (stype
== WLAN_FC_STYPE_DEAUTH
)
824 bss
->counters
[WLANTEST_BSS_COUNTER_BIP_DEAUTH
]++;
825 else if (stype
== WLAN_FC_STYPE_DISASSOC
)
826 bss
->counters
[WLANTEST_BSS_COUNTER_BIP_DISASSOC
]++;
832 static u8
* mgmt_ccmp_decrypt(struct wlantest
*wt
, const u8
*data
, size_t len
,
835 struct wlantest_bss
*bss
;
836 struct wlantest_sta
*sta
;
837 const struct ieee80211_hdr
*hdr
;
839 u8
*decrypted
, *frame
= NULL
;
842 hdr
= (const struct ieee80211_hdr
*) data
;
843 bss
= bss_get(wt
, hdr
->addr3
);
846 if (os_memcmp(hdr
->addr1
, hdr
->addr3
, ETH_ALEN
) == 0)
847 sta
= sta_get(bss
, hdr
->addr2
);
849 sta
= sta_get(bss
, hdr
->addr1
);
850 if (sta
== NULL
|| !sta
->ptk_set
) {
851 wpa_printf(MSG_MSGDUMP
, "No PTK known to decrypt the frame");
858 if (!(data
[24 + 3] & 0x20)) {
859 wpa_printf(MSG_INFO
, "Expected CCMP frame from " MACSTR
860 " did not have ExtIV bit set to 1",
861 MAC2STR(hdr
->addr2
));
865 if (data
[24 + 2] != 0 || (data
[24 + 3] & 0x1f) != 0) {
866 wpa_printf(MSG_INFO
, "CCMP mgmt frame from " MACSTR
" used "
867 "non-zero reserved bit", MAC2STR(hdr
->addr2
));
870 keyid
= data
[24 + 3] >> 6;
872 wpa_printf(MSG_INFO
, "Unexpected non-zero KeyID %d in "
873 "individually addressed Management frame from "
874 MACSTR
, keyid
, MAC2STR(hdr
->addr2
));
877 if (os_memcmp(hdr
->addr1
, hdr
->addr3
, ETH_ALEN
) == 0)
878 rsc
= sta
->rsc_tods
[16];
880 rsc
= sta
->rsc_fromds
[16];
882 ccmp_get_pn(pn
, data
+ 24);
883 if (os_memcmp(pn
, rsc
, 6) <= 0) {
884 wpa_printf(MSG_INFO
, "CCMP/TKIP replay detected: SA=" MACSTR
,
885 MAC2STR(hdr
->addr2
));
886 wpa_hexdump(MSG_INFO
, "RX PN", pn
, 6);
887 wpa_hexdump(MSG_INFO
, "RSC", rsc
, 6);
890 decrypted
= ccmp_decrypt(sta
->ptk
.tk1
, hdr
, data
+ 24, len
- 24, dlen
);
892 os_memcpy(rsc
, pn
, 6);
893 frame
= os_malloc(24 + *dlen
);
895 os_memcpy(frame
, data
, 24);
896 os_memcpy(frame
+ 24, decrypted
, *dlen
);
907 static int check_mgmt_ccmp(struct wlantest
*wt
, const u8
*data
, size_t len
)
909 const struct ieee80211_mgmt
*mgmt
;
911 struct wlantest_bss
*bss
;
912 struct wlantest_sta
*sta
;
914 mgmt
= (const struct ieee80211_mgmt
*) data
;
915 fc
= le_to_host16(mgmt
->frame_control
);
917 if (WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACTION
) {
919 mgmt
->u
.action
.category
== WLAN_ACTION_PUBLIC
)
920 return 0; /* Not a robust management frame */
923 bss
= bss_get(wt
, mgmt
->bssid
);
926 if (os_memcmp(mgmt
->da
, mgmt
->bssid
, ETH_ALEN
) == 0)
927 sta
= sta_get(bss
, mgmt
->sa
);
929 sta
= sta_get(bss
, mgmt
->da
);
933 if ((sta
->rsn_capab
& WPA_CAPABILITY_MFPC
) &&
934 (sta
->state
== STATE3
||
935 WLAN_FC_GET_STYPE(fc
) == WLAN_FC_STYPE_ACTION
)) {
936 wpa_printf(MSG_INFO
, "Robust individually-addressed "
937 "management frame sent without CCMP by "
938 MACSTR
, MAC2STR(mgmt
->sa
));
946 void rx_mgmt(struct wlantest
*wt
, const u8
*data
, size_t len
)
948 const struct ieee80211_hdr
*hdr
;
951 u8
*decrypted
= NULL
;
957 hdr
= (const struct ieee80211_hdr
*) data
;
958 fc
= le_to_host16(hdr
->frame_control
);
960 stype
= WLAN_FC_GET_STYPE(fc
);
962 if ((hdr
->addr1
[0] & 0x01) &&
963 (stype
== WLAN_FC_STYPE_DEAUTH
||
964 stype
== WLAN_FC_STYPE_DISASSOC
||
965 stype
== WLAN_FC_STYPE_ACTION
)) {
966 if (check_bip(wt
, data
, len
) < 0)
970 wpa_printf((stype
== WLAN_FC_STYPE_BEACON
||
971 stype
== WLAN_FC_STYPE_PROBE_RESP
||
972 stype
== WLAN_FC_STYPE_PROBE_REQ
) ?
973 MSG_EXCESSIVE
: MSG_MSGDUMP
,
974 "MGMT %s%s%s DA=" MACSTR
" SA=" MACSTR
" BSSID=" MACSTR
,
976 fc
& WLAN_FC_PWRMGT
? " PwrMgt" : "",
977 fc
& WLAN_FC_ISWEP
? " Prot" : "",
978 MAC2STR(hdr
->addr1
), MAC2STR(hdr
->addr2
),
979 MAC2STR(hdr
->addr3
));
981 if ((fc
& WLAN_FC_ISWEP
) &&
982 !(hdr
->addr1
[0] & 0x01) &&
983 (stype
== WLAN_FC_STYPE_DEAUTH
||
984 stype
== WLAN_FC_STYPE_DISASSOC
||
985 stype
== WLAN_FC_STYPE_ACTION
)) {
986 decrypted
= mgmt_ccmp_decrypt(wt
, data
, len
, &dlen
);
988 write_pcap_decrypted(wt
, decrypted
, dlen
, NULL
, 0);
995 if (!(fc
& WLAN_FC_ISWEP
) &&
996 !(hdr
->addr1
[0] & 0x01) &&
997 (stype
== WLAN_FC_STYPE_DEAUTH
||
998 stype
== WLAN_FC_STYPE_DISASSOC
||
999 stype
== WLAN_FC_STYPE_ACTION
)) {
1000 if (check_mgmt_ccmp(wt
, data
, len
) < 0)
1005 case WLAN_FC_STYPE_BEACON
:
1006 rx_mgmt_beacon(wt
, data
, len
);
1008 case WLAN_FC_STYPE_PROBE_RESP
:
1009 rx_mgmt_probe_resp(wt
, data
, len
);
1011 case WLAN_FC_STYPE_AUTH
:
1012 rx_mgmt_auth(wt
, data
, len
);
1014 case WLAN_FC_STYPE_DEAUTH
:
1015 rx_mgmt_deauth(wt
, data
, len
, valid
);
1017 case WLAN_FC_STYPE_ASSOC_REQ
:
1018 rx_mgmt_assoc_req(wt
, data
, len
);
1020 case WLAN_FC_STYPE_ASSOC_RESP
:
1021 rx_mgmt_assoc_resp(wt
, data
, len
);
1023 case WLAN_FC_STYPE_REASSOC_REQ
:
1024 rx_mgmt_reassoc_req(wt
, data
, len
);
1026 case WLAN_FC_STYPE_REASSOC_RESP
:
1027 rx_mgmt_reassoc_resp(wt
, data
, len
);
1029 case WLAN_FC_STYPE_DISASSOC
:
1030 rx_mgmt_disassoc(wt
, data
, len
, valid
);
1032 case WLAN_FC_STYPE_ACTION
:
1033 rx_mgmt_action(wt
, data
, len
, valid
);