* [PATCH 1/7] mac80211: clean up ieee80211_set_channel
2012-05-16 21:50 [PATCH 0/7] cfg80211/mac80211 channel redesign Johannes Berg
@ 2012-05-16 21:50 ` Johannes Berg
2012-05-16 21:50 ` [PATCH 2/7] mac80211: move ieee80211_set_channel function Johannes Berg
` (5 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-05-16 21:50 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
There's no need for ieee80211_set_channel to check
whether a change in configuration happened since
ieee80211_hw_config() auto-detects it.
Additionally, it's wrong to pretend the HT config
for the BSS changed, it didn't, the BSS can't be
up & running (AP beaconing etc.) when the channel
type is changed anyway.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/cfg.c | 18 ++----------------
1 file changed, 2 insertions(+), 16 deletions(-)
--- a/net/mac80211/cfg.c 2012-05-15 20:14:44.000000000 +0200
+++ b/net/mac80211/cfg.c 2012-05-15 20:14:53.000000000 +0200
@@ -1684,9 +1684,6 @@ static int ieee80211_set_channel(struct
{
struct ieee80211_local *local = wiphy_priv(wiphy);
struct ieee80211_sub_if_data *sdata = NULL;
- struct ieee80211_channel *old_oper;
- enum nl80211_channel_type old_oper_type;
- enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT;
if (netdev)
sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
@@ -1704,24 +1701,13 @@ static int ieee80211_set_channel(struct
break;
}
- if (sdata)
- old_vif_oper_type = sdata->vif.bss_conf.channel_type;
- old_oper_type = local->_oper_channel_type;
-
if (!ieee80211_set_channel_type(local, sdata, channel_type))
return -EBUSY;
- old_oper = local->oper_channel;
local->oper_channel = chan;
- /* Update driver if changes were actually made. */
- if ((old_oper != local->oper_channel) ||
- (old_oper_type != local->_oper_channel_type))
- ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-
- if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
- old_vif_oper_type != sdata->vif.bss_conf.channel_type)
- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
+ /* auto-detects changes */
+ ieee80211_hw_config(local, 0);
return 0;
}
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 2/7] mac80211: move ieee80211_set_channel function
2012-05-16 21:50 [PATCH 0/7] cfg80211/mac80211 channel redesign Johannes Berg
2012-05-16 21:50 ` [PATCH 1/7] mac80211: clean up ieee80211_set_channel Johannes Berg
@ 2012-05-16 21:50 ` Johannes Berg
2012-05-16 21:50 ` [PATCH 3/7] cfg80211: simplify cfg80211_can_beacon_sec_chan API Johannes Berg
` (4 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-05-16 21:50 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
Move the set_channel function up so it can be used
by other code in this file in the future.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/cfg.c | 70 ++++++++++++++++++++++++++---------------------------
1 file changed, 35 insertions(+), 35 deletions(-)
--- a/net/mac80211/cfg.c 2012-05-15 20:14:53.000000000 +0200
+++ b/net/mac80211/cfg.c 2012-05-15 20:14:53.000000000 +0200
@@ -674,6 +674,41 @@ static int ieee80211_get_station(struct
return ret;
}
+static int ieee80211_set_channel(struct wiphy *wiphy,
+ struct net_device *netdev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_sub_if_data *sdata = NULL;
+
+ if (netdev)
+ sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
+
+ switch (ieee80211_get_channel_mode(local, NULL)) {
+ case CHAN_MODE_HOPPING:
+ return -EBUSY;
+ case CHAN_MODE_FIXED:
+ if (local->oper_channel != chan)
+ return -EBUSY;
+ if (!sdata && local->_oper_channel_type == channel_type)
+ return 0;
+ break;
+ case CHAN_MODE_UNDEFINED:
+ break;
+ }
+
+ if (!ieee80211_set_channel_type(local, sdata, channel_type))
+ return -EBUSY;
+
+ local->oper_channel = chan;
+
+ /* auto-detects changes */
+ ieee80211_hw_config(local, 0);
+
+ return 0;
+}
+
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
const u8 *resp, size_t resp_len)
{
@@ -1676,41 +1711,6 @@ static int ieee80211_set_txq_params(stru
return 0;
}
-
-static int ieee80211_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
-{
- struct ieee80211_local *local = wiphy_priv(wiphy);
- struct ieee80211_sub_if_data *sdata = NULL;
-
- if (netdev)
- sdata = IEEE80211_DEV_TO_SUB_IF(netdev);
-
- switch (ieee80211_get_channel_mode(local, NULL)) {
- case CHAN_MODE_HOPPING:
- return -EBUSY;
- case CHAN_MODE_FIXED:
- if (local->oper_channel != chan)
- return -EBUSY;
- if (!sdata && local->_oper_channel_type == channel_type)
- return 0;
- break;
- case CHAN_MODE_UNDEFINED:
- break;
- }
-
- if (!ieee80211_set_channel_type(local, sdata, channel_type))
- return -EBUSY;
-
- local->oper_channel = chan;
-
- /* auto-detects changes */
- ieee80211_hw_config(local, 0);
-
- return 0;
-}
#ifdef CONFIG_PM
static int ieee80211_suspend(struct wiphy *wiphy,
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 3/7] cfg80211: simplify cfg80211_can_beacon_sec_chan API
2012-05-16 21:50 [PATCH 0/7] cfg80211/mac80211 channel redesign Johannes Berg
2012-05-16 21:50 ` [PATCH 1/7] mac80211: clean up ieee80211_set_channel Johannes Berg
2012-05-16 21:50 ` [PATCH 2/7] mac80211: move ieee80211_set_channel function Johannes Berg
@ 2012-05-16 21:50 ` Johannes Berg
2012-05-16 21:50 ` [PATCH 4/7] cfg80211: provide channel to start_ap function Johannes Berg
` (3 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-05-16 21:50 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
Change cfg80211_can_beacon_sec_chan() to return true
if there is no secondary channel to simplify all the
current users of it. They all check the channel type
before calling the function because it returns false
if there's no secondary channel.
Also actually document the return value.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/cfg80211.h | 5 ++++-
net/mac80211/ibss.c | 3 +--
net/wireless/chan.c | 22 ++++++----------------
3 files changed, 11 insertions(+), 19 deletions(-)
--- a/include/net/cfg80211.h 2012-05-15 20:14:52.000000000 +0200
+++ b/include/net/cfg80211.h 2012-05-15 20:14:53.000000000 +0200
@@ -3359,11 +3359,14 @@ void cfg80211_report_obss_beacon(struct
const u8 *frame, size_t len,
int freq, int sig_dbm, gfp_t gfp);
-/*
+/**
* cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
* @wiphy: the wiphy
* @chan: main channel
* @channel_type: HT mode
+ *
+ * This function returns true if there is no secondary channel or the secondary
+ * channel can be used for beaconing (i.e. is not a radar channel etc.)
*/
bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
struct ieee80211_channel *chan,
--- a/net/mac80211/ibss.c 2012-05-15 20:14:44.000000000 +0200
+++ b/net/mac80211/ibss.c 2012-05-15 20:14:53.000000000 +0200
@@ -82,8 +82,7 @@ static void __ieee80211_sta_join_ibss(st
local->oper_channel = chan;
channel_type = ifibss->channel_type;
- if (channel_type > NL80211_CHAN_HT20 &&
- !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
+ if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
channel_type = NL80211_CHAN_HT20;
if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
/* can only fail due to HT40+/- mismatch */
--- a/net/wireless/chan.c 2012-05-15 20:14:52.000000000 +0200
+++ b/net/wireless/chan.c 2012-05-15 20:14:53.000000000 +0200
@@ -60,7 +60,7 @@ bool cfg80211_can_beacon_sec_chan(struct
diff = -20;
break;
default:
- return false;
+ return true;
}
sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
@@ -107,21 +107,11 @@ int cfg80211_set_freq(struct cfg80211_re
wdev->iftype == NL80211_IFTYPE_AP ||
wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
- wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
- switch (channel_type) {
- case NL80211_CHAN_HT40PLUS:
- case NL80211_CHAN_HT40MINUS:
- if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan,
- channel_type)) {
- printk(KERN_DEBUG
- "cfg80211: Secondary channel not "
- "allowed to initiate communication\n");
- return -EINVAL;
- }
- break;
- default:
- break;
- }
+ wdev->iftype == NL80211_IFTYPE_P2P_GO) &&
+ !cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan, channel_type)) {
+ printk(KERN_DEBUG
+ "cfg80211: Secondary channel not allowed to beacon\n");
+ return -EINVAL;
}
result = rdev->ops->set_channel(&rdev->wiphy,
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 4/7] cfg80211: provide channel to start_ap function
2012-05-16 21:50 [PATCH 0/7] cfg80211/mac80211 channel redesign Johannes Berg
` (2 preceding siblings ...)
2012-05-16 21:50 ` [PATCH 3/7] cfg80211: simplify cfg80211_can_beacon_sec_chan API Johannes Berg
@ 2012-05-16 21:50 ` Johannes Berg
2012-05-16 21:50 ` [PATCH 5/7] cfg80211: disallow setting channel on WDS interfaces Johannes Berg
` (2 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-05-16 21:50 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless, Kalle Valo
From: Johannes Berg <johannes.berg@intel.com>
Instead of setting the channel first and then
starting the AP, let cfg80211 store the channel
and provide it as one of the AP settings.
This means that now you have to set the channel
before you can start an AP interface, but since
hostapd/wpa_supplicant always do that we're OK
with this change.
Alternatively, it's now possible to give the
channel as an attribute to the start-ap nl80211
command, overriding any preset channel.
Cc: Kalle Valo <kvalo@qca.qualcomm.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
drivers/net/wireless/ath/ath6kl/cfg80211.c | 36 +------------------
drivers/net/wireless/ath/ath6kl/core.h | 3 -
drivers/net/wireless/ath/ath6kl/main.c | 1
include/linux/nl80211.h | 2 +
include/net/cfg80211.h | 12 ++++++
net/mac80211/cfg.c | 5 ++
net/wireless/nl80211.c | 53 +++++++++++++++++++++++++++--
7 files changed, 72 insertions(+), 40 deletions(-)
--- a/include/net/cfg80211.h 2012-05-16 23:35:46.000000000 +0200
+++ b/include/net/cfg80211.h 2012-05-16 23:49:23.000000000 +0200
@@ -404,6 +404,8 @@ struct cfg80211_beacon_data {
*
* Used to configure an AP interface.
*
+ * @channel: the channel to start the AP on
+ * @channel_type: the channel type to use
* @beacon: beacon data
* @beacon_interval: beacon interval
* @dtim_period: DTIM period
@@ -417,6 +419,9 @@ struct cfg80211_beacon_data {
* @inactivity_timeout: time in seconds to determine station's inactivity.
*/
struct cfg80211_ap_settings {
+ struct ieee80211_channel *channel;
+ enum nl80211_channel_type channel_type;
+
struct cfg80211_beacon_data beacon;
int beacon_interval, dtim_period;
@@ -2263,7 +2268,10 @@ struct cfg80211_cached_keys;
* @netdev: (private) Used to reference back to the netdev
* @current_bss: (private) Used by the internal configuration code
* @channel: (private) Used by the internal configuration code to track
- * user-set AP, monitor and WDS channels for wireless extensions
+ * the user-set AP, monitor and WDS channel
+ * @preset_chan: (private) Used by the internal configuration code to
+ * track the channel to be used for AP later
+ * @preset_chantype: (private) the corresponding channel type
* @bssid: (private) Used by the internal configuration code
* @ssid: (private) Used by the internal configuration code
* @ssid_len: (private) Used by the internal configuration code
@@ -2314,6 +2322,8 @@ struct wireless_dev {
struct cfg80211_internal_bss *current_bss; /* associated / joined */
struct ieee80211_channel *channel;
+ struct ieee80211_channel *preset_chan;
+ enum nl80211_channel_type preset_chantype;
bool ps;
int ps_timeout;
--- a/net/wireless/nl80211.c 2012-05-16 21:15:51.000000000 +0200
+++ b/net/wireless/nl80211.c 2012-05-16 23:49:23.000000000 +0200
@@ -921,7 +921,11 @@ static int nl80211_send_wiphy(struct sk_
if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
goto nla_put_failure;
}
- CMD(set_channel, SET_CHANNEL);
+ if (dev->ops->set_channel || dev->ops->start_ap) {
+ i++;
+ if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
+ goto nla_put_failure;
+ }
CMD(set_wds_peer, SET_WDS_PEER);
if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_TDLS) {
CMD(tdls_mgmt, TDLS_MGMT);
@@ -1170,6 +1174,9 @@ static bool nl80211_can_set_dev_channel(
* 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.
+ *
+ * For AP/GO modes, it's only for compatibility, you can
+ * also give the channel to the start-AP command.
*/
return !wdev ||
wdev->iftype == NL80211_IFTYPE_AP ||
@@ -1204,6 +1211,7 @@ static int __nl80211_set_channel(struct
struct wireless_dev *wdev,
struct genl_info *info)
{
+ struct ieee80211_channel *channel;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u32 freq;
int result;
@@ -1221,7 +1229,25 @@ static int __nl80211_set_channel(struct
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
mutex_lock(&rdev->devlist_mtx);
- if (wdev) {
+ if (wdev) switch (wdev->iftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ if (wdev->beacon_interval) {
+ result = -EBUSY;
+ break;
+ }
+ channel = rdev_freq_to_chan(rdev, freq, channel_type);
+ if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+ channel,
+ channel_type)) {
+ result = -EINVAL;
+ break;
+ }
+ wdev->preset_chan = channel;
+ wdev->preset_chantype = channel_type;
+ result = 0;
+ break;
+ default:
wdev_lock(wdev);
result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
wdev_unlock(wdev);
@@ -2299,6 +2325,29 @@ static int nl80211_start_ap(struct sk_bu
info->attrs[NL80211_ATTR_INACTIVITY_TIMEOUT]);
}
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+ !nl80211_valid_channel_type(info, &channel_type))
+ return -EINVAL;
+
+ params.channel = rdev_freq_to_chan(rdev,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+ channel_type);
+ if (!params.channel)
+ return -EINVAL;
+ params.channel_type = channel_type;
+ } else if (wdev->preset_chan) {
+ params.channel = wdev->preset_chan;
+ params.channel_type = wdev->preset_chantype;
+ } else
+ return -EINVAL;
+
+ if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
+ params.channel_type))
+ return -EINVAL;
+
err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms);
if (!err)
wdev->beacon_interval = params.beacon_interval;
--- a/include/linux/nl80211.h 2012-05-16 21:15:51.000000000 +0200
+++ b/include/linux/nl80211.h 2012-05-16 23:35:47.000000000 +0200
@@ -170,6 +170,8 @@
* %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
* %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
* %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
+ * The channel to use can be set on the interface or be given using the
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
* @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
* @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
* @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c 2012-05-16 21:15:51.000000000 +0200
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c 2012-05-16 23:35:47.000000000 +0200
@@ -2585,35 +2585,6 @@ static int ath6kl_set_ies(struct ath6kl_
return 0;
}
-static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
-{
- struct ath6kl_vif *vif;
-
- /*
- * 'dev' could be NULL if a channel change is required for the hardware
- * device itself, instead of a particular VIF.
- *
- * FIXME: To be handled properly when monitor mode is supported.
- */
- if (!dev)
- return -EBUSY;
-
- vif = netdev_priv(dev);
-
- if (!ath6kl_cfg80211_ready(vif))
- return -EIO;
-
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n",
- __func__, chan->center_freq, chan->hw_value);
- vif->next_chan = chan->center_freq;
- vif->next_ch_type = channel_type;
- vif->next_ch_band = chan->band;
-
- return 0;
-}
-
static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
u8 *rsn_capab)
{
@@ -2791,7 +2762,7 @@ static int ath6kl_start_ap(struct wiphy
p.ssid_len = vif->ssid_len;
memcpy(p.ssid, vif->ssid, vif->ssid_len);
p.dot11_auth_mode = vif->dot11_auth_mode;
- p.ch = cpu_to_le16(vif->next_chan);
+ p.ch = cpu_to_le16(info->channel->center_freq);
/* Enable uAPSD support by default */
res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
@@ -2815,8 +2786,8 @@ static int ath6kl_start_ap(struct wiphy
return res;
}
- if (ath6kl_set_htcap(vif, vif->next_ch_band,
- vif->next_ch_type != NL80211_CHAN_NO_HT))
+ if (ath6kl_set_htcap(vif, info->channel->band,
+ info->channel_type != NL80211_CHAN_NO_HT))
return -EIO;
/*
@@ -3271,7 +3242,6 @@ static struct cfg80211_ops ath6kl_cfg802
.suspend = __ath6kl_cfg80211_suspend,
.resume = __ath6kl_cfg80211_resume,
#endif
- .set_channel = ath6kl_set_channel,
.start_ap = ath6kl_start_ap,
.change_beacon = ath6kl_change_beacon,
.stop_ap = ath6kl_stop_ap,
--- a/drivers/net/wireless/ath/ath6kl/core.h 2012-05-16 21:15:51.000000000 +0200
+++ b/drivers/net/wireless/ath/ath6kl/core.h 2012-05-16 23:35:47.000000000 +0200
@@ -553,9 +553,6 @@ struct ath6kl_vif {
u32 last_cancel_roc_id;
u32 send_action_id;
bool probe_req_report;
- u16 next_chan;
- enum nl80211_channel_type next_ch_type;
- enum ieee80211_band next_ch_band;
u16 assoc_bss_beacon_int;
u16 listen_intvl_t;
u16 bmiss_time_t;
--- a/net/mac80211/cfg.c 2012-05-16 23:35:45.000000000 +0200
+++ b/net/mac80211/cfg.c 2012-05-16 23:49:23.000000000 +0200
@@ -823,6 +823,11 @@ static int ieee80211_start_ap(struct wip
if (old)
return -EALREADY;
+ err = ieee80211_set_channel(wiphy, dev, params->channel,
+ params->channel_type);
+ if (err)
+ return err;
+
/*
* Apply control port protocol, this allows us to
* not encrypt dynamic WEP control frames.
--- a/drivers/net/wireless/ath/ath6kl/main.c 2012-05-16 21:15:51.000000000 +0200
+++ b/drivers/net/wireless/ath/ath6kl/main.c 2012-05-16 23:50:01.000000000 +0200
@@ -598,7 +598,6 @@ static int ath6kl_commit_ch_switch(struc
struct ath6kl *ar = vif->ar;
- vif->next_chan = channel;
vif->profile.ch = cpu_to_le16(channel);
switch (vif->nw_type) {
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 5/7] cfg80211: disallow setting channel on WDS interfaces
2012-05-16 21:50 [PATCH 0/7] cfg80211/mac80211 channel redesign Johannes Berg
` (3 preceding siblings ...)
2012-05-16 21:50 ` [PATCH 4/7] cfg80211: provide channel to start_ap function Johannes Berg
@ 2012-05-16 21:50 ` Johannes Berg
2012-05-16 21:50 ` [PATCH 6/7] cfg80211: provide channel to join_mesh function Johannes Berg
2012-05-16 21:50 ` [PATCH 7/7] cfg80211: clarify set_channel APIs Johannes Berg
6 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-05-16 21:50 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
If it worked (Felix says it doesn't right now), the
typical use-case for WDS interfaces would be to be
slaved to AP mode interfaces. Therefore, it isn't
necessary to set the channel on WDS interfaces. As
they don't support powersave or anything like that,
they also couldn't use a different channel anyway.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/wireless/nl80211.c | 5 ++---
net/wireless/wext-compat.c | 1 -
2 files changed, 2 insertions(+), 4 deletions(-)
--- a/net/wireless/nl80211.c 2012-05-16 10:24:41.000000000 +0200
+++ b/net/wireless/nl80211.c 2012-05-16 10:24:45.000000000 +0200
@@ -1166,8 +1166,8 @@ static int parse_txq_params(struct nlatt
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
+ * You can only set the channel explicitly for AP and
+ * mesh type interfaces; all others have their channel
* managed via their respective "establish a connection"
* command (connect, join, ...)
*
@@ -1180,7 +1180,6 @@ static bool nl80211_can_set_dev_channel(
*/
return !wdev ||
wdev->iftype == NL80211_IFTYPE_AP ||
- wdev->iftype == NL80211_IFTYPE_WDS ||
wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
wdev->iftype == NL80211_IFTYPE_MONITOR ||
wdev->iftype == NL80211_IFTYPE_P2P_GO;
--- a/net/wireless/wext-compat.c 2012-05-16 10:22:21.000000000 +0200
+++ b/net/wireless/wext-compat.c 2012-05-16 10:24:45.000000000 +0200
@@ -796,7 +796,6 @@ static int cfg80211_wext_siwfreq(struct
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_WDS:
case NL80211_IFTYPE_MESH_POINT:
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
if (freq < 0)
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 6/7] cfg80211: provide channel to join_mesh function
2012-05-16 21:50 [PATCH 0/7] cfg80211/mac80211 channel redesign Johannes Berg
` (4 preceding siblings ...)
2012-05-16 21:50 ` [PATCH 5/7] cfg80211: disallow setting channel on WDS interfaces Johannes Berg
@ 2012-05-16 21:50 ` Johannes Berg
2012-05-16 21:50 ` [PATCH 7/7] cfg80211: clarify set_channel APIs Johannes Berg
6 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-05-16 21:50 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
Just like the AP mode patch, instead of setting
the channel and then joining the mesh network,
provide the channel to join the network on to
the join_mesh() function.
Like in AP mode, you can also give the channel
to the join-mesh nl80211 command now.
Unlike AP mode, it picks a default channel if
none was given.
As libertas uses mesh mode interfaces but has
no join_mesh callback and we can't simply break
it, keep some compatibility code for that case
and configure the channel directly for it.
In the non-libertas case, where we store the
channel until join, allow setting it while the
interface is down.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/cfg80211.h | 4 +
net/mac80211/cfg.c | 6 ++
net/wireless/core.h | 7 ++-
net/wireless/mesh.c | 91 ++++++++++++++++++++++++++++++++++++++++++++-
net/wireless/nl80211.c | 43 ++++++++++++++++-----
net/wireless/wext-compat.c | 12 +++++
6 files changed, 148 insertions(+), 15 deletions(-)
--- a/include/net/cfg80211.h 2012-05-16 10:24:04.000000000 +0200
+++ b/include/net/cfg80211.h 2012-05-16 10:24:50.000000000 +0200
@@ -831,6 +831,8 @@ struct mesh_config {
/**
* struct mesh_setup - 802.11s mesh setup configuration
+ * @channel: the channel to start the mesh network on
+ * @channel_type: the channel type to use
* @mesh_id: the mesh ID
* @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
* @sync_method: which synchronization method to use
@@ -845,6 +847,8 @@ struct mesh_config {
* These parameters are fixed when the mesh is created.
*/
struct mesh_setup {
+ struct ieee80211_channel *channel;
+ enum nl80211_channel_type channel_type;
const u8 *mesh_id;
u8 mesh_id_len;
u8 sync_method;
--- a/net/wireless/nl80211.c 2012-05-16 10:24:45.000000000 +0200
+++ b/net/wireless/nl80211.c 2012-05-16 10:24:50.000000000 +0200
@@ -921,7 +921,8 @@ static int nl80211_send_wiphy(struct sk_
if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
goto nla_put_failure;
}
- if (dev->ops->set_channel || dev->ops->start_ap) {
+ if (dev->ops->set_channel || dev->ops->start_ap ||
+ dev->ops->join_mesh) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
goto nla_put_failure;
@@ -1166,17 +1167,19 @@ static int parse_txq_params(struct nlatt
static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
{
/*
- * You can only set the channel explicitly for AP and
- * mesh type interfaces; all others have their channel
- * managed via their respective "establish a connection"
- * command (connect, join, ...)
+ * You can only set the channel explicitly for WDS interfaces,
+ * all others have their channel managed via their respective
+ * "establish a connection" command (connect, join, ...)
+ *
+ * For AP/GO and mesh mode, the channel can be set with the
+ * channel userspace API, but is only stored and passed to the
+ * low-level driver when the AP starts or the mesh is joined.
+ * This is for backward compatibility, userspace can also give
+ * the channel in the start-ap or join-mesh commands instead.
*
* 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.
- *
- * For AP/GO modes, it's only for compatibility, you can
- * also give the channel to the start-AP command.
*/
return !wdev ||
wdev->iftype == NL80211_IFTYPE_AP ||
@@ -1246,6 +1249,9 @@ static int __nl80211_set_channel(struct
wdev->preset_chantype = channel_type;
result = 0;
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
+ break;
default:
wdev_lock(wdev);
result = cfg80211_set_freq(rdev, wdev, freq, channel_type);
@@ -1335,8 +1341,7 @@ static int nl80211_set_wiphy(struct sk_b
result = 0;
mutex_lock(&rdev->mtx);
- } else if (netif_running(netdev) &&
- nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
+ } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
wdev = netdev->ieee80211_ptr;
else
wdev = NULL;
@@ -6080,6 +6085,24 @@ static int nl80211_join_mesh(struct sk_b
return err;
}
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+
+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+ !nl80211_valid_channel_type(info, &channel_type))
+ return -EINVAL;
+
+ setup.channel = rdev_freq_to_chan(rdev,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+ channel_type);
+ if (!setup.channel)
+ return -EINVAL;
+ setup.channel_type = channel_type;
+ } else {
+ /* cfg80211_join_mesh() will sort it out */
+ setup.channel = NULL;
+ }
+
return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
}
--- a/net/wireless/core.h 2012-05-16 10:22:21.000000000 +0200
+++ b/net/wireless/core.h 2012-05-16 10:24:50.000000000 +0200
@@ -303,14 +303,17 @@ extern const struct mesh_config default_
extern const struct mesh_setup default_mesh_setup;
int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev,
- const struct mesh_setup *setup,
+ struct mesh_setup *setup,
const struct mesh_config *conf);
int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev,
- const struct mesh_setup *setup,
+ struct mesh_setup *setup,
const struct mesh_config *conf);
int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev);
+int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev, int freq,
+ enum nl80211_channel_type channel_type);
/* MLME */
int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
--- a/net/wireless/mesh.c 2012-05-16 10:22:21.000000000 +0200
+++ b/net/wireless/mesh.c 2012-05-16 10:24:50.000000000 +0200
@@ -65,6 +65,9 @@ const struct mesh_config default_mesh_co
};
const struct mesh_setup default_mesh_setup = {
+ /* cfg80211_join_mesh() will pick a channel if needed */
+ .channel = NULL,
+ .channel_type = NL80211_CHAN_NO_HT,
.sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
.path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
.path_metric = IEEE80211_PATH_METRIC_AIRTIME,
@@ -75,7 +78,7 @@ const struct mesh_setup default_mesh_set
int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev,
- const struct mesh_setup *setup,
+ struct mesh_setup *setup,
const struct mesh_config *conf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -101,6 +104,51 @@ int __cfg80211_join_mesh(struct cfg80211
if (!rdev->ops->join_mesh)
return -EOPNOTSUPP;
+ if (!setup->channel) {
+ /* if no channel explicitly given, use preset channel */
+ setup->channel = wdev->preset_chan;
+ setup->channel_type = wdev->preset_chantype;
+ }
+
+ if (!setup->channel) {
+ /* if we don't have that either, use the first usable channel */
+ enum ieee80211_band band;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *chan;
+ int i;
+
+ sband = rdev->wiphy.bands[band];
+ if (!sband)
+ continue;
+
+ for (i = 0; i < sband->n_channels; i++) {
+ chan = &sband->channels[i];
+ if (chan->flags & (IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN |
+ IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_RADAR))
+ continue;
+ setup->channel = chan;
+ break;
+ }
+
+ if (setup->channel)
+ break;
+ }
+
+ /* no usable channel ... */
+ if (!setup->channel)
+ return -EINVAL;
+
+ setup->channel_type = NL80211_CHAN_NO_HT;
+ }
+
+ if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel,
+ setup->channel_type))
+ return -EINVAL;
+
err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup);
if (!err) {
memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
@@ -112,7 +160,7 @@ int __cfg80211_join_mesh(struct cfg80211
int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
struct net_device *dev,
- const struct mesh_setup *setup,
+ struct mesh_setup *setup,
const struct mesh_config *conf)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -125,6 +173,45 @@ int cfg80211_join_mesh(struct cfg80211_r
return err;
}
+int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev, int freq,
+ enum nl80211_channel_type channel_type)
+{
+ struct ieee80211_channel *channel;
+
+ /*
+ * Workaround for libertas (only!), it puts the interface
+ * into mesh mode but doesn't implement join_mesh. Instead,
+ * it is configured via sysfs and then joins the mesh when
+ * you set the channel. Note that the libertas mesh isn't
+ * compatible with 802.11 mesh.
+ */
+ if (!rdev->ops->join_mesh) {
+ int err;
+
+ if (!netif_running(wdev->netdev))
+ return -ENETDOWN;
+ wdev_lock(wdev);
+ err = cfg80211_set_freq(rdev, wdev, freq, channel_type);
+ wdev_unlock(wdev);
+
+ return err;
+ }
+
+ if (wdev->mesh_id_len)
+ return -EBUSY;
+
+ channel = rdev_freq_to_chan(rdev, freq, channel_type);
+ if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+ channel,
+ channel_type)) {
+ return -EINVAL;
+ }
+ wdev->preset_chan = channel;
+ wdev->preset_chantype = channel_type;
+ return 0;
+}
+
void cfg80211_notify_new_peer_candidate(struct net_device *dev,
const u8 *macaddr, const u8* ie, u8 ie_len, gfp_t gfp)
{
--- a/net/mac80211/cfg.c 2012-05-16 10:24:04.000000000 +0200
+++ b/net/mac80211/cfg.c 2012-05-16 10:24:50.000000000 +0200
@@ -1598,6 +1598,12 @@ static int ieee80211_join_mesh(struct wi
err = copy_mesh_setup(ifmsh, setup);
if (err)
return err;
+
+ err = ieee80211_set_channel(wiphy, dev, setup->channel,
+ setup->channel_type);
+ if (err)
+ return err;
+
ieee80211_start_mesh(sdata);
return 0;
--- a/net/wireless/wext-compat.c 2012-05-16 10:24:45.000000000 +0200
+++ b/net/wireless/wext-compat.c 2012-05-16 10:24:50.000000000 +0200
@@ -796,7 +796,6 @@ static int cfg80211_wext_siwfreq(struct
case NL80211_IFTYPE_ADHOC:
return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_MESH_POINT:
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
if (freq < 0)
return freq;
@@ -808,6 +807,17 @@ static int cfg80211_wext_siwfreq(struct
wdev_unlock(wdev);
mutex_unlock(&rdev->devlist_mtx);
return err;
+ case NL80211_IFTYPE_MESH_POINT:
+ freq = cfg80211_wext_freq(wdev->wiphy, wextfreq);
+ if (freq < 0)
+ return freq;
+ if (freq == 0)
+ return -EINVAL;
+ mutex_lock(&rdev->devlist_mtx);
+ err = cfg80211_set_mesh_freq(rdev, wdev, freq,
+ NL80211_CHAN_NO_HT);
+ mutex_unlock(&rdev->devlist_mtx);
+ return err;
default:
return -EOPNOTSUPP;
}
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 7/7] cfg80211: clarify set_channel APIs
2012-05-16 21:50 [PATCH 0/7] cfg80211/mac80211 channel redesign Johannes Berg
` (5 preceding siblings ...)
2012-05-16 21:50 ` [PATCH 6/7] cfg80211: provide channel to join_mesh function Johannes Berg
@ 2012-05-16 21:50 ` Johannes Berg
2012-06-05 21:13 ` John W. Linville
6 siblings, 1 reply; 11+ messages in thread
From: Johannes Berg @ 2012-05-16 21:50 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
Now that we've removed all uses of the set_channel
API except for the monitor channel and in libertas,
clarify this. Split the libertas mesh use into a
new libertas_set_mesh_channel() operation, just to
keep backward compatibility, and rename the normal
set_channel() to set_monitor_channel().
Also describe the desired set_monitor_channel()
semantics more clearly.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
drivers/net/wireless/libertas/cfg.c | 39 +++++++++++++++++++++++++-------
drivers/net/wireless/orinoco/cfg.c | 10 ++++----
include/net/cfg80211.h | 24 ++++++++++++--------
net/mac80211/cfg.c | 9 ++++++-
net/wireless/chan.c | 43 ++++--------------------------------
net/wireless/core.h | 5 +---
net/wireless/mesh.c | 26 ++++++++++-----------
net/wireless/mlme.c | 2 -
net/wireless/nl80211.c | 21 ++++++++++-------
net/wireless/wext-compat.c | 10 +-------
net/wireless/wext-sme.c | 10 ++++++--
11 files changed, 100 insertions(+), 99 deletions(-)
--- a/include/net/cfg80211.h 2012-05-16 23:35:50.000000000 +0200
+++ b/include/net/cfg80211.h 2012-05-16 23:35:51.000000000 +0200
@@ -1420,11 +1420,14 @@ struct cfg80211_gtk_rekey_data {
*
* @set_txq_params: Set TX queue parameters
*
- * @set_channel: Set channel for a given wireless interface. Some devices
- * may support multi-channel operation (by channel hopping) so cfg80211
- * doesn't verify much. Note, however, that the passed netdev may be
- * %NULL as well if the user requested changing the channel for the
- * device itself, or for a monitor interface.
+ * @libertas_set_mesh_channel: Only for backward compatibility for libertas,
+ * as it doesn't implement join_mesh and needs to set the channel to
+ * join the mesh instead.
+ *
+ * @set_monitor_channel: Set the monitor mode channel for the device. If other
+ * interfaces are active this callback should reject the configuration.
+ * If no interfaces are active or the device is down, the channel should
+ * be stored for when a monitor interface becomes active.
* @get_channel: Get the current operating channel, should return %NULL if
* there's no single defined operating channel if for example the
* device implements channel hopping for multi-channel virtual interfaces.
@@ -1614,9 +1617,13 @@ struct cfg80211_ops {
int (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_txq_params *params);
- int (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type);
+ int (*libertas_set_mesh_channel)(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan);
+
+ int (*set_monitor_channel)(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
int (*scan)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request);
@@ -2325,7 +2332,6 @@ struct wireless_dev {
spinlock_t event_lock;
struct cfg80211_internal_bss *current_bss; /* associated / joined */
- struct ieee80211_channel *channel;
struct ieee80211_channel *preset_chan;
enum nl80211_channel_type preset_chantype;
--- a/net/wireless/chan.c 2012-05-16 23:35:46.000000000 +0200
+++ b/net/wireless/chan.c 2012-05-16 23:35:51.000000000 +0200
@@ -78,50 +78,17 @@ bool cfg80211_can_beacon_sec_chan(struct
}
EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, int freq,
- enum nl80211_channel_type channel_type)
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ int freq, enum nl80211_channel_type chantype)
{
struct ieee80211_channel *chan;
- int result;
- if (wdev && 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)
+ if (!rdev->ops->set_monitor_channel)
return -EOPNOTSUPP;
- chan = rdev_freq_to_chan(rdev, freq, channel_type);
+ chan = rdev_freq_to_chan(rdev, freq, chantype);
if (!chan)
return -EINVAL;
- /* Both channels should be able to initiate communication */
- if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
- wdev->iftype == NL80211_IFTYPE_AP ||
- wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
- wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
- wdev->iftype == NL80211_IFTYPE_P2P_GO) &&
- !cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan, channel_type)) {
- printk(KERN_DEBUG
- "cfg80211: Secondary channel not allowed to beacon\n");
- return -EINVAL;
- }
-
- result = rdev->ops->set_channel(&rdev->wiphy,
- wdev ? wdev->netdev : NULL,
- chan, channel_type);
- if (result)
- return result;
-
- if (wdev)
- wdev->channel = chan;
-
- return 0;
+ return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
}
--- a/net/wireless/mlme.c 2012-05-16 21:00:52.000000000 +0200
+++ b/net/wireless/mlme.c 2012-05-16 23:35:51.000000000 +0200
@@ -948,8 +948,6 @@ void cfg80211_ch_switch_notify(struct ne
if (WARN_ON(!chan))
goto out;
- wdev->channel = chan;
-
nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
out:
wdev_unlock(wdev);
--- a/net/wireless/wext-compat.c 2012-05-16 23:35:50.000000000 +0200
+++ b/net/wireless/wext-compat.c 2012-05-16 23:35:51.000000000 +0200
@@ -802,9 +802,7 @@ static int cfg80211_wext_siwfreq(struct
if (freq == 0)
return -EINVAL;
mutex_lock(&rdev->devlist_mtx);
- wdev_lock(wdev);
- err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
- wdev_unlock(wdev);
+ err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
mutex_unlock(&rdev->devlist_mtx);
return err;
case NL80211_IFTYPE_MESH_POINT:
@@ -848,11 +846,7 @@ static int cfg80211_wext_giwfreq(struct
freq->e = 6;
return 0;
default:
- if (!wdev->channel)
- return -EINVAL;
- freq->m = wdev->channel->center_freq;
- freq->e = 6;
- return 0;
+ return -EINVAL;
}
}
--- a/net/wireless/nl80211.c 2012-05-16 23:35:50.000000000 +0200
+++ b/net/wireless/nl80211.c 2012-05-16 23:35:51.000000000 +0200
@@ -921,7 +921,7 @@ static int nl80211_send_wiphy(struct sk_
if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
goto nla_put_failure;
}
- if (dev->ops->set_channel || dev->ops->start_ap ||
+ if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
dev->ops->join_mesh) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
@@ -1178,8 +1178,8 @@ static bool nl80211_can_set_dev_channel(
* the channel in the start-ap or join-mesh commands instead.
*
* 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.
+ * whatever else is going on, so they have their own special
+ * operation to set the monitor channel if possible.
*/
return !wdev ||
wdev->iftype == NL80211_IFTYPE_AP ||
@@ -1217,6 +1217,10 @@ static int __nl80211_set_channel(struct
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u32 freq;
int result;
+ enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
+
+ if (wdev)
+ iftype = wdev->iftype;
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
@@ -1231,7 +1235,7 @@ static int __nl80211_set_channel(struct
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
mutex_lock(&rdev->devlist_mtx);
- if (wdev) switch (wdev->iftype) {
+ switch (iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
if (wdev->beacon_interval) {
@@ -1252,12 +1256,11 @@ static int __nl80211_set_channel(struct
case NL80211_IFTYPE_MESH_POINT:
result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
break;
+ case NL80211_IFTYPE_MONITOR:
+ result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
+ break;
default:
- 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);
+ result = -EINVAL;
}
mutex_unlock(&rdev->devlist_mtx);
--- a/net/wireless/core.h 2012-05-16 23:35:50.000000000 +0200
+++ b/net/wireless/core.h 2012-05-16 23:35:51.000000000 +0200
@@ -444,9 +444,8 @@ cfg80211_can_add_interface(struct cfg802
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
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);
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ int freq, enum nl80211_channel_type chantype);
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
const u8 *rates, unsigned int n_rates,
--- a/net/wireless/wext-sme.c 2012-05-16 21:00:52.000000000 +0200
+++ b/net/wireless/wext-sme.c 2012-05-16 23:35:51.000000000 +0200
@@ -111,9 +111,15 @@ int cfg80211_mgd_wext_siwfreq(struct net
wdev->wext.connect.channel = chan;
- /* SSID is not set, we just want to switch channel */
+ /*
+ * SSID is not set, we just want to switch monitor channel,
+ * this is really just backward compatibility, if the SSID
+ * is set then we use the channel to select the BSS to use
+ * to connect to instead. If we were connected on another
+ * channel we disconnected above and reconnect below.
+ */
if (chan && !wdev->wext.connect.ssid_len) {
- err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
+ err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
goto out;
}
--- a/net/mac80211/cfg.c 2012-05-16 23:35:50.000000000 +0200
+++ b/net/mac80211/cfg.c 2012-05-16 23:35:51.000000000 +0200
@@ -709,6 +709,13 @@ static int ieee80211_set_channel(struct
return 0;
}
+static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
+}
+
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
const u8 *resp, size_t resp_len)
{
@@ -2930,7 +2937,7 @@ struct cfg80211_ops mac80211_config_ops
#endif
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
- .set_channel = ieee80211_set_channel,
+ .set_monitor_channel = ieee80211_set_monitor_channel,
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
.scan = ieee80211_scan,
--- a/net/wireless/mesh.c 2012-05-16 23:35:50.000000000 +0200
+++ b/net/wireless/mesh.c 2012-05-16 23:35:51.000000000 +0200
@@ -179,6 +179,13 @@ int cfg80211_set_mesh_freq(struct cfg802
{
struct ieee80211_channel *channel;
+ channel = rdev_freq_to_chan(rdev, freq, channel_type);
+ if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+ channel,
+ channel_type)) {
+ return -EINVAL;
+ }
+
/*
* Workaround for libertas (only!), it puts the interface
* into mesh mode but doesn't implement join_mesh. Instead,
@@ -186,27 +193,20 @@ int cfg80211_set_mesh_freq(struct cfg802
* you set the channel. Note that the libertas mesh isn't
* compatible with 802.11 mesh.
*/
- if (!rdev->ops->join_mesh) {
- int err;
+ if (rdev->ops->libertas_set_mesh_channel) {
+ if (channel_type != NL80211_CHAN_NO_HT)
+ return -EINVAL;
if (!netif_running(wdev->netdev))
return -ENETDOWN;
- wdev_lock(wdev);
- err = cfg80211_set_freq(rdev, wdev, freq, channel_type);
- wdev_unlock(wdev);
-
- return err;
+ return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
+ wdev->netdev,
+ channel);
}
if (wdev->mesh_id_len)
return -EBUSY;
- channel = rdev_freq_to_chan(rdev, freq, channel_type);
- if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
- channel,
- channel_type)) {
- return -EINVAL;
- }
wdev->preset_chan = channel;
wdev->preset_chantype = channel_type;
return 0;
--- a/drivers/net/wireless/libertas/cfg.c 2012-05-16 21:00:52.000000000 +0200
+++ b/drivers/net/wireless/libertas/cfg.c 2012-05-16 23:35:51.000000000 +0200
@@ -435,10 +435,9 @@ static int lbs_add_wpa_tlv(u8 *tlv, cons
* Set Channel
*/
-static int lbs_cfg_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type)
+static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type)
{
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = -ENOTSUPP;
@@ -449,10 +448,31 @@ static int lbs_cfg_set_channel(struct wi
if (channel_type != NL80211_CHAN_NO_HT)
goto out;
- if (netdev == priv->mesh_dev)
- ret = lbs_mesh_set_channel(priv, channel->hw_value);
- else
- ret = lbs_set_channel(priv, channel->hw_value);
+ ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
+ struct net_device *netdev,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = -ENOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
+ netdev_name(netdev), channel->center_freq, channel_type);
+
+ if (channel_type != NL80211_CHAN_NO_HT)
+ goto out;
+
+ if (netdev != priv->mesh_dev)
+ goto out;
+
+ ret = lbs_mesh_set_channel(priv, channel->hw_value);
out:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -2029,7 +2049,8 @@ static int lbs_leave_ibss(struct wiphy *
*/
static struct cfg80211_ops lbs_cfg80211_ops = {
- .set_channel = lbs_cfg_set_channel,
+ .set_monitor_channel = lbs_cfg_set_channel,
+ .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
.scan = lbs_cfg_scan,
.connect = lbs_cfg_connect,
.disconnect = lbs_cfg_disconnect,
--- a/drivers/net/wireless/orinoco/cfg.c 2012-05-16 21:00:52.000000000 +0200
+++ b/drivers/net/wireless/orinoco/cfg.c 2012-05-16 23:35:51.000000000 +0200
@@ -160,10 +160,10 @@ static int orinoco_scan(struct wiphy *wi
return err;
}
-static int orinoco_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
+static int orinoco_set_monitor_channel(struct wiphy *wiphy,
+ struct net_device *netdev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
{
struct orinoco_private *priv = wiphy_priv(wiphy);
int err = 0;
@@ -286,7 +286,7 @@ static int orinoco_set_wiphy_params(stru
const struct cfg80211_ops orinoco_cfg_ops = {
.change_virtual_intf = orinoco_change_vif,
- .set_channel = orinoco_set_channel,
+ .set_monitor_channel = orinoco_set_monitor_channel,
.scan = orinoco_scan,
.set_wiphy_params = orinoco_set_wiphy_params,
};
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 7/7] cfg80211: clarify set_channel APIs
2012-05-16 21:50 ` [PATCH 7/7] cfg80211: clarify set_channel APIs Johannes Berg
@ 2012-06-05 21:13 ` John W. Linville
2012-06-06 6:04 ` [PATCH 7/7 v2] " Johannes Berg
0 siblings, 1 reply; 11+ messages in thread
From: John W. Linville @ 2012-06-05 21:13 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On Wed, May 16, 2012 at 11:50:21PM +0200, Johannes Berg wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> Now that we've removed all uses of the set_channel
> API except for the monitor channel and in libertas,
> clarify this. Split the libertas mesh use into a
> new libertas_set_mesh_channel() operation, just to
> keep backward compatibility, and rename the normal
> set_channel() to set_monitor_channel().
>
> Also describe the desired set_monitor_channel()
> semantics more clearly.
>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This one fails in the libertas build...
> ---
> drivers/net/wireless/libertas/cfg.c | 39 +++++++++++++++++++++++++-------
> drivers/net/wireless/orinoco/cfg.c | 10 ++++----
> include/net/cfg80211.h | 24 ++++++++++++--------
> net/mac80211/cfg.c | 9 ++++++-
> net/wireless/chan.c | 43 ++++--------------------------------
> net/wireless/core.h | 5 +---
> net/wireless/mesh.c | 26 ++++++++++-----------
> net/wireless/mlme.c | 2 -
> net/wireless/nl80211.c | 21 ++++++++++-------
> net/wireless/wext-compat.c | 10 +-------
> net/wireless/wext-sme.c | 10 ++++++--
> 11 files changed, 100 insertions(+), 99 deletions(-)
>
> --- a/include/net/cfg80211.h 2012-05-16 23:35:50.000000000 +0200
> +++ b/include/net/cfg80211.h 2012-05-16 23:35:51.000000000 +0200
> @@ -1420,11 +1420,14 @@ struct cfg80211_gtk_rekey_data {
> *
> * @set_txq_params: Set TX queue parameters
> *
> - * @set_channel: Set channel for a given wireless interface. Some devices
> - * may support multi-channel operation (by channel hopping) so cfg80211
> - * doesn't verify much. Note, however, that the passed netdev may be
> - * %NULL as well if the user requested changing the channel for the
> - * device itself, or for a monitor interface.
> + * @libertas_set_mesh_channel: Only for backward compatibility for libertas,
> + * as it doesn't implement join_mesh and needs to set the channel to
> + * join the mesh instead.
> + *
> + * @set_monitor_channel: Set the monitor mode channel for the device. If other
> + * interfaces are active this callback should reject the configuration.
> + * If no interfaces are active or the device is down, the channel should
> + * be stored for when a monitor interface becomes active.
> * @get_channel: Get the current operating channel, should return %NULL if
> * there's no single defined operating channel if for example the
> * device implements channel hopping for multi-channel virtual interfaces.
> @@ -1614,9 +1617,13 @@ struct cfg80211_ops {
> int (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
> struct ieee80211_txq_params *params);
>
> - int (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
> - struct ieee80211_channel *chan,
> - enum nl80211_channel_type channel_type);
> + int (*libertas_set_mesh_channel)(struct wiphy *wiphy,
> + struct net_device *dev,
> + struct ieee80211_channel *chan);
> +
> + int (*set_monitor_channel)(struct wiphy *wiphy,
> + struct ieee80211_channel *chan,
> + enum nl80211_channel_type channel_type);
>
> int (*scan)(struct wiphy *wiphy, struct net_device *dev,
> struct cfg80211_scan_request *request);
> @@ -2325,7 +2332,6 @@ struct wireless_dev {
> spinlock_t event_lock;
>
> struct cfg80211_internal_bss *current_bss; /* associated / joined */
> - struct ieee80211_channel *channel;
> struct ieee80211_channel *preset_chan;
> enum nl80211_channel_type preset_chantype;
>
> --- a/net/wireless/chan.c 2012-05-16 23:35:46.000000000 +0200
> +++ b/net/wireless/chan.c 2012-05-16 23:35:51.000000000 +0200
> @@ -78,50 +78,17 @@ bool cfg80211_can_beacon_sec_chan(struct
> }
> EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
>
> -int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
> - struct wireless_dev *wdev, int freq,
> - enum nl80211_channel_type channel_type)
> +int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
> + int freq, enum nl80211_channel_type chantype)
> {
> struct ieee80211_channel *chan;
> - int result;
>
> - if (wdev && 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)
> + if (!rdev->ops->set_monitor_channel)
> return -EOPNOTSUPP;
>
> - chan = rdev_freq_to_chan(rdev, freq, channel_type);
> + chan = rdev_freq_to_chan(rdev, freq, chantype);
> if (!chan)
> return -EINVAL;
>
> - /* Both channels should be able to initiate communication */
> - if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
> - wdev->iftype == NL80211_IFTYPE_AP ||
> - wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
> - wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
> - wdev->iftype == NL80211_IFTYPE_P2P_GO) &&
> - !cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan, channel_type)) {
> - printk(KERN_DEBUG
> - "cfg80211: Secondary channel not allowed to beacon\n");
> - return -EINVAL;
> - }
> -
> - result = rdev->ops->set_channel(&rdev->wiphy,
> - wdev ? wdev->netdev : NULL,
> - chan, channel_type);
> - if (result)
> - return result;
> -
> - if (wdev)
> - wdev->channel = chan;
> -
> - return 0;
> + return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
> }
> --- a/net/wireless/mlme.c 2012-05-16 21:00:52.000000000 +0200
> +++ b/net/wireless/mlme.c 2012-05-16 23:35:51.000000000 +0200
> @@ -948,8 +948,6 @@ void cfg80211_ch_switch_notify(struct ne
> if (WARN_ON(!chan))
> goto out;
>
> - wdev->channel = chan;
> -
> nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
> out:
> wdev_unlock(wdev);
> --- a/net/wireless/wext-compat.c 2012-05-16 23:35:50.000000000 +0200
> +++ b/net/wireless/wext-compat.c 2012-05-16 23:35:51.000000000 +0200
> @@ -802,9 +802,7 @@ static int cfg80211_wext_siwfreq(struct
> if (freq == 0)
> return -EINVAL;
> mutex_lock(&rdev->devlist_mtx);
> - wdev_lock(wdev);
> - err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
> - wdev_unlock(wdev);
> + err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
> mutex_unlock(&rdev->devlist_mtx);
> return err;
> case NL80211_IFTYPE_MESH_POINT:
> @@ -848,11 +846,7 @@ static int cfg80211_wext_giwfreq(struct
> freq->e = 6;
> return 0;
> default:
> - if (!wdev->channel)
> - return -EINVAL;
> - freq->m = wdev->channel->center_freq;
> - freq->e = 6;
> - return 0;
> + return -EINVAL;
> }
> }
>
> --- a/net/wireless/nl80211.c 2012-05-16 23:35:50.000000000 +0200
> +++ b/net/wireless/nl80211.c 2012-05-16 23:35:51.000000000 +0200
> @@ -921,7 +921,7 @@ static int nl80211_send_wiphy(struct sk_
> if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
> goto nla_put_failure;
> }
> - if (dev->ops->set_channel || dev->ops->start_ap ||
> + if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
> dev->ops->join_mesh) {
> i++;
> if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
> @@ -1178,8 +1178,8 @@ static bool nl80211_can_set_dev_channel(
> * the channel in the start-ap or join-mesh commands instead.
> *
> * 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.
> + * whatever else is going on, so they have their own special
> + * operation to set the monitor channel if possible.
> */
> return !wdev ||
> wdev->iftype == NL80211_IFTYPE_AP ||
> @@ -1217,6 +1217,10 @@ static int __nl80211_set_channel(struct
> enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
> u32 freq;
> int result;
> + enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
> +
> + if (wdev)
> + iftype = wdev->iftype;
>
> if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
> return -EINVAL;
> @@ -1231,7 +1235,7 @@ static int __nl80211_set_channel(struct
> freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
>
> mutex_lock(&rdev->devlist_mtx);
> - if (wdev) switch (wdev->iftype) {
> + switch (iftype) {
> case NL80211_IFTYPE_AP:
> case NL80211_IFTYPE_P2P_GO:
> if (wdev->beacon_interval) {
> @@ -1252,12 +1256,11 @@ static int __nl80211_set_channel(struct
> case NL80211_IFTYPE_MESH_POINT:
> result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
> break;
> + case NL80211_IFTYPE_MONITOR:
> + result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
> + break;
> default:
> - 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);
> + result = -EINVAL;
> }
> mutex_unlock(&rdev->devlist_mtx);
>
> --- a/net/wireless/core.h 2012-05-16 23:35:50.000000000 +0200
> +++ b/net/wireless/core.h 2012-05-16 23:35:51.000000000 +0200
> @@ -444,9 +444,8 @@ cfg80211_can_add_interface(struct cfg802
> struct ieee80211_channel *
> rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
> 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);
> +int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
> + int freq, enum nl80211_channel_type chantype);
>
> int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
> const u8 *rates, unsigned int n_rates,
> --- a/net/wireless/wext-sme.c 2012-05-16 21:00:52.000000000 +0200
> +++ b/net/wireless/wext-sme.c 2012-05-16 23:35:51.000000000 +0200
> @@ -111,9 +111,15 @@ int cfg80211_mgd_wext_siwfreq(struct net
>
> wdev->wext.connect.channel = chan;
>
> - /* SSID is not set, we just want to switch channel */
> + /*
> + * SSID is not set, we just want to switch monitor channel,
> + * this is really just backward compatibility, if the SSID
> + * is set then we use the channel to select the BSS to use
> + * to connect to instead. If we were connected on another
> + * channel we disconnected above and reconnect below.
> + */
> if (chan && !wdev->wext.connect.ssid_len) {
> - err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
> + err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
> goto out;
> }
>
> --- a/net/mac80211/cfg.c 2012-05-16 23:35:50.000000000 +0200
> +++ b/net/mac80211/cfg.c 2012-05-16 23:35:51.000000000 +0200
> @@ -709,6 +709,13 @@ static int ieee80211_set_channel(struct
> return 0;
> }
>
> +static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
> + struct ieee80211_channel *chan,
> + enum nl80211_channel_type channel_type)
> +{
> + return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
> +}
> +
> static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
> const u8 *resp, size_t resp_len)
> {
> @@ -2930,7 +2937,7 @@ struct cfg80211_ops mac80211_config_ops
> #endif
> .change_bss = ieee80211_change_bss,
> .set_txq_params = ieee80211_set_txq_params,
> - .set_channel = ieee80211_set_channel,
> + .set_monitor_channel = ieee80211_set_monitor_channel,
> .suspend = ieee80211_suspend,
> .resume = ieee80211_resume,
> .scan = ieee80211_scan,
> --- a/net/wireless/mesh.c 2012-05-16 23:35:50.000000000 +0200
> +++ b/net/wireless/mesh.c 2012-05-16 23:35:51.000000000 +0200
> @@ -179,6 +179,13 @@ int cfg80211_set_mesh_freq(struct cfg802
> {
> struct ieee80211_channel *channel;
>
> + channel = rdev_freq_to_chan(rdev, freq, channel_type);
> + if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
> + channel,
> + channel_type)) {
> + return -EINVAL;
> + }
> +
> /*
> * Workaround for libertas (only!), it puts the interface
> * into mesh mode but doesn't implement join_mesh. Instead,
> @@ -186,27 +193,20 @@ int cfg80211_set_mesh_freq(struct cfg802
> * you set the channel. Note that the libertas mesh isn't
> * compatible with 802.11 mesh.
> */
> - if (!rdev->ops->join_mesh) {
> - int err;
> + if (rdev->ops->libertas_set_mesh_channel) {
> + if (channel_type != NL80211_CHAN_NO_HT)
> + return -EINVAL;
>
> if (!netif_running(wdev->netdev))
> return -ENETDOWN;
> - wdev_lock(wdev);
> - err = cfg80211_set_freq(rdev, wdev, freq, channel_type);
> - wdev_unlock(wdev);
> -
> - return err;
> + return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
> + wdev->netdev,
> + channel);
> }
>
> if (wdev->mesh_id_len)
> return -EBUSY;
>
> - channel = rdev_freq_to_chan(rdev, freq, channel_type);
> - if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
> - channel,
> - channel_type)) {
> - return -EINVAL;
> - }
> wdev->preset_chan = channel;
> wdev->preset_chantype = channel_type;
> return 0;
> --- a/drivers/net/wireless/libertas/cfg.c 2012-05-16 21:00:52.000000000 +0200
> +++ b/drivers/net/wireless/libertas/cfg.c 2012-05-16 23:35:51.000000000 +0200
> @@ -435,10 +435,9 @@ static int lbs_add_wpa_tlv(u8 *tlv, cons
> * Set Channel
> */
>
> -static int lbs_cfg_set_channel(struct wiphy *wiphy,
> - struct net_device *netdev,
> - struct ieee80211_channel *channel,
> - enum nl80211_channel_type channel_type)
> +static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
> + struct ieee80211_channel *channel,
> + enum nl80211_channel_type channel_type)
> {
> struct lbs_private *priv = wiphy_priv(wiphy);
> int ret = -ENOTSUPP;
> @@ -449,10 +448,31 @@ static int lbs_cfg_set_channel(struct wi
> if (channel_type != NL80211_CHAN_NO_HT)
> goto out;
>
> - if (netdev == priv->mesh_dev)
> - ret = lbs_mesh_set_channel(priv, channel->hw_value);
> - else
> - ret = lbs_set_channel(priv, channel->hw_value);
> + ret = lbs_set_channel(priv, channel->hw_value);
> +
> + out:
> + lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
> + return ret;
> +}
> +
> +static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
> + struct net_device *netdev,
> + struct ieee80211_channel *channel,
> + enum nl80211_channel_type channel_type)
> +{
> + struct lbs_private *priv = wiphy_priv(wiphy);
> + int ret = -ENOTSUPP;
> +
> + lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
> + netdev_name(netdev), channel->center_freq, channel_type);
> +
> + if (channel_type != NL80211_CHAN_NO_HT)
> + goto out;
> +
> + if (netdev != priv->mesh_dev)
> + goto out;
> +
> + ret = lbs_mesh_set_channel(priv, channel->hw_value);
>
> out:
> lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
> @@ -2029,7 +2049,8 @@ static int lbs_leave_ibss(struct wiphy *
> */
>
> static struct cfg80211_ops lbs_cfg80211_ops = {
> - .set_channel = lbs_cfg_set_channel,
> + .set_monitor_channel = lbs_cfg_set_channel,
> + .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
> .scan = lbs_cfg_scan,
> .connect = lbs_cfg_connect,
> .disconnect = lbs_cfg_disconnect,
> --- a/drivers/net/wireless/orinoco/cfg.c 2012-05-16 21:00:52.000000000 +0200
> +++ b/drivers/net/wireless/orinoco/cfg.c 2012-05-16 23:35:51.000000000 +0200
> @@ -160,10 +160,10 @@ static int orinoco_scan(struct wiphy *wi
> return err;
> }
>
> -static int orinoco_set_channel(struct wiphy *wiphy,
> - struct net_device *netdev,
> - struct ieee80211_channel *chan,
> - enum nl80211_channel_type channel_type)
> +static int orinoco_set_monitor_channel(struct wiphy *wiphy,
> + struct net_device *netdev,
> + struct ieee80211_channel *chan,
> + enum nl80211_channel_type channel_type)
> {
> struct orinoco_private *priv = wiphy_priv(wiphy);
> int err = 0;
> @@ -286,7 +286,7 @@ static int orinoco_set_wiphy_params(stru
>
> const struct cfg80211_ops orinoco_cfg_ops = {
> .change_virtual_intf = orinoco_change_vif,
> - .set_channel = orinoco_set_channel,
> + .set_monitor_channel = orinoco_set_monitor_channel,
> .scan = orinoco_scan,
> .set_wiphy_params = orinoco_set_wiphy_params,
> };
>
>
>
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH 7/7 v2] cfg80211: clarify set_channel APIs
2012-06-05 21:13 ` John W. Linville
@ 2012-06-06 6:04 ` Johannes Berg
2012-06-06 6:18 ` [PATCH 7/7 v3] " Johannes Berg
0 siblings, 1 reply; 11+ messages in thread
From: Johannes Berg @ 2012-06-06 6:04 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, Dan Williams
From: Johannes Berg <johannes.berg@intel.com>
Now that we've removed all uses of the set_channel
API except for the monitor channel and in libertas,
clarify this. Split the libertas mesh use into a
new libertas_set_mesh_channel() operation, just to
keep backward compatibility, and rename the normal
set_channel() to set_monitor_channel().
Also describe the desired set_monitor_channel()
semantics more clearly.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
drivers/net/wireless/libertas/cfg.c | 39 +++++++++++++++++++++---------
drivers/net/wireless/libertas/dev.h | 1 +
drivers/net/wireless/libertas/mesh.c | 7 ++----
drivers/net/wireless/orinoco/cfg.c | 10 ++++----
include/net/cfg80211.h | 24 ++++++++++++-------
net/mac80211/cfg.c | 9 ++++++-
net/wireless/chan.c | 43 ++++------------------------------
net/wireless/core.h | 5 ++--
net/wireless/mesh.c | 26 ++++++++++----------
net/wireless/mlme.c | 2 --
net/wireless/nl80211.c | 21 ++++++++++-------
net/wireless/wext-compat.c | 10 ++------
net/wireless/wext-sme.c | 10 ++++++--
13 files changed, 101 insertions(+), 106 deletions(-)
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 2fa879b..f4a2030 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -435,24 +435,40 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
* Set Channel
*/
-static int lbs_cfg_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type)
+static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type)
{
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = -ENOTSUPP;
- lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
- netdev_name(netdev), channel->center_freq, channel_type);
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
+ channel->center_freq, channel_type);
if (channel_type != NL80211_CHAN_NO_HT)
goto out;
- if (netdev == priv->mesh_dev)
- ret = lbs_mesh_set_channel(priv, channel->hw_value);
- else
- ret = lbs_set_channel(priv, channel->hw_value);
+ ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
+ struct net_device *netdev,
+ struct ieee80211_channel *channel)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = -ENOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
+ netdev_name(netdev), channel->center_freq);
+
+ if (netdev != priv->mesh_dev)
+ goto out;
+
+ ret = lbs_mesh_set_channel(priv, channel->hw_value);
out:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -2029,7 +2045,8 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
*/
static struct cfg80211_ops lbs_cfg80211_ops = {
- .set_channel = lbs_cfg_set_channel,
+ .set_monitor_channel = lbs_cfg_set_monitor_channel,
+ .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
.scan = lbs_cfg_scan,
.connect = lbs_cfg_connect,
.disconnect = lbs_cfg_disconnect,
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 6720054..60996ce 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -58,6 +58,7 @@ struct lbs_private {
uint16_t mesh_tlv;
u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 mesh_ssid_len;
+ u8 mesh_channel;
#endif
/* Debugfs */
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index e87c031..9780775 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -131,16 +131,13 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
{
+ priv->mesh_channel = channel;
return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
}
static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
{
- struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
- if (mesh_wdev->channel)
- return mesh_wdev->channel->hw_value;
- else
- return 1;
+ return priv->mesh_channel ?: 1;
}
/***************************************************************************
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index f7b15b8..e26af32 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -160,10 +160,10 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
return err;
}
-static int orinoco_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
+static int orinoco_set_monitor_channel(struct wiphy *wiphy,
+ struct net_device *netdev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
{
struct orinoco_private *priv = wiphy_priv(wiphy);
int err = 0;
@@ -286,7 +286,7 @@ static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
const struct cfg80211_ops orinoco_cfg_ops = {
.change_virtual_intf = orinoco_change_vif,
- .set_channel = orinoco_set_channel,
+ .set_monitor_channel = orinoco_set_monitor_channel,
.scan = orinoco_scan,
.set_wiphy_params = orinoco_set_wiphy_params,
};
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4c90c44..7319f25 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1420,11 +1420,14 @@ struct cfg80211_gtk_rekey_data {
*
* @set_txq_params: Set TX queue parameters
*
- * @set_channel: Set channel for a given wireless interface. Some devices
- * may support multi-channel operation (by channel hopping) so cfg80211
- * doesn't verify much. Note, however, that the passed netdev may be
- * %NULL as well if the user requested changing the channel for the
- * device itself, or for a monitor interface.
+ * @libertas_set_mesh_channel: Only for backward compatibility for libertas,
+ * as it doesn't implement join_mesh and needs to set the channel to
+ * join the mesh instead.
+ *
+ * @set_monitor_channel: Set the monitor mode channel for the device. If other
+ * interfaces are active this callback should reject the configuration.
+ * If no interfaces are active or the device is down, the channel should
+ * be stored for when a monitor interface becomes active.
* @get_channel: Get the current operating channel, should return %NULL if
* there's no single defined operating channel if for example the
* device implements channel hopping for multi-channel virtual interfaces.
@@ -1614,9 +1617,13 @@ struct cfg80211_ops {
int (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_txq_params *params);
- int (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type);
+ int (*libertas_set_mesh_channel)(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan);
+
+ int (*set_monitor_channel)(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
int (*scan)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request);
@@ -2325,7 +2332,6 @@ struct wireless_dev {
spinlock_t event_lock;
struct cfg80211_internal_bss *current_bss; /* associated / joined */
- struct ieee80211_channel *channel;
struct ieee80211_channel *preset_chan;
enum nl80211_channel_type preset_chantype;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index f47af8b..f6898c6 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -709,6 +709,13 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
return 0;
}
+static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
+}
+
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
const u8 *resp, size_t resp_len)
{
@@ -2932,7 +2939,7 @@ struct cfg80211_ops mac80211_config_ops = {
#endif
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
- .set_channel = ieee80211_set_channel,
+ .set_monitor_channel = ieee80211_set_monitor_channel,
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
.scan = ieee80211_scan,
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 20b87d8..c1999e4 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -78,50 +78,17 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
}
EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, int freq,
- enum nl80211_channel_type channel_type)
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ int freq, enum nl80211_channel_type chantype)
{
struct ieee80211_channel *chan;
- int result;
- if (wdev && 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)
+ if (!rdev->ops->set_monitor_channel)
return -EOPNOTSUPP;
- chan = rdev_freq_to_chan(rdev, freq, channel_type);
+ chan = rdev_freq_to_chan(rdev, freq, chantype);
if (!chan)
return -EINVAL;
- /* Both channels should be able to initiate communication */
- if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
- wdev->iftype == NL80211_IFTYPE_AP ||
- wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
- wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
- wdev->iftype == NL80211_IFTYPE_P2P_GO) &&
- !cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan, channel_type)) {
- printk(KERN_DEBUG
- "cfg80211: Secondary channel not allowed to beacon\n");
- return -EINVAL;
- }
-
- result = rdev->ops->set_channel(&rdev->wiphy,
- wdev ? wdev->netdev : NULL,
- chan, channel_type);
- if (result)
- return result;
-
- if (wdev)
- wdev->channel = chan;
-
- return 0;
+ return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 1d3d241..9348a47 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -444,9 +444,8 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
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);
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ int freq, enum nl80211_channel_type chantype);
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
const u8 *rates, unsigned int n_rates,
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 2e3b700..b44c736 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -179,6 +179,13 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
{
struct ieee80211_channel *channel;
+ channel = rdev_freq_to_chan(rdev, freq, channel_type);
+ if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+ channel,
+ channel_type)) {
+ return -EINVAL;
+ }
+
/*
* Workaround for libertas (only!), it puts the interface
* into mesh mode but doesn't implement join_mesh. Instead,
@@ -186,27 +193,20 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
* you set the channel. Note that the libertas mesh isn't
* compatible with 802.11 mesh.
*/
- if (!rdev->ops->join_mesh) {
- int err;
+ if (rdev->ops->libertas_set_mesh_channel) {
+ if (channel_type != NL80211_CHAN_NO_HT)
+ return -EINVAL;
if (!netif_running(wdev->netdev))
return -ENETDOWN;
- wdev_lock(wdev);
- err = cfg80211_set_freq(rdev, wdev, freq, channel_type);
- wdev_unlock(wdev);
-
- return err;
+ return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
+ wdev->netdev,
+ channel);
}
if (wdev->mesh_id_len)
return -EBUSY;
- channel = rdev_freq_to_chan(rdev, freq, channel_type);
- if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
- channel,
- channel_type)) {
- return -EINVAL;
- }
wdev->preset_chan = channel;
wdev->preset_chantype = channel_type;
return 0;
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index eb90988..da4406f 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -947,8 +947,6 @@ 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);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b22f1f8..5e29bd3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -921,7 +921,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
goto nla_put_failure;
}
- if (dev->ops->set_channel || dev->ops->start_ap ||
+ if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
dev->ops->join_mesh) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
@@ -1178,8 +1178,8 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
* the channel in the start-ap or join-mesh commands instead.
*
* 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.
+ * whatever else is going on, so they have their own special
+ * operation to set the monitor channel if possible.
*/
return !wdev ||
wdev->iftype == NL80211_IFTYPE_AP ||
@@ -1217,6 +1217,10 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u32 freq;
int result;
+ enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
+
+ if (wdev)
+ iftype = wdev->iftype;
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
@@ -1231,7 +1235,7 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
mutex_lock(&rdev->devlist_mtx);
- if (wdev) switch (wdev->iftype) {
+ switch (iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
if (wdev->beacon_interval) {
@@ -1252,12 +1256,11 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_MESH_POINT:
result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
break;
+ case NL80211_IFTYPE_MONITOR:
+ result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
+ break;
default:
- 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);
+ result = -EINVAL;
}
mutex_unlock(&rdev->devlist_mtx);
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index faeb035..bc87983 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -802,9 +802,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
if (freq == 0)
return -EINVAL;
mutex_lock(&rdev->devlist_mtx);
- wdev_lock(wdev);
- err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
- wdev_unlock(wdev);
+ err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
mutex_unlock(&rdev->devlist_mtx);
return err;
case NL80211_IFTYPE_MESH_POINT:
@@ -848,11 +846,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
freq->e = 6;
return 0;
default:
- if (!wdev->channel)
- return -EINVAL;
- freq->m = wdev->channel->center_freq;
- freq->e = 6;
- return 0;
+ return -EINVAL;
}
}
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 7decbd3..1f773f6 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -111,9 +111,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
wdev->wext.connect.channel = chan;
- /* SSID is not set, we just want to switch channel */
+ /*
+ * SSID is not set, we just want to switch monitor channel,
+ * this is really just backward compatibility, if the SSID
+ * is set then we use the channel to select the BSS to use
+ * to connect to instead. If we were connected on another
+ * channel we disconnected above and reconnect below.
+ */
if (chan && !wdev->wext.connect.ssid_len) {
- err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
+ err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
goto out;
}
--
1.7.10
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 7/7 v3] cfg80211: clarify set_channel APIs
2012-06-06 6:04 ` [PATCH 7/7 v2] " Johannes Berg
@ 2012-06-06 6:18 ` Johannes Berg
0 siblings, 0 replies; 11+ messages in thread
From: Johannes Berg @ 2012-06-06 6:18 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, Dan Williams
From: Johannes Berg <johannes.berg@intel.com>
Now that we've removed all uses of the set_channel
API except for the monitor channel and in libertas,
clarify this. Split the libertas mesh use into a
new libertas_set_mesh_channel() operation, just to
keep backward compatibility, and rename the normal
set_channel() to set_monitor_channel().
Also describe the desired set_monitor_channel()
semantics more clearly.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
v3: also fix orinoco compilation ... :-(
drivers/net/wireless/libertas/cfg.c | 39 +++++++++++++++++++++---------
drivers/net/wireless/libertas/dev.h | 1 +
drivers/net/wireless/libertas/mesh.c | 7 ++----
drivers/net/wireless/orinoco/cfg.c | 9 ++++---
include/net/cfg80211.h | 24 ++++++++++++-------
net/mac80211/cfg.c | 9 ++++++-
net/wireless/chan.c | 43 ++++------------------------------
net/wireless/core.h | 5 ++--
net/wireless/mesh.c | 26 ++++++++++----------
net/wireless/mlme.c | 2 --
net/wireless/nl80211.c | 21 ++++++++++-------
net/wireless/wext-compat.c | 10 ++------
net/wireless/wext-sme.c | 10 ++++++--
13 files changed, 100 insertions(+), 106 deletions(-)
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 2fa879b..f4a2030 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -435,24 +435,40 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
* Set Channel
*/
-static int lbs_cfg_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *channel,
- enum nl80211_channel_type channel_type)
+static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *channel,
+ enum nl80211_channel_type channel_type)
{
struct lbs_private *priv = wiphy_priv(wiphy);
int ret = -ENOTSUPP;
- lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d",
- netdev_name(netdev), channel->center_freq, channel_type);
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
+ channel->center_freq, channel_type);
if (channel_type != NL80211_CHAN_NO_HT)
goto out;
- if (netdev == priv->mesh_dev)
- ret = lbs_mesh_set_channel(priv, channel->hw_value);
- else
- ret = lbs_set_channel(priv, channel->hw_value);
+ ret = lbs_set_channel(priv, channel->hw_value);
+
+ out:
+ lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
+ return ret;
+}
+
+static int lbs_cfg_set_mesh_channel(struct wiphy *wiphy,
+ struct net_device *netdev,
+ struct ieee80211_channel *channel)
+{
+ struct lbs_private *priv = wiphy_priv(wiphy);
+ int ret = -ENOTSUPP;
+
+ lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d",
+ netdev_name(netdev), channel->center_freq);
+
+ if (netdev != priv->mesh_dev)
+ goto out;
+
+ ret = lbs_mesh_set_channel(priv, channel->hw_value);
out:
lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -2029,7 +2045,8 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
*/
static struct cfg80211_ops lbs_cfg80211_ops = {
- .set_channel = lbs_cfg_set_channel,
+ .set_monitor_channel = lbs_cfg_set_monitor_channel,
+ .libertas_set_mesh_channel = lbs_cfg_set_mesh_channel,
.scan = lbs_cfg_scan,
.connect = lbs_cfg_connect,
.disconnect = lbs_cfg_disconnect,
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 6720054..60996ce 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -58,6 +58,7 @@ struct lbs_private {
uint16_t mesh_tlv;
u8 mesh_ssid[IEEE80211_MAX_SSID_LEN + 1];
u8 mesh_ssid_len;
+ u8 mesh_channel;
#endif
/* Debugfs */
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index e87c031..9780775 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -131,16 +131,13 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
{
+ priv->mesh_channel = channel;
return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
}
static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
{
- struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr;
- if (mesh_wdev->channel)
- return mesh_wdev->channel->hw_value;
- else
- return 1;
+ return priv->mesh_channel ?: 1;
}
/***************************************************************************
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
index f7b15b8..e156755 100644
--- a/drivers/net/wireless/orinoco/cfg.c
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -160,10 +160,9 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
return err;
}
-static int orinoco_set_channel(struct wiphy *wiphy,
- struct net_device *netdev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
+static int orinoco_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
{
struct orinoco_private *priv = wiphy_priv(wiphy);
int err = 0;
@@ -286,7 +285,7 @@ static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
const struct cfg80211_ops orinoco_cfg_ops = {
.change_virtual_intf = orinoco_change_vif,
- .set_channel = orinoco_set_channel,
+ .set_monitor_channel = orinoco_set_monitor_channel,
.scan = orinoco_scan,
.set_wiphy_params = orinoco_set_wiphy_params,
};
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 4c90c44..7319f25 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1420,11 +1420,14 @@ struct cfg80211_gtk_rekey_data {
*
* @set_txq_params: Set TX queue parameters
*
- * @set_channel: Set channel for a given wireless interface. Some devices
- * may support multi-channel operation (by channel hopping) so cfg80211
- * doesn't verify much. Note, however, that the passed netdev may be
- * %NULL as well if the user requested changing the channel for the
- * device itself, or for a monitor interface.
+ * @libertas_set_mesh_channel: Only for backward compatibility for libertas,
+ * as it doesn't implement join_mesh and needs to set the channel to
+ * join the mesh instead.
+ *
+ * @set_monitor_channel: Set the monitor mode channel for the device. If other
+ * interfaces are active this callback should reject the configuration.
+ * If no interfaces are active or the device is down, the channel should
+ * be stored for when a monitor interface becomes active.
* @get_channel: Get the current operating channel, should return %NULL if
* there's no single defined operating channel if for example the
* device implements channel hopping for multi-channel virtual interfaces.
@@ -1614,9 +1617,13 @@ struct cfg80211_ops {
int (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_txq_params *params);
- int (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type);
+ int (*libertas_set_mesh_channel)(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct ieee80211_channel *chan);
+
+ int (*set_monitor_channel)(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
int (*scan)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request);
@@ -2325,7 +2332,6 @@ struct wireless_dev {
spinlock_t event_lock;
struct cfg80211_internal_bss *current_bss; /* associated / joined */
- struct ieee80211_channel *channel;
struct ieee80211_channel *preset_chan;
enum nl80211_channel_type preset_chantype;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index f47af8b..f6898c6 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -709,6 +709,13 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
return 0;
}
+static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ return ieee80211_set_channel(wiphy, NULL, chan, channel_type);
+}
+
static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
const u8 *resp, size_t resp_len)
{
@@ -2932,7 +2939,7 @@ struct cfg80211_ops mac80211_config_ops = {
#endif
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
- .set_channel = ieee80211_set_channel,
+ .set_monitor_channel = ieee80211_set_monitor_channel,
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
.scan = ieee80211_scan,
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 20b87d8..c1999e4 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -78,50 +78,17 @@ bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
}
EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
-int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
- struct wireless_dev *wdev, int freq,
- enum nl80211_channel_type channel_type)
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ int freq, enum nl80211_channel_type chantype)
{
struct ieee80211_channel *chan;
- int result;
- if (wdev && 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)
+ if (!rdev->ops->set_monitor_channel)
return -EOPNOTSUPP;
- chan = rdev_freq_to_chan(rdev, freq, channel_type);
+ chan = rdev_freq_to_chan(rdev, freq, chantype);
if (!chan)
return -EINVAL;
- /* Both channels should be able to initiate communication */
- if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC ||
- wdev->iftype == NL80211_IFTYPE_AP ||
- wdev->iftype == NL80211_IFTYPE_AP_VLAN ||
- wdev->iftype == NL80211_IFTYPE_MESH_POINT ||
- wdev->iftype == NL80211_IFTYPE_P2P_GO) &&
- !cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan, channel_type)) {
- printk(KERN_DEBUG
- "cfg80211: Secondary channel not allowed to beacon\n");
- return -EINVAL;
- }
-
- result = rdev->ops->set_channel(&rdev->wiphy,
- wdev ? wdev->netdev : NULL,
- chan, channel_type);
- if (result)
- return result;
-
- if (wdev)
- wdev->channel = chan;
-
- return 0;
+ return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype);
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 1d3d241..9348a47 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -444,9 +444,8 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
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);
+int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
+ int freq, enum nl80211_channel_type chantype);
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
const u8 *rates, unsigned int n_rates,
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 2e3b700..b44c736 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -179,6 +179,13 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
{
struct ieee80211_channel *channel;
+ channel = rdev_freq_to_chan(rdev, freq, channel_type);
+ if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
+ channel,
+ channel_type)) {
+ return -EINVAL;
+ }
+
/*
* Workaround for libertas (only!), it puts the interface
* into mesh mode but doesn't implement join_mesh. Instead,
@@ -186,27 +193,20 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
* you set the channel. Note that the libertas mesh isn't
* compatible with 802.11 mesh.
*/
- if (!rdev->ops->join_mesh) {
- int err;
+ if (rdev->ops->libertas_set_mesh_channel) {
+ if (channel_type != NL80211_CHAN_NO_HT)
+ return -EINVAL;
if (!netif_running(wdev->netdev))
return -ENETDOWN;
- wdev_lock(wdev);
- err = cfg80211_set_freq(rdev, wdev, freq, channel_type);
- wdev_unlock(wdev);
-
- return err;
+ return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy,
+ wdev->netdev,
+ channel);
}
if (wdev->mesh_id_len)
return -EBUSY;
- channel = rdev_freq_to_chan(rdev, freq, channel_type);
- if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
- channel,
- channel_type)) {
- return -EINVAL;
- }
wdev->preset_chan = channel;
wdev->preset_chantype = channel_type;
return 0;
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index eb90988..da4406f 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -947,8 +947,6 @@ 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);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b22f1f8..5e29bd3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -921,7 +921,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
if (nla_put_u32(msg, i, NL80211_CMD_SET_WIPHY_NETNS))
goto nla_put_failure;
}
- if (dev->ops->set_channel || dev->ops->start_ap ||
+ if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
dev->ops->join_mesh) {
i++;
if (nla_put_u32(msg, i, NL80211_CMD_SET_CHANNEL))
@@ -1178,8 +1178,8 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
* the channel in the start-ap or join-mesh commands instead.
*
* 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.
+ * whatever else is going on, so they have their own special
+ * operation to set the monitor channel if possible.
*/
return !wdev ||
wdev->iftype == NL80211_IFTYPE_AP ||
@@ -1217,6 +1217,10 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
u32 freq;
int result;
+ enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
+
+ if (wdev)
+ iftype = wdev->iftype;
if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
return -EINVAL;
@@ -1231,7 +1235,7 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
mutex_lock(&rdev->devlist_mtx);
- if (wdev) switch (wdev->iftype) {
+ switch (iftype) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
if (wdev->beacon_interval) {
@@ -1252,12 +1256,11 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_MESH_POINT:
result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
break;
+ case NL80211_IFTYPE_MONITOR:
+ result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
+ break;
default:
- 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);
+ result = -EINVAL;
}
mutex_unlock(&rdev->devlist_mtx);
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index faeb035..bc87983 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -802,9 +802,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
if (freq == 0)
return -EINVAL;
mutex_lock(&rdev->devlist_mtx);
- wdev_lock(wdev);
- err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
- wdev_unlock(wdev);
+ err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
mutex_unlock(&rdev->devlist_mtx);
return err;
case NL80211_IFTYPE_MESH_POINT:
@@ -848,11 +846,7 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
freq->e = 6;
return 0;
default:
- if (!wdev->channel)
- return -EINVAL;
- freq->m = wdev->channel->center_freq;
- freq->e = 6;
- return 0;
+ return -EINVAL;
}
}
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 7decbd3..1f773f6 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -111,9 +111,15 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
wdev->wext.connect.channel = chan;
- /* SSID is not set, we just want to switch channel */
+ /*
+ * SSID is not set, we just want to switch monitor channel,
+ * this is really just backward compatibility, if the SSID
+ * is set then we use the channel to select the BSS to use
+ * to connect to instead. If we were connected on another
+ * channel we disconnected above and reconnect below.
+ */
if (chan && !wdev->wext.connect.ssid_len) {
- err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT);
+ err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
goto out;
}
--
1.7.10
^ permalink raw reply related [flat|nested] 11+ messages in thread