wlantest: Create station list for each BSS
[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 bss_update(struct wlantest_bss *bss,
58                        struct ieee802_11_elems *elems)
59 {
60         if (elems->ssid == NULL || elems->ssid_len > 32) {
61                 wpa_printf(MSG_INFO, "Invalid or missing SSID in a Beacon "
62                            "frame for " MACSTR, MAC2STR(bss->bssid));
63                 bss->parse_error_reported = 1;
64                 return;
65         }
66
67         os_memcpy(bss->ssid, elems->ssid, elems->ssid_len);
68         bss->ssid_len = elems->ssid_len;
69
70         if (elems->rsn_ie == NULL) {
71                 if (bss->rsnie[0]) {
72                         wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE removed",
73                                    MAC2STR(bss->bssid));
74                         bss->rsnie[0] = 0;
75                 }
76         } else {
77                 if (bss->rsnie[0] == 0 ||
78                     os_memcmp(bss->rsnie, elems->rsn_ie - 2,
79                               elems->rsn_ie_len + 2) != 0) {
80                         wpa_printf(MSG_INFO, "BSS " MACSTR " - RSN IE "
81                                    "stored", MAC2STR(bss->bssid));
82                         wpa_hexdump(MSG_DEBUG, "RSN IE", elems->rsn_ie - 2,
83                                     elems->rsn_ie_len + 2);
84                 }
85                 os_memcpy(bss->rsnie, elems->rsn_ie - 2,
86                           elems->rsn_ie_len + 2);
87         }
88
89         if (elems->wpa_ie == NULL) {
90                 if (bss->wpaie[0]) {
91                         wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE removed",
92                                    MAC2STR(bss->bssid));
93                         bss->wpaie[0] = 0;
94                 }
95         } else {
96                 if (bss->wpaie[0] == 0 ||
97                     os_memcmp(bss->wpaie, elems->wpa_ie - 2,
98                               elems->wpa_ie_len + 2) != 0) {
99                         wpa_printf(MSG_INFO, "BSS " MACSTR " - WPA IE "
100                                    "stored", MAC2STR(bss->bssid));
101                         wpa_hexdump(MSG_DEBUG, "WPA IE", elems->wpa_ie - 2,
102                                     elems->wpa_ie_len + 2);
103                 }
104                 os_memcpy(bss->wpaie, elems->wpa_ie - 2,
105                           elems->wpa_ie_len + 2);
106         }
107 }
108
109
110 static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
111 {
112         const struct ieee80211_mgmt *mgmt;
113         struct wlantest_bss *bss;
114         struct ieee802_11_elems elems;
115
116         mgmt = (const struct ieee80211_mgmt *) data;
117         bss = bss_get(wt, mgmt->bssid);
118         if (bss == NULL)
119                 return;
120         if (bss->proberesp_seen)
121                 return; /* do not override with Beacon data */
122         bss->capab_info = le_to_host16(mgmt->u.beacon.capab_info);
123         if (ieee802_11_parse_elems(mgmt->u.beacon.variable,
124                                    len - (mgmt->u.beacon.variable - data),
125                                    &elems, 0) == ParseFailed) {
126                 if (bss->parse_error_reported)
127                         return;
128                 wpa_printf(MSG_INFO, "Invalid IEs in a Beacon frame from "
129                            MACSTR, MAC2STR(mgmt->sa));
130                 bss->parse_error_reported = 1;
131                 return;
132         }
133
134         bss_update(bss, &elems);
135 }
136
137
138 static void rx_mgmt_probe_resp(struct wlantest *wt, const u8 *data, size_t len)
139 {
140         const struct ieee80211_mgmt *mgmt;
141         struct wlantest_bss *bss;
142         struct ieee802_11_elems elems;
143
144         mgmt = (const struct ieee80211_mgmt *) data;
145         bss = bss_get(wt, mgmt->bssid);
146         if (bss == NULL)
147                 return;
148
149         bss->capab_info = le_to_host16(mgmt->u.probe_resp.capab_info);
150         if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
151                                    len - (mgmt->u.probe_resp.variable - data),
152                                    &elems, 0) == ParseFailed) {
153                 if (bss->parse_error_reported)
154                         return;
155                 wpa_printf(MSG_INFO, "Invalid IEs in a Probe Response frame "
156                            "from " MACSTR, MAC2STR(mgmt->sa));
157                 bss->parse_error_reported = 1;
158                 return;
159         }
160
161         bss_update(bss, &elems);
162 }
163
164
165 static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
166 {
167         const struct ieee80211_mgmt *mgmt;
168         struct wlantest_bss *bss;
169         struct wlantest_sta *sta;
170
171         mgmt = (const struct ieee80211_mgmt *) data;
172         bss = bss_get(wt, mgmt->bssid);
173         if (bss == NULL)
174                 return;
175         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
176                 sta = sta_get(bss, mgmt->da);
177         else
178                 sta = sta_get(bss, mgmt->sa);
179         if (sta == NULL)
180                 return;
181
182         if (len < 24 + 6) {
183                 wpa_printf(MSG_INFO, "Too short Authentication frame from "
184                            MACSTR, MAC2STR(mgmt->sa));
185                 return;
186         }
187
188         wpa_printf(MSG_DEBUG, "AUTH " MACSTR " -> " MACSTR
189                    " (alg=%u trans=%u status=%u)",
190                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
191                    le_to_host16(mgmt->u.auth.auth_alg),
192                    le_to_host16(mgmt->u.auth.auth_transaction),
193                    le_to_host16(mgmt->u.auth.status_code));
194 }
195
196
197 static void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
198 {
199         const struct ieee80211_hdr *hdr;
200         u16 fc, stype;
201
202         if (len < 24)
203                 return;
204
205         hdr = (const struct ieee80211_hdr *) data;
206         fc = le_to_host16(hdr->frame_control);
207         wt->rx_mgmt++;
208         stype = WLAN_FC_GET_STYPE(fc);
209
210         wpa_printf((stype == WLAN_FC_STYPE_BEACON ||
211                     stype == WLAN_FC_STYPE_PROBE_RESP ||
212                     stype == WLAN_FC_STYPE_PROBE_REQ) ?
213                    MSG_EXCESSIVE : MSG_MSGDUMP,
214                    "MGMT %s%s%s DA=" MACSTR " SA=" MACSTR " BSSID=" MACSTR,
215                    mgmt_stype(stype),
216                    fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
217                    fc & WLAN_FC_ISWEP ? " Prot" : "",
218                    MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
219                    MAC2STR(hdr->addr3));
220
221         switch (stype) {
222         case WLAN_FC_STYPE_BEACON:
223                 rx_mgmt_beacon(wt, data, len);
224                 break;
225         case WLAN_FC_STYPE_PROBE_RESP:
226                 rx_mgmt_probe_resp(wt, data, len);
227                 break;
228         case WLAN_FC_STYPE_AUTH:
229                 rx_mgmt_auth(wt, data, len);
230                 break;
231         }
232 }
233
234
235 static const char * data_stype(u16 stype)
236 {
237         switch (stype) {
238         case WLAN_FC_STYPE_DATA:
239                 return "DATA";
240         case WLAN_FC_STYPE_DATA_CFACK:
241                 return "DATA-CFACK";
242         case WLAN_FC_STYPE_DATA_CFPOLL:
243                 return "DATA-CFPOLL";
244         case WLAN_FC_STYPE_DATA_CFACKPOLL:
245                 return "DATA-CFACKPOLL";
246         case WLAN_FC_STYPE_NULLFUNC:
247                 return "NULLFUNC";
248         case WLAN_FC_STYPE_CFACK:
249                 return "CFACK";
250         case WLAN_FC_STYPE_CFPOLL:
251                 return "CFPOLL";
252         case WLAN_FC_STYPE_CFACKPOLL:
253                 return "CFACKPOLL";
254         case WLAN_FC_STYPE_QOS_DATA:
255                 return "QOSDATA";
256         case WLAN_FC_STYPE_QOS_DATA_CFACK:
257                 return "QOSDATA-CFACK";
258         case WLAN_FC_STYPE_QOS_DATA_CFPOLL:
259                 return "QOSDATA-CFPOLL";
260         case WLAN_FC_STYPE_QOS_DATA_CFACKPOLL:
261                 return "QOSDATA-CFACKPOLL";
262         case WLAN_FC_STYPE_QOS_NULL:
263                 return "QOS-NULL";
264         case WLAN_FC_STYPE_QOS_CFPOLL:
265                 return "QOS-CFPOLL";
266         case WLAN_FC_STYPE_QOS_CFACKPOLL:
267                 return "QOS-CFACKPOLL";
268         }
269         return "??";
270 }
271
272
273 static void rx_data(struct wlantest *wt, const u8 *data, size_t len)
274 {
275         const struct ieee80211_hdr *hdr;
276         u16 fc;
277
278         if (len < 24)
279                 return;
280
281         hdr = (const struct ieee80211_hdr *) data;
282         fc = le_to_host16(hdr->frame_control);
283         wt->rx_data++;
284
285         switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
286         case 0:
287                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s IBSS DA=" MACSTR " SA="
288                            MACSTR " BSSID=" MACSTR,
289                            data_stype(WLAN_FC_GET_STYPE(fc)),
290                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
291                            fc & WLAN_FC_ISWEP ? " Prot" : "",
292                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
293                            MAC2STR(hdr->addr3));
294                 break;
295         case WLAN_FC_FROMDS:
296                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s FromDS DA=" MACSTR
297                            " BSSID=" MACSTR " SA=" MACSTR,
298                            data_stype(WLAN_FC_GET_STYPE(fc)),
299                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
300                            fc & WLAN_FC_ISWEP ? " Prot" : "",
301                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
302                            MAC2STR(hdr->addr3));
303                 break;
304         case WLAN_FC_TODS:
305                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s ToDS BSSID=" MACSTR
306                            " SA=" MACSTR " DA=" MACSTR,
307                            data_stype(WLAN_FC_GET_STYPE(fc)),
308                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
309                            fc & WLAN_FC_ISWEP ? " Prot" : "",
310                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
311                            MAC2STR(hdr->addr3));
312                 break;
313         case WLAN_FC_TODS | WLAN_FC_FROMDS:
314                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s WDS RA=" MACSTR " TA="
315                            MACSTR " DA=" MACSTR " SA=" MACSTR,
316                            data_stype(WLAN_FC_GET_STYPE(fc)),
317                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
318                            fc & WLAN_FC_ISWEP ? " Prot" : "",
319                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
320                            MAC2STR(hdr->addr3),
321                            MAC2STR((const u8 *) (hdr + 1)));
322                 break;
323         }
324 }
325
326
327 static void rx_frame(struct wlantest *wt, const u8 *data, size_t len)
328 {
329         const struct ieee80211_hdr *hdr;
330         u16 fc;
331
332         wpa_hexdump(MSG_EXCESSIVE, "RX frame", data, len);
333         if (len < 2)
334                 return;
335
336         hdr = (const struct ieee80211_hdr *) data;
337         fc = le_to_host16(hdr->frame_control);
338         if (fc & WLAN_FC_PVER) {
339                 wpa_printf(MSG_DEBUG, "Drop RX frame with unexpected pver=%d",
340                            fc & WLAN_FC_PVER);
341                 return;
342         }
343
344         switch (WLAN_FC_GET_TYPE(fc)) {
345         case WLAN_FC_TYPE_MGMT:
346                 rx_mgmt(wt, data, len);
347                 break;
348         case WLAN_FC_TYPE_CTRL:
349                 if (len < 10)
350                         return;
351                 wt->rx_ctrl++;
352                 break;
353         case WLAN_FC_TYPE_DATA:
354                 rx_data(wt, data, len);
355                 break;
356         default:
357                 wpa_printf(MSG_DEBUG, "Drop RX frame with unexpected type %d",
358                            WLAN_FC_GET_TYPE(fc));
359                 break;
360         }
361 }
362
363
364 static void tx_status(struct wlantest *wt, const u8 *data, size_t len, int ack)
365 {
366         wpa_printf(MSG_DEBUG, "TX status: ack=%d", ack);
367         wpa_hexdump(MSG_EXCESSIVE, "TX status frame", data, len);
368 }
369
370
371 static int check_fcs(const u8 *frame, size_t frame_len, const u8 *fcs)
372 {
373         if (WPA_GET_LE32(fcs) != crc32(frame, frame_len))
374                 return -1;
375         return 0;
376 }
377
378
379 void wlantest_process(struct wlantest *wt, const u8 *data, size_t len)
380 {
381         struct ieee80211_radiotap_iterator iter;
382         int ret;
383         int rxflags = 0, txflags = 0, failed = 0, fcs = 0;
384         const u8 *frame, *fcspos;
385         size_t frame_len;
386
387         wpa_hexdump(MSG_EXCESSIVE, "Process data", data, len);
388
389         if (ieee80211_radiotap_iterator_init(&iter, (void *) data, len)) {
390                 wpa_printf(MSG_INFO, "Invalid radiotap frame");
391                 return;
392         }
393
394         for (;;) {
395                 ret = ieee80211_radiotap_iterator_next(&iter);
396                 wpa_printf(MSG_EXCESSIVE, "radiotap iter: %d "
397                            "this_arg_index=%d", ret, iter.this_arg_index);
398                 if (ret == -ENOENT)
399                         break;
400                 if (ret) {
401                         wpa_printf(MSG_INFO, "Invalid radiotap header: %d",
402                                    ret);
403                         return;
404                 }
405                 switch (iter.this_arg_index) {
406                 case IEEE80211_RADIOTAP_FLAGS:
407                         if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
408                                 fcs = 1;
409                         break;
410                 case IEEE80211_RADIOTAP_RX_FLAGS:
411                         rxflags = 1;
412                         break;
413                 case IEEE80211_RADIOTAP_TX_FLAGS:
414                         txflags = 1;
415                         failed = le_to_host16((*(u16 *) iter.this_arg)) &
416                                 IEEE80211_RADIOTAP_F_TX_FAIL;
417                         break;
418
419                 }
420         }
421
422         frame = data + iter.max_length;
423         frame_len = len - iter.max_length;
424
425         if (fcs && frame_len >= 4) {
426                 frame_len -= 4;
427                 fcspos = frame + frame_len;
428                 if (check_fcs(frame, frame_len, fcspos) < 0) {
429                         wpa_printf(MSG_EXCESSIVE, "Drop RX frame with invalid "
430                                    "FCS");
431                         wt->fcs_error++;
432                         return;
433                 }
434         }
435
436         if (rxflags && txflags)
437                 return;
438         if (!txflags)
439                 rx_frame(wt, frame, frame_len);
440         else
441                 tx_status(wt, frame, frame_len, !failed);
442 }