Commit 53873f13 authored by Johannes Berg's avatar Johannes Berg

cfg80211: make wdev_list accessible to drivers

There's no harm in having drivers read the list, since they can
use RCU protection or RTNL locking; allow this to not require
each and every driver to also implement its own bookkeeping.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 8b9b2f06
...@@ -3189,6 +3189,9 @@ struct wiphy_vendor_command { ...@@ -3189,6 +3189,9 @@ struct wiphy_vendor_command {
* @vht_capa_mod_mask: Specify what VHT capabilities can be over-ridden. * @vht_capa_mod_mask: Specify what VHT capabilities can be over-ridden.
* If null, then none can be over-ridden. * If null, then none can be over-ridden.
* *
* @wdev_list: the list of associated (virtual) interfaces; this list must
* not be modified by the driver, but can be read with RTNL/RCU protection.
*
* @max_acl_mac_addrs: Maximum number of MAC addresses that the device * @max_acl_mac_addrs: Maximum number of MAC addresses that the device
* supports for ACL. * supports for ACL.
* *
...@@ -3328,6 +3331,8 @@ struct wiphy { ...@@ -3328,6 +3331,8 @@ struct wiphy {
const struct ieee80211_ht_cap *ht_capa_mod_mask; const struct ieee80211_ht_cap *ht_capa_mod_mask;
const struct ieee80211_vht_cap *vht_capa_mod_mask; const struct ieee80211_vht_cap *vht_capa_mod_mask;
struct list_head wdev_list;
/* the network namespace this phy lives in currently */ /* the network namespace this phy lives in currently */
possible_net_t _net; possible_net_t _net;
......
...@@ -739,7 +739,7 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy, ...@@ -739,7 +739,7 @@ static bool cfg80211_ir_permissive_chan(struct wiphy *wiphy,
* and thus fail the GO instantiation, consider only the interfaces of * and thus fail the GO instantiation, consider only the interfaces of
* the current registered device. * the current registered device.
*/ */
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
struct ieee80211_channel *other_chan = NULL; struct ieee80211_channel *other_chan = NULL;
int r1, r2; int r1, r2;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* *
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2015 Intel Deutschland GmbH
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
...@@ -157,7 +158,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, ...@@ -157,7 +158,7 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
return -EOPNOTSUPP; return -EOPNOTSUPP;
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->netdev) if (!wdev->netdev)
continue; continue;
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
...@@ -171,7 +172,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, ...@@ -171,7 +172,8 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
/* failed -- clean up to old netns */ /* failed -- clean up to old netns */
net = wiphy_net(&rdev->wiphy); net = wiphy_net(&rdev->wiphy);
list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list, list_for_each_entry_continue_reverse(wdev,
&rdev->wiphy.wdev_list,
list) { list) {
if (!wdev->netdev) if (!wdev->netdev)
continue; continue;
...@@ -230,7 +232,7 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) ...@@ -230,7 +232,7 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy)
ASSERT_RTNL(); ASSERT_RTNL();
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (wdev->netdev) { if (wdev->netdev) {
dev_close(wdev->netdev); dev_close(wdev->netdev);
continue; continue;
...@@ -298,7 +300,8 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev) ...@@ -298,7 +300,8 @@ void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev)
kfree(item); kfree(item);
spin_unlock_irq(&rdev->destroy_list_lock); spin_unlock_irq(&rdev->destroy_list_lock);
list_for_each_entry_safe(wdev, tmp, &rdev->wdev_list, list) { list_for_each_entry_safe(wdev, tmp,
&rdev->wiphy.wdev_list, list) {
if (nlportid == wdev->owner_nlportid) if (nlportid == wdev->owner_nlportid)
rdev_del_virtual_intf(rdev, wdev); rdev_del_virtual_intf(rdev, wdev);
} }
...@@ -410,7 +413,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, ...@@ -410,7 +413,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx); dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
} }
INIT_LIST_HEAD(&rdev->wdev_list); INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
INIT_LIST_HEAD(&rdev->beacon_registrations); INIT_LIST_HEAD(&rdev->beacon_registrations);
spin_lock_init(&rdev->beacon_registrations_lock); spin_lock_init(&rdev->beacon_registrations_lock);
spin_lock_init(&rdev->bss_lock); spin_lock_init(&rdev->bss_lock);
...@@ -799,7 +802,7 @@ void wiphy_unregister(struct wiphy *wiphy) ...@@ -799,7 +802,7 @@ void wiphy_unregister(struct wiphy *wiphy)
nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY); nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY);
rdev->wiphy.registered = false; rdev->wiphy.registered = false;
WARN_ON(!list_empty(&rdev->wdev_list)); WARN_ON(!list_empty(&rdev->wiphy.wdev_list));
/* /*
* First remove the hardware from everywhere, this makes * First remove the hardware from everywhere, this makes
...@@ -1021,7 +1024,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, ...@@ -1021,7 +1024,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
spin_lock_init(&wdev->mgmt_registrations_lock); spin_lock_init(&wdev->mgmt_registrations_lock);
wdev->identifier = ++rdev->wdev_id; wdev->identifier = ++rdev->wdev_id;
list_add_rcu(&wdev->list, &rdev->wdev_list); list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
rdev->devlist_generation++; rdev->devlist_generation++;
/* can only change netns with wiphy */ /* can only change netns with wiphy */
dev->features |= NETIF_F_NETNS_LOCAL; dev->features |= NETIF_F_NETNS_LOCAL;
......
...@@ -50,8 +50,7 @@ struct cfg80211_registered_device { ...@@ -50,8 +50,7 @@ struct cfg80211_registered_device {
/* wiphy index, internal only */ /* wiphy index, internal only */
int wiphy_idx; int wiphy_idx;
/* associated wireless interfaces, protected by rtnl or RCU */ /* protected by RTNL */
struct list_head wdev_list;
int devlist_generation, wdev_id; int devlist_generation, wdev_id;
int opencount; int opencount;
wait_queue_head_t dev_wait; wait_queue_head_t dev_wait;
......
...@@ -103,7 +103,7 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) ...@@ -103,7 +103,7 @@ __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
continue; continue;
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (have_ifidx && wdev->netdev && if (have_ifidx && wdev->netdev &&
wdev->netdev->ifindex == ifidx) { wdev->netdev->ifindex == ifidx) {
result = wdev; result = wdev;
...@@ -149,7 +149,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) ...@@ -149,7 +149,7 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
if (tmp) { if (tmp) {
/* make sure wdev exists */ /* make sure wdev exists */
list_for_each_entry(wdev, &tmp->wdev_list, list) { list_for_each_entry(wdev, &tmp->wiphy.wdev_list, list) {
if (wdev->identifier != (u32)wdev_id) if (wdev->identifier != (u32)wdev_id)
continue; continue;
found = true; found = true;
...@@ -535,7 +535,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb, ...@@ -535,7 +535,7 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
*rdev = wiphy_to_rdev(wiphy); *rdev = wiphy_to_rdev(wiphy);
*wdev = NULL; *wdev = NULL;
list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
if (tmp->identifier == cb->args[1]) { if (tmp->identifier == cb->args[1]) {
*wdev = tmp; *wdev = tmp;
break; break;
...@@ -2490,7 +2490,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * ...@@ -2490,7 +2490,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
} }
if_idx = 0; if_idx = 0;
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (if_idx < if_start) { if (if_idx < if_start) {
if_idx++; if_idx++;
continue; continue;
...@@ -2762,7 +2762,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) ...@@ -2762,7 +2762,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
spin_lock_init(&wdev->mgmt_registrations_lock); spin_lock_init(&wdev->mgmt_registrations_lock);
wdev->identifier = ++rdev->wdev_id; wdev->identifier = ++rdev->wdev_id;
list_add_rcu(&wdev->list, &rdev->wdev_list); list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
rdev->devlist_generation++; rdev->devlist_generation++;
break; break;
default: default:
...@@ -3298,7 +3298,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, ...@@ -3298,7 +3298,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev; struct wireless_dev *wdev;
bool ret = false; bool ret = false;
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (wdev->iftype != NL80211_IFTYPE_AP && if (wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO) wdev->iftype != NL80211_IFTYPE_P2P_GO)
continue; continue;
...@@ -10392,7 +10392,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb, ...@@ -10392,7 +10392,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
*wdev = NULL; *wdev = NULL;
if (cb->args[1]) { if (cb->args[1]) {
list_for_each_entry(tmp, &(*rdev)->wdev_list, list) { list_for_each_entry(tmp, &wiphy->wdev_list, list) {
if (tmp->identifier == cb->args[1] - 1) { if (tmp->identifier == cb->args[1] - 1) {
*wdev = tmp; *wdev = tmp;
break; break;
...@@ -13413,7 +13413,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, ...@@ -13413,7 +13413,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
sched_scan_req->owner_nlportid == notify->portid) sched_scan_req->owner_nlportid == notify->portid)
schedule_scan_stop = true; schedule_scan_stop = true;
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) { list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
cfg80211_mlme_unregister_socket(wdev, notify->portid); cfg80211_mlme_unregister_socket(wdev, notify->portid);
if (wdev->owner_nlportid == notify->portid) if (wdev->owner_nlportid == notify->portid)
......
...@@ -1639,7 +1639,7 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy) ...@@ -1639,7 +1639,7 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy)
ASSERT_RTNL(); ASSERT_RTNL();
list_for_each_entry(wdev, &rdev->wdev_list, list) list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
if (!reg_wdev_chan_valid(wiphy, wdev)) if (!reg_wdev_chan_valid(wiphy, wdev))
cfg80211_leave(rdev, wdev); cfg80211_leave(rdev, wdev);
} }
......
...@@ -223,7 +223,7 @@ void cfg80211_conn_work(struct work_struct *work) ...@@ -223,7 +223,7 @@ void cfg80211_conn_work(struct work_struct *work)
rtnl_lock(); rtnl_lock();
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->netdev) if (!wdev->netdev)
continue; continue;
...@@ -617,7 +617,7 @@ static bool cfg80211_is_all_idle(void) ...@@ -617,7 +617,7 @@ static bool cfg80211_is_all_idle(void)
* count as new regulatory hints. * count as new regulatory hints.
*/ */
list_for_each_entry(rdev, &cfg80211_rdev_list, list) { list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
wdev_lock(wdev); wdev_lock(wdev);
if (wdev->conn || wdev->current_bss) if (wdev->conn || wdev->current_bss)
is_all_idle = false; is_all_idle = false;
......
...@@ -91,7 +91,7 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev) ...@@ -91,7 +91,7 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
{ {
struct wireless_dev *wdev; struct wireless_dev *wdev;
list_for_each_entry(wdev, &rdev->wdev_list, list) list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
cfg80211_leave(rdev, wdev); cfg80211_leave(rdev, wdev);
} }
......
...@@ -986,7 +986,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) ...@@ -986,7 +986,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
ASSERT_RTNL(); ASSERT_RTNL();
list_for_each_entry(wdev, &rdev->wdev_list, list) list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
cfg80211_process_wdev_events(wdev); cfg80211_process_wdev_events(wdev);
} }
...@@ -1560,7 +1560,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, ...@@ -1560,7 +1560,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
if (!beacon_int) if (!beacon_int)
return -EINVAL; return -EINVAL;
list_for_each_entry(wdev, &rdev->wdev_list, list) { list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
if (!wdev->beacon_interval) if (!wdev->beacon_interval)
continue; continue;
if (wdev->beacon_interval != beacon_int) { if (wdev->beacon_interval != beacon_int) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment