aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorAlexander Simon <an.alexsimon@googlemail.com>2011-11-30 10:56:34 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-12-06 16:05:25 -0500
commit13c40c54682ffe62977f670681268a26d500d6fa (patch)
tree4aa8897bc4054f13a637f2f29a1555c3501b3e97 /net/mac80211
parentff3cc5f40f36db1a60a8f1051be7fbc92233419b (diff)
mac80211: Add HT operation modes for IBSS
The HT mode is set by iw (previous patchsets). The interface is set into the specified HT mode. HT mode and capabilities are announced in beacons. If we add a station that uses HT also, the fastest matching HT mode will be used for transmission. That means if we are using HT40+ and we add a station running on HT40-, we would transfer at HT20. If we join an IBSS with HT40, but the secondary channel is not available, we will fall back into HT20 as well. Allow frame aggregation to start in IBSS mode. Signed-off-by: Alexander Simon <an.alexsimon@googlemail.com> [siwu@hrz.tu-chemnitz.de: Updates] * remove implicit channel_type enum assumptions * use rate_control_rate_init() if channel type changed * remove channel flags check * activate HT IBSS feature support * slightly reword commit message * rebase on wireless-testing Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> Reviewed-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/agg-rx.c2
-rw-r--r--net/mac80211/agg-tx.c5
-rw-r--r--net/mac80211/ht.c2
-rw-r--r--net/mac80211/ibss.c83
-rw-r--r--net/mac80211/ieee80211_i.h1
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/mac80211/rx.c3
7 files changed, 87 insertions, 12 deletions
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index e844e5a3840..96debba2c40 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -185,6 +185,8 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
185 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 185 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
186 else if (sdata->vif.type == NL80211_IFTYPE_STATION) 186 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
187 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); 187 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
188 else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
189 memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
188 190
189 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 191 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
190 IEEE80211_STYPE_ACTION); 192 IEEE80211_STYPE_ACTION);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 9bfe28c9ab5..c45fa5df0d4 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -83,6 +83,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
83 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 83 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
84 else if (sdata->vif.type == NL80211_IFTYPE_STATION) 84 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
85 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); 85 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
86 else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
87 memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
86 88
87 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 89 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
88 IEEE80211_STYPE_ACTION); 90 IEEE80211_STYPE_ACTION);
@@ -419,7 +421,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
419 if (sdata->vif.type != NL80211_IFTYPE_STATION && 421 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
420 sdata->vif.type != NL80211_IFTYPE_MESH_POINT && 422 sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
421 sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 423 sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
422 sdata->vif.type != NL80211_IFTYPE_AP) 424 sdata->vif.type != NL80211_IFTYPE_AP &&
425 sdata->vif.type != NL80211_IFTYPE_ADHOC)
423 return -EINVAL; 426 return -EINVAL;
424 427
425 if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { 428 if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) {
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index d3eafaefb16..e0a396bdf88 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -282,6 +282,8 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
282 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 282 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
283 else if (sdata->vif.type == NL80211_IFTYPE_STATION) 283 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
284 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); 284 memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
285 else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
286 memcpy(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN);
285 287
286 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 288 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
287 IEEE80211_STYPE_ACTION); 289 IEEE80211_STYPE_ACTION);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index a82f6b4adb5..3f830ac159e 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -77,6 +77,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
77 struct cfg80211_bss *bss; 77 struct cfg80211_bss *bss;
78 u32 bss_change; 78 u32 bss_change;
79 u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; 79 u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
80 enum nl80211_channel_type channel_type;
80 81
81 lockdep_assert_held(&ifibss->mtx); 82 lockdep_assert_held(&ifibss->mtx);
82 83
@@ -105,8 +106,16 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
105 106
106 sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; 107 sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
107 108
108 local->oper_channel = chan; 109 channel_type = ifibss->channel_type;
109 WARN_ON(!ieee80211_set_channel_type(local, sdata, NL80211_CHAN_NO_HT)); 110 if (channel_type > NL80211_CHAN_HT20 &&
111 !cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
112 channel_type = NL80211_CHAN_HT20;
113 if (!ieee80211_set_channel_type(local, sdata, channel_type)) {
114 /* can only fail due to HT40+/- mismatch */
115 channel_type = NL80211_CHAN_HT20;
116 WARN_ON(!ieee80211_set_channel_type(local, sdata,
117 NL80211_CHAN_HT20));
118 }
110 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); 119 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
111 120
112 sband = local->hw.wiphy->bands[chan->band]; 121 sband = local->hw.wiphy->bands[chan->band];
@@ -172,6 +181,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
172 memcpy(skb_put(skb, ifibss->ie_len), 181 memcpy(skb_put(skb, ifibss->ie_len),
173 ifibss->ie, ifibss->ie_len); 182 ifibss->ie, ifibss->ie_len);
174 183
184 /* add HT capability and information IEs */
185 if (channel_type && sband->ht_cap.ht_supported) {
186 pos = skb_put(skb, 4 +
187 sizeof(struct ieee80211_ht_cap) +
188 sizeof(struct ieee80211_ht_info));
189 pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
190 sband->ht_cap.cap);
191 pos = ieee80211_ie_build_ht_info(pos,
192 &sband->ht_cap,
193 chan,
194 channel_type);
195 }
196
175 if (local->hw.queues >= 4) { 197 if (local->hw.queues >= 4) {
176 pos = skb_put(skb, 9); 198 pos = skb_put(skb, 9);
177 *pos++ = WLAN_EID_VENDOR_SPECIFIC; 199 *pos++ = WLAN_EID_VENDOR_SPECIFIC;
@@ -195,6 +217,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
195 bss_change |= BSS_CHANGED_BEACON; 217 bss_change |= BSS_CHANGED_BEACON;
196 bss_change |= BSS_CHANGED_BEACON_ENABLED; 218 bss_change |= BSS_CHANGED_BEACON_ENABLED;
197 bss_change |= BSS_CHANGED_BASIC_RATES; 219 bss_change |= BSS_CHANGED_BASIC_RATES;
220 bss_change |= BSS_CHANGED_HT;
198 bss_change |= BSS_CHANGED_IBSS; 221 bss_change |= BSS_CHANGED_IBSS;
199 sdata->vif.bss_conf.ibss_joined = true; 222 sdata->vif.bss_conf.ibss_joined = true;
200 ieee80211_bss_info_change_notify(sdata, bss_change); 223 ieee80211_bss_info_change_notify(sdata, bss_change);
@@ -268,6 +291,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
268 u64 beacon_timestamp, rx_timestamp; 291 u64 beacon_timestamp, rx_timestamp;
269 u32 supp_rates = 0; 292 u32 supp_rates = 0;
270 enum ieee80211_band band = rx_status->band; 293 enum ieee80211_band band = rx_status->band;
294 struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
295 bool rates_updated = false;
271 296
272 if (elems->ds_params && elems->ds_params_len == 1) 297 if (elems->ds_params && elems->ds_params_len == 1)
273 freq = ieee80211_channel_to_frequency(elems->ds_params[0], 298 freq = ieee80211_channel_to_frequency(elems->ds_params[0],
@@ -307,7 +332,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
307 prev_rates, 332 prev_rates,
308 sta->sta.supp_rates[band]); 333 sta->sta.supp_rates[band]);
309#endif 334#endif
310 rate_control_rate_init(sta); 335 rates_updated = true;
311 } 336 }
312 } else 337 } else
313 sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, 338 sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
@@ -318,6 +343,39 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
318 if (sta && elems->wmm_info) 343 if (sta && elems->wmm_info)
319 set_sta_flag(sta, WLAN_STA_WME); 344 set_sta_flag(sta, WLAN_STA_WME);
320 345
346 if (sta && elems->ht_info_elem && elems->ht_cap_elem &&
347 sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
348 /* we both use HT */
349 struct ieee80211_sta_ht_cap sta_ht_cap_new;
350 enum nl80211_channel_type channel_type =
351 ieee80211_ht_info_to_channel_type(
352 elems->ht_info_elem);
353
354 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
355 elems->ht_cap_elem,
356 &sta_ht_cap_new);
357
358 /*
359 * fall back to HT20 if we don't use or use
360 * the other extension channel
361 */
362 if ((channel_type == NL80211_CHAN_HT40MINUS ||
363 channel_type == NL80211_CHAN_HT40PLUS) &&
364 channel_type != sdata->u.ibss.channel_type)
365 sta_ht_cap_new.cap &=
366 ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
367
368 if (memcmp(&sta->sta.ht_cap, &sta_ht_cap_new,
369 sizeof(sta_ht_cap_new))) {
370 memcpy(&sta->sta.ht_cap, &sta_ht_cap_new,
371 sizeof(sta_ht_cap_new));
372 rates_updated = true;
373 }
374 }
375
376 if (sta && rates_updated)
377 rate_control_rate_init(sta);
378
321 rcu_read_unlock(); 379 rcu_read_unlock();
322 } 380 }
323 381
@@ -899,10 +957,15 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
899 u32 changed = 0; 957 u32 changed = 0;
900 958
901 skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom + 959 skb = dev_alloc_skb(sdata->local->hw.extra_tx_headroom +
902 36 /* bitrates */ + 960 sizeof(struct ieee80211_hdr_3addr) +
903 34 /* SSID */ + 961 12 /* struct ieee80211_mgmt.u.beacon */ +
904 3 /* DS params */ + 962 2 + IEEE80211_MAX_SSID_LEN /* max SSID */ +
905 4 /* IBSS params */ + 963 2 + 8 /* max Supported Rates */ +
964 3 /* max DS params */ +
965 4 /* IBSS params */ +
966 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
967 2 + sizeof(struct ieee80211_ht_cap) +
968 2 + sizeof(struct ieee80211_ht_info) +
906 params->ie_len); 969 params->ie_len);
907 if (!skb) 970 if (!skb)
908 return -ENOMEM; 971 return -ENOMEM;
@@ -923,13 +986,15 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
923 sdata->vif.bss_conf.beacon_int = params->beacon_interval; 986 sdata->vif.bss_conf.beacon_int = params->beacon_interval;
924 987
925 sdata->u.ibss.channel = params->channel; 988 sdata->u.ibss.channel = params->channel;
989 sdata->u.ibss.channel_type = params->channel_type;
926 sdata->u.ibss.fixed_channel = params->channel_fixed; 990 sdata->u.ibss.fixed_channel = params->channel_fixed;
927 991
928 /* fix ourselves to that channel now already */ 992 /* fix ourselves to that channel now already */
929 if (params->channel_fixed) { 993 if (params->channel_fixed) {
930 sdata->local->oper_channel = params->channel; 994 sdata->local->oper_channel = params->channel;
931 WARN_ON(!ieee80211_set_channel_type(sdata->local, sdata, 995 if (!ieee80211_set_channel_type(sdata->local, sdata,
932 NL80211_CHAN_NO_HT)); 996 params->channel_type))
997 return -EINVAL;
933 } 998 }
934 999
935 if (params->ie) { 1000 if (params->ie) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index bdefa6ba3f4..96fe75410bb 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -474,6 +474,7 @@ struct ieee80211_if_ibss {
474 u8 ssid_len, ie_len; 474 u8 ssid_len, ie_len;
475 u8 *ie; 475 u8 *ie;
476 struct ieee80211_channel *channel; 476 struct ieee80211_channel *channel;
477 enum nl80211_channel_type channel_type;
477 478
478 unsigned long ibss_join_req; 479 unsigned long ibss_join_req;
479 /* probe response/beacon for IBSS */ 480 /* probe response/beacon for IBSS */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 24cc50b963a..60198ac664a 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -570,7 +570,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
570 WIPHY_FLAG_OFFCHAN_TX | 570 WIPHY_FLAG_OFFCHAN_TX |
571 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; 571 WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
572 572
573 wiphy->features = NL80211_FEATURE_SK_TX_STATUS; 573 wiphy->features = NL80211_FEATURE_SK_TX_STATUS |
574 NL80211_FEATURE_HT_IBSS;
574 575
575 if (!ops->set_key) 576 if (!ops->set_key)
576 wiphy->flags |= WIPHY_FLAG_IBSS_RSN; 577 wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index daf5cde65b3..2a85fdfebde 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2237,7 +2237,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
2237 if (sdata->vif.type != NL80211_IFTYPE_STATION && 2237 if (sdata->vif.type != NL80211_IFTYPE_STATION &&
2238 sdata->vif.type != NL80211_IFTYPE_MESH_POINT && 2238 sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
2239 sdata->vif.type != NL80211_IFTYPE_AP_VLAN && 2239 sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
2240 sdata->vif.type != NL80211_IFTYPE_AP) 2240 sdata->vif.type != NL80211_IFTYPE_AP &&
2241 sdata->vif.type != NL80211_IFTYPE_ADHOC)
2241 break; 2242 break;
2242 2243
2243 /* verify action_code is present */ 2244 /* verify action_code is present */