Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts: drivers/net/wireless/ath/ar9170/main.c
This commit is contained in:
@@ -9,38 +9,6 @@
|
||||
#include <net/cfg80211.h>
|
||||
#include "core.h"
|
||||
|
||||
struct ieee80211_channel *
|
||||
rdev_fixed_channel(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *for_wdev)
|
||||
{
|
||||
struct wireless_dev *wdev;
|
||||
struct ieee80211_channel *result = NULL;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&rdev->devlist_mtx));
|
||||
|
||||
list_for_each_entry(wdev, &rdev->netdev_list, list) {
|
||||
if (wdev == for_wdev)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Lock manually to tell lockdep about allowed
|
||||
* nesting here if for_wdev->mtx is held already.
|
||||
* This is ok as it's all under the rdev devlist
|
||||
* mutex and as such can only be done once at any
|
||||
* given time.
|
||||
*/
|
||||
mutex_lock_nested(&wdev->mtx, SINGLE_DEPTH_NESTING);
|
||||
if (wdev->current_bss)
|
||||
result = wdev->current_bss->pub.channel;
|
||||
wdev_unlock(wdev);
|
||||
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct ieee80211_channel *
|
||||
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
|
||||
int freq, enum nl80211_channel_type channel_type)
|
||||
@@ -75,15 +43,22 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
|
||||
return chan;
|
||||
}
|
||||
|
||||
int rdev_set_freq(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *for_wdev,
|
||||
int freq, enum nl80211_channel_type channel_type)
|
||||
int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, int freq,
|
||||
enum nl80211_channel_type channel_type)
|
||||
{
|
||||
struct ieee80211_channel *chan;
|
||||
int result;
|
||||
|
||||
if (rdev_fixed_channel(rdev, for_wdev))
|
||||
return -EBUSY;
|
||||
if (wdev->iftype == NL80211_IFTYPE_MONITOR)
|
||||
wdev = NULL;
|
||||
|
||||
if (wdev) {
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
if (!netif_running(wdev->netdev))
|
||||
return -ENETDOWN;
|
||||
}
|
||||
|
||||
if (!rdev->ops->set_channel)
|
||||
return -EOPNOTSUPP;
|
||||
@@ -92,11 +67,14 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev,
|
||||
if (!chan)
|
||||
return -EINVAL;
|
||||
|
||||
result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type);
|
||||
result = rdev->ops->set_channel(&rdev->wiphy,
|
||||
wdev ? wdev->netdev : NULL,
|
||||
chan, channel_type);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
rdev->channel = chan;
|
||||
if (wdev)
|
||||
wdev->channel = chan;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -70,9 +70,6 @@ struct cfg80211_registered_device {
|
||||
struct work_struct conn_work;
|
||||
struct work_struct event_work;
|
||||
|
||||
/* current channel */
|
||||
struct ieee80211_channel *channel;
|
||||
|
||||
/* must be last because of the way we do wiphy_priv(),
|
||||
* and it should at least be aligned to NETDEV_ALIGN */
|
||||
struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
|
||||
@@ -387,15 +384,12 @@ 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);
|
||||
|
||||
struct ieee80211_channel *
|
||||
rdev_fixed_channel(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *for_wdev);
|
||||
struct ieee80211_channel *
|
||||
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
|
||||
int freq, enum nl80211_channel_type channel_type);
|
||||
int rdev_set_freq(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *for_wdev,
|
||||
int freq, enum nl80211_channel_type channel_type);
|
||||
int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev, int freq,
|
||||
enum nl80211_channel_type channel_type);
|
||||
|
||||
u16 cfg80211_calculate_bitrate(struct rate_info *rate);
|
||||
|
||||
|
@@ -81,15 +81,10 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
|
||||
struct cfg80211_cached_keys *connkeys)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct ieee80211_channel *chan;
|
||||
int err;
|
||||
|
||||
ASSERT_WDEV_LOCK(wdev);
|
||||
|
||||
chan = rdev_fixed_channel(rdev, wdev);
|
||||
if (chan && chan != params->channel)
|
||||
return -EBUSY;
|
||||
|
||||
if (wdev->ssid_len)
|
||||
return -EALREADY;
|
||||
|
||||
|
@@ -589,6 +589,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
|
||||
i++;
|
||||
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
|
||||
}
|
||||
CMD(set_channel, SET_CHANNEL);
|
||||
|
||||
#undef CMD
|
||||
|
||||
@@ -689,10 +690,90 @@ static int parse_txq_params(struct nlattr *tb[],
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
|
||||
{
|
||||
/*
|
||||
* You can only set the channel explicitly for AP, mesh
|
||||
* and WDS type interfaces; all others have their channel
|
||||
* managed via their respective "establish a connection"
|
||||
* command (connect, join, ...)
|
||||
*
|
||||
* Monitors are special as they are normally slaved to
|
||||
* whatever else is going on, so they behave as though
|
||||
* you tried setting the wiphy channel itself.
|
||||
*/
|
||||
return !wdev ||
|
||||
wdev->iftype == NL80211_IFTYPE_AP ||
|
||||
wdev->iftype == NL80211_IFTYPE_WDS ||
|
||||
wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
|
||||
wdev->iftype == NL80211_IFTYPE_MONITOR;
|
||||
}
|
||||
|
||||
static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct genl_info *info)
|
||||
{
|
||||
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
|
||||
u32 freq;
|
||||
int result;
|
||||
|
||||
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
|
||||
return -EINVAL;
|
||||
|
||||
if (!nl80211_can_set_dev_channel(wdev))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
|
||||
channel_type = nla_get_u32(info->attrs[
|
||||
NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
|
||||
if (channel_type != NL80211_CHAN_NO_HT &&
|
||||
channel_type != NL80211_CHAN_HT20 &&
|
||||
channel_type != NL80211_CHAN_HT40PLUS &&
|
||||
channel_type != NL80211_CHAN_HT40MINUS)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
if (wdev) {
|
||||
wdev_lock(wdev);
|
||||
result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
|
||||
wdev_unlock(wdev);
|
||||
} else {
|
||||
result = cfg80211_set_freq(rdev, NULL, freq, channel_type);
|
||||
}
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct net_device *netdev;
|
||||
int result;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev);
|
||||
if (result)
|
||||
goto unlock;
|
||||
|
||||
result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info);
|
||||
|
||||
unlock:
|
||||
rtnl_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
int result = 0, rem_txq_params = 0;
|
||||
struct net_device *netdev = NULL;
|
||||
struct wireless_dev *wdev;
|
||||
int result, rem_txq_params = 0;
|
||||
struct nlattr *nl_txq_params;
|
||||
u32 changed;
|
||||
u8 retry_short = 0, retry_long = 0;
|
||||
@@ -701,16 +782,50 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
/*
|
||||
* Try to find the wiphy and netdev. Normally this
|
||||
* function shouldn't need the netdev, but this is
|
||||
* done for backward compatibility -- previously
|
||||
* setting the channel was done per wiphy, but now
|
||||
* it is per netdev. Previous userland like hostapd
|
||||
* also passed a netdev to set_wiphy, so that it is
|
||||
* possible to let that go to the right netdev!
|
||||
*/
|
||||
mutex_lock(&cfg80211_mutex);
|
||||
|
||||
rdev = __cfg80211_rdev_from_info(info);
|
||||
if (IS_ERR(rdev)) {
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
result = PTR_ERR(rdev);
|
||||
goto unlock;
|
||||
if (info->attrs[NL80211_ATTR_IFINDEX]) {
|
||||
int ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]);
|
||||
|
||||
netdev = dev_get_by_index(genl_info_net(info), ifindex);
|
||||
if (netdev && netdev->ieee80211_ptr) {
|
||||
rdev = wiphy_to_dev(netdev->ieee80211_ptr->wiphy);
|
||||
mutex_lock(&rdev->mtx);
|
||||
} else
|
||||
netdev = NULL;
|
||||
}
|
||||
|
||||
mutex_lock(&rdev->mtx);
|
||||
if (!netdev) {
|
||||
rdev = __cfg80211_rdev_from_info(info);
|
||||
if (IS_ERR(rdev)) {
|
||||
mutex_unlock(&cfg80211_mutex);
|
||||
result = PTR_ERR(rdev);
|
||||
goto unlock;
|
||||
}
|
||||
wdev = NULL;
|
||||
netdev = NULL;
|
||||
result = 0;
|
||||
|
||||
mutex_lock(&rdev->mtx);
|
||||
} else if (netif_running(netdev) &&
|
||||
nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
|
||||
wdev = netdev->ieee80211_ptr;
|
||||
else
|
||||
wdev = NULL;
|
||||
|
||||
/*
|
||||
* end workaround code, by now the rdev is available
|
||||
* and locked, and wdev may or may not be NULL.
|
||||
*/
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_NAME])
|
||||
result = cfg80211_dev_rename(
|
||||
@@ -749,26 +864,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
|
||||
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
|
||||
u32 freq;
|
||||
|
||||
result = -EINVAL;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
|
||||
channel_type = nla_get_u32(info->attrs[
|
||||
NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
|
||||
if (channel_type != NL80211_CHAN_NO_HT &&
|
||||
channel_type != NL80211_CHAN_HT20 &&
|
||||
channel_type != NL80211_CHAN_HT40PLUS &&
|
||||
channel_type != NL80211_CHAN_HT40MINUS)
|
||||
goto bad_res;
|
||||
}
|
||||
|
||||
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
result = rdev_set_freq(rdev, NULL, freq, channel_type);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
result = __nl80211_set_channel(rdev, wdev, info);
|
||||
if (result)
|
||||
goto bad_res;
|
||||
}
|
||||
@@ -865,6 +961,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
bad_res:
|
||||
mutex_unlock(&rdev->mtx);
|
||||
if (netdev)
|
||||
dev_put(netdev);
|
||||
unlock:
|
||||
rtnl_unlock();
|
||||
return result;
|
||||
@@ -3562,9 +3660,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct net_device *dev;
|
||||
struct wireless_dev *wdev;
|
||||
struct cfg80211_crypto_settings crypto;
|
||||
struct ieee80211_channel *chan, *fixedchan;
|
||||
struct ieee80211_channel *chan;
|
||||
const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL;
|
||||
int err, ssid_len, ie_len = 0;
|
||||
bool use_mfp = false;
|
||||
@@ -3607,16 +3704,6 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
wdev = dev->ieee80211_ptr;
|
||||
fixedchan = rdev_fixed_channel(rdev, wdev);
|
||||
if (fixedchan && chan != fixedchan) {
|
||||
err = -EBUSY;
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
|
||||
ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
|
||||
ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
|
||||
|
||||
@@ -5186,6 +5273,12 @@ static struct genl_ops nl80211_ops[] = {
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_CHANNEL,
|
||||
.doit = nl80211_set_channel,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct genl_multicast_group nl80211_mlme_mcgrp = {
|
||||
|
@@ -741,7 +741,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
const u8 *prev_bssid)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct ieee80211_channel *chan;
|
||||
struct cfg80211_bss *bss = NULL;
|
||||
int err;
|
||||
|
||||
@@ -750,10 +749,6 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
if (wdev->sme_state != CFG80211_SME_IDLE)
|
||||
return -EALREADY;
|
||||
|
||||
chan = rdev_fixed_channel(rdev, wdev);
|
||||
if (chan && chan != connect->channel)
|
||||
return -EBUSY;
|
||||
|
||||
if (WARN_ON(wdev->connect_keys)) {
|
||||
kfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
|
@@ -782,16 +782,22 @@ int cfg80211_wext_siwfreq(struct net_device *dev,
|
||||
return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
|
||||
default:
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
case NL80211_IFTYPE_WDS:
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
|
||||
if (freq < 0)
|
||||
return freq;
|
||||
if (freq == 0)
|
||||
return -EINVAL;
|
||||
wdev_lock(wdev);
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
err = rdev_set_freq(rdev, NULL, freq, NL80211_CHAN_NO_HT);
|
||||
err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
wdev_unlock(wdev);
|
||||
return err;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cfg80211_wext_siwfreq);
|
||||
@@ -801,7 +807,6 @@ int cfg80211_wext_giwfreq(struct net_device *dev,
|
||||
struct iw_freq *freq, char *extra)
|
||||
{
|
||||
struct wireless_dev *wdev = dev->ieee80211_ptr;
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
@@ -809,9 +814,9 @@ int cfg80211_wext_giwfreq(struct net_device *dev,
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
|
||||
default:
|
||||
if (!rdev->channel)
|
||||
if (!wdev->channel)
|
||||
return -EINVAL;
|
||||
freq->m = rdev->channel->center_freq;
|
||||
freq->m = wdev->channel->center_freq;
|
||||
freq->e = 6;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -108,7 +108,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
|
||||
|
||||
/* SSID is not set, we just want to switch channel */
|
||||
if (chan && !wdev->wext.connect.ssid_len) {
|
||||
err = rdev_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
|
||||
err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user