From a5969cabbb4660eab42b6ef0412cbbd1200cf14d Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Sat, 12 Oct 2024 07:10:09 +0000 Subject: [PATCH] 修改led为gpio --- kernel/drivers/net/wireless/quantenna/qtnfmac/event.c | 347 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 279 insertions(+), 68 deletions(-) diff --git a/kernel/drivers/net/wireless/quantenna/qtnfmac/event.c b/kernel/drivers/net/wireless/quantenna/qtnfmac/event.c index 68da81b..8dc8057 100644 --- a/kernel/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/kernel/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -1,22 +1,10 @@ -/* - * Copyright (c) 2015-2016 Quantenna Communications, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2015-2016 Quantenna Communications. All rights reserved. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/nospec.h> #include "cfg80211.h" #include "core.h" @@ -38,7 +26,6 @@ size_t payload_len; u16 tlv_type; u16 tlv_value_len; - size_t tlv_full_len; const struct qlink_tlv_hdr *tlv; int ret = 0; @@ -71,23 +58,17 @@ sinfo->generation = vif->generation; payload_len = len - sizeof(*sta_assoc); - tlv = (const struct qlink_tlv_hdr *)sta_assoc->ies; - while (payload_len >= sizeof(*tlv)) { + qlink_for_each_tlv(tlv, sta_assoc->ies, payload_len) { tlv_type = le16_to_cpu(tlv->type); tlv_value_len = le16_to_cpu(tlv->len); - tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); - - if (tlv_full_len > payload_len) { - ret = -EINVAL; - goto out; - } if (tlv_type == QTN_TLV_ID_IE_SET) { const struct qlink_tlv_ie_set *ie_set; unsigned int ie_len; - if (payload_len < sizeof(*ie_set)) { + if (tlv_value_len < + (sizeof(*ie_set) - sizeof(ie_set->hdr))) { ret = -EINVAL; goto out; } @@ -101,12 +82,10 @@ sinfo->assoc_req_ies_len = ie_len; } } - - payload_len -= tlv_full_len; - tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); } - if (payload_len) { + if (!qlink_tlv_parsing_ok(tlv, sta_assoc->ies, payload_len)) { + pr_err("Malformed TLV buffer\n"); ret = -EINVAL; goto out; } @@ -158,6 +137,18 @@ const struct qlink_event_bss_join *join_info, u16 len) { + struct wiphy *wiphy = priv_to_wiphy(vif->mac); + enum ieee80211_statuscode status = le16_to_cpu(join_info->status); + struct cfg80211_chan_def chandef; + struct cfg80211_bss *bss = NULL; + u8 *ie = NULL; + size_t payload_len; + u16 tlv_type; + u16 tlv_value_len; + const struct qlink_tlv_hdr *tlv; + const u8 *rsp_ies = NULL; + size_t rsp_ies_len = 0; + if (unlikely(len < sizeof(*join_info))) { pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", vif->mac->macid, vif->vifid, len, @@ -171,25 +162,120 @@ return -EPROTO; } - if (vif->sta_state != QTNF_STA_CONNECTING) { - pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n", - vif->mac->macid, vif->vifid); - return -EPROTO; + pr_debug("VIF%u.%u: BSSID:%pM chan:%u status:%u\n", + vif->mac->macid, vif->vifid, join_info->bssid, + le16_to_cpu(join_info->chan.chan.center_freq), status); + + if (status != WLAN_STATUS_SUCCESS) + goto done; + + qlink_chandef_q2cfg(wiphy, &join_info->chan, &chandef); + if (!cfg80211_chandef_valid(&chandef)) { + pr_warn("MAC%u.%u: bad channel freq=%u cf1=%u cf2=%u bw=%u\n", + vif->mac->macid, vif->vifid, + chandef.chan ? chandef.chan->center_freq : 0, + chandef.center_freq1, + chandef.center_freq2, + chandef.width); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto done; } - pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid, - join_info->bssid); + bss = cfg80211_get_bss(wiphy, chandef.chan, join_info->bssid, + NULL, 0, IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); + if (!bss) { + pr_warn("VIF%u.%u: add missing BSS:%pM chan:%u\n", + vif->mac->macid, vif->vifid, + join_info->bssid, chandef.chan->hw_value); - cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL, - 0, le16_to_cpu(join_info->status), GFP_KERNEL); + if (!vif->wdev.ssid_len) { + pr_warn("VIF%u.%u: SSID unknown for BSS:%pM\n", + vif->mac->macid, vif->vifid, + join_info->bssid); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto done; + } - if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) { - vif->sta_state = QTNF_STA_CONNECTED; + ie = kzalloc(2 + vif->wdev.ssid_len, GFP_KERNEL); + if (!ie) { + pr_warn("VIF%u.%u: IE alloc failed for BSS:%pM\n", + vif->mac->macid, vif->vifid, + join_info->bssid); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto done; + } + + ie[0] = WLAN_EID_SSID; + ie[1] = vif->wdev.ssid_len; + memcpy(ie + 2, vif->wdev.ssid, vif->wdev.ssid_len); + + bss = cfg80211_inform_bss(wiphy, chandef.chan, + CFG80211_BSS_FTYPE_UNKNOWN, + join_info->bssid, 0, + WLAN_CAPABILITY_ESS, 100, + ie, 2 + vif->wdev.ssid_len, + 0, GFP_KERNEL); + if (!bss) { + pr_warn("VIF%u.%u: can't connect to unknown BSS: %pM\n", + vif->mac->macid, vif->vifid, + join_info->bssid); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto done; + } + } + + payload_len = len - sizeof(*join_info); + + qlink_for_each_tlv(tlv, join_info->ies, payload_len) { + tlv_type = le16_to_cpu(tlv->type); + tlv_value_len = le16_to_cpu(tlv->len); + + if (tlv_type == QTN_TLV_ID_IE_SET) { + const struct qlink_tlv_ie_set *ie_set; + unsigned int ie_len; + + if (tlv_value_len < + (sizeof(*ie_set) - sizeof(ie_set->hdr))) { + pr_warn("invalid IE_SET TLV\n"); + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + goto done; + } + + ie_set = (const struct qlink_tlv_ie_set *)tlv; + ie_len = tlv_value_len - + (sizeof(*ie_set) - sizeof(ie_set->hdr)); + + switch (ie_set->type) { + case QLINK_IE_SET_ASSOC_RESP: + if (ie_len) { + rsp_ies = ie_set->ie_data; + rsp_ies_len = ie_len; + } + break; + default: + pr_warn("unexpected IE type: %u\n", + ie_set->type); + break; + } + } + } + + if (!qlink_tlv_parsing_ok(tlv, join_info->ies, payload_len)) + pr_warn("Malformed TLV buffer\n"); +done: + cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, rsp_ies, + rsp_ies_len, status, GFP_KERNEL); + if (bss) { + if (!ether_addr_equal(vif->bssid, join_info->bssid)) + ether_addr_copy(vif->bssid, join_info->bssid); + cfg80211_put_bss(wiphy, bss); + } + + if (status == WLAN_STATUS_SUCCESS) netif_carrier_on(vif->netdev); - } else { - vif->sta_state = QTNF_STA_DISCONNECTED; - } + kfree(ie); return 0; } @@ -211,16 +297,10 @@ return -EPROTO; } - if (vif->sta_state != QTNF_STA_CONNECTED) - pr_warn("VIF%u.%u: BSS_LEAVE event when STA is not connected\n", - vif->mac->macid, vif->vifid); - pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid); cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason), NULL, 0, 0, GFP_KERNEL); - - vif->sta_state = QTNF_STA_DISCONNECTED; netif_carrier_off(vif->netdev); return 0; @@ -267,7 +347,6 @@ size_t payload_len; u16 tlv_type; u16 tlv_value_len; - size_t tlv_full_len; const struct qlink_tlv_hdr *tlv; const u8 *ies = NULL; size_t ies_len = 0; @@ -286,21 +365,17 @@ } payload_len = len - sizeof(*sr); - tlv = (struct qlink_tlv_hdr *)sr->payload; - while (payload_len >= sizeof(struct qlink_tlv_hdr)) { + qlink_for_each_tlv(tlv, sr->payload, payload_len) { tlv_type = le16_to_cpu(tlv->type); tlv_value_len = le16_to_cpu(tlv->len); - tlv_full_len = tlv_value_len + sizeof(struct qlink_tlv_hdr); - - if (tlv_full_len > payload_len) - return -EINVAL; if (tlv_type == QTN_TLV_ID_IE_SET) { const struct qlink_tlv_ie_set *ie_set; unsigned int ie_len; - if (payload_len < sizeof(*ie_set)) + if (tlv_value_len < + (sizeof(*ie_set) - sizeof(ie_set->hdr))) return -EINVAL; ie_set = (const struct qlink_tlv_ie_set *)tlv; @@ -323,12 +398,9 @@ ies_len = ie_len; } } - - payload_len -= tlv_full_len; - tlv = (struct qlink_tlv_hdr *)(tlv->val + tlv_value_len); } - if (payload_len) + if (!qlink_tlv_parsing_ok(tlv, sr->payload, payload_len)) return -EINVAL; bss = cfg80211_inform_bss(wiphy, channel, frame_type, @@ -393,14 +465,20 @@ for (i = 0; i < QTNF_MAX_INTF; i++) { vif = &mac->iflist[i]; + if (vif->wdev.iftype == NL80211_IFTYPE_UNSPECIFIED) continue; - if (vif->netdev) { - mutex_lock(&vif->wdev.mtx); - cfg80211_ch_switch_notify(vif->netdev, &chandef); - mutex_unlock(&vif->wdev.mtx); - } + if (vif->wdev.iftype == NL80211_IFTYPE_STATION && + !vif->wdev.current_bss) + continue; + + if (!vif->netdev) + continue; + + mutex_lock(&vif->wdev.mtx); + cfg80211_ch_switch_notify(vif->netdev, &chandef); + mutex_unlock(&vif->wdev.mtx); } return 0; @@ -474,6 +552,125 @@ return 0; } +static int +qtnf_event_handle_external_auth(struct qtnf_vif *vif, + const struct qlink_event_external_auth *ev, + u16 len) +{ + struct cfg80211_external_auth_params auth = {0}; + struct wiphy *wiphy = priv_to_wiphy(vif->mac); + int ret; + + if (len < sizeof(*ev)) { + pr_err("MAC%u: payload is too short\n", vif->mac->macid); + return -EINVAL; + } + + if (!wiphy->registered || !vif->netdev) + return 0; + + if (ev->ssid_len) { + int len = clamp_val(ev->ssid_len, 0, IEEE80211_MAX_SSID_LEN); + + memcpy(auth.ssid.ssid, ev->ssid, len); + auth.ssid.ssid_len = len; + } + + auth.key_mgmt_suite = le32_to_cpu(ev->akm_suite); + ether_addr_copy(auth.bssid, ev->bssid); + auth.action = ev->action; + + pr_debug("%s: external SAE processing: bss=%pM action=%u akm=%u\n", + vif->netdev->name, auth.bssid, auth.action, + auth.key_mgmt_suite); + + ret = cfg80211_external_auth_request(vif->netdev, &auth, GFP_KERNEL); + if (ret) + pr_warn("failed to offload external auth request\n"); + + return ret; +} + +static int +qtnf_event_handle_mic_failure(struct qtnf_vif *vif, + const struct qlink_event_mic_failure *mic_ev, + u16 len) +{ + struct wiphy *wiphy = priv_to_wiphy(vif->mac); + u8 pairwise; + + if (len < sizeof(*mic_ev)) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + vif->mac->macid, vif->vifid, len, + sizeof(struct qlink_event_mic_failure)); + return -EINVAL; + } + + if (!wiphy->registered || !vif->netdev) + return 0; + + if (vif->wdev.iftype != NL80211_IFTYPE_STATION) { + pr_err("VIF%u.%u: MIC_FAILURE event when not in STA mode\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + pairwise = mic_ev->pairwise ? + NL80211_KEYTYPE_PAIRWISE : NL80211_KEYTYPE_GROUP; + + pr_info("%s: MIC error: src=%pM key_index=%u pairwise=%u\n", + vif->netdev->name, mic_ev->src, mic_ev->key_index, pairwise); + + cfg80211_michael_mic_failure(vif->netdev, mic_ev->src, pairwise, + mic_ev->key_index, NULL, GFP_KERNEL); + + return 0; +} + +static int +qtnf_event_handle_update_owe(struct qtnf_vif *vif, + const struct qlink_event_update_owe *owe_ev, + u16 len) +{ + struct wiphy *wiphy = priv_to_wiphy(vif->mac); + struct cfg80211_update_owe_info owe_info = {}; + const u16 ie_len = len - sizeof(*owe_ev); + u8 *ie; + + if (len < sizeof(*owe_ev)) { + pr_err("VIF%u.%u: payload is too short (%u < %zu)\n", + vif->mac->macid, vif->vifid, len, + sizeof(struct qlink_event_update_owe)); + return -EINVAL; + } + + if (!wiphy->registered || !vif->netdev) + return 0; + + if (vif->wdev.iftype != NL80211_IFTYPE_AP) { + pr_err("VIF%u.%u: UPDATE_OWE event when not in AP mode\n", + vif->mac->macid, vif->vifid); + return -EPROTO; + } + + ie = kzalloc(ie_len, GFP_KERNEL); + if (!ie) + return -ENOMEM; + + memcpy(owe_info.peer, owe_ev->peer, ETH_ALEN); + memcpy(ie, owe_ev->ies, ie_len); + owe_info.ie_len = ie_len; + owe_info.ie = ie; + + pr_info("%s: external OWE processing: peer=%pM\n", + vif->netdev->name, owe_ev->peer); + + cfg80211_update_owe_info_event(vif->netdev, &owe_info, GFP_KERNEL); + kfree(ie); + + return 0; +} + static int qtnf_event_parse(struct qtnf_wmac *mac, const struct sk_buff *event_skb) { @@ -482,17 +679,19 @@ int ret = -1; u16 event_id; u16 event_len; + u8 vifid; event = (const struct qlink_event *)event_skb->data; event_id = le16_to_cpu(event->event_id); event_len = le16_to_cpu(event->mhdr.len); - if (likely(event->vifid < QTNF_MAX_INTF)) { - vif = &mac->iflist[event->vifid]; - } else { + if (event->vifid >= QTNF_MAX_INTF) { pr_err("invalid vif(%u)\n", event->vifid); return -EINVAL; } + + vifid = array_index_nospec(event->vifid, QTNF_MAX_INTF); + vif = &mac->iflist[vifid]; switch (event_id) { case QLINK_EVENT_STA_ASSOCIATED: @@ -532,6 +731,18 @@ ret = qtnf_event_handle_radar(vif, (const void *)event, event_len); break; + case QLINK_EVENT_EXTERNAL_AUTH: + ret = qtnf_event_handle_external_auth(vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_MIC_FAILURE: + ret = qtnf_event_handle_mic_failure(vif, (const void *)event, + event_len); + break; + case QLINK_EVENT_UPDATE_OWE: + ret = qtnf_event_handle_update_owe(vif, (const void *)event, + event_len); + break; default: pr_warn("unknown event type: %x\n", event_id); break; -- Gitblit v1.6.2