This patch adds new NL80211_CMD_SET_WIPHY attributes
NL80211_ATTR_WIPHY_FREQ and NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET to allow
userspace to set the operating channel (e.g., hostapd for AP mode).
Signed-off-by: Jouni Malinen <[email protected]>
--
Userspace example of a user for this is available in hostap.git/hostapd
where this gets rid of one more WEXT ioctl and adds support for enabling
HT40. Drivers supporting AP mode can add HT40 support based on the new
struct ieee80211_ht_conf variable sec_chan_offset in their config()
handler.
Index: wireless-testing/include/linux/nl80211.h
===================================================================
--- wireless-testing.orig/include/linux/nl80211.h 2008-11-25 18:44:19.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h 2008-11-25 19:10:27.000000000 +0200
@@ -26,8 +26,9 @@
* @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
- * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME
- * and/or %NL80211_ATTR_WIPHY_TXQ_PARAMS.
+ * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or
+ * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@@ -180,6 +181,11 @@
* /sys/class/ieee80211/<phyname>/index
* @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
* @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
+ * if HT40 (40 MHz channels) are allowed:
+ * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
+ * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
*
* @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
* @NL80211_ATTR_IFNAME: network interface name
@@ -315,6 +321,8 @@
NL80211_ATTR_BSS_BASIC_RATES,
NL80211_ATTR_WIPHY_TXQ_PARAMS,
+ NL80211_ATTR_WIPHY_FREQ,
+ NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET,
/* add attributes here, update the policy in nl80211.c */
@@ -329,6 +337,8 @@
#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_REG_RULES 32
@@ -742,4 +752,9 @@
NL80211_TXQ_Q_BK
};
+enum nl80211_sec_chan_offset {
+ NL80211_SEC_CHAN_DISABLED /* HT20 only */,
+ NL80211_SEC_CHAN_BELOW /* HT40- */,
+ NL80211_SEC_CHAN_ABOVE /* HT40+ */
+};
#endif /* __LINUX_NL80211_H */
Index: wireless-testing/include/net/cfg80211.h
===================================================================
--- wireless-testing.orig/include/net/cfg80211.h 2008-11-25 18:50:47.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h 2008-11-25 18:52:51.000000000 +0200
@@ -450,6 +450,10 @@
* @change_bss: Modify parameters for a given BSS.
*
* @set_txq_params: Set TX queue parameters
+ *
+ * @set_channel: Set channel (freq = frequency in MHz, sec_chan_offset:
+ * 0 = HT40 disabled; 1 = HT40 enabled, secondary channel above primary;
+ * -1 = HT40 enabled, secondary channel below primary)
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -513,6 +517,9 @@
int (*set_txq_params)(struct wiphy *wiphy,
struct ieee80211_txq_params *params);
+
+ int (*set_channel)(struct wiphy *wiphy, int freq,
+ int sec_chan_offset);
};
#endif /* __NET_CFG80211_H */
Index: wireless-testing/net/mac80211/cfg.c
===================================================================
--- wireless-testing.orig/net/mac80211/cfg.c 2008-11-25 18:53:13.000000000 +0200
+++ wireless-testing/net/mac80211/cfg.c 2008-11-25 20:46:36.000000000 +0200
@@ -1095,6 +1095,22 @@
return 0;
}
+static int ieee80211_set_channel(struct wiphy *wiphy, int freq,
+ int sec_chan_offset)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_channel *chan;
+
+ chan = ieee80211_get_channel(local->hw.wiphy, freq);
+ if (!chan)
+ return -EINVAL;
+
+ local->oper_channel = chan;
+ local->hw.conf.ht.sec_chan_offset = sec_chan_offset;
+
+ return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -1122,4 +1138,5 @@
#endif
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
+ .set_channel = ieee80211_set_channel,
};
Index: wireless-testing/net/wireless/nl80211.c
===================================================================
--- wireless-testing.orig/net/wireless/nl80211.c 2008-11-25 18:55:20.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c 2008-11-25 19:24:03.000000000 +0200
@@ -59,6 +59,8 @@
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
.len = BUS_ID_SIZE-1 },
[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
+ [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U8 },
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -359,6 +361,32 @@
}
}
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ int sec_chan_offset = 0;
+
+ if (!rdev->ops->set_channel) {
+ result = -EOPNOTSUPP;
+ goto bad_res;
+ }
+
+ if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) {
+ u8 val = nla_get_u8(
+ info->attrs[
+ NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]);
+ if (val == NL80211_SEC_CHAN_BELOW)
+ sec_chan_offset = -1;
+ else if (val == NL80211_SEC_CHAN_ABOVE)
+ sec_chan_offset = 1;
+ }
+ result = rdev->ops->set_channel(
+ &rdev->wiphy,
+ nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
+ sec_chan_offset);
+ if (result)
+ goto bad_res;
+ }
+
+
bad_res:
cfg80211_put_dev(rdev);
return result;
Index: wireless-testing/include/net/mac80211.h
===================================================================
--- wireless-testing.orig/include/net/mac80211.h 2008-11-25 19:32:20.000000000 +0200
+++ wireless-testing/include/net/mac80211.h 2008-11-25 19:33:16.000000000 +0200
@@ -507,6 +507,9 @@
struct ieee80211_ht_conf {
bool enabled;
+ int sec_chan_offset; /* 0 = HT40 disabled; -1 = HT40 enabled, secondary
+ * channel below primary; 1 = HT40 enabled,
+ * secondary channel above primary */
};
/**
--
Jouni Malinen PGP id EFC895FA
Johannes Berg wrote:
> On Wed, 2008-11-26 at 10:21 +0530, Sujith wrote:
> > Jouni Malinen wrote:
> > > + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
> > > + * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
> > > + * if HT40 (40 MHz channels) are allowed:
> > > + * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
> > > + * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
> >
> > The driver needs to know if the selected channel is HT or not.
>
> Can you explain what difference that makes? Is it for running the phy in
> pure legacy mode?
Yes, we calibrate the HW differently for HT/legacy.
Also, we have different rate tables for legacy/HT.
For HT20, it can reach 130 Mbps.
Sujith
On Wed, 2008-11-26 at 10:38 +0200, Jouni Malinen wrote:
> On Tue, Nov 25, 2008 at 09:05:33PM +0200, Jouni Malinen wrote:
> > This patch adds new NL80211_CMD_SET_WIPHY attributes
> > NL80211_ATTR_WIPHY_FREQ and NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET to allow
> > userspace to set the operating channel (e.g., hostapd for AP mode).
>
> This version addresses the feedback I received by adding regulatory
> enforcement in net/wireless/nl80211.c and mechanism for indicating
> non-HT vs. HT20. In addition, the ht_enable/sec_chan_offset values are
> now handled similarly to local->oper_channel to avoid changing
> parameters for scan.
Thanks. A few other things that I just thought of:
> @@ -26,8 +26,9 @@
> * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
> * to get a list of all present wiphys.
> * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
> - * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME
> - * and/or %NL80211_ATTR_WIPHY_TXQ_PARAMS.
> + * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
> + * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or
> + * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET.
> * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
> * or rename notification. Has attributes %NL80211_ATTR_WIPHY and
> * %NL80211_ATTR_WIPHY_NAME.
> @@ -180,6 +181,12 @@
> * /sys/class/ieee80211/<phyname>/index
> * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
> * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
> + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
> + * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
> + * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
It's also possible to explicitly give the _NO_HT value too.
> + * NL80211_SEC_CHAN_DISABLED = HT20 only
> + * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
> + * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
> + *
> + * @set_channel: Set channel (freq = frequency in MHz, sec_chan_offset:
> + * 0 = HT40 disabled; 1 = HT40 enabled, secondary channel above primary;
> + * -1 = HT40 enabled, secondary channel below primary)
> */
> struct cfg80211_ops {
> int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
> @@ -513,6 +517,9 @@
>
> int (*set_txq_params)(struct wiphy *wiphy,
> struct ieee80211_txq_params *params);
> +
> + int (*set_channel)(struct wiphy *wiphy, int freq, bool ht_enabled,
> + int sec_chan_offset);
I wonder if we shouldn't simply pass in the enum nl80211_sec_chan_offset
value here, that seems easier to understand when you're looking at the
whole thing from userspace down to a possible non-mac80211 driver. Not
that I think that'll ever happen, but still? It might even make sense to
use that value within mac80211's driver API at some point, instead of
the enabled / +/-1 thing.
> +static int ieee80211_set_channel(struct wiphy *wiphy, int freq,
> + bool ht_enabled, int sec_chan_offset)
> +{
> + struct ieee80211_local *local = wiphy_priv(wiphy);
> + struct ieee80211_channel *chan;
> +
> + chan = ieee80211_get_channel(local->hw.wiphy, freq);
> + if (!chan)
> + return -EINVAL;
> +
> + local->oper_channel = chan;
> + local->oper_ht_enabled = ht_enabled;
> + local->oper_sec_chan_offset = sec_chan_offset;
And you could even store the enum here, and translate it only in
_hw_config.
> + [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
> + [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U8 },
I think it's more "normal" to use a u32 for an enum although I don't
think we'll ever add anything, so I guess it doesn't actually matter.
> + freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
> + chan = ieee80211_get_channel(&rdev->wiphy, freq);
> + result = rdev->ops->set_channel(&rdev->wiphy, freq, ht_enabled,
> + sec_chan_offset);
would it make sense to pass in 'chan'? mac80211 will do the lookup
again, and if a driver doesn't it can just use chan->center_freq.
johannes
Jouni Malinen wrote:
> + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
> + * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
> + * if HT40 (40 MHz channels) are allowed:
> + * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
> + * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
The driver needs to know if the selected channel is HT or not.
It receives only HT20/HT40+/HT40- flags, but a HT/non-HT flag is required too.
Sujith
On Wed, Nov 26, 2008 at 10:21:12AM +0530, Sujith wrote:
> Jouni Malinen wrote:
> > + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
> > + * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
> > + * if HT40 (40 MHz channels) are allowed:
> > + * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
> > + * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
>
> The driver needs to know if the selected channel is HT or not.
> It receives only HT20/HT40+/HT40- flags, but a HT/non-HT flag is required too.
Yes, indeed. I added a new enum value for that:
NL82011_SEC_CHAN_NO_HT = no HT (this is the default if
NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET is not included)
NL80211_SEC_CHAN_DISABLED = HT20 only
NL80211_SEC_CHAN_BELOW = HT40-
NL80211_SEC_CHAN_ABOVE = HT40+
The driver will then get hw.conf.ht.{enabled,sec_chan_offset} with the
needed information.
--
Jouni Malinen PGP id EFC895FA
On Wed, Nov 26, 2008 at 12:04:24PM +0100, Johannes Berg wrote:
> On Wed, 2008-11-26 at 10:38 +0200, Jouni Malinen wrote:
> > + * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
> > + * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
>
> It's also possible to explicitly give the _NO_HT value too.
>
> > + * NL80211_SEC_CHAN_DISABLED = HT20 only
Yes, I did not include in documentation, but I can add it here as
another option for not including the attribute.
> > +
> > + int (*set_channel)(struct wiphy *wiphy, int freq, bool ht_enabled,
> > + int sec_chan_offset);
>
> I wonder if we shouldn't simply pass in the enum nl80211_sec_chan_offset
> value here, that seems easier to understand when you're looking at the
> whole thing from userspace down to a possible non-mac80211 driver. Not
> that I think that'll ever happen, but still? It might even make sense to
> use that value within mac80211's driver API at some point, instead of
> the enabled / +/-1 thing.
I don't care much either way. nl80211.c uses the +/-1 to get the
secondary channel frequency and the driver API does not use it yet, so
conversion is needed somewhere at this point. I can move it somewhere
else if you want to; just point me to the place where you want it ;-).
cfg.c::ieee80211_set_channel()? main.c::ieee80211_hw_config()?
> > + [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
> > + [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U8 },
>
> I think it's more "normal" to use a u32 for an enum although I don't
> think we'll ever add anything, so I guess it doesn't actually matter.
I'm quite sure we won't need more than eight bits to store the possible
options for this attribute, but I can change this to u32 to be
consistent with existing attributes if you prefer it.
> > + freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
> > + chan = ieee80211_get_channel(&rdev->wiphy, freq);
> > + result = rdev->ops->set_channel(&rdev->wiphy, freq, ht_enabled,
> > + sec_chan_offset);
>
> would it make sense to pass in 'chan'? mac80211 will do the lookup
> again, and if a driver doesn't it can just use chan->center_freq.
Now that chan is here in nl80211.c (was added with regulatory
enforcement), sure, it could be passed to set_channel() to remove some
code.
--
Jouni Malinen PGP id EFC895FA
On Wed, 2008-11-26 at 10:21 +0530, Sujith wrote:
> Jouni Malinen wrote:
> > + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
> > + * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
> > + * if HT40 (40 MHz channels) are allowed:
> > + * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
> > + * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
>
> The driver needs to know if the selected channel is HT or not.
Can you explain what difference that makes? Is it for running the phy in
pure legacy mode?
johannes
On Wed, 2008-11-26 at 15:38 +0200, Jouni Malinen wrote:
> On Wed, Nov 26, 2008 at 12:04:24PM +0100, Johannes Berg wrote:
>
> > Thanks. A few other things that I just thought of:
>
> This version adds comment about _NO_HT, moves enum
> nl80211_sec_chan_offset conversion from nl80211.c into
> ieee80211_hw_config, changes enum to use NLA_U32, passes chan structure
> (instead of freq int) into set_channel() handler.
Cool, thanks, and sorry for all the delays.
Acked-by: Johannes Berg <[email protected]>
>
> Index: wireless-testing/include/linux/nl80211.h
> ===================================================================
> --- wireless-testing.orig/include/linux/nl80211.h 2008-11-26 15:15:31.000000000 +0200
> +++ wireless-testing/include/linux/nl80211.h 2008-11-26 15:16:59.000000000 +0200
> @@ -26,8 +26,9 @@
> * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
> * to get a list of all present wiphys.
> * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
> - * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME
> - * and/or %NL80211_ATTR_WIPHY_TXQ_PARAMS.
> + * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
> + * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or
> + * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET.
> * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
> * or rename notification. Has attributes %NL80211_ATTR_WIPHY and
> * %NL80211_ATTR_WIPHY_NAME.
> @@ -180,6 +181,14 @@
> * /sys/class/ieee80211/<phyname>/index
> * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
> * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
> + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
> + * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
> + * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
> + * NL80211_SEC_CHAN_NO_HT = HT not allowed (i.e., same as not including
> + * this attribute)
> + * NL80211_SEC_CHAN_DISABLED = HT20 only
> + * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
> + * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
> *
> * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
> * @NL80211_ATTR_IFNAME: network interface name
> @@ -315,6 +324,8 @@
> NL80211_ATTR_BSS_BASIC_RATES,
>
> NL80211_ATTR_WIPHY_TXQ_PARAMS,
> + NL80211_ATTR_WIPHY_FREQ,
> + NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET,
>
> /* add attributes here, update the policy in nl80211.c */
>
> @@ -329,6 +340,8 @@
> #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
> #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
> #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
> +#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
> +#define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET
>
> #define NL80211_MAX_SUPP_RATES 32
> #define NL80211_MAX_SUPP_REG_RULES 32
> @@ -742,4 +755,10 @@
> NL80211_TXQ_Q_BK
> };
>
> +enum nl80211_sec_chan_offset {
> + NL80211_SEC_CHAN_NO_HT /* No HT */,
> + NL80211_SEC_CHAN_DISABLED /* HT20 only */,
> + NL80211_SEC_CHAN_BELOW /* HT40- */,
> + NL80211_SEC_CHAN_ABOVE /* HT40+ */
> +};
> #endif /* __LINUX_NL80211_H */
> Index: wireless-testing/include/net/cfg80211.h
> ===================================================================
> --- wireless-testing.orig/include/net/cfg80211.h 2008-11-26 15:15:31.000000000 +0200
> +++ wireless-testing/include/net/cfg80211.h 2008-11-26 15:29:50.000000000 +0200
> @@ -392,6 +392,9 @@
> /* from net/wireless.h */
> struct wiphy;
>
> +/* from net/ieee80211.h */
> +struct ieee80211_channel;
> +
> /**
> * struct cfg80211_ops - backend description for wireless configuration
> *
> @@ -450,6 +453,8 @@
> * @change_bss: Modify parameters for a given BSS.
> *
> * @set_txq_params: Set TX queue parameters
> + *
> + * @set_channel: Set channel
> */
> struct cfg80211_ops {
> int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
> @@ -513,6 +518,10 @@
>
> int (*set_txq_params)(struct wiphy *wiphy,
> struct ieee80211_txq_params *params);
> +
> + int (*set_channel)(struct wiphy *wiphy,
> + struct ieee80211_channel *chan,
> + enum nl80211_sec_chan_offset);
> };
>
> #endif /* __NET_CFG80211_H */
> Index: wireless-testing/net/mac80211/cfg.c
> ===================================================================
> --- wireless-testing.orig/net/mac80211/cfg.c 2008-11-26 15:15:31.000000000 +0200
> +++ wireless-testing/net/mac80211/cfg.c 2008-11-26 15:19:34.000000000 +0200
> @@ -1095,6 +1095,18 @@
> return 0;
> }
>
> +static int ieee80211_set_channel(struct wiphy *wiphy,
> + struct ieee80211_channel *chan,
> + enum nl80211_sec_chan_offset sec_chan_offset)
> +{
> + struct ieee80211_local *local = wiphy_priv(wiphy);
> +
> + local->oper_channel = chan;
> + local->oper_sec_chan_offset = sec_chan_offset;
> +
> + return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
> +}
> +
> struct cfg80211_ops mac80211_config_ops = {
> .add_virtual_intf = ieee80211_add_iface,
> .del_virtual_intf = ieee80211_del_iface,
> @@ -1122,4 +1134,5 @@
> #endif
> .change_bss = ieee80211_change_bss,
> .set_txq_params = ieee80211_set_txq_params,
> + .set_channel = ieee80211_set_channel,
> };
> Index: wireless-testing/net/wireless/nl80211.c
> ===================================================================
> --- wireless-testing.orig/net/wireless/nl80211.c 2008-11-26 15:15:31.000000000 +0200
> +++ wireless-testing/net/wireless/nl80211.c 2008-11-26 15:31:31.000000000 +0200
> @@ -59,6 +59,8 @@
> [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
> .len = BUS_ID_SIZE-1 },
> [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
> + [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
> + [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U32 },
>
> [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
> [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
> @@ -359,6 +361,61 @@
> }
> }
>
> + if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
> + enum nl80211_sec_chan_offset sec_chan_offset =
> + NL80211_SEC_CHAN_NO_HT;
> + struct ieee80211_channel *chan;
> + u32 freq, sec_freq;
> +
> + if (!rdev->ops->set_channel) {
> + result = -EOPNOTSUPP;
> + goto bad_res;
> + }
> +
> + if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) {
> + sec_chan_offset = nla_get_u32(
> + info->attrs[
> + NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]);
> + if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT &&
> + sec_chan_offset != NL80211_SEC_CHAN_DISABLED &&
> + sec_chan_offset != NL80211_SEC_CHAN_BELOW &&
> + sec_chan_offset != NL80211_SEC_CHAN_ABOVE) {
> + result = -EINVAL;
> + goto bad_res;
> + }
> + }
> +
> + freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
> + chan = ieee80211_get_channel(&rdev->wiphy, freq);
> + if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
> + /* Primary channel not allowed */
> + result = -EINVAL;
> + goto bad_res;
> + }
> + if (sec_chan_offset == NL80211_SEC_CHAN_BELOW)
> + sec_freq = freq - 20;
> + else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE)
> + sec_freq = freq + 20;
> + else
> + sec_freq = 0;
> +
> + if (sec_freq) {
> + struct ieee80211_channel *schan;
> + schan = ieee80211_get_channel(&rdev->wiphy, sec_freq);
> + if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) {
> + /* Secondary channel not allowed */
> + result = -EINVAL;
> + goto bad_res;
> + }
> + }
> +
> + result = rdev->ops->set_channel(&rdev->wiphy, chan,
> + sec_chan_offset);
> + if (result)
> + goto bad_res;
> + }
> +
> +
> bad_res:
> cfg80211_put_dev(rdev);
> return result;
> Index: wireless-testing/include/net/mac80211.h
> ===================================================================
> --- wireless-testing.orig/include/net/mac80211.h 2008-11-26 15:15:31.000000000 +0200
> +++ wireless-testing/include/net/mac80211.h 2008-11-26 15:15:47.000000000 +0200
> @@ -507,6 +507,9 @@
>
> struct ieee80211_ht_conf {
> bool enabled;
> + int sec_chan_offset; /* 0 = HT40 disabled; -1 = HT40 enabled, secondary
> + * channel below primary; 1 = HT40 enabled,
> + * secondary channel above primary */
> };
>
> /**
> Index: wireless-testing/net/mac80211/util.c
> ===================================================================
> --- wireless-testing.orig/net/mac80211/util.c 2008-11-26 15:15:31.000000000 +0200
> +++ wireless-testing/net/mac80211/util.c 2008-11-26 15:20:26.000000000 +0200
> @@ -641,6 +641,7 @@
> chan->flags & IEEE80211_CHAN_NO_IBSS)
> return ret;
> local->oper_channel = chan;
> + local->oper_sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
>
> if (local->sw_scanning || local->hw_scanning)
> ret = 0;
> Index: wireless-testing/net/mac80211/ieee80211_i.h
> ===================================================================
> --- wireless-testing.orig/net/mac80211/ieee80211_i.h 2008-11-26 15:15:31.000000000 +0200
> +++ wireless-testing/net/mac80211/ieee80211_i.h 2008-11-26 15:20:12.000000000 +0200
> @@ -626,6 +626,7 @@
> struct delayed_work scan_work;
> struct ieee80211_sub_if_data *scan_sdata;
> struct ieee80211_channel *oper_channel, *scan_channel;
> + enum nl80211_sec_chan_offset oper_sec_chan_offset;
> u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
> size_t scan_ssid_len;
> struct list_head bss_list;
> Index: wireless-testing/net/mac80211/main.c
> ===================================================================
> --- wireless-testing.orig/net/mac80211/main.c 2008-11-26 15:15:31.000000000 +0200
> +++ wireless-testing/net/mac80211/main.c 2008-11-26 15:29:09.000000000 +0200
> @@ -195,20 +195,42 @@
> struct ieee80211_channel *chan;
> int ret = 0;
> int power;
> + enum nl80211_sec_chan_offset sec_chan_offset;
>
> might_sleep();
>
> - if (local->sw_scanning)
> + if (local->sw_scanning) {
> chan = local->scan_channel;
> - else
> + sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
> + } else {
> chan = local->oper_channel;
> + sec_chan_offset = local->oper_sec_chan_offset;
> + }
>
> - if (chan != local->hw.conf.channel) {
> + if (chan != local->hw.conf.channel ||
> + sec_chan_offset != local->hw.conf.ht.sec_chan_offset) {
> local->hw.conf.channel = chan;
> + switch (sec_chan_offset) {
> + case NL80211_SEC_CHAN_NO_HT:
> + local->hw.conf.ht.enabled = false;
> + local->hw.conf.ht.sec_chan_offset = 0;
> + break;
> + case NL80211_SEC_CHAN_DISABLED:
> + local->hw.conf.ht.enabled = true;
> + local->hw.conf.ht.sec_chan_offset = 0;
> + break;
> + case NL80211_SEC_CHAN_BELOW:
> + local->hw.conf.ht.enabled = true;
> + local->hw.conf.ht.sec_chan_offset = -1;
> + break;
> + case NL80211_SEC_CHAN_ABOVE:
> + local->hw.conf.ht.enabled = true;
> + local->hw.conf.ht.sec_chan_offset = 1;
> + break;
> + }
> changed |= IEEE80211_CONF_CHANGE_CHANNEL;
> }
>
> -
> if (!local->hw.conf.power_level)
> power = chan->max_power;
> else
On Tue, Nov 25, 2008 at 08:13:04PM +0100, Johannes Berg wrote:
> Isn't that missing regulatory enforcement? I'd rather see that in
> cfg80211 than re-implemented in all drivers.
Yes, that was supposed to be in ieee80211_get_channel() to match
ieee80211_set_freq() functionality, but I'll see how this could be done
in nl80211.c.
--
Jouni Malinen PGP id EFC895FA
On Tue, Nov 25, 2008 at 09:05:33PM +0200, Jouni Malinen wrote:
> This patch adds new NL80211_CMD_SET_WIPHY attributes
> NL80211_ATTR_WIPHY_FREQ and NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET to allow
> userspace to set the operating channel (e.g., hostapd for AP mode).
This version addresses the feedback I received by adding regulatory
enforcement in net/wireless/nl80211.c and mechanism for indicating
non-HT vs. HT20. In addition, the ht_enable/sec_chan_offset values are
now handled similarly to local->oper_channel to avoid changing
parameters for scan.
Index: wireless-testing/include/linux/nl80211.h
===================================================================
--- wireless-testing.orig/include/linux/nl80211.h 2008-11-26 09:28:51.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h 2008-11-26 09:36:01.000000000 +0200
@@ -26,8 +26,9 @@
* @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
- * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME
- * and/or %NL80211_ATTR_WIPHY_TXQ_PARAMS.
+ * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or
+ * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@@ -180,6 +181,12 @@
* /sys/class/ieee80211/<phyname>/index
* @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
* @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
+ * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ * NL80211_SEC_CHAN_DISABLED = HT20 only
+ * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
+ * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
*
* @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
* @NL80211_ATTR_IFNAME: network interface name
@@ -315,6 +322,8 @@
NL80211_ATTR_BSS_BASIC_RATES,
NL80211_ATTR_WIPHY_TXQ_PARAMS,
+ NL80211_ATTR_WIPHY_FREQ,
+ NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET,
/* add attributes here, update the policy in nl80211.c */
@@ -329,6 +338,8 @@
#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_REG_RULES 32
@@ -742,4 +753,10 @@
NL80211_TXQ_Q_BK
};
+enum nl80211_sec_chan_offset {
+ NL80211_SEC_CHAN_NO_HT /* No HT */,
+ NL80211_SEC_CHAN_DISABLED /* HT20 only */,
+ NL80211_SEC_CHAN_BELOW /* HT40- */,
+ NL80211_SEC_CHAN_ABOVE /* HT40+ */
+};
#endif /* __LINUX_NL80211_H */
Index: wireless-testing/include/net/cfg80211.h
===================================================================
--- wireless-testing.orig/include/net/cfg80211.h 2008-11-26 09:28:51.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h 2008-11-26 09:38:12.000000000 +0200
@@ -450,6 +450,10 @@
* @change_bss: Modify parameters for a given BSS.
*
* @set_txq_params: Set TX queue parameters
+ *
+ * @set_channel: Set channel (freq = frequency in MHz, sec_chan_offset:
+ * 0 = HT40 disabled; 1 = HT40 enabled, secondary channel above primary;
+ * -1 = HT40 enabled, secondary channel below primary)
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -513,6 +517,9 @@
int (*set_txq_params)(struct wiphy *wiphy,
struct ieee80211_txq_params *params);
+
+ int (*set_channel)(struct wiphy *wiphy, int freq, bool ht_enabled,
+ int sec_chan_offset);
};
#endif /* __NET_CFG80211_H */
Index: wireless-testing/net/mac80211/cfg.c
===================================================================
--- wireless-testing.orig/net/mac80211/cfg.c 2008-11-26 09:28:52.000000000 +0200
+++ wireless-testing/net/mac80211/cfg.c 2008-11-26 10:12:04.000000000 +0200
@@ -1095,6 +1095,23 @@
return 0;
}
+static int ieee80211_set_channel(struct wiphy *wiphy, int freq,
+ bool ht_enabled, int sec_chan_offset)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_channel *chan;
+
+ chan = ieee80211_get_channel(local->hw.wiphy, freq);
+ if (!chan)
+ return -EINVAL;
+
+ local->oper_channel = chan;
+ local->oper_ht_enabled = ht_enabled;
+ local->oper_sec_chan_offset = sec_chan_offset;
+
+ return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -1122,4 +1139,5 @@
#endif
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
+ .set_channel = ieee80211_set_channel,
};
Index: wireless-testing/net/wireless/nl80211.c
===================================================================
--- wireless-testing.orig/net/wireless/nl80211.c 2008-11-26 09:28:52.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c 2008-11-26 10:25:36.000000000 +0200
@@ -59,6 +59,8 @@
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
.len = BUS_ID_SIZE-1 },
[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
+ [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U8 },
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -359,6 +361,60 @@
}
}
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ int sec_chan_offset = 0;
+ bool ht_enabled = false;
+ struct ieee80211_channel *chan;
+ u32 freq;
+
+ if (!rdev->ops->set_channel) {
+ result = -EOPNOTSUPP;
+ goto bad_res;
+ }
+
+ if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) {
+ u8 val = nla_get_u8(
+ info->attrs[
+ NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]);
+ switch (val) {
+ case NL80211_SEC_CHAN_BELOW:
+ ht_enabled = true;
+ sec_chan_offset = -1;
+ break;
+ case NL80211_SEC_CHAN_ABOVE:
+ ht_enabled = true;
+ sec_chan_offset = 1;
+ break;
+ case NL80211_SEC_CHAN_DISABLED:
+ ht_enabled = true;
+ break;
+ }
+ }
+
+ freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+ chan = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
+ /* Primary channel not allowed */
+ result = -EINVAL;
+ goto bad_res;
+ }
+ if (sec_chan_offset) {
+ chan = ieee80211_get_channel(
+ &rdev->wiphy, freq + sec_chan_offset * 20);
+ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
+ /* Secondary channel not allowed */
+ result = -EINVAL;
+ goto bad_res;
+ }
+ }
+
+ result = rdev->ops->set_channel(&rdev->wiphy, freq, ht_enabled,
+ sec_chan_offset);
+ if (result)
+ goto bad_res;
+ }
+
+
bad_res:
cfg80211_put_dev(rdev);
return result;
Index: wireless-testing/include/net/mac80211.h
===================================================================
--- wireless-testing.orig/include/net/mac80211.h 2008-11-26 09:28:52.000000000 +0200
+++ wireless-testing/include/net/mac80211.h 2008-11-26 09:28:54.000000000 +0200
@@ -507,6 +507,9 @@
struct ieee80211_ht_conf {
bool enabled;
+ int sec_chan_offset; /* 0 = HT40 disabled; -1 = HT40 enabled, secondary
+ * channel below primary; 1 = HT40 enabled,
+ * secondary channel above primary */
};
/**
Index: wireless-testing/net/mac80211/util.c
===================================================================
--- wireless-testing.orig/net/mac80211/util.c 2008-11-26 10:00:57.000000000 +0200
+++ wireless-testing/net/mac80211/util.c 2008-11-26 10:09:01.000000000 +0200
@@ -641,6 +641,8 @@
chan->flags & IEEE80211_CHAN_NO_IBSS)
return ret;
local->oper_channel = chan;
+ local->oper_ht_enabled = false;
+ local->oper_sec_chan_offset = 0;
if (local->sw_scanning || local->hw_scanning)
ret = 0;
Index: wireless-testing/net/mac80211/ieee80211_i.h
===================================================================
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2008-11-26 10:12:16.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h 2008-11-26 10:12:34.000000000 +0200
@@ -626,6 +626,8 @@
struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata;
struct ieee80211_channel *oper_channel, *scan_channel;
+ bool oper_ht_enabled;
+ int oper_sec_chan_offset;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
struct list_head bss_list;
Index: wireless-testing/net/mac80211/main.c
===================================================================
--- wireless-testing.orig/net/mac80211/main.c 2008-11-26 10:09:09.000000000 +0200
+++ wireless-testing/net/mac80211/main.c 2008-11-26 10:11:49.000000000 +0200
@@ -195,20 +195,30 @@
struct ieee80211_channel *chan;
int ret = 0;
int power;
+ bool ht_enabled;
+ int sec_chan_offset;
might_sleep();
- if (local->sw_scanning)
+ if (local->sw_scanning) {
chan = local->scan_channel;
- else
+ ht_enabled = false;
+ sec_chan_offset = 0;
+ } else {
chan = local->oper_channel;
+ ht_enabled = local->oper_ht_enabled;
+ sec_chan_offset = local->oper_sec_chan_offset;
+ }
- if (chan != local->hw.conf.channel) {
+ if (chan != local->hw.conf.channel ||
+ ht_enabled != local->hw.conf.ht.enabled ||
+ sec_chan_offset != local->hw.conf.ht.sec_chan_offset) {
local->hw.conf.channel = chan;
+ local->hw.conf.ht.enabled = ht_enabled;
+ local->hw.conf.ht.sec_chan_offset = sec_chan_offset;
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
}
-
if (!local->hw.conf.power_level)
power = chan->max_power;
else
--
Jouni Malinen PGP id EFC895FA
Jouni Malinen wrote:
> On Wed, Nov 26, 2008 at 10:21:12AM +0530, Sujith wrote:
> > Jouni Malinen wrote:
> > > + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
> > > + * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
> > > + * if HT40 (40 MHz channels) are allowed:
> > > + * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
> > > + * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
> >
> > The driver needs to know if the selected channel is HT or not.
> > It receives only HT20/HT40+/HT40- flags, but a HT/non-HT flag is required too.
>
> Yes, indeed. I added a new enum value for that:
> NL82011_SEC_CHAN_NO_HT = no HT (this is the default if
> NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET is not included)
> NL80211_SEC_CHAN_DISABLED = HT20 only
> NL80211_SEC_CHAN_BELOW = HT40-
> NL80211_SEC_CHAN_ABOVE = HT40+
>
> The driver will then get hw.conf.ht.{enabled,sec_chan_offset} with the
> needed information.
That will work, thanks.
Sujith
On Wed, Nov 26, 2008 at 12:04:24PM +0100, Johannes Berg wrote:
> Thanks. A few other things that I just thought of:
This version adds comment about _NO_HT, moves enum
nl80211_sec_chan_offset conversion from nl80211.c into
ieee80211_hw_config, changes enum to use NLA_U32, passes chan structure
(instead of freq int) into set_channel() handler.
Index: wireless-testing/include/linux/nl80211.h
===================================================================
--- wireless-testing.orig/include/linux/nl80211.h 2008-11-26 15:15:31.000000000 +0200
+++ wireless-testing/include/linux/nl80211.h 2008-11-26 15:16:59.000000000 +0200
@@ -26,8 +26,9 @@
* @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
* to get a list of all present wiphys.
* @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
- * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME
- * and/or %NL80211_ATTR_WIPHY_TXQ_PARAMS.
+ * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or
+ * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET.
* @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
* or rename notification. Has attributes %NL80211_ATTR_WIPHY and
* %NL80211_ATTR_WIPHY_NAME.
@@ -180,6 +181,14 @@
* /sys/class/ieee80211/<phyname>/index
* @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
* @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET: included with NL80211_ATTR_WIPHY_FREQ
+ * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ * NL80211_SEC_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ * this attribute)
+ * NL80211_SEC_CHAN_DISABLED = HT20 only
+ * NL80211_SEC_CHAN_BELOW = secondary channel is below the primary channel
+ * NL80211_SEC_CHAN_ABOVE = secondary channel is above the primary channel
*
* @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
* @NL80211_ATTR_IFNAME: network interface name
@@ -315,6 +324,8 @@
NL80211_ATTR_BSS_BASIC_RATES,
NL80211_ATTR_WIPHY_TXQ_PARAMS,
+ NL80211_ATTR_WIPHY_FREQ,
+ NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET,
/* add attributes here, update the policy in nl80211.c */
@@ -329,6 +340,8 @@
#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_REG_RULES 32
@@ -742,4 +755,10 @@
NL80211_TXQ_Q_BK
};
+enum nl80211_sec_chan_offset {
+ NL80211_SEC_CHAN_NO_HT /* No HT */,
+ NL80211_SEC_CHAN_DISABLED /* HT20 only */,
+ NL80211_SEC_CHAN_BELOW /* HT40- */,
+ NL80211_SEC_CHAN_ABOVE /* HT40+ */
+};
#endif /* __LINUX_NL80211_H */
Index: wireless-testing/include/net/cfg80211.h
===================================================================
--- wireless-testing.orig/include/net/cfg80211.h 2008-11-26 15:15:31.000000000 +0200
+++ wireless-testing/include/net/cfg80211.h 2008-11-26 15:29:50.000000000 +0200
@@ -392,6 +392,9 @@
/* from net/wireless.h */
struct wiphy;
+/* from net/ieee80211.h */
+struct ieee80211_channel;
+
/**
* struct cfg80211_ops - backend description for wireless configuration
*
@@ -450,6 +453,8 @@
* @change_bss: Modify parameters for a given BSS.
*
* @set_txq_params: Set TX queue parameters
+ *
+ * @set_channel: Set channel
*/
struct cfg80211_ops {
int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
@@ -513,6 +518,10 @@
int (*set_txq_params)(struct wiphy *wiphy,
struct ieee80211_txq_params *params);
+
+ int (*set_channel)(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_sec_chan_offset);
};
#endif /* __NET_CFG80211_H */
Index: wireless-testing/net/mac80211/cfg.c
===================================================================
--- wireless-testing.orig/net/mac80211/cfg.c 2008-11-26 15:15:31.000000000 +0200
+++ wireless-testing/net/mac80211/cfg.c 2008-11-26 15:19:34.000000000 +0200
@@ -1095,6 +1095,18 @@
return 0;
}
+static int ieee80211_set_channel(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_sec_chan_offset sec_chan_offset)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ local->oper_channel = chan;
+ local->oper_sec_chan_offset = sec_chan_offset;
+
+ return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -1122,4 +1134,5 @@
#endif
.change_bss = ieee80211_change_bss,
.set_txq_params = ieee80211_set_txq_params,
+ .set_channel = ieee80211_set_channel,
};
Index: wireless-testing/net/wireless/nl80211.c
===================================================================
--- wireless-testing.orig/net/wireless/nl80211.c 2008-11-26 15:15:31.000000000 +0200
+++ wireless-testing/net/wireless/nl80211.c 2008-11-26 15:31:31.000000000 +0200
@@ -59,6 +59,8 @@
[NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
.len = BUS_ID_SIZE-1 },
[NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
+ [NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET] = { .type = NLA_U32 },
[NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
[NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
@@ -359,6 +361,61 @@
}
}
+ if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
+ enum nl80211_sec_chan_offset sec_chan_offset =
+ NL80211_SEC_CHAN_NO_HT;
+ struct ieee80211_channel *chan;
+ u32 freq, sec_freq;
+
+ if (!rdev->ops->set_channel) {
+ result = -EOPNOTSUPP;
+ goto bad_res;
+ }
+
+ if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) {
+ sec_chan_offset = nla_get_u32(
+ info->attrs[
+ NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]);
+ if (sec_chan_offset != NL80211_SEC_CHAN_NO_HT &&
+ sec_chan_offset != NL80211_SEC_CHAN_DISABLED &&
+ sec_chan_offset != NL80211_SEC_CHAN_BELOW &&
+ sec_chan_offset != NL80211_SEC_CHAN_ABOVE) {
+ result = -EINVAL;
+ goto bad_res;
+ }
+ }
+
+ freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+ chan = ieee80211_get_channel(&rdev->wiphy, freq);
+ if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
+ /* Primary channel not allowed */
+ result = -EINVAL;
+ goto bad_res;
+ }
+ if (sec_chan_offset == NL80211_SEC_CHAN_BELOW)
+ sec_freq = freq - 20;
+ else if (sec_chan_offset == NL80211_SEC_CHAN_ABOVE)
+ sec_freq = freq + 20;
+ else
+ sec_freq = 0;
+
+ if (sec_freq) {
+ struct ieee80211_channel *schan;
+ schan = ieee80211_get_channel(&rdev->wiphy, sec_freq);
+ if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) {
+ /* Secondary channel not allowed */
+ result = -EINVAL;
+ goto bad_res;
+ }
+ }
+
+ result = rdev->ops->set_channel(&rdev->wiphy, chan,
+ sec_chan_offset);
+ if (result)
+ goto bad_res;
+ }
+
+
bad_res:
cfg80211_put_dev(rdev);
return result;
Index: wireless-testing/include/net/mac80211.h
===================================================================
--- wireless-testing.orig/include/net/mac80211.h 2008-11-26 15:15:31.000000000 +0200
+++ wireless-testing/include/net/mac80211.h 2008-11-26 15:15:47.000000000 +0200
@@ -507,6 +507,9 @@
struct ieee80211_ht_conf {
bool enabled;
+ int sec_chan_offset; /* 0 = HT40 disabled; -1 = HT40 enabled, secondary
+ * channel below primary; 1 = HT40 enabled,
+ * secondary channel above primary */
};
/**
Index: wireless-testing/net/mac80211/util.c
===================================================================
--- wireless-testing.orig/net/mac80211/util.c 2008-11-26 15:15:31.000000000 +0200
+++ wireless-testing/net/mac80211/util.c 2008-11-26 15:20:26.000000000 +0200
@@ -641,6 +641,7 @@
chan->flags & IEEE80211_CHAN_NO_IBSS)
return ret;
local->oper_channel = chan;
+ local->oper_sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
if (local->sw_scanning || local->hw_scanning)
ret = 0;
Index: wireless-testing/net/mac80211/ieee80211_i.h
===================================================================
--- wireless-testing.orig/net/mac80211/ieee80211_i.h 2008-11-26 15:15:31.000000000 +0200
+++ wireless-testing/net/mac80211/ieee80211_i.h 2008-11-26 15:20:12.000000000 +0200
@@ -626,6 +626,7 @@
struct delayed_work scan_work;
struct ieee80211_sub_if_data *scan_sdata;
struct ieee80211_channel *oper_channel, *scan_channel;
+ enum nl80211_sec_chan_offset oper_sec_chan_offset;
u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
size_t scan_ssid_len;
struct list_head bss_list;
Index: wireless-testing/net/mac80211/main.c
===================================================================
--- wireless-testing.orig/net/mac80211/main.c 2008-11-26 15:15:31.000000000 +0200
+++ wireless-testing/net/mac80211/main.c 2008-11-26 15:29:09.000000000 +0200
@@ -195,20 +195,42 @@
struct ieee80211_channel *chan;
int ret = 0;
int power;
+ enum nl80211_sec_chan_offset sec_chan_offset;
might_sleep();
- if (local->sw_scanning)
+ if (local->sw_scanning) {
chan = local->scan_channel;
- else
+ sec_chan_offset = NL80211_SEC_CHAN_NO_HT;
+ } else {
chan = local->oper_channel;
+ sec_chan_offset = local->oper_sec_chan_offset;
+ }
- if (chan != local->hw.conf.channel) {
+ if (chan != local->hw.conf.channel ||
+ sec_chan_offset != local->hw.conf.ht.sec_chan_offset) {
local->hw.conf.channel = chan;
+ switch (sec_chan_offset) {
+ case NL80211_SEC_CHAN_NO_HT:
+ local->hw.conf.ht.enabled = false;
+ local->hw.conf.ht.sec_chan_offset = 0;
+ break;
+ case NL80211_SEC_CHAN_DISABLED:
+ local->hw.conf.ht.enabled = true;
+ local->hw.conf.ht.sec_chan_offset = 0;
+ break;
+ case NL80211_SEC_CHAN_BELOW:
+ local->hw.conf.ht.enabled = true;
+ local->hw.conf.ht.sec_chan_offset = -1;
+ break;
+ case NL80211_SEC_CHAN_ABOVE:
+ local->hw.conf.ht.enabled = true;
+ local->hw.conf.ht.sec_chan_offset = 1;
+ break;
+ }
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
}
-
if (!local->hw.conf.power_level)
power = chan->max_power;
else
--
Jouni Malinen PGP id EFC895FA
On Tue, 2008-11-25 at 21:05 +0200, Jouni Malinen wrote:
> + if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
> + int sec_chan_offset = 0;
> +
> + if (!rdev->ops->set_channel) {
> + result = -EOPNOTSUPP;
> + goto bad_res;
> + }
> +
> + if (info->attrs[NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]) {
> + u8 val = nla_get_u8(
> + info->attrs[
> + NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET]);
> + if (val == NL80211_SEC_CHAN_BELOW)
> + sec_chan_offset = -1;
> + else if (val == NL80211_SEC_CHAN_ABOVE)
> + sec_chan_offset = 1;
> + }
> + result = rdev->ops->set_channel(
> + &rdev->wiphy,
> + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
> + sec_chan_offset);
Isn't that missing regulatory enforcement? I'd rather see that in
cfg80211 than re-implemented in all drivers.
johannes