Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem

This commit is contained in:
John W. Linville
2012-07-20 12:30:48 -04:00
163 changed files with 5139 additions and 2915 deletions
+21
View File
@@ -74,6 +74,27 @@ config CFG80211_REG_DEBUG
If unsure, say N.
config CFG80211_CERTIFICATION_ONUS
bool "cfg80211 certification onus"
depends on CFG80211 && EXPERT
default n
---help---
You should disable this option unless you are both capable
and willing to ensure your system will remain regulatory
compliant with the features available under this option.
Some options may still be under heavy development and
for whatever reason regulatory compliance has not or
cannot yet be verified. Regulatory verification may at
times only be possible until you have the final system
in place.
This option should only be enabled by system integrators
or distributions that have done work necessary to ensure
regulatory certification on the system with the enabled
features. Alternatively you can enable this option if
you are a wireless researcher and are working in a controlled
and approved environment by your local regulatory agency.
config CFG80211_DEFAULT_PS
bool "enable powersave by default"
depends on CFG80211
+11 -13
View File
@@ -82,7 +82,6 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
int freq, enum nl80211_channel_type chantype)
{
struct ieee80211_channel *chan;
int err;
if (!rdev->ops->set_monitor_channel)
return -EOPNOTSUPP;
@@ -93,25 +92,17 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
if (!chan)
return -EINVAL;
err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
if (!err) {
rdev->monitor_channel = chan;
rdev->monitor_channel_type = chantype;
}
return err;
return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
}
void
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
cfg80211_get_chan_state(struct wireless_dev *wdev,
struct ieee80211_channel **chan,
enum cfg80211_chan_mode *chanmode)
{
*chan = NULL;
*chanmode = CHAN_MODE_UNDEFINED;
ASSERT_RDEV_LOCK(rdev);
ASSERT_WDEV_LOCK(wdev);
if (!netif_running(wdev->netdev))
@@ -136,9 +127,16 @@ cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
if (wdev->beacon_interval) {
*chan = wdev->channel;
*chanmode = CHAN_MODE_SHARED;
}
return;
case NL80211_IFTYPE_MESH_POINT:
*chan = wdev->channel;
*chanmode = CHAN_MODE_SHARED;
if (wdev->mesh_id_len) {
*chan = wdev->channel;
*chanmode = CHAN_MODE_SHARED;
}
return;
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP_VLAN:
+21 -58
View File
@@ -176,7 +176,9 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK))
return -EOPNOTSUPP;
list_for_each_entry(wdev, &rdev->netdev_list, list) {
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (!wdev->netdev)
continue;
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
err = dev_change_net_namespace(wdev->netdev, net, "wlan%d");
if (err)
@@ -188,8 +190,10 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev,
/* failed -- clean up to old netns */
net = wiphy_net(&rdev->wiphy);
list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list,
list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list,
list) {
if (!wdev->netdev)
continue;
wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL;
err = dev_change_net_namespace(wdev->netdev, net,
"wlan%d");
@@ -226,8 +230,9 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
rtnl_lock();
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list)
dev_close(wdev->netdev);
list_for_each_entry(wdev, &rdev->wdev_list, list)
if (wdev->netdev)
dev_close(wdev->netdev);
mutex_unlock(&rdev->devlist_mtx);
rtnl_unlock();
@@ -304,7 +309,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
mutex_init(&rdev->mtx);
mutex_init(&rdev->devlist_mtx);
mutex_init(&rdev->sched_scan_mtx);
INIT_LIST_HEAD(&rdev->netdev_list);
INIT_LIST_HEAD(&rdev->wdev_list);
spin_lock_init(&rdev->bss_lock);
INIT_LIST_HEAD(&rdev->bss_list);
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
@@ -537,7 +542,7 @@ int wiphy_register(struct wiphy *wiphy)
}
/* set up regulatory info */
regulatory_update(wiphy, NL80211_REGDOM_SET_BY_CORE);
wiphy_regulatory_register(wiphy);
list_add_rcu(&rdev->list, &cfg80211_rdev_list);
cfg80211_rdev_list_generation++;
@@ -622,7 +627,7 @@ void wiphy_unregister(struct wiphy *wiphy)
__count == 0; }));
mutex_lock(&rdev->devlist_mtx);
BUG_ON(!list_empty(&rdev->netdev_list));
BUG_ON(!list_empty(&rdev->wdev_list));
mutex_unlock(&rdev->devlist_mtx);
/*
@@ -647,9 +652,11 @@ void wiphy_unregister(struct wiphy *wiphy)
/* nothing */
cfg80211_unlock_rdev(rdev);
/* If this device got a regulatory hint tell core its
* free to listen now to a new shiny device regulatory hint */
reg_device_remove(wiphy);
/*
* If this device got a regulatory hint tell core its
* free to listen now to a new shiny device regulatory hint
*/
wiphy_regulatory_deregister(wiphy);
cfg80211_rdev_list_generation++;
device_del(&rdev->wiphy.dev);
@@ -703,7 +710,7 @@ static void wdev_cleanup_work(struct work_struct *work)
cfg80211_lock_rdev(rdev);
if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) {
if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
rdev->scan_req->aborted = true;
___cfg80211_scan_done(rdev, true);
}
@@ -731,59 +738,14 @@ static struct device_type wiphy_type = {
.name = "wlan",
};
static struct ieee80211_channel *
cfg80211_get_any_chan(struct cfg80211_registered_device *rdev)
{
struct ieee80211_supported_band *sband;
int i;
for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
sband = rdev->wiphy.bands[i];
if (sband && sband->n_channels > 0)
return &sband->channels[0];
}
return NULL;
}
static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev)
{
struct ieee80211_channel *chan;
chan = cfg80211_get_any_chan(rdev);
if (WARN_ON(!chan))
return;
mutex_lock(&rdev->devlist_mtx);
WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq,
NL80211_CHAN_NO_HT));
mutex_unlock(&rdev->devlist_mtx);
}
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num)
{
bool has_monitors_only_old = cfg80211_has_monitors_only(rdev);
bool has_monitors_only_new;
ASSERT_RTNL();
rdev->num_running_ifaces += num;
if (iftype == NL80211_IFTYPE_MONITOR)
rdev->num_running_monitor_ifaces += num;
has_monitors_only_new = cfg80211_has_monitors_only(rdev);
if (has_monitors_only_new != has_monitors_only_old) {
rdev->ops->set_monitor_enabled(&rdev->wiphy,
has_monitors_only_new);
if (!has_monitors_only_new) {
rdev->monitor_channel = NULL;
rdev->monitor_channel_type = NL80211_CHAN_NO_HT;
} else {
cfg80211_init_mon_chan(rdev);
}
}
}
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
@@ -820,7 +782,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
spin_lock_init(&wdev->mgmt_registrations_lock);
mutex_lock(&rdev->devlist_mtx);
list_add_rcu(&wdev->list, &rdev->netdev_list);
wdev->identifier = ++rdev->wdev_id;
list_add_rcu(&wdev->list, &rdev->wdev_list);
rdev->devlist_generation++;
/* can only change netns with wiphy */
dev->features |= NETIF_F_NETNS_LOCAL;
@@ -905,6 +868,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
mutex_unlock(&rdev->devlist_mtx);
dev_put(dev);
}
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
wdev_lock(wdev);
@@ -999,7 +963,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
mutex_unlock(&rdev->devlist_mtx);
if (ret)
return notifier_from_errno(ret);
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
break;
}
+5 -9
View File
@@ -47,11 +47,11 @@ struct cfg80211_registered_device {
/* wiphy index, internal only */
int wiphy_idx;
/* associate netdev list */
/* associated wireless interfaces */
struct mutex devlist_mtx;
/* protected by devlist_mtx or RCU */
struct list_head netdev_list;
int devlist_generation;
struct list_head wdev_list;
int devlist_generation, wdev_id;
int opencount; /* also protected by devlist_mtx */
wait_queue_head_t dev_wait;
@@ -61,9 +61,6 @@ struct cfg80211_registered_device {
int num_running_ifaces;
int num_running_monitor_ifaces;
struct ieee80211_channel *monitor_channel;
enum nl80211_channel_type monitor_channel_type;
/* BSSes/scanning */
spinlock_t bss_lock;
struct list_head bss_list;
@@ -372,7 +369,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
@@ -463,8 +460,7 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
}
void
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
cfg80211_get_chan_state(struct wireless_dev *wdev,
struct ieee80211_channel **chan,
enum cfg80211_chan_mode *chanmode);
+28 -19
View File
@@ -567,29 +567,28 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
}
}
void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie,
void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type,
nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type,
duration, gfp);
}
EXPORT_SYMBOL(cfg80211_ready_on_channel);
void cfg80211_remain_on_channel_expired(struct net_device *dev,
u64 cookie,
void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
gfp_t gfp)
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan,
nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan,
channel_type, gfp);
}
EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
@@ -678,8 +677,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid,
list_add(&nreg->list, &wdev->mgmt_registrations);
if (rdev->ops->mgmt_frame_register)
rdev->ops->mgmt_frame_register(wiphy, wdev->netdev,
frame_type, true);
rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, true);
out:
spin_unlock_bh(&wdev->mgmt_registrations_lock);
@@ -702,7 +700,7 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
if (rdev->ops->mgmt_frame_register) {
u16 frame_type = le16_to_cpu(reg->frame_type);
rdev->ops->mgmt_frame_register(wiphy, wdev->netdev,
rdev->ops->mgmt_frame_register(wiphy, wdev,
frame_type, false);
}
@@ -731,14 +729,14 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
}
int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct wireless_dev *wdev,
struct ieee80211_channel *chan, bool offchan,
enum nl80211_channel_type channel_type,
bool channel_type_valid, unsigned int wait,
const u8 *buf, size_t len, bool no_cck,
bool dont_wait_for_ack, u64 *cookie)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct net_device *dev = wdev->netdev;
const struct ieee80211_mgmt *mgmt;
u16 stype;
@@ -825,16 +823,15 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return -EINVAL;
/* Transmit the Action frame as requested by user space */
return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
channel_type, channel_type_valid,
wait, buf, len, no_cck, dont_wait_for_ack,
cookie);
}
bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm,
bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
const u8 *buf, size_t len, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct cfg80211_mgmt_registration *reg;
@@ -871,7 +868,7 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm,
/* found match! */
/* Indicate the received Action frame to user space */
if (nl80211_send_mgmt(rdev, dev, reg->nlpid,
if (nl80211_send_mgmt(rdev, wdev, reg->nlpid,
freq, sig_mbm,
buf, len, gfp))
continue;
@@ -886,15 +883,14 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm,
}
EXPORT_SYMBOL(cfg80211_rx_mgmt);
void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie,
void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
const u8 *buf, size_t len, bool ack, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
/* Indicate TX status of the Action frame to user space */
nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp);
}
EXPORT_SYMBOL(cfg80211_mgmt_tx_status);
@@ -923,6 +919,19 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
}
EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify);
void cfg80211_cqm_txe_notify(struct net_device *dev,
const u8 *peer, u32 num_packets,
u32 rate, u32 intvl, gfp_t gfp)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets,
rate, intvl, gfp);
}
EXPORT_SYMBOL(cfg80211_cqm_txe_notify);
void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
const u8 *replay_ctr, gfp_t gfp)
{
+398 -139
View File
@@ -46,28 +46,60 @@ static struct genl_family nl80211_fam = {
.post_doit = nl80211_post_doit,
};
/* internal helper: get rdev and dev */
static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs,
struct cfg80211_registered_device **rdev,
struct net_device **dev)
/* returns ERR_PTR values */
static struct wireless_dev *
__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
{
int ifindex;
struct cfg80211_registered_device *rdev;
struct wireless_dev *result = NULL;
bool have_ifidx = attrs[NL80211_ATTR_IFINDEX];
bool have_wdev_id = attrs[NL80211_ATTR_WDEV];
u64 wdev_id;
int wiphy_idx = -1;
int ifidx = -1;
if (!attrs[NL80211_ATTR_IFINDEX])
return -EINVAL;
assert_cfg80211_lock();
ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
*dev = dev_get_by_index(netns, ifindex);
if (!*dev)
return -ENODEV;
if (!have_ifidx && !have_wdev_id)
return ERR_PTR(-EINVAL);
*rdev = cfg80211_get_dev_from_ifindex(netns, ifindex);
if (IS_ERR(*rdev)) {
dev_put(*dev);
return PTR_ERR(*rdev);
if (have_ifidx)
ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
if (have_wdev_id) {
wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
wiphy_idx = wdev_id >> 32;
}
return 0;
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
struct wireless_dev *wdev;
if (wiphy_net(&rdev->wiphy) != netns)
continue;
if (have_wdev_id && rdev->wiphy_idx != wiphy_idx)
continue;
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (have_ifidx && wdev->netdev &&
wdev->netdev->ifindex == ifidx) {
result = wdev;
break;
}
if (have_wdev_id && wdev->identifier == (u32)wdev_id) {
result = wdev;
break;
}
}
mutex_unlock(&rdev->devlist_mtx);
if (result)
break;
}
if (result)
return result;
return ERR_PTR(-ENODEV);
}
static struct cfg80211_registered_device *
@@ -79,13 +111,40 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
assert_cfg80211_lock();
if (!attrs[NL80211_ATTR_WIPHY] &&
!attrs[NL80211_ATTR_IFINDEX])
!attrs[NL80211_ATTR_IFINDEX] &&
!attrs[NL80211_ATTR_WDEV])
return ERR_PTR(-EINVAL);
if (attrs[NL80211_ATTR_WIPHY])
rdev = cfg80211_rdev_by_wiphy_idx(
nla_get_u32(attrs[NL80211_ATTR_WIPHY]));
if (attrs[NL80211_ATTR_WDEV]) {
u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]);
struct wireless_dev *wdev;
bool found = false;
tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32);
if (tmp) {
/* make sure wdev exists */
mutex_lock(&tmp->devlist_mtx);
list_for_each_entry(wdev, &tmp->wdev_list, list) {
if (wdev->identifier != (u32)wdev_id)
continue;
found = true;
break;
}
mutex_unlock(&tmp->devlist_mtx);
if (!found)
tmp = NULL;
if (rdev && tmp != rdev)
return ERR_PTR(-EINVAL);
rdev = tmp;
}
}
if (attrs[NL80211_ATTR_IFINDEX]) {
int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]);
netdev = dev_get_by_index(netns, ifindex);
@@ -294,6 +353,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 },
[NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 },
[NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 },
[NL80211_ATTR_WDEV] = { .type = NLA_U64 },
[NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 },
};
/* policy for the key attributes */
@@ -1668,32 +1729,48 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
return result;
}
static inline u64 wdev_id(struct wireless_dev *wdev)
{
return (u64)wdev->identifier |
((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32);
}
static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
struct cfg80211_registered_device *rdev,
struct net_device *dev)
struct wireless_dev *wdev)
{
struct net_device *dev = wdev->netdev;
void *hdr;
hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE);
if (!hdr)
return -1;
if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) ||
nla_put_u32(msg, NL80211_ATTR_IFTYPE,
dev->ieee80211_ptr->iftype) ||
if (dev &&
(nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr)))
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) ||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
nla_put_u32(msg, NL80211_ATTR_GENERATION,
rdev->devlist_generation ^
(cfg80211_rdev_list_generation << 2)))
goto nla_put_failure;
if (rdev->monitor_channel) {
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
rdev->monitor_channel->center_freq) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
rdev->monitor_channel_type))
if (rdev->ops->get_channel) {
struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type;
chan = rdev->ops->get_channel(&rdev->wiphy, wdev,
&channel_type);
if (chan &&
(nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
chan->center_freq) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
channel_type)))
goto nla_put_failure;
}
@@ -1724,14 +1801,14 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
if_idx = 0;
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) {
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (if_idx < if_start) {
if_idx++;
continue;
}
if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
rdev, wdev->netdev) < 0) {
rdev, wdev) < 0) {
mutex_unlock(&rdev->devlist_mtx);
goto out;
}
@@ -1754,14 +1831,14 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *msg;
struct cfg80211_registered_device *dev = info->user_ptr[0];
struct net_device *netdev = info->user_ptr[1];
struct wireless_dev *wdev = info->user_ptr[1];
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
dev, netdev) < 0) {
dev, wdev) < 0) {
nlmsg_free(msg);
return -ENOBUFS;
}
@@ -1901,7 +1978,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct vif_params params;
struct net_device *dev;
struct wireless_dev *wdev;
struct sk_buff *msg;
int err;
enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
u32 flags;
@@ -1928,19 +2006,23 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
return err;
}
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags);
dev = rdev->ops->add_virtual_intf(&rdev->wiphy,
wdev = rdev->ops->add_virtual_intf(&rdev->wiphy,
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params);
if (IS_ERR(dev))
return PTR_ERR(dev);
if (IS_ERR(wdev)) {
nlmsg_free(msg);
return PTR_ERR(wdev);
}
if (type == NL80211_IFTYPE_MESH_POINT &&
info->attrs[NL80211_ATTR_MESH_ID]) {
struct wireless_dev *wdev = dev->ieee80211_ptr;
wdev_lock(wdev);
BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
IEEE80211_MAX_MESH_ID_LEN);
@@ -1951,18 +2033,34 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
wdev_unlock(wdev);
}
return 0;
if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0,
rdev, wdev) < 0) {
nlmsg_free(msg);
return -ENOBUFS;
}
return genlmsg_reply(msg, info);
}
static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = info->user_ptr[1];
if (!rdev->ops->del_virtual_intf)
return -EOPNOTSUPP;
return rdev->ops->del_virtual_intf(&rdev->wiphy, dev);
/*
* If we remove a wireless device without a netdev then clear
* user_ptr[1] so that nl80211_post_doit won't dereference it
* to check if it needs to do dev_put(). Otherwise it crashes
* since the wdev has been freed, unlike with a netdev where
* we need the dev_put() for the netdev to really be freed.
*/
if (!wdev->netdev)
info->user_ptr[1] = NULL;
return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev);
}
static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info)
@@ -2350,7 +2448,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) {
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO)
continue;
@@ -3485,6 +3583,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
{
int r;
char *data = NULL;
enum nl80211_user_reg_hint_type user_reg_hint_type;
/*
* You should only get this when cfg80211 hasn't yet initialized
@@ -3504,7 +3603,21 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
r = regulatory_hint_user(data);
if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE])
user_reg_hint_type =
nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]);
else
user_reg_hint_type = NL80211_USER_REG_HINT_USER;
switch (user_reg_hint_type) {
case NL80211_USER_REG_HINT_USER:
case NL80211_USER_REG_HINT_CELL_BASE:
break;
default:
return -EINVAL;
}
r = regulatory_hint_user(data, user_reg_hint_type);
return r;
}
@@ -3874,6 +3987,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
cfg80211_regdomain->dfs_region)))
goto nla_put_failure;
if (reg_last_request_cell_base() &&
nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
NL80211_USER_REG_HINT_CELL_BASE))
goto nla_put_failure;
nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
if (!nl_reg_rules)
goto nla_put_failure;
@@ -4039,7 +4157,7 @@ static int validate_scan_freqs(struct nlattr *freqs)
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = info->user_ptr[1];
struct cfg80211_scan_request *request;
struct nlattr *attr;
struct wiphy *wiphy;
@@ -4199,15 +4317,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
request->no_cck =
nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
request->dev = dev;
request->wdev = wdev;
request->wiphy = &rdev->wiphy;
rdev->scan_req = request;
err = rdev->ops->scan(&rdev->wiphy, dev, request);
err = rdev->ops->scan(&rdev->wiphy, request);
if (!err) {
nl80211_send_scan_start(rdev, dev);
dev_hold(dev);
nl80211_send_scan_start(rdev, wdev);
if (wdev->netdev)
dev_hold(wdev->netdev);
} else {
out_free:
rdev->scan_req = NULL;
@@ -5685,7 +5804,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = info->user_ptr[1];
struct ieee80211_channel *chan;
struct sk_buff *msg;
void *hdr;
@@ -5733,7 +5852,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
goto free_msg;
}
err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan,
err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan,
channel_type, duration, &cookie);
if (err)
@@ -5757,7 +5876,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = info->user_ptr[1];
u64 cookie;
if (!info->attrs[NL80211_ATTR_COOKIE])
@@ -5768,7 +5887,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb,
cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie);
return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie);
}
static u32 rateset_to_mask(struct ieee80211_supported_band *sband,
@@ -5917,7 +6036,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = info->user_ptr[1];
u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
@@ -5926,21 +6045,24 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_FRAME_TYPE])
frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_GO:
break;
default:
return -EOPNOTSUPP;
}
/* not much point in registering if we can't reply */
if (!rdev->ops->mgmt_tx)
return -EOPNOTSUPP;
return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
frame_type,
return cfg80211_mlme_register_mgmt(wdev, info->snd_pid, frame_type,
nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
}
@@ -5948,7 +6070,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = info->user_ptr[1];
struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
bool channel_type_valid = false;
@@ -5969,14 +6091,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->mgmt_tx)
return -EOPNOTSUPP;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_P2P_GO:
break;
default:
return -EOPNOTSUPP;
}
if (info->attrs[NL80211_ATTR_DURATION]) {
if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
@@ -6025,7 +6151,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
}
}
err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type,
err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type,
channel_type_valid, wait,
nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]),
@@ -6053,7 +6179,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = info->user_ptr[1];
u64 cookie;
if (!info->attrs[NL80211_ATTR_COOKIE])
@@ -6062,17 +6188,21 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in
if (!rdev->ops->mgmt_tx_cancel_wait)
return -EOPNOTSUPP;
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_GO:
break;
default:
return -EOPNOTSUPP;
}
cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie);
return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie);
}
static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
@@ -6158,8 +6288,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = {
[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
[NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
[NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
};
static int nl80211_set_cqm_txe(struct genl_info *info,
u32 rate, u32 pkts, u32 intvl)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev;
struct net_device *dev = info->user_ptr[1];
if ((rate < 0 || rate > 100) ||
(intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL))
return -EINVAL;
wdev = dev->ieee80211_ptr;
if (!rdev->ops->set_cqm_txe_config)
return -EOPNOTSUPP;
if (wdev->iftype != NL80211_IFTYPE_STATION &&
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
return -EOPNOTSUPP;
return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev,
rate, pkts, intvl);
}
static int nl80211_set_cqm_rssi(struct genl_info *info,
s32 threshold, u32 hysteresis)
{
@@ -6207,6 +6364,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
err = nl80211_set_cqm_rssi(info, threshold, hysteresis);
} else if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
attrs[NL80211_ATTR_CQM_TXE_PKTS] &&
attrs[NL80211_ATTR_CQM_TXE_INTVL]) {
u32 rate, pkts, intvl;
rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]);
pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]);
intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]);
err = nl80211_set_cqm_txe(info, rate, pkts, intvl);
} else
err = -EINVAL;
@@ -6363,8 +6528,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
struct cfg80211_wowlan no_triggers = {};
struct cfg80211_wowlan new_triggers = {};
struct cfg80211_wowlan *ntrig;
struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
int err, i;
bool prev_enabled = rdev->wowlan;
@@ -6372,8 +6537,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
return -EOPNOTSUPP;
if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS])
goto no_triggers;
if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
cfg80211_rdev_free_wowlan(rdev);
rdev->wowlan = NULL;
goto set_wakeup;
}
err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
@@ -6484,22 +6652,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
}
}
if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) {
struct cfg80211_wowlan *ntrig;
ntrig = kmemdup(&new_triggers, sizeof(new_triggers),
GFP_KERNEL);
if (!ntrig) {
err = -ENOMEM;
goto error;
}
cfg80211_rdev_free_wowlan(rdev);
rdev->wowlan = ntrig;
} else {
no_triggers:
cfg80211_rdev_free_wowlan(rdev);
rdev->wowlan = NULL;
ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
if (!ntrig) {
err = -ENOMEM;
goto error;
}
cfg80211_rdev_free_wowlan(rdev);
rdev->wowlan = ntrig;
set_wakeup:
if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan)
rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan);
@@ -6655,13 +6816,17 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
#define NL80211_FLAG_CHECK_NETDEV_UP 0x08
#define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\
NL80211_FLAG_CHECK_NETDEV_UP)
#define NL80211_FLAG_NEED_WDEV 0x10
/* If a netdev is associated, it must be UP */
#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\
NL80211_FLAG_CHECK_NETDEV_UP)
static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
struct genl_info *info)
{
struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
struct net_device *dev;
int err;
bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL;
if (rtnl)
@@ -6675,24 +6840,51 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb,
return PTR_ERR(rdev);
}
info->user_ptr[0] = rdev;
} else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs,
&rdev, &dev);
if (err) {
} else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV ||
ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
mutex_lock(&cfg80211_mutex);
wdev = __cfg80211_wdev_from_attrs(genl_info_net(info),
info->attrs);
if (IS_ERR(wdev)) {
mutex_unlock(&cfg80211_mutex);
if (rtnl)
rtnl_unlock();
return err;
return PTR_ERR(wdev);
}
if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
!netif_running(dev)) {
cfg80211_unlock_rdev(rdev);
dev_put(dev);
if (rtnl)
rtnl_unlock();
return -ENETDOWN;
dev = wdev->netdev;
rdev = wiphy_to_dev(wdev->wiphy);
if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) {
if (!dev) {
mutex_unlock(&cfg80211_mutex);
if (rtnl)
rtnl_unlock();
return -EINVAL;
}
info->user_ptr[1] = dev;
} else {
info->user_ptr[1] = wdev;
}
if (dev) {
if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP &&
!netif_running(dev)) {
mutex_unlock(&cfg80211_mutex);
if (rtnl)
rtnl_unlock();
return -ENETDOWN;
}
dev_hold(dev);
}
cfg80211_lock_rdev(rdev);
mutex_unlock(&cfg80211_mutex);
info->user_ptr[0] = rdev;
info->user_ptr[1] = dev;
}
return 0;
@@ -6703,8 +6895,16 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb,
{
if (info->user_ptr[0])
cfg80211_unlock_rdev(info->user_ptr[0]);
if (info->user_ptr[1])
dev_put(info->user_ptr[1]);
if (info->user_ptr[1]) {
if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) {
struct wireless_dev *wdev = info->user_ptr[1];
if (wdev->netdev)
dev_put(wdev->netdev);
} else {
dev_put(info->user_ptr[1]);
}
}
if (ops->internal_flags & NL80211_FLAG_NEED_RTNL)
rtnl_unlock();
}
@@ -6731,7 +6931,7 @@ static struct genl_ops nl80211_ops[] = {
.dumpit = nl80211_dump_interface,
.policy = nl80211_policy,
/* can be retrieved by unprivileged users */
.internal_flags = NL80211_FLAG_NEED_NETDEV,
.internal_flags = NL80211_FLAG_NEED_WDEV,
},
{
.cmd = NL80211_CMD_SET_INTERFACE,
@@ -6754,7 +6954,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_del_interface,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
.internal_flags = NL80211_FLAG_NEED_WDEV |
NL80211_FLAG_NEED_RTNL,
},
{
@@ -6925,7 +7125,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_trigger_scan,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
{
@@ -7066,7 +7266,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_remain_on_channel,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
{
@@ -7074,7 +7274,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_cancel_remain_on_channel,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
{
@@ -7090,7 +7290,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_register_mgmt,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV |
.internal_flags = NL80211_FLAG_NEED_WDEV |
NL80211_FLAG_NEED_RTNL,
},
{
@@ -7098,7 +7298,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_tx_mgmt,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
{
@@ -7106,7 +7306,7 @@ static struct genl_ops nl80211_ops[] = {
.doit = nl80211_tx_mgmt_cancel_wait,
.policy = nl80211_policy,
.flags = GENL_ADMIN_PERM,
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
.internal_flags = NL80211_FLAG_NEED_WDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
{
@@ -7317,7 +7517,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
static int nl80211_send_scan_msg(struct sk_buff *msg,
struct cfg80211_registered_device *rdev,
struct net_device *netdev,
struct wireless_dev *wdev,
u32 pid, u32 seq, int flags,
u32 cmd)
{
@@ -7328,7 +7528,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
return -1;
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
(wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
wdev->netdev->ifindex)) ||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
goto nla_put_failure;
/* ignore errors and send incomplete event anyway */
@@ -7365,7 +7567,7 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg,
}
void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
struct net_device *netdev)
struct wireless_dev *wdev)
{
struct sk_buff *msg;
@@ -7373,7 +7575,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
if (!msg)
return;
if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0,
if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
NL80211_CMD_TRIGGER_SCAN) < 0) {
nlmsg_free(msg);
return;
@@ -7384,7 +7586,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
}
void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
struct net_device *netdev)
struct wireless_dev *wdev)
{
struct sk_buff *msg;
@@ -7392,7 +7594,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
if (!msg)
return;
if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0,
if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
NL80211_CMD_NEW_SCAN_RESULTS) < 0) {
nlmsg_free(msg);
return;
@@ -7403,7 +7605,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
}
void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
struct net_device *netdev)
struct wireless_dev *wdev)
{
struct sk_buff *msg;
@@ -7411,7 +7613,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
if (!msg)
return;
if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0,
if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0,
NL80211_CMD_SCAN_ABORTED) < 0) {
nlmsg_free(msg);
return;
@@ -7934,7 +8136,7 @@ nla_put_failure:
static void nl80211_send_remain_on_chan_event(
int cmd, struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie,
struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp)
@@ -7953,7 +8155,9 @@ static void nl80211_send_remain_on_chan_event(
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
(wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
wdev->netdev->ifindex)) ||
nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) ||
nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
@@ -7975,23 +8179,24 @@ static void nl80211_send_remain_on_chan_event(
}
void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie,
struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp)
{
nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
rdev, netdev, cookie, chan,
rdev, wdev, cookie, chan,
channel_type, duration, gfp);
}
void nl80211_send_remain_on_channel_cancel(
struct cfg80211_registered_device *rdev, struct net_device *netdev,
struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
u64 cookie, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, gfp_t gfp)
{
nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
rdev, netdev, cookie, chan,
rdev, wdev, cookie, chan,
channel_type, 0, gfp);
}
@@ -8105,10 +8310,11 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev,
}
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 nlpid,
struct wireless_dev *wdev, u32 nlpid,
int freq, int sig_dbm,
const u8 *buf, size_t len, gfp_t gfp)
{
struct net_device *netdev = wdev->netdev;
struct sk_buff *msg;
void *hdr;
@@ -8123,7 +8329,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
(netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
netdev->ifindex)) ||
nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
(sig_dbm &&
nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
@@ -8141,10 +8348,11 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
}
void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie,
struct wireless_dev *wdev, u64 cookie,
const u8 *buf, size_t len, bool ack,
gfp_t gfp)
{
struct net_device *netdev = wdev->netdev;
struct sk_buff *msg;
void *hdr;
@@ -8159,7 +8367,8 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
(netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX,
netdev->ifindex)) ||
nla_put(msg, NL80211_ATTR_FRAME, len, buf) ||
nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) ||
(ack && nla_put_flag(msg, NL80211_ATTR_ACK)))
@@ -8342,6 +8551,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
nlmsg_free(msg);
}
void
nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *peer,
u32 num_packets, u32 rate, u32 intvl, gfp_t gfp)
{
struct sk_buff *msg;
struct nlattr *pinfoattr;
void *hdr;
msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
if (!msg)
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM);
if (!hdr) {
nlmsg_free(msg);
return;
}
if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer))
goto nla_put_failure;
pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM);
if (!pinfoattr)
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets))
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate))
goto nla_put_failure;
if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl))
goto nla_put_failure;
nla_nest_end(msg, pinfoattr);
genlmsg_end(msg, hdr);
genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
nl80211_mlme_mcgrp.id, gfp);
return;
nla_put_failure:
genlmsg_cancel(msg, hdr);
nlmsg_free(msg);
}
void
nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *peer,
@@ -8483,7 +8742,7 @@ 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->netdev_list, list)
list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
cfg80211_mlme_unregister_socket(wdev, notify->pid);
if (rdev->ap_beacons_nlpid == notify->pid)
rdev->ap_beacons_nlpid = 0;
+13 -8
View File
@@ -7,11 +7,11 @@ int nl80211_init(void);
void nl80211_exit(void);
void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev);
void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
struct net_device *netdev);
struct wireless_dev *wdev);
void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
struct net_device *netdev);
struct wireless_dev *wdev);
void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
struct net_device *netdev);
struct wireless_dev *wdev);
void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 cmd);
void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
@@ -74,13 +74,13 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
gfp_t gfp);
void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
u64 cookie,
struct wireless_dev *wdev, u64 cookie,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
unsigned int duration, gfp_t gfp);
void nl80211_send_remain_on_channel_cancel(
struct cfg80211_registered_device *rdev, struct net_device *netdev,
struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
u64 cookie, struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type, gfp_t gfp);
@@ -92,11 +92,11 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
gfp_t gfp);
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 nlpid,
struct wireless_dev *wdev, u32 nlpid,
int freq, int sig_dbm,
const u8 *buf, size_t len, gfp_t gfp);
void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u64 cookie,
struct wireless_dev *wdev, u64 cookie,
const u8 *buf, size_t len, bool ack,
gfp_t gfp);
@@ -110,6 +110,11 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *peer,
u32 num_packets, gfp_t gfp);
void
nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *peer,
u32 num_packets, u32 rate, u32 intvl, gfp_t gfp);
void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev, const u8 *bssid,
const u8 *replay_ctr, gfp_t gfp);
+116 -16
View File
@@ -97,9 +97,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain;
* - cfg80211_world_regdom
* - cfg80211_regdom
* - last_request
* - reg_num_devs_support_basehint
*/
static DEFINE_MUTEX(reg_mutex);
/*
* Number of devices that registered to the core
* that support cellular base station regulatory hints
*/
static int reg_num_devs_support_basehint;
static inline void assert_reg_lock(void)
{
lockdep_assert_held(&reg_mutex);
@@ -911,6 +918,61 @@ static void handle_band(struct wiphy *wiphy,
handle_channel(wiphy, initiator, band, i);
}
static bool reg_request_cell_base(struct regulatory_request *request)
{
if (request->initiator != NL80211_REGDOM_SET_BY_USER)
return false;
if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
return false;
return true;
}
bool reg_last_request_cell_base(void)
{
bool val;
assert_cfg80211_lock();
mutex_lock(&reg_mutex);
val = reg_request_cell_base(last_request);
mutex_unlock(&reg_mutex);
return val;
}
#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS
/* Core specific check */
static int reg_ignore_cell_hint(struct regulatory_request *pending_request)
{
if (!reg_num_devs_support_basehint)
return -EOPNOTSUPP;
if (reg_request_cell_base(last_request)) {
if (!regdom_changes(pending_request->alpha2))
return -EALREADY;
return 0;
}
return 0;
}
/* Device specific check */
static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy)
{
if (!(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS))
return true;
return false;
}
#else
static int reg_ignore_cell_hint(struct regulatory_request *pending_request)
{
return -EOPNOTSUPP;
}
static int reg_dev_ignore_cell_hint(struct wiphy *wiphy)
{
return true;
}
#endif
static bool ignore_reg_update(struct wiphy *wiphy,
enum nl80211_reg_initiator initiator)
{
@@ -944,6 +1006,9 @@ static bool ignore_reg_update(struct wiphy *wiphy,
return true;
}
if (reg_request_cell_base(last_request))
return reg_dev_ignore_cell_hint(wiphy);
return false;
}
@@ -1169,14 +1234,6 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,
wiphy->reg_notifier(wiphy, last_request);
}
void regulatory_update(struct wiphy *wiphy,
enum nl80211_reg_initiator setby)
{
mutex_lock(&reg_mutex);
wiphy_update_regulatory(wiphy, setby);
mutex_unlock(&reg_mutex);
}
static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
{
struct cfg80211_registered_device *rdev;
@@ -1307,6 +1364,13 @@ static int ignore_request(struct wiphy *wiphy,
return 0;
case NL80211_REGDOM_SET_BY_COUNTRY_IE:
if (reg_request_cell_base(last_request)) {
/* Trust a Cell base station over the AP's country IE */
if (regdom_changes(pending_request->alpha2))
return -EOPNOTSUPP;
return -EALREADY;
}
last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
if (unlikely(!is_an_alpha2(pending_request->alpha2)))
@@ -1351,6 +1415,12 @@ static int ignore_request(struct wiphy *wiphy,
return REG_INTERSECT;
case NL80211_REGDOM_SET_BY_USER:
if (reg_request_cell_base(pending_request))
return reg_ignore_cell_hint(pending_request);
if (reg_request_cell_base(last_request))
return -EOPNOTSUPP;
if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
return REG_INTERSECT;
/*
@@ -1640,7 +1710,8 @@ static int regulatory_hint_core(const char *alpha2)
}
/* User hints */
int regulatory_hint_user(const char *alpha2)
int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type)
{
struct regulatory_request *request;
@@ -1654,6 +1725,7 @@ int regulatory_hint_user(const char *alpha2)
request->alpha2[0] = alpha2[0];
request->alpha2[1] = alpha2[1];
request->initiator = NL80211_REGDOM_SET_BY_USER;
request->user_reg_hint_type = user_reg_hint_type;
queue_regulatory_request(request);
@@ -1906,7 +1978,7 @@ static void restore_regulatory_settings(bool reset_user)
* settings, user regulatory settings takes precedence.
*/
if (is_an_alpha2(alpha2))
regulatory_hint_user(user_alpha2);
regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER);
if (list_empty(&tmp_reg_req_list))
return;
@@ -2081,9 +2153,16 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
else {
if (is_unknown_alpha2(rd->alpha2))
pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n");
else
pr_info("Regulatory domain changed to country: %c%c\n",
rd->alpha2[0], rd->alpha2[1]);
else {
if (reg_request_cell_base(last_request))
pr_info("Regulatory domain changed "
"to country: %c%c by Cell Station\n",
rd->alpha2[0], rd->alpha2[1]);
else
pr_info("Regulatory domain changed "
"to country: %c%c\n",
rd->alpha2[0], rd->alpha2[1]);
}
}
print_dfs_region(rd->dfs_region);
print_rd_rules(rd);
@@ -2128,7 +2207,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
* checking if the alpha2 changes if CRDA was already called
*/
if (!regdom_changes(rd->alpha2))
return -EINVAL;
return -EALREADY;
}
/*
@@ -2248,6 +2327,9 @@ int set_regdom(const struct ieee80211_regdomain *rd)
/* Note that this doesn't update the wiphys, this is done below */
r = __set_regdom(rd);
if (r) {
if (r == -EALREADY)
reg_set_request_processed();
kfree(rd);
mutex_unlock(&reg_mutex);
return r;
@@ -2290,8 +2372,22 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
}
#endif /* CONFIG_HOTPLUG */
void wiphy_regulatory_register(struct wiphy *wiphy)
{
assert_cfg80211_lock();
mutex_lock(&reg_mutex);
if (!reg_dev_ignore_cell_hint(wiphy))
reg_num_devs_support_basehint++;
wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
mutex_unlock(&reg_mutex);
}
/* Caller must hold cfg80211_mutex */
void reg_device_remove(struct wiphy *wiphy)
void wiphy_regulatory_deregister(struct wiphy *wiphy)
{
struct wiphy *request_wiphy = NULL;
@@ -2299,6 +2395,9 @@ void reg_device_remove(struct wiphy *wiphy)
mutex_lock(&reg_mutex);
if (!reg_dev_ignore_cell_hint(wiphy))
reg_num_devs_support_basehint--;
kfree(wiphy->regd);
if (last_request)
@@ -2364,7 +2463,8 @@ int __init regulatory_init(void)
* as a user hint.
*/
if (!is_world_regdom(ieee80211_regdom))
regulatory_hint_user(ieee80211_regdom);
regulatory_hint_user(ieee80211_regdom,
NL80211_USER_REG_HINT_USER);
return 0;
}
+5 -3
View File
@@ -22,17 +22,19 @@ bool is_world_regdom(const char *alpha2);
bool reg_is_valid_request(const char *alpha2);
bool reg_supported_dfs_region(u8 dfs_region);
int regulatory_hint_user(const char *alpha2);
int regulatory_hint_user(const char *alpha2,
enum nl80211_user_reg_hint_type user_reg_hint_type);
int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env);
void reg_device_remove(struct wiphy *wiphy);
void wiphy_regulatory_register(struct wiphy *wiphy);
void wiphy_regulatory_deregister(struct wiphy *wiphy);
int __init regulatory_init(void);
void regulatory_exit(void);
int set_regdom(const struct ieee80211_regdomain *rd);
void regulatory_update(struct wiphy *wiphy, enum nl80211_reg_initiator setby);
bool reg_last_request_cell_base(void);
/**
* regulatory_hint_found_beacon - hints a beacon was found on a channel
+13 -11
View File
@@ -23,7 +23,7 @@
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
struct cfg80211_scan_request *request;
struct net_device *dev;
struct wireless_dev *wdev;
#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -35,29 +35,31 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
if (!request)
return;
dev = request->dev;
wdev = request->wdev;
/*
* This must be before sending the other events!
* Otherwise, wpa_supplicant gets completely confused with
* wext events.
*/
cfg80211_sme_scan_done(dev);
if (wdev->netdev)
cfg80211_sme_scan_done(wdev->netdev);
if (request->aborted)
nl80211_send_scan_aborted(rdev, dev);
nl80211_send_scan_aborted(rdev, wdev);
else
nl80211_send_scan_done(rdev, dev);
nl80211_send_scan_done(rdev, wdev);
#ifdef CONFIG_CFG80211_WEXT
if (!request->aborted) {
if (wdev->netdev && !request->aborted) {
memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL);
}
#endif
dev_put(dev);
if (wdev->netdev)
dev_put(wdev->netdev);
rdev->scan_req = NULL;
@@ -955,7 +957,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
}
creq->wiphy = wiphy;
creq->dev = dev;
creq->wdev = dev->ieee80211_ptr;
/* SSIDs come after channels */
creq->ssids = (void *)&creq->channels[n_channels];
creq->n_channels = n_channels;
@@ -1024,12 +1026,12 @@ int cfg80211_wext_siwscan(struct net_device *dev,
creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
rdev->scan_req = creq;
err = rdev->ops->scan(wiphy, dev, creq);
err = rdev->ops->scan(wiphy, creq);
if (err) {
rdev->scan_req = NULL;
/* creq will be freed below */
} else {
nl80211_send_scan_start(rdev, dev);
nl80211_send_scan_start(rdev, dev->ieee80211_ptr);
/* creq now owned by driver */
creq = NULL;
dev_hold(dev);
+5 -5
View File
@@ -51,7 +51,7 @@ static bool cfg80211_is_all_idle(void)
*/
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
cfg80211_lock_rdev(rdev);
list_for_each_entry(wdev, &rdev->netdev_list, list) {
list_for_each_entry(wdev, &rdev->wdev_list, list) {
wdev_lock(wdev);
if (wdev->sme_state != CFG80211_SME_IDLE)
is_all_idle = false;
@@ -136,15 +136,15 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
wdev->conn->params.ssid_len);
request->ssids[0].ssid_len = wdev->conn->params.ssid_len;
request->dev = wdev->netdev;
request->wdev = wdev;
request->wiphy = &rdev->wiphy;
rdev->scan_req = request;
err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request);
err = rdev->ops->scan(wdev->wiphy, request);
if (!err) {
wdev->conn->state = CFG80211_CONN_SCANNING;
nl80211_send_scan_start(rdev, wdev->netdev);
nl80211_send_scan_start(rdev, wdev);
dev_hold(wdev->netdev);
} else {
rdev->scan_req = NULL;
@@ -221,7 +221,7 @@ void cfg80211_conn_work(struct work_struct *work)
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) {
list_for_each_entry(wdev, &rdev->wdev_list, list) {
wdev_lock(wdev);
if (!netif_running(wdev->netdev)) {
wdev_unlock(wdev);
+13 -4
View File
@@ -793,7 +793,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list)
list_for_each_entry(wdev, &rdev->wdev_list, list)
cfg80211_process_wdev_events(wdev);
mutex_unlock(&rdev->devlist_mtx);
@@ -994,7 +994,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) {
list_for_each_entry(wdev, &rdev->wdev_list, list) {
if (!wdev->beacon_interval)
continue;
if (wdev->beacon_interval != beacon_int) {
@@ -1050,7 +1050,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
break;
}
list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
if (wdev_iter == wdev)
continue;
if (!netif_running(wdev_iter->netdev))
@@ -1059,7 +1059,16 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
continue;
cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode);
/*
* We may be holding the "wdev" mutex, but now need to lock
* wdev_iter. This is OK because once we get here wdev_iter
* is not wdev (tested above), but we need to use the nested
* locking for lockdep.
*/
mutex_lock_nested(&wdev_iter->mtx, 1);
__acquire(wdev_iter->mtx);
cfg80211_get_chan_state(wdev_iter, &ch, &chmode);
wdev_unlock(wdev_iter);
switch (chmode) {
case CHAN_MODE_UNDEFINED:
+7 -2
View File
@@ -827,6 +827,8 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type;
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
@@ -834,10 +836,13 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
case NL80211_IFTYPE_MONITOR:
if (!rdev->monitor_channel)
if (!rdev->ops->get_channel)
return -EINVAL;
freq->m = rdev->monitor_channel->center_freq;
chan = rdev->ops->get_channel(wdev->wiphy, wdev, &channel_type);
if (!chan)
return -EINVAL;
freq->m = chan->center_freq;
freq->e = 6;
return 0;
default: