mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
wifi: mac80211: track MU-MIMO configuration on disabled interfaces
For monitoring, userspace will try to configure the VIF sdata, while the driver may see the monitor_sdata that is created when only monitor interfaces are up. This causes the odd situation that it may not be possible to store the MU-MIMO configuration on monitor_sdata. Fix this by storing that information on the VIF sdata and updating the monitor_sdata when available and the interface is up. Also, adjust the code that adds monitor_sdata so that it will configure MU-MIMO based on the newly added interface or one of the existing ones. This should give a mostly consistent behaviour when configuring MU-MIMO on sniffer interfaces. Should the user configure MU-MIMO on multiple sniffer interfaces, then mac80211 will simply select one of the configurations. This behaviour should be good enough and avoids breaking user expectations in the common scenarios. Signed-off-by: Benjamin Berg <benjamin.berg@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com> Link: https://patch.msgid.link/20251110141514.677915f8f6bb.If4e04a57052f9ca763562a67248b06fd80d0c2c1@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
committed by
Johannes Berg
parent
b54cf0f449
commit
a5aa46f1ac
@@ -63,12 +63,14 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata,
|
||||
memcpy(sdata->vif.bss_conf.mu_group.position,
|
||||
params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN,
|
||||
WLAN_USER_POSITION_LEN);
|
||||
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
|
||||
BSS_CHANGED_MU_GROUPS);
|
||||
|
||||
/* don't care about endianness - just check for 0 */
|
||||
memcpy(&membership, params->vht_mumimo_groups,
|
||||
WLAN_MEMBERSHIP_LEN);
|
||||
mu_mimo_groups = membership != 0;
|
||||
|
||||
/* Unset following if configured explicitly */
|
||||
eth_broadcast_addr(sdata->u.mntr.mu_follow_addr);
|
||||
}
|
||||
|
||||
if (params->vht_mumimo_follow_addr) {
|
||||
@@ -76,16 +78,26 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata,
|
||||
is_valid_ether_addr(params->vht_mumimo_follow_addr);
|
||||
ether_addr_copy(sdata->u.mntr.mu_follow_addr,
|
||||
params->vht_mumimo_follow_addr);
|
||||
|
||||
/* Unset current membership until a management frame is RXed */
|
||||
memset(sdata->vif.bss_conf.mu_group.membership, 0,
|
||||
WLAN_MEMBERSHIP_LEN);
|
||||
}
|
||||
|
||||
sdata->vif.bss_conf.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow;
|
||||
|
||||
/* Notify only after setting mu_mimo_owner */
|
||||
if (sdata->vif.bss_conf.mu_mimo_owner &&
|
||||
sdata->flags & IEEE80211_SDATA_IN_DRIVER)
|
||||
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
|
||||
BSS_CHANGED_MU_GROUPS);
|
||||
}
|
||||
|
||||
static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
|
||||
struct vif_params *params)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct ieee80211_sub_if_data *monitor_sdata;
|
||||
struct ieee80211_sub_if_data *monitor_sdata = NULL;
|
||||
|
||||
/* check flags first */
|
||||
if (params->flags && ieee80211_sdata_running(sdata)) {
|
||||
@@ -103,23 +115,28 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* also validate MU-MIMO change */
|
||||
if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
monitor_sdata = sdata;
|
||||
else
|
||||
monitor_sdata = wiphy_dereference(local->hw.wiphy,
|
||||
local->monitor_sdata);
|
||||
|
||||
if (!monitor_sdata &&
|
||||
/* validate whether MU-MIMO can be configured */
|
||||
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
|
||||
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
|
||||
(params->vht_mumimo_groups || params->vht_mumimo_follow_addr))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Also update dependent monitor_sdata if required */
|
||||
if (test_bit(SDATA_STATE_RUNNING, &sdata->state) &&
|
||||
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
monitor_sdata = wiphy_dereference(local->hw.wiphy,
|
||||
local->monitor_sdata);
|
||||
|
||||
/* apply all changes now - no failures allowed */
|
||||
|
||||
if (monitor_sdata &&
|
||||
(ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
|
||||
ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)))
|
||||
ieee80211_set_mu_mimo_follow(monitor_sdata, params);
|
||||
if (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
|
||||
ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
|
||||
/* This is copied in when the VIF is activated */
|
||||
ieee80211_set_mu_mimo_follow(sdata, params);
|
||||
|
||||
if (monitor_sdata)
|
||||
ieee80211_set_mu_mimo_follow(monitor_sdata, params);
|
||||
}
|
||||
|
||||
if (params->flags) {
|
||||
if (ieee80211_sdata_running(sdata)) {
|
||||
|
||||
@@ -2107,7 +2107,8 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
|
||||
const int offset);
|
||||
int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up);
|
||||
void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata);
|
||||
int ieee80211_add_virtual_monitor(struct ieee80211_local *local);
|
||||
int ieee80211_add_virtual_monitor(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *creator_sdata);
|
||||
void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
|
||||
|
||||
bool __ieee80211_recalc_txpower(struct ieee80211_link_data *link);
|
||||
|
||||
@@ -733,8 +733,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
|
||||
ieee80211_configure_filter(local);
|
||||
ieee80211_hw_config(local, -1, hw_reconf_flags);
|
||||
|
||||
/* Passing NULL means an interface is picked for configuration */
|
||||
if (local->virt_monitors == local->open_count)
|
||||
ieee80211_add_virtual_monitor(local);
|
||||
ieee80211_add_virtual_monitor(local, NULL);
|
||||
}
|
||||
|
||||
void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata)
|
||||
@@ -1168,7 +1169,8 @@ static void ieee80211_sdata_init(struct ieee80211_local *local,
|
||||
ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf);
|
||||
}
|
||||
|
||||
int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
int ieee80211_add_virtual_monitor(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *creator_sdata)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
int ret;
|
||||
@@ -1176,10 +1178,14 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
ASSERT_RTNL();
|
||||
lockdep_assert_wiphy(local->hw.wiphy);
|
||||
|
||||
if (local->monitor_sdata ||
|
||||
ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
|
||||
return 0;
|
||||
|
||||
/* Already have a monitor set up, configure it */
|
||||
sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata);
|
||||
if (sdata)
|
||||
goto configure_monitor;
|
||||
|
||||
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
|
||||
if (!sdata)
|
||||
return -ENOMEM;
|
||||
@@ -1232,6 +1238,32 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
||||
skb_queue_head_init(&sdata->status_queue);
|
||||
wiphy_work_init(&sdata->work, ieee80211_iface_work);
|
||||
|
||||
configure_monitor:
|
||||
/* Copy in the MU-MIMO configuration if set */
|
||||
if (!creator_sdata) {
|
||||
struct ieee80211_sub_if_data *other;
|
||||
|
||||
list_for_each_entry(other, &local->mon_list, list) {
|
||||
if (!other->vif.bss_conf.mu_mimo_owner)
|
||||
continue;
|
||||
|
||||
creator_sdata = other;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (creator_sdata && creator_sdata->vif.bss_conf.mu_mimo_owner) {
|
||||
sdata->vif.bss_conf.mu_mimo_owner = true;
|
||||
memcpy(&sdata->vif.bss_conf.mu_group,
|
||||
&creator_sdata->vif.bss_conf.mu_group,
|
||||
sizeof(sdata->vif.bss_conf.mu_group));
|
||||
memcpy(&sdata->u.mntr.mu_follow_addr,
|
||||
creator_sdata->u.mntr.mu_follow_addr, ETH_ALEN);
|
||||
|
||||
ieee80211_link_info_change_notify(sdata, &sdata->deflink,
|
||||
BSS_CHANGED_MU_GROUPS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1388,11 +1420,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
|
||||
if (res)
|
||||
goto err_stop;
|
||||
} else {
|
||||
if (local->virt_monitors == 0 && local->open_count == 0) {
|
||||
res = ieee80211_add_virtual_monitor(local);
|
||||
/* add/configure if there is no non-monitor interface */
|
||||
if (local->virt_monitors == local->open_count) {
|
||||
res = ieee80211_add_virtual_monitor(local, sdata);
|
||||
if (res)
|
||||
goto err_stop;
|
||||
}
|
||||
|
||||
local->virt_monitors++;
|
||||
|
||||
/* must be before the call to ieee80211_configure_filter */
|
||||
|
||||
@@ -2206,9 +2206,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
}
|
||||
}
|
||||
|
||||
/* Passing NULL means an interface is picked for configuration */
|
||||
if (local->virt_monitors > 0 &&
|
||||
local->virt_monitors == local->open_count)
|
||||
ieee80211_add_virtual_monitor(local);
|
||||
ieee80211_add_virtual_monitor(local, NULL);
|
||||
|
||||
if (!suspended)
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user