wlantest: Move bss_update() into bss.c
[mech_eap.git] / wlantest / process.c
1 /*
2  * Received frame processing
3  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
4  *
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.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "utils/includes.h"
16
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"
22 #include "wlantest.h"
23
24
25 static const char * mgmt_stype(u16 stype)
26 {
27         switch (stype) {
28         case WLAN_FC_STYPE_ASSOC_REQ:
29                 return "ASSOC-REQ";
30         case WLAN_FC_STYPE_ASSOC_RESP:
31                 return "ASSOC-RESP";
32         case WLAN_FC_STYPE_REASSOC_REQ:
33                 return "REASSOC-REQ";
34         case WLAN_FC_STYPE_REASSOC_RESP:
35                 return "REASSOC-RESP";
36         case WLAN_FC_STYPE_PROBE_REQ:
37                 return "PROBE-REQ";
38         case WLAN_FC_STYPE_PROBE_RESP:
39                 return "PROBE-RESP";
40         case WLAN_FC_STYPE_BEACON:
41                 return "BEACON";
42         case WLAN_FC_STYPE_ATIM:
43                 return "ATIM";
44         case WLAN_FC_STYPE_DISASSOC:
45                 return "DISASSOC";
46         case WLAN_FC_STYPE_AUTH:
47                 return "AUTH";
48         case WLAN_FC_STYPE_DEAUTH:
49                 return "DEAUTH";
50         case WLAN_FC_STYPE_ACTION:
51                 return "ACTION";
52         }
53         return "??";
54 }
55
56
57 static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
58 {
59         const struct ieee80211_mgmt *mgmt;
60         struct wlantest_bss *bss;
61         struct ieee802_11_elems elems;
62
63         mgmt = (const struct ieee80211_mgmt *) data;
64         bss = bss_get(wt, mgmt->bssid);
65         if (bss == NULL)
66                 return;
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)
74                         return;
75                 wpa_printf(MSG_INFO, "Invalid IEs in a Beacon frame from "
76                            MACSTR, MAC2STR(mgmt->sa));
77                 bss->parse_error_reported = 1;
78                 return;
79         }
80
81         bss_update(bss, &elems);
82 }
83
84
85 static void rx_mgmt_probe_resp(struct wlantest *wt, const u8 *data, size_t len)
86 {
87         const struct ieee80211_mgmt *mgmt;
88         struct wlantest_bss *bss;
89         struct ieee802_11_elems elems;
90
91         mgmt = (const struct ieee80211_mgmt *) data;
92         bss = bss_get(wt, mgmt->bssid);
93         if (bss == NULL)
94                 return;
95
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)
101                         return;
102                 wpa_printf(MSG_INFO, "Invalid IEs in a Probe Response frame "
103                            "from " MACSTR, MAC2STR(mgmt->sa));
104                 bss->parse_error_reported = 1;
105                 return;
106         }
107
108         bss_update(bss, &elems);
109 }
110
111
112 static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
113 {
114         const struct ieee80211_mgmt *mgmt;
115         struct wlantest_bss *bss;
116         struct wlantest_sta *sta;
117         u16 alg, trans, status;
118
119         mgmt = (const struct ieee80211_mgmt *) data;
120         bss = bss_get(wt, mgmt->bssid);
121         if (bss == NULL)
122                 return;
123         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
124                 sta = sta_get(bss, mgmt->da);
125         else
126                 sta = sta_get(bss, mgmt->sa);
127         if (sta == NULL)
128                 return;
129
130         if (len < 24 + 6) {
131                 wpa_printf(MSG_INFO, "Too short Authentication frame from "
132                            MACSTR, MAC2STR(mgmt->sa));
133                 return;
134         }
135
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);
139
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);
143
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));
149                         sta->state = STATE2;
150                 }
151         }
152 }
153
154
155 static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len)
156 {
157         const struct ieee80211_mgmt *mgmt;
158         struct wlantest_bss *bss;
159         struct wlantest_sta *sta;
160
161         mgmt = (const struct ieee80211_mgmt *) data;
162         bss = bss_get(wt, mgmt->bssid);
163         if (bss == NULL)
164                 return;
165         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
166                 sta = sta_get(bss, mgmt->da);
167         else
168                 sta = sta_get(bss, mgmt->sa);
169         if (sta == NULL)
170                 return;
171
172         if (len < 24 + 2) {
173                 wpa_printf(MSG_INFO, "Too short Deauthentication frame from "
174                            MACSTR, MAC2STR(mgmt->sa));
175                 return;
176         }
177
178         wpa_printf(MSG_DEBUG, "DEAUTH " MACSTR " -> " MACSTR
179                    " (reason=%u)",
180                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
181                    le_to_host16(mgmt->u.deauth.reason_code));
182
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));
187                 sta->state = STATE1;
188         }
189 }
190
191
192 static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len)
193 {
194         const struct ieee80211_mgmt *mgmt;
195         struct wlantest_bss *bss;
196         struct wlantest_sta *sta;
197
198         mgmt = (const struct ieee80211_mgmt *) data;
199         bss = bss_get(wt, mgmt->bssid);
200         if (bss == NULL)
201                 return;
202         sta = sta_get(bss, mgmt->sa);
203         if (sta == NULL)
204                 return;
205
206         if (len < 24 + 4) {
207                 wpa_printf(MSG_INFO, "Too short Association Request frame "
208                            "from " MACSTR, MAC2STR(mgmt->sa));
209                 return;
210         }
211
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));
217 }
218
219
220 static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
221 {
222         const struct ieee80211_mgmt *mgmt;
223         struct wlantest_bss *bss;
224         struct wlantest_sta *sta;
225         u16 capab, status, aid;
226
227         mgmt = (const struct ieee80211_mgmt *) data;
228         bss = bss_get(wt, mgmt->bssid);
229         if (bss == NULL)
230                 return;
231         sta = sta_get(bss, mgmt->da);
232         if (sta == NULL)
233                 return;
234
235         if (len < 24 + 6) {
236                 wpa_printf(MSG_INFO, "Too short Association Response frame "
237                            "from " MACSTR, MAC2STR(mgmt->sa));
238                 return;
239         }
240
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);
244
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,
248                    aid & 0x3fff);
249
250         if (status)
251                 return;
252
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,
256                            MAC2STR(mgmt->sa));
257         }
258         sta->aid = aid & 0xc000;
259
260         if (sta->state < STATE2) {
261                 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
262                            "getting associated", MAC2STR(sta->addr));
263         }
264
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));
269                 sta->state = STATE3;
270         }
271 }
272
273
274 static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
275                                 size_t len)
276 {
277         const struct ieee80211_mgmt *mgmt;
278         struct wlantest_bss *bss;
279         struct wlantest_sta *sta;
280
281         mgmt = (const struct ieee80211_mgmt *) data;
282         bss = bss_get(wt, mgmt->bssid);
283         if (bss == NULL)
284                 return;
285         sta = sta_get(bss, mgmt->sa);
286         if (sta == NULL)
287                 return;
288
289         if (len < 24 + 4 + ETH_ALEN) {
290                 wpa_printf(MSG_INFO, "Too short Reassociation Request frame "
291                            "from " MACSTR, MAC2STR(mgmt->sa));
292                 return;
293         }
294
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));
301 }
302
303
304 static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
305                                  size_t len)
306 {
307         const struct ieee80211_mgmt *mgmt;
308         struct wlantest_bss *bss;
309         struct wlantest_sta *sta;
310         u16 capab, status, aid;
311
312         mgmt = (const struct ieee80211_mgmt *) data;
313         bss = bss_get(wt, mgmt->bssid);
314         if (bss == NULL)
315                 return;
316         sta = sta_get(bss, mgmt->da);
317         if (sta == NULL)
318                 return;
319
320         if (len < 24 + 6) {
321                 wpa_printf(MSG_INFO, "Too short Reassociation Response frame "
322                            "from " MACSTR, MAC2STR(mgmt->sa));
323                 return;
324         }
325
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);
329
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,
333                    aid & 0x3fff);
334
335         if (status)
336                 return;
337
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,
341                            MAC2STR(mgmt->sa));
342         }
343         sta->aid = aid & 0xc000;
344
345         if (sta->state < STATE2) {
346                 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
347                            "getting associated", MAC2STR(sta->addr));
348         }
349
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));
354                 sta->state = STATE3;
355         }
356 }
357
358
359 static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len)
360 {
361         const struct ieee80211_mgmt *mgmt;
362         struct wlantest_bss *bss;
363         struct wlantest_sta *sta;
364
365         mgmt = (const struct ieee80211_mgmt *) data;
366         bss = bss_get(wt, mgmt->bssid);
367         if (bss == NULL)
368                 return;
369         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
370                 sta = sta_get(bss, mgmt->da);
371         else
372                 sta = sta_get(bss, mgmt->sa);
373         if (sta == NULL)
374                 return;
375
376         if (len < 24 + 2) {
377                 wpa_printf(MSG_INFO, "Too short Disassociation frame from "
378                            MACSTR, MAC2STR(mgmt->sa));
379                 return;
380         }
381
382         wpa_printf(MSG_DEBUG, "DISASSOC " MACSTR " -> " MACSTR
383                    " (reason=%u)",
384                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
385                    le_to_host16(mgmt->u.disassoc.reason_code));
386
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));
390         }
391
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));
396                 sta->state = STATE2;
397         }
398 }
399
400
401 static void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
402 {
403         const struct ieee80211_hdr *hdr;
404         u16 fc, stype;
405
406         if (len < 24)
407                 return;
408
409         hdr = (const struct ieee80211_hdr *) data;
410         fc = le_to_host16(hdr->frame_control);
411         wt->rx_mgmt++;
412         stype = WLAN_FC_GET_STYPE(fc);
413
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,
419                    mgmt_stype(stype),
420                    fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
421                    fc & WLAN_FC_ISWEP ? " Prot" : "",
422                    MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
423                    MAC2STR(hdr->addr3));
424
425         switch (stype) {
426         case WLAN_FC_STYPE_BEACON:
427                 rx_mgmt_beacon(wt, data, len);
428                 break;
429         case WLAN_FC_STYPE_PROBE_RESP:
430                 rx_mgmt_probe_resp(wt, data, len);
431                 break;
432         case WLAN_FC_STYPE_AUTH:
433                 rx_mgmt_auth(wt, data, len);
434                 break;
435         case WLAN_FC_STYPE_DEAUTH:
436                 rx_mgmt_deauth(wt, data, len);
437                 break;
438         case WLAN_FC_STYPE_ASSOC_REQ:
439                 rx_mgmt_assoc_req(wt, data, len);
440                 break;
441         case WLAN_FC_STYPE_ASSOC_RESP:
442                 rx_mgmt_assoc_resp(wt, data, len);
443                 break;
444         case WLAN_FC_STYPE_REASSOC_REQ:
445                 rx_mgmt_reassoc_req(wt, data, len);
446                 break;
447         case WLAN_FC_STYPE_REASSOC_RESP:
448                 rx_mgmt_reassoc_resp(wt, data, len);
449                 break;
450         case WLAN_FC_STYPE_DISASSOC:
451                 rx_mgmt_disassoc(wt, data, len);
452                 break;
453         }
454 }
455
456
457 static const char * data_stype(u16 stype)
458 {
459         switch (stype) {
460         case WLAN_FC_STYPE_DATA:
461                 return "DATA";
462         case WLAN_FC_STYPE_DATA_CFACK:
463                 return "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:
469                 return "NULLFUNC";
470         case WLAN_FC_STYPE_CFACK:
471                 return "CFACK";
472         case WLAN_FC_STYPE_CFPOLL:
473                 return "CFPOLL";
474         case WLAN_FC_STYPE_CFACKPOLL:
475                 return "CFACKPOLL";
476         case WLAN_FC_STYPE_QOS_DATA:
477                 return "QOSDATA";
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:
485                 return "QOS-NULL";
486         case WLAN_FC_STYPE_QOS_CFPOLL:
487                 return "QOS-CFPOLL";
488         case WLAN_FC_STYPE_QOS_CFACKPOLL:
489                 return "QOS-CFACKPOLL";
490         }
491         return "??";
492 }
493
494
495 static void rx_data(struct wlantest *wt, const u8 *data, size_t len)
496 {
497         const struct ieee80211_hdr *hdr;
498         u16 fc;
499
500         if (len < 24)
501                 return;
502
503         hdr = (const struct ieee80211_hdr *) data;
504         fc = le_to_host16(hdr->frame_control);
505         wt->rx_data++;
506
507         switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
508         case 0:
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));
516                 break;
517         case WLAN_FC_FROMDS:
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));
525                 break;
526         case WLAN_FC_TODS:
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));
534                 break;
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),
542                            MAC2STR(hdr->addr3),
543                            MAC2STR((const u8 *) (hdr + 1)));
544                 break;
545         }
546 }
547
548
549 static void rx_frame(struct wlantest *wt, const u8 *data, size_t len)
550 {
551         const struct ieee80211_hdr *hdr;
552         u16 fc;
553
554         wpa_hexdump(MSG_EXCESSIVE, "RX frame", data, len);
555         if (len < 2)
556                 return;
557
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",
562                            fc & WLAN_FC_PVER);
563                 return;
564         }
565
566         switch (WLAN_FC_GET_TYPE(fc)) {
567         case WLAN_FC_TYPE_MGMT:
568                 rx_mgmt(wt, data, len);
569                 break;
570         case WLAN_FC_TYPE_CTRL:
571                 if (len < 10)
572                         return;
573                 wt->rx_ctrl++;
574                 break;
575         case WLAN_FC_TYPE_DATA:
576                 rx_data(wt, data, len);
577                 break;
578         default:
579                 wpa_printf(MSG_DEBUG, "Drop RX frame with unexpected type %d",
580                            WLAN_FC_GET_TYPE(fc));
581                 break;
582         }
583 }
584
585
586 static void tx_status(struct wlantest *wt, const u8 *data, size_t len, int ack)
587 {
588         wpa_printf(MSG_DEBUG, "TX status: ack=%d", ack);
589         wpa_hexdump(MSG_EXCESSIVE, "TX status frame", data, len);
590 }
591
592
593 static int check_fcs(const u8 *frame, size_t frame_len, const u8 *fcs)
594 {
595         if (WPA_GET_LE32(fcs) != crc32(frame, frame_len))
596                 return -1;
597         return 0;
598 }
599
600
601 void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
602 {
603         struct ieee80211_radiotap_iterator iter;
604         int ret;
605         int rxflags = 0, txflags = 0, failed = 0, fcs = 0;
606         const u8 *frame, *fcspos;
607         size_t frame_len;
608
609         wpa_hexdump(MSG_EXCESSIVE, "Process data", data, len);
610
611         if (ieee80211_radiotap_iterator_init(&iter, (void *) data, len)) {
612                 wpa_printf(MSG_INFO, "Invalid radiotap frame");
613                 return;
614         }
615
616         for (;;) {
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);
620                 if (ret == -ENOENT)
621                         break;
622                 if (ret) {
623                         wpa_printf(MSG_INFO, "Invalid radiotap header: %d",
624                                    ret);
625                         return;
626                 }
627                 switch (iter.this_arg_index) {
628                 case IEEE80211_RADIOTAP_FLAGS:
629                         if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
630                                 fcs = 1;
631                         break;
632                 case IEEE80211_RADIOTAP_RX_FLAGS:
633                         rxflags = 1;
634                         break;
635                 case IEEE80211_RADIOTAP_TX_FLAGS:
636                         txflags = 1;
637                         failed = le_to_host16((*(u16 *) iter.this_arg)) &
638                                 IEEE80211_RADIOTAP_F_TX_FAIL;
639                         break;
640
641                 }
642         }
643
644         frame = data + iter.max_length;
645         frame_len = len - iter.max_length;
646
647         if (fcs && frame_len >= 4) {
648                 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 "
652                                    "FCS");
653                         wt->fcs_error++;
654                         return;
655                 }
656         }
657
658         if (rxflags && txflags)
659                 return;
660         if (!txflags)
661                 rx_frame(wt, frame, frame_len);
662         else
663                 tx_status(wt, frame, frame_len, !failed);
664 }