wifi: cfg80211: clean up links appropriately
authorJohannes Berg <johannes.berg@intel.com>
Wed, 6 Jul 2022 07:57:42 +0000 (09:57 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 15 Jul 2022 09:43:18 +0000 (11:43 +0200)
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
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/util.c

index 6b5321bb11768ea48b7e868c2f9e2b0d7c502e19..eefd6d8ff46518d5875d86ef704b3463132d9e86 100644 (file)
@@ -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:
index e72ca6eefafb8fc2b5e83d193c6741aafdfa4682..775e16cb99edab3f1fd979da3964c492733258cd 100644 (file)
@@ -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 */
index 11cad2d46d0eafe01495308d4d3ead0bd679f9ab..d774e9a954929ef6190586379af22384289bbc30 100644 (file)
@@ -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;
index b7257862e0fe65a9ebe32117f0ee78f0c5378aac..fe7956c8c6dadf43e95459219b92db51f316dbc5 100644 (file)
@@ -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);
+}