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:
John W. Linville
2010-05-11 14:24:55 -04:00
63 changed files with 1367 additions and 1510 deletions

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 = {

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}