diff options
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/cfg80211.c | 10 | ||||
-rw-r--r-- | include/net/cfg80211.h | 73 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 61 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 5 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 13 | ||||
-rw-r--r-- | net/wireless/chan.c | 249 | ||||
-rw-r--r-- | net/wireless/core.h | 6 | ||||
-rw-r--r-- | net/wireless/ibss.c | 4 | ||||
-rw-r--r-- | net/wireless/mesh.c | 4 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 160 | ||||
-rw-r--r-- | net/wireless/trace.h | 28 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 4 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 3 |
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 | */ |
314 | struct cfg80211_chan_def { | 316 | struct 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 | */ | ||
319 | static inline enum nl80211_channel_type | 330 | static inline enum nl80211_channel_type |
320 | cfg80211_get_chandef_type(const struct cfg80211_chan_def *chandef) | 331 | cfg80211_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 | */ | ||
356 | void 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 | */ | ||
368 | static inline bool | ||
369 | cfg80211_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 | */ | ||
386 | const struct cfg80211_chan_def * | ||
387 | cfg80211_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 | */ | ||
2491 | enum 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 | ||
14 | bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | 14 | void 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 | } | ||
45 | EXPORT_SYMBOL(cfg80211_chandef_create); | ||
46 | |||
47 | bool 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 | |||
109 | static 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 | |||
145 | const struct cfg80211_chan_def * | ||
146 | cfg80211_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 | } | ||
188 | EXPORT_SYMBOL(cfg80211_chandef_compatible); | ||
189 | |||
190 | bool 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 | |||
208 | static 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 | |||
218 | bool 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 | } |
52 | EXPORT_SYMBOL(cfg80211_reg_can_beacon); | 261 | EXPORT_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, | |||
483 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | 483 | void 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 | ||
486 | bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef); | ||
487 | |||
488 | bool 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 | ||
1363 | static 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 | |||
1384 | static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, | 1368 | static 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) | |||
1800 | static int nl80211_send_chandef(struct sk_buff *msg, | 1841 | static 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); |