diff options
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r-- | net/mac80211/ibss.c | 184 |
1 files changed, 153 insertions, 31 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index ea7b9c2c7e66..e08387cdc8fd 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | 31 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) |
32 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | 32 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) |
33 | #define IEEE80211_IBSS_RSN_INACTIVITY_LIMIT (10 * HZ) | ||
33 | 34 | ||
34 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | 35 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 |
35 | 36 | ||
@@ -43,16 +44,18 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
43 | { | 44 | { |
44 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 45 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
45 | struct ieee80211_local *local = sdata->local; | 46 | struct ieee80211_local *local = sdata->local; |
46 | int rates, i; | 47 | int rates_n = 0, i, ri; |
47 | struct ieee80211_mgmt *mgmt; | 48 | struct ieee80211_mgmt *mgmt; |
48 | u8 *pos; | 49 | u8 *pos; |
49 | struct ieee80211_supported_band *sband; | 50 | struct ieee80211_supported_band *sband; |
50 | struct cfg80211_bss *bss; | 51 | struct cfg80211_bss *bss; |
51 | u32 bss_change; | 52 | u32 bss_change, rate_flags, rates = 0, rates_added = 0; |
52 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | ||
53 | struct cfg80211_chan_def chandef; | 53 | struct cfg80211_chan_def chandef; |
54 | enum nl80211_bss_scan_width scan_width; | ||
55 | bool have_higher_than_11mbit = false; | ||
54 | struct beacon_data *presp; | 56 | struct beacon_data *presp; |
55 | int frame_len; | 57 | int frame_len; |
58 | int shift; | ||
56 | 59 | ||
57 | sdata_assert_lock(sdata); | 60 | sdata_assert_lock(sdata); |
58 | 61 | ||
@@ -83,6 +86,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
83 | 86 | ||
84 | chandef = ifibss->chandef; | 87 | chandef = ifibss->chandef; |
85 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { | 88 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { |
89 | if (chandef.width == NL80211_CHAN_WIDTH_5 || | ||
90 | chandef.width == NL80211_CHAN_WIDTH_10 || | ||
91 | chandef.width == NL80211_CHAN_WIDTH_20_NOHT || | ||
92 | chandef.width == NL80211_CHAN_WIDTH_20) { | ||
93 | sdata_info(sdata, | ||
94 | "Failed to join IBSS, beacons forbidden\n"); | ||
95 | return; | ||
96 | } | ||
86 | chandef.width = NL80211_CHAN_WIDTH_20; | 97 | chandef.width = NL80211_CHAN_WIDTH_20; |
87 | chandef.center_freq1 = chan->center_freq; | 98 | chandef.center_freq1 = chan->center_freq; |
88 | } | 99 | } |
@@ -99,6 +110,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
99 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | 110 | memcpy(ifibss->bssid, bssid, ETH_ALEN); |
100 | 111 | ||
101 | sband = local->hw.wiphy->bands[chan->band]; | 112 | sband = local->hw.wiphy->bands[chan->band]; |
113 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
102 | 114 | ||
103 | /* Build IBSS probe response */ | 115 | /* Build IBSS probe response */ |
104 | frame_len = sizeof(struct ieee80211_hdr_3addr) + | 116 | frame_len = sizeof(struct ieee80211_hdr_3addr) + |
@@ -134,15 +146,33 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
134 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); | 146 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); |
135 | pos += ifibss->ssid_len; | 147 | pos += ifibss->ssid_len; |
136 | 148 | ||
137 | rates = min_t(int, 8, sband->n_bitrates); | 149 | rate_flags = ieee80211_chandef_rate_flags(&chandef); |
150 | for (i = 0; i < sband->n_bitrates; i++) { | ||
151 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
152 | continue; | ||
153 | if (sband->bitrates[i].bitrate > 110) | ||
154 | have_higher_than_11mbit = true; | ||
155 | |||
156 | rates |= BIT(i); | ||
157 | rates_n++; | ||
158 | } | ||
159 | |||
138 | *pos++ = WLAN_EID_SUPP_RATES; | 160 | *pos++ = WLAN_EID_SUPP_RATES; |
139 | *pos++ = rates; | 161 | *pos++ = min_t(int, 8, rates_n); |
140 | for (i = 0; i < rates; i++) { | 162 | for (ri = 0; ri < sband->n_bitrates; ri++) { |
141 | int rate = sband->bitrates[i].bitrate; | 163 | int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate, |
164 | 5 * (1 << shift)); | ||
142 | u8 basic = 0; | 165 | u8 basic = 0; |
143 | if (basic_rates & BIT(i)) | 166 | if (!(rates & BIT(ri))) |
167 | continue; | ||
168 | |||
169 | if (basic_rates & BIT(ri)) | ||
144 | basic = 0x80; | 170 | basic = 0x80; |
145 | *pos++ = basic | (u8) (rate / 5); | 171 | *pos++ = basic | (u8) rate; |
172 | if (++rates_added == 8) { | ||
173 | ri++; /* continue at next rate for EXT_SUPP_RATES */ | ||
174 | break; | ||
175 | } | ||
146 | } | 176 | } |
147 | 177 | ||
148 | if (sband->band == IEEE80211_BAND_2GHZ) { | 178 | if (sband->band == IEEE80211_BAND_2GHZ) { |
@@ -157,15 +187,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
157 | *pos++ = 0; | 187 | *pos++ = 0; |
158 | *pos++ = 0; | 188 | *pos++ = 0; |
159 | 189 | ||
160 | if (sband->n_bitrates > 8) { | 190 | /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */ |
191 | if (rates_n > 8) { | ||
161 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 192 | *pos++ = WLAN_EID_EXT_SUPP_RATES; |
162 | *pos++ = sband->n_bitrates - 8; | 193 | *pos++ = rates_n - 8; |
163 | for (i = 8; i < sband->n_bitrates; i++) { | 194 | for (; ri < sband->n_bitrates; ri++) { |
164 | int rate = sband->bitrates[i].bitrate; | 195 | int rate = DIV_ROUND_UP(sband->bitrates[ri].bitrate, |
196 | 5 * (1 << shift)); | ||
165 | u8 basic = 0; | 197 | u8 basic = 0; |
166 | if (basic_rates & BIT(i)) | 198 | if (!(rates & BIT(ri))) |
199 | continue; | ||
200 | |||
201 | if (basic_rates & BIT(ri)) | ||
167 | basic = 0x80; | 202 | basic = 0x80; |
168 | *pos++ = basic | (u8) (rate / 5); | 203 | *pos++ = basic | (u8) rate; |
169 | } | 204 | } |
170 | } | 205 | } |
171 | 206 | ||
@@ -179,8 +214,12 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
179 | chandef.width != NL80211_CHAN_WIDTH_5 && | 214 | chandef.width != NL80211_CHAN_WIDTH_5 && |
180 | chandef.width != NL80211_CHAN_WIDTH_10 && | 215 | chandef.width != NL80211_CHAN_WIDTH_10 && |
181 | sband->ht_cap.ht_supported) { | 216 | sband->ht_cap.ht_supported) { |
182 | pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, | 217 | struct ieee80211_sta_ht_cap ht_cap; |
183 | sband->ht_cap.cap); | 218 | |
219 | memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); | ||
220 | ieee80211_apply_htcap_overrides(sdata, &ht_cap); | ||
221 | |||
222 | pos = ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); | ||
184 | /* | 223 | /* |
185 | * Note: According to 802.11n-2009 9.13.3.1, HT Protection | 224 | * Note: According to 802.11n-2009 9.13.3.1, HT Protection |
186 | * field and RIFS Mode are reserved in IBSS mode, therefore | 225 | * field and RIFS Mode are reserved in IBSS mode, therefore |
@@ -236,18 +275,26 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
236 | sdata->vif.bss_conf.use_short_slot = chan->band == IEEE80211_BAND_5GHZ; | 275 | sdata->vif.bss_conf.use_short_slot = chan->band == IEEE80211_BAND_5GHZ; |
237 | bss_change |= BSS_CHANGED_ERP_SLOT; | 276 | bss_change |= BSS_CHANGED_ERP_SLOT; |
238 | 277 | ||
278 | /* cf. IEEE 802.11 9.2.12 */ | ||
279 | if (chan->band == IEEE80211_BAND_2GHZ && have_higher_than_11mbit) | ||
280 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
281 | else | ||
282 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | ||
283 | |||
239 | sdata->vif.bss_conf.ibss_joined = true; | 284 | sdata->vif.bss_conf.ibss_joined = true; |
240 | sdata->vif.bss_conf.ibss_creator = creator; | 285 | sdata->vif.bss_conf.ibss_creator = creator; |
241 | ieee80211_bss_info_change_notify(sdata, bss_change); | 286 | ieee80211_bss_info_change_notify(sdata, bss_change); |
242 | 287 | ||
243 | ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates); | 288 | ieee80211_set_wmm_default(sdata, true); |
244 | 289 | ||
245 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; | 290 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; |
246 | mod_timer(&ifibss->timer, | 291 | mod_timer(&ifibss->timer, |
247 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | 292 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); |
248 | 293 | ||
249 | bss = cfg80211_inform_bss_frame(local->hw.wiphy, chan, | 294 | scan_width = cfg80211_chandef_to_scan_width(&chandef); |
250 | mgmt, presp->head_len, 0, GFP_KERNEL); | 295 | bss = cfg80211_inform_bss_width_frame(local->hw.wiphy, chan, |
296 | scan_width, mgmt, | ||
297 | presp->head_len, 0, GFP_KERNEL); | ||
251 | cfg80211_put_bss(local->hw.wiphy, bss); | 298 | cfg80211_put_bss(local->hw.wiphy, bss); |
252 | netif_carrier_on(sdata->dev); | 299 | netif_carrier_on(sdata->dev); |
253 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); | 300 | cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); |
@@ -264,6 +311,8 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
264 | u16 beacon_int = cbss->beacon_interval; | 311 | u16 beacon_int = cbss->beacon_interval; |
265 | const struct cfg80211_bss_ies *ies; | 312 | const struct cfg80211_bss_ies *ies; |
266 | u64 tsf; | 313 | u64 tsf; |
314 | u32 rate_flags; | ||
315 | int shift; | ||
267 | 316 | ||
268 | sdata_assert_lock(sdata); | 317 | sdata_assert_lock(sdata); |
269 | 318 | ||
@@ -271,15 +320,24 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
271 | beacon_int = 10; | 320 | beacon_int = 10; |
272 | 321 | ||
273 | sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; | 322 | sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; |
323 | rate_flags = ieee80211_chandef_rate_flags(&sdata->u.ibss.chandef); | ||
324 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
274 | 325 | ||
275 | basic_rates = 0; | 326 | basic_rates = 0; |
276 | 327 | ||
277 | for (i = 0; i < bss->supp_rates_len; i++) { | 328 | for (i = 0; i < bss->supp_rates_len; i++) { |
278 | int rate = (bss->supp_rates[i] & 0x7f) * 5; | 329 | int rate = bss->supp_rates[i] & 0x7f; |
279 | bool is_basic = !!(bss->supp_rates[i] & 0x80); | 330 | bool is_basic = !!(bss->supp_rates[i] & 0x80); |
280 | 331 | ||
281 | for (j = 0; j < sband->n_bitrates; j++) { | 332 | for (j = 0; j < sband->n_bitrates; j++) { |
282 | if (sband->bitrates[j].bitrate == rate) { | 333 | int brate; |
334 | if ((rate_flags & sband->bitrates[j].flags) | ||
335 | != rate_flags) | ||
336 | continue; | ||
337 | |||
338 | brate = DIV_ROUND_UP(sband->bitrates[j].bitrate, | ||
339 | 5 * (1 << shift)); | ||
340 | if (brate == rate) { | ||
283 | if (is_basic) | 341 | if (is_basic) |
284 | basic_rates |= BIT(j); | 342 | basic_rates |= BIT(j); |
285 | break; | 343 | break; |
@@ -335,6 +393,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, | |||
335 | struct sta_info *sta; | 393 | struct sta_info *sta; |
336 | struct ieee80211_chanctx_conf *chanctx_conf; | 394 | struct ieee80211_chanctx_conf *chanctx_conf; |
337 | struct ieee80211_supported_band *sband; | 395 | struct ieee80211_supported_band *sband; |
396 | enum nl80211_bss_scan_width scan_width; | ||
338 | int band; | 397 | int band; |
339 | 398 | ||
340 | /* | 399 | /* |
@@ -363,6 +422,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, | |||
363 | if (WARN_ON_ONCE(!chanctx_conf)) | 422 | if (WARN_ON_ONCE(!chanctx_conf)) |
364 | return NULL; | 423 | return NULL; |
365 | band = chanctx_conf->def.chan->band; | 424 | band = chanctx_conf->def.chan->band; |
425 | scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); | ||
366 | rcu_read_unlock(); | 426 | rcu_read_unlock(); |
367 | 427 | ||
368 | sta = sta_info_alloc(sdata, addr, GFP_KERNEL); | 428 | sta = sta_info_alloc(sdata, addr, GFP_KERNEL); |
@@ -376,7 +436,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid, | |||
376 | /* make sure mandatory rates are always added */ | 436 | /* make sure mandatory rates are always added */ |
377 | sband = local->hw.wiphy->bands[band]; | 437 | sband = local->hw.wiphy->bands[band]; |
378 | sta->sta.supp_rates[band] = supp_rates | | 438 | sta->sta.supp_rates[band] = supp_rates | |
379 | ieee80211_mandatory_rates(sband); | 439 | ieee80211_mandatory_rates(sband, scan_width); |
380 | 440 | ||
381 | return ieee80211_ibss_finish_sta(sta); | 441 | return ieee80211_ibss_finish_sta(sta); |
382 | } | 442 | } |
@@ -440,6 +500,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
440 | u64 beacon_timestamp, rx_timestamp; | 500 | u64 beacon_timestamp, rx_timestamp; |
441 | u32 supp_rates = 0; | 501 | u32 supp_rates = 0; |
442 | enum ieee80211_band band = rx_status->band; | 502 | enum ieee80211_band band = rx_status->band; |
503 | enum nl80211_bss_scan_width scan_width; | ||
443 | struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; | 504 | struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; |
444 | bool rates_updated = false; | 505 | bool rates_updated = false; |
445 | 506 | ||
@@ -461,16 +522,22 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
461 | sta = sta_info_get(sdata, mgmt->sa); | 522 | sta = sta_info_get(sdata, mgmt->sa); |
462 | 523 | ||
463 | if (elems->supp_rates) { | 524 | if (elems->supp_rates) { |
464 | supp_rates = ieee80211_sta_get_rates(local, elems, | 525 | supp_rates = ieee80211_sta_get_rates(sdata, elems, |
465 | band, NULL); | 526 | band, NULL); |
466 | if (sta) { | 527 | if (sta) { |
467 | u32 prev_rates; | 528 | u32 prev_rates; |
468 | 529 | ||
469 | prev_rates = sta->sta.supp_rates[band]; | 530 | prev_rates = sta->sta.supp_rates[band]; |
470 | /* make sure mandatory rates are always added */ | 531 | /* make sure mandatory rates are always added */ |
471 | sta->sta.supp_rates[band] = supp_rates | | 532 | scan_width = NL80211_BSS_CHAN_WIDTH_20; |
472 | ieee80211_mandatory_rates(sband); | 533 | if (rx_status->flag & RX_FLAG_5MHZ) |
534 | scan_width = NL80211_BSS_CHAN_WIDTH_5; | ||
535 | if (rx_status->flag & RX_FLAG_10MHZ) | ||
536 | scan_width = NL80211_BSS_CHAN_WIDTH_10; | ||
473 | 537 | ||
538 | sta->sta.supp_rates[band] = supp_rates | | ||
539 | ieee80211_mandatory_rates(sband, | ||
540 | scan_width); | ||
474 | if (sta->sta.supp_rates[band] != prev_rates) { | 541 | if (sta->sta.supp_rates[band] != prev_rates) { |
475 | ibss_dbg(sdata, | 542 | ibss_dbg(sdata, |
476 | "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", | 543 | "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", |
@@ -585,7 +652,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
585 | "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n", | 652 | "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n", |
586 | mgmt->bssid); | 653 | mgmt->bssid); |
587 | ieee80211_sta_join_ibss(sdata, bss); | 654 | ieee80211_sta_join_ibss(sdata, bss); |
588 | supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL); | 655 | supp_rates = ieee80211_sta_get_rates(sdata, elems, band, NULL); |
589 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, | 656 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
590 | supp_rates); | 657 | supp_rates); |
591 | rcu_read_unlock(); | 658 | rcu_read_unlock(); |
@@ -604,6 +671,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
604 | struct sta_info *sta; | 671 | struct sta_info *sta; |
605 | struct ieee80211_chanctx_conf *chanctx_conf; | 672 | struct ieee80211_chanctx_conf *chanctx_conf; |
606 | struct ieee80211_supported_band *sband; | 673 | struct ieee80211_supported_band *sband; |
674 | enum nl80211_bss_scan_width scan_width; | ||
607 | int band; | 675 | int band; |
608 | 676 | ||
609 | /* | 677 | /* |
@@ -629,6 +697,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
629 | return; | 697 | return; |
630 | } | 698 | } |
631 | band = chanctx_conf->def.chan->band; | 699 | band = chanctx_conf->def.chan->band; |
700 | scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); | ||
632 | rcu_read_unlock(); | 701 | rcu_read_unlock(); |
633 | 702 | ||
634 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | 703 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); |
@@ -640,7 +709,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |||
640 | /* make sure mandatory rates are always added */ | 709 | /* make sure mandatory rates are always added */ |
641 | sband = local->hw.wiphy->bands[band]; | 710 | sband = local->hw.wiphy->bands[band]; |
642 | sta->sta.supp_rates[band] = supp_rates | | 711 | sta->sta.supp_rates[band] = supp_rates | |
643 | ieee80211_mandatory_rates(sband); | 712 | ieee80211_mandatory_rates(sband, scan_width); |
644 | 713 | ||
645 | spin_lock(&ifibss->incomplete_lock); | 714 | spin_lock(&ifibss->incomplete_lock); |
646 | list_add(&sta->list, &ifibss->incomplete_stations); | 715 | list_add(&sta->list, &ifibss->incomplete_stations); |
@@ -672,6 +741,33 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | |||
672 | return active; | 741 | return active; |
673 | } | 742 | } |
674 | 743 | ||
744 | static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata) | ||
745 | { | ||
746 | struct ieee80211_local *local = sdata->local; | ||
747 | struct sta_info *sta, *tmp; | ||
748 | unsigned long exp_time = IEEE80211_IBSS_INACTIVITY_LIMIT; | ||
749 | unsigned long exp_rsn_time = IEEE80211_IBSS_RSN_INACTIVITY_LIMIT; | ||
750 | |||
751 | mutex_lock(&local->sta_mtx); | ||
752 | |||
753 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | ||
754 | if (sdata != sta->sdata) | ||
755 | continue; | ||
756 | |||
757 | if (time_after(jiffies, sta->last_rx + exp_time) || | ||
758 | (time_after(jiffies, sta->last_rx + exp_rsn_time) && | ||
759 | sta->sta_state != IEEE80211_STA_AUTHORIZED)) { | ||
760 | sta_dbg(sta->sdata, "expiring inactive %sSTA %pM\n", | ||
761 | sta->sta_state != IEEE80211_STA_AUTHORIZED ? | ||
762 | "not authorized " : "", sta->sta.addr); | ||
763 | |||
764 | WARN_ON(__sta_info_destroy(sta)); | ||
765 | } | ||
766 | } | ||
767 | |||
768 | mutex_unlock(&local->sta_mtx); | ||
769 | } | ||
770 | |||
675 | /* | 771 | /* |
676 | * This function is called with state == IEEE80211_IBSS_MLME_JOINED | 772 | * This function is called with state == IEEE80211_IBSS_MLME_JOINED |
677 | */ | 773 | */ |
@@ -679,13 +775,14 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | |||
679 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | 775 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) |
680 | { | 776 | { |
681 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 777 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
778 | enum nl80211_bss_scan_width scan_width; | ||
682 | 779 | ||
683 | sdata_assert_lock(sdata); | 780 | sdata_assert_lock(sdata); |
684 | 781 | ||
685 | mod_timer(&ifibss->timer, | 782 | mod_timer(&ifibss->timer, |
686 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | 783 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); |
687 | 784 | ||
688 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | 785 | ieee80211_ibss_sta_expire(sdata); |
689 | 786 | ||
690 | if (time_before(jiffies, ifibss->last_scan_completed + | 787 | if (time_before(jiffies, ifibss->last_scan_completed + |
691 | IEEE80211_IBSS_MERGE_INTERVAL)) | 788 | IEEE80211_IBSS_MERGE_INTERVAL)) |
@@ -700,8 +797,9 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | |||
700 | sdata_info(sdata, | 797 | sdata_info(sdata, |
701 | "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); | 798 | "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); |
702 | 799 | ||
800 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); | ||
703 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, | 801 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len, |
704 | NULL); | 802 | NULL, scan_width); |
705 | } | 803 | } |
706 | 804 | ||
707 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | 805 | static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) |
@@ -751,6 +849,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
751 | struct cfg80211_bss *cbss; | 849 | struct cfg80211_bss *cbss; |
752 | struct ieee80211_channel *chan = NULL; | 850 | struct ieee80211_channel *chan = NULL; |
753 | const u8 *bssid = NULL; | 851 | const u8 *bssid = NULL; |
852 | enum nl80211_bss_scan_width scan_width; | ||
754 | int active_ibss; | 853 | int active_ibss; |
755 | u16 capability; | 854 | u16 capability; |
756 | 855 | ||
@@ -799,8 +898,10 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
799 | IEEE80211_SCAN_INTERVAL)) { | 898 | IEEE80211_SCAN_INTERVAL)) { |
800 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); | 899 | sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); |
801 | 900 | ||
901 | scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); | ||
802 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, | 902 | ieee80211_request_ibss_scan(sdata, ifibss->ssid, |
803 | ifibss->ssid_len, chan); | 903 | ifibss->ssid_len, chan, |
904 | scan_width); | ||
804 | } else { | 905 | } else { |
805 | int interval = IEEE80211_SCAN_INTERVAL; | 906 | int interval = IEEE80211_SCAN_INTERVAL; |
806 | 907 | ||
@@ -1020,6 +1121,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1020 | struct cfg80211_ibss_params *params) | 1121 | struct cfg80211_ibss_params *params) |
1021 | { | 1122 | { |
1022 | u32 changed = 0; | 1123 | u32 changed = 0; |
1124 | u32 rate_flags; | ||
1125 | struct ieee80211_supported_band *sband; | ||
1126 | int i; | ||
1023 | 1127 | ||
1024 | if (params->bssid) { | 1128 | if (params->bssid) { |
1025 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); | 1129 | memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN); |
@@ -1030,6 +1134,14 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1030 | sdata->u.ibss.privacy = params->privacy; | 1134 | sdata->u.ibss.privacy = params->privacy; |
1031 | sdata->u.ibss.control_port = params->control_port; | 1135 | sdata->u.ibss.control_port = params->control_port; |
1032 | sdata->u.ibss.basic_rates = params->basic_rates; | 1136 | sdata->u.ibss.basic_rates = params->basic_rates; |
1137 | |||
1138 | /* fix basic_rates if channel does not support these rates */ | ||
1139 | rate_flags = ieee80211_chandef_rate_flags(¶ms->chandef); | ||
1140 | sband = sdata->local->hw.wiphy->bands[params->chandef.chan->band]; | ||
1141 | for (i = 0; i < sband->n_bitrates; i++) { | ||
1142 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | ||
1143 | sdata->u.ibss.basic_rates &= ~BIT(i); | ||
1144 | } | ||
1033 | memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate, | 1145 | memcpy(sdata->vif.bss_conf.mcast_rate, params->mcast_rate, |
1034 | sizeof(params->mcast_rate)); | 1146 | sizeof(params->mcast_rate)); |
1035 | 1147 | ||
@@ -1051,6 +1163,11 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | |||
1051 | memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len); | 1163 | memcpy(sdata->u.ibss.ssid, params->ssid, params->ssid_len); |
1052 | sdata->u.ibss.ssid_len = params->ssid_len; | 1164 | sdata->u.ibss.ssid_len = params->ssid_len; |
1053 | 1165 | ||
1166 | memcpy(&sdata->u.ibss.ht_capa, ¶ms->ht_capa, | ||
1167 | sizeof(sdata->u.ibss.ht_capa)); | ||
1168 | memcpy(&sdata->u.ibss.ht_capa_mask, ¶ms->ht_capa_mask, | ||
1169 | sizeof(sdata->u.ibss.ht_capa_mask)); | ||
1170 | |||
1054 | /* | 1171 | /* |
1055 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is | 1172 | * 802.11n-2009 9.13.3.1: In an IBSS, the HT Protection field is |
1056 | * reserved, but an HT STA shall protect HT transmissions as though | 1173 | * reserved, but an HT STA shall protect HT transmissions as though |
@@ -1131,6 +1248,11 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1131 | presp = rcu_dereference_protected(ifibss->presp, | 1248 | presp = rcu_dereference_protected(ifibss->presp, |
1132 | lockdep_is_held(&sdata->wdev.mtx)); | 1249 | lockdep_is_held(&sdata->wdev.mtx)); |
1133 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); | 1250 | RCU_INIT_POINTER(sdata->u.ibss.presp, NULL); |
1251 | |||
1252 | /* on the next join, re-program HT parameters */ | ||
1253 | memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa)); | ||
1254 | memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask)); | ||
1255 | |||
1134 | sdata->vif.bss_conf.ibss_joined = false; | 1256 | sdata->vif.bss_conf.ibss_joined = false; |
1135 | sdata->vif.bss_conf.ibss_creator = false; | 1257 | sdata->vif.bss_conf.ibss_creator = false; |
1136 | sdata->vif.bss_conf.enable_beacon = false; | 1258 | sdata->vif.bss_conf.enable_beacon = false; |