]> git.ipfire.org Git - thirdparty/hostap.git/blob - wlantest/process.c
wlantest: Create station list for each BSS
[thirdparty/hostap.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 }