diff options
Diffstat (limited to 'net/mac80211/ibss.c')
-rw-r--r-- | net/mac80211/ibss.c | 226 |
1 files changed, 148 insertions, 78 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index e08387cdc8fd..a12afe77bb26 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -34,13 +34,12 @@ | |||
34 | 34 | ||
35 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | 35 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 |
36 | 36 | ||
37 | 37 | static struct beacon_data * | |
38 | static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 38 | ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata, |
39 | const u8 *bssid, const int beacon_int, | 39 | const int beacon_int, const u32 basic_rates, |
40 | struct ieee80211_channel *chan, | 40 | const u16 capability, u64 tsf, |
41 | const u32 basic_rates, | 41 | struct cfg80211_chan_def *chandef, |
42 | const u16 capability, u64 tsf, | 42 | bool *have_higher_than_11mbit) |
43 | bool creator) | ||
44 | { | 43 | { |
45 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 44 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
46 | struct ieee80211_local *local = sdata->local; | 45 | struct ieee80211_local *local = sdata->local; |
@@ -48,70 +47,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
48 | struct ieee80211_mgmt *mgmt; | 47 | struct ieee80211_mgmt *mgmt; |
49 | u8 *pos; | 48 | u8 *pos; |
50 | struct ieee80211_supported_band *sband; | 49 | struct ieee80211_supported_band *sband; |
51 | struct cfg80211_bss *bss; | 50 | u32 rate_flags, rates = 0, rates_added = 0; |
52 | u32 bss_change, rate_flags, rates = 0, rates_added = 0; | ||
53 | struct cfg80211_chan_def chandef; | ||
54 | enum nl80211_bss_scan_width scan_width; | ||
55 | bool have_higher_than_11mbit = false; | ||
56 | struct beacon_data *presp; | 51 | struct beacon_data *presp; |
57 | int frame_len; | 52 | int frame_len; |
58 | int shift; | 53 | int shift; |
59 | 54 | ||
60 | sdata_assert_lock(sdata); | ||
61 | |||
62 | /* Reset own TSF to allow time synchronization work. */ | ||
63 | drv_reset_tsf(local, sdata); | ||
64 | |||
65 | if (!ether_addr_equal(ifibss->bssid, bssid)) | ||
66 | sta_info_flush(sdata); | ||
67 | |||
68 | /* if merging, indicate to driver that we leave the old IBSS */ | ||
69 | if (sdata->vif.bss_conf.ibss_joined) { | ||
70 | sdata->vif.bss_conf.ibss_joined = false; | ||
71 | sdata->vif.bss_conf.ibss_creator = false; | ||
72 | sdata->vif.bss_conf.enable_beacon = false; | ||
73 | netif_carrier_off(sdata->dev); | ||
74 | ieee80211_bss_info_change_notify(sdata, | ||
75 | BSS_CHANGED_IBSS | | ||
76 | BSS_CHANGED_BEACON_ENABLED); | ||
77 | } | ||
78 | |||
79 | presp = rcu_dereference_protected(ifibss->presp, | ||
80 | lockdep_is_held(&sdata->wdev.mtx)); | ||
81 | rcu_assign_pointer(ifibss->presp, NULL); | ||
82 | if (presp) | ||
83 | kfree_rcu(presp, rcu_head); | ||
84 | |||
85 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
86 | |||
87 | chandef = ifibss->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 | } | ||
97 | chandef.width = NL80211_CHAN_WIDTH_20; | ||
98 | chandef.center_freq1 = chan->center_freq; | ||
99 | } | ||
100 | |||
101 | ieee80211_vif_release_channel(sdata); | ||
102 | if (ieee80211_vif_use_channel(sdata, &chandef, | ||
103 | ifibss->fixed_channel ? | ||
104 | IEEE80211_CHANCTX_SHARED : | ||
105 | IEEE80211_CHANCTX_EXCLUSIVE)) { | ||
106 | sdata_info(sdata, "Failed to join IBSS, no channel context\n"); | ||
107 | return; | ||
108 | } | ||
109 | |||
110 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | ||
111 | |||
112 | sband = local->hw.wiphy->bands[chan->band]; | ||
113 | shift = ieee80211_vif_get_shift(&sdata->vif); | ||
114 | |||
115 | /* Build IBSS probe response */ | 55 | /* Build IBSS probe response */ |
116 | frame_len = sizeof(struct ieee80211_hdr_3addr) + | 56 | frame_len = sizeof(struct ieee80211_hdr_3addr) + |
117 | 12 /* struct ieee80211_mgmt.u.beacon */ + | 57 | 12 /* struct ieee80211_mgmt.u.beacon */ + |
@@ -125,7 +65,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
125 | ifibss->ie_len; | 65 | ifibss->ie_len; |
126 | presp = kzalloc(sizeof(*presp) + frame_len, GFP_KERNEL); | 66 | presp = kzalloc(sizeof(*presp) + frame_len, GFP_KERNEL); |
127 | if (!presp) | 67 | if (!presp) |
128 | return; | 68 | return NULL; |
129 | 69 | ||
130 | presp->head = (void *)(presp + 1); | 70 | presp->head = (void *)(presp + 1); |
131 | 71 | ||
@@ -146,12 +86,19 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
146 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); | 86 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); |
147 | pos += ifibss->ssid_len; | 87 | pos += ifibss->ssid_len; |
148 | 88 | ||
149 | rate_flags = ieee80211_chandef_rate_flags(&chandef); | 89 | sband = local->hw.wiphy->bands[chandef->chan->band]; |
90 | rate_flags = ieee80211_chandef_rate_flags(chandef); | ||
91 | shift = ieee80211_chandef_get_shift(chandef); | ||
92 | rates_n = 0; | ||
93 | if (have_higher_than_11mbit) | ||
94 | *have_higher_than_11mbit = false; | ||
95 | |||
150 | for (i = 0; i < sband->n_bitrates; i++) { | 96 | for (i = 0; i < sband->n_bitrates; i++) { |
151 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) | 97 | if ((rate_flags & sband->bitrates[i].flags) != rate_flags) |
152 | continue; | 98 | continue; |
153 | if (sband->bitrates[i].bitrate > 110) | 99 | if (sband->bitrates[i].bitrate > 110 && |
154 | have_higher_than_11mbit = true; | 100 | have_higher_than_11mbit) |
101 | *have_higher_than_11mbit = true; | ||
155 | 102 | ||
156 | rates |= BIT(i); | 103 | rates |= BIT(i); |
157 | rates_n++; | 104 | rates_n++; |
@@ -178,7 +125,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
178 | if (sband->band == IEEE80211_BAND_2GHZ) { | 125 | if (sband->band == IEEE80211_BAND_2GHZ) { |
179 | *pos++ = WLAN_EID_DS_PARAMS; | 126 | *pos++ = WLAN_EID_DS_PARAMS; |
180 | *pos++ = 1; | 127 | *pos++ = 1; |
181 | *pos++ = ieee80211_frequency_to_channel(chan->center_freq); | 128 | *pos++ = ieee80211_frequency_to_channel( |
129 | chandef->chan->center_freq); | ||
182 | } | 130 | } |
183 | 131 | ||
184 | *pos++ = WLAN_EID_IBSS_PARAMS; | 132 | *pos++ = WLAN_EID_IBSS_PARAMS; |
@@ -210,9 +158,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
210 | } | 158 | } |
211 | 159 | ||
212 | /* add HT capability and information IEs */ | 160 | /* add HT capability and information IEs */ |
213 | if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT && | 161 | if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT && |
214 | chandef.width != NL80211_CHAN_WIDTH_5 && | 162 | chandef->width != NL80211_CHAN_WIDTH_5 && |
215 | chandef.width != NL80211_CHAN_WIDTH_10 && | 163 | chandef->width != NL80211_CHAN_WIDTH_10 && |
216 | sband->ht_cap.ht_supported) { | 164 | sband->ht_cap.ht_supported) { |
217 | struct ieee80211_sta_ht_cap ht_cap; | 165 | struct ieee80211_sta_ht_cap ht_cap; |
218 | 166 | ||
@@ -226,7 +174,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
226 | * keep them at 0 | 174 | * keep them at 0 |
227 | */ | 175 | */ |
228 | pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, | 176 | pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, |
229 | &chandef, 0); | 177 | chandef, 0); |
230 | } | 178 | } |
231 | 179 | ||
232 | if (local->hw.queues >= IEEE80211_NUM_ACS) { | 180 | if (local->hw.queues >= IEEE80211_NUM_ACS) { |
@@ -243,9 +191,97 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
243 | 191 | ||
244 | presp->head_len = pos - presp->head; | 192 | presp->head_len = pos - presp->head; |
245 | if (WARN_ON(presp->head_len > frame_len)) | 193 | if (WARN_ON(presp->head_len > frame_len)) |
194 | goto error; | ||
195 | |||
196 | return presp; | ||
197 | error: | ||
198 | kfree(presp); | ||
199 | return NULL; | ||
200 | } | ||
201 | |||
202 | static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||
203 | const u8 *bssid, const int beacon_int, | ||
204 | struct cfg80211_chan_def *req_chandef, | ||
205 | const u32 basic_rates, | ||
206 | const u16 capability, u64 tsf, | ||
207 | bool creator) | ||
208 | { | ||
209 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
210 | struct ieee80211_local *local = sdata->local; | ||
211 | struct ieee80211_supported_band *sband; | ||
212 | struct ieee80211_mgmt *mgmt; | ||
213 | struct cfg80211_bss *bss; | ||
214 | u32 bss_change; | ||
215 | struct cfg80211_chan_def chandef; | ||
216 | struct ieee80211_channel *chan; | ||
217 | struct beacon_data *presp; | ||
218 | enum nl80211_bss_scan_width scan_width; | ||
219 | bool have_higher_than_11mbit; | ||
220 | |||
221 | sdata_assert_lock(sdata); | ||
222 | |||
223 | /* Reset own TSF to allow time synchronization work. */ | ||
224 | drv_reset_tsf(local, sdata); | ||
225 | |||
226 | if (!ether_addr_equal(ifibss->bssid, bssid)) | ||
227 | sta_info_flush(sdata); | ||
228 | |||
229 | /* if merging, indicate to driver that we leave the old IBSS */ | ||
230 | if (sdata->vif.bss_conf.ibss_joined) { | ||
231 | sdata->vif.bss_conf.ibss_joined = false; | ||
232 | sdata->vif.bss_conf.ibss_creator = false; | ||
233 | sdata->vif.bss_conf.enable_beacon = false; | ||
234 | netif_carrier_off(sdata->dev); | ||
235 | ieee80211_bss_info_change_notify(sdata, | ||
236 | BSS_CHANGED_IBSS | | ||
237 | BSS_CHANGED_BEACON_ENABLED); | ||
238 | } | ||
239 | |||
240 | presp = rcu_dereference_protected(ifibss->presp, | ||
241 | lockdep_is_held(&sdata->wdev.mtx)); | ||
242 | rcu_assign_pointer(ifibss->presp, NULL); | ||
243 | if (presp) | ||
244 | kfree_rcu(presp, rcu_head); | ||
245 | |||
246 | sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
247 | |||
248 | /* make a copy of the chandef, it could be modified below. */ | ||
249 | chandef = *req_chandef; | ||
250 | chan = chandef.chan; | ||
251 | if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { | ||
252 | if (chandef.width == NL80211_CHAN_WIDTH_5 || | ||
253 | chandef.width == NL80211_CHAN_WIDTH_10 || | ||
254 | chandef.width == NL80211_CHAN_WIDTH_20_NOHT || | ||
255 | chandef.width == NL80211_CHAN_WIDTH_20) { | ||
256 | sdata_info(sdata, | ||
257 | "Failed to join IBSS, beacons forbidden\n"); | ||
258 | return; | ||
259 | } | ||
260 | chandef.width = NL80211_CHAN_WIDTH_20; | ||
261 | chandef.center_freq1 = chan->center_freq; | ||
262 | } | ||
263 | |||
264 | ieee80211_vif_release_channel(sdata); | ||
265 | if (ieee80211_vif_use_channel(sdata, &chandef, | ||
266 | ifibss->fixed_channel ? | ||
267 | IEEE80211_CHANCTX_SHARED : | ||
268 | IEEE80211_CHANCTX_EXCLUSIVE)) { | ||
269 | sdata_info(sdata, "Failed to join IBSS, no channel context\n"); | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | ||
274 | |||
275 | sband = local->hw.wiphy->bands[chan->band]; | ||
276 | |||
277 | presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates, | ||
278 | capability, tsf, &chandef, | ||
279 | &have_higher_than_11mbit); | ||
280 | if (!presp) | ||
246 | return; | 281 | return; |
247 | 282 | ||
248 | rcu_assign_pointer(ifibss->presp, presp); | 283 | rcu_assign_pointer(ifibss->presp, presp); |
284 | mgmt = (void *)presp->head; | ||
249 | 285 | ||
250 | sdata->vif.bss_conf.enable_beacon = true; | 286 | sdata->vif.bss_conf.enable_beacon = true; |
251 | sdata->vif.bss_conf.beacon_int = beacon_int; | 287 | sdata->vif.bss_conf.beacon_int = beacon_int; |
@@ -306,10 +342,12 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
306 | struct cfg80211_bss *cbss = | 342 | struct cfg80211_bss *cbss = |
307 | container_of((void *)bss, struct cfg80211_bss, priv); | 343 | container_of((void *)bss, struct cfg80211_bss, priv); |
308 | struct ieee80211_supported_band *sband; | 344 | struct ieee80211_supported_band *sband; |
345 | struct cfg80211_chan_def chandef; | ||
309 | u32 basic_rates; | 346 | u32 basic_rates; |
310 | int i, j; | 347 | int i, j; |
311 | u16 beacon_int = cbss->beacon_interval; | 348 | u16 beacon_int = cbss->beacon_interval; |
312 | const struct cfg80211_bss_ies *ies; | 349 | const struct cfg80211_bss_ies *ies; |
350 | enum nl80211_channel_type chan_type; | ||
313 | u64 tsf; | 351 | u64 tsf; |
314 | u32 rate_flags; | 352 | u32 rate_flags; |
315 | int shift; | 353 | int shift; |
@@ -319,6 +357,26 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
319 | if (beacon_int < 10) | 357 | if (beacon_int < 10) |
320 | beacon_int = 10; | 358 | beacon_int = 10; |
321 | 359 | ||
360 | switch (sdata->u.ibss.chandef.width) { | ||
361 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
362 | case NL80211_CHAN_WIDTH_20: | ||
363 | case NL80211_CHAN_WIDTH_40: | ||
364 | chan_type = cfg80211_get_chandef_type(&sdata->u.ibss.chandef); | ||
365 | cfg80211_chandef_create(&chandef, cbss->channel, chan_type); | ||
366 | break; | ||
367 | case NL80211_CHAN_WIDTH_5: | ||
368 | case NL80211_CHAN_WIDTH_10: | ||
369 | cfg80211_chandef_create(&chandef, cbss->channel, | ||
370 | NL80211_CHAN_WIDTH_20_NOHT); | ||
371 | chandef.width = sdata->u.ibss.chandef.width; | ||
372 | break; | ||
373 | default: | ||
374 | /* fall back to 20 MHz for unsupported modes */ | ||
375 | cfg80211_chandef_create(&chandef, cbss->channel, | ||
376 | NL80211_CHAN_WIDTH_20_NOHT); | ||
377 | break; | ||
378 | } | ||
379 | |||
322 | sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; | 380 | sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; |
323 | rate_flags = ieee80211_chandef_rate_flags(&sdata->u.ibss.chandef); | 381 | rate_flags = ieee80211_chandef_rate_flags(&sdata->u.ibss.chandef); |
324 | shift = ieee80211_vif_get_shift(&sdata->vif); | 382 | shift = ieee80211_vif_get_shift(&sdata->vif); |
@@ -352,7 +410,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
352 | 410 | ||
353 | __ieee80211_sta_join_ibss(sdata, cbss->bssid, | 411 | __ieee80211_sta_join_ibss(sdata, cbss->bssid, |
354 | beacon_int, | 412 | beacon_int, |
355 | cbss->channel, | 413 | &chandef, |
356 | basic_rates, | 414 | basic_rates, |
357 | cbss->capability, | 415 | cbss->capability, |
358 | tsf, false); | 416 | tsf, false); |
@@ -834,7 +892,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
834 | sdata->drop_unencrypted = 0; | 892 | sdata->drop_unencrypted = 0; |
835 | 893 | ||
836 | __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, | 894 | __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int, |
837 | ifibss->chandef.chan, ifibss->basic_rates, | 895 | &ifibss->chandef, ifibss->basic_rates, |
838 | capability, 0, true); | 896 | capability, 0, true); |
839 | } | 897 | } |
840 | 898 | ||
@@ -891,6 +949,17 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
891 | return; | 949 | return; |
892 | } | 950 | } |
893 | 951 | ||
952 | /* if a fixed bssid and a fixed freq have been provided create the IBSS | ||
953 | * directly and do not waste time scanning | ||
954 | */ | ||
955 | if (ifibss->fixed_bssid && ifibss->fixed_channel) { | ||
956 | sdata_info(sdata, "Created IBSS using preconfigured BSSID %pM\n", | ||
957 | bssid); | ||
958 | ieee80211_sta_create_ibss(sdata); | ||
959 | return; | ||
960 | } | ||
961 | |||
962 | |||
894 | ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n"); | 963 | ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n"); |
895 | 964 | ||
896 | /* Selected IBSS not found in current scan results - try to scan */ | 965 | /* Selected IBSS not found in current scan results - try to scan */ |
@@ -1260,6 +1329,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata) | |||
1260 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); | 1329 | clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); |
1261 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | | 1330 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED | |
1262 | BSS_CHANGED_IBSS); | 1331 | BSS_CHANGED_IBSS); |
1332 | ieee80211_vif_release_channel(sdata); | ||
1263 | synchronize_rcu(); | 1333 | synchronize_rcu(); |
1264 | kfree(presp); | 1334 | kfree(presp); |
1265 | 1335 | ||