Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
This commit is contained in:
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
|
||||
obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
|
||||
|
||||
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
|
||||
cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o
|
||||
cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o
|
||||
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
|
||||
cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
|
||||
cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
|
||||
|
46
net/wireless/ap.c
Normal file
46
net/wireless/ap.c
Normal file
@@ -0,0 +1,46 @@
|
||||
#include <linux/ieee80211.h>
|
||||
#include <linux/export.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "nl80211.h"
|
||||
#include "core.h"
|
||||
|
||||
|
||||
static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!rdev->ops->stop_ap)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!wdev->beacon_interval)
|
||||
return -ENOENT;
|
||||
|
||||
err = rdev->ops->stop_ap(&rdev->wiphy, dev);
|
||||
if (!err) {
|
||||
wdev->beacon_interval = 0;
|
||||
wdev->channel = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_stop_ap(rdev, dev);
|
||||
wdev_unlock(wdev);
|
||||
|
||||
return err;
|
||||
}
|
@@ -82,13 +82,73 @@ 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;
|
||||
if (!cfg80211_has_monitors_only(rdev))
|
||||
return -EBUSY;
|
||||
|
||||
chan = rdev_freq_to_chan(rdev, freq, chantype);
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
|
||||
return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
|
||||
err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
|
||||
if (!err) {
|
||||
rdev->monitor_channel = chan;
|
||||
rdev->monitor_channel_type = chantype;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
|
||||
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))
|
||||
return;
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
if (wdev->current_bss) {
|
||||
*chan = wdev->current_bss->pub.channel;
|
||||
*chanmode = wdev->ibss_fixed
|
||||
? CHAN_MODE_SHARED
|
||||
: CHAN_MODE_EXCLUSIVE;
|
||||
return;
|
||||
}
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (wdev->current_bss) {
|
||||
*chan = wdev->current_bss->pub.channel;
|
||||
*chanmode = CHAN_MODE_SHARED;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
*chan = wdev->channel;
|
||||
*chanmode = CHAN_MODE_SHARED;
|
||||
return;
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_AP_VLAN:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
/* these interface types don't really have a channel */
|
||||
return;
|
||||
case NL80211_IFTYPE_UNSPECIFIED:
|
||||
case NUM_NL80211_IFTYPES:
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
|
||||
if (WARN_ON(!c->num_different_channels))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Put a sane limit on maximum number of different
|
||||
* channels to simplify channel accounting code.
|
||||
*/
|
||||
if (WARN_ON(c->num_different_channels >
|
||||
CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(!c->n_limits))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -421,9 +429,11 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
int i;
|
||||
u16 ifmodes = wiphy->interface_modes;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
|
||||
!(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
if (WARN_ON(wiphy->ap_sme_capa &&
|
||||
!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
|
||||
@@ -458,8 +468,14 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
continue;
|
||||
|
||||
sband->band = band;
|
||||
|
||||
if (WARN_ON(!sband->n_channels || !sband->n_bitrates))
|
||||
if (WARN_ON(!sband->n_channels))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* on 60gHz band, there are no legacy rates, so
|
||||
* n_bitrates is 0
|
||||
*/
|
||||
if (WARN_ON(band != IEEE80211_BAND_60GHZ &&
|
||||
!sband->n_bitrates))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
@@ -500,12 +516,14 @@ int wiphy_register(struct wiphy *wiphy)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (rdev->wiphy.wowlan.n_patterns) {
|
||||
if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len ||
|
||||
rdev->wiphy.wowlan.pattern_min_len >
|
||||
rdev->wiphy.wowlan.pattern_max_len))
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check and set up bitrates */
|
||||
ieee80211_set_bitrate_flags(wiphy);
|
||||
@@ -713,6 +731,61 @@ 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,
|
||||
unsigned long state,
|
||||
void *ndev)
|
||||
@@ -806,12 +879,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
cfg80211_leave_mesh(rdev, dev);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
cfg80211_stop_ap(rdev, dev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
wdev->beacon_interval = 0;
|
||||
break;
|
||||
case NETDEV_DOWN:
|
||||
cfg80211_update_iface_num(rdev, wdev->iftype, -1);
|
||||
dev_hold(dev);
|
||||
queue_work(cfg80211_wq, &wdev->cleanup_work);
|
||||
break;
|
||||
@@ -917,9 +994,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
|
||||
return notifier_from_errno(-EOPNOTSUPP);
|
||||
if (rfkill_blocked(rdev->rfkill))
|
||||
return notifier_from_errno(-ERFKILL);
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
ret = cfg80211_can_add_interface(rdev, wdev->iftype);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
if (ret)
|
||||
return notifier_from_errno(ret);
|
||||
cfg80211_update_iface_num(rdev, wdev->iftype, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include "reg.h"
|
||||
@@ -56,6 +57,13 @@ struct cfg80211_registered_device {
|
||||
|
||||
u32 ap_beacons_nlpid;
|
||||
|
||||
/* protected by RTNL only */
|
||||
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;
|
||||
@@ -197,6 +205,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev)
|
||||
#define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx)
|
||||
#define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx)
|
||||
|
||||
static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces &&
|
||||
rdev->num_running_ifaces > 0;
|
||||
}
|
||||
|
||||
enum cfg80211_event_type {
|
||||
EVENT_CONNECT_RESULT,
|
||||
EVENT_ROAMED,
|
||||
@@ -241,6 +257,12 @@ struct cfg80211_cached_keys {
|
||||
int def, defmgmt;
|
||||
};
|
||||
|
||||
enum cfg80211_chan_mode {
|
||||
CHAN_MODE_UNDEFINED,
|
||||
CHAN_MODE_SHARED,
|
||||
CHAN_MODE_EXCLUSIVE,
|
||||
};
|
||||
|
||||
|
||||
/* free object */
|
||||
extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
|
||||
@@ -289,6 +311,10 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, int freq,
|
||||
enum nl80211_channel_type channel_type);
|
||||
|
||||
/* AP */
|
||||
int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev);
|
||||
|
||||
/* MLME */
|
||||
int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
@@ -404,9 +430,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
u32 *flags, struct vif_params *params);
|
||||
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
|
||||
|
||||
int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype);
|
||||
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode);
|
||||
|
||||
static inline int
|
||||
cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
|
||||
CHAN_MODE_UNDEFINED);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
|
||||
@@ -415,6 +452,22 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
|
||||
return cfg80211_can_change_interface(rdev, NULL, iftype);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode)
|
||||
{
|
||||
return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
|
||||
chan, chanmode);
|
||||
}
|
||||
|
||||
void
|
||||
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel **chan,
|
||||
enum cfg80211_chan_mode *chanmode);
|
||||
|
||||
struct ieee80211_channel *
|
||||
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
|
||||
int freq, enum nl80211_channel_type channel_type);
|
||||
@@ -428,6 +481,11 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
|
||||
int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
||||
u32 beacon_int);
|
||||
|
||||
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_iftype iftype, int num);
|
||||
|
||||
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
|
||||
|
||||
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
|
||||
#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
|
||||
#else
|
||||
|
@@ -113,10 +113,21 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
kfree(wdev->connect_keys);
|
||||
wdev->connect_keys = connkeys;
|
||||
|
||||
wdev->ibss_fixed = params->channel_fixed;
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
wdev->wext.ibss.channel = params->channel;
|
||||
#endif
|
||||
wdev->sme_state = CFG80211_SME_CONNECTING;
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, params->channel,
|
||||
params->channel_fixed
|
||||
? CHAN_MODE_SHARED
|
||||
: CHAN_MODE_EXCLUSIVE);
|
||||
if (err) {
|
||||
wdev->connect_keys = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
|
||||
if (err) {
|
||||
wdev->connect_keys = NULL;
|
||||
|
@@ -155,10 +155,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
|
||||
setup->channel_type))
|
||||
return -EINVAL;
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, setup->channel,
|
||||
CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
|
||||
if (!err) {
|
||||
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
|
||||
wdev->mesh_id_len = setup->mesh_id_len;
|
||||
wdev->channel = setup->channel;
|
||||
}
|
||||
|
||||
return err;
|
||||
@@ -172,9 +178,11 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_join_mesh(rdev, dev, setup, conf);
|
||||
wdev_unlock(wdev);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -184,6 +192,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct ieee80211_channel *channel;
|
||||
int err;
|
||||
|
||||
channel = rdev_freq_to_chan(rdev, freq, channel_type);
|
||||
if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
|
||||
@@ -205,9 +214,19 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
|
||||
|
||||
if (!netif_running(wdev->netdev))
|
||||
return -ENETDOWN;
|
||||
return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
|
||||
wdev->netdev,
|
||||
channel);
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, channel,
|
||||
CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
|
||||
wdev->netdev,
|
||||
channel);
|
||||
if (!err)
|
||||
wdev->channel = channel;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
if (wdev->mesh_id_len)
|
||||
@@ -249,8 +268,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
|
||||
return -ENOTCONN;
|
||||
|
||||
err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
|
||||
if (!err)
|
||||
if (!err) {
|
||||
wdev->mesh_id_len = 0;
|
||||
wdev->channel = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@@ -302,8 +302,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
if (!req.bss)
|
||||
return -ENOENT;
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
|
||||
CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = rdev->ops->auth(&rdev->wiphy, dev, &req);
|
||||
|
||||
out:
|
||||
cfg80211_put_bss(req.bss);
|
||||
return err;
|
||||
}
|
||||
@@ -317,11 +323,13 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
wdev_lock(dev->ieee80211_ptr);
|
||||
err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
|
||||
ssid, ssid_len, ie, ie_len,
|
||||
key, key_len, key_idx);
|
||||
wdev_unlock(dev->ieee80211_ptr);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -397,8 +405,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel,
|
||||
CHAN_MODE_SHARED);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
|
||||
|
||||
out:
|
||||
if (err) {
|
||||
if (was_connected)
|
||||
wdev->sme_state = CFG80211_SME_CONNECTED;
|
||||
@@ -421,11 +435,13 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
wdev_lock(wdev);
|
||||
err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
|
||||
ssid, ssid_len, ie, ie_len, use_mfp, crypt,
|
||||
assoc_flags, ht_capa, ht_capa_mask);
|
||||
wdev_unlock(wdev);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -947,6 +963,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
|
||||
if (WARN_ON(!chan))
|
||||
goto out;
|
||||
|
||||
wdev->channel = chan;
|
||||
nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
|
||||
out:
|
||||
wdev_unlock(wdev);
|
||||
|
@@ -921,6 +921,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
dev->wiphy.bands[band]->ht_cap.ampdu_density)))
|
||||
goto nla_put_failure;
|
||||
|
||||
/* add VHT info */
|
||||
if (dev->wiphy.bands[band]->vht_cap.vht_supported &&
|
||||
(nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET,
|
||||
sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs),
|
||||
&dev->wiphy.bands[band]->vht_cap.vht_mcs) ||
|
||||
nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA,
|
||||
dev->wiphy.bands[band]->vht_cap.cap)))
|
||||
goto nla_put_failure;
|
||||
|
||||
/* add frequencies */
|
||||
nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
|
||||
if (!nl_freqs)
|
||||
@@ -1112,6 +1121,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
nla_nest_end(msg, nl_ifs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) {
|
||||
struct nlattr *nl_wowlan;
|
||||
|
||||
@@ -1152,6 +1162,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
|
||||
nla_nest_end(msg, nl_wowlan);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
|
||||
dev->wiphy.software_iftypes))
|
||||
@@ -1678,16 +1689,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
(cfg80211_rdev_list_generation << 2)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (rdev->ops->get_channel) {
|
||||
struct ieee80211_channel *chan;
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
chan = rdev->ops->get_channel(&rdev->wiphy, &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)))
|
||||
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))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
@@ -2472,11 +2478,20 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
||||
params.channel_type))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
err = cfg80211_can_use_chan(rdev, wdev, params.channel,
|
||||
CHAN_MODE_SHARED);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms);
|
||||
if (!err) {
|
||||
wdev->preset_chan = params.channel;
|
||||
wdev->preset_chantype = params.channel_type;
|
||||
wdev->beacon_interval = params.beacon_interval;
|
||||
wdev->channel = params.channel;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -2510,23 +2525,8 @@ static int nl80211_stop_ap(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 = dev->ieee80211_ptr;
|
||||
int err;
|
||||
|
||||
if (!rdev->ops->stop_ap)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
|
||||
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!wdev->beacon_interval)
|
||||
return -ENOENT;
|
||||
|
||||
err = rdev->ops->stop_ap(&rdev->wiphy, dev);
|
||||
if (!err)
|
||||
wdev->beacon_interval = 0;
|
||||
return err;
|
||||
return cfg80211_stop_ap(rdev, dev);
|
||||
}
|
||||
|
||||
static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
|
||||
@@ -2618,7 +2618,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
int attr)
|
||||
{
|
||||
struct nlattr *rate;
|
||||
u16 bitrate;
|
||||
u32 bitrate;
|
||||
u16 bitrate_compat;
|
||||
|
||||
rate = nla_nest_start(msg, attr);
|
||||
if (!rate)
|
||||
@@ -2626,8 +2627,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
|
||||
|
||||
/* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
|
||||
bitrate = cfg80211_calculate_bitrate(info);
|
||||
/* report 16-bit bitrate only if we can */
|
||||
bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
|
||||
if ((bitrate > 0 &&
|
||||
nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) ||
|
||||
nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) ||
|
||||
(bitrate_compat > 0 &&
|
||||
nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) ||
|
||||
((info->flags & RATE_INFO_FLAGS_MCS) &&
|
||||
nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) ||
|
||||
((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) &&
|
||||
@@ -6276,6 +6281,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
|
||||
return cfg80211_leave_mesh(rdev, dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
@@ -6504,6 +6510,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
|
||||
kfree(new_triggers.patterns);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
@@ -7158,6 +7165,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
#ifdef CONFIG_PM
|
||||
{
|
||||
.cmd = NL80211_CMD_GET_WOWLAN,
|
||||
.doit = nl80211_get_wowlan,
|
||||
@@ -7174,6 +7182,7 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.internal_flags = NL80211_FLAG_NEED_WIPHY |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_REKEY_OFFLOAD,
|
||||
.doit = nl80211_set_rekey_data,
|
||||
|
@@ -129,7 +129,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work);
|
||||
|
||||
/* We keep a static world regulatory domain in case of the absence of CRDA */
|
||||
static const struct ieee80211_regdomain world_regdom = {
|
||||
.n_reg_rules = 5,
|
||||
.n_reg_rules = 6,
|
||||
.alpha2 = "00",
|
||||
.reg_rules = {
|
||||
/* IEEE 802.11b/g, channels 1..11 */
|
||||
@@ -156,6 +156,9 @@ static const struct ieee80211_regdomain world_regdom = {
|
||||
REG_RULE(5745-10, 5825+10, 40, 6, 20,
|
||||
NL80211_RRF_PASSIVE_SCAN |
|
||||
NL80211_RRF_NO_IBSS),
|
||||
|
||||
/* IEEE 802.11ad (60gHz), channels 1..3 */
|
||||
REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0),
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -35,19 +35,29 @@ int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band)
|
||||
{
|
||||
/* see 802.11 17.3.8.3.2 and Annex J
|
||||
* there are overlapping channel numbers in 5GHz and 2GHz bands */
|
||||
if (band == IEEE80211_BAND_5GHZ) {
|
||||
if (chan >= 182 && chan <= 196)
|
||||
return 4000 + chan * 5;
|
||||
else
|
||||
return 5000 + chan * 5;
|
||||
} else { /* IEEE80211_BAND_2GHZ */
|
||||
if (chan <= 0)
|
||||
return 0; /* not supported */
|
||||
switch (band) {
|
||||
case IEEE80211_BAND_2GHZ:
|
||||
if (chan == 14)
|
||||
return 2484;
|
||||
else if (chan < 14)
|
||||
return 2407 + chan * 5;
|
||||
break;
|
||||
case IEEE80211_BAND_5GHZ:
|
||||
if (chan >= 182 && chan <= 196)
|
||||
return 4000 + chan * 5;
|
||||
else
|
||||
return 0; /* not supported */
|
||||
return 5000 + chan * 5;
|
||||
break;
|
||||
case IEEE80211_BAND_60GHZ:
|
||||
if (chan < 5)
|
||||
return 56160 + chan * 2160;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return 0; /* not supported */
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_channel_to_frequency);
|
||||
|
||||
@@ -60,8 +70,12 @@ int ieee80211_frequency_to_channel(int freq)
|
||||
return (freq - 2407) / 5;
|
||||
else if (freq >= 4910 && freq <= 4980)
|
||||
return (freq - 4000) / 5;
|
||||
else
|
||||
else if (freq <= 45000) /* DMG band lower limit */
|
||||
return (freq - 5000) / 5;
|
||||
else if (freq >= 58320 && freq <= 64800)
|
||||
return (freq - 56160) / 2160;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_frequency_to_channel);
|
||||
|
||||
@@ -137,6 +151,11 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
|
||||
}
|
||||
WARN_ON(want != 0 && want != 3 && want != 6);
|
||||
break;
|
||||
case IEEE80211_BAND_60GHZ:
|
||||
/* check for mandatory HT MCS 1..4 */
|
||||
WARN_ON(!sband->ht_cap.ht_supported);
|
||||
WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e);
|
||||
break;
|
||||
case IEEE80211_NUM_BANDS:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
@@ -805,8 +824,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
return -EBUSY;
|
||||
|
||||
if (ntype != otype && netif_running(dev)) {
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
|
||||
ntype);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -814,6 +835,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
dev->ieee80211_ptr->mesh_id_up_len = 0;
|
||||
|
||||
switch (otype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
cfg80211_stop_ap(rdev, dev);
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
cfg80211_leave_ibss(rdev, dev, false);
|
||||
break;
|
||||
@@ -868,15 +892,69 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
||||
}
|
||||
}
|
||||
|
||||
if (!err && ntype != otype && netif_running(dev)) {
|
||||
cfg80211_update_iface_num(rdev, ntype, 1);
|
||||
cfg80211_update_iface_num(rdev, otype, -1);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
u16 cfg80211_calculate_bitrate(struct rate_info *rate)
|
||||
static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
|
||||
{
|
||||
static const u32 __mcs2bitrate[] = {
|
||||
/* control PHY */
|
||||
[0] = 275,
|
||||
/* SC PHY */
|
||||
[1] = 3850,
|
||||
[2] = 7700,
|
||||
[3] = 9625,
|
||||
[4] = 11550,
|
||||
[5] = 12512, /* 1251.25 mbps */
|
||||
[6] = 15400,
|
||||
[7] = 19250,
|
||||
[8] = 23100,
|
||||
[9] = 25025,
|
||||
[10] = 30800,
|
||||
[11] = 38500,
|
||||
[12] = 46200,
|
||||
/* OFDM PHY */
|
||||
[13] = 6930,
|
||||
[14] = 8662, /* 866.25 mbps */
|
||||
[15] = 13860,
|
||||
[16] = 17325,
|
||||
[17] = 20790,
|
||||
[18] = 27720,
|
||||
[19] = 34650,
|
||||
[20] = 41580,
|
||||
[21] = 45045,
|
||||
[22] = 51975,
|
||||
[23] = 62370,
|
||||
[24] = 67568, /* 6756.75 mbps */
|
||||
/* LP-SC PHY */
|
||||
[25] = 6260,
|
||||
[26] = 8340,
|
||||
[27] = 11120,
|
||||
[28] = 12510,
|
||||
[29] = 16680,
|
||||
[30] = 22240,
|
||||
[31] = 25030,
|
||||
};
|
||||
|
||||
if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate)))
|
||||
return 0;
|
||||
|
||||
return __mcs2bitrate[rate->mcs];
|
||||
}
|
||||
|
||||
u32 cfg80211_calculate_bitrate(struct rate_info *rate)
|
||||
{
|
||||
int modulation, streams, bitrate;
|
||||
|
||||
if (!(rate->flags & RATE_INFO_FLAGS_MCS))
|
||||
return rate->legacy;
|
||||
if (rate->flags & RATE_INFO_FLAGS_60G)
|
||||
return cfg80211_calculate_bitrate_60g(rate);
|
||||
|
||||
/* the formula below does only work for MCS values smaller than 32 */
|
||||
if (WARN_ON_ONCE(rate->mcs >= 32))
|
||||
@@ -930,27 +1008,48 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
||||
return res;
|
||||
}
|
||||
|
||||
int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype)
|
||||
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode)
|
||||
{
|
||||
struct wireless_dev *wdev_iter;
|
||||
u32 used_iftypes = BIT(iftype);
|
||||
int num[NUM_NL80211_IFTYPES];
|
||||
struct ieee80211_channel
|
||||
*used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
|
||||
struct ieee80211_channel *ch;
|
||||
enum cfg80211_chan_mode chmode;
|
||||
int num_different_channels = 0;
|
||||
int total = 1;
|
||||
int i, j;
|
||||
|
||||
ASSERT_RTNL();
|
||||
lockdep_assert_held(&rdev->devlist_mtx);
|
||||
|
||||
/* Always allow software iftypes */
|
||||
if (rdev->wiphy.software_iftypes & BIT(iftype))
|
||||
return 0;
|
||||
|
||||
memset(num, 0, sizeof(num));
|
||||
memset(used_channels, 0, sizeof(used_channels));
|
||||
|
||||
num[iftype] = 1;
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
switch (chanmode) {
|
||||
case CHAN_MODE_UNDEFINED:
|
||||
break;
|
||||
case CHAN_MODE_SHARED:
|
||||
WARN_ON(!chan);
|
||||
used_channels[0] = chan;
|
||||
num_different_channels++;
|
||||
break;
|
||||
case CHAN_MODE_EXCLUSIVE:
|
||||
num_different_channels++;
|
||||
break;
|
||||
}
|
||||
|
||||
list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
|
||||
if (wdev_iter == wdev)
|
||||
continue;
|
||||
@@ -960,11 +1059,33 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
|
||||
continue;
|
||||
|
||||
cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode);
|
||||
|
||||
switch (chmode) {
|
||||
case CHAN_MODE_UNDEFINED:
|
||||
break;
|
||||
case CHAN_MODE_SHARED:
|
||||
for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++)
|
||||
if (!used_channels[i] || used_channels[i] == ch)
|
||||
break;
|
||||
|
||||
if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS)
|
||||
return -EBUSY;
|
||||
|
||||
if (used_channels[i] == NULL) {
|
||||
used_channels[i] = ch;
|
||||
num_different_channels++;
|
||||
}
|
||||
break;
|
||||
case CHAN_MODE_EXCLUSIVE:
|
||||
num_different_channels++;
|
||||
break;
|
||||
}
|
||||
|
||||
num[wdev_iter->iftype]++;
|
||||
total++;
|
||||
used_iftypes |= BIT(wdev_iter->iftype);
|
||||
}
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
if (total == 1)
|
||||
return 0;
|
||||
@@ -976,12 +1097,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
|
||||
c = &rdev->wiphy.iface_combinations[i];
|
||||
|
||||
if (total > c->max_interfaces)
|
||||
continue;
|
||||
if (num_different_channels > c->num_different_channels)
|
||||
continue;
|
||||
|
||||
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
|
||||
GFP_KERNEL);
|
||||
if (!limits)
|
||||
return -ENOMEM;
|
||||
if (total > c->max_interfaces)
|
||||
goto cont;
|
||||
|
||||
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
|
||||
if (rdev->wiphy.software_iftypes & BIT(iftype))
|
||||
|
@@ -827,8 +827,6 @@ 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:
|
||||
@@ -836,13 +834,10 @@ 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->ops->get_channel)
|
||||
if (!rdev->monitor_channel)
|
||||
return -EINVAL;
|
||||
|
||||
chan = rdev->ops->get_channel(wdev->wiphy, &channel_type);
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
freq->m = chan->center_freq;
|
||||
freq->m = rdev->monitor_channel->center_freq;
|
||||
freq->e = 6;
|
||||
return 0;
|
||||
default:
|
||||
|
Reference in New Issue
Block a user