6083390fe0fad559dd79fbf843b60334d445b86c
[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 "wlantest.h"
22
23
24 static void rx_frame(struct wlantest *wt, const u8 *data, size_t len)
25 {
26         const struct ieee80211_hdr *hdr;
27         u16 fc;
28
29         wpa_hexdump(MSG_EXCESSIVE, "RX frame", data, len);
30         if (len < 2)
31                 return;
32
33         hdr = (const struct ieee80211_hdr *) data;
34         fc = le_to_host16(hdr->frame_control);
35         if (fc & WLAN_FC_PVER) {
36                 wpa_printf(MSG_DEBUG, "Drop RX frame with unexpected pver=%d",
37                            fc & WLAN_FC_PVER);
38                 return;
39         }
40
41         switch (WLAN_FC_GET_TYPE(fc)) {
42         case WLAN_FC_TYPE_MGMT:
43                 rx_mgmt(wt, data, len);
44                 break;
45         case WLAN_FC_TYPE_CTRL:
46                 if (len < 10)
47                         return;
48                 wt->rx_ctrl++;
49                 break;
50         case WLAN_FC_TYPE_DATA:
51                 rx_data(wt, data, len);
52                 break;
53         default:
54                 wpa_printf(MSG_DEBUG, "Drop RX frame with unexpected type %d",
55                            WLAN_FC_GET_TYPE(fc));
56                 break;
57         }
58 }
59
60
61 static void tx_status(struct wlantest *wt, const u8 *data, size_t len, int ack)
62 {
63         wpa_printf(MSG_DEBUG, "TX status: ack=%d", ack);
64         wpa_hexdump(MSG_EXCESSIVE, "TX status frame", data, len);
65 }
66
67
68 static int check_fcs(const u8 *frame, size_t frame_len, const u8 *fcs)
69 {
70         if (WPA_GET_LE32(fcs) != crc32(frame, frame_len))
71                 return -1;
72         return 0;
73 }
74
75
76 void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
77 {
78         struct ieee80211_radiotap_iterator iter;
79         int ret;
80         int rxflags = 0, txflags = 0, failed = 0, fcs = 0;
81         const u8 *frame, *fcspos;
82         size_t frame_len;
83
84         wpa_hexdump(MSG_EXCESSIVE, "Process data", data, len);
85
86         if (ieee80211_radiotap_iterator_init(&iter, (void *) data, len)) {
87                 wpa_printf(MSG_INFO, "Invalid radiotap frame");
88                 return;
89         }
90
91         for (;;) {
92                 ret = ieee80211_radiotap_iterator_next(&iter);
93                 wpa_printf(MSG_EXCESSIVE, "radiotap iter: %d "
94                            "this_arg_index=%d", ret, iter.this_arg_index);
95                 if (ret == -ENOENT)
96                         break;
97                 if (ret) {
98                         wpa_printf(MSG_INFO, "Invalid radiotap header: %d",
99                                    ret);
100                         return;
101                 }
102                 switch (iter.this_arg_index) {
103                 case IEEE80211_RADIOTAP_FLAGS:
104                         if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
105                                 fcs = 1;
106                         break;
107                 case IEEE80211_RADIOTAP_RX_FLAGS:
108                         rxflags = 1;
109                         break;
110                 case IEEE80211_RADIOTAP_TX_FLAGS:
111                         txflags = 1;
112                         failed = le_to_host16((*(u16 *) iter.this_arg)) &
113                                 IEEE80211_RADIOTAP_F_TX_FAIL;
114                         break;
115
116                 }
117         }
118
119         frame = data + iter.max_length;
120         frame_len = len - iter.max_length;
121
122         if (fcs && frame_len >= 4) {
123                 frame_len -= 4;
124                 fcspos = frame + frame_len;
125                 if (check_fcs(frame, frame_len, fcspos) < 0) {
126                         wpa_printf(MSG_EXCESSIVE, "Drop RX frame with invalid "
127                                    "FCS");
128                         wt->fcs_error++;
129                         return;
130                 }
131         }
132
133         if (rxflags && txflags)
134                 return;
135         if (!txflags)
136                 rx_frame(wt, frame, frame_len);
137         else
138                 tx_status(wt, frame, frame_len, !failed);
139 }