wlantest: Add counters for AP deauth/disassoc while asleep/awake
[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 "crypto/aes_wrap.h"
21 #include "wlantest.h"
22
23
24 static const char * mgmt_stype(u16 stype)
25 {
26         switch (stype) {
27         case WLAN_FC_STYPE_ASSOC_REQ:
28                 return "ASSOC-REQ";
29         case WLAN_FC_STYPE_ASSOC_RESP:
30                 return "ASSOC-RESP";
31         case WLAN_FC_STYPE_REASSOC_REQ:
32                 return "REASSOC-REQ";
33         case WLAN_FC_STYPE_REASSOC_RESP:
34                 return "REASSOC-RESP";
35         case WLAN_FC_STYPE_PROBE_REQ:
36                 return "PROBE-REQ";
37         case WLAN_FC_STYPE_PROBE_RESP:
38                 return "PROBE-RESP";
39         case WLAN_FC_STYPE_BEACON:
40                 return "BEACON";
41         case WLAN_FC_STYPE_ATIM:
42                 return "ATIM";
43         case WLAN_FC_STYPE_DISASSOC:
44                 return "DISASSOC";
45         case WLAN_FC_STYPE_AUTH:
46                 return "AUTH";
47         case WLAN_FC_STYPE_DEAUTH:
48                 return "DEAUTH";
49         case WLAN_FC_STYPE_ACTION:
50                 return "ACTION";
51         }
52         return "??";
53 }
54
55
56 static void rx_mgmt_beacon(struct wlantest *wt, const u8 *data, size_t len)
57 {
58         const struct ieee80211_mgmt *mgmt;
59         struct wlantest_bss *bss;
60         struct ieee802_11_elems elems;
61
62         mgmt = (const struct ieee80211_mgmt *) data;
63         bss = bss_get(wt, mgmt->bssid);
64         if (bss == NULL)
65                 return;
66         if (bss->proberesp_seen)
67                 return; /* do not override with Beacon data */
68         bss->capab_info = le_to_host16(mgmt->u.beacon.capab_info);
69         if (ieee802_11_parse_elems(mgmt->u.beacon.variable,
70                                    len - (mgmt->u.beacon.variable - data),
71                                    &elems, 0) == ParseFailed) {
72                 if (bss->parse_error_reported)
73                         return;
74                 wpa_printf(MSG_INFO, "Invalid IEs in a Beacon frame from "
75                            MACSTR, MAC2STR(mgmt->sa));
76                 bss->parse_error_reported = 1;
77                 return;
78         }
79
80         bss_update(wt, bss, &elems);
81 }
82
83
84 static void rx_mgmt_probe_resp(struct wlantest *wt, const u8 *data, size_t len)
85 {
86         const struct ieee80211_mgmt *mgmt;
87         struct wlantest_bss *bss;
88         struct ieee802_11_elems elems;
89
90         mgmt = (const struct ieee80211_mgmt *) data;
91         bss = bss_get(wt, mgmt->bssid);
92         if (bss == NULL)
93                 return;
94
95         bss->capab_info = le_to_host16(mgmt->u.probe_resp.capab_info);
96         if (ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
97                                    len - (mgmt->u.probe_resp.variable - data),
98                                    &elems, 0) == ParseFailed) {
99                 if (bss->parse_error_reported)
100                         return;
101                 wpa_printf(MSG_INFO, "Invalid IEs in a Probe Response frame "
102                            "from " MACSTR, MAC2STR(mgmt->sa));
103                 bss->parse_error_reported = 1;
104                 return;
105         }
106
107         bss_update(wt, bss, &elems);
108 }
109
110
111 static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
112 {
113         const struct ieee80211_mgmt *mgmt;
114         struct wlantest_bss *bss;
115         struct wlantest_sta *sta;
116         u16 alg, trans, status;
117
118         mgmt = (const struct ieee80211_mgmt *) data;
119         bss = bss_get(wt, mgmt->bssid);
120         if (bss == NULL)
121                 return;
122         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
123                 sta = sta_get(bss, mgmt->da);
124         else
125                 sta = sta_get(bss, mgmt->sa);
126         if (sta == NULL)
127                 return;
128
129         if (len < 24 + 6) {
130                 wpa_printf(MSG_INFO, "Too short Authentication frame from "
131                            MACSTR, MAC2STR(mgmt->sa));
132                 return;
133         }
134
135         alg = le_to_host16(mgmt->u.auth.auth_alg);
136         trans = le_to_host16(mgmt->u.auth.auth_transaction);
137         status = le_to_host16(mgmt->u.auth.status_code);
138
139         wpa_printf(MSG_DEBUG, "AUTH " MACSTR " -> " MACSTR
140                    " (alg=%u trans=%u status=%u)",
141                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da), alg, trans, status);
142
143         if (alg == 0 && trans == 2 && status == 0) {
144                 if (sta->state == STATE1) {
145                         wpa_printf(MSG_DEBUG, "STA " MACSTR
146                                    " moved to State 2 with " MACSTR,
147                                    MAC2STR(sta->addr), MAC2STR(bss->bssid));
148                         sta->state = STATE2;
149                 }
150         }
151
152         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
153                 sta->counters[WLANTEST_STA_COUNTER_AUTH_RX]++;
154         else
155                 sta->counters[WLANTEST_STA_COUNTER_AUTH_TX]++;
156 }
157
158
159 static void deauth_all_stas(struct wlantest_bss *bss)
160 {
161         struct wlantest_sta *sta;
162         dl_list_for_each(sta, &bss->sta, struct wlantest_sta, list) {
163                 if (sta->state == STATE1)
164                         continue;
165                 wpa_printf(MSG_DEBUG, "STA " MACSTR
166                            " moved to State 1 with " MACSTR,
167                            MAC2STR(sta->addr), MAC2STR(bss->bssid));
168                 sta->state = STATE1;
169         }
170 }
171
172
173 static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len,
174                            int valid)
175 {
176         const struct ieee80211_mgmt *mgmt;
177         struct wlantest_bss *bss;
178         struct wlantest_sta *sta;
179
180         mgmt = (const struct ieee80211_mgmt *) data;
181         bss = bss_get(wt, mgmt->bssid);
182         if (bss == NULL)
183                 return;
184         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
185                 sta = sta_get(bss, mgmt->da);
186         else
187                 sta = sta_get(bss, mgmt->sa);
188
189         if (len < 24 + 2) {
190                 wpa_printf(MSG_INFO, "Too short Deauthentication frame from "
191                            MACSTR, MAC2STR(mgmt->sa));
192                 return;
193         }
194
195         wpa_printf(MSG_DEBUG, "DEAUTH " MACSTR " -> " MACSTR
196                    " (reason=%u) (valid=%d)",
197                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
198                    le_to_host16(mgmt->u.deauth.reason_code), valid);
199         wpa_hexdump(MSG_MSGDUMP, "DEAUTH payload", data + 24, len - 24);
200
201         if (sta == NULL) {
202                 if (valid && mgmt->da[0] == 0xff)
203                         deauth_all_stas(bss);
204                 return;
205         }
206
207         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
208                 sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DEAUTH_RX :
209                               WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX]++;
210                 if (sta->pwrmgt && !sta->pspoll)
211                         sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_ASLEEP]++;
212                 else
213                         sta->counters[WLANTEST_STA_COUNTER_DEAUTH_RX_AWAKE]++;
214         } else
215                 sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DEAUTH_TX :
216                               WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX]++;
217
218         if (!valid) {
219                 wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State "
220                            "since Disassociation frame was not protected "
221                            "correctly", MAC2STR(sta->addr));
222                 return;
223         }
224
225         if (sta->state != STATE1) {
226                 wpa_printf(MSG_DEBUG, "STA " MACSTR
227                            " moved to State 1 with " MACSTR,
228                            MAC2STR(sta->addr), MAC2STR(bss->bssid));
229                 sta->state = STATE1;
230         }
231 }
232
233
234 static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len)
235 {
236         const struct ieee80211_mgmt *mgmt;
237         struct wlantest_bss *bss;
238         struct wlantest_sta *sta;
239         struct ieee802_11_elems elems;
240
241         mgmt = (const struct ieee80211_mgmt *) data;
242         bss = bss_get(wt, mgmt->bssid);
243         if (bss == NULL)
244                 return;
245         sta = sta_get(bss, mgmt->sa);
246         if (sta == NULL)
247                 return;
248
249         if (len < 24 + 4) {
250                 wpa_printf(MSG_INFO, "Too short Association Request frame "
251                            "from " MACSTR, MAC2STR(mgmt->sa));
252                 return;
253         }
254
255         wpa_printf(MSG_DEBUG, "ASSOCREQ " MACSTR " -> " MACSTR
256                    " (capab=0x%x listen_int=%u)",
257                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
258                    le_to_host16(mgmt->u.assoc_req.capab_info),
259                    le_to_host16(mgmt->u.assoc_req.listen_interval));
260
261         sta->counters[WLANTEST_STA_COUNTER_ASSOCREQ_TX]++;
262
263         if (ieee802_11_parse_elems(mgmt->u.assoc_req.variable,
264                                    len - (mgmt->u.assoc_req.variable - data),
265                                    &elems, 0) == ParseFailed) {
266                 wpa_printf(MSG_INFO, "Invalid IEs in Association Request "
267                            "frame from " MACSTR, MAC2STR(mgmt->sa));
268                 return;
269         }
270
271         sta->assocreq_capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
272         sta->assocreq_listen_int =
273                 le_to_host16(mgmt->u.assoc_req.listen_interval);
274         os_free(sta->assocreq_ies);
275         sta->assocreq_ies_len = len - (mgmt->u.assoc_req.variable - data);
276         sta->assocreq_ies = os_malloc(sta->assocreq_ies_len);
277         if (sta->assocreq_ies)
278                 os_memcpy(sta->assocreq_ies, mgmt->u.assoc_req.variable,
279                           sta->assocreq_ies_len);
280
281         sta_update_assoc(sta, &elems);
282 }
283
284
285 static void rx_mgmt_assoc_resp(struct wlantest *wt, const u8 *data, size_t len)
286 {
287         const struct ieee80211_mgmt *mgmt;
288         struct wlantest_bss *bss;
289         struct wlantest_sta *sta;
290         u16 capab, status, aid;
291
292         mgmt = (const struct ieee80211_mgmt *) data;
293         bss = bss_get(wt, mgmt->bssid);
294         if (bss == NULL)
295                 return;
296         sta = sta_get(bss, mgmt->da);
297         if (sta == NULL)
298                 return;
299
300         if (len < 24 + 6) {
301                 wpa_printf(MSG_INFO, "Too short Association Response frame "
302                            "from " MACSTR, MAC2STR(mgmt->sa));
303                 return;
304         }
305
306         capab = le_to_host16(mgmt->u.assoc_resp.capab_info);
307         status = le_to_host16(mgmt->u.assoc_resp.status_code);
308         aid = le_to_host16(mgmt->u.assoc_resp.aid);
309
310         wpa_printf(MSG_DEBUG, "ASSOCRESP " MACSTR " -> " MACSTR
311                    " (capab=0x%x status=%u aid=%u)",
312                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
313                    aid & 0x3fff);
314
315         if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
316                 struct ieee802_11_elems elems;
317                 const u8 *ies = mgmt->u.assoc_resp.variable;
318                 size_t ies_len = len - (mgmt->u.assoc_resp.variable - data);
319                 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
320                     ParseFailed) {
321                         wpa_printf(MSG_INFO, "Failed to parse IEs in "
322                                    "AssocResp from " MACSTR,
323                                    MAC2STR(mgmt->sa));
324                 } else if (elems.timeout_int == 0 ||
325                            elems.timeout_int_len != 5) {
326                         wpa_printf(MSG_INFO, "No valid Timeout Interval IE in "
327                                    "AssocResp (status=30) from " MACSTR,
328                                    MAC2STR(mgmt->sa));
329                 } else {
330                         sta->counters[
331                                 WLANTEST_STA_COUNTER_ASSOCRESP_COMEBACK]++;
332                 }
333         }
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 Association 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_reassoc_req(struct wlantest *wt, const u8 *data,
360                                 size_t len)
361 {
362         const struct ieee80211_mgmt *mgmt;
363         struct wlantest_bss *bss;
364         struct wlantest_sta *sta;
365         struct ieee802_11_elems elems;
366
367         mgmt = (const struct ieee80211_mgmt *) data;
368         bss = bss_get(wt, mgmt->bssid);
369         if (bss == NULL)
370                 return;
371         sta = sta_get(bss, mgmt->sa);
372         if (sta == NULL)
373                 return;
374
375         if (len < 24 + 4 + ETH_ALEN) {
376                 wpa_printf(MSG_INFO, "Too short Reassociation Request frame "
377                            "from " MACSTR, MAC2STR(mgmt->sa));
378                 return;
379         }
380
381         wpa_printf(MSG_DEBUG, "REASSOCREQ " MACSTR " -> " MACSTR
382                    " (capab=0x%x listen_int=%u current_ap=" MACSTR ")",
383                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
384                    le_to_host16(mgmt->u.reassoc_req.capab_info),
385                    le_to_host16(mgmt->u.reassoc_req.listen_interval),
386                    MAC2STR(mgmt->u.reassoc_req.current_ap));
387
388         sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX]++;
389
390         if (ieee802_11_parse_elems(mgmt->u.reassoc_req.variable,
391                                    len - (mgmt->u.reassoc_req.variable - data),
392                                    &elems, 0) == ParseFailed) {
393                 wpa_printf(MSG_INFO, "Invalid IEs in Reassociation Request "
394                            "frame from " MACSTR, MAC2STR(mgmt->sa));
395                 return;
396         }
397
398         sta->assocreq_capab_info =
399                 le_to_host16(mgmt->u.reassoc_req.capab_info);
400         sta->assocreq_listen_int =
401                 le_to_host16(mgmt->u.reassoc_req.listen_interval);
402         os_free(sta->assocreq_ies);
403         sta->assocreq_ies_len = len - (mgmt->u.reassoc_req.variable - data);
404         sta->assocreq_ies = os_malloc(sta->assocreq_ies_len);
405         if (sta->assocreq_ies)
406                 os_memcpy(sta->assocreq_ies, mgmt->u.reassoc_req.variable,
407                           sta->assocreq_ies_len);
408
409         sta_update_assoc(sta, &elems);
410 }
411
412
413 static void rx_mgmt_reassoc_resp(struct wlantest *wt, const u8 *data,
414                                  size_t len)
415 {
416         const struct ieee80211_mgmt *mgmt;
417         struct wlantest_bss *bss;
418         struct wlantest_sta *sta;
419         u16 capab, status, aid;
420
421         mgmt = (const struct ieee80211_mgmt *) data;
422         bss = bss_get(wt, mgmt->bssid);
423         if (bss == NULL)
424                 return;
425         sta = sta_get(bss, mgmt->da);
426         if (sta == NULL)
427                 return;
428
429         if (len < 24 + 6) {
430                 wpa_printf(MSG_INFO, "Too short Reassociation Response frame "
431                            "from " MACSTR, MAC2STR(mgmt->sa));
432                 return;
433         }
434
435         capab = le_to_host16(mgmt->u.reassoc_resp.capab_info);
436         status = le_to_host16(mgmt->u.reassoc_resp.status_code);
437         aid = le_to_host16(mgmt->u.reassoc_resp.aid);
438
439         wpa_printf(MSG_DEBUG, "REASSOCRESP " MACSTR " -> " MACSTR
440                    " (capab=0x%x status=%u aid=%u)",
441                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da), capab, status,
442                    aid & 0x3fff);
443
444         if (status == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) {
445                 struct ieee802_11_elems elems;
446                 const u8 *ies = mgmt->u.reassoc_resp.variable;
447                 size_t ies_len = len - (mgmt->u.reassoc_resp.variable - data);
448                 if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
449                     ParseFailed) {
450                         wpa_printf(MSG_INFO, "Failed to parse IEs in "
451                                    "ReassocResp from " MACSTR,
452                                    MAC2STR(mgmt->sa));
453                 } else if (elems.timeout_int == 0 ||
454                            elems.timeout_int_len != 5) {
455                         wpa_printf(MSG_INFO, "No valid Timeout Interval IE in "
456                                    "ReassocResp (status=30) from " MACSTR,
457                                    MAC2STR(mgmt->sa));
458                 } else {
459                         sta->counters[
460                                 WLANTEST_STA_COUNTER_REASSOCRESP_COMEBACK]++;
461                 }
462         }
463
464         if (status)
465                 return;
466
467         if ((aid & 0xc000) != 0xc000) {
468                 wpa_printf(MSG_DEBUG, "Two MSBs of the AID were not set to 1 "
469                            "in Reassociation Response from " MACSTR,
470                            MAC2STR(mgmt->sa));
471         }
472         sta->aid = aid & 0xc000;
473
474         if (sta->state < STATE2) {
475                 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 when "
476                            "getting associated", MAC2STR(sta->addr));
477         }
478
479         if (sta->state < STATE3) {
480                 wpa_printf(MSG_DEBUG, "STA " MACSTR
481                            " moved to State 3 with " MACSTR,
482                            MAC2STR(sta->addr), MAC2STR(bss->bssid));
483                 sta->state = STATE3;
484         }
485 }
486
487
488 static void disassoc_all_stas(struct wlantest_bss *bss)
489 {
490         struct wlantest_sta *sta;
491         dl_list_for_each(sta, &bss->sta, struct wlantest_sta, list) {
492                 if (sta->state <= STATE2)
493                         continue;
494                 wpa_printf(MSG_DEBUG, "STA " MACSTR
495                            " moved to State 2 with " MACSTR,
496                            MAC2STR(sta->addr), MAC2STR(bss->bssid));
497                 sta->state = STATE2;
498         }
499 }
500
501
502 static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len,
503                              int valid)
504 {
505         const struct ieee80211_mgmt *mgmt;
506         struct wlantest_bss *bss;
507         struct wlantest_sta *sta;
508
509         mgmt = (const struct ieee80211_mgmt *) data;
510         bss = bss_get(wt, mgmt->bssid);
511         if (bss == NULL)
512                 return;
513         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
514                 sta = sta_get(bss, mgmt->da);
515         else
516                 sta = sta_get(bss, mgmt->sa);
517
518         if (len < 24 + 2) {
519                 wpa_printf(MSG_INFO, "Too short Disassociation frame from "
520                            MACSTR, MAC2STR(mgmt->sa));
521                 return;
522         }
523
524         wpa_printf(MSG_DEBUG, "DISASSOC " MACSTR " -> " MACSTR
525                    " (reason=%u) (valid=%d)",
526                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
527                    le_to_host16(mgmt->u.disassoc.reason_code), valid);
528         wpa_hexdump(MSG_MSGDUMP, "DISASSOC payload", data + 24, len - 24);
529
530         if (sta == NULL) {
531                 if (valid && mgmt->da[0] == 0xff)
532                         disassoc_all_stas(bss);
533                 return;
534         }
535
536         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
537                 sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DISASSOC_RX :
538                               WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX]++;
539                 if (sta->pwrmgt && !sta->pspoll)
540                         sta->counters[
541                                 WLANTEST_STA_COUNTER_DISASSOC_RX_ASLEEP]++;
542                 else
543                         sta->counters[
544                                 WLANTEST_STA_COUNTER_DISASSOC_RX_AWAKE]++;
545         } else
546                 sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DISASSOC_TX :
547                               WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX]++;
548
549         if (!valid) {
550                 wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State "
551                            "since Disassociation frame was not protected "
552                            "correctly", MAC2STR(sta->addr));
553                 return;
554         }
555
556         if (sta->state < STATE2) {
557                 wpa_printf(MSG_DEBUG, "STA " MACSTR " was not in State 2 or 3 "
558                            "when getting disassociated", MAC2STR(sta->addr));
559         }
560
561         if (sta->state > STATE2) {
562                 wpa_printf(MSG_DEBUG, "STA " MACSTR
563                            " moved to State 2 with " MACSTR,
564                            MAC2STR(sta->addr), MAC2STR(bss->bssid));
565                 sta->state = STATE2;
566         }
567 }
568
569
570 static void rx_mgmt_action_sa_query_req(struct wlantest *wt,
571                                         struct wlantest_sta *sta,
572                                         const struct ieee80211_mgmt *mgmt,
573                                         size_t len, int valid)
574 {
575         const u8 *rx_id;
576         u8 *id;
577
578         rx_id = (const u8 *) mgmt->u.action.u.sa_query_req.trans_id;
579         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
580                 id = sta->ap_sa_query_tr;
581         else
582                 id = sta->sta_sa_query_tr;
583         wpa_printf(MSG_INFO, "SA Query Request " MACSTR " -> " MACSTR
584                    " (trans_id=%02x%02x)%s",
585                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1],
586                    valid ? "" : " (invalid protection)");
587         os_memcpy(id, mgmt->u.action.u.sa_query_req.trans_id, 2);
588         if (os_memcmp(mgmt->sa, sta->addr, ETH_ALEN) == 0)
589                 sta->counters[valid ?
590                               WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX :
591                               WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX]++;
592         else
593                 sta->counters[valid ?
594                               WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX :
595                               WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX]++;
596 }
597
598
599 static void rx_mgmt_action_sa_query_resp(struct wlantest *wt,
600                                          struct wlantest_sta *sta,
601                                          const struct ieee80211_mgmt *mgmt,
602                                          size_t len, int valid)
603 {
604         const u8 *rx_id;
605         u8 *id;
606         int match;
607
608         rx_id = (const u8 *) mgmt->u.action.u.sa_query_resp.trans_id;
609         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
610                 id = sta->sta_sa_query_tr;
611         else
612                 id = sta->ap_sa_query_tr;
613         match = os_memcmp(rx_id, id, 2) == 0;
614         wpa_printf(MSG_INFO, "SA Query Response " MACSTR " -> " MACSTR
615                    " (trans_id=%02x%02x; %s)%s",
616                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1],
617                    match ? "match" : "mismatch",
618                    valid ? "" : " (invalid protection)");
619         if (os_memcmp(mgmt->sa, sta->addr, ETH_ALEN) == 0)
620                 sta->counters[(valid && match) ?
621                               WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX :
622                               WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX]++;
623         else
624                 sta->counters[(valid && match) ?
625                               WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX :
626                               WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX]++;
627 }
628
629
630 static void rx_mgmt_action_sa_query(struct wlantest *wt,
631                                     struct wlantest_sta *sta,
632                                     const struct ieee80211_mgmt *mgmt,
633                                     size_t len, int valid)
634 {
635         if (len < 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN) {
636                 wpa_printf(MSG_INFO, "Too short SA Query frame from " MACSTR,
637                            MAC2STR(mgmt->sa));
638                 return;
639         }
640
641         if (len > 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN) {
642                 size_t elen = len - (24 + 2 + WLAN_SA_QUERY_TR_ID_LEN);
643                 wpa_printf(MSG_INFO, "Unexpected %u octets of extra data at "
644                            "the end of SA Query frame from " MACSTR,
645                            (unsigned) elen, MAC2STR(mgmt->sa));
646                 wpa_hexdump(MSG_INFO, "SA Query extra data",
647                             ((const u8 *) mgmt) + len - elen, elen);
648         }
649
650         switch (mgmt->u.action.u.sa_query_req.action) {
651         case WLAN_SA_QUERY_REQUEST:
652                 rx_mgmt_action_sa_query_req(wt, sta, mgmt, len, valid);
653                 break;
654         case WLAN_SA_QUERY_RESPONSE:
655                 rx_mgmt_action_sa_query_resp(wt, sta, mgmt, len, valid);
656                 break;
657         default:
658                 wpa_printf(MSG_INFO, "Unexpected SA Query action value %u "
659                            "from " MACSTR,
660                            mgmt->u.action.u.sa_query_req.action,
661                            MAC2STR(mgmt->sa));
662         }
663 }
664
665
666 static void rx_mgmt_action(struct wlantest *wt, const u8 *data, size_t len,
667                            int valid)
668 {
669         const struct ieee80211_mgmt *mgmt;
670         struct wlantest_bss *bss;
671         struct wlantest_sta *sta;
672
673         mgmt = (const struct ieee80211_mgmt *) data;
674         if (mgmt->da[0] & 0x01) {
675                 wpa_printf(MSG_DEBUG, "Group addressed Action frame: DA="
676                            MACSTR " SA=" MACSTR " BSSID=" MACSTR
677                            " category=%u",
678                            MAC2STR(mgmt->da), MAC2STR(mgmt->sa),
679                            MAC2STR(mgmt->bssid), mgmt->u.action.category);
680                 return; /* Ignore group addressed Action frames for now */
681         }
682         bss = bss_get(wt, mgmt->bssid);
683         if (bss == NULL)
684                 return;
685         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
686                 sta = sta_get(bss, mgmt->da);
687         else
688                 sta = sta_get(bss, mgmt->sa);
689         if (sta == NULL)
690                 return;
691
692         if (len < 24 + 1) {
693                 wpa_printf(MSG_INFO, "Too short Action frame from "
694                            MACSTR, MAC2STR(mgmt->sa));
695                 return;
696         }
697
698         wpa_printf(MSG_DEBUG, "ACTION " MACSTR " -> " MACSTR
699                    " (category=%u) (valid=%d)",
700                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
701                    mgmt->u.action.category, valid);
702         wpa_hexdump(MSG_MSGDUMP, "ACTION payload", data + 24, len - 24);
703
704         if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
705             sta->state < STATE3) {
706                 wpa_printf(MSG_INFO, "Action frame sent when STA is not in "
707                            "State 3 (SA=" MACSTR " DATA=" MACSTR ")",
708                            MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
709         }
710
711         switch (mgmt->u.action.category) {
712         case WLAN_ACTION_SA_QUERY:
713                 rx_mgmt_action_sa_query(wt, sta, mgmt, len, valid);
714                 break;
715         }
716 }
717
718
719 static int check_mmie_mic(const u8 *igtk, const u8 *data, size_t len)
720 {
721         u8 *buf;
722         u8 mic[16];
723         u16 fc;
724         const struct ieee80211_hdr *hdr;
725
726         buf = os_malloc(len + 20 - 24);
727         if (buf == NULL)
728                 return -1;
729
730         /* BIP AAD: FC(masked) A1 A2 A3 */
731         hdr = (const struct ieee80211_hdr *) data;
732         fc = le_to_host16(hdr->frame_control);
733         fc &= ~(WLAN_FC_RETRY | WLAN_FC_PWRMGT | WLAN_FC_MOREDATA);
734         WPA_PUT_LE16(buf, fc);
735         os_memcpy(buf + 2, hdr->addr1, 3 * ETH_ALEN);
736
737         /* Frame body with MMIE MIC masked to zero */
738         os_memcpy(buf + 20, data + 24, len - 24 - 8);
739         os_memset(buf + 20 + len - 24 - 8, 0, 8);
740
741         wpa_hexdump(MSG_MSGDUMP, "BIP: AAD|Body(masked)", buf, len + 20 - 24);
742         /* MIC = L(AES-128-CMAC(AAD || Frame Body(masked)), 0, 64) */
743         if (omac1_aes_128(igtk, buf, len + 20 - 24, mic) < 0) {
744                 os_free(buf);
745                 return -1;
746         }
747
748         os_free(buf);
749
750         if (os_memcmp(data + len - 8, mic, 8) != 0)
751                 return -1;
752
753         return 0;
754 }
755
756
757 static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
758 {
759         const struct ieee80211_mgmt *mgmt;
760         u16 fc, stype;
761         const u8 *mmie;
762         u16 keyid;
763         struct wlantest_bss *bss;
764
765         mgmt = (const struct ieee80211_mgmt *) data;
766         fc = le_to_host16(mgmt->frame_control);
767         stype = WLAN_FC_GET_STYPE(fc);
768
769         if (stype == WLAN_FC_STYPE_ACTION) {
770                 if (len < 24 + 1)
771                         return 0;
772                 if (mgmt->u.action.category == WLAN_ACTION_PUBLIC)
773                         return 0; /* Not a robust management frame */
774         }
775
776         bss = bss_get(wt, mgmt->bssid);
777         if (bss == NULL)
778                 return 0; /* No key known yet */
779
780         if (len < 24 + 18 || data[len - 18] != WLAN_EID_MMIE ||
781             data[len - 17] != 16) {
782                 /* No MMIE */
783                 if (bss->rsn_capab & WPA_CAPABILITY_MFPC) {
784                         wpa_printf(MSG_INFO, "Robust group-addressed "
785                                    "management frame sent without BIP by "
786                                    MACSTR, MAC2STR(mgmt->sa));
787                         bss->counters[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE]++;
788                         return -1;
789                 }
790                 return 0;
791         }
792
793         mmie = data + len - 16;
794         keyid = WPA_GET_LE16(mmie);
795         if (keyid & 0xf000) {
796                 wpa_printf(MSG_INFO, "MMIE KeyID reserved bits not zero "
797                            "(%04x) from " MACSTR, keyid, MAC2STR(mgmt->sa));
798                 keyid &= 0x0fff;
799         }
800         if (keyid < 4 || keyid > 5) {
801                 wpa_printf(MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR,
802                            keyid, MAC2STR(mgmt->sa));
803                 bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
804                 return 0;
805         }
806         wpa_printf(MSG_DEBUG, "MMIE KeyID %u", keyid);
807         wpa_hexdump(MSG_MSGDUMP, "MMIE IPN", mmie + 2, 6);
808         wpa_hexdump(MSG_MSGDUMP, "MMIE MIC", mmie + 8, 8);
809
810         if (!bss->igtk_set[keyid]) {
811                 wpa_printf(MSG_DEBUG, "No IGTK known to validate BIP frame");
812                 return 0;
813         }
814
815         if (os_memcmp(mmie + 2, bss->ipn[keyid], 6) <= 0) {
816                 wpa_printf(MSG_INFO, "BIP replay detected: SA=" MACSTR,
817                            MAC2STR(mgmt->sa));
818                 wpa_hexdump(MSG_INFO, "RX IPN", mmie + 2, 6);
819                 wpa_hexdump(MSG_INFO, "Last RX IPN", bss->ipn[keyid], 6);
820         }
821
822         if (check_mmie_mic(bss->igtk[keyid], data, len) < 0) {
823                 wpa_printf(MSG_INFO, "Invalid MMIE MIC in a frame from "
824                            MACSTR, MAC2STR(mgmt->sa));
825                 bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
826                 return -1;
827         }
828
829         wpa_printf(MSG_DEBUG, "Valid MMIE MIC");
830         os_memcpy(bss->ipn[keyid], mmie + 2, 6);
831         bss->counters[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE]++;
832
833         if (stype == WLAN_FC_STYPE_DEAUTH)
834                 bss->counters[WLANTEST_BSS_COUNTER_BIP_DEAUTH]++;
835         else if (stype == WLAN_FC_STYPE_DISASSOC)
836                 bss->counters[WLANTEST_BSS_COUNTER_BIP_DISASSOC]++;
837
838         return 0;
839 }
840
841
842 static u8 * mgmt_ccmp_decrypt(struct wlantest *wt, const u8 *data, size_t len,
843                               size_t *dlen)
844 {
845         struct wlantest_bss *bss;
846         struct wlantest_sta *sta;
847         const struct ieee80211_hdr *hdr;
848         int keyid;
849         u8 *decrypted, *frame = NULL;
850         u8 pn[6], *rsc;
851
852         hdr = (const struct ieee80211_hdr *) data;
853         bss = bss_get(wt, hdr->addr3);
854         if (bss == NULL)
855                 return NULL;
856         if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
857                 sta = sta_get(bss, hdr->addr2);
858         else
859                 sta = sta_get(bss, hdr->addr1);
860         if (sta == NULL || !sta->ptk_set) {
861                 wpa_printf(MSG_MSGDUMP, "No PTK known to decrypt the frame");
862                 return NULL;
863         }
864
865         if (len < 24 + 4)
866                 return NULL;
867
868         if (!(data[24 + 3] & 0x20)) {
869                 wpa_printf(MSG_INFO, "Expected CCMP frame from " MACSTR
870                            " did not have ExtIV bit set to 1",
871                            MAC2STR(hdr->addr2));
872                 return NULL;
873         }
874
875         if (data[24 + 2] != 0 || (data[24 + 3] & 0x1f) != 0) {
876                 wpa_printf(MSG_INFO, "CCMP mgmt frame from " MACSTR " used "
877                            "non-zero reserved bit", MAC2STR(hdr->addr2));
878         }
879
880         keyid = data[24 + 3] >> 6;
881         if (keyid != 0) {
882                 wpa_printf(MSG_INFO, "Unexpected non-zero KeyID %d in "
883                            "individually addressed Management frame from "
884                            MACSTR, keyid, MAC2STR(hdr->addr2));
885         }
886
887         if (os_memcmp(hdr->addr1, hdr->addr3, ETH_ALEN) == 0)
888                 rsc = sta->rsc_tods[16];
889         else
890                 rsc = sta->rsc_fromds[16];
891
892         ccmp_get_pn(pn, data + 24);
893         if (os_memcmp(pn, rsc, 6) <= 0) {
894                 u16 seq_ctrl = le_to_host16(hdr->seq_ctrl);
895                 wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: A1=" MACSTR
896                            " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u",
897                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
898                            MAC2STR(hdr->addr3),
899                            WLAN_GET_SEQ_SEQ(seq_ctrl),
900                            WLAN_GET_SEQ_FRAG(seq_ctrl));
901                 wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
902                 wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
903         }
904
905         decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data + 24, len - 24, dlen);
906         if (decrypted) {
907                 os_memcpy(rsc, pn, 6);
908                 frame = os_malloc(24 + *dlen);
909                 if (frame) {
910                         os_memcpy(frame, data, 24);
911                         os_memcpy(frame + 24, decrypted, *dlen);
912                         *dlen += 24;
913                 }
914         }
915
916         os_free(decrypted);
917
918         return frame;
919 }
920
921
922 static int check_mgmt_ccmp(struct wlantest *wt, const u8 *data, size_t len)
923 {
924         const struct ieee80211_mgmt *mgmt;
925         u16 fc;
926         struct wlantest_bss *bss;
927         struct wlantest_sta *sta;
928
929         mgmt = (const struct ieee80211_mgmt *) data;
930         fc = le_to_host16(mgmt->frame_control);
931
932         if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
933                 if (len > 24 &&
934                     mgmt->u.action.category == WLAN_ACTION_PUBLIC)
935                         return 0; /* Not a robust management frame */
936         }
937
938         bss = bss_get(wt, mgmt->bssid);
939         if (bss == NULL)
940                 return 0;
941         if (os_memcmp(mgmt->da, mgmt->bssid, ETH_ALEN) == 0)
942                 sta = sta_get(bss, mgmt->sa);
943         else
944                 sta = sta_get(bss, mgmt->da);
945         if (sta == NULL)
946                 return 0;
947
948         if ((sta->rsn_capab & WPA_CAPABILITY_MFPC) &&
949             (sta->state == STATE3 ||
950              WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION)) {
951                 wpa_printf(MSG_INFO, "Robust individually-addressed "
952                            "management frame sent without CCMP by "
953                            MACSTR, MAC2STR(mgmt->sa));
954                 return -1;
955         }
956
957         return 0;
958 }
959
960
961 void rx_mgmt(struct wlantest *wt, const u8 *data, size_t len)
962 {
963         const struct ieee80211_hdr *hdr;
964         u16 fc, stype;
965         int valid = 1;
966         u8 *decrypted = NULL;
967         size_t dlen;
968
969         if (len < 24)
970                 return;
971
972         hdr = (const struct ieee80211_hdr *) data;
973         fc = le_to_host16(hdr->frame_control);
974         wt->rx_mgmt++;
975         stype = WLAN_FC_GET_STYPE(fc);
976
977         if ((hdr->addr1[0] & 0x01) &&
978             (stype == WLAN_FC_STYPE_DEAUTH ||
979              stype == WLAN_FC_STYPE_DISASSOC ||
980              stype == WLAN_FC_STYPE_ACTION)) {
981                 if (check_bip(wt, data, len) < 0)
982                         valid = 0;
983         }
984
985         wpa_printf((stype == WLAN_FC_STYPE_BEACON ||
986                     stype == WLAN_FC_STYPE_PROBE_RESP ||
987                     stype == WLAN_FC_STYPE_PROBE_REQ) ?
988                    MSG_EXCESSIVE : MSG_MSGDUMP,
989                    "MGMT %s%s%s DA=" MACSTR " SA=" MACSTR " BSSID=" MACSTR,
990                    mgmt_stype(stype),
991                    fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
992                    fc & WLAN_FC_ISWEP ? " Prot" : "",
993                    MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
994                    MAC2STR(hdr->addr3));
995
996         if ((fc & WLAN_FC_ISWEP) &&
997             !(hdr->addr1[0] & 0x01) &&
998             (stype == WLAN_FC_STYPE_DEAUTH ||
999              stype == WLAN_FC_STYPE_DISASSOC ||
1000              stype == WLAN_FC_STYPE_ACTION)) {
1001                 decrypted = mgmt_ccmp_decrypt(wt, data, len, &dlen);
1002                 if (decrypted) {
1003                         write_pcap_decrypted(wt, decrypted, dlen, NULL, 0);
1004                         data = decrypted;
1005                         len = dlen;
1006                 } else
1007                         valid = 0;
1008         }
1009
1010         if (!(fc & WLAN_FC_ISWEP) &&
1011             !(hdr->addr1[0] & 0x01) &&
1012             (stype == WLAN_FC_STYPE_DEAUTH ||
1013              stype == WLAN_FC_STYPE_DISASSOC ||
1014              stype == WLAN_FC_STYPE_ACTION)) {
1015                 if (check_mgmt_ccmp(wt, data, len) < 0)
1016                         valid = 0;
1017         }
1018
1019         switch (stype) {
1020         case WLAN_FC_STYPE_BEACON:
1021                 rx_mgmt_beacon(wt, data, len);
1022                 break;
1023         case WLAN_FC_STYPE_PROBE_RESP:
1024                 rx_mgmt_probe_resp(wt, data, len);
1025                 break;
1026         case WLAN_FC_STYPE_AUTH:
1027                 rx_mgmt_auth(wt, data, len);
1028                 break;
1029         case WLAN_FC_STYPE_DEAUTH:
1030                 rx_mgmt_deauth(wt, data, len, valid);
1031                 break;
1032         case WLAN_FC_STYPE_ASSOC_REQ:
1033                 rx_mgmt_assoc_req(wt, data, len);
1034                 break;
1035         case WLAN_FC_STYPE_ASSOC_RESP:
1036                 rx_mgmt_assoc_resp(wt, data, len);
1037                 break;
1038         case WLAN_FC_STYPE_REASSOC_REQ:
1039                 rx_mgmt_reassoc_req(wt, data, len);
1040                 break;
1041         case WLAN_FC_STYPE_REASSOC_RESP:
1042                 rx_mgmt_reassoc_resp(wt, data, len);
1043                 break;
1044         case WLAN_FC_STYPE_DISASSOC:
1045                 rx_mgmt_disassoc(wt, data, len, valid);
1046                 break;
1047         case WLAN_FC_STYPE_ACTION:
1048                 rx_mgmt_action(wt, data, len, valid);
1049                 break;
1050         }
1051
1052         os_free(decrypted);
1053
1054         wt->last_mgmt_valid = valid;
1055 }
1056
1057
1058 static void rx_mgmt_deauth_ack(struct wlantest *wt,
1059                                const struct ieee80211_hdr *hdr)
1060 {
1061         const struct ieee80211_mgmt *mgmt;
1062         struct wlantest_bss *bss;
1063         struct wlantest_sta *sta;
1064
1065         mgmt = (const struct ieee80211_mgmt *) hdr;
1066         bss = bss_get(wt, mgmt->bssid);
1067         if (bss == NULL)
1068                 return;
1069         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
1070                 sta = sta_get(bss, mgmt->da);
1071         else
1072                 sta = sta_get(bss, mgmt->sa);
1073         if (sta == NULL)
1074                 return;
1075
1076         wpa_printf(MSG_DEBUG, "DEAUTH from " MACSTR " acknowledged by " MACSTR,
1077                    MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
1078         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
1079                 int c;
1080                 c = wt->last_mgmt_valid ?
1081                         WLANTEST_STA_COUNTER_VALID_DEAUTH_RX_ACK :
1082                         WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX_ACK;
1083                 sta->counters[c]++;
1084         }
1085 }
1086
1087
1088 static void rx_mgmt_disassoc_ack(struct wlantest *wt,
1089                                  const struct ieee80211_hdr *hdr)
1090 {
1091         const struct ieee80211_mgmt *mgmt;
1092         struct wlantest_bss *bss;
1093         struct wlantest_sta *sta;
1094
1095         mgmt = (const struct ieee80211_mgmt *) hdr;
1096         bss = bss_get(wt, mgmt->bssid);
1097         if (bss == NULL)
1098                 return;
1099         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0)
1100                 sta = sta_get(bss, mgmt->da);
1101         else
1102                 sta = sta_get(bss, mgmt->sa);
1103         if (sta == NULL)
1104                 return;
1105
1106         wpa_printf(MSG_DEBUG, "DISASSOC from " MACSTR " acknowledged by "
1107                    MACSTR, MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
1108         if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) {
1109                 int c;
1110                 c = wt->last_mgmt_valid ?
1111                         WLANTEST_STA_COUNTER_VALID_DISASSOC_RX_ACK :
1112                         WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX_ACK;
1113                 sta->counters[c]++;
1114         }
1115 }
1116
1117
1118 void rx_mgmt_ack(struct wlantest *wt, const struct ieee80211_hdr *hdr)
1119 {
1120         u16 fc, stype;
1121         fc = le_to_host16(hdr->frame_control);
1122         stype = WLAN_FC_GET_STYPE(fc);
1123
1124         wpa_printf(MSG_MSGDUMP, "MGMT ACK: stype=%u a1=" MACSTR " a2=" MACSTR
1125                    " a3=" MACSTR,
1126                    stype, MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
1127                    MAC2STR(hdr->addr3));
1128
1129         switch (stype) {
1130         case WLAN_FC_STYPE_DEAUTH:
1131                 rx_mgmt_deauth_ack(wt, hdr);
1132                 break;
1133         case WLAN_FC_STYPE_DISASSOC:
1134                 rx_mgmt_disassoc_ack(wt, hdr);
1135                 break;
1136         }
1137 }