diff mbox series

[57/76] wifi: cfg80211: clean up links appropriately

Message ID 20220713114425.f9bea0264306.Iac8f8265454b023660801822fee547803dab3796@changeid
State New
Headers show
Series wifi: more MLO work | expand

Commit Message

Johannes Berg July 13, 2022, 9:44 a.m. UTC
From: Johannes Berg <johannes.berg@intel.com>

This was missing earlier, we need to remove links when
interfaces are being destroyed, and we also need to
stop (AP) operations when a link is being destroyed.
Address these issues to remove many warnings that will
otherwise appear in mac80211.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/wireless/core.c    |  3 ++-
 net/wireless/core.h    |  5 +++++
 net/wireless/nl80211.c | 11 ++---------
 net/wireless/util.c    | 43 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 52 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6b5321bb1176..eefd6d8ff465 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -342,7 +342,7 @@  void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
 
 			wiphy_lock(&rdev->wiphy);
 			cfg80211_leave(rdev, wdev);
-			rdev_del_virtual_intf(rdev, wdev);
+			cfg80211_remove_virtual_intf(rdev, wdev);
 			wiphy_unlock(&rdev->wiphy);
 		}
 	}
@@ -1437,6 +1437,7 @@  static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 	case NETDEV_GOING_DOWN:
 		wiphy_lock(&rdev->wiphy);
 		cfg80211_leave(rdev, wdev);
+		cfg80211_remove_links(wdev);
 		wiphy_unlock(&rdev->wiphy);
 		break;
 	case NETDEV_DOWN:
diff --git a/net/wireless/core.h b/net/wireless/core.h
index e72ca6eefafb..775e16cb99ed 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -562,4 +562,9 @@  void cfg80211_release_pmsr(struct wireless_dev *wdev, u32 portid);
 void cfg80211_pmsr_wdev_down(struct wireless_dev *wdev);
 void cfg80211_pmsr_free_wk(struct work_struct *work);
 
+void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id);
+void cfg80211_remove_links(struct wireless_dev *wdev);
+int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev,
+				 struct wireless_dev *wdev);
+
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 11cad2d46d0e..d774e9a95492 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4279,7 +4279,7 @@  static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
 
 	mutex_lock(&rdev->wiphy.mtx);
 
-	return rdev_del_virtual_intf(rdev, wdev);
+	return cfg80211_remove_virtual_intf(rdev, wdev);
 }
 
 static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
@@ -15707,7 +15707,6 @@  static int nl80211_add_link(struct sk_buff *skb, struct genl_info *info)
 
 static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
 {
-	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	unsigned int link_id = nl80211_link_id(info->attrs);
 	struct net_device *dev = info->user_ptr[1];
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -15723,14 +15722,8 @@  static int nl80211_remove_link(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 	}
 
-	/* FIXME: stop the link operations first */
-
 	wdev_lock(wdev);
-	wdev->valid_links &= ~BIT(link_id);
-
-	rdev_del_intf_link(rdev, wdev, link_id);
-
-	eth_zero_addr(wdev->links[link_id].addr);
+	cfg80211_remove_link(wdev, link_id);
 	wdev_unlock(wdev);
 
 	return 0;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index b7257862e0fe..fe7956c8c6da 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -2447,3 +2447,46 @@  bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
 	return false;
 }
 EXPORT_SYMBOL(cfg80211_iftype_allowed);
+
+void cfg80211_remove_link(struct wireless_dev *wdev, unsigned int link_id)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+
+	ASSERT_WDEV_LOCK(wdev);
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+		__cfg80211_stop_ap(rdev, wdev->netdev, link_id, true);
+		break;
+	default:
+		/* per-link not relevant */
+		break;
+	}
+
+	wdev->valid_links &= ~BIT(link_id);
+
+	rdev_del_intf_link(rdev, wdev, link_id);
+
+	eth_zero_addr(wdev->links[link_id].addr);
+}
+
+void cfg80211_remove_links(struct wireless_dev *wdev)
+{
+	unsigned int link_id;
+
+	wdev_lock(wdev);
+	if (wdev->valid_links) {
+		for_each_valid_link(wdev, link_id)
+			cfg80211_remove_link(wdev, link_id);
+	}
+	wdev_unlock(wdev);
+}
+
+int cfg80211_remove_virtual_intf(struct cfg80211_registered_device *rdev,
+				 struct wireless_dev *wdev)
+{
+	cfg80211_remove_links(wdev);
+
+	return rdev_del_virtual_intf(rdev, wdev);
+}