aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 052c1bf8ffac..b25b5ce4076d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -385,6 +385,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
385 [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN }, 385 [NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
386 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 }, 386 [NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
387 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 }, 387 [NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
388 [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
388}; 389};
389 390
390/* policy for the key attributes */ 391/* policy for the key attributes */
@@ -2514,6 +2515,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2514 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; 2515 enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
2515 u32 flags; 2516 u32 flags;
2516 2517
2518 /* to avoid failing a new interface creation due to pending removal */
2519 cfg80211_destroy_ifaces(rdev);
2520
2517 memset(&params, 0, sizeof(params)); 2521 memset(&params, 0, sizeof(params));
2518 2522
2519 if (!info->attrs[NL80211_ATTR_IFNAME]) 2523 if (!info->attrs[NL80211_ATTR_IFNAME])
@@ -2563,6 +2567,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
2563 return PTR_ERR(wdev); 2567 return PTR_ERR(wdev);
2564 } 2568 }
2565 2569
2570 if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER])
2571 wdev->owner_nlportid = info->snd_portid;
2572
2566 switch (type) { 2573 switch (type) {
2567 case NL80211_IFTYPE_MESH_POINT: 2574 case NL80211_IFTYPE_MESH_POINT:
2568 if (!info->attrs[NL80211_ATTR_MESH_ID]) 2575 if (!info->attrs[NL80211_ATTR_MESH_ID])
@@ -11649,9 +11656,15 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
11649 rcu_read_lock(); 11656 rcu_read_lock();
11650 11657
11651 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { 11658 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
11652 list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) 11659 bool schedule_destroy_work = false;
11660
11661 list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
11653 cfg80211_mlme_unregister_socket(wdev, notify->portid); 11662 cfg80211_mlme_unregister_socket(wdev, notify->portid);
11654 11663
11664 if (wdev->owner_nlportid == notify->portid)
11665 schedule_destroy_work = true;
11666 }
11667
11655 spin_lock_bh(&rdev->beacon_registrations_lock); 11668 spin_lock_bh(&rdev->beacon_registrations_lock);
11656 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations, 11669 list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
11657 list) { 11670 list) {
@@ -11662,6 +11675,19 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
11662 } 11675 }
11663 } 11676 }
11664 spin_unlock_bh(&rdev->beacon_registrations_lock); 11677 spin_unlock_bh(&rdev->beacon_registrations_lock);
11678
11679 if (schedule_destroy_work) {
11680 struct cfg80211_iface_destroy *destroy;
11681
11682 destroy = kzalloc(sizeof(*destroy), GFP_ATOMIC);
11683 if (destroy) {
11684 destroy->nlportid = notify->portid;
11685 spin_lock(&rdev->destroy_list_lock);
11686 list_add(&destroy->list, &rdev->destroy_list);
11687 spin_unlock(&rdev->destroy_list_lock);
11688 schedule_work(&rdev->destroy_work);
11689 }
11690 }
11665 } 11691 }
11666 11692
11667 rcu_read_unlock(); 11693 rcu_read_unlock();