treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / net / wireless / quantenna / qtnfmac / event.c
blob51af93bdf06e88ee34c2364cbea886f159959036
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */
4 #include <linux/kernel.h>
5 #include <linux/module.h>
6 #include <linux/slab.h>
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"
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)
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;
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;
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;
44 sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
45 if (!sinfo)
46 return -ENOMEM;
48 sta_addr = sta_assoc->sta_addr;
49 frame_control = le16_to_cpu(sta_assoc->frame_control);
51 pr_debug("VIF%u.%u: MAC:%pM FC:%x\n", mac->macid, vif->vifid, sta_addr,
52 frame_control);
54 qtnf_sta_list_add(vif, sta_addr);
56 sinfo->assoc_req_ies = NULL;
57 sinfo->assoc_req_ies_len = 0;
58 sinfo->generation = vif->generation;
60 payload_len = len - sizeof(*sta_assoc);
61 tlv = (const struct qlink_tlv_hdr *)sta_assoc->ies;
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);
68 if (tlv_full_len > payload_len) {
69 ret = -EINVAL;
70 goto out;
73 if (tlv_type == QTN_TLV_ID_IE_SET) {
74 const struct qlink_tlv_ie_set *ie_set;
75 unsigned int ie_len;
77 if (payload_len < sizeof(*ie_set)) {
78 ret = -EINVAL;
79 goto out;
82 ie_set = (const struct qlink_tlv_ie_set *)tlv;
83 ie_len = tlv_value_len -
84 (sizeof(*ie_set) - sizeof(ie_set->hdr));
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;
92 payload_len -= tlv_full_len;
93 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
96 if (payload_len) {
97 ret = -EINVAL;
98 goto out;
101 cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, sinfo,
102 GFP_KERNEL);
104 out:
105 kfree(sinfo);
106 return ret;
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)
114 const u8 *sta_addr;
115 u16 reason;
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;
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;
130 sta_addr = sta_deauth->sta_addr;
131 reason = le16_to_cpu(sta_deauth->reason);
133 pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid,
134 sta_addr, reason);
136 if (qtnf_sta_list_del(vif, sta_addr))
137 cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr,
138 GFP_KERNEL);
140 return 0;
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)
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;
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;
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;
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);
178 if (status != WLAN_STATUS_SUCCESS)
179 goto done;
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;
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);
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;
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;
218 ie[0] = WLAN_EID_SSID;
219 ie[1] = vif->wdev.ssid_len;
220 memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len);
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;
237 payload_len = len - sizeof(*join_info);
238 tlv = (struct qlink_tlv_hdr *)join_info->ies;
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);
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;
251 if (tlv_type == QTN_TLV_ID_IE_SET) {
252 const struct qlink_tlv_ie_set *ie_set;
253 unsigned int ie_len;
255 if (payload_len < sizeof(*ie_set)) {
256 pr_warn("invalid IE_SET TLV\n");
257 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
258 goto done;
261 ie_set = (const struct qlink_tlv_ie_set *)tlv;
262 ie_len = tlv_value_len -
263 (sizeof(*ie_set) - sizeof(ie_set->hdr));
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;
271 break;
272 default:
273 pr_warn("unexpected IE type: %u\n",
274 ie_set->type);
275 break;
279 payload_len -= tlv_full_len;
280 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
283 if (payload_len)
284 pr_warn("VIF%u.%u: unexpected remaining payload: %zu\n",
285 vif->mac->macid, vif->vifid, payload_len);
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);
296 if (status == WLAN_STATUS_SUCCESS)
297 netif_carrier_on(vif->netdev);
299 kfree(ie);
300 return 0;
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)
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;
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;
321 pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);
323 cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason),
324 NULL, 0, 0, GFP_KERNEL);
325 netif_carrier_off(vif->netdev);
327 return 0;
330 static int
331 qtnf_event_handle_mgmt_received(struct qtnf_vif *vif,
332 const struct qlink_event_rxmgmt *rxmgmt,
333 u16 len)
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;
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;
347 if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED)
348 flags |= NL80211_RXMGMT_FLAG_ANSWERED;
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);
353 cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq), rxmgmt->sig_dbm,
354 rxmgmt->frame_data, frame_len, flags);
356 return 0;
359 static int
360 qtnf_event_handle_scan_results(struct qtnf_vif *vif,
361 const struct qlink_event_scan_result *sr,
362 u16 len)
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;
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;
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;
389 payload_len = len - sizeof(*sr);
390 tlv = (struct qlink_tlv_hdr *)sr->payload;
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);
397 if (tlv_full_len > payload_len)
398 return -EINVAL;
400 if (tlv_type == QTN_TLV_ID_IE_SET) {
401 const struct qlink_tlv_ie_set *ie_set;
402 unsigned int ie_len;
404 if (payload_len < sizeof(*ie_set))
405 return -EINVAL;
407 ie_set = (const struct qlink_tlv_ie_set *)tlv;
408 ie_len = tlv_value_len -
409 (sizeof(*ie_set) - sizeof(ie_set->hdr));
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;
422 if (ie_len) {
423 ies = ie_set->ie_data;
424 ies_len = ie_len;
428 payload_len -= tlv_full_len;
429 tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len);
432 if (payload_len)
433 return -EINVAL;
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;
443 cfg80211_put_bss(wiphy, bss);
445 return 0;
448 static int
449 qtnf_event_handle_scan_complete(struct qtnf_wmac *mac,
450 const struct qlink_event_scan_complete *status,
451 u16 len)
453 if (len < sizeof(*status)) {
454 pr_err("MAC%u: payload is too short\n", mac->macid);
455 return -EINVAL;
458 qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED);
460 return 0;
463 static int
464 qtnf_event_handle_freq_change(struct qtnf_wmac *mac,
465 const struct qlink_event_freq_change *data,
466 u16 len)
468 struct wiphy *wiphy = priv_to_wiphy(mac);
469 struct cfg80211_chan_def chandef;
470 struct qtnf_vif *vif;
471 int i;
473 if (len < sizeof(*data)) {
474 pr_err("MAC%u: payload is too short\n", mac->macid);
475 return -EINVAL;
478 if (!wiphy->registered)
479 return 0;
481 qlink_chandef_q2cfg(wiphy, &data->chan, &chandef);
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;
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);
495 for (i = 0; i < QTNF_MAX_INTF; i++) {
496 vif = &mac->iflist[i];
498 if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED)
499 continue;
501 if (vif->wdev.iftype == NL80211_IFTYPE_STATION &&
502 !vif->wdev.current_bss)
503 continue;
505 if (!vif->netdev)
506 continue;
508 mutex_lock(&vif->wdev.mtx);
509 cfg80211_ch_switch_notify(vif->netdev, &chandef);
510 mutex_unlock(&vif->wdev.mtx);
513 return 0;
516 static int qtnf_event_handle_radar(struct qtnf_vif *vif,
517 const struct qlink_event_radar *ev,
518 u16 len)
520 struct wiphy *wiphy = priv_to_wiphy(vif->mac);
521 struct cfg80211_chan_def chandef;
523 if (len < sizeof(*ev)) {
524 pr_err("MAC%u: payload is too short\n", vif->mac->macid);
525 return -EINVAL;
528 if (!wiphy->registered || !vif->netdev)
529 return 0;
531 qlink_chandef_q2cfg(wiphy, &ev->chan, &chandef);
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;
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);
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;
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;
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;
568 if (!wiphy_ext_feature_isset(wiphy,
569 NL80211_EXT_FEATURE_DFS_OFFLOAD))
570 break;
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;
581 return 0;
584 static int
585 qtnf_event_handle_external_auth(struct qtnf_vif *vif,
586 const struct qlink_event_external_auth *ev,
587 u16 len)
589 struct cfg80211_external_auth_params auth = {0};
590 struct wiphy *wiphy = priv_to_wiphy(vif->mac);
591 int ret;
593 if (len < sizeof(*ev)) {
594 pr_err("MAC%u: payload is too short\n", vif->mac->macid);
595 return -EINVAL;
598 if (!wiphy->registered || !vif->netdev)
599 return 0;
601 if (ev->ssid_len) {
602 memcpy(auth.ssid.ssid, ev->ssid, ev->ssid_len);
603 auth.ssid.ssid_len = ev->ssid_len;
606 auth.key_mgmt_suite = le32_to_cpu(ev->akm_suite);
607 ether_addr_copy(auth.bssid, ev->bssid);
608 auth.action = ev->action;
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);
614 ret = cfg80211_external_auth_request(vif->netdev, &auth, GFP_KERNEL);
615 if (ret)
616 pr_warn("failed to offload external auth request\n");
618 return ret;
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)
626 struct wiphy *wiphy = priv_to_wiphy(vif->mac);
627 u8 pairwise;
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;
636 if (!wiphy->registered || !vif->netdev)
637 return 0;
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;
645 pairwise = mic_ev->pairwise ?
646 NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP;
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);
651 cfg80211_michael_mic_failure(vif->netdev, mic_ev->src, pairwise,
652 mic_ev->key_index, NULL, GFP_KERNEL);
654 return 0;
657 static int qtnf_event_parse(struct qtnf_wmac *mac,
658 const struct sk_buff *event_skb)
660 const struct qlink_event *event;
661 struct qtnf_vif *vif = NULL;
662 int ret = -1;
663 u16 event_id;
664 u16 event_len;
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);
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;
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;
728 return ret;
731 static int qtnf_event_process_skb(struct qtnf_bus *bus,
732 const struct sk_buff *skb)
734 const struct qlink_event *event;
735 struct qtnf_wmac *mac;
736 int res;
738 if (unlikely(!skb || skb->len < sizeof(*event))) {
739 pr_err("invalid event buffer\n");
740 return -EINVAL;
743 event = (struct qlink_event *)skb->data;
745 mac = qtnf_core_get_mac(bus, event->macid);
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);
751 if (unlikely(!mac))
752 return -ENXIO;
754 rtnl_lock();
755 res = qtnf_event_parse(mac, skb);
756 rtnl_unlock();
758 return res;
761 void qtnf_event_work_handler(struct work_struct *work)
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);
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);