p54spi: Lock fixes
[openwrt/svn-archive/archive.git] / package / mac80211 / patches / 300-pending_work.patch
1 --- a/include/net/cfg80211.h
2 +++ b/include/net/cfg80211.h
3 @@ -1122,6 +1122,7 @@ struct cfg80211_ibss_params {
4 u8 *ssid;
5 u8 *bssid;
6 struct ieee80211_channel *channel;
7 + enum nl80211_channel_type channel_type;
8 u8 *ie;
9 u8 ssid_len, ie_len;
10 u16 beacon_interval;
11 @@ -3188,6 +3189,16 @@ void cfg80211_gtk_rekey_notify(struct ne
12 void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
13 const u8 *bssid, bool preauth, gfp_t gfp);
14
15 +/**
16 + * cfg80211_can_use_ext_chan - test if ht40 on extension channel can be used
17 + * @wiphy: the wiphy
18 + * @chan: main channel
19 + * @channel_type: HT mode
20 + */
21 +bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
22 + struct ieee80211_channel *chan,
23 + enum nl80211_channel_type channel_type);
24 +
25 /* Logging, debugging and troubleshooting/diagnostic helpers. */
26
27 /* wiphy_printk helpers, similar to dev_printk */
28 --- a/net/mac80211/agg-rx.c
29 +++ b/net/mac80211/agg-rx.c
30 @@ -180,6 +180,10 @@ static void ieee80211_send_addba_resp(st
31 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
32 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
33 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
34 + else if (sdata->vif.type == NL80211_IFTYPE_WDS)
35 + memcpy(mgmt->bssid, da, ETH_ALEN);
36 + else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
37 + memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
38
39 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
40 IEEE80211_STYPE_ACTION);
41 --- a/net/mac80211/agg-tx.c
42 +++ b/net/mac80211/agg-tx.c
43 @@ -77,10 +77,13 @@ static void ieee80211_send_addba_request
44 memcpy(mgmt->da, da, ETH_ALEN);
45 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
46 if (sdata->vif.type == NL80211_IFTYPE_AP ||
47 - sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
48 + sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
49 + sdata->vif.type == NL80211_IFTYPE_WDS)
50 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
51 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
52 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
53 + else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
54 + memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
55
56 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
57 IEEE80211_STYPE_ACTION);
58 @@ -397,7 +400,9 @@ int ieee80211_start_tx_ba_session(struct
59 */
60 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
61 sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
62 - sdata->vif.type != NL80211_IFTYPE_AP)
63 + sdata->vif.type != NL80211_IFTYPE_AP &&
64 + sdata->vif.type != NL80211_IFTYPE_ADHOC &&
65 + sdata->vif.type != NL80211_IFTYPE_WDS)
66 return -EINVAL;
67
68 if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
69 --- a/net/mac80211/debugfs_sta.c
70 +++ b/net/mac80211/debugfs_sta.c
71 @@ -63,11 +63,11 @@ static ssize_t sta_flags_read(struct fil
72 test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
73
74 int res = scnprintf(buf, sizeof(buf),
75 - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
76 + "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
77 TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
78 TEST(PS_DRIVER), TEST(AUTHORIZED),
79 TEST(SHORT_PREAMBLE), TEST(ASSOC_AP),
80 - TEST(WME), TEST(WDS), TEST(CLEAR_PS_FILT),
81 + TEST(WME), TEST(CLEAR_PS_FILT),
82 TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
83 TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
84 TEST(TDLS_PEER_AUTH));
85 --- a/net/mac80211/ht.c
86 +++ b/net/mac80211/ht.c
87 @@ -199,6 +199,8 @@ void ieee80211_send_delba(struct ieee802
88 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
89 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
90 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
91 + else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
92 + memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
93
94 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
95 IEEE80211_STYPE_ACTION);
96 --- a/net/mac80211/ibss.c
97 +++ b/net/mac80211/ibss.c
98 @@ -77,6 +77,7 @@ static void __ieee80211_sta_join_ibss(st
99 struct cfg80211_bss *bss;
100 u32 bss_change;
101 u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
102 + enum nl80211_channel_type channel_type;
103
104 lockdep_assert_held(&ifibss->mtx);
105
106 @@ -104,8 +105,16 @@ static void __ieee80211_sta_join_ibss(st
107
108 sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
109
110 - local->oper_channel = chan;
111 - WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
112 + channel_type = ifibss->channel_type;
113 + if (channel_type > NL80211_CHAN_HT20 &&
114 + !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
115 + channel_type = NL80211_CHAN_HT20;
116 + if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
117 + /* can only fail due to HT40+/- mismatch */
118 + channel_type = NL80211_CHAN_HT20;
119 + WARN_ON(!ieee80211_set_channel_type(local, sdata,
120 + NL80211_CHAN_HT20));
121 + }
122 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
123
124 sband = local->hw.wiphy->bands[chan->band];
125 @@ -171,6 +180,18 @@ static void __ieee80211_sta_join_ibss(st
126 memcpy(skb_put(skb, ifibss->ie_len),
127 ifibss->ie, ifibss->ie_len);
128
129 + /* add HT capability and information IEs */
130 + if (channel_type && sband->ht_cap.ht_supported) {
131 + pos = skb_put(skb, 4 +
132 + sizeof(struct ieee80211_ht_cap) +
133 + sizeof(struct ieee80211_ht_info));
134 + pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
135 + pos = ieee80211_ie_build_ht_info(pos,
136 + &sband->ht_cap,
137 + chan,
138 + channel_type);
139 + }
140 +
141 if (local->hw.queues >= 4) {
142 pos = skb_put(skb, 9);
143 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
144 @@ -194,6 +215,7 @@ static void __ieee80211_sta_join_ibss(st
145 bss_change |= BSS_CHANGED_BEACON;
146 bss_change |= BSS_CHANGED_BEACON_ENABLED;
147 bss_change |= BSS_CHANGED_BASIC_RATES;
148 + bss_change |= BSS_CHANGED_HT;
149 bss_change |= BSS_CHANGED_IBSS;
150 sdata->vif.bss_conf.ibss_joined = true;
151 ieee80211_bss_info_change_notify(sdata, bss_change);
152 @@ -266,6 +288,7 @@ static void ieee80211_rx_bss_info(struct
153 u64 beacon_timestamp, rx_timestamp;
154 u32 supp_rates = 0;
155 enum ieee80211_band band = rx_status->band;
156 + struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
157
158 if (elems->ds_params && elems->ds_params_len == 1)
159 freq = ieee80211_channel_to_frequency(elems->ds_params[0],
160 @@ -275,7 +298,10 @@ static void ieee80211_rx_bss_info(struct
161
162 channel = ieee80211_get_channel(local->hw.wiphy, freq);
163
164 - if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
165 + if (!channel ||
166 + channel->flags & (IEEE80211_CHAN_DISABLED ||
167 + IEEE80211_CHAN_NO_IBSS ||
168 + IEEE80211_CHAN_RADAR))
169 return;
170
171 if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
172 @@ -313,8 +339,41 @@ static void ieee80211_rx_bss_info(struct
173 GFP_ATOMIC);
174 }
175
176 - if (sta && elems->wmm_info)
177 - set_sta_flag(sta, WLAN_STA_WME);
178 + if (sta) {
179 + if (elems->wmm_info)
180 + set_sta_flag(sta, WLAN_STA_WME);
181 +
182 + /* we both use HT */
183 + if (elems->ht_info_elem && elems->ht_cap_elem &&
184 + sdata->u.ibss.channel_type) {
185 + enum nl80211_channel_type channel_type =
186 + ieee80211_ht_info_to_channel_type(
187 + elems->ht_info_elem);
188 + struct ieee80211_sta_ht_cap sta_ht_cap_new;
189 +
190 + /*
191 + * fall back to HT20 if we don't use or use
192 + * the other extension channel
193 + */
194 + if (channel_type > NL80211_CHAN_HT20 &&
195 + channel_type != sdata->u.ibss.channel_type)
196 + channel_type = NL80211_CHAN_HT20;
197 +
198 + ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
199 + elems->ht_cap_elem,
200 + &sta_ht_cap_new);
201 + if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new,
202 + sizeof(sta_ht_cap_new))) {
203 + memcpy(&sta->sta.ht_cap,
204 + &sta_ht_cap_new,
205 + sizeof(sta_ht_cap_new));
206 + rate_control_rate_update(local, sband,
207 + sta,
208 + IEEE80211_RC_HT_CHANGED,
209 + channel_type);
210 + }
211 + }
212 + }
213
214 rcu_read_unlock();
215 }
216 @@ -896,10 +955,15 @@ int ieee80211_ibss_join(struct ieee80211
217 struct sk_buff *skb;
218
219 skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
220 - 36 /* bitrates */ +
221 - 34 /* SSID */ +
222 - 3 /* DS params */ +
223 - 4 /* IBSS params */ +
224 + sizeof(struct ieee80211_hdr_3addr) +
225 + 12 /* struct ieee80211_mgmt.u.beacon */ +
226 + 2 + IEEE80211_MAX_SSID_LEN /* max SSID */ +
227 + 2 + 8 /* max Supported Rates */ +
228 + 3 /* max DS params */ +
229 + 4 /* IBSS params */ +
230 + 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
231 + 2 + sizeof(struct ieee80211_ht_cap) +
232 + 2 + sizeof(struct ieee80211_ht_info) +
233 params->ie_len);
234 if (!skb)
235 return -ENOMEM;
236 @@ -920,13 +984,15 @@ int ieee80211_ibss_join(struct ieee80211
237 sdata->vif.bss_conf.beacon_int = params->beacon_interval;
238
239 sdata->u.ibss.channel = params->channel;
240 + sdata->u.ibss.channel_type = params->channel_type;
241 sdata->u.ibss.fixed_channel = params->channel_fixed;
242
243 /* fix ourselves to that channel now already */
244 if (params->channel_fixed) {
245 sdata->local->oper_channel = params->channel;
246 - WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
247 - NL80211_CHAN_NO_HT));
248 + if (!ieee80211_set_channel_type(sdata->local, sdata,
249 + params->channel_type))
250 + return -EINVAL;
251 }
252
253 if (params->ie) {
254 --- a/net/mac80211/ieee80211_i.h
255 +++ b/net/mac80211/ieee80211_i.h
256 @@ -465,6 +465,7 @@ struct ieee80211_if_ibss {
257 u8 ssid_len, ie_len;
258 u8 *ie;
259 struct ieee80211_channel *channel;
260 + enum nl80211_channel_type channel_type;
261
262 unsigned long ibss_join_req;
263 /* probe response/beacon for IBSS */
264 @@ -1339,6 +1340,12 @@ void ieee80211_recalc_smps(struct ieee80
265 size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
266 const u8 *ids, int n_ids, size_t offset);
267 size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
268 +u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
269 + u16 cap);
270 +u8 *ieee80211_ie_build_ht_info(u8 *pos,
271 + struct ieee80211_sta_ht_cap *ht_cap,
272 + struct ieee80211_channel *channel,
273 + enum nl80211_channel_type channel_type);
274
275 /* internal work items */
276 void ieee80211_work_init(struct ieee80211_local *local);
277 @@ -1367,6 +1374,8 @@ ieee80211_get_channel_mode(struct ieee80
278 bool ieee80211_set_channel_type(struct ieee80211_local *local,
279 struct ieee80211_sub_if_data *sdata,
280 enum nl80211_channel_type chantype);
281 +enum nl80211_channel_type
282 +ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info);
283
284 #ifdef CONFIG_MAC80211_NOINLINE
285 #define debug_noinline noinline
286 --- a/net/mac80211/iface.c
287 +++ b/net/mac80211/iface.c
288 @@ -178,7 +178,6 @@ static int ieee80211_do_open(struct net_
289 {
290 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
291 struct ieee80211_local *local = sdata->local;
292 - struct sta_info *sta;
293 u32 changed = 0;
294 int res;
295 u32 hw_reconf_flags = 0;
296 @@ -290,27 +289,6 @@ static int ieee80211_do_open(struct net_
297
298 set_bit(SDATA_STATE_RUNNING, &sdata->state);
299
300 - if (sdata->vif.type == NL80211_IFTYPE_WDS) {
301 - /* Create STA entry for the WDS peer */
302 - sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
303 - GFP_KERNEL);
304 - if (!sta) {
305 - res = -ENOMEM;
306 - goto err_del_interface;
307 - }
308 -
309 - /* no atomic bitop required since STA is not live yet */
310 - set_sta_flag(sta, WLAN_STA_AUTHORIZED);
311 -
312 - res = sta_info_insert(sta);
313 - if (res) {
314 - /* STA has been freed */
315 - goto err_del_interface;
316 - }
317 -
318 - rate_control_rate_init(sta);
319 - }
320 -
321 /*
322 * set_multicast_list will be invoked by the networking core
323 * which will check whether any increments here were done in
324 @@ -344,8 +322,7 @@ static int ieee80211_do_open(struct net_
325 netif_tx_start_all_queues(dev);
326
327 return 0;
328 - err_del_interface:
329 - drv_remove_interface(local, &sdata->vif);
330 +
331 err_stop:
332 if (!local->open_count)
333 drv_stop(local);
334 @@ -716,6 +693,70 @@ static void ieee80211_if_setup(struct ne
335 dev->destructor = free_netdev;
336 }
337
338 +static void ieee80211_wds_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
339 + struct sk_buff *skb)
340 +{
341 + struct ieee80211_local *local = sdata->local;
342 + struct ieee80211_rx_status *rx_status;
343 + struct ieee802_11_elems elems;
344 + struct ieee80211_mgmt *mgmt;
345 + struct sta_info *sta;
346 + size_t baselen;
347 + u32 rates = 0;
348 + u16 stype;
349 + bool new = false;
350 + enum ieee80211_band band = local->hw.conf.channel->band;
351 + struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
352 +
353 + rx_status = IEEE80211_SKB_RXCB(skb);
354 + mgmt = (struct ieee80211_mgmt *) skb->data;
355 + stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
356 +
357 + if (stype != IEEE80211_STYPE_BEACON)
358 + return;
359 +
360 + baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
361 + if (baselen > skb->len)
362 + return;
363 +
364 + ieee802_11_parse_elems(mgmt->u.probe_resp.variable,
365 + skb->len - baselen, &elems);
366 +
367 + rates = ieee80211_sta_get_rates(local, &elems, band);
368 +
369 + rcu_read_lock();
370 +
371 + sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
372 +
373 + if (!sta) {
374 + rcu_read_unlock();
375 + sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
376 + GFP_KERNEL);
377 + if (!sta)
378 + return;
379 +
380 + new = true;
381 + }
382 +
383 + sta->last_rx = jiffies;
384 + sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
385 +
386 + if (elems.ht_cap_elem)
387 + ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
388 + elems.ht_cap_elem, &sta->sta.ht_cap);
389 +
390 + if (elems.wmm_param)
391 + set_sta_flag(sta, WLAN_STA_WME);
392 +
393 + if (new) {
394 + set_sta_flag(sta, WLAN_STA_AUTHORIZED);
395 + rate_control_rate_init(sta);
396 + sta_info_insert_rcu(sta);
397 + }
398 +
399 + rcu_read_unlock();
400 +}
401 +
402 static void ieee80211_iface_work(struct work_struct *work)
403 {
404 struct ieee80211_sub_if_data *sdata =
405 @@ -820,6 +861,9 @@ static void ieee80211_iface_work(struct
406 break;
407 ieee80211_mesh_rx_queued_mgmt(sdata, skb);
408 break;
409 + case NL80211_IFTYPE_WDS:
410 + ieee80211_wds_rx_queued_mgmt(sdata, skb);
411 + break;
412 default:
413 WARN(1, "frame for unexpected interface type");
414 break;
415 --- a/net/mac80211/rx.c
416 +++ b/net/mac80211/rx.c
417 @@ -2211,7 +2211,9 @@ ieee80211_rx_h_action(struct ieee80211_r
418 */
419 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
420 sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
421 - sdata->vif.type != NL80211_IFTYPE_AP)
422 + sdata->vif.type != NL80211_IFTYPE_AP &&
423 + sdata->vif.type != NL80211_IFTYPE_ADHOC &&
424 + sdata->vif.type != NL80211_IFTYPE_WDS)
425 break;
426
427 /* verify action_code is present */
428 @@ -2426,13 +2428,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
429
430 if (!ieee80211_vif_is_mesh(&sdata->vif) &&
431 sdata->vif.type != NL80211_IFTYPE_ADHOC &&
432 - sdata->vif.type != NL80211_IFTYPE_STATION)
433 + sdata->vif.type != NL80211_IFTYPE_STATION &&
434 + sdata->vif.type != NL80211_IFTYPE_WDS)
435 return RX_DROP_MONITOR;
436
437 switch (stype) {
438 case cpu_to_le16(IEEE80211_STYPE_BEACON):
439 case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
440 - /* process for all: mesh, mlme, ibss */
441 + /* process for all: mesh, mlme, ibss, wds */
442 break;
443 case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
444 case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
445 @@ -2775,10 +2778,16 @@ static int prepare_for_handlers(struct i
446 }
447 break;
448 case NL80211_IFTYPE_WDS:
449 - if (bssid || !ieee80211_is_data(hdr->frame_control))
450 - return 0;
451 if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
452 return 0;
453 +
454 + if (ieee80211_is_data(hdr->frame_control) ||
455 + ieee80211_is_action(hdr->frame_control)) {
456 + if (compare_ether_addr(sdata->vif.addr, hdr->addr1))
457 + return 0;
458 + } else if (!ieee80211_is_beacon(hdr->frame_control))
459 + return 0;
460 +
461 break;
462 default:
463 /* should never get here */
464 --- a/net/mac80211/sta_info.h
465 +++ b/net/mac80211/sta_info.h
466 @@ -32,7 +32,6 @@
467 * frames.
468 * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
469 * @WLAN_STA_WME: Station is a QoS-STA.
470 - * @WLAN_STA_WDS: Station is one of our WDS peers.
471 * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
472 * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next
473 * frame to this station is transmitted.
474 @@ -61,7 +60,6 @@ enum ieee80211_sta_info_flags {
475 WLAN_STA_SHORT_PREAMBLE,
476 WLAN_STA_ASSOC_AP,
477 WLAN_STA_WME,
478 - WLAN_STA_WDS,
479 WLAN_STA_CLEAR_PS_FILT,
480 WLAN_STA_MFP,
481 WLAN_STA_BLOCK_BA,
482 --- a/net/mac80211/util.c
483 +++ b/net/mac80211/util.c
484 @@ -836,23 +836,8 @@ int ieee80211_build_preq_ies(struct ieee
485 offset = noffset;
486 }
487
488 - if (sband->ht_cap.ht_supported) {
489 - u16 cap = sband->ht_cap.cap;
490 - __le16 tmp;
491 -
492 - *pos++ = WLAN_EID_HT_CAPABILITY;
493 - *pos++ = sizeof(struct ieee80211_ht_cap);
494 - memset(pos, 0, sizeof(struct ieee80211_ht_cap));
495 - tmp = cpu_to_le16(cap);
496 - memcpy(pos, &tmp, sizeof(u16));
497 - pos += sizeof(u16);
498 - *pos++ = sband->ht_cap.ampdu_factor |
499 - (sband->ht_cap.ampdu_density <<
500 - IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
501 - memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
502 - pos += sizeof(sband->ht_cap.mcs);
503 - pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
504 - }
505 + if (sband->ht_cap.ht_supported)
506 + pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
507
508 /*
509 * If adding more here, adjust code in main.c
510 @@ -1443,3 +1428,100 @@ int ieee80211_add_ext_srates_ie(struct i
511 }
512 return 0;
513 }
514 +
515 +u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
516 + u16 cap)
517 +{
518 + __le16 tmp;
519 +
520 + *pos++ = WLAN_EID_HT_CAPABILITY;
521 + *pos++ = sizeof(struct ieee80211_ht_cap);
522 + memset(pos, 0, sizeof(struct ieee80211_ht_cap));
523 +
524 + /* capability flags */
525 + tmp = cpu_to_le16(cap);
526 + memcpy(pos, &tmp, sizeof(u16));
527 + pos += sizeof(u16);
528 +
529 + /* AMPDU parameters */
530 + *pos++ = sband->ht_cap.ampdu_factor |
531 + (sband->ht_cap.ampdu_density <<
532 + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
533 +
534 + /* MCS set */
535 + memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
536 + pos += sizeof(sband->ht_cap.mcs);
537 +
538 + /* extended capabilities */
539 + pos += sizeof(__le16);
540 +
541 + /* BF capabilities */
542 + pos += sizeof(__le32);
543 +
544 + /* antenna selection */
545 + pos += sizeof(u8);
546 +
547 + return pos;
548 +}
549 +
550 +u8 *ieee80211_ie_build_ht_info(u8 *pos,
551 + struct ieee80211_sta_ht_cap *ht_cap,
552 + struct ieee80211_channel *channel,
553 + enum nl80211_channel_type channel_type)
554 +{
555 + struct ieee80211_ht_info *ht_info;
556 + /* Build HT Information */
557 + *pos++ = WLAN_EID_HT_INFORMATION;
558 + *pos++ = sizeof(struct ieee80211_ht_info);
559 + ht_info = (struct ieee80211_ht_info *)pos;
560 + ht_info->control_chan =
561 + ieee80211_frequency_to_channel(channel->center_freq);
562 + switch (channel_type) {
563 + case NL80211_CHAN_HT40MINUS:
564 + ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
565 + break;
566 + case NL80211_CHAN_HT40PLUS:
567 + ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
568 + break;
569 + case NL80211_CHAN_HT20:
570 + default:
571 + ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
572 + break;
573 + }
574 + if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
575 + ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
576 + ht_info->operation_mode = 0x0000;
577 + ht_info->stbc_param = 0x0000;
578 +
579 + /* It seems that Basic MCS set and Supported MCS set
580 + are identical for the first 10 bytes */
581 + memset(&ht_info->basic_set, 0, 16);
582 + memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
583 +
584 + return pos + sizeof(struct ieee80211_ht_info);
585 +}
586 +
587 +enum nl80211_channel_type
588 +ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
589 +{
590 + enum nl80211_channel_type channel_type;
591 +
592 + if (!ht_info)
593 + return NL80211_CHAN_NO_HT;
594 +
595 + switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
596 + case IEEE80211_HT_PARAM_CHA_SEC_NONE:
597 + channel_type = NL80211_CHAN_HT20;
598 + break;
599 + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
600 + channel_type = NL80211_CHAN_HT40PLUS;
601 + break;
602 + case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
603 + channel_type = NL80211_CHAN_HT40MINUS;
604 + break;
605 + default:
606 + channel_type = NL80211_CHAN_NO_HT;
607 + }
608 +
609 + return channel_type;
610 +}
611 --- a/net/mac80211/work.c
612 +++ b/net/mac80211/work.c
613 @@ -118,7 +118,6 @@ static void ieee80211_add_ht_ie(struct s
614 u8 *pos;
615 u32 flags = channel->flags;
616 u16 cap = sband->ht_cap.cap;
617 - __le16 tmp;
618
619 if (!sband->ht_cap.ht_supported)
620 return;
621 @@ -169,34 +168,8 @@ static void ieee80211_add_ht_ie(struct s
622 }
623
624 /* reserve and fill IE */
625 -
626 pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
627 - *pos++ = WLAN_EID_HT_CAPABILITY;
628 - *pos++ = sizeof(struct ieee80211_ht_cap);
629 - memset(pos, 0, sizeof(struct ieee80211_ht_cap));
630 -
631 - /* capability flags */
632 - tmp = cpu_to_le16(cap);
633 - memcpy(pos, &tmp, sizeof(u16));
634 - pos += sizeof(u16);
635 -
636 - /* AMPDU parameters */
637 - *pos++ = sband->ht_cap.ampdu_factor |
638 - (sband->ht_cap.ampdu_density <<
639 - IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
640 -
641 - /* MCS set */
642 - memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
643 - pos += sizeof(sband->ht_cap.mcs);
644 -
645 - /* extended capabilities */
646 - pos += sizeof(__le16);
647 -
648 - /* BF capabilities */
649 - pos += sizeof(__le32);
650 -
651 - /* antenna selection */
652 - pos += sizeof(u8);
653 + ieee80211_ie_build_ht_cap(pos, sband, cap);
654 }
655
656 static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
657 --- a/net/wireless/chan.c
658 +++ b/net/wireless/chan.c
659 @@ -44,9 +44,9 @@ rdev_freq_to_chan(struct cfg80211_regist
660 return chan;
661 }
662
663 -static bool can_beacon_sec_chan(struct wiphy *wiphy,
664 - struct ieee80211_channel *chan,
665 - enum nl80211_channel_type channel_type)
666 +bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
667 + struct ieee80211_channel *chan,
668 + enum nl80211_channel_type channel_type)
669 {
670 struct ieee80211_channel *sec_chan;
671 int diff;
672 @@ -75,6 +75,7 @@ static bool can_beacon_sec_chan(struct w
673
674 return true;
675 }
676 +EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
677
678 int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
679 struct wireless_dev *wdev, int freq,
680 @@ -109,8 +110,8 @@ int cfg80211_set_freq(struct cfg80211_re
681 switch (channel_type) {
682 case NL80211_CHAN_HT40PLUS:
683 case NL80211_CHAN_HT40MINUS:
684 - if (!can_beacon_sec_chan(&rdev->wiphy, chan,
685 - channel_type)) {
686 + if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, chan,
687 + channel_type)) {
688 printk(KERN_DEBUG
689 "cfg80211: Secondary channel not "
690 "allowed to initiate communication\n");
691 --- a/net/wireless/nl80211.c
692 +++ b/net/wireless/nl80211.c
693 @@ -4574,13 +4574,34 @@ static int nl80211_join_ibss(struct sk_b
694 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
695 }
696
697 - ibss.channel = ieee80211_get_channel(wiphy,
698 - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
699 + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
700 + enum nl80211_channel_type channel_type;
701 +
702 + channel_type = nla_get_u32(
703 + info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
704 + if (channel_type > NL80211_CHAN_HT40PLUS)
705 + return -EINVAL;
706 + ibss.channel_type = channel_type;
707 + } else {
708 + ibss.channel_type = NL80211_CHAN_NO_HT;
709 + }
710 +
711 + ibss.channel = rdev_freq_to_chan(rdev,
712 + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
713 + ibss.channel_type);
714 if (!ibss.channel ||
715 + ibss.channel->flags & IEEE80211_CHAN_RADAR ||
716 ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
717 ibss.channel->flags & IEEE80211_CHAN_DISABLED)
718 return -EINVAL;
719
720 + /* Both channels should be able to initiate communication */
721 + if ((ibss.channel_type == NL80211_CHAN_HT40PLUS ||
722 + ibss.channel_type == NL80211_CHAN_HT40MINUS) &&
723 + !cfg80211_can_beacon_sec_chan(&rdev->wiphy, ibss.channel,
724 + ibss.channel_type))
725 + return -EINVAL;
726 +
727 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
728 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
729