From: Thomas Pedersen <thomas@cozybit.com>
To: Johannes Berg <johannes@sipsolutions.net>
Cc: linux-wireless@vger.kernel.org, Dan Williams <dcbw@redhat.com>
Subject: Re: [RFC 1/3] cfg80211: provide channel to join_mesh function
Date: Fri, 11 May 2012 12:10:49 -0700 [thread overview]
Message-ID: <CAG6hwVPgTOc_VtE2NaNcOTh6xTn_zBso7UOoN=_Tn4M7asG3dA@mail.gmail.com> (raw)
In-Reply-To: <20120511181044.806226449@sipsolutions.net>
Hi Johannes,
On Fri, May 11, 2012 at 11:08 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> 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;
Can we make the default channel type HT20 if the band supports it? The
HT mixed-mode protection implementation in mesh currently only
considers mesh peers, so maybe this isn't acceptable, but it would be
nice.
> + }
> +
> + 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;
> }
>
>
next prev parent reply other threads:[~2012-05-11 19:11 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
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 19:10 ` Thomas Pedersen [this message]
2012-05-11 19:15 ` Johannes Berg
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAG6hwVPgTOc_VtE2NaNcOTh6xTn_zBso7UOoN=_Tn4M7asG3dA@mail.gmail.com' \
--to=thomas@cozybit.com \
--cc=dcbw@redhat.com \
--cc=johannes@sipsolutions.net \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).