mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Currently DFS works under assumption there could be only one channel context in the hardware. Hence, drivers just calls the function ieee80211_radar_detected() passing the hardware structure. However, with MLO, this obviously will not work since number of channel contexts will be more than one and hence drivers would need to pass the channel information as well on which the radar is detected. Also, when radar is detected in one of the links, other link's CAC should not be cancelled. Hence, in order to support DFS with MLO, do the following changes - * Add channel context conf pointer as an argument to the function ieee80211_radar_detected(). During MLO, drivers would have to pass on which channel context conf radar is detected. Otherwise, drivers could just pass NULL. * ieee80211_radar_detected() will iterate over all channel contexts present and * if channel context conf is passed, only mark that as radar detected * if NULL is passed, then mark all channel contexts as radar detected * Then as usual, schedule the radar detected work. * In the worker, go over all the contexts again and for all such context which is marked with radar detected, cancel the ongoing CAC by calling ieee80211_dfs_cac_cancel() and then notify cfg80211 via cfg80211_radar_event(). * To cancel the CAC, pass the channel context as well where radar is detected to ieee80211_dfs_cac_cancel(). This ensures that CAC is canceled only on the links using the provided context, leaving other links unaffected. This would also help in scenarios where there is split phy 5 GHz radio, which is capable of DFS channels in both lower and upper band. In this case, simultaneous radars can be detected. Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com> Link: https://patch.msgid.link/20240906064426.2101315-9-quic_adisi@quicinc.com Signed-off-by: Johannes Berg <johannes.berg@intel.com>
236 lines
6 KiB
C
236 lines
6 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* This file is part of wl12xx
|
|
*
|
|
* Copyright (C) 2012 Texas Instruments. All rights reserved.
|
|
*/
|
|
|
|
#include <net/genetlink.h>
|
|
#include "event.h"
|
|
#include "scan.h"
|
|
#include "conf.h"
|
|
#include "../wlcore/cmd.h"
|
|
#include "../wlcore/debug.h"
|
|
#include "../wlcore/vendor_cmd.h"
|
|
|
|
int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
|
|
bool *timeout)
|
|
{
|
|
u32 local_event;
|
|
|
|
switch (event) {
|
|
case WLCORE_EVENT_PEER_REMOVE_COMPLETE:
|
|
local_event = PEER_REMOVE_COMPLETE_EVENT_ID;
|
|
break;
|
|
|
|
case WLCORE_EVENT_DFS_CONFIG_COMPLETE:
|
|
local_event = DFS_CHANNELS_CONFIG_COMPLETE_EVENT;
|
|
break;
|
|
|
|
default:
|
|
/* event not implemented */
|
|
return 0;
|
|
}
|
|
return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
|
|
}
|
|
|
|
static const char *wl18xx_radar_type_decode(u8 radar_type)
|
|
{
|
|
switch (radar_type) {
|
|
case RADAR_TYPE_REGULAR:
|
|
return "REGULAR";
|
|
case RADAR_TYPE_CHIRP:
|
|
return "CHIRP";
|
|
case RADAR_TYPE_NONE:
|
|
default:
|
|
return "N/A";
|
|
}
|
|
}
|
|
|
|
static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel,
|
|
u8 sync_band)
|
|
{
|
|
struct sk_buff *skb;
|
|
enum nl80211_band band;
|
|
int freq;
|
|
|
|
if (sync_band == WLCORE_BAND_5GHZ)
|
|
band = NL80211_BAND_5GHZ;
|
|
else
|
|
band = NL80211_BAND_2GHZ;
|
|
|
|
freq = ieee80211_channel_to_frequency(sync_channel, band);
|
|
|
|
wl1271_debug(DEBUG_EVENT,
|
|
"SMART_CONFIG_SYNC_EVENT_ID, freq: %d (chan: %d band %d)",
|
|
freq, sync_channel, sync_band);
|
|
skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL, 20,
|
|
WLCORE_VENDOR_EVENT_SC_SYNC,
|
|
GFP_KERNEL);
|
|
|
|
if (nla_put_u32(skb, WLCORE_VENDOR_ATTR_FREQ, freq)) {
|
|
kfree_skb(skb);
|
|
return -EMSGSIZE;
|
|
}
|
|
cfg80211_vendor_event(skb, GFP_KERNEL);
|
|
return 0;
|
|
}
|
|
|
|
static int wlcore_smart_config_decode_event(struct wl1271 *wl,
|
|
u8 ssid_len, u8 *ssid,
|
|
u8 pwd_len, u8 *pwd)
|
|
{
|
|
struct sk_buff *skb;
|
|
|
|
wl1271_debug(DEBUG_EVENT, "SMART_CONFIG_DECODE_EVENT_ID");
|
|
wl1271_dump_ascii(DEBUG_EVENT, "SSID:", ssid, ssid_len);
|
|
|
|
skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL,
|
|
ssid_len + pwd_len + 20,
|
|
WLCORE_VENDOR_EVENT_SC_DECODE,
|
|
GFP_KERNEL);
|
|
|
|
if (nla_put(skb, WLCORE_VENDOR_ATTR_SSID, ssid_len, ssid) ||
|
|
nla_put(skb, WLCORE_VENDOR_ATTR_PSK, pwd_len, pwd)) {
|
|
kfree_skb(skb);
|
|
return -EMSGSIZE;
|
|
}
|
|
cfg80211_vendor_event(skb, GFP_KERNEL);
|
|
return 0;
|
|
}
|
|
|
|
static void wlcore_event_time_sync(struct wl1271 *wl,
|
|
u16 tsf_high_msb, u16 tsf_high_lsb,
|
|
u16 tsf_low_msb, u16 tsf_low_lsb)
|
|
{
|
|
u32 clock_low;
|
|
u32 clock_high;
|
|
|
|
clock_high = (tsf_high_msb << 16) | tsf_high_lsb;
|
|
clock_low = (tsf_low_msb << 16) | tsf_low_lsb;
|
|
|
|
wl1271_info("TIME_SYNC_EVENT_ID: clock_high %u, clock low %u",
|
|
clock_high, clock_low);
|
|
}
|
|
|
|
int wl18xx_process_mailbox_events(struct wl1271 *wl)
|
|
{
|
|
struct wl18xx_event_mailbox *mbox = wl->mbox;
|
|
u32 vector;
|
|
|
|
vector = le32_to_cpu(mbox->events_vector);
|
|
wl1271_debug(DEBUG_EVENT, "MBOX vector: 0x%x", vector);
|
|
|
|
if (vector & SCAN_COMPLETE_EVENT_ID) {
|
|
wl1271_debug(DEBUG_EVENT, "scan results: %d",
|
|
mbox->number_of_scan_results);
|
|
|
|
if (wl->scan_wlvif)
|
|
wl18xx_scan_completed(wl, wl->scan_wlvif);
|
|
}
|
|
|
|
if (vector & TIME_SYNC_EVENT_ID)
|
|
wlcore_event_time_sync(wl,
|
|
le16_to_cpu(mbox->time_sync_tsf_high_msb),
|
|
le16_to_cpu(mbox->time_sync_tsf_high_lsb),
|
|
le16_to_cpu(mbox->time_sync_tsf_low_msb),
|
|
le16_to_cpu(mbox->time_sync_tsf_low_lsb));
|
|
|
|
if (vector & RADAR_DETECTED_EVENT_ID) {
|
|
wl1271_info("radar event: channel %d type %s",
|
|
mbox->radar_channel,
|
|
wl18xx_radar_type_decode(mbox->radar_type));
|
|
|
|
if (!wl->radar_debug_mode)
|
|
ieee80211_radar_detected(wl->hw, NULL);
|
|
}
|
|
|
|
if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
|
|
wl1271_debug(DEBUG_EVENT,
|
|
"PERIODIC_SCAN_REPORT_EVENT (results %d)",
|
|
mbox->number_of_sched_scan_results);
|
|
|
|
wlcore_scan_sched_scan_results(wl);
|
|
}
|
|
|
|
if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID)
|
|
wlcore_event_sched_scan_completed(wl, 1);
|
|
|
|
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID)
|
|
wlcore_event_rssi_trigger(wl, mbox->rssi_snr_trigger_metric);
|
|
|
|
if (vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)
|
|
wlcore_event_ba_rx_constraint(wl,
|
|
le16_to_cpu(mbox->rx_ba_role_id_bitmap),
|
|
le16_to_cpu(mbox->rx_ba_allowed_bitmap));
|
|
|
|
if (vector & BSS_LOSS_EVENT_ID)
|
|
wlcore_event_beacon_loss(wl,
|
|
le16_to_cpu(mbox->bss_loss_bitmap));
|
|
|
|
if (vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID)
|
|
wlcore_event_channel_switch(wl,
|
|
le16_to_cpu(mbox->channel_switch_role_id_bitmap),
|
|
true);
|
|
|
|
if (vector & DUMMY_PACKET_EVENT_ID)
|
|
wlcore_event_dummy_packet(wl);
|
|
|
|
/*
|
|
* "TX retries exceeded" has a different meaning according to mode.
|
|
* In AP mode the offending station is disconnected.
|
|
*/
|
|
if (vector & MAX_TX_FAILURE_EVENT_ID)
|
|
wlcore_event_max_tx_failure(wl,
|
|
le16_to_cpu(mbox->tx_retry_exceeded_bitmap));
|
|
|
|
if (vector & INACTIVE_STA_EVENT_ID)
|
|
wlcore_event_inactive_sta(wl,
|
|
le16_to_cpu(mbox->inactive_sta_bitmap));
|
|
|
|
if (vector & REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID)
|
|
wlcore_event_roc_complete(wl);
|
|
|
|
if (vector & SMART_CONFIG_SYNC_EVENT_ID)
|
|
wlcore_smart_config_sync_event(wl, mbox->sc_sync_channel,
|
|
mbox->sc_sync_band);
|
|
|
|
if (vector & SMART_CONFIG_DECODE_EVENT_ID)
|
|
wlcore_smart_config_decode_event(wl,
|
|
mbox->sc_ssid_len,
|
|
mbox->sc_ssid,
|
|
mbox->sc_pwd_len,
|
|
mbox->sc_pwd);
|
|
if (vector & FW_LOGGER_INDICATION)
|
|
wlcore_event_fw_logger(wl);
|
|
|
|
if (vector & RX_BA_WIN_SIZE_CHANGE_EVENT_ID) {
|
|
struct wl12xx_vif *wlvif;
|
|
struct ieee80211_vif *vif;
|
|
struct ieee80211_sta *sta;
|
|
u8 link_id = mbox->rx_ba_link_id;
|
|
u8 win_size = mbox->rx_ba_win_size;
|
|
const u8 *addr;
|
|
|
|
wlvif = wl->links[link_id].wlvif;
|
|
vif = wl12xx_wlvif_to_vif(wlvif);
|
|
|
|
/* Update RX aggregation window size and call
|
|
* MAC routine to stop active RX aggregations for this link
|
|
*/
|
|
if (wlvif->bss_type != BSS_TYPE_AP_BSS)
|
|
addr = vif->bss_conf.bssid;
|
|
else
|
|
addr = wl->links[link_id].addr;
|
|
|
|
sta = ieee80211_find_sta(vif, addr);
|
|
if (sta) {
|
|
sta->max_rx_aggregation_subframes = win_size;
|
|
ieee80211_stop_rx_ba_session(vif,
|
|
wl->links[link_id].ba_bitmap,
|
|
addr);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|