@@ -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:
@@ -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 */
@@ -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;
@@ -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);
+}