]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
wifi: mac80211: support open and close for NAN_DATA interfaces
authorMiri Korenblit <miriam.rachel.korenblit@intel.com>
Thu, 26 Mar 2026 10:14:36 +0000 (12:14 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Tue, 7 Apr 2026 13:36:03 +0000 (15:36 +0200)
Support opening and closing a NAN_DATA interface.
Track the NAN (NMI) interface, for convenience.
Allow opening an NAN_DATA interface only if the NAN interface is running
(NAN has started).
When closing the NAN interface, make sure all NAN_DATA interfaces are
closed first, and warn if this is not the case.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260326121156.a19de68119e5.Ia6724dac6a0e17cb69989dd714d14f4df1c69bef@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/ieee80211_i.h
net/mac80211/iface.c

index 92ea8de8a6dbbd78c0dc3e3dec42a6b02875a9f5..e3a051beba6a307b70b005ee1abcadd74bbad561 100644 (file)
@@ -1006,6 +1006,16 @@ struct ieee80211_if_nan {
        DECLARE_BITMAP(removed_channels, IEEE80211_NAN_MAX_CHANNELS);
 };
 
+/**
+ * struct ieee80211_if_nan_data - NAN data path state
+ *
+ * @nmi: pointer to the NAN management interface sdata. Used for data path,
+ *     hence RCU.
+ */
+struct ieee80211_if_nan_data {
+       struct ieee80211_sub_if_data __rcu *nmi;
+};
+
 struct ieee80211_link_data_managed {
        u8 bssid[ETH_ALEN] __aligned(2);
 
@@ -1204,6 +1214,7 @@ struct ieee80211_sub_if_data {
                struct ieee80211_if_ocb ocb;
                struct ieee80211_if_mntr mntr;
                struct ieee80211_if_nan nan;
+               struct ieee80211_if_nan_data nan_data;
        } u;
 
        struct ieee80211_link_data deflink;
index 0f3e49cdbb392ae2586a0cf32011e41488803b8f..507c5e016ec8ecf8df9c9eac53b84839f7ede2df 100644 (file)
@@ -361,6 +361,17 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
                             nsdata->vif.type == NL80211_IFTYPE_OCB))
                                return -EBUSY;
 
+                       /*
+                        * A NAN DATA interface is correlated to the NAN
+                        * (management) one
+                        */
+                       if (iftype == NL80211_IFTYPE_NAN_DATA &&
+                           nsdata->vif.type == NL80211_IFTYPE_NAN) {
+                               if (!nsdata->u.nan.started)
+                                       return -EINVAL;
+                               rcu_assign_pointer(sdata->u.nan_data.nmi, nsdata);
+                       }
+
                        /*
                         * Allow only a single IBSS interface to be up at any
                         * time. This is restricted because beacon distribution
@@ -475,6 +486,7 @@ static int ieee80211_open(struct net_device *dev)
 static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_down)
 {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_sub_if_data *iter;
        unsigned long flags;
        struct sk_buff_head freeq;
        struct sk_buff *skb, *tmp;
@@ -621,6 +633,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
                }
                break;
        case NL80211_IFTYPE_NAN:
+               /* Check if any open NAN_DATA interfaces */
+               list_for_each_entry(iter, &local->interfaces, list) {
+                       WARN_ON(iter->vif.type == NL80211_IFTYPE_NAN_DATA &&
+                               ieee80211_sdata_running(iter));
+               }
+
                /* clean all the functions */
                if (!(local->hw.wiphy->nan_capa.flags &
                      WIPHY_NAN_FLAGS_USERSPACE_DE)) {
@@ -636,6 +654,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
                        spin_unlock_bh(&sdata->u.nan.de.func_lock);
                }
                break;
+       case NL80211_IFTYPE_NAN_DATA:
+               RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
+               fallthrough;
        default:
                wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
                /*
@@ -1384,9 +1405,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
        case NL80211_IFTYPE_P2P_DEVICE:
        case NL80211_IFTYPE_OCB:
        case NL80211_IFTYPE_NAN:
-       case NL80211_IFTYPE_NAN_DATA:
                /* no special treatment */
                break;
+       case NL80211_IFTYPE_NAN_DATA:
+               if (WARN_ON(!rcu_access_pointer(sdata->u.nan_data.nmi)))
+                       return -ENOLINK;
+               break;
        case NL80211_IFTYPE_UNSPECIFIED:
        case NUM_NL80211_IFTYPES:
        case NL80211_IFTYPE_P2P_CLIENT:
@@ -1404,8 +1428,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                res = drv_start(local);
                if (res) {
                        /*
-                        * no need to worry about AP_VLAN cleanup since in that
-                        * case we can't have open_count == 0
+                        * no need to worry about AP_VLAN/NAN_DATA cleanup since
+                        * in that case we can't have open_count == 0
                         */
                        return res;
                }
@@ -1524,6 +1548,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                case NL80211_IFTYPE_AP:
                case NL80211_IFTYPE_MESH_POINT:
                case NL80211_IFTYPE_OCB:
+               case NL80211_IFTYPE_NAN_DATA:
                        netif_carrier_off(dev);
                        break;
                case NL80211_IFTYPE_P2P_DEVICE:
@@ -1570,6 +1595,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
  err_stop:
        if (!local->open_count)
                drv_stop(local, false);
+       if (sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
+               RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                list_del(&sdata->u.vlan.list);
        /* Might not be initialized yet, but it is harmless */