2019-09-19 14:25:41 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
|
/*
|
|
|
|
* Implementation of mac80211 API.
|
|
|
|
*
|
2020-10-07 12:19:41 +02:00
|
|
|
* Copyright (c) 2017-2020, Silicon Laboratories, Inc.
|
2019-09-19 14:25:41 +00:00
|
|
|
* Copyright (c) 2010, ST-Ericsson
|
|
|
|
*/
|
2021-03-09 15:51:56 +01:00
|
|
|
#include <linux/etherdevice.h>
|
2019-09-19 14:25:41 +00:00
|
|
|
#include <net/mac80211.h>
|
|
|
|
|
|
|
|
#include "sta.h"
|
|
|
|
#include "wfx.h"
|
2025-03-04 16:32:24 +01:00
|
|
|
#include "bus.h"
|
2021-03-09 15:51:56 +01:00
|
|
|
#include "fwio.h"
|
|
|
|
#include "bh.h"
|
|
|
|
#include "key.h"
|
2019-09-19 14:25:47 +00:00
|
|
|
#include "scan.h"
|
2021-03-09 15:51:56 +01:00
|
|
|
#include "debug.h"
|
|
|
|
#include "hif_tx.h"
|
2019-09-19 14:25:47 +00:00
|
|
|
#include "hif_tx_mib.h"
|
2019-09-19 14:25:41 +00:00
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
#define HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES 2
|
|
|
|
|
2020-04-27 15:40:20 +02:00
|
|
|
void wfx_cooling_timeout_work(struct work_struct *work)
|
|
|
|
{
|
2022-01-13 09:55:13 +01:00
|
|
|
struct wfx_dev *wdev = container_of(to_delayed_work(work), struct wfx_dev,
|
2020-04-27 15:40:20 +02:00
|
|
|
cooling_timeout_work);
|
|
|
|
|
|
|
|
wdev->chip_frozen = true;
|
|
|
|
wfx_tx_unlock(wdev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd)
|
|
|
|
{
|
|
|
|
if (cmd == STA_NOTIFY_AWAKE) {
|
2021-09-13 15:01:58 +02:00
|
|
|
/* Device recover normal temperature */
|
2020-04-27 15:40:20 +02:00
|
|
|
if (cancel_delayed_work(&wdev->cooling_timeout_work))
|
|
|
|
wfx_tx_unlock(wdev);
|
|
|
|
} else {
|
2021-09-13 15:01:58 +02:00
|
|
|
/* Device is too hot */
|
2020-04-27 15:40:20 +02:00
|
|
|
schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ);
|
|
|
|
wfx_tx_lock(wdev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-15 18:11:44 +02:00
|
|
|
static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
2022-01-13 09:55:11 +01:00
|
|
|
static const struct wfx_hif_ie_table_entry filter_ies[] = {
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
|
|
|
.ie_id = WLAN_EID_VENDOR_SPECIFIC,
|
|
|
|
.has_changed = 1,
|
|
|
|
.no_longer = 1,
|
|
|
|
.has_appeared = 1,
|
2019-10-08 09:42:58 +00:00
|
|
|
.oui = { 0x50, 0x6F, 0x9A },
|
2019-09-19 14:25:48 +00:00
|
|
|
}, {
|
|
|
|
.ie_id = WLAN_EID_HT_OPERATION,
|
|
|
|
.has_changed = 1,
|
|
|
|
.no_longer = 1,
|
|
|
|
.has_appeared = 1,
|
|
|
|
}, {
|
|
|
|
.ie_id = WLAN_EID_ERP_INFO,
|
|
|
|
.has_changed = 1,
|
|
|
|
.no_longer = 1,
|
|
|
|
.has_appeared = 1,
|
2021-09-13 15:01:41 +02:00
|
|
|
}, {
|
|
|
|
.ie_id = WLAN_EID_CHANNEL_SWITCH,
|
|
|
|
.has_changed = 1,
|
|
|
|
.no_longer = 1,
|
|
|
|
.has_appeared = 1,
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-04-15 18:11:44 +02:00
|
|
|
if (!filter_beacon) {
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_beacon_filter_control(wvif, 0, 1);
|
2019-09-19 14:25:48 +00:00
|
|
|
} else {
|
2022-01-13 09:55:13 +01:00
|
|
|
wfx_hif_set_beacon_filter_table(wvif, ARRAY_SIZE(filter_ies), filter_ies);
|
|
|
|
wfx_hif_beacon_filter_control(wvif, HIF_BEACON_FILTER_ENABLE, 0);
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
2020-04-15 18:11:44 +02:00
|
|
|
}
|
|
|
|
|
2020-05-05 14:37:55 +02:00
|
|
|
void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
|
|
|
|
unsigned int *total_flags, u64 unused)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
2020-09-07 12:14:56 +02:00
|
|
|
bool filter_bssid, filter_prbreq, filter_beacon;
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = NULL;
|
|
|
|
struct wfx_dev *wdev = hw->priv;
|
|
|
|
struct wfx_vif *wvif = NULL;
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2021-09-13 15:01:58 +02:00
|
|
|
/* Notes:
|
|
|
|
* - Probe responses (FIF_BCN_PRBRESP_PROMISC) are never filtered
|
|
|
|
* - PS-Poll (FIF_PSPOLL) are never filtered
|
|
|
|
* - RTS, CTS and Ack (FIF_CONTROL) are always filtered
|
|
|
|
* - Broken frames (FIF_FCSFAIL and FIF_PLCPFAIL) are always filtered
|
2022-01-13 09:55:14 +01:00
|
|
|
* - Firmware does (yet) allow to forward unicast traffic sent to other stations (aka.
|
|
|
|
* promiscuous mode)
|
2021-09-13 15:01:58 +02:00
|
|
|
*/
|
2020-04-15 18:11:30 +02:00
|
|
|
*total_flags &= FIF_BCN_PRBRESP_PROMISC | FIF_ALLMULTI | FIF_OTHER_BSS |
|
|
|
|
FIF_PROBE_REQ | FIF_PSPOLL;
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2023-10-04 19:28:40 +02:00
|
|
|
/* Filters are ignored during the scan. No frames are filtered. */
|
2023-10-04 19:28:41 +02:00
|
|
|
if (mutex_is_locked(&wdev->scan_lock))
|
2023-10-04 19:28:40 +02:00
|
|
|
return;
|
|
|
|
|
2020-04-10 15:32:21 +02:00
|
|
|
mutex_lock(&wdev->conf_mutex);
|
2019-09-19 14:25:48 +00:00
|
|
|
while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
|
2021-09-13 15:01:58 +02:00
|
|
|
/* Note: FIF_BCN_PRBRESP_PROMISC covers probe response and
|
|
|
|
* beacons from other BSS
|
|
|
|
*/
|
2020-04-15 18:11:30 +02:00
|
|
|
if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
|
2020-04-15 18:11:44 +02:00
|
|
|
filter_beacon = false;
|
2020-04-15 18:11:30 +02:00
|
|
|
else
|
2020-04-15 18:11:44 +02:00
|
|
|
filter_beacon = true;
|
|
|
|
wfx_filter_beacon(wvif, filter_beacon);
|
2020-04-15 18:11:30 +02:00
|
|
|
|
|
|
|
if (*total_flags & FIF_OTHER_BSS)
|
2020-04-15 18:11:43 +02:00
|
|
|
filter_bssid = false;
|
2020-04-15 18:11:30 +02:00
|
|
|
else
|
2020-04-15 18:11:43 +02:00
|
|
|
filter_bssid = true;
|
2020-04-15 18:11:30 +02:00
|
|
|
|
2022-05-06 13:00:46 -04:00
|
|
|
vif = wvif_to_vif(wvif);
|
2021-09-13 15:01:58 +02:00
|
|
|
/* In AP mode, chip can reply to probe request itself */
|
2022-05-06 13:00:46 -04:00
|
|
|
if (*total_flags & FIF_PROBE_REQ && vif->type == NL80211_IFTYPE_AP) {
|
2020-04-15 18:11:37 +02:00
|
|
|
dev_dbg(wdev->dev, "do not forward probe request in AP mode\n");
|
|
|
|
*total_flags &= ~FIF_PROBE_REQ;
|
|
|
|
}
|
|
|
|
|
2020-04-15 18:11:30 +02:00
|
|
|
if (*total_flags & FIF_PROBE_REQ)
|
2020-04-15 18:11:43 +02:00
|
|
|
filter_prbreq = false;
|
2020-04-15 18:11:30 +02:00
|
|
|
else
|
2020-04-15 18:11:43 +02:00
|
|
|
filter_prbreq = true;
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_rx_filter(wvif, filter_bssid, filter_prbreq);
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
2020-04-10 15:32:21 +02:00
|
|
|
mutex_unlock(&wdev->conf_mutex);
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
2020-06-09 14:24:14 -07:00
|
|
|
static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps)
|
2019-12-17 16:15:11 +00:00
|
|
|
{
|
2020-01-15 13:55:02 +00:00
|
|
|
struct ieee80211_channel *chan0 = NULL, *chan1 = NULL;
|
2020-05-26 19:18:17 +02:00
|
|
|
struct ieee80211_conf *conf = &wvif->wdev->hw->conf;
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = wvif_to_vif(wvif);
|
2019-12-17 16:15:11 +00:00
|
|
|
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
WARN(!vif->cfg.assoc && enable_ps,
|
2020-05-26 19:18:17 +02:00
|
|
|
"enable_ps is reliable only if associated");
|
2022-05-06 13:00:46 -04:00
|
|
|
if (wdev_to_wvif(wvif->wdev, 0)) {
|
|
|
|
struct wfx_vif *wvif_ch0 = wdev_to_wvif(wvif->wdev, 0);
|
|
|
|
struct ieee80211_vif *vif_ch0 = wvif_to_vif(wvif_ch0);
|
|
|
|
|
wifi: mac80211: introduce 'channel request'
For channel contexts, mac80211 currently uses the cfg80211
chandef struct (control channel, center freq(s), width) to
define towards drivers and internally how these behave. In
fact, there are _two_ such structs used, where the min_def
can reduce bandwidth according to the stations connected.
Unfortunately, with EHT this is longer be sufficient, at
least not for all hardware. EHT requires that non-AP STAs
that are connected to an AP with a lower bandwidth than it
(the AP) advertises (e.g. 160 MHz STA connected to 320 MHz
AP) still be able to receive downlink OFDMA and respond to
trigger frames for uplink OFDMA that specify the position
and bandwidth for the non-AP STA relative to the channel
the AP is using. Therefore, they need to be aware of this,
and at least for some hardware (e.g. Intel) this awareness
is in the hardware. As a result, use of the "same" channel
may need to be split over two channel contexts where they
differ by the AP being used.
As a first step, introduce a concept of a channel request
('chanreq') for each interface, to control the context it
requests. This step does nothing but reorganise the code,
so that later the AP's chandef can be added to the request
in order to handle the EHT case described above.
Link: https://msgid.link/20240129194108.2e88e48bd2e9.I4256183debe975c5ed71621611206fdbb69ba330@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-01-29 19:34:40 +01:00
|
|
|
chan0 = vif_ch0->bss_conf.chanreq.oper.chan;
|
2022-05-06 13:00:46 -04:00
|
|
|
}
|
|
|
|
if (wdev_to_wvif(wvif->wdev, 1)) {
|
|
|
|
struct wfx_vif *wvif_ch1 = wdev_to_wvif(wvif->wdev, 1);
|
|
|
|
struct ieee80211_vif *vif_ch1 = wvif_to_vif(wvif_ch1);
|
|
|
|
|
wifi: mac80211: introduce 'channel request'
For channel contexts, mac80211 currently uses the cfg80211
chandef struct (control channel, center freq(s), width) to
define towards drivers and internally how these behave. In
fact, there are _two_ such structs used, where the min_def
can reduce bandwidth according to the stations connected.
Unfortunately, with EHT this is longer be sufficient, at
least not for all hardware. EHT requires that non-AP STAs
that are connected to an AP with a lower bandwidth than it
(the AP) advertises (e.g. 160 MHz STA connected to 320 MHz
AP) still be able to receive downlink OFDMA and respond to
trigger frames for uplink OFDMA that specify the position
and bandwidth for the non-AP STA relative to the channel
the AP is using. Therefore, they need to be aware of this,
and at least for some hardware (e.g. Intel) this awareness
is in the hardware. As a result, use of the "same" channel
may need to be split over two channel contexts where they
differ by the AP being used.
As a first step, introduce a concept of a channel request
('chanreq') for each interface, to control the context it
requests. This step does nothing but reorganise the code,
so that later the AP's chandef can be added to the request
in order to handle the EHT case described above.
Link: https://msgid.link/20240129194108.2e88e48bd2e9.I4256183debe975c5ed71621611206fdbb69ba330@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2024-01-29 19:34:40 +01:00
|
|
|
chan1 = vif_ch1->bss_conf.chanreq.oper.chan;
|
2022-05-06 13:00:46 -04:00
|
|
|
}
|
|
|
|
if (chan0 && chan1 && vif->type != NL80211_IFTYPE_AP) {
|
2021-09-13 15:01:34 +02:00
|
|
|
if (chan0->hw_value == chan1->hw_value) {
|
2021-09-13 15:01:58 +02:00
|
|
|
/* It is useless to enable PS if channels are the same. */
|
2021-09-13 15:01:34 +02:00
|
|
|
if (enable_ps)
|
|
|
|
*enable_ps = false;
|
2022-06-24 15:02:16 +02:00
|
|
|
if (vif->cfg.assoc && vif->cfg.ps)
|
2021-09-13 15:01:34 +02:00
|
|
|
dev_info(wvif->wdev->dev, "ignoring requested PS mode");
|
|
|
|
return -1;
|
|
|
|
}
|
2022-01-13 09:55:14 +01:00
|
|
|
/* It is necessary to enable PS if channels are different. */
|
2021-09-14 20:01:06 +05:30
|
|
|
if (enable_ps)
|
|
|
|
*enable_ps = true;
|
2022-01-13 09:55:19 +01:00
|
|
|
if (wfx_api_older_than(wvif->wdev, 3, 2))
|
2021-09-14 20:01:06 +05:30
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return 30;
|
2019-12-17 16:15:11 +00:00
|
|
|
}
|
2020-05-26 19:18:17 +02:00
|
|
|
if (enable_ps)
|
2022-06-24 15:02:16 +02:00
|
|
|
*enable_ps = vif->cfg.ps;
|
|
|
|
if (vif->cfg.assoc && vif->cfg.ps)
|
2020-05-26 19:18:17 +02:00
|
|
|
return conf->dynamic_ps_timeout;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-07-01 17:07:06 +02:00
|
|
|
int wfx_update_pm(struct wfx_vif *wvif)
|
2020-05-26 19:18:17 +02:00
|
|
|
{
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = wvif_to_vif(wvif);
|
2020-05-26 19:18:17 +02:00
|
|
|
int ps_timeout;
|
|
|
|
bool ps;
|
|
|
|
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
if (!vif->cfg.assoc)
|
2020-05-26 19:18:17 +02:00
|
|
|
return 0;
|
|
|
|
ps_timeout = wfx_get_ps_timeout(wvif, &ps);
|
|
|
|
if (!ps)
|
|
|
|
ps_timeout = 0;
|
|
|
|
WARN_ON(ps_timeout < 0);
|
|
|
|
if (wvif->uapsd_mask)
|
|
|
|
ps_timeout = 0;
|
2019-12-17 16:15:11 +00:00
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete, TU_TO_JIFFIES(512)))
|
|
|
|
dev_warn(wvif->wdev->dev, "timeout while waiting of set_pm_mode_complete\n");
|
2022-01-13 09:55:07 +01:00
|
|
|
return wfx_hif_set_pm(wvif, ps, ps_timeout);
|
2019-12-17 16:15:11 +00:00
|
|
|
}
|
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
2022-06-24 15:40:11 +02:00
|
|
|
unsigned int link_id, u16 queue,
|
|
|
|
const struct ieee80211_tx_queue_params *params)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
|
|
|
struct wfx_dev *wdev = hw->priv;
|
2020-05-05 14:37:56 +02:00
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
2020-01-15 13:55:03 +00:00
|
|
|
int old_uapsd = wvif->uapsd_mask;
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2019-12-17 16:15:19 +00:00
|
|
|
WARN_ON(queue >= hw->queues);
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2019-12-17 16:15:19 +00:00
|
|
|
mutex_lock(&wdev->conf_mutex);
|
2019-12-17 16:15:24 +00:00
|
|
|
assign_bit(queue, &wvif->uapsd_mask, params->uapsd);
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_edca_queue_params(wvif, queue, params);
|
2022-05-06 13:00:46 -04:00
|
|
|
if (vif->type == NL80211_IFTYPE_STATION &&
|
|
|
|
old_uapsd != wvif->uapsd_mask) {
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_uapsd_info(wvif, wvif->uapsd_mask);
|
2020-01-15 13:54:38 +00:00
|
|
|
wfx_update_pm(wvif);
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
mutex_unlock(&wdev->conf_mutex);
|
2020-03-10 19:55:08 +05:30
|
|
|
return 0;
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
2025-06-15 13:53:09 +05:30
|
|
|
int wfx_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 value)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
|
|
|
struct wfx_dev *wdev = hw->priv;
|
|
|
|
struct wfx_vif *wvif = NULL;
|
|
|
|
|
|
|
|
while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_rts_threshold(wvif, value);
|
2019-09-19 14:25:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-20 18:02:59 +02:00
|
|
|
void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
|
|
|
/* RSSI: signed Q8.0, RCPI: unsigned Q7.1
|
|
|
|
* RSSI = RCPI / 2 - 110
|
|
|
|
*/
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = wvif_to_vif(wvif);
|
2019-09-19 14:25:48 +00:00
|
|
|
int rcpi_rssi;
|
|
|
|
int cqm_evt;
|
|
|
|
|
|
|
|
rcpi_rssi = raw_rcpi_rssi / 2 - 110;
|
2022-05-06 13:00:46 -04:00
|
|
|
if (rcpi_rssi <= vif->bss_conf.cqm_rssi_thold)
|
2019-09-19 14:25:48 +00:00
|
|
|
cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW;
|
|
|
|
else
|
|
|
|
cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
|
2022-05-06 13:00:46 -04:00
|
|
|
ieee80211_cqm_rssi_notify(vif, cqm_evt, rcpi_rssi, GFP_KERNEL);
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
2020-04-20 18:02:57 +02:00
|
|
|
static void wfx_beacon_loss_work(struct work_struct *work)
|
|
|
|
{
|
2022-01-13 09:55:13 +01:00
|
|
|
struct wfx_vif *wvif = container_of(to_delayed_work(work), struct wfx_vif,
|
|
|
|
beacon_loss_work);
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = wvif_to_vif(wvif);
|
|
|
|
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
2020-04-20 18:02:57 +02:00
|
|
|
|
2022-05-06 13:00:46 -04:00
|
|
|
ieee80211_beacon_loss(vif);
|
2022-01-13 09:55:13 +01:00
|
|
|
schedule_delayed_work(to_delayed_work(work), msecs_to_jiffies(bss_conf->beacon_int));
|
2020-04-20 18:02:57 +02:00
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
void wfx_set_default_unicast_key(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx)
|
2020-04-20 18:03:05 +02:00
|
|
|
{
|
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
|
|
|
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_wep_default_key_id(wvif, idx);
|
2020-04-20 18:03:05 +02:00
|
|
|
}
|
|
|
|
|
2020-05-15 10:33:17 +02:00
|
|
|
void wfx_reset(struct wfx_vif *wvif)
|
|
|
|
{
|
2020-05-15 10:33:20 +02:00
|
|
|
struct wfx_dev *wdev = wvif->wdev;
|
|
|
|
|
|
|
|
wfx_tx_lock_flush(wdev);
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_reset(wvif, false);
|
2020-05-15 10:33:17 +02:00
|
|
|
wfx_tx_policy_init(wvif);
|
2020-05-15 10:33:20 +02:00
|
|
|
if (wvif_count(wdev) <= 1)
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
|
2020-05-15 10:33:20 +02:00
|
|
|
wfx_tx_unlock(wdev);
|
2020-05-15 10:33:19 +02:00
|
|
|
wvif->join_in_progress = false;
|
2020-05-15 10:33:17 +02:00
|
|
|
cancel_delayed_work_sync(&wvif->beacon_loss_work);
|
2020-05-15 10:33:20 +02:00
|
|
|
wvif = NULL;
|
|
|
|
while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
|
|
|
|
wfx_update_pm(wvif);
|
2020-05-15 10:33:17 +02:00
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
2020-05-05 14:37:56 +02:00
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
|
|
|
struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv;
|
2019-09-19 14:25:48 +00:00
|
|
|
|
|
|
|
sta_priv->vif_id = wvif->id;
|
|
|
|
|
2020-08-25 10:58:19 +02:00
|
|
|
if (vif->type == NL80211_IFTYPE_STATION)
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_mfp(wvif, sta->mfp, sta->mfp);
|
2020-08-25 10:58:19 +02:00
|
|
|
|
2021-09-13 15:01:58 +02:00
|
|
|
/* In station mode, the firmware interprets new link-id as a TDLS peer */
|
2020-04-27 15:40:15 +02:00
|
|
|
if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
|
2020-01-15 13:55:15 +00:00
|
|
|
return 0;
|
|
|
|
sta_priv->link_id = ffz(wvif->link_id_map);
|
|
|
|
wvif->link_id_map |= BIT(sta_priv->link_id);
|
|
|
|
WARN_ON(!sta_priv->link_id);
|
2020-04-06 13:17:47 +02:00
|
|
|
WARN_ON(sta_priv->link_id >= HIF_LINK_ID_MAX);
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_map_link(wvif, false, sta->addr, sta_priv->link_id, sta->mfp);
|
2020-01-15 13:55:15 +00:00
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
2020-05-05 14:37:56 +02:00
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
|
|
|
struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv;
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2021-09-13 15:01:58 +02:00
|
|
|
/* See note in wfx_sta_add() */
|
2020-04-27 15:40:15 +02:00
|
|
|
if (!sta_priv->link_id)
|
2019-09-19 14:25:48 +00:00
|
|
|
return 0;
|
2021-09-13 15:01:58 +02:00
|
|
|
/* FIXME add a mutex? */
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_map_link(wvif, true, sta->addr, sta_priv->link_id, false);
|
2020-01-15 13:55:15 +00:00
|
|
|
wvif->link_id_map &= ~BIT(sta_priv->link_id);
|
2019-09-19 14:25:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:54:24 +00:00
|
|
|
static int wfx_upload_ap_templates(struct wfx_vif *wvif)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = wvif_to_vif(wvif);
|
2019-12-17 16:15:34 +00:00
|
|
|
struct sk_buff *skb;
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2022-06-06 14:25:54 +03:00
|
|
|
skb = ieee80211_beacon_get(wvif->wdev->hw, vif, 0);
|
2019-09-19 14:25:48 +00:00
|
|
|
if (!skb)
|
|
|
|
return -ENOMEM;
|
2022-01-13 09:55:13 +01:00
|
|
|
wfx_hif_set_template_frame(wvif, skb, HIF_TMPLT_BCN, API_RATE_INDEX_B_1MBPS);
|
2020-01-15 13:54:26 +00:00
|
|
|
dev_kfree_skb(skb);
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2022-05-06 13:00:46 -04:00
|
|
|
skb = ieee80211_proberesp_get(wvif->wdev->hw, vif);
|
2020-01-15 13:54:26 +00:00
|
|
|
if (!skb)
|
|
|
|
return -ENOMEM;
|
2022-01-13 09:55:13 +01:00
|
|
|
wfx_hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBRES, API_RATE_INDEX_B_1MBPS);
|
2019-11-02 16:59:45 +01:00
|
|
|
dev_kfree_skb(skb);
|
2019-12-17 16:15:34 +00:00
|
|
|
return 0;
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
2023-12-04 20:11:28 +03:00
|
|
|
static int wfx_set_mfp_ap(struct wfx_vif *wvif)
|
2020-08-25 10:58:17 +02:00
|
|
|
{
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = wvif_to_vif(wvif);
|
2022-06-06 14:25:54 +03:00
|
|
|
struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, vif, 0);
|
2020-08-25 10:58:17 +02:00
|
|
|
const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
|
|
|
|
const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16);
|
|
|
|
const int pairwise_cipher_suite_size = 4 / sizeof(u16);
|
|
|
|
const int akm_suite_size = 4 / sizeof(u16);
|
2024-02-02 17:42:13 +01:00
|
|
|
int ret = -EINVAL;
|
2023-12-04 20:11:28 +03:00
|
|
|
const u16 *ptr;
|
2020-08-25 10:58:17 +02:00
|
|
|
|
2023-12-04 20:11:28 +03:00
|
|
|
if (unlikely(!skb))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset,
|
|
|
|
skb->len - ieoffset);
|
2024-08-23 15:15:20 +02:00
|
|
|
if (!ptr) {
|
|
|
|
/* No RSN IE is fine in open networks */
|
|
|
|
ret = 0;
|
2024-02-02 17:42:13 +01:00
|
|
|
goto free_skb;
|
2024-08-23 15:15:20 +02:00
|
|
|
}
|
2023-12-04 20:11:28 +03:00
|
|
|
|
|
|
|
ptr += pairwise_cipher_suite_count_offset;
|
|
|
|
if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
|
2024-02-02 17:42:13 +01:00
|
|
|
goto free_skb;
|
2023-12-04 20:11:28 +03:00
|
|
|
|
|
|
|
ptr += 1 + pairwise_cipher_suite_size * *ptr;
|
|
|
|
if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
|
2024-02-02 17:42:13 +01:00
|
|
|
goto free_skb;
|
2023-12-04 20:11:28 +03:00
|
|
|
|
|
|
|
ptr += 1 + akm_suite_size * *ptr;
|
|
|
|
if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb)))
|
2024-02-02 17:42:13 +01:00
|
|
|
goto free_skb;
|
2023-12-04 20:11:28 +03:00
|
|
|
|
|
|
|
wfx_hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6));
|
2024-02-02 17:42:13 +01:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
free_skb:
|
|
|
|
dev_kfree_skb(skb);
|
|
|
|
return ret;
|
2020-08-25 10:58:17 +02:00
|
|
|
}
|
|
|
|
|
2022-06-02 15:08:16 +03:00
|
|
|
int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
2022-06-29 12:22:24 +03:00
|
|
|
struct ieee80211_bss_conf *link_conf)
|
2020-04-10 15:32:24 +02:00
|
|
|
{
|
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
2020-05-15 10:33:20 +02:00
|
|
|
struct wfx_dev *wdev = wvif->wdev;
|
2020-05-15 10:33:22 +02:00
|
|
|
int ret;
|
2020-04-10 15:32:24 +02:00
|
|
|
|
2020-05-15 10:33:20 +02:00
|
|
|
wvif = NULL;
|
|
|
|
while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
|
|
|
|
wfx_update_pm(wvif);
|
|
|
|
wvif = (struct wfx_vif *)vif->drv_priv;
|
2020-04-10 15:32:24 +02:00
|
|
|
wfx_upload_ap_templates(wvif);
|
2022-01-13 09:55:07 +01:00
|
|
|
ret = wfx_hif_start(wvif, &vif->bss_conf, wvif->channel);
|
2020-05-15 10:33:22 +02:00
|
|
|
if (ret > 0)
|
|
|
|
return -EIO;
|
2023-12-04 20:11:28 +03:00
|
|
|
return wfx_set_mfp_ap(wvif);
|
2020-04-10 15:32:24 +02:00
|
|
|
}
|
|
|
|
|
2022-06-02 15:08:16 +03:00
|
|
|
void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
2022-06-29 12:22:24 +03:00
|
|
|
struct ieee80211_bss_conf *link_conf)
|
2020-04-10 15:32:24 +02:00
|
|
|
{
|
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
2023-10-04 19:28:36 +02:00
|
|
|
struct wfx_dev *wdev = wvif->wdev;
|
2020-04-10 15:32:24 +02:00
|
|
|
|
2023-10-04 19:28:36 +02:00
|
|
|
wvif = NULL;
|
|
|
|
while ((wvif = wvif_iterate(wdev, wvif)) != NULL)
|
|
|
|
wfx_update_pm(wvif);
|
|
|
|
wvif = (struct wfx_vif *)vif->drv_priv;
|
2020-05-15 10:33:18 +02:00
|
|
|
wfx_reset(wvif);
|
2020-04-10 15:32:24 +02:00
|
|
|
}
|
|
|
|
|
2020-09-07 12:14:52 +02:00
|
|
|
static void wfx_join(struct wfx_vif *wvif)
|
|
|
|
{
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = wvif_to_vif(wvif);
|
|
|
|
struct ieee80211_bss_conf *conf = &vif->bss_conf;
|
2020-09-07 12:14:52 +02:00
|
|
|
struct cfg80211_bss *bss = NULL;
|
|
|
|
u8 ssid[IEEE80211_MAX_SSID_LEN];
|
2022-04-01 10:53:50 -04:00
|
|
|
const u8 *ssid_ie = NULL;
|
|
|
|
int ssid_len = 0;
|
2022-05-06 13:00:46 -04:00
|
|
|
int ret;
|
2020-09-07 12:14:52 +02:00
|
|
|
|
|
|
|
wfx_tx_lock_flush(wvif->wdev);
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel, conf->bssid, NULL, 0,
|
2020-09-07 12:14:52 +02:00
|
|
|
IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
if (!bss && !vif->cfg.ibss_joined) {
|
2020-09-07 12:14:52 +02:00
|
|
|
wfx_tx_unlock(wvif->wdev);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-04-01 10:53:50 -04:00
|
|
|
rcu_read_lock(); /* protect ssid_ie */
|
2020-09-07 12:14:52 +02:00
|
|
|
if (bss)
|
2022-04-01 10:53:50 -04:00
|
|
|
ssid_ie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
|
|
|
|
if (ssid_ie) {
|
|
|
|
ssid_len = ssid_ie[1];
|
|
|
|
if (ssid_len > IEEE80211_MAX_SSID_LEN)
|
|
|
|
ssid_len = IEEE80211_MAX_SSID_LEN;
|
|
|
|
memcpy(ssid, &ssid_ie[2], ssid_len);
|
2020-09-07 12:14:52 +02:00
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
cfg80211_put_bss(wvif->wdev->hw->wiphy, bss);
|
|
|
|
|
|
|
|
wvif->join_in_progress = true;
|
2022-04-01 10:53:50 -04:00
|
|
|
ret = wfx_hif_join(wvif, conf, wvif->channel, ssid, ssid_len);
|
2020-09-07 12:14:52 +02:00
|
|
|
if (ret) {
|
2022-05-06 13:00:46 -04:00
|
|
|
ieee80211_connection_loss(vif);
|
2020-09-07 12:14:52 +02:00
|
|
|
wfx_reset(wvif);
|
|
|
|
} else {
|
2022-01-13 09:55:14 +01:00
|
|
|
/* Due to beacon filtering it is possible that the AP's beacon is not known for the
|
|
|
|
* mac80211 stack. Disable filtering temporary to make sure the stack receives at
|
|
|
|
* least one
|
2020-09-07 12:14:52 +02:00
|
|
|
*/
|
|
|
|
wfx_filter_beacon(wvif, false);
|
|
|
|
}
|
|
|
|
wfx_tx_unlock(wvif->wdev);
|
|
|
|
}
|
|
|
|
|
2022-02-25 12:23:59 +01:00
|
|
|
static void wfx_join_finalize(struct wfx_vif *wvif, struct ieee80211_bss_conf *info)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = wvif_to_vif(wvif);
|
2020-09-07 12:14:53 +02:00
|
|
|
struct ieee80211_sta *sta = NULL;
|
|
|
|
int ampdu_density = 0;
|
|
|
|
bool greenfield = false;
|
|
|
|
|
2021-09-13 15:01:58 +02:00
|
|
|
rcu_read_lock(); /* protect sta */
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
if (info->bssid && !vif->cfg.ibss_joined)
|
2022-05-06 13:00:46 -04:00
|
|
|
sta = ieee80211_find_sta(vif, info->bssid);
|
mac80211: prepare sta handling for MLO support
Currently in mac80211 each STA object is represented
using sta_info datastructure with the associated
STA specific information and drivers access ieee80211_sta
part of it.
With MLO (Multi Link Operation) support being added
in 802.11be standard, though the association is logically
with a single Multi Link capable STA, at the physical level
communication can happen via different advertised
links (uniquely identified by Channel, operating class,
BSSID) and hence the need to handle multiple link
STA parameters within a composite sta_info object
called the MLD STA. The different link STA part of
MLD STA are identified using the link address which can
be same or different as the MLD STA address and unique
link id based on the link vif.
To support extension of such a model, the sta_info
datastructure is modified to hold multiple link STA
objects with link specific params currently within
sta_info moved to this new structure. Similarly this is
done for ieee80211_sta as well which will be accessed
within mac80211 as well as by drivers, hence trivial
driver changes are expected to support this.
For current non MLO supported drivers, only one link STA
is present and link information is accessed via 'deflink'
member.
For MLO drivers, we still need to define the APIs etc. to
get the correct link ID and access the correct part of
the station info.
Currently in mac80211, all link STA info are accessed directly
via deflink. These will be updated to access via link pointers
indexed by link id with MLO support patches, with link id
being 0 for non MLO supported cases.
Except for couple of macro related changes, below spatch takes
care of updating mac80211 and driver code to access to the
link STA info via deflink.
@ieee80211_sta@
struct ieee80211_sta *s;
struct sta_info *si;
identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr};
@@
(
s->
- var
+ deflink.var
|
si->sta.
- var
+ deflink.var
)
@sta_info@
struct sta_info *si;
identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth};
@@
(
si->
- var
+ deflink.var
)
Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com
[remove MLO-drivers notes from commit message, not clear yet; run spatch]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 21:11:23 +05:30
|
|
|
if (sta && sta->deflink.ht_cap.ht_supported)
|
|
|
|
ampdu_density = sta->deflink.ht_cap.ampdu_density;
|
|
|
|
if (sta && sta->deflink.ht_cap.ht_supported &&
|
2020-09-07 12:14:53 +02:00
|
|
|
!(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT))
|
mac80211: prepare sta handling for MLO support
Currently in mac80211 each STA object is represented
using sta_info datastructure with the associated
STA specific information and drivers access ieee80211_sta
part of it.
With MLO (Multi Link Operation) support being added
in 802.11be standard, though the association is logically
with a single Multi Link capable STA, at the physical level
communication can happen via different advertised
links (uniquely identified by Channel, operating class,
BSSID) and hence the need to handle multiple link
STA parameters within a composite sta_info object
called the MLD STA. The different link STA part of
MLD STA are identified using the link address which can
be same or different as the MLD STA address and unique
link id based on the link vif.
To support extension of such a model, the sta_info
datastructure is modified to hold multiple link STA
objects with link specific params currently within
sta_info moved to this new structure. Similarly this is
done for ieee80211_sta as well which will be accessed
within mac80211 as well as by drivers, hence trivial
driver changes are expected to support this.
For current non MLO supported drivers, only one link STA
is present and link information is accessed via 'deflink'
member.
For MLO drivers, we still need to define the APIs etc. to
get the correct link ID and access the correct part of
the station info.
Currently in mac80211, all link STA info are accessed directly
via deflink. These will be updated to access via link pointers
indexed by link id with MLO support patches, with link id
being 0 for non MLO supported cases.
Except for couple of macro related changes, below spatch takes
care of updating mac80211 and driver code to access to the
link STA info via deflink.
@ieee80211_sta@
struct ieee80211_sta *s;
struct sta_info *si;
identifier var = {supp_rates, ht_cap, vht_cap, he_cap, he_6ghz_capa, eht_cap, rx_nss, bandwidth, txpwr};
@@
(
s->
- var
+ deflink.var
|
si->sta.
- var
+ deflink.var
)
@sta_info@
struct sta_info *si;
identifier var = {gtk, pcpu_rx_stats, rx_stats, rx_stats_avg, status_stats, tx_stats, cur_max_bandwidth};
@@
(
si->
- var
+ deflink.var
)
Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Link: https://lore.kernel.org/r/1649086883-13246-1-git-send-email-quic_srirrama@quicinc.com
[remove MLO-drivers notes from commit message, not clear yet; run spatch]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-04-04 21:11:23 +05:30
|
|
|
greenfield = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
|
2020-09-07 12:14:53 +02:00
|
|
|
rcu_read_unlock();
|
|
|
|
|
2020-05-15 10:33:19 +02:00
|
|
|
wvif->join_in_progress = false;
|
2022-01-13 09:55:13 +01:00
|
|
|
wfx_hif_set_association_mode(wvif, ampdu_density, greenfield, info->use_short_preamble);
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_keep_alive_period(wvif, 0);
|
2022-01-13 09:55:14 +01:00
|
|
|
/* beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use the same value. */
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
wfx_hif_set_bss_params(wvif, vif->cfg.aid, 7);
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_beacon_wakeup_period(wvif, 1, 1);
|
2020-04-20 18:03:00 +02:00
|
|
|
wfx_update_pm(wvif);
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
2020-04-10 15:32:35 +02:00
|
|
|
int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|
|
|
{
|
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
|
|
|
|
|
|
|
wfx_upload_ap_templates(wvif);
|
2020-09-07 12:14:52 +02:00
|
|
|
wfx_join(wvif);
|
2020-04-10 15:32:35 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|
|
|
{
|
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
|
|
|
|
2020-05-15 10:33:17 +02:00
|
|
|
wfx_reset(wvif);
|
2020-04-10 15:32:35 +02:00
|
|
|
}
|
|
|
|
|
2020-05-05 14:37:52 +02:00
|
|
|
static void wfx_enable_beacon(struct wfx_vif *wvif, bool enable)
|
2020-04-01 13:04:04 +02:00
|
|
|
{
|
2022-01-13 09:55:14 +01:00
|
|
|
/* Driver has Content After DTIM Beacon in queue. Driver is waiting for a signal from the
|
|
|
|
* firmware. Since we are going to stop to send beacons, this signal will never happens. See
|
|
|
|
* also wfx_suspend_resume_mc()
|
2021-09-13 15:01:58 +02:00
|
|
|
*/
|
2020-04-01 13:04:04 +02:00
|
|
|
if (!enable && wfx_tx_queues_has_cab(wvif)) {
|
|
|
|
wvif->after_dtim_tx_allowed = true;
|
|
|
|
wfx_bh_request_tx(wvif->wdev);
|
|
|
|
}
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_beacon_transmit(wvif, enable);
|
2020-04-01 13:04:04 +02:00
|
|
|
}
|
|
|
|
|
2020-05-05 14:37:55 +02:00
|
|
|
void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
2022-05-24 10:55:56 +02:00
|
|
|
struct ieee80211_bss_conf *info, u64 changed)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
|
|
|
struct wfx_dev *wdev = hw->priv;
|
2020-05-05 14:37:56 +02:00
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
2019-09-19 14:25:48 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
mutex_lock(&wdev->conf_mutex);
|
|
|
|
|
2020-04-10 15:32:26 +02:00
|
|
|
if (changed & BSS_CHANGED_BASIC_RATES ||
|
|
|
|
changed & BSS_CHANGED_BEACON_INT ||
|
|
|
|
changed & BSS_CHANGED_BSSID) {
|
2020-04-10 15:32:35 +02:00
|
|
|
if (vif->type == NL80211_IFTYPE_STATION)
|
2020-09-07 12:14:52 +02:00
|
|
|
wfx_join(wvif);
|
2020-04-10 15:32:26 +02:00
|
|
|
}
|
|
|
|
|
2020-09-07 12:14:51 +02:00
|
|
|
if (changed & BSS_CHANGED_ASSOC) {
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
if (vif->cfg.assoc || vif->cfg.ibss_joined)
|
2020-09-07 12:14:51 +02:00
|
|
|
wfx_join_finalize(wvif, info);
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
else if (!vif->cfg.assoc && vif->type == NL80211_IFTYPE_STATION)
|
2020-09-07 12:14:51 +02:00
|
|
|
wfx_reset(wvif);
|
|
|
|
else
|
2022-01-13 09:55:18 +01:00
|
|
|
dev_warn(wdev->dev, "misunderstood change: ASSOC\n");
|
2020-09-07 12:14:51 +02:00
|
|
|
}
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2020-04-15 18:11:31 +02:00
|
|
|
if (changed & BSS_CHANGED_BEACON_INFO) {
|
|
|
|
if (vif->type != NL80211_IFTYPE_STATION)
|
2022-01-13 09:55:18 +01:00
|
|
|
dev_warn(wdev->dev, "misunderstood change: BEACON_INFO\n");
|
2022-01-13 09:55:13 +01:00
|
|
|
wfx_hif_set_beacon_wakeup_period(wvif, info->dtim_period, info->dtim_period);
|
2022-01-13 09:55:14 +01:00
|
|
|
/* We temporary forwarded beacon for join process. It is now no more necessary. */
|
2020-04-15 18:11:44 +02:00
|
|
|
wfx_filter_beacon(wvif, true);
|
2020-04-15 18:11:31 +02:00
|
|
|
}
|
2020-01-15 13:54:32 +00:00
|
|
|
|
2020-09-07 12:14:51 +02:00
|
|
|
if (changed & BSS_CHANGED_ARP_FILTER) {
|
|
|
|
for (i = 0; i < HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES; i++) {
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
__be32 *arp_addr = &vif->cfg.arp_addr_list[i];
|
2020-09-07 12:14:51 +02:00
|
|
|
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
if (vif->cfg.arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES)
|
2020-09-07 12:14:51 +02:00
|
|
|
arp_addr = NULL;
|
wifi: mac80211: move interface config to new struct
We'll use bss_conf for per-link configuration later, so
move out all the non-link-specific data out into a new
struct ieee80211_vif_cfg used in the vif.
Some adjustments were done with the following spatch:
@@
expression sdata;
struct ieee80211_vif *vifp;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
(
-sdata->vif.bss_conf.var
+sdata->vif.cfg.var
|
-vifp->bss_conf.var
+vifp->cfg.var
)
@bss_conf@
struct ieee80211_bss_conf *bss_conf;
identifier var = { assoc, ibss_joined, aid, arp_addr_list, arp_addr_cnt, ssid, ssid_len, s1g, ibss_creator };
@@
-bss_conf->var
+vif_cfg->var
(though more manual fixups were needed, e.g. replacing
"vif_cfg->" by "vif->cfg." in many files.)
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
2022-05-10 17:05:04 +02:00
|
|
|
if (i >= vif->cfg.arp_addr_cnt)
|
2020-09-07 12:14:51 +02:00
|
|
|
arp_addr = NULL;
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_arp_ipv4_filter(wvif, i, arp_addr);
|
2020-09-07 12:14:51 +02:00
|
|
|
}
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
if (changed & BSS_CHANGED_AP_PROBE_RESP || changed & BSS_CHANGED_BEACON)
|
2020-09-07 12:14:51 +02:00
|
|
|
wfx_upload_ap_templates(wvif);
|
|
|
|
|
|
|
|
if (changed & BSS_CHANGED_BEACON_ENABLED)
|
|
|
|
wfx_enable_beacon(wvif, info->enable_beacon);
|
|
|
|
|
2020-04-10 15:32:28 +02:00
|
|
|
if (changed & BSS_CHANGED_KEEP_ALIVE)
|
2022-02-25 12:23:59 +01:00
|
|
|
wfx_hif_keep_alive_period(wvif,
|
|
|
|
info->max_idle_period * USEC_PER_TU / USEC_PER_MSEC);
|
2020-04-10 15:32:28 +02:00
|
|
|
|
2020-04-10 15:32:33 +02:00
|
|
|
if (changed & BSS_CHANGED_ERP_CTS_PROT)
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_erp_use_protection(wvif, info->use_cts_prot);
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2020-04-10 15:32:32 +02:00
|
|
|
if (changed & BSS_CHANGED_ERP_SLOT)
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_slot_time(wvif, info->use_short_slot ? 9 : 20);
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2020-04-10 15:32:32 +02:00
|
|
|
if (changed & BSS_CHANGED_CQM)
|
2022-01-13 09:55:13 +01:00
|
|
|
wfx_hif_set_rcpi_rssi_threshold(wvif, info->cqm_rssi_thold, info->cqm_rssi_hyst);
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2020-01-15 13:54:21 +00:00
|
|
|
if (changed & BSS_CHANGED_TXPOWER)
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_output_power(wvif, info->txpower);
|
2020-01-15 13:55:01 +00:00
|
|
|
|
|
|
|
if (changed & BSS_CHANGED_PS)
|
|
|
|
wfx_update_pm(wvif);
|
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
mutex_unlock(&wdev->conf_mutex);
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:55:13 +00:00
|
|
|
static int wfx_update_tim(struct wfx_vif *wvif)
|
2019-09-19 14:25:45 +00:00
|
|
|
{
|
2022-05-06 13:00:46 -04:00
|
|
|
struct ieee80211_vif *vif = wvif_to_vif(wvif);
|
2019-09-19 14:25:45 +00:00
|
|
|
struct sk_buff *skb;
|
|
|
|
u16 tim_offset, tim_length;
|
|
|
|
u8 *tim_ptr;
|
|
|
|
|
2022-05-06 13:00:46 -04:00
|
|
|
skb = ieee80211_beacon_get_tim(wvif->wdev->hw, vif, &tim_offset,
|
2022-06-06 14:25:54 +03:00
|
|
|
&tim_length, 0);
|
2020-04-01 13:04:01 +02:00
|
|
|
if (!skb)
|
2019-09-19 14:25:45 +00:00
|
|
|
return -ENOENT;
|
|
|
|
tim_ptr = skb->data + tim_offset;
|
|
|
|
|
|
|
|
if (tim_offset && tim_length >= 6) {
|
2021-09-13 15:01:57 +02:00
|
|
|
/* Firmware handles DTIM counter internally */
|
2019-09-19 14:25:45 +00:00
|
|
|
tim_ptr[2] = 0;
|
|
|
|
|
|
|
|
/* Set/reset aid0 bit */
|
2020-04-01 13:03:53 +02:00
|
|
|
if (wfx_tx_queues_has_cab(wvif))
|
2019-09-19 14:25:45 +00:00
|
|
|
tim_ptr[4] |= 1;
|
|
|
|
else
|
|
|
|
tim_ptr[4] &= ~1;
|
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_update_ie_beacon(wvif, tim_ptr, tim_length);
|
2019-09-19 14:25:45 +00:00
|
|
|
dev_kfree_skb(skb);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:55:13 +00:00
|
|
|
static void wfx_update_tim_work(struct work_struct *work)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
2020-01-15 13:55:13 +00:00
|
|
|
struct wfx_vif *wvif = container_of(work, struct wfx_vif, update_tim_work);
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2020-01-15 13:55:13 +00:00
|
|
|
wfx_update_tim(wvif);
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
|
|
|
|
{
|
|
|
|
struct wfx_dev *wdev = hw->priv;
|
2020-03-15 05:49:22 +01:00
|
|
|
struct wfx_sta_priv *sta_dev = (struct wfx_sta_priv *)&sta->drv_priv;
|
2019-09-19 14:25:48 +00:00
|
|
|
struct wfx_vif *wvif = wdev_to_wvif(wdev, sta_dev->vif_id);
|
|
|
|
|
2020-10-09 19:13:02 +02:00
|
|
|
if (!wvif) {
|
|
|
|
dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__);
|
|
|
|
return -EIO;
|
|
|
|
}
|
2020-01-15 13:55:13 +00:00
|
|
|
schedule_work(&wvif->update_tim_work);
|
2019-09-19 14:25:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-15 13:55:25 +00:00
|
|
|
void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd notify_cmd)
|
2019-09-19 14:25:45 +00:00
|
|
|
{
|
2020-04-27 15:40:19 +02:00
|
|
|
if (notify_cmd != STA_NOTIFY_AWAKE)
|
|
|
|
return;
|
2021-09-13 15:01:33 +02:00
|
|
|
|
2022-01-13 09:55:14 +01:00
|
|
|
/* Device won't be able to honor CAB if a scan is in progress on any interface. Prefer to
|
|
|
|
* skip this DTIM and wait for the next one.
|
2021-09-13 15:01:33 +02:00
|
|
|
*/
|
2023-10-04 19:28:41 +02:00
|
|
|
if (mutex_is_locked(&wvif->wdev->scan_lock))
|
|
|
|
return;
|
2021-09-13 15:01:33 +02:00
|
|
|
|
2021-09-13 15:01:32 +02:00
|
|
|
if (!wfx_tx_queues_has_cab(wvif) || wvif->after_dtim_tx_allowed)
|
|
|
|
dev_warn(wvif->wdev->dev, "incorrect sequence (%d CAB in queue)",
|
|
|
|
wfx_tx_queues_has_cab(wvif));
|
2020-01-15 13:55:25 +00:00
|
|
|
wvif->after_dtim_tx_allowed = true;
|
|
|
|
wfx_bh_request_tx(wvif->wdev);
|
2019-09-19 14:25:45 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
int wfx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
2019-09-19 14:25:48 +00:00
|
|
|
struct ieee80211_ampdu_params *params)
|
|
|
|
{
|
2021-09-13 15:01:58 +02:00
|
|
|
/* Aggregation is implemented fully in firmware */
|
2020-08-25 10:58:23 +02:00
|
|
|
switch (params->action) {
|
|
|
|
case IEEE80211_AMPDU_RX_START:
|
|
|
|
case IEEE80211_AMPDU_RX_STOP:
|
2021-09-13 15:01:58 +02:00
|
|
|
/* Just acknowledge it to enable frame re-ordering */
|
2020-08-25 10:58:23 +02:00
|
|
|
return 0;
|
|
|
|
default:
|
2021-09-13 15:01:58 +02:00
|
|
|
/* Leave the firmware doing its business for tx aggregation */
|
2021-09-13 15:01:50 +02:00
|
|
|
return -EOPNOTSUPP;
|
2020-08-25 10:58:23 +02:00
|
|
|
}
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
int wfx_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
void wfx_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
void wfx_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf, u32 changed)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
2022-07-03 18:04:15 +03:00
|
|
|
struct ieee80211_bss_conf *link_conf,
|
2019-09-19 14:25:48 +00:00
|
|
|
struct ieee80211_chanctx_conf *conf)
|
|
|
|
{
|
2020-05-05 14:37:56 +02:00
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
2019-09-19 14:25:48 +00:00
|
|
|
struct ieee80211_channel *ch = conf->def.chan;
|
|
|
|
|
|
|
|
WARN(wvif->channel, "channel overwrite");
|
|
|
|
wvif->channel = ch;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-01-13 09:55:13 +01:00
|
|
|
void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
2022-07-03 18:04:15 +03:00
|
|
|
struct ieee80211_bss_conf *link_conf,
|
2019-09-19 14:25:48 +00:00
|
|
|
struct ieee80211_chanctx_conf *conf)
|
|
|
|
{
|
2020-05-05 14:37:56 +02:00
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
2019-09-19 14:25:48 +00:00
|
|
|
struct ieee80211_channel *ch = conf->def.chan;
|
|
|
|
|
|
|
|
WARN(wvif->channel != ch, "channel mismatch");
|
|
|
|
wvif->channel = NULL;
|
|
|
|
}
|
|
|
|
|
2025-06-15 13:53:09 +05:30
|
|
|
int wfx_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
|
2019-09-19 14:25:48 +00:00
|
|
|
{
|
2020-01-15 13:55:01 +00:00
|
|
|
return 0;
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
|
|
|
|
2019-09-19 14:25:41 +00:00
|
|
|
int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|
|
|
{
|
2022-02-25 12:24:00 +01:00
|
|
|
int i;
|
2019-09-19 14:25:41 +00:00
|
|
|
struct wfx_dev *wdev = hw->priv;
|
2020-05-05 14:37:56 +02:00
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
2019-09-19 14:25:41 +00:00
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
|
|
|
|
IEEE80211_VIF_SUPPORTS_UAPSD |
|
|
|
|
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
|
|
|
|
|
2019-09-19 14:25:47 +00:00
|
|
|
mutex_lock(&wdev->conf_mutex);
|
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
switch (vif->type) {
|
|
|
|
case NL80211_IFTYPE_STATION:
|
|
|
|
case NL80211_IFTYPE_ADHOC:
|
|
|
|
case NL80211_IFTYPE_AP:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mutex_unlock(&wdev->conf_mutex);
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2019-09-19 14:25:41 +00:00
|
|
|
wvif->wdev = wdev;
|
|
|
|
|
2021-09-13 15:01:58 +02:00
|
|
|
wvif->link_id_map = 1; /* link-id 0 is reserved for multicast */
|
2020-01-15 13:55:13 +00:00
|
|
|
INIT_WORK(&wvif->update_tim_work, wfx_update_tim_work);
|
2020-04-20 18:02:57 +02:00
|
|
|
INIT_DELAYED_WORK(&wvif->beacon_loss_work, wfx_beacon_loss_work);
|
2019-09-19 14:25:45 +00:00
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
init_completion(&wvif->set_pm_mode_complete);
|
|
|
|
complete(&wvif->set_pm_mode_complete);
|
2019-12-17 16:14:27 +00:00
|
|
|
INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work);
|
2019-12-17 16:15:35 +00:00
|
|
|
|
|
|
|
init_completion(&wvif->scan_complete);
|
2019-12-17 16:15:37 +00:00
|
|
|
INIT_WORK(&wvif->scan_work, wfx_hw_scan_work);
|
2023-10-04 19:28:43 +02:00
|
|
|
INIT_WORK(&wvif->remain_on_channel_work, wfx_remain_on_channel_work);
|
2019-12-17 16:15:35 +00:00
|
|
|
|
2020-08-25 10:58:24 +02:00
|
|
|
wfx_tx_queues_init(wvif);
|
|
|
|
wfx_tx_policy_init(wvif);
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) {
|
|
|
|
if (!wdev->vif[i]) {
|
|
|
|
wdev->vif[i] = vif;
|
|
|
|
wvif->id = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
WARN(i == ARRAY_SIZE(wdev->vif), "try to instantiate more vif than supported");
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_macaddr(wvif, vif->addr);
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2020-08-25 10:58:24 +02:00
|
|
|
mutex_unlock(&wdev->conf_mutex);
|
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
wvif = NULL;
|
|
|
|
while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
|
2021-09-13 15:01:58 +02:00
|
|
|
/* Combo mode does not support Block Acks. We can re-enable them */
|
2019-09-19 14:25:48 +00:00
|
|
|
if (wvif_count(wdev) == 1)
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
|
2019-09-19 14:25:48 +00:00
|
|
|
else
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_block_ack_policy(wvif, 0x00, 0x00);
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
2022-02-25 12:24:00 +01:00
|
|
|
return 0;
|
2019-09-19 14:25:41 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 14:37:55 +02:00
|
|
|
void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
2019-09-19 14:25:41 +00:00
|
|
|
{
|
2019-09-19 14:25:48 +00:00
|
|
|
struct wfx_dev *wdev = hw->priv;
|
2020-05-05 14:37:56 +02:00
|
|
|
struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv;
|
2019-09-19 14:25:48 +00:00
|
|
|
|
|
|
|
wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300));
|
2020-07-01 17:06:55 +02:00
|
|
|
wfx_tx_queues_check_empty(wvif);
|
2019-09-19 14:25:45 +00:00
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
mutex_lock(&wdev->conf_mutex);
|
2020-01-15 13:55:15 +00:00
|
|
|
WARN(wvif->link_id_map != 1, "corrupted state");
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_reset(wvif, false);
|
|
|
|
wfx_hif_set_macaddr(wvif, NULL);
|
2020-04-20 18:03:09 +02:00
|
|
|
wfx_tx_policy_init(wvif);
|
2019-09-19 14:25:48 +00:00
|
|
|
|
2020-04-20 18:02:57 +02:00
|
|
|
cancel_delayed_work_sync(&wvif->beacon_loss_work);
|
2019-09-19 14:25:48 +00:00
|
|
|
wdev->vif[wvif->id] = NULL;
|
|
|
|
|
|
|
|
mutex_unlock(&wdev->conf_mutex);
|
2020-08-25 10:58:24 +02:00
|
|
|
|
2019-09-19 14:25:48 +00:00
|
|
|
wvif = NULL;
|
|
|
|
while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
|
2021-09-13 15:01:58 +02:00
|
|
|
/* Combo mode does not support Block Acks. We can re-enable them */
|
2019-09-19 14:25:48 +00:00
|
|
|
if (wvif_count(wdev) == 1)
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_block_ack_policy(wvif, 0xFF, 0xFF);
|
2019-09-19 14:25:48 +00:00
|
|
|
else
|
2022-01-13 09:55:07 +01:00
|
|
|
wfx_hif_set_block_ack_policy(wvif, 0x00, 0x00);
|
2019-09-19 14:25:48 +00:00
|
|
|
}
|
2019-09-19 14:25:41 +00:00
|
|
|
}
|
|
|
|
|
2025-03-04 16:32:21 +01:00
|
|
|
#ifdef CONFIG_PM
|
|
|
|
int wfx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|
|
|
{
|
|
|
|
/* FIXME: hardware also support WIPHY_WOWLAN_MAGIC_PKT and other filters */
|
|
|
|
if (!wowlan->any || !wowlan->disconnect)
|
|
|
|
return -EINVAL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int wfx_resume(struct ieee80211_hw *hw)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2025-03-04 16:32:24 +01:00
|
|
|
|
|
|
|
void wfx_set_wakeup(struct ieee80211_hw *hw, bool enabled)
|
|
|
|
{
|
|
|
|
struct wfx_dev *wdev = hw->priv;
|
|
|
|
|
|
|
|
if (enabled)
|
|
|
|
dev_info(wdev->dev, "support for WoWLAN is experimental\n");
|
|
|
|
wdev->hwbus_ops->set_wakeup(wdev->hwbus_priv, enabled);
|
|
|
|
}
|
2025-03-04 16:32:21 +01:00
|
|
|
#endif
|
|
|
|
|
2019-09-19 14:25:41 +00:00
|
|
|
int wfx_start(struct ieee80211_hw *hw)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-06-18 19:25:56 +03:00
|
|
|
void wfx_stop(struct ieee80211_hw *hw, bool suspend)
|
2019-09-19 14:25:41 +00:00
|
|
|
{
|
2019-09-19 14:25:45 +00:00
|
|
|
struct wfx_dev *wdev = hw->priv;
|
|
|
|
|
2020-07-01 17:06:55 +02:00
|
|
|
WARN_ON(!skb_queue_empty_lockless(&wdev->tx_pending));
|
2019-09-19 14:25:41 +00:00
|
|
|
}
|