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