diff options
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r-- | net/wireless/nl80211.c | 28 |
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(¶ms, 0, sizeof(params)); | 2521 | memset(¶ms, 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(); |