|
@@ -385,6 +385,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|
|
[NL80211_ATTR_MAC_HINT] = { .len = ETH_ALEN },
|
|
|
[NL80211_ATTR_WIPHY_FREQ_HINT] = { .type = NLA_U32 },
|
|
|
[NL80211_ATTR_TDLS_PEER_CAPABILITY] = { .type = NLA_U32 },
|
|
|
+ [NL80211_ATTR_IFACE_SOCKET_OWNER] = { .type = NLA_FLAG },
|
|
|
};
|
|
|
|
|
|
/* policy for the key attributes */
|
|
@@ -2514,6 +2515,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|
|
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
|
|
|
u32 flags;
|
|
|
|
|
|
+ /* to avoid failing a new interface creation due to pending removal */
|
|
|
+ cfg80211_destroy_ifaces(rdev);
|
|
|
+
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
|
|
|
|
if (!info->attrs[NL80211_ATTR_IFNAME])
|
|
@@ -2563,6 +2567,9 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
|
|
|
return PTR_ERR(wdev);
|
|
|
}
|
|
|
|
|
|
+ if (info->attrs[NL80211_ATTR_IFACE_SOCKET_OWNER])
|
|
|
+ wdev->owner_nlportid = info->snd_portid;
|
|
|
+
|
|
|
switch (type) {
|
|
|
case NL80211_IFTYPE_MESH_POINT:
|
|
|
if (!info->attrs[NL80211_ATTR_MESH_ID])
|
|
@@ -11649,9 +11656,15 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
|
|
rcu_read_lock();
|
|
|
|
|
|
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
|
|
|
- list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
|
|
|
+ bool schedule_destroy_work = false;
|
|
|
+
|
|
|
+ list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
|
|
|
cfg80211_mlme_unregister_socket(wdev, notify->portid);
|
|
|
|
|
|
+ if (wdev->owner_nlportid == notify->portid)
|
|
|
+ schedule_destroy_work = true;
|
|
|
+ }
|
|
|
+
|
|
|
spin_lock_bh(&rdev->beacon_registrations_lock);
|
|
|
list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
|
|
|
list) {
|
|
@@ -11662,6 +11675,19 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
|
|
|
}
|
|
|
}
|
|
|
spin_unlock_bh(&rdev->beacon_registrations_lock);
|
|
|
+
|
|
|
+ if (schedule_destroy_work) {
|
|
|
+ struct cfg80211_iface_destroy *destroy;
|
|
|
+
|
|
|
+ destroy = kzalloc(sizeof(*destroy), GFP_ATOMIC);
|
|
|
+ if (destroy) {
|
|
|
+ destroy->nlportid = notify->portid;
|
|
|
+ spin_lock(&rdev->destroy_list_lock);
|
|
|
+ list_add(&destroy->list, &rdev->destroy_list);
|
|
|
+ spin_unlock(&rdev->destroy_list_lock);
|
|
|
+ schedule_work(&rdev->destroy_work);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
rcu_read_unlock();
|