Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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, ¶ms);
|
||||
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
@@ -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
@@ -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(®_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(®_mutex);
|
||||
val = reg_request_cell_base(last_request);
|
||||
mutex_unlock(®_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(®_mutex);
|
||||
wiphy_update_regulatory(wiphy, setby);
|
||||
mutex_unlock(®_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(®_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(®_mutex);
|
||||
|
||||
if (!reg_dev_ignore_cell_hint(wiphy))
|
||||
reg_num_devs_support_basehint++;
|
||||
|
||||
wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
|
||||
|
||||
mutex_unlock(®_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(®_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
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user