eb1c8fce8bbf58c89dd28d7320c2c9e5d2767f39
[openwrt/svn-archive/archive.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);