2 * Received 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 "utils/radiotap.h"
19 #include "utils/radiotap_iter.h"
20 #include "common/ieee802_11_defs.h"
21 #include "common/ieee802_11_common.h"
25 static const char * mgmt_stype(u16 stype)
28 case WLAN_FC_STYPE_ASSOC_REQ:
30 case WLAN_FC_STYPE_ASSOC_RESP:
32 case WLAN_FC_STYPE_REASSOC_REQ:
34 case WLAN_FC_STYPE_REASSOC_RESP:
35 return "REASSOC-RESP";
36 case WLAN_FC_STYPE_PROBE_REQ:
38 case WLAN_FC_STYPE_PROBE_RESP:
40 case WLAN_FC_STYPE_BEACON:
42 case WLAN_FC_STYPE_ATIM:
44 case WLAN_FC_STYPE_DISASSOC:
46 case WLAN_FC_STYPE_AUTH:
48 case WLAN_FC_STYPE_DEAUTH:
50 case WLAN_FC_STYPE_ACTION:
57 static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
59 const struct ieee80211_mgmt *mgmt;
60 struct wlantest_bss *bss;
61 struct ieee802_11_elems elems;
63 mgmt = (const struct ieee80211_mgmt *) data;
64 bss = bss_get(wt, mgmt->bssid);
67 if (bss->proberesp_seen)
68 return; /* do not override with Beacon data */
69 bss->capab_info = le_to_host16(mgmt->u.beacon.capab_info);
70 if (ieee802_11_parse_elems(mgmt->u.beacon.variable,
71 len - (mgmt->u.beacon.variable - data),
72 &elems, 0) == ParseFailed) {
73 if (bss->parse_error_reported)
75 wpa_printf(MSG_INFO, "Invalid IEs in a Beacon frame from "
76 MACSTR, MAC2STR(mgmt->sa));
77 bss->parse_error_reported = 1;
81 bss_update(bss, &elems);
85 static void rx_mgmt_probe_resp(struct wlantest *wt, const u8 *data, size_t len)
87 const struct ieee80211_mgmt *mgmt;
88 struct wlantest_bss *bss;
89 struct ieee802_11_elems elems;
91 mgmt = (const struct ieee80211_mgmt *) data;
92 bss = bss_get(wt, mgmt->bssid);
96 bss->capab_info = le_to_host16(mgmt->u.probe_resp.capab_info);
97 if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
98 len - (mgmt->u.probe_resp.variable - data),
99 &elems, 0) == ParseFailed) {
100 if (bss->parse_error_reported)
102 wpa_printf(MSG_INFO, "Invalid IEs in a Probe Response frame "
103 "from " MACSTR, MAC2STR(mgmt->sa));
104 bss->parse_error_reported = 1;
108 bss_update(bss, &elems);
112 static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
114 const struct ieee80211_mgmt *mgmt;
115 struct wlantest_bss *bss;
116 struct wlantest_sta *sta;
117 u16 alg, trans, status;
119 mgmt = (const struct ieee80211_mgmt *) data;
120 bss = bss_get(wt, mgmt->bssid);
123 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
124 sta = sta_get(bss, mgmt->da);
126 sta = sta_get(bss, mgmt->sa);
131 wpa_printf(MSG_INFO, "Too short Authentication frame from "
132 MACSTR, MAC2STR(mgmt->sa));
136 alg = le_to_host16(mgmt->u.auth.auth_alg);
137 trans = le_to_host16(mgmt->u.auth.auth_transaction);
138 status = le_to_host16(mgmt->u.auth.status_code);
140 wpa_printf(MSG_DEBUG, "AUTH " MACSTR " -> " MACSTR
141 " (alg=%u trans=%u status=%u)",
142 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), alg, trans, status);
144 if (alg == 0 && trans == 2 && status == 0) {
145 if (sta->state == STATE1) {
146 wpa_printf(MSG_DEBUG, "STA " MACSTR
147 " moved to State 2 with " MACSTR,
148 MAC2STR(sta->addr), MAC2STR(bss->bssid));
155 static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len)
157 const struct ieee80211_mgmt *mgmt;
158 struct wlantest_bss *bss;
159 struct wlantest_sta *sta;
161 mgmt = (const struct ieee80211_mgmt *) data;
162 bss = bss_get(wt, mgmt->bssid);
165 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
166 sta = sta_get(bss, mgmt->da);
168 sta = sta_get(bss, mgmt->sa);
173 wpa_printf(MSG_INFO, "Too short Deauthentication frame from "
174 MACSTR, MAC2STR(mgmt->sa));
178 wpa_printf(MSG_DEBUG, "DEAUTH " MACSTR " -> " MACSTR
180 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
181 le_to_host16(mgmt->u.deauth.reason_code));
183 if (sta->state != STATE1) {
184 wpa_printf(MSG_DEBUG, "STA " MACSTR
185 " moved to State 1 with " MACSTR,
186 MAC2STR(sta->addr), MAC2STR(bss->bssid));
192 static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len)
194 const struct ieee80211_mgmt *mgmt;
195 struct wlantest_bss *bss;
196 struct wlantest_sta *sta;
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));
220 static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
222 const struct ieee80211_mgmt *mgmt;
223 struct wlantest_bss *bss;
224 struct wlantest_sta *sta;
225 u16 capab, status, aid;
227 mgmt = (const struct ieee80211_mgmt *) data;
228 bss = bss_get(wt, mgmt->bssid);
231 sta = sta_get(bss, mgmt->da);
236 wpa_printf(MSG_INFO, "Too short Association Response frame "
237 "from " MACSTR, MAC2STR(mgmt->sa));
241 capab = le_to_host16(mgmt->u.assoc_resp.capab_info);
242 status = le_to_host16(mgmt->u.assoc_resp.status_code);
243 aid = le_to_host16(mgmt->u.assoc_resp.aid);
245 wpa_printf(MSG_DEBUG, "ASSOCRESP " MACSTR " -> " MACSTR
246 " (capab=0x%x status=%u aid=%u)",
247 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
253 if ((aid & 0xc000) != 0xc000) {
254 wpa_printf(MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
255 "in Association Response from " MACSTR,
258 sta->aid = aid & 0xc000;
260 if (sta->state < STATE2) {
261 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
262 "getting associated", MAC2STR(sta->addr));
265 if (sta->state < STATE3) {
266 wpa_printf(MSG_DEBUG, "STA " MACSTR
267 " moved to State 3 with " MACSTR,
268 MAC2STR(sta->addr), MAC2STR(bss->bssid));
274 static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
277 const struct ieee80211_mgmt *mgmt;
278 struct wlantest_bss *bss;
279 struct wlantest_sta *sta;
281 mgmt = (const struct ieee80211_mgmt *) data;
282 bss = bss_get(wt, mgmt->bssid);
285 sta = sta_get(bss, mgmt->sa);
289 if (len < 24 + 4 + ETH_ALEN) {
290 wpa_printf(MSG_INFO, "Too short Reassociation Request frame "
291 "from " MACSTR, MAC2STR(mgmt->sa));
295 wpa_printf(MSG_DEBUG, "REASSOCREQ " MACSTR " -> " MACSTR
296 " (capab=0x%x listen_int=%u current_ap=" MACSTR ")",
297 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
298 le_to_host16(mgmt->u.reassoc_req.capab_info),
299 le_to_host16(mgmt->u.reassoc_req.listen_interval),
300 MAC2STR(mgmt->u.reassoc_req.current_ap));
304 static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
307 const struct ieee80211_mgmt *mgmt;
308 struct wlantest_bss *bss;
309 struct wlantest_sta *sta;
310 u16 capab, status, aid;
312 mgmt = (const struct ieee80211_mgmt *) data;
313 bss = bss_get(wt, mgmt->bssid);
316 sta = sta_get(bss, mgmt->da);
321 wpa_printf(MSG_INFO, "Too short Reassociation Response frame "
322 "from " MACSTR, MAC2STR(mgmt->sa));
326 capab = le_to_host16(mgmt->u.reassoc_resp.capab_info);
327 status = le_to_host16(mgmt->u.reassoc_resp.status_code);
328 aid = le_to_host16(mgmt->u.reassoc_resp.aid);
330 wpa_printf(MSG_DEBUG, "REASSOCRESP " MACSTR " -> " MACSTR
331 " (capab=0x%x status=%u aid=%u)",
332 MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
338 if ((aid & 0xc000) != 0xc000) {
339 wpa_printf(MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
340 "in Reassociation Response from " MACSTR,
343 sta->aid = aid & 0xc000;
345 if (sta->state < STATE2) {
346 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
347 "getting associated", MAC2STR(sta->addr));
350 if (sta->state < STATE3) {
351 wpa_printf(MSG_DEBUG, "STA " MACSTR
352 " moved to State 3 with " MACSTR,
353 MAC2STR(sta->addr), MAC2STR(bss->bssid));
359 static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len)
361 const struct ieee80211_mgmt *mgmt;
362 struct wlantest_bss *bss;
363 struct wlantest_sta *sta;
365 mgmt = (const struct ieee80211_mgmt *) data;
366 bss = bss_get(wt, mgmt->bssid);
369 if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
370 sta = sta_get(bss, mgmt->da);
372 sta = sta_get(bss, mgmt->sa);
377 wpa_printf(MSG_INFO, "Too short Disassociation frame from "
378 MACSTR, MAC2STR(mgmt->sa));
382 wpa_printf(MSG_DEBUG, "DISASSOC " MACSTR " -> " MACSTR
384 MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
385 le_to_host16(mgmt->u.disassoc.reason_code));
387 if (sta->state < STATE2) {
388 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 or 3 "
389 "when getting disassociated", MAC2STR(sta->addr));
392 if (sta->state > STATE2) {
393 wpa_printf(MSG_DEBUG, "STA " MACSTR
394 " moved to State 2 with " MACSTR,
395 MAC2STR(sta->addr), MAC2STR(bss->bssid));
401 static void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
403 const struct ieee80211_hdr *hdr;
409 hdr = (const struct ieee80211_hdr *) data;
410 fc = le_to_host16(hdr->frame_control);
412 stype = WLAN_FC_GET_STYPE(fc);
414 wpa_printf((stype == WLAN_FC_STYPE_BEACON ||
415 stype == WLAN_FC_STYPE_PROBE_RESP ||
416 stype == WLAN_FC_STYPE_PROBE_REQ) ?
417 MSG_EXCESSIVE : MSG_MSGDUMP,
418 "MGMT %s%s%s DA=" MACSTR " SA=" MACSTR " BSSID=" MACSTR,
420 fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
421 fc & WLAN_FC_ISWEP ? " Prot" : "",
422 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
423 MAC2STR(hdr->addr3));
426 case WLAN_FC_STYPE_BEACON:
427 rx_mgmt_beacon(wt, data, len);
429 case WLAN_FC_STYPE_PROBE_RESP:
430 rx_mgmt_probe_resp(wt, data, len);
432 case WLAN_FC_STYPE_AUTH:
433 rx_mgmt_auth(wt, data, len);
435 case WLAN_FC_STYPE_DEAUTH:
436 rx_mgmt_deauth(wt, data, len);
438 case WLAN_FC_STYPE_ASSOC_REQ:
439 rx_mgmt_assoc_req(wt, data, len);
441 case WLAN_FC_STYPE_ASSOC_RESP:
442 rx_mgmt_assoc_resp(wt, data, len);
444 case WLAN_FC_STYPE_REASSOC_REQ:
445 rx_mgmt_reassoc_req(wt, data, len);
447 case WLAN_FC_STYPE_REASSOC_RESP:
448 rx_mgmt_reassoc_resp(wt, data, len);
450 case WLAN_FC_STYPE_DISASSOC:
451 rx_mgmt_disassoc(wt, data, len);
457 static const char * data_stype(u16 stype)
460 case WLAN_FC_STYPE_DATA:
462 case WLAN_FC_STYPE_DATA_CFACK:
464 case WLAN_FC_STYPE_DATA_CFPOLL:
465 return "DATA-CFPOLL";
466 case WLAN_FC_STYPE_DATA_CFACKPOLL:
467 return "DATA-CFACKPOLL";
468 case WLAN_FC_STYPE_NULLFUNC:
470 case WLAN_FC_STYPE_CFACK:
472 case WLAN_FC_STYPE_CFPOLL:
474 case WLAN_FC_STYPE_CFACKPOLL:
476 case WLAN_FC_STYPE_QOS_DATA:
478 case WLAN_FC_STYPE_QOS_DATA_CFACK:
479 return "QOSDATA-CFACK";
480 case WLAN_FC_STYPE_QOS_DATA_CFPOLL:
481 return "QOSDATA-CFPOLL";
482 case WLAN_FC_STYPE_QOS_DATA_CFACKPOLL:
483 return "QOSDATA-CFACKPOLL";
484 case WLAN_FC_STYPE_QOS_NULL:
486 case WLAN_FC_STYPE_QOS_CFPOLL:
488 case WLAN_FC_STYPE_QOS_CFACKPOLL:
489 return "QOS-CFACKPOLL";
495 static void rx_data(struct wlantest *wt, const u8 *data, size_t len)
497 const struct ieee80211_hdr *hdr;
503 hdr = (const struct ieee80211_hdr *) data;
504 fc = le_to_host16(hdr->frame_control);
507 switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
509 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s IBSS DA=" MACSTR " SA="
510 MACSTR " BSSID=" MACSTR,
511 data_stype(WLAN_FC_GET_STYPE(fc)),
512 fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
513 fc & WLAN_FC_ISWEP ? " Prot" : "",
514 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
515 MAC2STR(hdr->addr3));
518 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s FromDS DA=" MACSTR
519 " BSSID=" MACSTR " SA=" MACSTR,
520 data_stype(WLAN_FC_GET_STYPE(fc)),
521 fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
522 fc & WLAN_FC_ISWEP ? " Prot" : "",
523 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
524 MAC2STR(hdr->addr3));
527 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s ToDS BSSID=" MACSTR
528 " SA=" MACSTR " DA=" MACSTR,
529 data_stype(WLAN_FC_GET_STYPE(fc)),
530 fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
531 fc & WLAN_FC_ISWEP ? " Prot" : "",
532 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
533 MAC2STR(hdr->addr3));
535 case WLAN_FC_TODS | WLAN_FC_FROMDS:
536 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s WDS RA=" MACSTR " TA="
537 MACSTR " DA=" MACSTR " SA=" MACSTR,
538 data_stype(WLAN_FC_GET_STYPE(fc)),
539 fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
540 fc & WLAN_FC_ISWEP ? " Prot" : "",
541 MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
543 MAC2STR((const u8 *) (hdr + 1)));
549 static void rx_frame(struct wlantest *wt, const u8 *data, size_t len)
551 const struct ieee80211_hdr *hdr;
554 wpa_hexdump(MSG_EXCESSIVE, "RX frame", data, len);
558 hdr = (const struct ieee80211_hdr *) data;
559 fc = le_to_host16(hdr->frame_control);
560 if (fc & WLAN_FC_PVER) {
561 wpa_printf(MSG_DEBUG, "Drop RX frame with unexpected pver=%d",
566 switch (WLAN_FC_GET_TYPE(fc)) {
567 case WLAN_FC_TYPE_MGMT:
568 rx_mgmt(wt, data, len);
570 case WLAN_FC_TYPE_CTRL:
575 case WLAN_FC_TYPE_DATA:
576 rx_data(wt, data, len);
579 wpa_printf(MSG_DEBUG, "Drop RX frame with unexpected type %d",
580 WLAN_FC_GET_TYPE(fc));
586 static void tx_status(struct wlantest *wt, const u8 *data, size_t len, int ack)
588 wpa_printf(MSG_DEBUG, "TX status: ack=%d", ack);
589 wpa_hexdump(MSG_EXCESSIVE, "TX status frame", data, len);
593 static int check_fcs(const u8 *frame, size_t frame_len, const u8 *fcs)
595 if (WPA_GET_LE32(fcs) != crc32(frame, frame_len))
601 void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
603 struct ieee80211_radiotap_iterator iter;
605 int rxflags = 0, txflags = 0, failed = 0, fcs = 0;
606 const u8 *frame, *fcspos;
609 wpa_hexdump(MSG_EXCESSIVE, "Process data", data, len);
611 if (ieee80211_radiotap_iterator_init(&iter, (void *) data, len)) {
612 wpa_printf(MSG_INFO, "Invalid radiotap frame");
617 ret = ieee80211_radiotap_iterator_next(&iter);
618 wpa_printf(MSG_EXCESSIVE, "radiotap iter: %d "
619 "this_arg_index=%d", ret, iter.this_arg_index);
623 wpa_printf(MSG_INFO, "Invalid radiotap header: %d",
627 switch (iter.this_arg_index) {
628 case IEEE80211_RADIOTAP_FLAGS:
629 if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
632 case IEEE80211_RADIOTAP_RX_FLAGS:
635 case IEEE80211_RADIOTAP_TX_FLAGS:
637 failed = le_to_host16((*(u16 *) iter.this_arg)) &
638 IEEE80211_RADIOTAP_F_TX_FAIL;
644 frame = data + iter.max_length;
645 frame_len = len - iter.max_length;
647 if (fcs && frame_len >= 4) {
649 fcspos = frame + frame_len;
650 if (check_fcs(frame, frame_len, fcspos) < 0) {
651 wpa_printf(MSG_EXCESSIVE, "Drop RX frame with invalid "
658 if (rxflags && txflags)
661 rx_frame(wt, frame, frame_len);
663 tx_status(wt, frame, frame_len, !failed);