From: Hari Chandrakanthan When any incumbent signal is detected by an AP/mesh interface operating in 6 GHz band, FCC mandates the AP/mesh to vacate the channels affected by it [1]. Add a new API cfg80211_incumbent_signal_detect_event() that can be used by mac80211 (or full mac drivers) to notify the higher layers about the signal interference event with the interference bitmap in which each bit denotes the affected 20 MHz in the operating channel. Add support for the new nl80211 event and nl80211 attribute as well to notify userspace on the details about the interference event. Userspace is expected to process it and take further action - vacate the channel, or reduce the bandwidth. [1] - https://apps.fcc.gov/kdb/GetAttachment.html?id=nXQiRC%2B4mfiA54Zha%2BrW4Q%3D%3D&desc=987594%20D02%20U-NII%206%20GHz%20EMC%20Measurement%20v03&tracking_number=277034 Signed-off-by: Hari Chandrakanthan Signed-off-by: Amith A --- include/net/cfg80211.h | 19 ++++++++++++++++++ include/uapi/linux/nl80211.h | 19 ++++++++++++++++++ net/wireless/nl80211.c | 39 ++++++++++++++++++++++++++++++++++++ net/wireless/trace.h | 19 ++++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 4072a67c9cc9..821f96353189 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -10052,4 +10052,23 @@ ssize_t wiphy_locked_debugfs_write(struct wiphy *wiphy, struct file *file, void *data); #endif + +/** + * cfg80211_incumbent_signal_notify - Notify userspace of incumbent signal detection + * @wiphy: the wiphy to use + * @chandef: channel definition in which the interference was detected + * @signal_interference_bitmap: bitmap indicating interference across 20 MHz segments + * + * Use this function to notify userspace when an incumbent signal is detected on + * the operating channel in the 6 GHz band. The notification includes the + * current channel definition and a bitmap representing interference across + * the operating bandwidth. Each bit in the bitmap corresponds to a 20 MHz + * segment, with the lowest bit representing the lowest frequency segment. + * Punctured sub-channels are included in the bitmap structure but are always + * set to zero since interference detection is not performed on them. + */ +void cfg80211_incumbent_signal_notify(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + u32 signal_interference_bitmap); + #endif /* __NET_CFG80211_H */ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index aed0b4c5d5e8..5970357eae32 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1344,6 +1344,12 @@ * control EPCS configuration. Used to notify userland on the current state * of EPCS. * + * @NL80211_CMD_INCUMBENT_SIGNAL_DETECT: Once any incumbent signal is detected + * on the operating channel in 6 GHz band, userspace is notified with the + * signal interference bitmap using + * %NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP. The current channel + * definition is also sent. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1604,6 +1610,8 @@ enum nl80211_commands { NL80211_CMD_ASSOC_MLO_RECONF, NL80211_CMD_EPCS_CFG, + NL80211_CMD_INCUMBENT_SIGNAL_DETECT, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2936,6 +2944,15 @@ enum nl80211_commands { * indicate that it wants strict checking on the BSS parameters to be * modified. * + * @NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP: u32 attribute specifying + * the signal interference bitmap detected on the operating bandwidth for + * %NL80211_CMD_INCUMBENT_SIGNAL_DETECT. Each bit represents a 20 MHz + * segment, lowest bit corresponds to the lowest 20 MHz segment, in the + * operating bandwidth where the interference is detected. Punctured + * sub-channels are included in the bitmap structure; however, since + * interference detection is not performed on these sub-channels, their + * corresponding bits are consistently set to zero. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -3499,6 +3516,8 @@ enum nl80211_attrs { NL80211_ATTR_S1G_SHORT_BEACON, NL80211_ATTR_BSS_PARAM, + NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 99e2aadc65f7..1cd93292cf17 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -20714,6 +20714,45 @@ void cfg80211_ch_switch_notify(struct net_device *dev, } EXPORT_SYMBOL(cfg80211_ch_switch_notify); +void cfg80211_incumbent_signal_notify(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + u32 signal_interference_bitmap) +{ + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + struct sk_buff *msg; + void *hdr; + + trace_cfg80211_incumbent_signal_notify(wiphy, chandef, signal_interference_bitmap); + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_INCUMBENT_SIGNAL_DETECT); + if (!hdr) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx)) + goto nla_put_failure; + + if (nl80211_send_chandef(msg, chandef)) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP, + signal_interference_bitmap)) + goto nla_put_failure; + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0, + NL80211_MCGRP_MLME, GFP_KERNEL); + return; + +nla_put_failure: + nlmsg_free(msg); +} +EXPORT_SYMBOL(cfg80211_incumbent_signal_notify); + void cfg80211_ch_switch_started_notify(struct net_device *dev, struct cfg80211_chan_def *chandef, unsigned int link_id, u8 count, diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 9b6074155d59..eaf1a489e9c4 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -4166,6 +4166,25 @@ TRACE_EVENT(cfg80211_epcs_changed, WDEV_PR_ARG, __entry->enabled) ); +TRACE_EVENT(cfg80211_incumbent_signal_notify, + TP_PROTO(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + u32 signal_interference_bitmap), + TP_ARGS(wiphy, chandef, signal_interference_bitmap), + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_DEF_ENTRY + __field(u32, signal_interference_bitmap) + ), + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_DEF_ASSIGN(chandef); + __entry->signal_interference_bitmap = signal_interference_bitmap; + ), + TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", signal_interference_bitmap=0x%x", + WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->signal_interference_bitmap) +); + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH -- 2.34.1 From: Hari Chandrakanthan Add a new API ieee80211_incumbent_signal_detected() that can be used by wireless drivers to notify the higher layers about the interference of incumbent signals in 6 GHz band with the operating channel (mandatory to pass during MLO) and the interference bitmap in which each bit denotes the affected 20 MHz in the operating channel. Signed-off-by: Hari Chandrakanthan Co-developed-by: Aditya Kumar Singh Signed-off-by: Aditya Kumar Singh Signed-off-by: Amith A --- include/net/mac80211.h | 18 ++++++++++++++++++ net/mac80211/trace.h | 26 ++++++++++++++++++++++++++ net/mac80211/util.c | 15 +++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index a45e4bee65d4..678e58609280 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -257,6 +257,8 @@ struct ieee80211_chan_req { * after RTS/CTS handshake to receive SMPS MIMO transmissions; * this will always be >= @rx_chains_static. * @radar_enabled: whether radar detection is enabled on this channel. + * @incumbt_sig_intf_bmap: Bitmap indicating the sub-channels where an + * incumbent signal's interference was detected. * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *), size is determined in hw information. */ @@ -270,6 +272,8 @@ struct ieee80211_chanctx_conf { bool radar_enabled; + u32 incumbt_sig_intf_bmap; + u8 drv_priv[] __aligned(sizeof(void *)); }; @@ -7834,4 +7838,18 @@ int ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *hw, int n_vifs, enum ieee80211_chanctx_switch_mode mode); +/** + * ieee80211_incumbent_signal_detected - inform that an incumbent signal + * interference was detected + * @hw: pointer as obtained from ieee80211_alloc_hw() + * @chanctx_conf: Channel context on which the signal interference was detected. + * Mandatory to pass a valid pointer for MLO. For non-MLO %NULL can be + * passed + * @incumbt_sig_intf_bmap: Bitmap indicating where the incumbent signal was + * detected. + */ +void ieee80211_incumbent_signal_detected(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *chanctx_conf, + u32 incumbt_sig_intf_bmap); + #endif /* MAC80211_H */ diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 0bfbce157486..ce97faab1765 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -3136,6 +3136,32 @@ TRACE_EVENT(api_radar_detected, ) ); +TRACE_EVENT(api_incumbent_signal_detected, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_chanctx_conf *chanctx_conf), + + TP_ARGS(local, chanctx_conf), + + TP_STRUCT__entry( + LOCAL_ENTRY + CHANDEF_ENTRY + __field(u32, bitmap) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + CHANDEF_ASSIGN(&chanctx_conf->def) + __entry->bitmap = + chanctx_conf ? chanctx_conf->incumbt_sig_intf_bmap : 0; + ), + + TP_printk( + LOCAL_PR_FMT " Incumbent signal detected." + CHANDEF_PR_FMT " Bitmap: 0x%x ", + LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->bitmap + ) +); + TRACE_EVENT(api_request_smps, TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 9eb35e3b9e52..68beb0725cf3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3592,6 +3592,21 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_radar_detected); +void ieee80211_incumbent_signal_detected(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *chanctx_conf, + u32 incumbt_sig_intf_bmap) +{ + struct ieee80211_local *local = hw_to_local(hw); + + chanctx_conf->incumbt_sig_intf_bmap = incumbt_sig_intf_bmap; + + trace_api_incumbent_signal_detected(local, chanctx_conf); + cfg80211_incumbent_signal_notify(hw->wiphy, + &chanctx_conf->def, + chanctx_conf->incumbt_sig_intf_bmap); +} +EXPORT_SYMBOL(ieee80211_incumbent_signal_detected); + void ieee80211_chandef_downgrade(struct cfg80211_chan_def *c, struct ieee80211_conn_settings *conn) { -- 2.34.1 From: Aditya Kumar Singh Add a debugfs 'simulate_incumbent_signal_interference' which calls the function ieee80211_incumbent_signal_detected() and starts the incumbent signal detection. Signed-off-by: Aditya Kumar Singh Signed-off-by: Amith A --- drivers/net/wireless/virtual/mac80211_hwsim.c | 33 +++++++++++++++++++ drivers/net/wireless/virtual/mac80211_hwsim.h | 4 +++ 2 files changed, 37 insertions(+) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 3789d46d5614..a311ba6b3e4f 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -1154,6 +1154,36 @@ static int hwsim_write_simulate_radar(void *dat, u64 val) DEFINE_DEBUGFS_ATTRIBUTE(hwsim_simulate_radar, NULL, hwsim_write_simulate_radar, "%llu\n"); +static void hwsim_6ghz_chanctx_iter(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + void *data) +{ + struct hwsim_get_any_chanctx_conf_arg *arg = data; + + if (conf->def.chan && conf->def.chan->band == NL80211_BAND_6GHZ) + arg->chanctx_conf = conf; +} + +static int hwsim_write_simulate_incumbent_signal(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + struct hwsim_get_any_chanctx_conf_arg arg = { .chanctx_conf = NULL }; + + ieee80211_iter_chan_contexts_atomic(data->hw, + hwsim_6ghz_chanctx_iter, + &arg); + + if (!arg.chanctx_conf) + return -EINVAL; + + ieee80211_incumbent_signal_detected(data->hw, arg.chanctx_conf, (u32)val); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(hwsim_simulate_incumbent_signal, NULL, + hwsim_write_simulate_incumbent_signal, "%llu\n"); + static int hwsim_fops_group_read(void *dat, u64 *val) { struct mac80211_hwsim_data *data = dat; @@ -5590,6 +5620,9 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, debugfs_create_file("dfs_simulate_radar", 0222, data->debugfs, data, &hwsim_simulate_radar); + debugfs_create_file("simulate_incumbent_signal_interference", 0200, + data->debugfs, + data, &hwsim_simulate_incumbent_signal); if (param->pmsr_capa) { data->pmsr_capa = *param->pmsr_capa; diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.h b/drivers/net/wireless/virtual/mac80211_hwsim.h index fa157c883f7f..4dc48cf33ec4 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim.h @@ -341,4 +341,8 @@ enum hwsim_rate_info_attributes { HWSIM_RATE_INFO_ATTR_MAX = NUM_HWSIM_RATE_INFO_ATTRS - 1 }; +struct hwsim_get_any_chanctx_conf_arg { + struct ieee80211_chanctx_conf *chanctx_conf; +}; + #endif /* __MAC80211_HWSIM_H */ -- 2.34.1