wifi: mac80211: run NAN DE code only when appropriate

NAN DE (Discovery Engine) may be handled in the device or in user space.
When handled in user space, all the NAN func management code should not
run. Moreover, devices with user space DE should not provide the
add/del_nan_func callbaks. For such devices, ieee80211_reconfig_nan will
always fail.

Make it clear what parts of ieee80211_if_nan are relevant to DE
management, and touch those only when DE is offloaded.

Add a check that makes sure that a driver doesn't register with
add_del/nan_func callbacks if DE is in user space.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260326121156.6665f64865cd.Iee24bef3bae2e1d502216192e760c1e699d271c9@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Miri Korenblit
2026-03-26 12:14:34 +02:00
committed by Johannes Berg
parent b16df0dacb
commit 23eab70e30
5 changed files with 67 additions and 37 deletions

View File

@@ -502,12 +502,15 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
if (!ieee80211_sdata_running(sdata))
return -ENETDOWN;
spin_lock_bh(&sdata->u.nan.func_lock);
if (WARN_ON(wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE))
return -EOPNOTSUPP;
ret = idr_alloc(&sdata->u.nan.function_inst_ids,
spin_lock_bh(&sdata->u.nan.de.func_lock);
ret = idr_alloc(&sdata->u.nan.de.function_inst_ids,
nan_func, 1, sdata->local->hw.max_nan_de_entries + 1,
GFP_ATOMIC);
spin_unlock_bh(&sdata->u.nan.func_lock);
spin_unlock_bh(&sdata->u.nan.de.func_lock);
if (ret < 0)
return ret;
@@ -518,10 +521,10 @@ static int ieee80211_add_nan_func(struct wiphy *wiphy,
ret = drv_add_nan_func(sdata->local, sdata, nan_func);
if (ret) {
spin_lock_bh(&sdata->u.nan.func_lock);
idr_remove(&sdata->u.nan.function_inst_ids,
spin_lock_bh(&sdata->u.nan.de.func_lock);
idr_remove(&sdata->u.nan.de.function_inst_ids,
nan_func->instance_id);
spin_unlock_bh(&sdata->u.nan.func_lock);
spin_unlock_bh(&sdata->u.nan.de.func_lock);
}
return ret;
@@ -534,9 +537,9 @@ ieee80211_find_nan_func_by_cookie(struct ieee80211_sub_if_data *sdata,
struct cfg80211_nan_func *func;
int id;
lockdep_assert_held(&sdata->u.nan.func_lock);
lockdep_assert_held(&sdata->u.nan.de.func_lock);
idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id) {
idr_for_each_entry(&sdata->u.nan.de.function_inst_ids, func, id) {
if (func->cookie == cookie)
return func;
}
@@ -555,13 +558,16 @@ static void ieee80211_del_nan_func(struct wiphy *wiphy,
!ieee80211_sdata_running(sdata))
return;
spin_lock_bh(&sdata->u.nan.func_lock);
if (WARN_ON(wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE))
return;
spin_lock_bh(&sdata->u.nan.de.func_lock);
func = ieee80211_find_nan_func_by_cookie(sdata, cookie);
if (func)
instance_id = func->instance_id;
spin_unlock_bh(&sdata->u.nan.func_lock);
spin_unlock_bh(&sdata->u.nan.de.func_lock);
if (instance_id)
drv_del_nan_func(sdata->local, sdata, instance_id);
@@ -4888,18 +4894,22 @@ void ieee80211_nan_func_terminated(struct ieee80211_vif *vif,
if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
return;
spin_lock_bh(&sdata->u.nan.func_lock);
if (WARN_ON(sdata->local->hw.wiphy->nan_capa.flags &
WIPHY_NAN_FLAGS_USERSPACE_DE))
return;
func = idr_find(&sdata->u.nan.function_inst_ids, inst_id);
spin_lock_bh(&sdata->u.nan.de.func_lock);
func = idr_find(&sdata->u.nan.de.function_inst_ids, inst_id);
if (WARN_ON(!func)) {
spin_unlock_bh(&sdata->u.nan.func_lock);
spin_unlock_bh(&sdata->u.nan.de.func_lock);
return;
}
cookie = func->cookie;
idr_remove(&sdata->u.nan.function_inst_ids, inst_id);
idr_remove(&sdata->u.nan.de.function_inst_ids, inst_id);
spin_unlock_bh(&sdata->u.nan.func_lock);
spin_unlock_bh(&sdata->u.nan.de.func_lock);
cfg80211_free_nan_func(func);
@@ -4918,16 +4928,20 @@ void ieee80211_nan_func_match(struct ieee80211_vif *vif,
if (WARN_ON(vif->type != NL80211_IFTYPE_NAN))
return;
spin_lock_bh(&sdata->u.nan.func_lock);
if (WARN_ON(sdata->local->hw.wiphy->nan_capa.flags &
WIPHY_NAN_FLAGS_USERSPACE_DE))
return;
func = idr_find(&sdata->u.nan.function_inst_ids, match->inst_id);
spin_lock_bh(&sdata->u.nan.de.func_lock);
func = idr_find(&sdata->u.nan.de.function_inst_ids, match->inst_id);
if (WARN_ON(!func)) {
spin_unlock_bh(&sdata->u.nan.func_lock);
spin_unlock_bh(&sdata->u.nan.de.func_lock);
return;
}
match->cookie = func->cookie;
spin_unlock_bh(&sdata->u.nan.func_lock);
spin_unlock_bh(&sdata->u.nan.de.func_lock);
cfg80211_nan_match(ieee80211_vif_to_wdev(vif), match, gfp);
}

View File

@@ -987,16 +987,19 @@ struct ieee80211_if_mntr {
*
* @conf: current NAN configuration
* @started: true iff NAN is started
* @func_lock: lock for @func_inst_ids
* @function_inst_ids: a bitmap of available instance_id's
* @de: Discovery Engine state (only valid if !WIPHY_NAN_FLAGS_USERSPACE_DE)
* @de.func_lock: lock for @de.function_inst_ids
* @de.function_inst_ids: a bitmap of available instance_id's
*/
struct ieee80211_if_nan {
struct cfg80211_nan_conf conf;
bool started;
/* protects function_inst_ids */
spinlock_t func_lock;
struct idr function_inst_ids;
struct {
/* protects function_inst_ids */
spinlock_t func_lock;
struct idr function_inst_ids;
} de;
};
struct ieee80211_link_data_managed {

View File

@@ -622,15 +622,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
break;
case NL80211_IFTYPE_NAN:
/* clean all the functions */
spin_lock_bh(&sdata->u.nan.func_lock);
if (!(local->hw.wiphy->nan_capa.flags &
WIPHY_NAN_FLAGS_USERSPACE_DE)) {
spin_lock_bh(&sdata->u.nan.de.func_lock);
idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) {
idr_remove(&sdata->u.nan.function_inst_ids, i);
cfg80211_free_nan_func(func);
idr_for_each_entry(&sdata->u.nan.de.function_inst_ids,
func, i) {
idr_remove(&sdata->u.nan.de.function_inst_ids, i);
cfg80211_free_nan_func(func);
}
idr_destroy(&sdata->u.nan.de.function_inst_ids);
spin_unlock_bh(&sdata->u.nan.de.func_lock);
}
idr_destroy(&sdata->u.nan.function_inst_ids);
spin_unlock_bh(&sdata->u.nan.func_lock);
break;
default:
wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
@@ -1942,8 +1946,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
MONITOR_FLAG_OTHER_BSS;
break;
case NL80211_IFTYPE_NAN:
idr_init(&sdata->u.nan.function_inst_ids);
spin_lock_init(&sdata->u.nan.func_lock);
if (!(sdata->local->hw.wiphy->nan_capa.flags &
WIPHY_NAN_FLAGS_USERSPACE_DE)) {
idr_init(&sdata->u.nan.de.function_inst_ids);
spin_lock_init(&sdata->u.nan.de.func_lock);
}
sdata->vif.bss_conf.bssid = sdata->vif.addr;
break;
case NL80211_IFTYPE_AP_VLAN:

View File

@@ -1157,7 +1157,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (WARN_ON(local->hw.wiphy->interface_modes &
BIT(NL80211_IFTYPE_NAN) &&
(!local->ops->start_nan || !local->ops->stop_nan)))
((!local->ops->start_nan || !local->ops->stop_nan) ||
(local->hw.wiphy->nan_capa.flags & WIPHY_NAN_FLAGS_USERSPACE_DE &&
(local->ops->add_nan_func || local->ops->del_nan_func)))))
return -EINVAL;
if (hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO) {

View File

@@ -1754,6 +1754,10 @@ static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
if (WARN_ON(res))
return res;
if (sdata->local->hw.wiphy->nan_capa.flags &
WIPHY_NAN_FLAGS_USERSPACE_DE)
return 0;
funcs = kzalloc_objs(*funcs, sdata->local->hw.max_nan_de_entries + 1);
if (!funcs)
return -ENOMEM;
@@ -1762,12 +1766,12 @@ static int ieee80211_reconfig_nan(struct ieee80211_sub_if_data *sdata)
* This is a little bit ugly. We need to call a potentially sleeping
* callback for each NAN function, so we can't hold the spinlock.
*/
spin_lock_bh(&sdata->u.nan.func_lock);
spin_lock_bh(&sdata->u.nan.de.func_lock);
idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, id)
idr_for_each_entry(&sdata->u.nan.de.function_inst_ids, func, id)
funcs[i++] = func;
spin_unlock_bh(&sdata->u.nan.func_lock);
spin_unlock_bh(&sdata->u.nan.de.func_lock);
for (i = 0; funcs[i]; i++) {
res = drv_add_nan_func(sdata->local, sdata, funcs[i]);