aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 c0cc2e59fe6c..51bbe85c574c 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 86f777af79e8..977da58fb7ea 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 82b5ad38435b..84f9c7d84c69 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 fbb2d072cb9e..7136b945798e 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 bed616fd97e9..5648bbed240b 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 e834422de40a..bf2dfd54ff3b 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 6183a0d25b8b..a0c8decf6a47 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 ccc8865dfadb..9b9551e4a6f9 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 12b5a570a306..3ee5a7282283 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 999108cd947c..15158a3d64a3 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 1370d52b1393..3c7aa1221563 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 da3307f32362..f9680c9cf9b3 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 e6e5dbf2f616..873af63187c0 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);