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 | 23 +++++++++++++++++++++ include/uapi/linux/nl80211.h | 19 +++++++++++++++++ net/wireless/nl80211.c | 40 ++++++++++++++++++++++++++++++++++++ net/wireless/trace.h | 19 +++++++++++++++++ 4 files changed, 101 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0ae0aa7594a3..91c85a896fd6 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -10423,4 +10423,27 @@ cfg80211_s1g_get_primary_sibling(struct wiphy *wiphy, return ieee80211_get_channel_khz(wiphy, sibling_1mhz_khz); } + +/** + * 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 + * @gfp: allocation context for message creation and multicast; pass GFP_ATOMIC + * if called from atomic context (e.g. firmware event handler), otherwise + * GFP_KERNEL + * + * 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, + gfp_t gfp); + #endif /* __NET_CFG80211_H */ diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 54ddbd9a5459..0bda5c05b47a 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1361,6 +1361,12 @@ * user space that the NAN new cluster has been joined. The cluster ID is * indicated by %NL80211_ATTR_MAC. * + * @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 */ @@ -1624,6 +1630,8 @@ enum nl80211_commands { NL80211_CMD_NAN_NEXT_DW_NOTIFICATION, NL80211_CMD_NAN_CLUSTER_JOINED, + NL80211_CMD_INCUMBENT_SIGNAL_DETECT, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2976,6 +2984,15 @@ enum nl80211_commands { * @NL80211_ATTR_EPP_PEER: A flag attribute to indicate if the peer is an EPP * STA. Used with %NL80211_CMD_NEW_STA and %NL80211_CMD_ADD_LINK_STA * + * @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 @@ -3546,6 +3563,8 @@ enum nl80211_attrs { NL80211_ATTR_EPP_PEER, + 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 85e30fda4c46..2b4a84794f8e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -21045,6 +21045,46 @@ 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, + gfp_t gfp) +{ + 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); + 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); + 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 643ccf4f0227..deb283d9e017 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -4225,6 +4225,25 @@ TRACE_EVENT(cfg80211_nan_cluster_joined, WDEV_PR_ARG, __entry->cluster_id, __entry->new_cluster ? " [new]" : "") ); + +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 | 14 ++++++++++++++ net/mac80211/trace.h | 26 ++++++++++++++++++++++++++ net/mac80211/util.c | 14 ++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 36ae7fe9ddf3..d586eab10f26 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -7899,4 +7899,18 @@ int ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *hw, * Return: %true iff the vif is a NAN interface and NAN is started */ bool ieee80211_vif_nan_started(struct ieee80211_vif *vif); + +/** + * 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..74741a61546c 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, + u32 bitmap), + + TP_ARGS(local, chanctx_conf, bitmap), + + TP_STRUCT__entry( + LOCAL_ENTRY + CHANDEF_ENTRY + __field(u32, bitmap) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + CHANDEF_ASSIGN(&chanctx_conf->def) + __entry->bitmap = bitmap; + ), + + 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 4d5680da7aa0..0e1ee2559130 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -3670,6 +3670,20 @@ 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); + + trace_api_incumbent_signal_detected(local, chanctx_conf, incumbt_sig_intf_bmap); + cfg80211_incumbent_signal_notify(hw->wiphy, + &chanctx_conf->def, + incumbt_sig_intf_bmap, + GFP_ATOMIC); +} +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() to report that incumbent signal interference has been detected on the current 6 GHz operating channel. The written value is a bitmap of affected 20 MHz segments. 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 | 2 ++ 2 files changed, 35 insertions(+) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 4d9f5f87e814..f1105f97504b 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -1164,6 +1164,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 ieee80211_chanctx_conf **out = data; + + if (conf->def.chan && conf->def.chan->band == NL80211_BAND_6GHZ) + *out = conf; +} + +static int hwsim_write_simulate_incumbent_signal(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + struct ieee80211_chanctx_conf *chanctx_conf = NULL; + + ieee80211_iter_chan_contexts_atomic(data->hw, + hwsim_6ghz_chanctx_iter, + &chanctx_conf); + + if (!chanctx_conf) + return -EINVAL; + + ieee80211_incumbent_signal_detected(data->hw, 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; @@ -5832,6 +5862,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 c2d06cf852a5..d897aa720ec2 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim.h @@ -343,4 +343,6 @@ enum hwsim_rate_info_attributes { HWSIM_RATE_INFO_ATTR_MAX = NUM_HWSIM_RATE_INFO_ATTRS - 1 }; +/* no longer used - previously used for debugfs iterator */ + #endif /* __MAC80211_HWSIM_H */ -- 2.34.1