aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-11-08 17:14:50 -0500
committerJohannes Berg <johannes.berg@intel.com>2012-11-26 06:42:59 -0500
commit3d9d1d6656a73ea8407734cfb00b81d14ef62d4b (patch)
tree74f8b3b4acd0b91068ebebbfaa00aaef1f7e097e
parent683b6d3b31a51956ea540df00abb0b78894924c1 (diff)
nl80211/cfg80211: support VHT channel configuration
Change nl80211 to support specifying a VHT (or HT) using the control channel frequency (as before) and new attributes for the channel width and first and second center frequency. The old channel type is of course still supported for HT. Also change the cfg80211 channel definition struct to support these by adding the relevant fields to it (and removing the _type field.) This also adds new helper functions: - cfg80211_chandef_create to create a channel def struct given the control channel and channel type, - cfg80211_chandef_identical to check if two channel definitions are identical - cfg80211_chandef_compatible to check if the given channel definitions are compatible, and return the wider of the two This isn't entirely complete, but that doesn't matter until we have a driver using it. In particular, it's missing - regulatory checks on the usable bandwidth (if that even makes sense) - regulatory TX power (database can't deal with it) - a proper channel compatibility calculation for the new channel types Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c10
-rw-r--r--include/net/cfg80211.h73
-rw-r--r--include/uapi/linux/nl80211.h61
-rw-r--r--net/mac80211/cfg.c5
-rw-r--r--net/mac80211/ibss.c13
-rw-r--r--net/wireless/chan.c249
-rw-r--r--net/wireless/core.h6
-rw-r--r--net/wireless/ibss.c4
-rw-r--r--net/wireless/mesh.c4
-rw-r--r--net/wireless/nl80211.c160
-rw-r--r--net/wireless/trace.h28
-rw-r--r--net/wireless/wext-compat.c4
-rw-r--r--net/wireless/wext-sme.c3
13 files changed, 507 insertions, 113 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index c0cc2e59fe6..51bbe85c574 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1099,12 +1099,10 @@ void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
1099 "channel switch notify nw_type %d freq %d mode %d\n", 1099 "channel switch notify nw_type %d freq %d mode %d\n",
1100 vif->nw_type, freq, mode); 1100 vif->nw_type, freq, mode);
1101 1101
1102 chandef.chan = ieee80211_get_channel(vif->ar->wiphy, freq); 1102 cfg80211_chandef_create(&chandef,
1103 if (WARN_ON(!chandef.chan)) 1103 ieee80211_get_channel(vif->ar->wiphy, freq),
1104 return; 1104 (mode == WMI_11G_HT20) ?
1105 1105 NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
1106 chandef._type = (mode == WMI_11G_HT20) ?
1107 NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
1108 1106
1109 cfg80211_ch_switch_notify(vif->ndev, &chandef); 1107 cfg80211_ch_switch_notify(vif->ndev, &chandef);
1110} 1108}
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 86f777af79e..977da58fb7e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -308,21 +308,86 @@ struct key_params {
308/** 308/**
309 * struct cfg80211_chan_def - channel definition 309 * struct cfg80211_chan_def - channel definition
310 * @chan: the (control) channel 310 * @chan: the (control) channel
311 * @_type: the channel type, don't use this field, 311 * @width: channel width
312 * use cfg80211_get_chandef_type() if needed. 312 * @center_freq1: center frequency of first segment
313 * @center_freq2: center frequency of second segment
314 * (only with 80+80 MHz)
313 */ 315 */
314struct cfg80211_chan_def { 316struct cfg80211_chan_def {
315 struct ieee80211_channel *chan; 317 struct ieee80211_channel *chan;
316 enum nl80211_channel_type _type; 318 enum nl80211_chan_width width;
319 u32 center_freq1;
320 u32 center_freq2;
317}; 321};
318 322
323/**
324 * cfg80211_get_chandef_type - return old channel type from chandef
325 * @chandef: the channel definition
326 *
327 * Returns the old channel type (NOHT, HT20, HT40+/-) from a given
328 * chandef, which must have a bandwidth allowing this conversion.
329 */
319static inline enum nl80211_channel_type 330static inline enum nl80211_channel_type
320cfg80211_get_chandef_type(const struct cfg80211_chan_def *chandef) 331cfg80211_get_chandef_type(const struct cfg80211_chan_def *chandef)
321{ 332{
322 return chandef->_type; 333 switch (chandef->width) {
334 case NL80211_CHAN_WIDTH_20_NOHT:
335 return NL80211_CHAN_NO_HT;
336 case NL80211_CHAN_WIDTH_20:
337 return NL80211_CHAN_HT20;
338 case NL80211_CHAN_WIDTH_40:
339 if (chandef->center_freq1 > chandef->chan->center_freq)
340 return NL80211_CHAN_HT40PLUS;
341 return NL80211_CHAN_HT40MINUS;
342 default:
343 WARN_ON(1);
344 return NL80211_CHAN_NO_HT;
345 }
346}
347
348/**
349 * cfg80211_chandef_create - create channel definition using channel type
350 * @chandef: the channel definition struct to fill
351 * @channel: the control channel
352 * @chantype: the channel type
353 *
354 * Given a channel type, create a channel definition.
355 */
356void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
357 struct ieee80211_channel *channel,
358 enum nl80211_channel_type chantype);
359
360/**
361 * cfg80211_chandef_identical - check if two channel definitions are identical
362 * @chandef1: first channel definition
363 * @chandef2: second channel definition
364 *
365 * Returns %true if the channels defined by the channel definitions are
366 * identical, %false otherwise.
367 */
368static inline bool
369cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
370 const struct cfg80211_chan_def *chandef2)
371{
372 return (chandef1->chan == chandef2->chan &&
373 chandef1->width == chandef2->width &&
374 chandef1->center_freq1 == chandef2->center_freq1 &&
375 chandef1->center_freq2 == chandef2->center_freq2);
323} 376}
324 377
325/** 378/**
379 * cfg80211_chandef_compatible - check if two channel definitions are compatible
380 * @chandef1: first channel definition
381 * @chandef2: second channel definition
382 *
383 * Returns %NULL if the given channel definitions are incompatible,
384 * chandef1 or chandef2 otherwise.
385 */
386const struct cfg80211_chan_def *
387cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
388 const struct cfg80211_chan_def *chandef2);
389
390/**
326 * enum survey_info_flags - survey information flags 391 * enum survey_info_flags - survey information flags
327 * 392 *
328 * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in 393 * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 82b5ad38435..84f9c7d84c6 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -118,8 +118,9 @@
118 * to get a list of all present wiphys. 118 * to get a list of all present wiphys.
119 * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or 119 * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
120 * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, 120 * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
121 * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, 121 * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
122 * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT, 122 * attributes determining the channel width; this is used for setting
123 * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT,
123 * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, 124 * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
124 * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD. 125 * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
125 * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL 126 * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
@@ -171,7 +172,7 @@
171 * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY, 172 * %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
172 * %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT. 173 * %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
173 * The channel to use can be set on the interface or be given using the 174 * The channel to use can be set on the interface or be given using the
174 * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs. 175 * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
175 * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP 176 * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
176 * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface 177 * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
177 * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP 178 * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
@@ -471,8 +472,8 @@
471 * command is used as an event to indicate the that a trigger level was 472 * command is used as an event to indicate the that a trigger level was
472 * reached. 473 * reached.
473 * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ 474 * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
474 * and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed 475 * and the attributes determining channel width) the given interface
475 * by %NL80211_ATTR_IFINDEX) shall operate on. 476 * (identifed by %NL80211_ATTR_IFINDEX) shall operate on.
476 * In case multiple channels are supported by the device, the mechanism 477 * In case multiple channels are supported by the device, the mechanism
477 * with which it switches channels is implementation-defined. 478 * with which it switches channels is implementation-defined.
478 * When a monitor interface is given, it can only switch channel while 479 * When a monitor interface is given, it can only switch channel while
@@ -566,8 +567,8 @@
566 * 567 *
567 * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels 568 * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
568 * independently of the userspace SME, send this event indicating 569 * independently of the userspace SME, send this event indicating
569 * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with 570 * %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
570 * %NL80211_ATTR_WIPHY_CHANNEL_TYPE. 571 * attributes determining channel width.
571 * 572 *
572 * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by 573 * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
573 * its %NL80211_ATTR_WDEV identifier. It must have been created with 574 * its %NL80211_ATTR_WDEV identifier. It must have been created with
@@ -771,14 +772,26 @@ enum nl80211_commands {
771 * /sys/class/ieee80211/<phyname>/index 772 * /sys/class/ieee80211/<phyname>/index
772 * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) 773 * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
773 * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters 774 * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
774 * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz 775 * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz,
776 * defines the channel together with the (deprecated)
777 * %NL80211_ATTR_WIPHY_CHANNEL_TYPE attribute or the attributes
778 * %NL80211_ATTR_CHANNEL_WIDTH and if needed %NL80211_ATTR_CENTER_FREQ1
779 * and %NL80211_ATTR_CENTER_FREQ2
780 * @NL80211_ATTR_CHANNEL_WIDTH: u32 attribute containing one of the values
781 * of &enum nl80211_chan_width, describing the channel width. See the
782 * documentation of the enum for more information.
783 * @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
784 * channel, used for anything but 20 MHz bandwidth
785 * @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
786 * channel, used only for 80+80 MHz bandwidth
775 * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ 787 * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
776 * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): 788 * if HT20 or HT40 are to be used (i.e., HT disabled if not included):
777 * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including 789 * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
778 * this attribute) 790 * this attribute)
779 * NL80211_CHAN_HT20 = HT20 only 791 * NL80211_CHAN_HT20 = HT20 only
780 * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel 792 * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
781 * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel 793 * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
794 * This attribute is now deprecated.
782 * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is 795 * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
783 * less than or equal to the RTS threshold; allowed range: 1..255; 796 * less than or equal to the RTS threshold; allowed range: 1..255;
784 * dot11ShortRetryLimit; u8 797 * dot11ShortRetryLimit; u8
@@ -1553,6 +1566,10 @@ enum nl80211_attrs {
1553 1566
1554 NL80211_ATTR_SCAN_FLAGS, 1567 NL80211_ATTR_SCAN_FLAGS,
1555 1568
1569 NL80211_ATTR_CHANNEL_WIDTH,
1570 NL80211_ATTR_CENTER_FREQ1,
1571 NL80211_ATTR_CENTER_FREQ2,
1572
1556 /* add attributes here, update the policy in nl80211.c */ 1573 /* add attributes here, update the policy in nl80211.c */
1557 1574
1558 __NL80211_ATTR_AFTER_LAST, 1575 __NL80211_ATTR_AFTER_LAST,
@@ -2455,6 +2472,32 @@ enum nl80211_channel_type {
2455}; 2472};
2456 2473
2457/** 2474/**
2475 * enum nl80211_chan_width - channel width definitions
2476 *
2477 * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH
2478 * attribute.
2479 *
2480 * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel
2481 * @NL80211_CHAN_WIDTH_20: 20 MHz HT channel
2482 * @NL80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
2483 * attribute must be provided as well
2484 * @NL80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
2485 * attribute must be provided as well
2486 * @NL80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
2487 * and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
2488 * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
2489 * attribute must be provided as well
2490 */
2491enum nl80211_chan_width {
2492 NL80211_CHAN_WIDTH_20_NOHT,
2493 NL80211_CHAN_WIDTH_20,
2494 NL80211_CHAN_WIDTH_40,
2495 NL80211_CHAN_WIDTH_80,
2496 NL80211_CHAN_WIDTH_80P80,
2497 NL80211_CHAN_WIDTH_160,
2498};
2499
2500/**
2458 * enum nl80211_bss - netlink attributes for a BSS 2501 * enum nl80211_bss - netlink attributes for a BSS
2459 * 2502 *
2460 * @__NL80211_BSS_INVALID: invalid 2503 * @__NL80211_BSS_INVALID: invalid
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fbb2d072cb9..7136b945798 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3125,8 +3125,9 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
3125 rcu_read_lock(); 3125 rcu_read_lock();
3126 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); 3126 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
3127 if (chanctx_conf) { 3127 if (chanctx_conf) {
3128 chandef->chan = chanctx_conf->channel; 3128 cfg80211_chandef_create(chandef,
3129 chandef->_type = chanctx_conf->channel_type; 3129 chanctx_conf->channel,
3130 chanctx_conf->channel_type);
3130 ret = 0; 3131 ret = 0;
3131 } 3132 }
3132 rcu_read_unlock(); 3133 rcu_read_unlock();
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index bed616fd97e..5648bbed240 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -52,6 +52,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
52 u32 bss_change; 52 u32 bss_change;
53 u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; 53 u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
54 struct cfg80211_chan_def chandef; 54 struct cfg80211_chan_def chandef;
55 enum nl80211_channel_type chan_type;
55 56
56 lockdep_assert_held(&ifibss->mtx); 57 lockdep_assert_held(&ifibss->mtx);
57 58
@@ -79,13 +80,13 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
79 80
80 sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; 81 sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
81 82
82 chandef.chan = chan; 83 chan_type = ifibss->channel_type;
83 chandef._type = ifibss->channel_type; 84 cfg80211_chandef_create(&chandef, chan, chan_type);
84 if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) 85 if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef))
85 chandef._type = NL80211_CHAN_HT20; 86 chan_type = NL80211_CHAN_HT20;
86 87
87 ieee80211_vif_release_channel(sdata); 88 ieee80211_vif_release_channel(sdata);
88 if (ieee80211_vif_use_channel(sdata, chan, chandef._type, 89 if (ieee80211_vif_use_channel(sdata, chan, chan_type,
89 ifibss->fixed_channel ? 90 ifibss->fixed_channel ?
90 IEEE80211_CHANCTX_SHARED : 91 IEEE80211_CHANCTX_SHARED :
91 IEEE80211_CHANCTX_EXCLUSIVE)) { 92 IEEE80211_CHANCTX_EXCLUSIVE)) {
@@ -159,7 +160,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
159 ifibss->ie, ifibss->ie_len); 160 ifibss->ie, ifibss->ie_len);
160 161
161 /* add HT capability and information IEs */ 162 /* add HT capability and information IEs */
162 if (chandef._type != NL80211_CHAN_NO_HT && 163 if (chan_type != NL80211_CHAN_NO_HT &&
163 sband->ht_cap.ht_supported) { 164 sband->ht_cap.ht_supported) {
164 pos = skb_put(skb, 4 + 165 pos = skb_put(skb, 4 +
165 sizeof(struct ieee80211_ht_cap) + 166 sizeof(struct ieee80211_ht_cap) +
@@ -172,7 +173,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
172 * keep them at 0 173 * keep them at 0
173 */ 174 */
174 pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, 175 pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
175 chan, chandef._type, 0); 176 chan, chan_type, 0);
176 } 177 }
177 178
178 if (local->hw.queues >= IEEE80211_NUM_ACS) { 179 if (local->hw.queues >= IEEE80211_NUM_ACS) {
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index e834422de40..bf2dfd54ff3 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -11,43 +11,252 @@
11#include "core.h" 11#include "core.h"
12#include "rdev-ops.h" 12#include "rdev-ops.h"
13 13
14bool cfg80211_reg_can_beacon(struct wiphy *wiphy, 14void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
15 struct cfg80211_chan_def *chandef) 15 struct ieee80211_channel *chan,
16 enum nl80211_channel_type chan_type)
16{ 17{
17 struct ieee80211_channel *sec_chan; 18 if (WARN_ON(!chan))
18 int diff; 19 return;
19 20
20 trace_cfg80211_reg_can_beacon(wiphy, chandef); 21 chandef->chan = chan;
22 chandef->center_freq2 = 0;
21 23
22 switch (chandef->_type) { 24 switch (chan_type) {
25 case NL80211_CHAN_NO_HT:
26 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
27 chandef->center_freq1 = chan->center_freq;
28 break;
29 case NL80211_CHAN_HT20:
30 chandef->width = NL80211_CHAN_WIDTH_20;
31 chandef->center_freq1 = chan->center_freq;
32 break;
23 case NL80211_CHAN_HT40PLUS: 33 case NL80211_CHAN_HT40PLUS:
24 diff = 20; 34 chandef->width = NL80211_CHAN_WIDTH_40;
35 chandef->center_freq1 = chan->center_freq + 10;
25 break; 36 break;
26 case NL80211_CHAN_HT40MINUS: 37 case NL80211_CHAN_HT40MINUS:
27 diff = -20; 38 chandef->width = NL80211_CHAN_WIDTH_40;
39 chandef->center_freq1 = chan->center_freq - 10;
40 break;
41 default:
42 WARN_ON(1);
43 }
44}
45EXPORT_SYMBOL(cfg80211_chandef_create);
46
47bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef)
48{
49 u32 control_freq;
50
51 if (!chandef->chan)
52 return false;
53
54 control_freq = chandef->chan->center_freq;
55
56 switch (chandef->width) {
57 case NL80211_CHAN_WIDTH_20:
58 case NL80211_CHAN_WIDTH_20_NOHT:
59 if (chandef->center_freq1 != control_freq)
60 return false;
61 if (chandef->center_freq2)
62 return false;
63 break;
64 case NL80211_CHAN_WIDTH_40:
65 if (chandef->center_freq1 != control_freq + 10 &&
66 chandef->center_freq1 != control_freq - 10)
67 return false;
68 if (chandef->center_freq2)
69 return false;
70 break;
71 case NL80211_CHAN_WIDTH_80P80:
72 if (chandef->center_freq1 != control_freq + 30 &&
73 chandef->center_freq1 != control_freq + 10 &&
74 chandef->center_freq1 != control_freq - 10 &&
75 chandef->center_freq1 != control_freq - 30)
76 return false;
77 if (!chandef->center_freq2)
78 return false;
79 break;
80 case NL80211_CHAN_WIDTH_80:
81 if (chandef->center_freq1 != control_freq + 30 &&
82 chandef->center_freq1 != control_freq + 10 &&
83 chandef->center_freq1 != control_freq - 10 &&
84 chandef->center_freq1 != control_freq - 30)
85 return false;
86 if (chandef->center_freq2)
87 return false;
88 break;
89 case NL80211_CHAN_WIDTH_160:
90 if (chandef->center_freq1 != control_freq + 70 &&
91 chandef->center_freq1 != control_freq + 50 &&
92 chandef->center_freq1 != control_freq + 30 &&
93 chandef->center_freq1 != control_freq + 10 &&
94 chandef->center_freq1 != control_freq - 10 &&
95 chandef->center_freq1 != control_freq - 30 &&
96 chandef->center_freq1 != control_freq - 50 &&
97 chandef->center_freq1 != control_freq - 70)
98 return false;
99 if (chandef->center_freq2)
100 return false;
101 break;
102 default:
103 return false;
104 }
105
106 return true;
107}
108
109static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
110 int *pri40, int *pri80)
111{
112 int tmp;
113
114 switch (c->width) {
115 case NL80211_CHAN_WIDTH_40:
116 *pri40 = c->center_freq1;
117 *pri80 = 0;
118 break;
119 case NL80211_CHAN_WIDTH_80:
120 case NL80211_CHAN_WIDTH_80P80:
121 *pri80 = c->center_freq1;
122 /* n_P20 */
123 tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
124 /* n_P40 */
125 tmp /= 2;
126 /* freq_P40 */
127 *pri40 = c->center_freq1 - 20 + 40 * tmp;
128 break;
129 case NL80211_CHAN_WIDTH_160:
130 /* n_P20 */
131 tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
132 /* n_P40 */
133 tmp /= 2;
134 /* freq_P40 */
135 *pri40 = c->center_freq1 - 60 + 40 * tmp;
136 /* n_P80 */
137 tmp /= 2;
138 *pri80 = c->center_freq1 - 40 + 80 * tmp;
28 break; 139 break;
29 default: 140 default:
30 trace_cfg80211_return_bool(true); 141 WARN_ON_ONCE(1);
31 return true;
32 } 142 }
143}
144
145const struct cfg80211_chan_def *
146cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
147 const struct cfg80211_chan_def *c2)
148{
149 u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
33 150
34 sec_chan = ieee80211_get_channel(wiphy, 151 /* If they are identical, return */
35 chandef->chan->center_freq + diff); 152 if (cfg80211_chandef_identical(c1, c2))
36 if (!sec_chan) { 153 return c1;
154
155 /* otherwise, must have same control channel */
156 if (c1->chan != c2->chan)
157 return NULL;
158
159 /*
160 * If they have the same width, but aren't identical,
161 * then they can't be compatible.
162 */
163 if (c1->width == c2->width)
164 return NULL;
165
166 if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
167 c1->width == NL80211_CHAN_WIDTH_20)
168 return c2;
169
170 if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
171 c2->width == NL80211_CHAN_WIDTH_20)
172 return c1;
173
174 chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
175 chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
176
177 if (c1_pri40 != c2_pri40)
178 return NULL;
179
180 WARN_ON(!c1_pri80 && !c2_pri80);
181 if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
182 return NULL;
183
184 if (c1->width > c2->width)
185 return c1;
186 return c2;
187}
188EXPORT_SYMBOL(cfg80211_chandef_compatible);
189
190bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
191 u32 center_freq, u32 bandwidth,
192 u32 prohibited_flags)
193{
194 struct ieee80211_channel *c;
195 u32 freq;
196
197 for (freq = center_freq - bandwidth/2 + 10;
198 freq <= center_freq + bandwidth/2 - 10;
199 freq += 20) {
200 c = ieee80211_get_channel(wiphy, freq);
201 if (!c || c->flags & prohibited_flags)
202 return false;
203 }
204
205 return true;
206}
207
208static bool cfg80211_check_beacon_chans(struct wiphy *wiphy,
209 u32 center_freq, u32 bw)
210{
211 return cfg80211_secondary_chans_ok(wiphy, center_freq, bw,
212 IEEE80211_CHAN_DISABLED |
213 IEEE80211_CHAN_PASSIVE_SCAN |
214 IEEE80211_CHAN_NO_IBSS |
215 IEEE80211_CHAN_RADAR);
216}
217
218bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
219 struct cfg80211_chan_def *chandef)
220{
221 u32 width;
222 bool res;
223
224 trace_cfg80211_reg_can_beacon(wiphy, chandef);
225
226 if (WARN_ON(!cfg80211_chan_def_valid(chandef))) {
37 trace_cfg80211_return_bool(false); 227 trace_cfg80211_return_bool(false);
38 return false; 228 return false;
39 } 229 }
40 230
41 /* we'll need a DFS capability later */ 231 switch (chandef->width) {
42 if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | 232 case NL80211_CHAN_WIDTH_20_NOHT:
43 IEEE80211_CHAN_PASSIVE_SCAN | 233 case NL80211_CHAN_WIDTH_20:
44 IEEE80211_CHAN_NO_IBSS | 234 width = 20;
45 IEEE80211_CHAN_RADAR)) { 235 break;
236 case NL80211_CHAN_WIDTH_40:
237 width = 40;
238 break;
239 case NL80211_CHAN_WIDTH_80:
240 case NL80211_CHAN_WIDTH_80P80:
241 width = 80;
242 break;
243 case NL80211_CHAN_WIDTH_160:
244 width = 160;
245 break;
246 default:
247 WARN_ON_ONCE(1);
46 trace_cfg80211_return_bool(false); 248 trace_cfg80211_return_bool(false);
47 return false; 249 return false;
48 } 250 }
49 trace_cfg80211_return_bool(true); 251
50 return true; 252 res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width);
253
254 if (res && chandef->center_freq2)
255 res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2,
256 width);
257
258 trace_cfg80211_return_bool(res);
259 return res;
51} 260}
52EXPORT_SYMBOL(cfg80211_reg_can_beacon); 261EXPORT_SYMBOL(cfg80211_reg_can_beacon);
53 262
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 6183a0d25b8..a0c8decf6a4 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -483,6 +483,12 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
483void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, 483void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
484 enum nl80211_iftype iftype, int num); 484 enum nl80211_iftype iftype, int num);
485 485
486bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef);
487
488bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
489 u32 center_freq, u32 bandwidth,
490 u32 prohibited_flags);
491
486#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 492#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
487 493
488#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS 494#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index ccc8865dfad..9b9551e4a6f 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -252,7 +252,7 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
252 252
253 /* try to find an IBSS channel if none requested ... */ 253 /* try to find an IBSS channel if none requested ... */
254 if (!wdev->wext.ibss.chandef.chan) { 254 if (!wdev->wext.ibss.chandef.chan) {
255 wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT; 255 wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
256 256
257 for (band = 0; band < IEEE80211_NUM_BANDS; band++) { 257 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
258 struct ieee80211_supported_band *sband; 258 struct ieee80211_supported_band *sband;
@@ -352,7 +352,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
352 352
353 if (chan) { 353 if (chan) {
354 wdev->wext.ibss.chandef.chan = chan; 354 wdev->wext.ibss.chandef.chan = chan;
355 wdev->wext.ibss.chandef._type = NL80211_CHAN_NO_HT; 355 wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
356 wdev->wext.ibss.channel_fixed = true; 356 wdev->wext.ibss.channel_fixed = true;
357 } else { 357 } else {
358 /* cfg80211_ibss_wext_join will pick one if needed */ 358 /* cfg80211_ibss_wext_join will pick one if needed */
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 12b5a570a30..3ee5a728228 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -146,7 +146,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
146 if (!setup->chandef.chan) 146 if (!setup->chandef.chan)
147 return -EINVAL; 147 return -EINVAL;
148 148
149 setup->chandef._type = NL80211_CHAN_NO_HT; 149 setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;;
150 } 150 }
151 151
152 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) 152 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
@@ -198,7 +198,7 @@ int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
198 * compatible with 802.11 mesh. 198 * compatible with 802.11 mesh.
199 */ 199 */
200 if (rdev->ops->libertas_set_mesh_channel) { 200 if (rdev->ops->libertas_set_mesh_channel) {
201 if (chandef->_type != NL80211_CHAN_NO_HT) 201 if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
202 return -EINVAL; 202 return -EINVAL;
203 203
204 if (!netif_running(wdev->netdev)) 204 if (!netif_running(wdev->netdev))
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 999108cd947..15158a3d64a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -223,8 +223,13 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
223 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, 223 [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
224 .len = 20-1 }, 224 .len = 20-1 },
225 [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, 225 [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
226
226 [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, 227 [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
227 [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, 228 [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
229 [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
230 [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
231 [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
232
228 [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 }, 233 [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 },
229 [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 }, 234 [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
230 [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 }, 235 [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
@@ -1360,35 +1365,13 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
1360 wdev->iftype == NL80211_IFTYPE_P2P_GO; 1365 wdev->iftype == NL80211_IFTYPE_P2P_GO;
1361} 1366}
1362 1367
1363static bool nl80211_valid_channel_type(struct genl_info *info,
1364 enum nl80211_channel_type *channel_type)
1365{
1366 enum nl80211_channel_type tmp;
1367
1368 if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
1369 return false;
1370
1371 tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1372 if (tmp != NL80211_CHAN_NO_HT &&
1373 tmp != NL80211_CHAN_HT20 &&
1374 tmp != NL80211_CHAN_HT40PLUS &&
1375 tmp != NL80211_CHAN_HT40MINUS)
1376 return false;
1377
1378 if (channel_type)
1379 *channel_type = tmp;
1380
1381 return true;
1382}
1383
1384static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, 1368static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
1385 struct genl_info *info, 1369 struct genl_info *info,
1386 struct cfg80211_chan_def *chandef) 1370 struct cfg80211_chan_def *chandef)
1387{ 1371{
1388 struct ieee80211_sta_ht_cap *ht_cap; 1372 struct ieee80211_sta_ht_cap *ht_cap;
1389 struct ieee80211_channel *sc; 1373 struct ieee80211_sta_vht_cap *vht_cap;
1390 u32 control_freq; 1374 u32 control_freq, width;
1391 int offs;
1392 1375
1393 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) 1376 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
1394 return -EINVAL; 1377 return -EINVAL;
@@ -1396,47 +1379,105 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
1396 control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); 1379 control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
1397 1380
1398 chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq); 1381 chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
1399 chandef->_type = NL80211_CHAN_NO_HT; 1382 chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
1400 1383 chandef->center_freq1 = control_freq;
1401 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && 1384 chandef->center_freq2 = 0;
1402 !nl80211_valid_channel_type(info, &chandef->_type))
1403 return -EINVAL;
1404 1385
1405 /* Primary channel not allowed */ 1386 /* Primary channel not allowed */
1406 if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) 1387 if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
1407 return -EINVAL; 1388 return -EINVAL;
1408 1389
1390 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
1391 enum nl80211_channel_type chantype;
1392
1393 chantype = nla_get_u32(
1394 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
1395
1396 switch (chantype) {
1397 case NL80211_CHAN_NO_HT:
1398 case NL80211_CHAN_HT20:
1399 case NL80211_CHAN_HT40PLUS:
1400 case NL80211_CHAN_HT40MINUS:
1401 cfg80211_chandef_create(chandef, chandef->chan,
1402 chantype);
1403 break;
1404 default:
1405 return -EINVAL;
1406 }
1407 } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
1408 chandef->width =
1409 nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
1410 if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
1411 chandef->center_freq1 =
1412 nla_get_u32(
1413 info->attrs[NL80211_ATTR_CENTER_FREQ1]);
1414 if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
1415 chandef->center_freq2 =
1416 nla_get_u32(
1417 info->attrs[NL80211_ATTR_CENTER_FREQ2]);
1418 }
1419
1409 ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; 1420 ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap;
1421 vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap;
1410 1422
1411 switch (chandef->_type) { 1423 if (!cfg80211_chan_def_valid(chandef))
1412 case NL80211_CHAN_NO_HT: 1424 return -EINVAL;
1425
1426 switch (chandef->width) {
1427 case NL80211_CHAN_WIDTH_20:
1428 if (!ht_cap->ht_supported)
1429 return -EINVAL;
1430 case NL80211_CHAN_WIDTH_20_NOHT:
1431 width = 20;
1413 break; 1432 break;
1414 case NL80211_CHAN_HT40MINUS: 1433 case NL80211_CHAN_WIDTH_40:
1415 if (chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS) 1434 width = 40;
1435 /* quick early regulatory check */
1436 if (chandef->center_freq1 < control_freq &&
1437 chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
1438 return -EINVAL;
1439 if (chandef->center_freq1 > control_freq &&
1440 chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
1441 return -EINVAL;
1442 if (!ht_cap->ht_supported)
1416 return -EINVAL; 1443 return -EINVAL;
1417 offs = -20;
1418 /* fall through */
1419 case NL80211_CHAN_HT40PLUS:
1420 if (chandef->_type == NL80211_CHAN_HT40PLUS) {
1421 if (chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
1422 return -EINVAL;
1423 offs = 20;
1424 }
1425 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || 1444 if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
1426 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) 1445 ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
1427 return -EINVAL; 1446 return -EINVAL;
1428 1447 break;
1429 sc = ieee80211_get_channel(&rdev->wiphy, 1448 case NL80211_CHAN_WIDTH_80:
1430 chandef->chan->center_freq + offs); 1449 width = 80;
1431 if (!sc || sc->flags & IEEE80211_CHAN_DISABLED) 1450 if (!vht_cap->vht_supported)
1432 return -EINVAL; 1451 return -EINVAL;
1433 /* fall through */ 1452 break;
1434 case NL80211_CHAN_HT20: 1453 case NL80211_CHAN_WIDTH_80P80:
1435 if (!ht_cap->ht_supported) 1454 width = 80;
1455 if (!vht_cap->vht_supported)
1456 return -EINVAL;
1457 if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
1458 return -EINVAL;
1459 break;
1460 case NL80211_CHAN_WIDTH_160:
1461 width = 160;
1462 if (!vht_cap->vht_supported)
1463 return -EINVAL;
1464 if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
1436 return -EINVAL; 1465 return -EINVAL;
1437 break; 1466 break;
1467 default:
1468 return -EINVAL;
1438 } 1469 }
1439 1470
1471 if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1,
1472 width, IEEE80211_CHAN_DISABLED))
1473 return -EINVAL;
1474 if (chandef->center_freq2 &&
1475 !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2,
1476 width, IEEE80211_CHAN_DISABLED))
1477 return -EINVAL;
1478
1479 /* TODO: missing regulatory check on bandwidth */
1480
1440 return 0; 1481 return 0;
1441} 1482}
1442 1483
@@ -1800,10 +1841,28 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
1800static int nl80211_send_chandef(struct sk_buff *msg, 1841static int nl80211_send_chandef(struct sk_buff *msg,
1801 struct cfg80211_chan_def *chandef) 1842 struct cfg80211_chan_def *chandef)
1802{ 1843{
1844 WARN_ON(!cfg80211_chan_def_valid(chandef));
1845
1803 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, 1846 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
1804 chandef->chan->center_freq)) 1847 chandef->chan->center_freq))
1805 return -ENOBUFS; 1848 return -ENOBUFS;
1806 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, chandef->_type)) 1849 switch (chandef->width) {
1850 case NL80211_CHAN_WIDTH_20_NOHT:
1851 case NL80211_CHAN_WIDTH_20:
1852 case NL80211_CHAN_WIDTH_40:
1853 if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
1854 cfg80211_get_chandef_type(chandef)))
1855 return -ENOBUFS;
1856 break;
1857 default:
1858 break;
1859 }
1860 if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
1861 return -ENOBUFS;
1862 if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
1863 return -ENOBUFS;
1864 if (chandef->center_freq2 &&
1865 nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
1807 return -ENOBUFS; 1866 return -ENOBUFS;
1808 return 0; 1867 return 0;
1809} 1868}
@@ -5447,7 +5506,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
5447 if (IS_ERR(connkeys)) 5506 if (IS_ERR(connkeys))
5448 return PTR_ERR(connkeys); 5507 return PTR_ERR(connkeys);
5449 5508
5450 if ((ibss.chandef._type != NL80211_CHAN_NO_HT) && no_ht) { 5509 if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
5510 no_ht) {
5451 kfree(connkeys); 5511 kfree(connkeys);
5452 return -EINVAL; 5512 return -EINVAL;
5453 } 5513 }
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 1370d52b139..3c7aa122156 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -126,25 +126,33 @@
126#define CHAN_PR_FMT ", band: %d, freq: %u" 126#define CHAN_PR_FMT ", band: %d, freq: %u"
127#define CHAN_PR_ARG __entry->band, __entry->center_freq 127#define CHAN_PR_ARG __entry->band, __entry->center_freq
128 128
129#define CHAN_DEF_ENTRY __field(enum ieee80211_band, band) \ 129#define CHAN_DEF_ENTRY __field(enum ieee80211_band, band) \
130 __field(u16, center_freq) \ 130 __field(u32, control_freq) \
131 __field(u32, channel_type) 131 __field(u32, width) \
132 __field(u32, center_freq1) \
133 __field(u32, center_freq2)
132#define CHAN_DEF_ASSIGN(chandef) \ 134#define CHAN_DEF_ASSIGN(chandef) \
133 do { \ 135 do { \
134 if ((chandef) && (chandef)->chan) { \ 136 if ((chandef) && (chandef)->chan) { \
135 __entry->band = (chandef)->chan->band; \ 137 __entry->band = (chandef)->chan->band; \
136 __entry->center_freq = \ 138 __entry->control_freq = \
137 (chandef)->chan->center_freq; \ 139 (chandef)->chan->center_freq; \
138 __entry->channel_type = (chandef)->_type; \ 140 __entry->width = (chandef)->width; \
141 __entry->center_freq1 = (chandef)->center_freq1;\
142 __entry->center_freq2 = (chandef)->center_freq2;\
139 } else { \ 143 } else { \
140 __entry->band = 0; \ 144 __entry->band = 0; \
141 __entry->center_freq = 0; \ 145 __entry->control_freq = 0; \
142 __entry->channel_type = 0; \ 146 __entry->width = 0; \
147 __entry->center_freq1 = 0; \
148 __entry->center_freq2 = 0; \
143 } \ 149 } \
144 } while (0) 150 } while (0)
145#define CHAN_DEF_PR_FMT ", band: %d, freq: %u, chantype: %d" 151#define CHAN_DEF_PR_FMT \
146#define CHAN_DEF_PR_ARG __entry->band, __entry->center_freq, \ 152 ", band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u"
147 __entry->channel_type 153#define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq, \
154 __entry->width, __entry->center_freq1, \
155 __entry->center_freq2
148 156
149#define SINFO_ENTRY __field(int, generation) \ 157#define SINFO_ENTRY __field(int, generation) \
150 __field(u32, connected_time) \ 158 __field(u32, connected_time) \
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index da3307f3236..f9680c9cf9b 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -785,7 +785,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
785 struct wireless_dev *wdev = dev->ieee80211_ptr; 785 struct wireless_dev *wdev = dev->ieee80211_ptr;
786 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 786 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
787 struct cfg80211_chan_def chandef = { 787 struct cfg80211_chan_def chandef = {
788 ._type = NL80211_CHAN_NO_HT, 788 .width = NL80211_CHAN_WIDTH_20_NOHT,
789 }; 789 };
790 int freq, err; 790 int freq, err;
791 791
@@ -800,6 +800,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
800 return freq; 800 return freq;
801 if (freq == 0) 801 if (freq == 0)
802 return -EINVAL; 802 return -EINVAL;
803 chandef.center_freq1 = freq;
803 chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); 804 chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
804 if (!chandef.chan) 805 if (!chandef.chan)
805 return -EINVAL; 806 return -EINVAL;
@@ -813,6 +814,7 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
813 return freq; 814 return freq;
814 if (freq == 0) 815 if (freq == 0)
815 return -EINVAL; 816 return -EINVAL;
817 chandef.center_freq1 = freq;
816 chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); 818 chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
817 if (!chandef.chan) 819 if (!chandef.chan)
818 return -EINVAL; 820 return -EINVAL;
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index e6e5dbf2f61..873af63187c 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -120,7 +120,8 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
120 */ 120 */
121 if (chan && !wdev->wext.connect.ssid_len) { 121 if (chan && !wdev->wext.connect.ssid_len) {
122 struct cfg80211_chan_def chandef = { 122 struct cfg80211_chan_def chandef = {
123 ._type = NL80211_CHAN_NO_HT, 123 .width = NL80211_CHAN_WIDTH_20_NOHT,
124 .center_freq1 = freq,
124 }; 125 };
125 126
126 chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq); 127 chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);