* [RFC 1/3] cfg80211: provide channel to join_mesh function
2012-05-11 18:08 [RFC 0/3] mesh/wds channel changes & clarifications Johannes Berg
@ 2012-05-11 18:08 ` Johannes Berg
2012-05-11 19:10 ` Thomas Pedersen
2012-05-11 18:08 ` [RFC 2/3] cfg80211: disallow setting channel on WDS interfaces Johannes Berg
2012-05-11 18:08 ` [RFC 3/3] cfg80211: clarify set_channel APIs Johannes Berg
2 siblings, 1 reply; 6+ messages in thread
From: Johannes Berg @ 2012-05-11 18:08 UTC (permalink / raw)
To: linux-wireless; +Cc: Dan Williams, Thomas Pedersen
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 then.
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 | 40 +++++++++++++++----
net/wireless/wext-compat.c | 12 +++++
6 files changed, 147 insertions(+), 13 deletions(-)
--- a/include/net/cfg80211.h 2012-05-11 19:25:38.000000000 +0200
+++ b/include/net/cfg80211.h 2012-05-11 19:25:39.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-11 19:25:38.000000000 +0200
+++ b/net/wireless/nl80211.c 2012-05-11 19:34:13.000000000 +0200
@@ -896,7 +896,8 @@ static int nl80211_send_wiphy(struct sk_
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
}
- if (dev->ops->set_channel || dev->ops->start_ap) {
+ if (dev->ops->set_channel || dev->ops->start_ap ||
+ dev->ops->join_mesh) {
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_SET_CHANNEL);
}
@@ -1127,17 +1128,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, mesh
- * and WDS 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 ||
@@ -1208,6 +1211,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);
@@ -5999,6 +6005,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-11 19:25:19.000000000 +0200
+++ b/net/wireless/core.h 2012-05-11 19:36:17.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-11 19:25:19.000000000 +0200
+++ b/net/wireless/mesh.c 2012-05-11 19:44:13.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-11 19:25:38.000000000 +0200
+++ b/net/mac80211/cfg.c 2012-05-11 19:25:39.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-11 19:25:19.000000000 +0200
+++ b/net/wireless/wext-compat.c 2012-05-11 19:45:41.000000000 +0200
@@ -797,7 +797,6 @@ static int cfg80211_wext_siwfreq(struct
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)
return freq;
@@ -809,6 +808,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] 6+ messages in thread* [RFC 3/3] cfg80211: clarify set_channel APIs
2012-05-11 18:08 [RFC 0/3] mesh/wds channel changes & clarifications Johannes Berg
2012-05-11 18:08 ` [RFC 1/3] cfg80211: provide channel to join_mesh function Johannes Berg
2012-05-11 18:08 ` [RFC 2/3] cfg80211: disallow setting channel on WDS interfaces Johannes Berg
@ 2012-05-11 18:08 ` Johannes Berg
2 siblings, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2012-05-11 18:08 UTC (permalink / raw)
To: linux-wireless; +Cc: Dan Williams, Thomas Pedersen
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 | 16 +++++++------
net/wireless/wext-compat.c | 10 +-------
net/wireless/wext-sme.c | 10 ++++++--
11 files changed, 97 insertions(+), 97 deletions(-)
--- a/include/net/cfg80211.h 2012-05-11 20:01:08.000000000 +0200
+++ b/include/net/cfg80211.h 2012-05-11 20:01:11.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-11 20:01:08.000000000 +0200
+++ b/net/wireless/chan.c 2012-05-11 20:01:11.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-11 20:01:08.000000000 +0200
+++ b/net/wireless/mlme.c 2012-05-11 20:01:11.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-11 20:01:08.000000000 +0200
+++ b/net/wireless/wext-compat.c 2012-05-11 20:01:11.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-11 20:01:08.000000000 +0200
+++ b/net/wireless/nl80211.c 2012-05-11 20:01:11.000000000 +0200
@@ -896,7 +896,7 @@ static int nl80211_send_wiphy(struct sk_
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
}
- if (dev->ops->set_channel || dev->ops->start_ap ||
+ if (dev->ops->set_monitor_channel || dev->ops->start_ap ||
dev->ops->join_mesh) {
i++;
NLA_PUT_U32(msg, i, NL80211_CMD_SET_CHANNEL);
@@ -1177,6 +1177,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;
@@ -1191,7 +1195,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) {
@@ -1212,12 +1216,10 @@ 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);
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-11 20:01:08.000000000 +0200
+++ b/net/wireless/core.h 2012-05-11 20:01:11.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);
u16 cfg80211_calculate_bitrate(struct rate_info *rate);
--- a/net/wireless/wext-sme.c 2012-05-11 20:01:08.000000000 +0200
+++ b/net/wireless/wext-sme.c 2012-05-11 20:01:11.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-11 20:01:08.000000000 +0200
+++ b/net/mac80211/cfg.c 2012-05-11 20:01:11.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-11 20:01:08.000000000 +0200
+++ b/net/wireless/mesh.c 2012-05-11 20:01:11.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-11 20:01:08.000000000 +0200
+++ b/drivers/net/wireless/libertas/cfg.c 2012-05-11 20:01:11.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-11 20:01:08.000000000 +0200
+++ b/drivers/net/wireless/orinoco/cfg.c 2012-05-11 20:01:11.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] 6+ messages in thread