]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mac80211: Extend support for changing NAN configuration
authorIlan Peer <ilan.peer@intel.com>
Mon, 8 Sep 2025 11:13:07 +0000 (14:13 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 19 Sep 2025 09:26:23 +0000 (11:26 +0200)
As 'struct cfg80211_nan_config' was updated, update the relevant
logic to accommodate these changes.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250908140015.92b530ddaedf.I2b6d6f6074e25487303fde573ce764a64f87bdcd@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c

index 252c0804de2ffe160d84d12c5f941615b56008b3..da15ccfcf4a2a536132545220f0ff0c9981498ef 100644 (file)
@@ -311,6 +311,96 @@ static void ieee80211_stop_p2p_device(struct wiphy *wiphy,
        ieee80211_sdata_stop(IEEE80211_WDEV_TO_SUB_IF(wdev));
 }
 
+static void ieee80211_nan_conf_free(struct cfg80211_nan_conf *conf)
+{
+       kfree(conf->cluster_id);
+       kfree(conf->extra_nan_attrs);
+       kfree(conf->vendor_elems);
+       memset(conf, 0, sizeof(*conf));
+}
+
+static void ieee80211_stop_nan(struct wiphy *wiphy,
+                              struct wireless_dev *wdev)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+       if (!sdata->u.nan.started)
+               return;
+
+       drv_stop_nan(sdata->local, sdata);
+       sdata->u.nan.started = false;
+
+       ieee80211_nan_conf_free(&sdata->u.nan.conf);
+
+       ieee80211_sdata_stop(sdata);
+       ieee80211_recalc_idle(sdata->local);
+}
+
+static int ieee80211_nan_conf_copy(struct cfg80211_nan_conf *dst,
+                                  struct cfg80211_nan_conf *src,
+                                  u32 changes)
+{
+       if (changes & CFG80211_NAN_CONF_CHANGED_PREF)
+               dst->master_pref = src->master_pref;
+
+       if (changes & CFG80211_NAN_CONF_CHANGED_BANDS)
+               dst->bands = src->bands;
+
+       if (changes & CFG80211_NAN_CONF_CHANGED_CONFIG) {
+               dst->scan_period = src->scan_period;
+               dst->scan_dwell_time = src->scan_dwell_time;
+               dst->discovery_beacon_interval =
+                       src->discovery_beacon_interval;
+               dst->enable_dw_notification = src->enable_dw_notification;
+               memcpy(&dst->band_cfgs, &src->band_cfgs,
+                      sizeof(dst->band_cfgs));
+
+               kfree(dst->cluster_id);
+               dst->cluster_id = NULL;
+
+               kfree(dst->extra_nan_attrs);
+               dst->extra_nan_attrs = NULL;
+               dst->extra_nan_attrs_len = 0;
+
+               kfree(dst->vendor_elems);
+               dst->vendor_elems = NULL;
+               dst->vendor_elems_len = 0;
+
+               if (src->cluster_id) {
+                       dst->cluster_id = kmemdup(src->cluster_id, ETH_ALEN,
+                                                 GFP_KERNEL);
+                       if (!dst->cluster_id)
+                               goto no_mem;
+               }
+
+               if (src->extra_nan_attrs && src->extra_nan_attrs_len) {
+                       dst->extra_nan_attrs = kmemdup(src->extra_nan_attrs,
+                                                      src->extra_nan_attrs_len,
+                                                      GFP_KERNEL);
+                       if (!dst->extra_nan_attrs)
+                               goto no_mem;
+
+                       dst->extra_nan_attrs_len = src->extra_nan_attrs_len;
+               }
+
+               if (src->vendor_elems && src->vendor_elems_len) {
+                       dst->vendor_elems = kmemdup(src->vendor_elems,
+                                                   src->vendor_elems_len,
+                                                   GFP_KERNEL);
+                       if (!dst->vendor_elems)
+                               goto no_mem;
+
+                       dst->vendor_elems_len = src->vendor_elems_len;
+               }
+       }
+
+       return 0;
+
+no_mem:
+       ieee80211_nan_conf_free(dst);
+       return -ENOMEM;
+}
+
 static int ieee80211_start_nan(struct wiphy *wiphy,
                               struct wireless_dev *wdev,
                               struct cfg80211_nan_conf *conf)
@@ -340,33 +430,22 @@ static int ieee80211_start_nan(struct wiphy *wiphy,
        sdata->u.nan.started = true;
        ieee80211_recalc_idle(sdata->local);
 
-       sdata->u.nan.conf.master_pref = conf->master_pref;
-       sdata->u.nan.conf.bands = conf->bands;
+       ret = ieee80211_nan_conf_copy(&sdata->u.nan.conf, conf, 0xFFFFFFFF);
+       if (ret) {
+               ieee80211_stop_nan(wiphy, wdev);
+               return ret;
+       }
 
        return 0;
 }
 
-static void ieee80211_stop_nan(struct wiphy *wiphy,
-                              struct wireless_dev *wdev)
-{
-       struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
-
-       if (!sdata->u.nan.started)
-               return;
-
-       drv_stop_nan(sdata->local, sdata);
-       sdata->u.nan.started = false;
-       ieee80211_sdata_stop(sdata);
-       ieee80211_recalc_idle(sdata->local);
-}
-
 static int ieee80211_nan_change_conf(struct wiphy *wiphy,
                                     struct wireless_dev *wdev,
                                     struct cfg80211_nan_conf *conf,
                                     u32 changes)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
-       struct cfg80211_nan_conf new_conf;
+       struct cfg80211_nan_conf new_conf = {};
        int ret = 0;
 
        if (sdata->vif.type != NL80211_IFTYPE_NAN)
@@ -375,17 +454,28 @@ static int ieee80211_nan_change_conf(struct wiphy *wiphy,
        if (!ieee80211_sdata_running(sdata))
                return -ENETDOWN;
 
-       new_conf = sdata->u.nan.conf;
+       if (!changes)
+               return 0;
 
-       if (changes & CFG80211_NAN_CONF_CHANGED_PREF)
-               new_conf.master_pref = conf->master_pref;
+       /* First make a full copy of the previous configuration and then apply
+        * the changes. This might be a little wasteful, but it is simpler.
+        */
+       ret = ieee80211_nan_conf_copy(&new_conf, &sdata->u.nan.conf,
+                                     0xFFFFFFFF);
+       if (ret < 0)
+               return ret;
 
-       if (changes & CFG80211_NAN_CONF_CHANGED_BANDS)
-               new_conf.bands = conf->bands;
+       ret = ieee80211_nan_conf_copy(&new_conf, conf, changes);
+       if (ret < 0)
+               return ret;
 
        ret = drv_nan_change_conf(sdata->local, sdata, &new_conf, changes);
-       if (!ret)
+       if (ret) {
+               ieee80211_nan_conf_free(&new_conf);
+       } else {
+               ieee80211_nan_conf_free(&sdata->u.nan.conf);
                sdata->u.nan.conf = new_conf;
+       }
 
        return ret;
 }