From 0e8ec738a71ee4e8da7c56d21dd7bb54f954c38b Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 18 Mar 2026 14:39:17 +0200 Subject: wifi: cfg80211: add support for NAN data interface This new interface type represents a NAN data interface (NDI). It is used for data communication with NAN peers. Note that the existing NL80211_IFTYPE_NAN interface, which is the NAN Management Interface (NMI), is used for management communication. An NDI interface is started when a new NAN data path is about to be established, and is stopped after the NAN data path is terminated. - An NDI interface can only be started if the NMI is running, and NAN is started. - Before the NMI is stopped, the NDI interfaces will be stopped. Add the new interface type, handle add/remove operations for it, and makes sure of the conditions above. Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20260219114327.0d681335c2e2.I92973483e927820ae2297853c141842fdb262747@changeid Link: https://patch.msgid.link/20260318123926.206536-4-miriam.rachel.korenblit@intel.com Signed-off-by: Johannes Berg --- net/wireless/core.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 9 deletions(-) (limited to 'net/wireless/core.c') diff --git a/net/wireless/core.c b/net/wireless/core.c index 54c89b0db352..200b97f912eb 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -329,16 +329,21 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) ASSERT_RTNL(); + /* + * Some netdev interfaces need to be closed before some non-netdev + * ones, i.e. NAN_DATA interfaces need to be closed before the NAN + * interface + */ list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (wdev->netdev) { dev_close(wdev->netdev); continue; } + } - /* otherwise, check iftype */ - - guard(wiphy)(wiphy); + guard(wiphy)(wiphy); + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { switch (wdev->iftype) { case NL80211_IFTYPE_P2P_DEVICE: cfg80211_stop_p2p_device(rdev, wdev); @@ -396,6 +401,8 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) { if (wdev->nl_owner_dead) { + cfg80211_close_dependents(rdev, wdev); + if (wdev->netdev) dev_close(wdev->netdev); @@ -406,6 +413,21 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) } } +void cfg80211_close_dependents(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + ASSERT_RTNL(); + + if (wdev->iftype != NL80211_IFTYPE_NAN) + return; + + /* Close all NAN DATA interfaces */ + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + if (wdev->iftype == NL80211_IFTYPE_NAN_DATA) + dev_close(wdev->netdev); + } +} + static void cfg80211_destroy_iface_wk(struct work_struct *work) { struct cfg80211_registered_device *rdev; @@ -1419,9 +1441,8 @@ void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, rdev->num_running_monitor_ifaces += num; } -void cfg80211_leave(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, - int link_id) +void cfg80211_leave_locked(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, int link_id) { struct net_device *dev = wdev->netdev; struct cfg80211_sched_scan_request *pos, *tmp; @@ -1472,6 +1493,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, break; case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_NAN_DATA: /* nothing to do */ break; case NL80211_IFTYPE_UNSPECIFIED: @@ -1482,6 +1504,19 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, } } +void cfg80211_leave(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, int link_id) +{ + ASSERT_RTNL(); + + /* NAN_DATA interfaces must be closed before stopping NAN */ + cfg80211_close_dependents(rdev, wdev); + + guard(wiphy)(&rdev->wiphy); + + cfg80211_leave_locked(rdev, wdev, link_id); +} + void cfg80211_stop_link(struct wiphy *wiphy, struct wireless_dev *wdev, int link_id, gfp_t gfp) { @@ -1497,6 +1532,9 @@ void cfg80211_stop_link(struct wiphy *wiphy, struct wireless_dev *wdev, trace_cfg80211_stop_link(wiphy, wdev, link_id); + if (wdev->iftype == NL80211_IFTYPE_NAN) + return; + ev = kzalloc_obj(*ev, gfp); if (!ev) return; @@ -1647,10 +1685,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, } break; case NETDEV_GOING_DOWN: - scoped_guard(wiphy, &rdev->wiphy) { - cfg80211_leave(rdev, wdev, -1); + cfg80211_leave(rdev, wdev, -1); + scoped_guard(wiphy, &rdev->wiphy) cfg80211_remove_links(wdev); - } /* since we just did cfg80211_leave() nothing to do there */ cancel_work_sync(&wdev->disconnect_wk); cancel_work_sync(&wdev->pmsr_free_wk); @@ -1731,6 +1768,23 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, if (rfkill_blocked(rdev->wiphy.rfkill)) return notifier_from_errno(-ERFKILL); + + /* NAN_DATA interfaces require a running NAN interface */ + if (wdev->iftype == NL80211_IFTYPE_NAN_DATA) { + struct wireless_dev *iter; + bool nan_started = false; + + list_for_each_entry(iter, &rdev->wiphy.wdev_list, list) { + if (iter->iftype == NL80211_IFTYPE_NAN && + wdev_running(iter)) { + nan_started = true; + break; + } + } + + if (!nan_started) + return notifier_from_errno(-ENOLINK); + } break; default: return NOTIFY_DONE; -- cgit v1.2.3