371e82bcaeae36d334304055b6daf2319756b29d
[openwrt.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