wlantest: Maintain a copy of WPA/RSN IE from (Re)AssocReq
[mech_eap.git] / wlantest / rx_mgmt.c
1 /*
2  * Received Management 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 "common/ieee802_11_defs.h"
19 #include "common/ieee802_11_common.h"
20 #include "wlantest.h"
21
22
23 static const char * mgmt_stype(u16 stype)
24 {
25         switch (stype) {
26         case WLAN_FC_STYPE_ASSOC_REQ:
27                 return "ASSOC-REQ";
28         case WLAN_FC_STYPE_ASSOC_RESP:
29                 return "ASSOC-RESP";
30         case WLAN_FC_STYPE_REASSOC_REQ:
31                 return "REASSOC-REQ";
32         case WLAN_FC_STYPE_REASSOC_RESP:
33                 return "REASSOC-RESP";
34         case WLAN_FC_STYPE_PROBE_REQ:
35                 return "PROBE-REQ";
36         case WLAN_FC_STYPE_PROBE_RESP:
37                 return "PROBE-RESP";
38         case WLAN_FC_STYPE_BEACON:
39                 return "BEACON";
40         case WLAN_FC_STYPE_ATIM:
41                 return "ATIM";
42         case WLAN_FC_STYPE_DISASSOC:
43                 return "DISASSOC";
44         case WLAN_FC_STYPE_AUTH:
45                 return "AUTH";
46         case WLAN_FC_STYPE_DEAUTH:
47                 return "DEAUTH";
48         case WLAN_FC_STYPE_ACTION:
49                 return "ACTION";
50         }
51         return "??";
52 }
53
54
55 static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
56 {
57         const struct ieee80211_mgmt *mgmt;
58         struct wlantest_bss *bss;
59         struct ieee802_11_elems elems;
60
61         mgmt = (const struct ieee80211_mgmt *) data;
62         bss = bss_get(wt, mgmt->bssid);
63         if (bss == NULL)
64                 return;
65         if (bss->proberesp_seen)
66                 return; /* do not override with Beacon data */
67         bss->capab_info = le_to_host16(mgmt->u.beacon.capab_info);
68         if (ieee802_11_parse_elems(mgmt->u.beacon.variable,
69                                    len - (mgmt->u.beacon.variable - data),
70                                    &elems, 0) == ParseFailed) {
71                 if (bss->parse_error_reported)
72                         return;
73                 wpa_printf(MSG_INFO, "Invalid IEs in a Beacon frame from "
74                            MACSTR, MAC2STR(mgmt->sa));
75                 bss->parse_error_reported = 1;
76                 return;
77         }
78
79         bss_update(bss, &elems);
80 }
81
82
83 static void rx_mgmt_probe_resp(struct wlantest *wt, const u8 *data, size_t len)
84 {
85         const struct ieee80211_mgmt *mgmt;
86         struct wlantest_bss *bss;
87         struct ieee802_11_elems elems;
88
89         mgmt = (const struct ieee80211_mgmt *) data;
90         bss = bss_get(wt, mgmt->bssid);
91         if (bss == NULL)
92                 return;
93
94         bss->capab_info = le_to_host16(mgmt->u.probe_resp.capab_info);
95         if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
96                                    len - (mgmt->u.probe_resp.variable - data),
97                                    &elems, 0) == ParseFailed) {
98                 if (bss->parse_error_reported)
99                         return;
100                 wpa_printf(MSG_INFO, "Invalid IEs in a Probe Response frame "
101                            "from " MACSTR, MAC2STR(mgmt->sa));
102                 bss->parse_error_reported = 1;
103                 return;
104         }
105
106         bss_update(bss, &elems);
107 }
108
109
110 static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
111 {
112         const struct ieee80211_mgmt *mgmt;
113         struct wlantest_bss *bss;
114         struct wlantest_sta *sta;
115         u16 alg, trans, status;
116
117         mgmt = (const struct ieee80211_mgmt *) data;
118         bss = bss_get(wt, mgmt->bssid);
119         if (bss == NULL)
120                 return;
121         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
122                 sta = sta_get(bss, mgmt->da);
123         else
124                 sta = sta_get(bss, mgmt->sa);
125         if (sta == NULL)
126                 return;
127
128         if (len < 24 + 6) {
129                 wpa_printf(MSG_INFO, "Too short Authentication frame from "
130                            MACSTR, MAC2STR(mgmt->sa));
131                 return;
132         }
133
134         alg = le_to_host16(mgmt->u.auth.auth_alg);
135         trans = le_to_host16(mgmt->u.auth.auth_transaction);
136         status = le_to_host16(mgmt->u.auth.status_code);
137
138         wpa_printf(MSG_DEBUG, "AUTH " MACSTR " -> " MACSTR
139                    " (alg=%u trans=%u status=%u)",
140                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da), alg, trans, status);
141
142         if (alg == 0 && trans == 2 && status == 0) {
143                 if (sta->state == STATE1) {
144                         wpa_printf(MSG_DEBUG, "STA " MACSTR
145                                    " moved to State 2 with " MACSTR,
146                                    MAC2STR(sta->addr), MAC2STR(bss->bssid));
147                         sta->state = STATE2;
148                 }
149         }
150 }
151
152
153 static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len)
154 {
155         const struct ieee80211_mgmt *mgmt;
156         struct wlantest_bss *bss;
157         struct wlantest_sta *sta;
158
159         mgmt = (const struct ieee80211_mgmt *) data;
160         bss = bss_get(wt, mgmt->bssid);
161         if (bss == NULL)
162                 return;
163         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
164                 sta = sta_get(bss, mgmt->da);
165         else
166                 sta = sta_get(bss, mgmt->sa);
167         if (sta == NULL)
168                 return;
169
170         if (len < 24 + 2) {
171                 wpa_printf(MSG_INFO, "Too short Deauthentication frame from "
172                            MACSTR, MAC2STR(mgmt->sa));
173                 return;
174         }
175
176         wpa_printf(MSG_DEBUG, "DEAUTH " MACSTR " -> " MACSTR
177                    " (reason=%u)",
178                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
179                    le_to_host16(mgmt->u.deauth.reason_code));
180
181         if (sta->state != STATE1) {
182                 wpa_printf(MSG_DEBUG, "STA " MACSTR
183                            " moved to State 1 with " MACSTR,
184                            MAC2STR(sta->addr), MAC2STR(bss->bssid));
185                 sta->state = STATE1;
186         }
187 }
188
189
190 static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len)
191 {
192         const struct ieee80211_mgmt *mgmt;
193         struct wlantest_bss *bss;
194         struct wlantest_sta *sta;
195         struct ieee802_11_elems elems;
196
197         mgmt = (const struct ieee80211_mgmt *) data;
198         bss = bss_get(wt, mgmt->bssid);
199         if (bss == NULL)
200                 return;
201         sta = sta_get(bss, mgmt->sa);
202         if (sta == NULL)
203                 return;
204
205         if (len < 24 + 4) {
206                 wpa_printf(MSG_INFO, "Too short Association Request frame "
207                            "from " MACSTR, MAC2STR(mgmt->sa));
208                 return;
209         }
210
211         wpa_printf(MSG_DEBUG, "ASSOCREQ " MACSTR " -> " MACSTR
212                    " (capab=0x%x listen_int=%u)",
213                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
214                    le_to_host16(mgmt->u.assoc_req.capab_info),
215                    le_to_host16(mgmt->u.assoc_req.listen_interval));
216
217         if (ieee802_11_parse_elems(mgmt->u.assoc_req.variable,
218                                    len - (mgmt->u.assoc_req.variable - data),
219                                    &elems, 0) == ParseFailed) {
220                 wpa_printf(MSG_INFO, "Invalid IEs in Association Request "
221                            "frame from " MACSTR, MAC2STR(mgmt->sa));
222                 return;
223         }
224
225         sta_update_assoc(sta, &elems);
226 }
227
228
229 static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
230 {
231         const struct ieee80211_mgmt *mgmt;
232         struct wlantest_bss *bss;
233         struct wlantest_sta *sta;
234         u16 capab, status, aid;
235
236         mgmt = (const struct ieee80211_mgmt *) data;
237         bss = bss_get(wt, mgmt->bssid);
238         if (bss == NULL)
239                 return;
240         sta = sta_get(bss, mgmt->da);
241         if (sta == NULL)
242                 return;
243
244         if (len < 24 + 6) {
245                 wpa_printf(MSG_INFO, "Too short Association Response frame "
246                            "from " MACSTR, MAC2STR(mgmt->sa));
247                 return;
248         }
249
250         capab = le_to_host16(mgmt->u.assoc_resp.capab_info);
251         status = le_to_host16(mgmt->u.assoc_resp.status_code);
252         aid = le_to_host16(mgmt->u.assoc_resp.aid);
253
254         wpa_printf(MSG_DEBUG, "ASSOCRESP " MACSTR " -> " MACSTR
255                    " (capab=0x%x status=%u aid=%u)",
256                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
257                    aid & 0x3fff);
258
259         if (status)
260                 return;
261
262         if ((aid & 0xc000) != 0xc000) {
263                 wpa_printf(MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
264                            "in Association Response from " MACSTR,
265                            MAC2STR(mgmt->sa));
266         }
267         sta->aid = aid & 0xc000;
268
269         if (sta->state < STATE2) {
270                 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
271                            "getting associated", MAC2STR(sta->addr));
272         }
273
274         if (sta->state < STATE3) {
275                 wpa_printf(MSG_DEBUG, "STA " MACSTR
276                            " moved to State 3 with " MACSTR,
277                            MAC2STR(sta->addr), MAC2STR(bss->bssid));
278                 sta->state = STATE3;
279         }
280 }
281
282
283 static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data,
284                                 size_t len)
285 {
286         const struct ieee80211_mgmt *mgmt;
287         struct wlantest_bss *bss;
288         struct wlantest_sta *sta;
289         struct ieee802_11_elems elems;
290
291         mgmt = (const struct ieee80211_mgmt *) data;
292         bss = bss_get(wt, mgmt->bssid);
293         if (bss == NULL)
294                 return;
295         sta = sta_get(bss, mgmt->sa);
296         if (sta == NULL)
297                 return;
298
299         if (len < 24 + 4 + ETH_ALEN) {
300                 wpa_printf(MSG_INFO, "Too short Reassociation Request frame "
301                            "from " MACSTR, MAC2STR(mgmt->sa));
302                 return;
303         }
304
305         wpa_printf(MSG_DEBUG, "REASSOCREQ " MACSTR " -> " MACSTR
306                    " (capab=0x%x listen_int=%u current_ap=" MACSTR ")",
307                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
308                    le_to_host16(mgmt->u.reassoc_req.capab_info),
309                    le_to_host16(mgmt->u.reassoc_req.listen_interval),
310                    MAC2STR(mgmt->u.reassoc_req.current_ap));
311
312         if (ieee802_11_parse_elems(mgmt->u.reassoc_req.variable,
313                                    len - (mgmt->u.reassoc_req.variable - data),
314                                    &elems, 0) == ParseFailed) {
315                 wpa_printf(MSG_INFO, "Invalid IEs in Reassociation Request "
316                            "frame from " MACSTR, MAC2STR(mgmt->sa));
317                 return;
318         }
319
320         sta_update_assoc(sta, &elems);
321 }
322
323
324 static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
325                                  size_t len)
326 {
327         const struct ieee80211_mgmt *mgmt;
328         struct wlantest_bss *bss;
329         struct wlantest_sta *sta;
330         u16 capab, status, aid;
331
332         mgmt = (const struct ieee80211_mgmt *) data;
333         bss = bss_get(wt, mgmt->bssid);
334         if (bss == NULL)
335                 return;
336         sta = sta_get(bss, mgmt->da);
337         if (sta == NULL)
338                 return;
339
340         if (len < 24 + 6) {
341                 wpa_printf(MSG_INFO, "Too short Reassociation Response frame "
342                            "from " MACSTR, MAC2STR(mgmt->sa));
343                 return;
344         }
345
346         capab = le_to_host16(mgmt->u.reassoc_resp.capab_info);
347         status = le_to_host16(mgmt->u.reassoc_resp.status_code);
348         aid = le_to_host16(mgmt->u.reassoc_resp.aid);
349
350         wpa_printf(MSG_DEBUG, "REASSOCRESP " MACSTR " -> " MACSTR
351                    " (capab=0x%x status=%u aid=%u)",
352                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
353                    aid & 0x3fff);
354
355         if (status)
356                 return;
357
358         if ((aid & 0xc000) != 0xc000) {
359                 wpa_printf(MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
360                            "in Reassociation Response from " MACSTR,
361                            MAC2STR(mgmt->sa));
362         }
363         sta->aid = aid & 0xc000;
364
365         if (sta->state < STATE2) {
366                 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
367                            "getting associated", MAC2STR(sta->addr));
368         }
369
370         if (sta->state < STATE3) {
371                 wpa_printf(MSG_DEBUG, "STA " MACSTR
372                            " moved to State 3 with " MACSTR,
373                            MAC2STR(sta->addr), MAC2STR(bss->bssid));
374                 sta->state = STATE3;
375         }
376 }
377
378
379 static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len)
380 {
381         const struct ieee80211_mgmt *mgmt;
382         struct wlantest_bss *bss;
383         struct wlantest_sta *sta;
384
385         mgmt = (const struct ieee80211_mgmt *) data;
386         bss = bss_get(wt, mgmt->bssid);
387         if (bss == NULL)
388                 return;
389         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
390                 sta = sta_get(bss, mgmt->da);
391         else
392                 sta = sta_get(bss, mgmt->sa);
393         if (sta == NULL)
394                 return;
395
396         if (len < 24 + 2) {
397                 wpa_printf(MSG_INFO, "Too short Disassociation frame from "
398                            MACSTR, MAC2STR(mgmt->sa));
399                 return;
400         }
401
402         wpa_printf(MSG_DEBUG, "DISASSOC " MACSTR " -> " MACSTR
403                    " (reason=%u)",
404                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
405                    le_to_host16(mgmt->u.disassoc.reason_code));
406
407         if (sta->state < STATE2) {
408                 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 or 3 "
409                            "when getting disassociated", MAC2STR(sta->addr));
410         }
411
412         if (sta->state > STATE2) {
413                 wpa_printf(MSG_DEBUG, "STA " MACSTR
414                            " moved to State 2 with " MACSTR,
415                            MAC2STR(sta->addr), MAC2STR(bss->bssid));
416                 sta->state = STATE2;
417         }
418 }
419
420
421 void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
422 {
423         const struct ieee80211_hdr *hdr;
424         u16 fc, stype;
425
426         if (len < 24)
427                 return;
428
429         hdr = (const struct ieee80211_hdr *) data;
430         fc = le_to_host16(hdr->frame_control);
431         wt->rx_mgmt++;
432         stype = WLAN_FC_GET_STYPE(fc);
433
434         wpa_printf((stype == WLAN_FC_STYPE_BEACON ||
435                     stype == WLAN_FC_STYPE_PROBE_RESP ||
436                     stype == WLAN_FC_STYPE_PROBE_REQ) ?
437                    MSG_EXCESSIVE : MSG_MSGDUMP,
438                    "MGMT %s%s%s DA=" MACSTR " SA=" MACSTR " BSSID=" MACSTR,
439                    mgmt_stype(stype),
440                    fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
441                    fc & WLAN_FC_ISWEP ? " Prot" : "",
442                    MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
443                    MAC2STR(hdr->addr3));
444
445         switch (stype) {
446         case WLAN_FC_STYPE_BEACON:
447                 rx_mgmt_beacon(wt, data, len);
448                 break;
449         case WLAN_FC_STYPE_PROBE_RESP:
450                 rx_mgmt_probe_resp(wt, data, len);
451                 break;
452         case WLAN_FC_STYPE_AUTH:
453                 rx_mgmt_auth(wt, data, len);
454                 break;
455         case WLAN_FC_STYPE_DEAUTH:
456                 rx_mgmt_deauth(wt, data, len);
457                 break;
458         case WLAN_FC_STYPE_ASSOC_REQ:
459                 rx_mgmt_assoc_req(wt, data, len);
460                 break;
461         case WLAN_FC_STYPE_ASSOC_RESP:
462                 rx_mgmt_assoc_resp(wt, data, len);
463                 break;
464         case WLAN_FC_STYPE_REASSOC_REQ:
465                 rx_mgmt_reassoc_req(wt, data, len);
466                 break;
467         case WLAN_FC_STYPE_REASSOC_RESP:
468                 rx_mgmt_reassoc_resp(wt, data, len);
469                 break;
470         case WLAN_FC_STYPE_DISASSOC:
471                 rx_mgmt_disassoc(wt, data, len);
472                 break;
473         }
474 }