eb1c8fce8bbf58c89dd28d7320c2c9e5d2767f39
[openwrt-10.03/.git] / package / mac80211 / patches / 310-ibss_ht.patch
1 --- a/include/net/cfg80211.h
2 +++ b/include/net/cfg80211.h
3 @@ -1085,6 +1085,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 @@ -2584,6 +2585,12 @@ struct cfg80211_bss *cfg80211_get_bss(st
12                                       const u8 *bssid,
13                                       const u8 *ssid, size_t ssid_len,
14                                       u16 capa_mask, u16 capa_val);
15 +struct cfg80211_bss *cfg80211_get_bss_ht(struct wiphy *wiphy,
16 +                                         struct ieee80211_channel *channel,
17 +                                         const u8 *bssid,
18 +                                         const u8 *ssid, size_t ssid_len,
19 +                                         u16 capa_mask, u16 capa_val,
20 +                                      enum nl80211_channel_type channel_type);
21  static inline struct cfg80211_bss *
22  cfg80211_get_ibss(struct wiphy *wiphy,
23                   struct ieee80211_channel *channel,
24 --- a/net/wireless/nl80211.c
25 +++ b/net/wireless/nl80211.c
26 @@ -4470,13 +4470,41 @@ static int nl80211_join_ibss(struct sk_b
27                 ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
28         }
29  
30 -       ibss.channel = ieee80211_get_channel(wiphy,
31 -               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
32 +       if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
33 +               enum nl80211_channel_type channel_type;
34 +
35 +               channel_type = nla_get_u32(
36 +                       info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
37 +               if (channel_type != NL80211_CHAN_NO_HT &&
38 +                   channel_type != NL80211_CHAN_HT20 &&
39 +                   channel_type != NL80211_CHAN_HT40PLUS &&
40 +                   channel_type != NL80211_CHAN_HT40MINUS)
41 +                       return -EINVAL;
42 +               ibss.channel_type = channel_type;
43 +       } else {
44 +               ibss.channel_type = NL80211_CHAN_NO_HT;
45 +       }
46 +
47 +       ibss.channel = rdev_freq_to_chan(rdev,
48 +               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
49 +               ibss.channel_type);
50         if (!ibss.channel ||
51 +           ibss.channel->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
52             ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
53 -           ibss.channel->flags & IEEE80211_CHAN_DISABLED)
54 +           ibss.channel->flags & IEEE80211_CHAN_RADAR)
55                 return -EINVAL;
56  
57 +       /* Both channels should be able to initiate communication */
58 +       if ((ibss.channel_type == NL80211_CHAN_HT40PLUS ||
59 +            ibss.channel_type == NL80211_CHAN_HT40MINUS) &&
60 +           !can_beacon_sec_chan(&rdev->wiphy, ibss.channel,
61 +                                ibss.channel_type)) {
62 +               printk(KERN_DEBUG
63 +                      "cfg80211: Secondary channel not "
64 +                      "allowed to initiate communication\n");
65 +               return -EINVAL;
66 +       }
67 +
68         ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
69         ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
70  
71 --- a/net/wireless/chan.c
72 +++ b/net/wireless/chan.c
73 @@ -44,7 +44,7 @@ rdev_freq_to_chan(struct cfg80211_regist
74         return chan;
75  }
76  
77 -static bool can_beacon_sec_chan(struct wiphy *wiphy,
78 +bool can_beacon_sec_chan(struct wiphy *wiphy,
79                                 struct ieee80211_channel *chan,
80                                 enum nl80211_channel_type channel_type)
81  {
82 @@ -75,6 +75,7 @@ static bool can_beacon_sec_chan(struct w
83  
84         return true;
85  }
86 +EXPORT_SYMBOL(can_beacon_sec_chan);
87  
88  int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
89                       struct wireless_dev *wdev, int freq,
90 --- a/net/wireless/core.h
91 +++ b/net/wireless/core.h
92 @@ -441,6 +441,9 @@ cfg80211_can_add_interface(struct cfg802
93  struct ieee80211_channel *
94  rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
95                   int freq, enum nl80211_channel_type channel_type);
96 +bool can_beacon_sec_chan(struct wiphy *wiphy,
97 +                               struct ieee80211_channel *chan,
98 +                               enum nl80211_channel_type channel_type);
99  int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
100                       struct wireless_dev *wdev, int freq,
101                       enum nl80211_channel_type channel_type);
102 --- a/net/wireless/scan.c
103 +++ b/net/wireless/scan.c
104 @@ -365,6 +365,19 @@ struct cfg80211_bss *cfg80211_get_bss(st
105                                       const u8 *ssid, size_t ssid_len,
106                                       u16 capa_mask, u16 capa_val)
107  {
108 +       /* call HT version with no HT requirements */
109 +       return cfg80211_get_bss_ht(wiphy, channel, bssid, ssid, ssid_len,
110 +                                  capa_mask, capa_val, NL80211_CHAN_NO_HT);
111 +}
112 +EXPORT_SYMBOL(cfg80211_get_bss);
113 +
114 +struct cfg80211_bss *cfg80211_get_bss_ht(struct wiphy *wiphy,
115 +                                     struct ieee80211_channel *channel,
116 +                                     const u8 *bssid,
117 +                                     const u8 *ssid, size_t ssid_len,
118 +                                     u16 capa_mask, u16 capa_val,
119 +                                     enum nl80211_channel_type require_ht)
120 +{
121         struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
122         struct cfg80211_internal_bss *bss, *res = NULL;
123         unsigned long now = jiffies;
124 @@ -374,8 +387,26 @@ struct cfg80211_bss *cfg80211_get_bss(st
125         list_for_each_entry(bss, &dev->bss_list, list) {
126                 if ((bss->pub.capability & capa_mask) != capa_val)
127                         continue;
128 -               if (channel && bss->pub.channel != channel)
129 -                       continue;
130 +               if (channel) {
131 +                       if (bss->pub.channel != channel)
132 +                               continue;
133 +                       if (require_ht != NL80211_CHAN_NO_HT) {
134 +                               struct ieee80211_ht_info *ht_info;
135 +                               ht_info = (struct ieee80211_ht_info *)
136 +                                       ieee80211_bss_get_ie(&bss->pub,
137 +                                                      WLAN_EID_HT_INFORMATION);
138 +                               if (!ht_info)
139 +                                       continue;
140 +                               if (require_ht == NL80211_CHAN_HT40MINUS &&
141 +                                             !(ht_info->ht_param &
142 +                                             IEEE80211_HT_PARAM_CHA_SEC_BELOW))
143 +                                       continue;
144 +                               if (require_ht == NL80211_CHAN_HT40PLUS &&
145 +                                             !(ht_info->ht_param &
146 +                                             IEEE80211_HT_PARAM_CHA_SEC_ABOVE))
147 +                                       continue;
148 +                       }
149 +               }
150                 /* Don't get expired BSS structs */
151                 if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
152                     !atomic_read(&bss->hold))
153 @@ -392,7 +423,7 @@ struct cfg80211_bss *cfg80211_get_bss(st
154                 return NULL;
155         return &res->pub;
156  }
157 -EXPORT_SYMBOL(cfg80211_get_bss);
158 +EXPORT_SYMBOL(cfg80211_get_bss_ht);
159  
160  struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy,
161                                        struct ieee80211_channel *channel,
162 --- a/net/mac80211/ieee80211_i.h
163 +++ b/net/mac80211/ieee80211_i.h
164 @@ -464,6 +464,7 @@ struct ieee80211_if_ibss {
165         u8 ssid_len, ie_len;
166         u8 *ie;
167         struct ieee80211_channel *channel;
168 +       enum nl80211_channel_type channel_type;
169  
170         unsigned long ibss_join_req;
171         /* probe response/beacon for IBSS */
172 @@ -1089,6 +1090,7 @@ void ieee80211_ibss_notify_scan_complete
173  void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
174  struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
175                                         u8 *bssid, u8 *addr, u32 supp_rates,
176 +                                       struct ieee80211_ht_cap *ht_cap,
177                                         gfp_t gfp);
178  int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
179                         struct cfg80211_ibss_params *params);
180 @@ -1343,6 +1345,12 @@ void ieee80211_recalc_smps(struct ieee80
181  size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
182                           const u8 *ids, int n_ids, size_t offset);
183  size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
184 +u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
185 +                              u16 cap);
186 +u8 *ieee80211_ie_build_ht_info(u8 *pos,
187 +                               struct ieee80211_sta_ht_cap *ht_cap,
188 +                               struct ieee80211_channel *channel,
189 +                               enum nl80211_channel_type channel_type);
190  
191  /* internal work items */
192  void ieee80211_work_init(struct ieee80211_local *local);
193 @@ -1371,6 +1379,8 @@ ieee80211_get_channel_mode(struct ieee80
194  bool ieee80211_set_channel_type(struct ieee80211_local *local,
195                                 struct ieee80211_sub_if_data *sdata,
196                                 enum nl80211_channel_type chantype);
197 +enum nl80211_channel_type ieee80211_ht_info_to_channel_type(
198 +                                       struct ieee80211_ht_info *ht_info);
199  
200  #ifdef CONFIG_MAC80211_NOINLINE
201  #define debug_noinline noinline
202 --- a/net/mac80211/util.c
203 +++ b/net/mac80211/util.c
204 @@ -841,23 +841,8 @@ int ieee80211_build_preq_ies(struct ieee
205                 offset = noffset;
206         }
207  
208 -       if (sband->ht_cap.ht_supported) {
209 -               u16 cap = sband->ht_cap.cap;
210 -               __le16 tmp;
211 -
212 -               *pos++ = WLAN_EID_HT_CAPABILITY;
213 -               *pos++ = sizeof(struct ieee80211_ht_cap);
214 -               memset(pos, 0, sizeof(struct ieee80211_ht_cap));
215 -               tmp = cpu_to_le16(cap);
216 -               memcpy(pos, &tmp, sizeof(u16));
217 -               pos += sizeof(u16);
218 -               *pos++ = sband->ht_cap.ampdu_factor |
219 -                        (sband->ht_cap.ampdu_density <<
220 -                               IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
221 -               memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
222 -               pos += sizeof(sband->ht_cap.mcs);
223 -               pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
224 -       }
225 +       if (sband->ht_cap.ht_supported)
226 +               pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
227  
228         /*
229          * If adding more here, adjust code in main.c
230 @@ -1381,3 +1366,100 @@ void ieee80211_disable_rssi_reports(stru
231         _ieee80211_enable_rssi_reports(sdata, 0, 0);
232  }
233  EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
234 +
235 +u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
236 +                              u16 cap)
237 +{
238 +       __le16 tmp;
239 +
240 +       *pos++ = WLAN_EID_HT_CAPABILITY;
241 +       *pos++ = sizeof(struct ieee80211_ht_cap);
242 +       memset(pos, 0, sizeof(struct ieee80211_ht_cap));
243 +
244 +       /* capability flags */
245 +       tmp = cpu_to_le16(cap);
246 +       memcpy(pos, &tmp, sizeof(u16));
247 +       pos += sizeof(u16);
248 +
249 +       /* AMPDU parameters */
250 +       *pos++ = sband->ht_cap.ampdu_factor |
251 +                (sband->ht_cap.ampdu_density <<
252 +                       IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
253 +
254 +       /* MCS set */
255 +       memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
256 +       pos += sizeof(sband->ht_cap.mcs);
257 +
258 +       /* extended capabilities */
259 +       pos += sizeof(__le16);
260 +
261 +       /* BF capabilities */
262 +       pos += sizeof(__le32);
263 +
264 +       /* antenna selection */
265 +       pos += sizeof(u8);
266 +
267 +       return pos;
268 +}
269 +
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 +       struct ieee80211_ht_info *ht_info;
276 +       /* Build HT Information */
277 +       *pos++ = WLAN_EID_HT_INFORMATION;
278 +       *pos++ = sizeof(struct ieee80211_ht_info);
279 +       ht_info = (struct ieee80211_ht_info *)pos;
280 +       ht_info->control_chan =
281 +                       ieee80211_frequency_to_channel(channel->center_freq);
282 +       switch (channel_type) {
283 +       case NL80211_CHAN_HT40MINUS:
284 +               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
285 +               break;
286 +       case NL80211_CHAN_HT40PLUS:
287 +               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
288 +               break;
289 +       case NL80211_CHAN_HT20:
290 +       default:
291 +               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
292 +               break;
293 +       }
294 +       if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
295 +               ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
296 +       ht_info->operation_mode = 0x0000;
297 +       ht_info->stbc_param = 0x0000;
298 +
299 +       /* It seems that Basic MCS set and Supported MCS set
300 +          are identical for the first 10 bytes */
301 +       memset(&ht_info->basic_set, 0, 16);
302 +       memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
303 +
304 +       return pos + sizeof(struct ieee80211_ht_info);
305 +}
306 +
307 +enum nl80211_channel_type ieee80211_ht_info_to_channel_type(
308 +                                       struct ieee80211_ht_info *ht_info)
309 +{
310 +       enum nl80211_channel_type channel_type;
311 +
312 +       if (!ht_info)
313 +               return NL80211_CHAN_NO_HT;
314 +
315 +       switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
316 +       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
317 +               channel_type = NL80211_CHAN_HT20;
318 +               break;
319 +       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
320 +               channel_type = NL80211_CHAN_HT40PLUS;
321 +               break;
322 +       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
323 +               channel_type = NL80211_CHAN_HT40MINUS;
324 +               break;
325 +       default:
326 +               channel_type = NL80211_CHAN_NO_HT;
327 +       }
328 +
329 +       return channel_type;
330 +}
331 --- a/net/mac80211/work.c
332 +++ b/net/mac80211/work.c
333 @@ -118,7 +118,6 @@ static void ieee80211_add_ht_ie(struct s
334         u8 *pos;
335         u32 flags = channel->flags;
336         u16 cap = sband->ht_cap.cap;
337 -       __le16 tmp;
338  
339         if (!sband->ht_cap.ht_supported)
340                 return;
341 @@ -169,34 +168,8 @@ static void ieee80211_add_ht_ie(struct s
342         }
343  
344         /* reserve and fill IE */
345 -
346         pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
347 -       *pos++ = WLAN_EID_HT_CAPABILITY;
348 -       *pos++ = sizeof(struct ieee80211_ht_cap);
349 -       memset(pos, 0, sizeof(struct ieee80211_ht_cap));
350 -
351 -       /* capability flags */
352 -       tmp = cpu_to_le16(cap);
353 -       memcpy(pos, &tmp, sizeof(u16));
354 -       pos += sizeof(u16);
355 -
356 -       /* AMPDU parameters */
357 -       *pos++ = sband->ht_cap.ampdu_factor |
358 -                (sband->ht_cap.ampdu_density <<
359 -                       IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
360 -
361 -       /* MCS set */
362 -       memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
363 -       pos += sizeof(sband->ht_cap.mcs);
364 -
365 -       /* extended capabilities */
366 -       pos += sizeof(__le16);
367 -
368 -       /* BF capabilities */
369 -       pos += sizeof(__le32);
370 -
371 -       /* antenna selection */
372 -       pos += sizeof(u8);
373 +       ieee80211_ie_build_ht_cap(pos, sband, cap);
374  }
375  
376  static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
377 --- a/net/mac80211/agg-tx.c
378 +++ b/net/mac80211/agg-tx.c
379 @@ -84,6 +84,8 @@ static void ieee80211_send_addba_request
380                 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
381         else if (sdata->vif.type == NL80211_IFTYPE_STATION)
382                 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
383 +       else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
384 +               memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
385  
386         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
387                                           IEEE80211_STYPE_ACTION);
388 @@ -400,7 +402,8 @@ int ieee80211_start_tx_ba_session(struct
389         if (sdata->vif.type != NL80211_IFTYPE_STATION &&
390             sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
391             sdata->vif.type != NL80211_IFTYPE_AP &&
392 -           sdata->vif.type != NL80211_IFTYPE_WDS)
393 +           sdata->vif.type != NL80211_IFTYPE_WDS &&
394 +           sdata->vif.type != NL80211_IFTYPE_ADHOC)
395                 return -EINVAL;
396  
397         if (test_sta_flags(sta, WLAN_STA_BLOCK_BA)) {
398 --- a/net/mac80211/ht.c
399 +++ b/net/mac80211/ht.c
400 @@ -203,6 +203,8 @@ void ieee80211_send_delba(struct ieee802
401                 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
402         else if (sdata->vif.type == NL80211_IFTYPE_STATION)
403                 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
404 +       else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
405 +               memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
406  
407         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
408                                           IEEE80211_STYPE_ACTION);
409 --- a/net/mac80211/ibss.c
410 +++ b/net/mac80211/ibss.c
411 @@ -35,6 +35,76 @@
412  
413  #define IEEE80211_IBSS_MAX_STA_ENTRIES 128
414  
415 +static bool ieee80211_can_use_ext_chan(struct ieee80211_sub_if_data *sdata,
416 +                                      struct ieee80211_channel *channel,
417 +                                      enum nl80211_channel_type channel_type)
418 +{
419 +       /* check if we are legally allowed to use HT extension channel */
420 +       if ((channel_type == NL80211_CHAN_HT40PLUS) ||
421 +                       (channel_type == NL80211_CHAN_HT40MINUS)) {
422 +               int sec_freq = channel->center_freq +
423 +                            (channel_type == NL80211_CHAN_HT40PLUS ? 20 : -20);
424 +               struct ieee80211_channel *sec_chan =
425 +                            ieee80211_get_channel(sdata->wdev.wiphy, sec_freq);
426 +               if (!sec_chan || sec_chan->flags & (IEEE80211_CHAN_DISABLED |
427 +                                          IEEE80211_CHAN_PASSIVE_SCAN |
428 +                                          IEEE80211_CHAN_NO_IBSS |
429 +                                          IEEE80211_CHAN_RADAR)) {
430 +                       return false;
431 +               }
432 +       }
433 +       return true;
434 +}
435 +
436 +static void ieee80211_update_ht_elems(struct ieee80211_sub_if_data *sdata,
437 +                                     struct ieee80211_mgmt *mgmt,
438 +                                     struct ieee80211_ht_info *ht_info)
439 +{
440 +       struct ieee80211_local *local = sdata->local;
441 +       struct ieee80211_supported_band *sband =
442 +                       local->hw.wiphy->bands[local->oper_channel->band];
443 +       enum nl80211_channel_type channel_type =
444 +                       ieee80211_ht_info_to_channel_type(ht_info);
445 +
446 +       if (!ieee80211_can_use_ext_chan(sdata, local->oper_channel, channel_type))
447 +               channel_type = NL80211_CHAN_HT20;
448 +
449 +       if (channel_type != local->_oper_channel_type) {
450 +               struct sk_buff *skb = rcu_dereference_protected(
451 +                               sdata->u.ibss.presp,
452 +                               lockdep_is_held(&ifibss->mtx));
453 +               struct sk_buff *nskb;
454 +               u8 *ht_ie;
455 +
456 +               /* update HT IE. If not yet existing, create one */
457 +               nskb = skb_copy(skb, GFP_ATOMIC);
458 +               ht_ie = (u8 *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY,
459 +                                              (const u8 *)(nskb->data + 24 +
460 +                                                       sizeof(mgmt->u.beacon)),
461 +                                              nskb->len - 24 -
462 +                                                       sizeof(mgmt->u.beacon));
463 +               if (!ht_ie)
464 +                       ht_ie = skb_put(nskb, 4 +
465 +                                             sizeof(struct ieee80211_ht_cap) +
466 +                                             sizeof(struct ieee80211_ht_info));
467 +
468 +               ht_ie = ieee80211_ie_build_ht_cap(ht_ie, sband,
469 +                                                 sband->ht_cap.cap);
470 +               ht_ie = ieee80211_ie_build_ht_info(ht_ie, &sband->ht_cap,
471 +                                            local->oper_channel, channel_type);
472 +               rcu_assign_pointer(sdata->u.ibss.presp, nskb);
473 +               kfree_skb(skb);
474 +
475 +               if(!ieee80211_set_channel_type(local, sdata, channel_type)) {
476 +                       channel_type = NL80211_CHAN_HT20;
477 +                       WARN_ON(!ieee80211_set_channel_type(local, sdata,
478 +                                                           channel_type));
479 +               }
480 +
481 +               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
482 +       }
483 +
484 +}
485  
486  static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
487                                         struct ieee80211_mgmt *mgmt,
488 @@ -64,6 +134,7 @@ static void ieee80211_rx_mgmt_auth_ibss(
489  static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
490                                       const u8 *bssid, const int beacon_int,
491                                       struct ieee80211_channel *chan,
492 +                                     enum nl80211_channel_type channel_type,
493                                       const u32 basic_rates,
494                                       const u16 capability, u64 tsf)
495  {
496 @@ -104,8 +175,17 @@ static void __ieee80211_sta_join_ibss(st
497  
498         sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
499  
500 +       /* entering a legacy IBSS. Use given HT configuration. */
501 +       if (channel_type == NL80211_CHAN_NO_HT)
502 +               channel_type = ifibss->channel_type;
503         local->oper_channel = chan;
504 -       WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT));
505 +
506 +       /* if phy is on a different extension channel, setting ht40 will fail */
507 +       if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
508 +               channel_type = NL80211_CHAN_HT20;
509 +               WARN_ON(!ieee80211_set_channel_type(local, sdata,
510 +                                                                channel_type));
511 +       }
512         ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
513  
514         sband = local->hw.wiphy->bands[chan->band];
515 @@ -171,6 +251,18 @@ static void __ieee80211_sta_join_ibss(st
516                 memcpy(skb_put(skb, ifibss->ie_len),
517                        ifibss->ie, ifibss->ie_len);
518  
519 +       /* add HT capability and information IEs */
520 +       if (channel_type != NL80211_CHAN_NO_HT && sband->ht_cap.ht_supported) {
521 +               pos = skb_put(skb, 4 +
522 +                                  sizeof(struct ieee80211_ht_cap) +
523 +                                  sizeof(struct ieee80211_ht_info));
524 +               pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
525 +               pos = ieee80211_ie_build_ht_info(pos,
526 +                                                &sband->ht_cap,
527 +                                                chan,
528 +                                                channel_type);
529 +       }
530 +
531         if (local->hw.queues >= 4) {
532                 pos = skb_put(skb, 9);
533                 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
534 @@ -219,6 +311,8 @@ static void ieee80211_sta_join_ibss(stru
535         u32 basic_rates;
536         int i, j;
537         u16 beacon_int = cbss->beacon_interval;
538 +       const u8 *ht_info_ie;
539 +       enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
540  
541         lockdep_assert_held(&sdata->u.ibss.mtx);
542  
543 @@ -242,9 +336,23 @@ static void ieee80211_sta_join_ibss(stru
544                 }
545         }
546  
547 +       ht_info_ie = ieee80211_bss_get_ie(cbss, WLAN_EID_HT_INFORMATION);
548 +       if (ht_info_ie)
549 +               channel_type = ieee80211_ht_info_to_channel_type(
550 +                       (struct ieee80211_ht_info *) (ht_info_ie + 2));
551 +
552 +       if (!ieee80211_can_use_ext_chan(sdata, cbss->channel, channel_type)) {
553 +               channel_type = NL80211_CHAN_HT20;
554 +#ifdef CONFIG_MAC80211_IBSS_DEBUG
555 +               printk(KERN_DEBUG "%s: IBSS not allowed on secondary channel\n",
556 +                      sdata->name);
557 +#endif
558 +       }
559 +
560         __ieee80211_sta_join_ibss(sdata, cbss->bssid,
561                                   beacon_int,
562                                   cbss->channel,
563 +                                 channel_type,
564                                   basic_rates,
565                                   cbss->capability,
566                                   cbss->tsf);
567 @@ -310,11 +418,24 @@ static void ieee80211_rx_bss_info(struct
568                         } else
569                                 sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
570                                                 mgmt->sa, supp_rates,
571 -                                               GFP_ATOMIC);
572 +                                               elems->ht_cap_elem, GFP_ATOMIC);
573                 }
574  
575 -               if (sta && elems->wmm_info)
576 -                       set_sta_flags(sta, WLAN_STA_WME);
577 +               if (sta) {
578 +                       if (elems->wmm_info)
579 +                               set_sta_flags(sta, WLAN_STA_WME);
580 +
581 +                       /* remote station uses ht */
582 +                       if (elems->ht_info_elem) {
583 +                               ieee80211_update_ht_elems(sdata, mgmt,
584 +                                                         elems->ht_info_elem);
585 +                               ieee80211_ht_cap_ie_to_sta_ht_cap(
586 +                                               local->hw.wiphy->bands[
587 +                                                    local->oper_channel->band],
588 +                                               elems->ht_cap_elem,
589 +                                               &sta->sta.ht_cap);
590 +                       }
591 +               }
592  
593                 rcu_read_unlock();
594         }
595 @@ -404,7 +525,7 @@ static void ieee80211_rx_bss_info(struct
596                 ieee80211_sta_join_ibss(sdata, bss);
597                 supp_rates = ieee80211_sta_get_rates(local, elems, band);
598                 ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa,
599 -                                      supp_rates, GFP_KERNEL);
600 +                                   supp_rates, elems->ht_cap_elem, GFP_KERNEL);
601         }
602  
603   put_bss:
604 @@ -417,7 +538,8 @@ static void ieee80211_rx_bss_info(struct
605   * must be callable in atomic context.
606   */
607  struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
608 -                                       u8 *bssid,u8 *addr, u32 supp_rates,
609 +                                       u8 *bssid, u8 *addr, u32 supp_rates,
610 +                                       struct ieee80211_ht_cap *ht_cap,
611                                         gfp_t gfp)
612  {
613         struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
614 @@ -458,6 +580,11 @@ struct sta_info *ieee80211_ibss_add_sta(
615         sta->sta.supp_rates[band] = supp_rates |
616                         ieee80211_mandatory_rates(local, band);
617  
618 +       /* fill in ht rates */
619 +       if (ht_cap)
620 +               ieee80211_ht_cap_ie_to_sta_ht_cap(local->hw.wiphy->bands[band],
621 +                               ht_cap, &sta->sta.ht_cap);
622 +
623         rate_control_rate_init(sta);
624  
625         /* If it fails, maybe we raced another insertion? */
626 @@ -556,8 +683,8 @@ static void ieee80211_sta_create_ibss(st
627                 sdata->drop_unencrypted = 0;
628  
629         __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
630 -                                 ifibss->channel, ifibss->basic_rates,
631 -                                 capability, 0);
632 +                                 ifibss->channel, ifibss->channel_type,
633 +                                 ifibss->basic_rates, capability, 0);
634  }
635  
636  /*
637 @@ -594,10 +721,10 @@ static void ieee80211_sta_find_ibss(stru
638                 chan = ifibss->channel;
639         if (!is_zero_ether_addr(ifibss->bssid))
640                 bssid = ifibss->bssid;
641 -       cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid,
642 +       cbss = cfg80211_get_bss_ht(local->hw.wiphy, chan, bssid,
643                                 ifibss->ssid, ifibss->ssid_len,
644                                 WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY,
645 -                               capability);
646 +                               capability, ifibss->channel_type);
647  
648         if (cbss) {
649                 struct ieee80211_bss *bss;
650 @@ -896,10 +1023,15 @@ int ieee80211_ibss_join(struct ieee80211
651         struct sk_buff *skb;
652  
653         skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
654 -                           36 /* bitrates */ +
655 -                           34 /* SSID */ +
656 -                           3  /* DS params */ +
657 -                           4  /* IBSS params */ +
658 +                           sizeof(struct ieee80211_hdr_3addr) +
659 +                           12 /* struct ieee80211_mgmt.u.beacon */ +
660 +                           2 + IEEE80211_MAX_SSID_LEN /* max SSID */ +
661 +                           2 + 8 /* max Supported Rates */ +
662 +                           3 /* max DS params */ +
663 +                           4 /* IBSS params */ +
664 +                           2 + (IEEE80211_MAX_SUPP_RATES - 8) +
665 +                           2 + sizeof(struct ieee80211_ht_cap) +
666 +                           2 + sizeof(struct ieee80211_ht_info) +
667                             params->ie_len);
668         if (!skb)
669                 return -ENOMEM;
670 @@ -920,13 +1052,15 @@ int ieee80211_ibss_join(struct ieee80211
671         sdata->vif.bss_conf.beacon_int = params->beacon_interval;
672  
673         sdata->u.ibss.channel = params->channel;
674 +       sdata->u.ibss.channel_type = params->channel_type;
675         sdata->u.ibss.fixed_channel = params->channel_fixed;
676  
677         /* fix ourselves to that channel now already */
678         if (params->channel_fixed) {
679                 sdata->local->oper_channel = params->channel;
680 -               WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata,
681 -                                                   NL80211_CHAN_NO_HT));
682 +               if(!ieee80211_set_channel_type(sdata->local, sdata,
683 +                                              params->channel_type))
684 +                       return -EINVAL;
685         }
686  
687         if (params->ie) {
688 --- a/net/mac80211/rx.c
689 +++ b/net/mac80211/rx.c
690 @@ -2161,7 +2161,8 @@ ieee80211_rx_h_action(struct ieee80211_r
691                 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
692                     sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
693                     sdata->vif.type != NL80211_IFTYPE_AP &&
694 -                   sdata->vif.type != NL80211_IFTYPE_WDS)
695 +                   sdata->vif.type != NL80211_IFTYPE_WDS &&
696 +                   sdata->vif.type != NL80211_IFTYPE_ADHOC)
697                         break;
698  
699                 /* verify action_code is present */
700 @@ -2696,7 +2697,8 @@ static int prepare_for_handlers(struct i
701                         else
702                                 rate_idx = status->rate_idx;
703                         rx->sta = ieee80211_ibss_add_sta(sdata, bssid,
704 -                                       hdr->addr2, BIT(rate_idx), GFP_ATOMIC);
705 +                                       hdr->addr2, BIT(rate_idx), NULL,
706 +                                                               GFP_ATOMIC);
707                 }
708                 break;
709         case NL80211_IFTYPE_MESH_POINT:
710 --- a/net/mac80211/agg-rx.c
711 +++ b/net/mac80211/agg-rx.c
712 @@ -186,6 +186,8 @@ static void ieee80211_send_addba_resp(st
713                 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
714         else if (sdata->vif.type == NL80211_IFTYPE_WDS)
715                 memcpy(mgmt->bssid, da, ETH_ALEN);
716 +       else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
717 +               memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
718  
719         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
720                                           IEEE80211_STYPE_ACTION);