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));
154 static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len)
156 const struct ieee80211_mgmt *mgmt;
157 struct wlantest_bss *bss;
158 struct wlantest_sta *sta;
160 mgmt = (const struct ieee80211_mgmt *) data;
161 bss = bss_get(wt, mgmt->bssid);
164 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
165 sta = sta_get(bss, mgmt->da);
167 sta = sta_get(bss, mgmt->sa);
172 wpa_printf(MSG_INFO, "Too short Deauthentication frame from "
173 MACSTR, MAC2STR(mgmt->sa));
177 wpa_printf(MSG_DEBUG, "DEAUTH " MACSTR " -> " MACSTR
179 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
180 le_to_host16(mgmt->u.deauth.reason_code));
182 if (sta->state != STATE1) {
183 wpa_printf(MSG_DEBUG, "STA " MACSTR
184 " moved to State 1 with " MACSTR,
185 MAC2STR(sta->addr), MAC2STR(bss->bssid));
191 static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len)
193 const struct ieee80211_mgmt *mgmt;
194 struct wlantest_bss *bss;
195 struct wlantest_sta *sta;
196 struct ieee802_11_elems elems;
198 mgmt = (const struct ieee80211_mgmt *) data;
199 bss = bss_get(wt, mgmt->bssid);
202 sta = sta_get(bss, mgmt->sa);
207 wpa_printf(MSG_INFO, "Too short Association Request frame "
208 "from " MACSTR, MAC2STR(mgmt->sa));
212 wpa_printf(MSG_DEBUG, "ASSOCREQ " MACSTR " -> " MACSTR
213 " (capab=0x%x listen_int=%u)",
214 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
215 le_to_host16(mgmt->u.assoc_req.capab_info),
216 le_to_host16(mgmt->u.assoc_req.listen_interval));
218 if (ieee802_11_parse_elems(mgmt->u.assoc_req.variable,
219 len - (mgmt->u.assoc_req.variable - data),
220 &elems, 0) == ParseFailed) {
221 wpa_printf(MSG_INFO, "Invalid IEs in Association Request "
222 "frame from " MACSTR, MAC2STR(mgmt->sa));
226 sta_update_assoc(sta, &elems);
230 static void rx_mgmt_assoc_resp(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 u16 capab, status, aid;
237 mgmt = (const struct ieee80211_mgmt *) data;
238 bss = bss_get(wt, mgmt->bssid);
241 sta = sta_get(bss, mgmt->da);
246 wpa_printf(MSG_INFO, "Too short Association Response frame "
247 "from " MACSTR, MAC2STR(mgmt->sa));
251 capab = le_to_host16(mgmt->u.assoc_resp.capab_info);
252 status = le_to_host16(mgmt->u.assoc_resp.status_code);
253 aid = le_to_host16(mgmt->u.assoc_resp.aid);
255 wpa_printf(MSG_DEBUG, "ASSOCRESP " MACSTR " -> " MACSTR
256 " (capab=0x%x status=%u aid=%u)",
257 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
263 if ((aid & 0xc000) != 0xc000) {
264 wpa_printf(MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
265 "in Association Response from " MACSTR,
268 sta->aid = aid & 0xc000;
270 if (sta->state < STATE2) {
271 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
272 "getting associated", MAC2STR(sta->addr));
275 if (sta->state < STATE3) {
276 wpa_printf(MSG_DEBUG, "STA " MACSTR
277 " moved to State 3 with " MACSTR,
278 MAC2STR(sta->addr), MAC2STR(bss->bssid));
284 static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
287 const struct ieee80211_mgmt *mgmt;
288 struct wlantest_bss *bss;
289 struct wlantest_sta *sta;
290 struct ieee802_11_elems elems;
292 mgmt = (const struct ieee80211_mgmt *) data;
293 bss = bss_get(wt, mgmt->bssid);
296 sta = sta_get(bss, mgmt->sa);
300 if (len < 24 + 4 + ETH_ALEN) {
301 wpa_printf(MSG_INFO, "Too short Reassociation Request frame "
302 "from " MACSTR, MAC2STR(mgmt->sa));
306 wpa_printf(MSG_DEBUG, "REASSOCREQ " MACSTR " -> " MACSTR
307 " (capab=0x%x listen_int=%u current_ap=" MACSTR ")",
308 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
309 le_to_host16(mgmt->u.reassoc_req.capab_info),
310 le_to_host16(mgmt->u.reassoc_req.listen_interval),
311 MAC2STR(mgmt->u.reassoc_req.current_ap));
313 if (ieee802_11_parse_elems(mgmt->u.reassoc_req.variable,
314 len - (mgmt->u.reassoc_req.variable - data),
315 &elems, 0) == ParseFailed) {
316 wpa_printf(MSG_INFO, "Invalid IEs in Reassociation Request "
317 "frame from " MACSTR, MAC2STR(mgmt->sa));
321 sta_update_assoc(sta, &elems);
325 static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
328 const struct ieee80211_mgmt *mgmt;
329 struct wlantest_bss *bss;
330 struct wlantest_sta *sta;
331 u16 capab, status, aid;
333 mgmt = (const struct ieee80211_mgmt *) data;
334 bss = bss_get(wt, mgmt->bssid);
337 sta = sta_get(bss, mgmt->da);
342 wpa_printf(MSG_INFO, "Too short Reassociation Response frame "
343 "from " MACSTR, MAC2STR(mgmt->sa));
347 capab = le_to_host16(mgmt->u.reassoc_resp.capab_info);
348 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
349 aid = le_to_host16(mgmt->u.reassoc_resp.aid);
351 wpa_printf(MSG_DEBUG, "REASSOCRESP " MACSTR " -> " MACSTR
352 " (capab=0x%x status=%u aid=%u)",
353 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
359 if ((aid & 0xc000) != 0xc000) {
360 wpa_printf(MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
361 "in Reassociation Response from " MACSTR,
364 sta->aid = aid & 0xc000;
366 if (sta->state < STATE2) {
367 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
368 "getting associated", MAC2STR(sta->addr));
371 if (sta->state < STATE3) {
372 wpa_printf(MSG_DEBUG, "STA " MACSTR
373 " moved to State 3 with " MACSTR,
374 MAC2STR(sta->addr), MAC2STR(bss->bssid));
380 static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len)
382 const struct ieee80211_mgmt *mgmt;
383 struct wlantest_bss *bss;
384 struct wlantest_sta *sta;
386 mgmt = (const struct ieee80211_mgmt *) data;
387 bss = bss_get(wt, mgmt->bssid);
390 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
391 sta = sta_get(bss, mgmt->da);
393 sta = sta_get(bss, mgmt->sa);
398 wpa_printf(MSG_INFO, "Too short Disassociation frame from "
399 MACSTR, MAC2STR(mgmt->sa));
403 wpa_printf(MSG_DEBUG, "DISASSOC " MACSTR " -> " MACSTR
405 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
406 le_to_host16(mgmt->u.disassoc.reason_code));
408 if (sta->state < STATE2) {
409 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 or 3 "
410 "when getting disassociated", MAC2STR(sta->addr));
413 if (sta->state > STATE2) {
414 wpa_printf(MSG_DEBUG, "STA " MACSTR
415 " moved to State 2 with " MACSTR,
416 MAC2STR(sta->addr), MAC2STR(bss->bssid));
422 static int check_mmie_mic(const u8 *igtk, const u8 *data, size_t len)
427 const struct ieee80211_hdr *hdr;
429 buf = os_malloc(len + 20 - 24);
433 /* BIP AAD: FC(masked) A1 A2 A3 */
434 hdr = (const struct ieee80211_hdr *) data;
435 fc = le_to_host16(hdr->frame_control);
436 fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
437 WPA_PUT_LE16(buf, fc);
438 os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
440 /* Frame body with MMIE MIC masked to zero */
441 os_memcpy(buf + 20, data + 24, len - 24 - 8);
442 os_memset(buf + 20 + len - 24 - 8, 0, 8);
444 wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, len + 20 - 24);
445 /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
446 if (omac1_aes_128(igtk, buf, len + 20 - 24, mic) < 0) {
453 if (os_memcmp(data + len - 8, mic, 8) != 0)
460 static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
462 const struct ieee80211_mgmt *mgmt;
466 struct wlantest_bss *bss;
468 mgmt = (const struct ieee80211_mgmt *) data;
469 fc = le_to_host16(mgmt->frame_control);
470 stype = WLAN_FC_GET_STYPE(fc);
472 if (stype == WLAN_FC_STYPE_ACTION) {
475 if (mgmt->u.action.category == WLAN_ACTION_PUBLIC)
476 return 0; /* Not a robust management frame */
479 bss = bss_get(wt, mgmt->bssid);
481 return 0; /* No key known yet */
483 if (len < 24 + 18 || data[len - 18] != WLAN_EID_MMIE ||
484 data[len - 17] != 16) {
486 /* TODO: use MFPC flag in RSN IE instead of IGTK flags */
487 if (bss->igtk_set[4] || bss->igtk_set[5]) {
488 wpa_printf(MSG_INFO, "Robust group-addressed "
489 "management frame sent without BIP by "
490 MACSTR, MAC2STR(mgmt->sa));
496 mmie = data + len - 16;
497 keyid = WPA_GET_LE16(mmie);
498 if (keyid < 4 || keyid > 5) {
499 wpa_printf(MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR,
500 keyid, MAC2STR(mgmt->sa));
503 wpa_printf(MSG_DEBUG, "MMIE KeyID %u", keyid);
504 wpa_hexdump(MSG_MSGDUMP, "MMIE IPN", mmie + 2, 6);
505 wpa_hexdump(MSG_MSGDUMP, "MMIE MIC", mmie + 8, 8);
507 if (!bss->igtk_set[keyid]) {
508 wpa_printf(MSG_DEBUG, "No IGTK known to validate BIP frame");
512 if (os_memcmp(mmie + 2, bss->ipn[keyid], 6) <= 0) {
513 wpa_printf(MSG_INFO, "BIP replay detected: SA=" MACSTR,
515 wpa_hexdump(MSG_INFO, "RX IPN", mmie + 2, 6);
516 wpa_hexdump(MSG_INFO, "Last RX IPN", bss->ipn[keyid], 6);
519 if (check_mmie_mic(bss->igtk[keyid], data, len) < 0) {
520 wpa_printf(MSG_INFO, "Invalid MMIE MIC in a frame from "
521 MACSTR, MAC2STR(mgmt->sa));
525 wpa_printf(MSG_DEBUG, "Valid MMIE MIC");
526 os_memcpy(bss->ipn[keyid], mmie + 2, 6);
532 void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
534 const struct ieee80211_hdr *hdr;
540 hdr = (const struct ieee80211_hdr *) data;
541 fc = le_to_host16(hdr->frame_control);
543 stype = WLAN_FC_GET_STYPE(fc);
545 if ((hdr->addr1[0] & 0x01) &&
546 (stype == WLAN_FC_STYPE_DEAUTH ||
547 stype == WLAN_FC_STYPE_DISASSOC ||
548 stype == WLAN_FC_STYPE_ACTION))
549 check_bip(wt, data, len);
551 wpa_printf((stype == WLAN_FC_STYPE_BEACON ||
552 stype == WLAN_FC_STYPE_PROBE_RESP ||
553 stype == WLAN_FC_STYPE_PROBE_REQ) ?
554 MSG_EXCESSIVE : MSG_MSGDUMP,
555 "MGMT %s%s%s DA=" MACSTR " SA=" MACSTR " BSSID=" MACSTR,
557 fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
558 fc & WLAN_FC_ISWEP ? " Prot" : "",
559 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
560 MAC2STR(hdr->addr3));
563 case WLAN_FC_STYPE_BEACON:
564 rx_mgmt_beacon(wt, data, len);
566 case WLAN_FC_STYPE_PROBE_RESP:
567 rx_mgmt_probe_resp(wt, data, len);
569 case WLAN_FC_STYPE_AUTH:
570 rx_mgmt_auth(wt, data, len);
572 case WLAN_FC_STYPE_DEAUTH:
573 rx_mgmt_deauth(wt, data, len);
575 case WLAN_FC_STYPE_ASSOC_REQ:
576 rx_mgmt_assoc_req(wt, data, len);
578 case WLAN_FC_STYPE_ASSOC_RESP:
579 rx_mgmt_assoc_resp(wt, data, len);
581 case WLAN_FC_STYPE_REASSOC_REQ:
582 rx_mgmt_reassoc_req(wt, data, len);
584 case WLAN_FC_STYPE_REASSOC_RESP:
585 rx_mgmt_reassoc_resp(wt, data, len);
587 case WLAN_FC_STYPE_DISASSOC:
588 rx_mgmt_disassoc(wt, data, len);