18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/kernel.h> 58c2ecf20Sopenharmony_ci#include <linux/module.h> 68c2ecf20Sopenharmony_ci#include <linux/slab.h> 78c2ecf20Sopenharmony_ci#include <linux/nospec.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "cfg80211.h" 108c2ecf20Sopenharmony_ci#include "core.h" 118c2ecf20Sopenharmony_ci#include "qlink.h" 128c2ecf20Sopenharmony_ci#include "bus.h" 138c2ecf20Sopenharmony_ci#include "trans.h" 148c2ecf20Sopenharmony_ci#include "util.h" 158c2ecf20Sopenharmony_ci#include "event.h" 168c2ecf20Sopenharmony_ci#include "qlink_util.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic int 198c2ecf20Sopenharmony_ciqtnf_event_handle_sta_assoc(struct qtnf_wmac *mac, struct qtnf_vif *vif, 208c2ecf20Sopenharmony_ci const struct qlink_event_sta_assoc *sta_assoc, 218c2ecf20Sopenharmony_ci u16 len) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci const u8 *sta_addr; 248c2ecf20Sopenharmony_ci u16 frame_control; 258c2ecf20Sopenharmony_ci struct station_info *sinfo; 268c2ecf20Sopenharmony_ci size_t payload_len; 278c2ecf20Sopenharmony_ci u16 tlv_type; 288c2ecf20Sopenharmony_ci u16 tlv_value_len; 298c2ecf20Sopenharmony_ci const struct qlink_tlv_hdr *tlv; 308c2ecf20Sopenharmony_ci int ret = 0; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (unlikely(len < sizeof(*sta_assoc))) { 338c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 348c2ecf20Sopenharmony_ci mac->macid, vif->vifid, len, sizeof(*sta_assoc)); 358c2ecf20Sopenharmony_ci return -EINVAL; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (vif->wdev.iftype != NL80211_IFTYPE_AP) { 398c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: STA_ASSOC event when not in AP mode\n", 408c2ecf20Sopenharmony_ci mac->macid, vif->vifid); 418c2ecf20Sopenharmony_ci return -EPROTO; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL); 458c2ecf20Sopenharmony_ci if (!sinfo) 468c2ecf20Sopenharmony_ci return -ENOMEM; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci sta_addr = sta_assoc->sta_addr; 498c2ecf20Sopenharmony_ci frame_control = le16_to_cpu(sta_assoc->frame_control); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci pr_debug("VIF%u.%u: MAC:%pM FC:%x\n", mac->macid, vif->vifid, sta_addr, 528c2ecf20Sopenharmony_ci frame_control); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci qtnf_sta_list_add(vif, sta_addr); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci sinfo->assoc_req_ies = NULL; 578c2ecf20Sopenharmony_ci sinfo->assoc_req_ies_len = 0; 588c2ecf20Sopenharmony_ci sinfo->generation = vif->generation; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci payload_len = len - sizeof(*sta_assoc); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci qlink_for_each_tlv(tlv, sta_assoc->ies, payload_len) { 638c2ecf20Sopenharmony_ci tlv_type = le16_to_cpu(tlv->type); 648c2ecf20Sopenharmony_ci tlv_value_len = le16_to_cpu(tlv->len); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (tlv_type == QTN_TLV_ID_IE_SET) { 678c2ecf20Sopenharmony_ci const struct qlink_tlv_ie_set *ie_set; 688c2ecf20Sopenharmony_ci unsigned int ie_len; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (tlv_value_len < 718c2ecf20Sopenharmony_ci (sizeof(*ie_set) - sizeof(ie_set->hdr))) { 728c2ecf20Sopenharmony_ci ret = -EINVAL; 738c2ecf20Sopenharmony_ci goto out; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ie_set = (const struct qlink_tlv_ie_set *)tlv; 778c2ecf20Sopenharmony_ci ie_len = tlv_value_len - 788c2ecf20Sopenharmony_ci (sizeof(*ie_set) - sizeof(ie_set->hdr)); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (ie_set->type == QLINK_IE_SET_ASSOC_REQ && ie_len) { 818c2ecf20Sopenharmony_ci sinfo->assoc_req_ies = ie_set->ie_data; 828c2ecf20Sopenharmony_ci sinfo->assoc_req_ies_len = ie_len; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (!qlink_tlv_parsing_ok(tlv, sta_assoc->ies, payload_len)) { 888c2ecf20Sopenharmony_ci pr_err("Malformed TLV buffer\n"); 898c2ecf20Sopenharmony_ci ret = -EINVAL; 908c2ecf20Sopenharmony_ci goto out; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci cfg80211_new_sta(vif->netdev, sta_assoc->sta_addr, sinfo, 948c2ecf20Sopenharmony_ci GFP_KERNEL); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciout: 978c2ecf20Sopenharmony_ci kfree(sinfo); 988c2ecf20Sopenharmony_ci return ret; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int 1028c2ecf20Sopenharmony_ciqtnf_event_handle_sta_deauth(struct qtnf_wmac *mac, struct qtnf_vif *vif, 1038c2ecf20Sopenharmony_ci const struct qlink_event_sta_deauth *sta_deauth, 1048c2ecf20Sopenharmony_ci u16 len) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci const u8 *sta_addr; 1078c2ecf20Sopenharmony_ci u16 reason; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (unlikely(len < sizeof(*sta_deauth))) { 1108c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 1118c2ecf20Sopenharmony_ci mac->macid, vif->vifid, len, 1128c2ecf20Sopenharmony_ci sizeof(struct qlink_event_sta_deauth)); 1138c2ecf20Sopenharmony_ci return -EINVAL; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (vif->wdev.iftype != NL80211_IFTYPE_AP) { 1178c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: STA_DEAUTH event when not in AP mode\n", 1188c2ecf20Sopenharmony_ci mac->macid, vif->vifid); 1198c2ecf20Sopenharmony_ci return -EPROTO; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci sta_addr = sta_deauth->sta_addr; 1238c2ecf20Sopenharmony_ci reason = le16_to_cpu(sta_deauth->reason); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci pr_debug("VIF%u.%u: MAC:%pM reason:%x\n", mac->macid, vif->vifid, 1268c2ecf20Sopenharmony_ci sta_addr, reason); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (qtnf_sta_list_del(vif, sta_addr)) 1298c2ecf20Sopenharmony_ci cfg80211_del_sta(vif->netdev, sta_deauth->sta_addr, 1308c2ecf20Sopenharmony_ci GFP_KERNEL); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int 1368c2ecf20Sopenharmony_ciqtnf_event_handle_bss_join(struct qtnf_vif *vif, 1378c2ecf20Sopenharmony_ci const struct qlink_event_bss_join *join_info, 1388c2ecf20Sopenharmony_ci u16 len) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(vif->mac); 1418c2ecf20Sopenharmony_ci enum ieee80211_statuscode status = le16_to_cpu(join_info->status); 1428c2ecf20Sopenharmony_ci struct cfg80211_chan_def chandef; 1438c2ecf20Sopenharmony_ci struct cfg80211_bss *bss = NULL; 1448c2ecf20Sopenharmony_ci u8 *ie = NULL; 1458c2ecf20Sopenharmony_ci size_t payload_len; 1468c2ecf20Sopenharmony_ci u16 tlv_type; 1478c2ecf20Sopenharmony_ci u16 tlv_value_len; 1488c2ecf20Sopenharmony_ci const struct qlink_tlv_hdr *tlv; 1498c2ecf20Sopenharmony_ci const u8 *rsp_ies = NULL; 1508c2ecf20Sopenharmony_ci size_t rsp_ies_len = 0; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (unlikely(len < sizeof(*join_info))) { 1538c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 1548c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, len, 1558c2ecf20Sopenharmony_ci sizeof(struct qlink_event_bss_join)); 1568c2ecf20Sopenharmony_ci return -EINVAL; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { 1608c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: BSS_JOIN event when not in STA mode\n", 1618c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid); 1628c2ecf20Sopenharmony_ci return -EPROTO; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci pr_debug("VIF%u.%u: BSSID:%pM chan:%u status:%u\n", 1668c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, join_info->bssid, 1678c2ecf20Sopenharmony_ci le16_to_cpu(join_info->chan.chan.center_freq), status); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (status != WLAN_STATUS_SUCCESS) 1708c2ecf20Sopenharmony_ci goto done; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci qlink_chandef_q2cfg(wiphy, &join_info->chan, &chandef); 1738c2ecf20Sopenharmony_ci if (!cfg80211_chandef_valid(&chandef)) { 1748c2ecf20Sopenharmony_ci pr_warn("MAC%u.%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n", 1758c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, 1768c2ecf20Sopenharmony_ci chandef.chan ? chandef.chan->center_freq : 0, 1778c2ecf20Sopenharmony_ci chandef.center_freq1, 1788c2ecf20Sopenharmony_ci chandef.center_freq2, 1798c2ecf20Sopenharmony_ci chandef.width); 1808c2ecf20Sopenharmony_ci status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1818c2ecf20Sopenharmony_ci goto done; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci bss = cfg80211_get_bss(wiphy, chandef.chan, join_info->bssid, 1858c2ecf20Sopenharmony_ci NULL, 0, IEEE80211_BSS_TYPE_ESS, 1868c2ecf20Sopenharmony_ci IEEE80211_PRIVACY_ANY); 1878c2ecf20Sopenharmony_ci if (!bss) { 1888c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: add missing BSS:%pM chan:%u\n", 1898c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, 1908c2ecf20Sopenharmony_ci join_info->bssid, chandef.chan->hw_value); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!vif->wdev.ssid_len) { 1938c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n", 1948c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, 1958c2ecf20Sopenharmony_ci join_info->bssid); 1968c2ecf20Sopenharmony_ci status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1978c2ecf20Sopenharmony_ci goto done; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL); 2018c2ecf20Sopenharmony_ci if (!ie) { 2028c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n", 2038c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, 2048c2ecf20Sopenharmony_ci join_info->bssid); 2058c2ecf20Sopenharmony_ci status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2068c2ecf20Sopenharmony_ci goto done; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci ie[0] = WLAN_EID_SSID; 2108c2ecf20Sopenharmony_ci ie[1] = vif->wdev.ssid_len; 2118c2ecf20Sopenharmony_ci memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci bss = cfg80211_inform_bss(wiphy, chandef.chan, 2148c2ecf20Sopenharmony_ci CFG80211_BSS_FTYPE_UNKNOWN, 2158c2ecf20Sopenharmony_ci join_info->bssid, 0, 2168c2ecf20Sopenharmony_ci WLAN_CAPABILITY_ESS, 100, 2178c2ecf20Sopenharmony_ci ie, 2 + vif->wdev.ssid_len, 2188c2ecf20Sopenharmony_ci 0, GFP_KERNEL); 2198c2ecf20Sopenharmony_ci if (!bss) { 2208c2ecf20Sopenharmony_ci pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n", 2218c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, 2228c2ecf20Sopenharmony_ci join_info->bssid); 2238c2ecf20Sopenharmony_ci status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2248c2ecf20Sopenharmony_ci goto done; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci payload_len = len - sizeof(*join_info); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci qlink_for_each_tlv(tlv, join_info->ies, payload_len) { 2318c2ecf20Sopenharmony_ci tlv_type = le16_to_cpu(tlv->type); 2328c2ecf20Sopenharmony_ci tlv_value_len = le16_to_cpu(tlv->len); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (tlv_type == QTN_TLV_ID_IE_SET) { 2358c2ecf20Sopenharmony_ci const struct qlink_tlv_ie_set *ie_set; 2368c2ecf20Sopenharmony_ci unsigned int ie_len; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (tlv_value_len < 2398c2ecf20Sopenharmony_ci (sizeof(*ie_set) - sizeof(ie_set->hdr))) { 2408c2ecf20Sopenharmony_ci pr_warn("invalid IE_SET TLV\n"); 2418c2ecf20Sopenharmony_ci status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2428c2ecf20Sopenharmony_ci goto done; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci ie_set = (const struct qlink_tlv_ie_set *)tlv; 2468c2ecf20Sopenharmony_ci ie_len = tlv_value_len - 2478c2ecf20Sopenharmony_ci (sizeof(*ie_set) - sizeof(ie_set->hdr)); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci switch (ie_set->type) { 2508c2ecf20Sopenharmony_ci case QLINK_IE_SET_ASSOC_RESP: 2518c2ecf20Sopenharmony_ci if (ie_len) { 2528c2ecf20Sopenharmony_ci rsp_ies = ie_set->ie_data; 2538c2ecf20Sopenharmony_ci rsp_ies_len = ie_len; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci default: 2578c2ecf20Sopenharmony_ci pr_warn("unexpected IE type: %u\n", 2588c2ecf20Sopenharmony_ci ie_set->type); 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (!qlink_tlv_parsing_ok(tlv, join_info->ies, payload_len)) 2658c2ecf20Sopenharmony_ci pr_warn("Malformed TLV buffer\n"); 2668c2ecf20Sopenharmony_cidone: 2678c2ecf20Sopenharmony_ci cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, rsp_ies, 2688c2ecf20Sopenharmony_ci rsp_ies_len, status, GFP_KERNEL); 2698c2ecf20Sopenharmony_ci if (bss) { 2708c2ecf20Sopenharmony_ci if (!ether_addr_equal(vif->bssid, join_info->bssid)) 2718c2ecf20Sopenharmony_ci ether_addr_copy(vif->bssid, join_info->bssid); 2728c2ecf20Sopenharmony_ci cfg80211_put_bss(wiphy, bss); 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (status == WLAN_STATUS_SUCCESS) 2768c2ecf20Sopenharmony_ci netif_carrier_on(vif->netdev); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci kfree(ie); 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int 2838c2ecf20Sopenharmony_ciqtnf_event_handle_bss_leave(struct qtnf_vif *vif, 2848c2ecf20Sopenharmony_ci const struct qlink_event_bss_leave *leave_info, 2858c2ecf20Sopenharmony_ci u16 len) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci if (unlikely(len < sizeof(*leave_info))) { 2888c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 2898c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, len, 2908c2ecf20Sopenharmony_ci sizeof(struct qlink_event_bss_leave)); 2918c2ecf20Sopenharmony_ci return -EINVAL; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { 2958c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: BSS_LEAVE event when not in STA mode\n", 2968c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid); 2978c2ecf20Sopenharmony_ci return -EPROTO; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason), 3038c2ecf20Sopenharmony_ci NULL, 0, 0, GFP_KERNEL); 3048c2ecf20Sopenharmony_ci netif_carrier_off(vif->netdev); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int 3108c2ecf20Sopenharmony_ciqtnf_event_handle_mgmt_received(struct qtnf_vif *vif, 3118c2ecf20Sopenharmony_ci const struct qlink_event_rxmgmt *rxmgmt, 3128c2ecf20Sopenharmony_ci u16 len) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci const size_t min_len = sizeof(*rxmgmt) + 3158c2ecf20Sopenharmony_ci sizeof(struct ieee80211_hdr_3addr); 3168c2ecf20Sopenharmony_ci const struct ieee80211_hdr_3addr *frame = (void *)rxmgmt->frame_data; 3178c2ecf20Sopenharmony_ci const u16 frame_len = len - sizeof(*rxmgmt); 3188c2ecf20Sopenharmony_ci enum nl80211_rxmgmt_flags flags = 0; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (unlikely(len < min_len)) { 3218c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 3228c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, len, min_len); 3238c2ecf20Sopenharmony_ci return -EINVAL; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (le32_to_cpu(rxmgmt->flags) & QLINK_RXMGMT_FLAG_ANSWERED) 3278c2ecf20Sopenharmony_ci flags |= NL80211_RXMGMT_FLAG_ANSWERED; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci pr_debug("%s LEN:%u FC:%.4X SA:%pM\n", vif->netdev->name, frame_len, 3308c2ecf20Sopenharmony_ci le16_to_cpu(frame->frame_control), frame->addr2); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci cfg80211_rx_mgmt(&vif->wdev, le32_to_cpu(rxmgmt->freq), rxmgmt->sig_dbm, 3338c2ecf20Sopenharmony_ci rxmgmt->frame_data, frame_len, flags); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int 3398c2ecf20Sopenharmony_ciqtnf_event_handle_scan_results(struct qtnf_vif *vif, 3408c2ecf20Sopenharmony_ci const struct qlink_event_scan_result *sr, 3418c2ecf20Sopenharmony_ci u16 len) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct cfg80211_bss *bss; 3448c2ecf20Sopenharmony_ci struct ieee80211_channel *channel; 3458c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(vif->mac); 3468c2ecf20Sopenharmony_ci enum cfg80211_bss_frame_type frame_type = CFG80211_BSS_FTYPE_UNKNOWN; 3478c2ecf20Sopenharmony_ci size_t payload_len; 3488c2ecf20Sopenharmony_ci u16 tlv_type; 3498c2ecf20Sopenharmony_ci u16 tlv_value_len; 3508c2ecf20Sopenharmony_ci const struct qlink_tlv_hdr *tlv; 3518c2ecf20Sopenharmony_ci const u8 *ies = NULL; 3528c2ecf20Sopenharmony_ci size_t ies_len = 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (len < sizeof(*sr)) { 3558c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: payload is too short\n", vif->mac->macid, 3568c2ecf20Sopenharmony_ci vif->vifid); 3578c2ecf20Sopenharmony_ci return -EINVAL; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci channel = ieee80211_get_channel(wiphy, le16_to_cpu(sr->freq)); 3618c2ecf20Sopenharmony_ci if (!channel) { 3628c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: channel at %u MHz not found\n", 3638c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, le16_to_cpu(sr->freq)); 3648c2ecf20Sopenharmony_ci return -EINVAL; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci payload_len = len - sizeof(*sr); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci qlink_for_each_tlv(tlv, sr->payload, payload_len) { 3708c2ecf20Sopenharmony_ci tlv_type = le16_to_cpu(tlv->type); 3718c2ecf20Sopenharmony_ci tlv_value_len = le16_to_cpu(tlv->len); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (tlv_type == QTN_TLV_ID_IE_SET) { 3748c2ecf20Sopenharmony_ci const struct qlink_tlv_ie_set *ie_set; 3758c2ecf20Sopenharmony_ci unsigned int ie_len; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (tlv_value_len < 3788c2ecf20Sopenharmony_ci (sizeof(*ie_set) - sizeof(ie_set->hdr))) 3798c2ecf20Sopenharmony_ci return -EINVAL; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ie_set = (const struct qlink_tlv_ie_set *)tlv; 3828c2ecf20Sopenharmony_ci ie_len = tlv_value_len - 3838c2ecf20Sopenharmony_ci (sizeof(*ie_set) - sizeof(ie_set->hdr)); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci switch (ie_set->type) { 3868c2ecf20Sopenharmony_ci case QLINK_IE_SET_BEACON_IES: 3878c2ecf20Sopenharmony_ci frame_type = CFG80211_BSS_FTYPE_BEACON; 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci case QLINK_IE_SET_PROBE_RESP_IES: 3908c2ecf20Sopenharmony_ci frame_type = CFG80211_BSS_FTYPE_PRESP; 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci default: 3938c2ecf20Sopenharmony_ci frame_type = CFG80211_BSS_FTYPE_UNKNOWN; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (ie_len) { 3978c2ecf20Sopenharmony_ci ies = ie_set->ie_data; 3988c2ecf20Sopenharmony_ci ies_len = ie_len; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (!qlink_tlv_parsing_ok(tlv, sr->payload, payload_len)) 4048c2ecf20Sopenharmony_ci return -EINVAL; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci bss = cfg80211_inform_bss(wiphy, channel, frame_type, 4078c2ecf20Sopenharmony_ci sr->bssid, get_unaligned_le64(&sr->tsf), 4088c2ecf20Sopenharmony_ci le16_to_cpu(sr->capab), 4098c2ecf20Sopenharmony_ci le16_to_cpu(sr->bintval), ies, ies_len, 4108c2ecf20Sopenharmony_ci DBM_TO_MBM(sr->sig_dbm), GFP_KERNEL); 4118c2ecf20Sopenharmony_ci if (!bss) 4128c2ecf20Sopenharmony_ci return -ENOMEM; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci cfg80211_put_bss(wiphy, bss); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int 4208c2ecf20Sopenharmony_ciqtnf_event_handle_scan_complete(struct qtnf_wmac *mac, 4218c2ecf20Sopenharmony_ci const struct qlink_event_scan_complete *status, 4228c2ecf20Sopenharmony_ci u16 len) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci if (len < sizeof(*status)) { 4258c2ecf20Sopenharmony_ci pr_err("MAC%u: payload is too short\n", mac->macid); 4268c2ecf20Sopenharmony_ci return -EINVAL; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci qtnf_scan_done(mac, le32_to_cpu(status->flags) & QLINK_SCAN_ABORTED); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return 0; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic int 4358c2ecf20Sopenharmony_ciqtnf_event_handle_freq_change(struct qtnf_wmac *mac, 4368c2ecf20Sopenharmony_ci const struct qlink_event_freq_change *data, 4378c2ecf20Sopenharmony_ci u16 len) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(mac); 4408c2ecf20Sopenharmony_ci struct cfg80211_chan_def chandef; 4418c2ecf20Sopenharmony_ci struct qtnf_vif *vif; 4428c2ecf20Sopenharmony_ci int i; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (len < sizeof(*data)) { 4458c2ecf20Sopenharmony_ci pr_err("MAC%u: payload is too short\n", mac->macid); 4468c2ecf20Sopenharmony_ci return -EINVAL; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (!wiphy->registered) 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci qlink_chandef_q2cfg(wiphy, &data->chan, &chandef); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (!cfg80211_chandef_valid(&chandef)) { 4558c2ecf20Sopenharmony_ci pr_err("MAC%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n", 4568c2ecf20Sopenharmony_ci mac->macid, chandef.chan->center_freq, 4578c2ecf20Sopenharmony_ci chandef.center_freq1, chandef.center_freq2, 4588c2ecf20Sopenharmony_ci chandef.width); 4598c2ecf20Sopenharmony_ci return -EINVAL; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci pr_debug("MAC%d: new channel ieee=%u freq1=%u freq2=%u bw=%u\n", 4638c2ecf20Sopenharmony_ci mac->macid, chandef.chan->hw_value, chandef.center_freq1, 4648c2ecf20Sopenharmony_ci chandef.center_freq2, chandef.width); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci for (i = 0; i < QTNF_MAX_INTF; i++) { 4678c2ecf20Sopenharmony_ci vif = &mac->iflist[i]; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) 4708c2ecf20Sopenharmony_ci continue; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (vif->wdev.iftype == NL80211_IFTYPE_STATION && 4738c2ecf20Sopenharmony_ci !vif->wdev.current_bss) 4748c2ecf20Sopenharmony_ci continue; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (!vif->netdev) 4778c2ecf20Sopenharmony_ci continue; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci mutex_lock(&vif->wdev.mtx); 4808c2ecf20Sopenharmony_ci cfg80211_ch_switch_notify(vif->netdev, &chandef); 4818c2ecf20Sopenharmony_ci mutex_unlock(&vif->wdev.mtx); 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return 0; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic int qtnf_event_handle_radar(struct qtnf_vif *vif, 4888c2ecf20Sopenharmony_ci const struct qlink_event_radar *ev, 4898c2ecf20Sopenharmony_ci u16 len) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(vif->mac); 4928c2ecf20Sopenharmony_ci struct cfg80211_chan_def chandef; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (len < sizeof(*ev)) { 4958c2ecf20Sopenharmony_ci pr_err("MAC%u: payload is too short\n", vif->mac->macid); 4968c2ecf20Sopenharmony_ci return -EINVAL; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (!wiphy->registered || !vif->netdev) 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci qlink_chandef_q2cfg(wiphy, &ev->chan, &chandef); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (!cfg80211_chandef_valid(&chandef)) { 5058c2ecf20Sopenharmony_ci pr_err("MAC%u: bad channel f1=%u f2=%u bw=%u\n", 5068c2ecf20Sopenharmony_ci vif->mac->macid, 5078c2ecf20Sopenharmony_ci chandef.center_freq1, chandef.center_freq2, 5088c2ecf20Sopenharmony_ci chandef.width); 5098c2ecf20Sopenharmony_ci return -EINVAL; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci pr_info("%s: radar event=%u f1=%u f2=%u bw=%u\n", 5138c2ecf20Sopenharmony_ci vif->netdev->name, ev->event, 5148c2ecf20Sopenharmony_ci chandef.center_freq1, chandef.center_freq2, 5158c2ecf20Sopenharmony_ci chandef.width); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci switch (ev->event) { 5188c2ecf20Sopenharmony_ci case QLINK_RADAR_DETECTED: 5198c2ecf20Sopenharmony_ci cfg80211_radar_event(wiphy, &chandef, GFP_KERNEL); 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci case QLINK_RADAR_CAC_FINISHED: 5228c2ecf20Sopenharmony_ci if (!vif->wdev.cac_started) 5238c2ecf20Sopenharmony_ci break; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci cfg80211_cac_event(vif->netdev, &chandef, 5268c2ecf20Sopenharmony_ci NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci case QLINK_RADAR_CAC_ABORTED: 5298c2ecf20Sopenharmony_ci if (!vif->wdev.cac_started) 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci cfg80211_cac_event(vif->netdev, &chandef, 5338c2ecf20Sopenharmony_ci NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci case QLINK_RADAR_CAC_STARTED: 5368c2ecf20Sopenharmony_ci if (vif->wdev.cac_started) 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (!wiphy_ext_feature_isset(wiphy, 5408c2ecf20Sopenharmony_ci NL80211_EXT_FEATURE_DFS_OFFLOAD)) 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci cfg80211_cac_event(vif->netdev, &chandef, 5448c2ecf20Sopenharmony_ci NL80211_RADAR_CAC_STARTED, GFP_KERNEL); 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci default: 5478c2ecf20Sopenharmony_ci pr_warn("%s: unhandled radar event %u\n", 5488c2ecf20Sopenharmony_ci vif->netdev->name, ev->event); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic int 5568c2ecf20Sopenharmony_ciqtnf_event_handle_external_auth(struct qtnf_vif *vif, 5578c2ecf20Sopenharmony_ci const struct qlink_event_external_auth *ev, 5588c2ecf20Sopenharmony_ci u16 len) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct cfg80211_external_auth_params auth = {0}; 5618c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(vif->mac); 5628c2ecf20Sopenharmony_ci int ret; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (len < sizeof(*ev)) { 5658c2ecf20Sopenharmony_ci pr_err("MAC%u: payload is too short\n", vif->mac->macid); 5668c2ecf20Sopenharmony_ci return -EINVAL; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (!wiphy->registered || !vif->netdev) 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (ev->ssid_len) { 5738c2ecf20Sopenharmony_ci int len = clamp_val(ev->ssid_len, 0, IEEE80211_MAX_SSID_LEN); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci memcpy(auth.ssid.ssid, ev->ssid, len); 5768c2ecf20Sopenharmony_ci auth.ssid.ssid_len = len; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci auth.key_mgmt_suite = le32_to_cpu(ev->akm_suite); 5808c2ecf20Sopenharmony_ci ether_addr_copy(auth.bssid, ev->bssid); 5818c2ecf20Sopenharmony_ci auth.action = ev->action; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci pr_debug("%s: external SAE processing: bss=%pM action=%u akm=%u\n", 5848c2ecf20Sopenharmony_ci vif->netdev->name, auth.bssid, auth.action, 5858c2ecf20Sopenharmony_ci auth.key_mgmt_suite); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci ret = cfg80211_external_auth_request(vif->netdev, &auth, GFP_KERNEL); 5888c2ecf20Sopenharmony_ci if (ret) 5898c2ecf20Sopenharmony_ci pr_warn("failed to offload external auth request\n"); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return ret; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic int 5958c2ecf20Sopenharmony_ciqtnf_event_handle_mic_failure(struct qtnf_vif *vif, 5968c2ecf20Sopenharmony_ci const struct qlink_event_mic_failure *mic_ev, 5978c2ecf20Sopenharmony_ci u16 len) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(vif->mac); 6008c2ecf20Sopenharmony_ci u8 pairwise; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (len < sizeof(*mic_ev)) { 6038c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 6048c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, len, 6058c2ecf20Sopenharmony_ci sizeof(struct qlink_event_mic_failure)); 6068c2ecf20Sopenharmony_ci return -EINVAL; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (!wiphy->registered || !vif->netdev) 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { 6138c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: MIC_FAILURE event when not in STA mode\n", 6148c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid); 6158c2ecf20Sopenharmony_ci return -EPROTO; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci pairwise = mic_ev->pairwise ? 6198c2ecf20Sopenharmony_ci NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci pr_info("%s: MIC error: src=%pM key_index=%u pairwise=%u\n", 6228c2ecf20Sopenharmony_ci vif->netdev->name, mic_ev->src, mic_ev->key_index, pairwise); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci cfg80211_michael_mic_failure(vif->netdev, mic_ev->src, pairwise, 6258c2ecf20Sopenharmony_ci mic_ev->key_index, NULL, GFP_KERNEL); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int 6318c2ecf20Sopenharmony_ciqtnf_event_handle_update_owe(struct qtnf_vif *vif, 6328c2ecf20Sopenharmony_ci const struct qlink_event_update_owe *owe_ev, 6338c2ecf20Sopenharmony_ci u16 len) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct wiphy *wiphy = priv_to_wiphy(vif->mac); 6368c2ecf20Sopenharmony_ci struct cfg80211_update_owe_info owe_info = {}; 6378c2ecf20Sopenharmony_ci const u16 ie_len = len - sizeof(*owe_ev); 6388c2ecf20Sopenharmony_ci u8 *ie; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (len < sizeof(*owe_ev)) { 6418c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", 6428c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid, len, 6438c2ecf20Sopenharmony_ci sizeof(struct qlink_event_update_owe)); 6448c2ecf20Sopenharmony_ci return -EINVAL; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (!wiphy->registered || !vif->netdev) 6488c2ecf20Sopenharmony_ci return 0; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (vif->wdev.iftype != NL80211_IFTYPE_AP) { 6518c2ecf20Sopenharmony_ci pr_err("VIF%u.%u: UPDATE_OWE event when not in AP mode\n", 6528c2ecf20Sopenharmony_ci vif->mac->macid, vif->vifid); 6538c2ecf20Sopenharmony_ci return -EPROTO; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci ie = kzalloc(ie_len, GFP_KERNEL); 6578c2ecf20Sopenharmony_ci if (!ie) 6588c2ecf20Sopenharmony_ci return -ENOMEM; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci memcpy(owe_info.peer, owe_ev->peer, ETH_ALEN); 6618c2ecf20Sopenharmony_ci memcpy(ie, owe_ev->ies, ie_len); 6628c2ecf20Sopenharmony_ci owe_info.ie_len = ie_len; 6638c2ecf20Sopenharmony_ci owe_info.ie = ie; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci pr_info("%s: external OWE processing: peer=%pM\n", 6668c2ecf20Sopenharmony_ci vif->netdev->name, owe_ev->peer); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci cfg80211_update_owe_info_event(vif->netdev, &owe_info, GFP_KERNEL); 6698c2ecf20Sopenharmony_ci kfree(ie); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return 0; 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic int qtnf_event_parse(struct qtnf_wmac *mac, 6758c2ecf20Sopenharmony_ci const struct sk_buff *event_skb) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci const struct qlink_event *event; 6788c2ecf20Sopenharmony_ci struct qtnf_vif *vif = NULL; 6798c2ecf20Sopenharmony_ci int ret = -1; 6808c2ecf20Sopenharmony_ci u16 event_id; 6818c2ecf20Sopenharmony_ci u16 event_len; 6828c2ecf20Sopenharmony_ci u8 vifid; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci event = (const struct qlink_event *)event_skb->data; 6858c2ecf20Sopenharmony_ci event_id = le16_to_cpu(event->event_id); 6868c2ecf20Sopenharmony_ci event_len = le16_to_cpu(event->mhdr.len); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (event->vifid >= QTNF_MAX_INTF) { 6898c2ecf20Sopenharmony_ci pr_err("invalid vif(%u)\n", event->vifid); 6908c2ecf20Sopenharmony_ci return -EINVAL; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci vifid = array_index_nospec(event->vifid, QTNF_MAX_INTF); 6948c2ecf20Sopenharmony_ci vif = &mac->iflist[vifid]; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci switch (event_id) { 6978c2ecf20Sopenharmony_ci case QLINK_EVENT_STA_ASSOCIATED: 6988c2ecf20Sopenharmony_ci ret = qtnf_event_handle_sta_assoc(mac, vif, (const void *)event, 6998c2ecf20Sopenharmony_ci event_len); 7008c2ecf20Sopenharmony_ci break; 7018c2ecf20Sopenharmony_ci case QLINK_EVENT_STA_DEAUTH: 7028c2ecf20Sopenharmony_ci ret = qtnf_event_handle_sta_deauth(mac, vif, 7038c2ecf20Sopenharmony_ci (const void *)event, 7048c2ecf20Sopenharmony_ci event_len); 7058c2ecf20Sopenharmony_ci break; 7068c2ecf20Sopenharmony_ci case QLINK_EVENT_MGMT_RECEIVED: 7078c2ecf20Sopenharmony_ci ret = qtnf_event_handle_mgmt_received(vif, (const void *)event, 7088c2ecf20Sopenharmony_ci event_len); 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci case QLINK_EVENT_SCAN_RESULTS: 7118c2ecf20Sopenharmony_ci ret = qtnf_event_handle_scan_results(vif, (const void *)event, 7128c2ecf20Sopenharmony_ci event_len); 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci case QLINK_EVENT_SCAN_COMPLETE: 7158c2ecf20Sopenharmony_ci ret = qtnf_event_handle_scan_complete(mac, (const void *)event, 7168c2ecf20Sopenharmony_ci event_len); 7178c2ecf20Sopenharmony_ci break; 7188c2ecf20Sopenharmony_ci case QLINK_EVENT_BSS_JOIN: 7198c2ecf20Sopenharmony_ci ret = qtnf_event_handle_bss_join(vif, (const void *)event, 7208c2ecf20Sopenharmony_ci event_len); 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci case QLINK_EVENT_BSS_LEAVE: 7238c2ecf20Sopenharmony_ci ret = qtnf_event_handle_bss_leave(vif, (const void *)event, 7248c2ecf20Sopenharmony_ci event_len); 7258c2ecf20Sopenharmony_ci break; 7268c2ecf20Sopenharmony_ci case QLINK_EVENT_FREQ_CHANGE: 7278c2ecf20Sopenharmony_ci ret = qtnf_event_handle_freq_change(mac, (const void *)event, 7288c2ecf20Sopenharmony_ci event_len); 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci case QLINK_EVENT_RADAR: 7318c2ecf20Sopenharmony_ci ret = qtnf_event_handle_radar(vif, (const void *)event, 7328c2ecf20Sopenharmony_ci event_len); 7338c2ecf20Sopenharmony_ci break; 7348c2ecf20Sopenharmony_ci case QLINK_EVENT_EXTERNAL_AUTH: 7358c2ecf20Sopenharmony_ci ret = qtnf_event_handle_external_auth(vif, (const void *)event, 7368c2ecf20Sopenharmony_ci event_len); 7378c2ecf20Sopenharmony_ci break; 7388c2ecf20Sopenharmony_ci case QLINK_EVENT_MIC_FAILURE: 7398c2ecf20Sopenharmony_ci ret = qtnf_event_handle_mic_failure(vif, (const void *)event, 7408c2ecf20Sopenharmony_ci event_len); 7418c2ecf20Sopenharmony_ci break; 7428c2ecf20Sopenharmony_ci case QLINK_EVENT_UPDATE_OWE: 7438c2ecf20Sopenharmony_ci ret = qtnf_event_handle_update_owe(vif, (const void *)event, 7448c2ecf20Sopenharmony_ci event_len); 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci default: 7478c2ecf20Sopenharmony_ci pr_warn("unknown event type: %x\n", event_id); 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return ret; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int qtnf_event_process_skb(struct qtnf_bus *bus, 7558c2ecf20Sopenharmony_ci const struct sk_buff *skb) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci const struct qlink_event *event; 7588c2ecf20Sopenharmony_ci struct qtnf_wmac *mac; 7598c2ecf20Sopenharmony_ci int res; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (unlikely(!skb || skb->len < sizeof(*event))) { 7628c2ecf20Sopenharmony_ci pr_err("invalid event buffer\n"); 7638c2ecf20Sopenharmony_ci return -EINVAL; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci event = (struct qlink_event *)skb->data; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci mac = qtnf_core_get_mac(bus, event->macid); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci pr_debug("new event id:%x len:%u mac:%u vif:%u\n", 7718c2ecf20Sopenharmony_ci le16_to_cpu(event->event_id), le16_to_cpu(event->mhdr.len), 7728c2ecf20Sopenharmony_ci event->macid, event->vifid); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (unlikely(!mac)) 7758c2ecf20Sopenharmony_ci return -ENXIO; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci rtnl_lock(); 7788c2ecf20Sopenharmony_ci res = qtnf_event_parse(mac, skb); 7798c2ecf20Sopenharmony_ci rtnl_unlock(); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci return res; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_civoid qtnf_event_work_handler(struct work_struct *work) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct qtnf_bus *bus = container_of(work, struct qtnf_bus, event_work); 7878c2ecf20Sopenharmony_ci struct sk_buff_head *event_queue = &bus->trans.event_queue; 7888c2ecf20Sopenharmony_ci struct sk_buff *current_event_skb = skb_dequeue(event_queue); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci while (current_event_skb) { 7918c2ecf20Sopenharmony_ci qtnf_event_process_skb(bus, current_event_skb); 7928c2ecf20Sopenharmony_ci dev_kfree_skb_any(current_event_skb); 7938c2ecf20Sopenharmony_ci current_event_skb = skb_dequeue(event_queue); 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci} 796