Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / net / wireless / quantenna / qtnfmac / event.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */
3
4 #include <linux/kernel.h>
5 #include <linux/module.h>
6 #include <linux/slab.h>
7
8 #include "cfg80211.h"
9 #include "core.h"
10 #include "qlink.h"
11 #include "bus.h"
12 #include "trans.h"
13 #include "util.h"
14 #include "event.h"
15 #include "qlink_util.h"
16
17 static int
18 qtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif,
19                             const struct qlink_event_sta_assoc *sta_assoc,
20                             u16 len)
21 {
22         const u8 *sta_addr;
23         u16 frame_control;
24         struct station_info *sinfo;
25         size_t payload_len;
26         u16 tlv_type;
27         u16 tlv_value_len;
28         size_t tlv_full_len;
29         const struct qlink_tlv_hdr *tlv;
30         int ret = 0;
31
32         if (unlikely(len < sizeof(*sta_assoc))) {
33                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
34                        mac->macid, vif->vifid, len, sizeof(*sta_assoc));
35                 return -EINVAL;
36         }
37
38         if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
39                 pr_err("VIF%u.%u: STA_ASSOC event when not in AP mode\n",
40                        mac->macid, vif->vifid);
41                 return -EPROTO;
42         }
43
44         sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
45         if (!sinfo)
46                 return -ENOMEM;
47
48         sta_addr = sta_assoc->sta_addr;
49         frame_control = le16_to_cpu(sta_assoc->frame_control);
50
51         pr_debug("VIF%u.%u: MAC:%pM FC:%x\n", mac->macid, vif->vifid, sta_addr,
52                  frame_control);
53
54         qtnf_sta_list_add(vif, sta_addr);
55
56         sinfo->assoc_req_ies = NULL;
57         sinfo->assoc_req_ies_len = 0;
58         sinfo->generation = vif->generation;
59
60         payload_len = len - sizeof(*sta_assoc);
61         tlv = (const struct qlink_tlv_hdr *)sta_assoc->ies;
62
63         while (payload_len >= sizeof(*tlv)) {
64                 tlv_type = le16_to_cpu(tlv->type);
65                 tlv_value_len = le16_to_cpu(tlv->len);
66                 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
67
68                 if (tlv_full_len > payload_len) {
69                         ret = -EINVAL;
70                         goto out;
71                 }
72
73                 if (tlv_type == QTN_TLV_ID_IE_SET) {
74                         const struct qlink_tlv_ie_set *ie_set;
75                         unsigned int ie_len;
76
77                         if (payload_len < sizeof(*ie_set)) {
78                                 ret = -EINVAL;
79                                 goto out;
80                         }
81
82                         ie_set = (const struct qlink_tlv_ie_set *)tlv;
83                         ie_len = tlv_value_len -
84                                 (sizeof(*ie_set) - sizeof(ie_set->hdr));
85
86                         if (ie_set->type == QLINK_IE_SET_ASSOC_REQ && ie_len) {
87                                 sinfo->assoc_req_ies = ie_set->ie_data;
88                                 sinfo->assoc_req_ies_len = ie_len;
89                         }
90                 }
91
92                 payload_len -= tlv_full_len;
93                 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
94         }
95
96         if (payload_len) {
97                 ret = -EINVAL;
98                 goto out;
99         }
100
101         cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, sinfo,
102                          GFP_KERNEL);
103
104 out:
105         kfree(sinfo);
106         return ret;
107 }
108
109 static int
110 qtnf_event_handle_sta_deauth(struct qtnf_wmac *mac, struct qtnf_vif *vif,
111                              const struct qlink_event_sta_deauth *sta_deauth,
112                              u16 len)
113 {
114         const u8 *sta_addr;
115         u16 reason;
116
117         if (unlikely(len < sizeof(*sta_deauth))) {
118                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
119                        mac->macid, vif->vifid, len,
120                        sizeof(struct qlink_event_sta_deauth));
121                 return -EINVAL;
122         }
123
124         if (vif->wdev.iftype != NL80211_IFTYPE_AP) {
125                 pr_err("VIF%u.%u: STA_DEAUTH event when not in AP mode\n",
126                        mac->macid, vif->vifid);
127                 return -EPROTO;
128         }
129
130         sta_addr = sta_deauth->sta_addr;
131         reason = le16_to_cpu(sta_deauth->reason);
132
133         pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid,
134                  sta_addr, reason);
135
136         if (qtnf_sta_list_del(vif, sta_addr))
137                 cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr,
138                                  GFP_KERNEL);
139
140         return 0;
141 }
142
143 static int
144 qtnf_event_handle_bss_join(struct qtnf_vif *vif,
145                            const struct qlink_event_bss_join *join_info,
146                            u16 len)
147 {
148         struct wiphy *wiphy = priv_to_wiphy(vif->mac);
149         enum ieee80211_statuscode status = le16_to_cpu(join_info->status);
150         struct cfg80211_chan_def chandef;
151         struct cfg80211_bss *bss = NULL;
152         u8 *ie = NULL;
153         size_t payload_len;
154         u16 tlv_type;
155         u16 tlv_value_len;
156         size_t tlv_full_len;
157         const struct qlink_tlv_hdr *tlv;
158         const u8 *rsp_ies = NULL;
159         size_t rsp_ies_len = 0;
160
161         if (unlikely(len < sizeof(*join_info))) {
162                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
163                        vif->mac->macid, vif->vifid, len,
164                        sizeof(struct qlink_event_bss_join));
165                 return -EINVAL;
166         }
167
168         if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
169                 pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n",
170                        vif->mac->macid, vif->vifid);
171                 return -EPROTO;
172         }
173
174         pr_debug("VIF%u.%u: BSSID:%pM chan:%u status:%u\n",
175                  vif->mac->macid, vif->vifid, join_info->bssid,
176                  le16_to_cpu(join_info->chan.chan.center_freq), status);
177
178         if (status != WLAN_STATUS_SUCCESS)
179                 goto done;
180
181         qlink_chandef_q2cfg(wiphy, &join_info->chan, &chandef);
182         if (!cfg80211_chandef_valid(&chandef)) {
183                 pr_warn("MAC%u.%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n",
184                         vif->mac->macid, vif->vifid,
185                         chandef.chan ? chandef.chan->center_freq : 0,
186                         chandef.center_freq1,
187                         chandef.center_freq2,
188                         chandef.width);
189                 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
190                 goto done;
191         }
192
193         bss = cfg80211_get_bss(wiphy, chandef.chan, join_info->bssid,
194                                NULL, 0, IEEE80211_BSS_TYPE_ESS,
195                                IEEE80211_PRIVACY_ANY);
196         if (!bss) {
197                 pr_warn("VIF%u.%u: add missing BSS:%pM chan:%u\n",
198                         vif->mac->macid, vif->vifid,
199                         join_info->bssid, chandef.chan->hw_value);
200
201                 if (!vif->wdev.ssid_len) {
202                         pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n",
203                                 vif->mac->macid, vif->vifid,
204                                 join_info->bssid);
205                         status = WLAN_STATUS_UNSPECIFIED_FAILURE;
206                         goto done;
207                 }
208
209                 ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL);
210                 if (!ie) {
211                         pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n",
212                                 vif->mac->macid, vif->vifid,
213                                 join_info->bssid);
214                         status = WLAN_STATUS_UNSPECIFIED_FAILURE;
215                         goto done;
216                 }
217
218                 ie[0] = WLAN_EID_SSID;
219                 ie[1] = vif->wdev.ssid_len;
220                 memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len);
221
222                 bss = cfg80211_inform_bss(wiphy, chandef.chan,
223                                           CFG80211_BSS_FTYPE_UNKNOWN,
224                                           join_info->bssid, 0,
225                                           WLAN_CAPABILITY_ESS, 100,
226                                           ie, 2 + vif->wdev.ssid_len,
227                                           0, GFP_KERNEL);
228                 if (!bss) {
229                         pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n",
230                                 vif->mac->macid, vif->vifid,
231                                 join_info->bssid);
232                         status = WLAN_STATUS_UNSPECIFIED_FAILURE;
233                         goto done;
234                 }
235         }
236
237         payload_len = len - sizeof(*join_info);
238         tlv = (struct qlink_tlv_hdr *)join_info->ies;
239
240         while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
241                 tlv_type = le16_to_cpu(tlv->type);
242                 tlv_value_len = le16_to_cpu(tlv->len);
243                 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
244
245                 if (payload_len < tlv_full_len) {
246                         pr_warn("invalid %u TLV\n", tlv_type);
247                         status = WLAN_STATUS_UNSPECIFIED_FAILURE;
248                         goto done;
249                 }
250
251                 if (tlv_type == QTN_TLV_ID_IE_SET) {
252                         const struct qlink_tlv_ie_set *ie_set;
253                         unsigned int ie_len;
254
255                         if (payload_len < sizeof(*ie_set)) {
256                                 pr_warn("invalid IE_SET TLV\n");
257                                 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
258                                 goto done;
259                         }
260
261                         ie_set = (const struct qlink_tlv_ie_set *)tlv;
262                         ie_len = tlv_value_len -
263                                 (sizeof(*ie_set) - sizeof(ie_set->hdr));
264
265                         switch (ie_set->type) {
266                         case QLINK_IE_SET_ASSOC_RESP:
267                                 if (ie_len) {
268                                         rsp_ies = ie_set->ie_data;
269                                         rsp_ies_len = ie_len;
270                                 }
271                                 break;
272                         default:
273                                 pr_warn("unexpected IE type: %u\n",
274                                         ie_set->type);
275                                 break;
276                         }
277                 }
278
279                 payload_len -= tlv_full_len;
280                 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
281         }
282
283         if (payload_len)
284                 pr_warn("VIF%u.%u: unexpected remaining payload: %zu\n",
285                         vif->mac->macid, vif->vifid, payload_len);
286
287 done:
288         cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, rsp_ies,
289                                 rsp_ies_len, status, GFP_KERNEL);
290         if (bss) {
291                 if (!ether_addr_equal(vif->bssid, join_info->bssid))
292                         ether_addr_copy(vif->bssid, join_info->bssid);
293                 cfg80211_put_bss(wiphy, bss);
294         }
295
296         if (status == WLAN_STATUS_SUCCESS)
297                 netif_carrier_on(vif->netdev);
298
299         kfree(ie);
300         return 0;
301 }
302
303 static int
304 qtnf_event_handle_bss_leave(struct qtnf_vif *vif,
305                             const struct qlink_event_bss_leave *leave_info,
306                             u16 len)
307 {
308         if (unlikely(len < sizeof(*leave_info))) {
309                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
310                        vif->mac->macid, vif->vifid, len,
311                        sizeof(struct qlink_event_bss_leave));
312                 return -EINVAL;
313         }
314
315         if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
316                 pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n",
317                        vif->mac->macid, vif->vifid);
318                 return -EPROTO;
319         }
320
321         pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);
322
323         cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason),
324                               NULL, 0, 0, GFP_KERNEL);
325         netif_carrier_off(vif->netdev);
326
327         return 0;
328 }
329
330 static int
331 qtnf_event_handle_mgmt_received(struct qtnf_vif *vif,
332                                 const struct qlink_event_rxmgmt *rxmgmt,
333                                 u16 len)
334 {
335         const size_t min_len = sizeof(*rxmgmt) +
336                                sizeof(struct ieee80211_hdr_3addr);
337         const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data;
338         const u16 frame_len = len - sizeof(*rxmgmt);
339         enum nl80211_rxmgmt_flags flags = 0;
340
341         if (unlikely(len < min_len)) {
342                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
343                        vif->mac->macid, vif->vifid, len, min_len);
344                 return -EINVAL;
345         }
346
347         if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED)
348                 flags |= NL80211_RXMGMT_FLAG_ANSWERED;
349
350         pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len,
351                  le16_to_cpu(frame->frame_control), frame->addr2);
352
353         cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq), rxmgmt->sig_dbm,
354                          rxmgmt->frame_data, frame_len, flags);
355
356         return 0;
357 }
358
359 static int
360 qtnf_event_handle_scan_results(struct qtnf_vif *vif,
361                                const struct qlink_event_scan_result *sr,
362                                u16 len)
363 {
364         struct cfg80211_bss *bss;
365         struct ieee80211_channel *channel;
366         struct wiphy *wiphy = priv_to_wiphy(vif->mac);
367         enum cfg80211_bss_frame_type frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
368         size_t payload_len;
369         u16 tlv_type;
370         u16 tlv_value_len;
371         size_t tlv_full_len;
372         const struct qlink_tlv_hdr *tlv;
373         const u8 *ies = NULL;
374         size_t ies_len = 0;
375
376         if (len < sizeof(*sr)) {
377                 pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid,
378                        vif->vifid);
379                 return -EINVAL;
380         }
381
382         channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq));
383         if (!channel) {
384                 pr_err("VIF%u.%u: channel at %u MHz not found\n",
385                        vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq));
386                 return -EINVAL;
387         }
388
389         payload_len = len - sizeof(*sr);
390         tlv = (struct qlink_tlv_hdr *)sr->payload;
391
392         while (payload_len >= sizeof(struct qlink_tlv_hdr)) {
393                 tlv_type = le16_to_cpu(tlv->type);
394                 tlv_value_len = le16_to_cpu(tlv->len);
395                 tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr);
396
397                 if (tlv_full_len > payload_len)
398                         return -EINVAL;
399
400                 if (tlv_type == QTN_TLV_ID_IE_SET) {
401                         const struct qlink_tlv_ie_set *ie_set;
402                         unsigned int ie_len;
403
404                         if (payload_len < sizeof(*ie_set))
405                                 return -EINVAL;
406
407                         ie_set = (const struct qlink_tlv_ie_set *)tlv;
408                         ie_len = tlv_value_len -
409                                 (sizeof(*ie_set) - sizeof(ie_set->hdr));
410
411                         switch (ie_set->type) {
412                         case QLINK_IE_SET_BEACON_IES:
413                                 frame_type = CFG80211_BSS_FTYPE_BEACON;
414                                 break;
415                         case QLINK_IE_SET_PROBE_RESP_IES:
416                                 frame_type = CFG80211_BSS_FTYPE_PRESP;
417                                 break;
418                         default:
419                                 frame_type = CFG80211_BSS_FTYPE_UNKNOWN;
420                         }
421
422                         if (ie_len) {
423                                 ies = ie_set->ie_data;
424                                 ies_len = ie_len;
425                         }
426                 }
427
428                 payload_len -= tlv_full_len;
429                 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
430         }
431
432         if (payload_len)
433                 return -EINVAL;
434
435         bss = cfg80211_inform_bss(wiphy, channel, frame_type,
436                                   sr->bssid, get_unaligned_le64(&sr->tsf),
437                                   le16_to_cpu(sr->capab),
438                                   le16_to_cpu(sr->bintval), ies, ies_len,
439                                   DBM_TO_MBM(sr->sig_dbm), GFP_KERNEL);
440         if (!bss)
441                 return -ENOMEM;
442
443         cfg80211_put_bss(wiphy, bss);
444
445         return 0;
446 }
447
448 static int
449 qtnf_event_handle_scan_complete(struct qtnf_wmac *mac,
450                                 const struct qlink_event_scan_complete *status,
451                                 u16 len)
452 {
453         if (len < sizeof(*status)) {
454                 pr_err("MAC%u: payload is too short\n", mac->macid);
455                 return -EINVAL;
456         }
457
458         qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED);
459
460         return 0;
461 }
462
463 static int
464 qtnf_event_handle_freq_change(struct qtnf_wmac *mac,
465                               const struct qlink_event_freq_change *data,
466                               u16 len)
467 {
468         struct wiphy *wiphy = priv_to_wiphy(mac);
469         struct cfg80211_chan_def chandef;
470         struct qtnf_vif *vif;
471         int i;
472
473         if (len < sizeof(*data)) {
474                 pr_err("MAC%u: payload is too short\n", mac->macid);
475                 return -EINVAL;
476         }
477
478         if (!wiphy->registered)
479                 return 0;
480
481         qlink_chandef_q2cfg(wiphy, &data->chan, &chandef);
482
483         if (!cfg80211_chandef_valid(&chandef)) {
484                 pr_err("MAC%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n",
485                        mac->macid, chandef.chan->center_freq,
486                        chandef.center_freq1, chandef.center_freq2,
487                        chandef.width);
488                 return -EINVAL;
489         }
490
491         pr_debug("MAC%d: new channel ieee=%u freq1=%u freq2=%u bw=%u\n",
492                  mac->macid, chandef.chan->hw_value, chandef.center_freq1,
493                  chandef.center_freq2, chandef.width);
494
495         for (i = 0; i < QTNF_MAX_INTF; i++) {
496                 vif = &mac->iflist[i];
497
498                 if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
499                         continue;
500
501                 if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
502                     !vif->wdev.current_bss)
503                         continue;
504
505                 if (!vif->netdev)
506                         continue;
507
508                 mutex_lock(&vif->wdev.mtx);
509                 cfg80211_ch_switch_notify(vif->netdev, &chandef);
510                 mutex_unlock(&vif->wdev.mtx);
511         }
512
513         return 0;
514 }
515
516 static int qtnf_event_handle_radar(struct qtnf_vif *vif,
517                                    const struct qlink_event_radar *ev,
518                                    u16 len)
519 {
520         struct wiphy *wiphy = priv_to_wiphy(vif->mac);
521         struct cfg80211_chan_def chandef;
522
523         if (len < sizeof(*ev)) {
524                 pr_err("MAC%u: payload is too short\n", vif->mac->macid);
525                 return -EINVAL;
526         }
527
528         if (!wiphy->registered || !vif->netdev)
529                 return 0;
530
531         qlink_chandef_q2cfg(wiphy, &ev->chan, &chandef);
532
533         if (!cfg80211_chandef_valid(&chandef)) {
534                 pr_err("MAC%u: bad channel f1=%u f2=%u bw=%u\n",
535                        vif->mac->macid,
536                        chandef.center_freq1, chandef.center_freq2,
537                        chandef.width);
538                 return -EINVAL;
539         }
540
541         pr_info("%s: radar event=%u f1=%u f2=%u bw=%u\n",
542                 vif->netdev->name, ev->event,
543                 chandef.center_freq1, chandef.center_freq2,
544                 chandef.width);
545
546         switch (ev->event) {
547         case QLINK_RADAR_DETECTED:
548                 cfg80211_radar_event(wiphy, &chandef, GFP_KERNEL);
549                 break;
550         case QLINK_RADAR_CAC_FINISHED:
551                 if (!vif->wdev.cac_started)
552                         break;
553
554                 cfg80211_cac_event(vif->netdev, &chandef,
555                                    NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
556                 break;
557         case QLINK_RADAR_CAC_ABORTED:
558                 if (!vif->wdev.cac_started)
559                         break;
560
561                 cfg80211_cac_event(vif->netdev, &chandef,
562                                    NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
563                 break;
564         case QLINK_RADAR_CAC_STARTED:
565                 if (vif->wdev.cac_started)
566                         break;
567
568                 if (!wiphy_ext_feature_isset(wiphy,
569                                              NL80211_EXT_FEATURE_DFS_OFFLOAD))
570                         break;
571
572                 cfg80211_cac_event(vif->netdev, &chandef,
573                                    NL80211_RADAR_CAC_STARTED, GFP_KERNEL);
574                 break;
575         default:
576                 pr_warn("%s: unhandled radar event %u\n",
577                         vif->netdev->name, ev->event);
578                 break;
579         }
580
581         return 0;
582 }
583
584 static int
585 qtnf_event_handle_external_auth(struct qtnf_vif *vif,
586                                 const struct qlink_event_external_auth *ev,
587                                 u16 len)
588 {
589         struct cfg80211_external_auth_params auth = {0};
590         struct wiphy *wiphy = priv_to_wiphy(vif->mac);
591         int ret;
592
593         if (len < sizeof(*ev)) {
594                 pr_err("MAC%u: payload is too short\n", vif->mac->macid);
595                 return -EINVAL;
596         }
597
598         if (!wiphy->registered || !vif->netdev)
599                 return 0;
600
601         if (ev->ssid_len) {
602                 memcpy(auth.ssid.ssid, ev->ssid, ev->ssid_len);
603                 auth.ssid.ssid_len = ev->ssid_len;
604         }
605
606         auth.key_mgmt_suite = le32_to_cpu(ev->akm_suite);
607         ether_addr_copy(auth.bssid, ev->bssid);
608         auth.action = ev->action;
609
610         pr_info("%s: external auth bss=%pM action=%u akm=%u\n",
611                 vif->netdev->name, auth.bssid, auth.action,
612                 auth.key_mgmt_suite);
613
614         ret = cfg80211_external_auth_request(vif->netdev, &auth, GFP_KERNEL);
615         if (ret)
616                 pr_warn("failed to offload external auth request\n");
617
618         return ret;
619 }
620
621 static int
622 qtnf_event_handle_mic_failure(struct qtnf_vif *vif,
623                               const struct qlink_event_mic_failure *mic_ev,
624                               u16 len)
625 {
626         struct wiphy *wiphy = priv_to_wiphy(vif->mac);
627         u8 pairwise;
628
629         if (len < sizeof(*mic_ev)) {
630                 pr_err("VIF%u.%u: payload is too short (%u < %zu)\n",
631                        vif->mac->macid, vif->vifid, len,
632                        sizeof(struct qlink_event_mic_failure));
633                 return -EINVAL;
634         }
635
636         if (!wiphy->registered || !vif->netdev)
637                 return 0;
638
639         if (vif->wdev.iftype != NL80211_IFTYPE_STATION) {
640                 pr_err("VIF%u.%u: MIC_FAILURE event when not in STA mode\n",
641                        vif->mac->macid, vif->vifid);
642                 return -EPROTO;
643         }
644
645         pairwise = mic_ev->pairwise ?
646                 NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP;
647
648         pr_info("%s: MIC error: src=%pM key_index=%u pairwise=%u\n",
649                 vif->netdev->name, mic_ev->src, mic_ev->key_index, pairwise);
650
651         cfg80211_michael_mic_failure(vif->netdev, mic_ev->src, pairwise,
652                                      mic_ev->key_index, NULL, GFP_KERNEL);
653
654         return 0;
655 }
656
657 static int qtnf_event_parse(struct qtnf_wmac *mac,
658                             const struct sk_buff *event_skb)
659 {
660         const struct qlink_event *event;
661         struct qtnf_vif *vif = NULL;
662         int ret = -1;
663         u16 event_id;
664         u16 event_len;
665
666         event = (const struct qlink_event *)event_skb->data;
667         event_id = le16_to_cpu(event->event_id);
668         event_len = le16_to_cpu(event->mhdr.len);
669
670         if (likely(event->vifid < QTNF_MAX_INTF)) {
671                 vif = &mac->iflist[event->vifid];
672         } else {
673                 pr_err("invalid vif(%u)\n", event->vifid);
674                 return -EINVAL;
675         }
676
677         switch (event_id) {
678         case QLINK_EVENT_STA_ASSOCIATED:
679                 ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event,
680                                                   event_len);
681                 break;
682         case QLINK_EVENT_STA_DEAUTH:
683                 ret = qtnf_event_handle_sta_deauth(mac, vif,
684                                                    (const void *)event,
685                                                    event_len);
686                 break;
687         case QLINK_EVENT_MGMT_RECEIVED:
688                 ret = qtnf_event_handle_mgmt_received(vif, (const void *)event,
689                                                       event_len);
690                 break;
691         case QLINK_EVENT_SCAN_RESULTS:
692                 ret = qtnf_event_handle_scan_results(vif, (const void *)event,
693                                                      event_len);
694                 break;
695         case QLINK_EVENT_SCAN_COMPLETE:
696                 ret = qtnf_event_handle_scan_complete(mac, (const void *)event,
697                                                       event_len);
698                 break;
699         case QLINK_EVENT_BSS_JOIN:
700                 ret = qtnf_event_handle_bss_join(vif, (const void *)event,
701                                                  event_len);
702                 break;
703         case QLINK_EVENT_BSS_LEAVE:
704                 ret = qtnf_event_handle_bss_leave(vif, (const void *)event,
705                                                   event_len);
706                 break;
707         case QLINK_EVENT_FREQ_CHANGE:
708                 ret = qtnf_event_handle_freq_change(mac, (const void *)event,
709                                                     event_len);
710                 break;
711         case QLINK_EVENT_RADAR:
712                 ret = qtnf_event_handle_radar(vif, (const void *)event,
713                                               event_len);
714                 break;
715         case QLINK_EVENT_EXTERNAL_AUTH:
716                 ret = qtnf_event_handle_external_auth(vif, (const void *)event,
717                                                       event_len);
718                 break;
719         case QLINK_EVENT_MIC_FAILURE:
720                 ret = qtnf_event_handle_mic_failure(vif, (const void *)event,
721                                                     event_len);
722                 break;
723         default:
724                 pr_warn("unknown event type: %x\n", event_id);
725                 break;
726         }
727
728         return ret;
729 }
730
731 static int qtnf_event_process_skb(struct qtnf_bus *bus,
732                                   const struct sk_buff *skb)
733 {
734         const struct qlink_event *event;
735         struct qtnf_wmac *mac;
736         int res;
737
738         if (unlikely(!skb || skb->len < sizeof(*event))) {
739                 pr_err("invalid event buffer\n");
740                 return -EINVAL;
741         }
742
743         event = (struct qlink_event *)skb->data;
744
745         mac = qtnf_core_get_mac(bus, event->macid);
746
747         pr_debug("new event id:%x len:%u mac:%u vif:%u\n",
748                  le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len),
749                  event->macid, event->vifid);
750
751         if (unlikely(!mac))
752                 return -ENXIO;
753
754         rtnl_lock();
755         res = qtnf_event_parse(mac, skb);
756         rtnl_unlock();
757
758         return res;
759 }
760
761 void qtnf_event_work_handler(struct work_struct *work)
762 {
763         struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work);
764         struct sk_buff_head *event_queue = &bus->trans.event_queue;
765         struct sk_buff *current_event_skb = skb_dequeue(event_queue);
766
767         while (current_event_skb) {
768                 qtnf_event_process_skb(bus, current_event_skb);
769                 dev_kfree_skb_any(current_event_skb);
770                 current_event_skb = skb_dequeue(event_queue);
771         }
772 }