aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h3
-rw-r--r--include/uapi/linux/nl80211.h6
-rw-r--r--net/wireless/core.c44
-rw-r--r--net/wireless/core.h11
-rw-r--r--net/wireless/nl80211.c28
5 files changed, 91 insertions, 1 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index f3539a15c411..6510ccf53a54 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3194,6 +3194,7 @@ struct cfg80211_cached_keys;
3194 * @ibss_dfs_possible: (private) IBSS may change to a DFS channel 3194 * @ibss_dfs_possible: (private) IBSS may change to a DFS channel
3195 * @event_list: (private) list for internal event processing 3195 * @event_list: (private) list for internal event processing
3196 * @event_lock: (private) lock for event list 3196 * @event_lock: (private) lock for event list
3197 * @owner_nlportid: (private) owner socket port ID
3197 */ 3198 */
3198struct wireless_dev { 3199struct wireless_dev {
3199 struct wiphy *wiphy; 3200 struct wiphy *wiphy;
@@ -3241,6 +3242,8 @@ struct wireless_dev {
3241 unsigned long cac_start_time; 3242 unsigned long cac_start_time;
3242 unsigned int cac_time_ms; 3243 unsigned int cac_time_ms;
3243 3244
3245 u32 owner_nlportid;
3246
3244#ifdef CONFIG_CFG80211_WEXT 3247#ifdef CONFIG_CFG80211_WEXT
3245 /* wext data */ 3248 /* wext data */
3246 struct { 3249 struct {
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 1ba9d626aa83..5e405fd55a71 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1579,6 +1579,10 @@ enum nl80211_commands {
1579 * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32. 1579 * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
1580 * As specified in the &enum nl80211_tdls_peer_capability. 1580 * As specified in the &enum nl80211_tdls_peer_capability.
1581 * 1581 *
1582 * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
1583 * creation then the new interface will be owned by the netlink socket
1584 * that created it and will be destroyed when the socket is closed
1585 *
1582 * @NL80211_ATTR_MAX: highest attribute number currently defined 1586 * @NL80211_ATTR_MAX: highest attribute number currently defined
1583 * @__NL80211_ATTR_AFTER_LAST: internal use 1587 * @__NL80211_ATTR_AFTER_LAST: internal use
1584 */ 1588 */
@@ -1914,6 +1918,8 @@ enum nl80211_attrs {
1914 1918
1915 NL80211_ATTR_TDLS_PEER_CAPABILITY, 1919 NL80211_ATTR_TDLS_PEER_CAPABILITY,
1916 1920
1921 NL80211_ATTR_IFACE_SOCKET_OWNER,
1922
1917 /* add attributes here, update the policy in nl80211.c */ 1923 /* add attributes here, update the policy in nl80211.c */
1918 1924
1919 __NL80211_ATTR_AFTER_LAST, 1925 __NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 086cddd03ba6..5a63c3cbda2e 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -260,6 +260,45 @@ static void cfg80211_event_work(struct work_struct *work)
260 rtnl_unlock(); 260 rtnl_unlock();
261} 261}
262 262
263void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
264{
265 struct cfg80211_iface_destroy *item;
266
267 ASSERT_RTNL();
268
269 spin_lock_irq(&rdev->destroy_list_lock);
270 while ((item = list_first_entry_or_null(&rdev->destroy_list,
271 struct cfg80211_iface_destroy,
272 list))) {
273 struct wireless_dev *wdev, *tmp;
274 u32 nlportid = item->nlportid;
275
276 list_del(&item->list);
277 kfree(item);
278 spin_unlock_irq(&rdev->destroy_list_lock);
279
280 list_for_each_entry_safe(wdev, tmp, &rdev->wdev_list, list) {
281 if (nlportid == wdev->owner_nlportid)
282 rdev_del_virtual_intf(rdev, wdev);
283 }
284
285 spin_lock_irq(&rdev->destroy_list_lock);
286 }
287 spin_unlock_irq(&rdev->destroy_list_lock);
288}
289
290static void cfg80211_destroy_iface_wk(struct work_struct *work)
291{
292 struct cfg80211_registered_device *rdev;
293
294 rdev = container_of(work, struct cfg80211_registered_device,
295 destroy_work);
296
297 rtnl_lock();
298 cfg80211_destroy_ifaces(rdev);
299 rtnl_unlock();
300}
301
263/* exported functions */ 302/* exported functions */
264 303
265struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) 304struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
@@ -318,6 +357,10 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
318 rdev->wiphy.dev.class = &ieee80211_class; 357 rdev->wiphy.dev.class = &ieee80211_class;
319 rdev->wiphy.dev.platform_data = rdev; 358 rdev->wiphy.dev.platform_data = rdev;
320 359
360 INIT_LIST_HEAD(&rdev->destroy_list);
361 spin_lock_init(&rdev->destroy_list_lock);
362 INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
363
321#ifdef CONFIG_CFG80211_DEFAULT_PS 364#ifdef CONFIG_CFG80211_DEFAULT_PS
322 rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; 365 rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
323#endif 366#endif
@@ -675,6 +718,7 @@ void wiphy_unregister(struct wiphy *wiphy)
675 cancel_work_sync(&rdev->conn_work); 718 cancel_work_sync(&rdev->conn_work);
676 flush_work(&rdev->event_work); 719 flush_work(&rdev->event_work);
677 cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); 720 cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
721 flush_work(&rdev->destroy_work);
678 722
679#ifdef CONFIG_PM 723#ifdef CONFIG_PM
680 if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) 724 if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 5b1fdcadd469..6f6f75609852 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -80,6 +80,10 @@ struct cfg80211_registered_device {
80 80
81 struct cfg80211_coalesce *coalesce; 81 struct cfg80211_coalesce *coalesce;
82 82
83 spinlock_t destroy_list_lock;
84 struct list_head destroy_list;
85 struct work_struct destroy_work;
86
83 /* must be last because of the way we do wiphy_priv(), 87 /* must be last because of the way we do wiphy_priv(),
84 * and it should at least be aligned to NETDEV_ALIGN */ 88 * and it should at least be aligned to NETDEV_ALIGN */
85 struct wiphy wiphy __aligned(NETDEV_ALIGN); 89 struct wiphy wiphy __aligned(NETDEV_ALIGN);
@@ -232,6 +236,13 @@ struct cfg80211_beacon_registration {
232 u32 nlportid; 236 u32 nlportid;
233}; 237};
234 238
239struct cfg80211_iface_destroy {
240 struct list_head list;
241 u32 nlportid;
242};
243
244void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev);
245
235/* free object */ 246/* free object */
236void cfg80211_dev_free(struct cfg80211_registered_device *rdev); 247void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
237 248
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();