aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-03-24 12:57:27 -0400
committerJohannes Berg <johannes.berg@intel.com>2014-04-09 04:55:28 -0400
commit78f22b6a3a9254460d23060530b48ae02a9394e3 (patch)
tree0770800533747eac02405fc01007cf719e0406f3
parent6e1ee5d2e9e411892b5d84e3ea93e3fc88ac786c (diff)
cfg80211: allow userspace to take ownership of interfaces
When dynamically creating interfaces from userspace, e.g. for P2P usage, such interfaces are usually owned by the process that created them, i.e. wpa_supplicant. Should wpa_supplicant crash, such interfaces will often cease operating properly and cause problems on restarting the process. To avoid this problem, introduce an ownership concept for interfaces. If an interface is owned by a netlink socket, then it will be destroyed if the netlink socket is closed for any reason, including if the process it belongs to crashed. This gives us a race-free way to get rid of any such interfaces. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-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();