summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/ibss.c185
1 files changed, 109 insertions, 76 deletions
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 79e294e9b5cc..74de0f10558a 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 37static struct beacon_data *
38static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, 38ieee80211_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,94 @@ 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;
197error:
198 kfree(presp);
199 return NULL;
200}
201
202static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
203 const u8 *bssid, const int beacon_int,
204 struct ieee80211_channel *chan,
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 beacon_data *presp;
217 enum nl80211_bss_scan_width scan_width;
218 bool have_higher_than_11mbit;
219
220 sdata_assert_lock(sdata);
221
222 /* Reset own TSF to allow time synchronization work. */
223 drv_reset_tsf(local, sdata);
224
225 if (!ether_addr_equal(ifibss->bssid, bssid))
226 sta_info_flush(sdata);
227
228 /* if merging, indicate to driver that we leave the old IBSS */
229 if (sdata->vif.bss_conf.ibss_joined) {
230 sdata->vif.bss_conf.ibss_joined = false;
231 sdata->vif.bss_conf.ibss_creator = false;
232 sdata->vif.bss_conf.enable_beacon = false;
233 netif_carrier_off(sdata->dev);
234 ieee80211_bss_info_change_notify(sdata,
235 BSS_CHANGED_IBSS |
236 BSS_CHANGED_BEACON_ENABLED);
237 }
238
239 presp = rcu_dereference_protected(ifibss->presp,
240 lockdep_is_held(&sdata->wdev.mtx));
241 rcu_assign_pointer(ifibss->presp, NULL);
242 if (presp)
243 kfree_rcu(presp, rcu_head);
244
245 sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
246
247 chandef = ifibss->chandef;
248 if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
249 if (chandef.width == NL80211_CHAN_WIDTH_5 ||
250 chandef.width == NL80211_CHAN_WIDTH_10 ||
251 chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
252 chandef.width == NL80211_CHAN_WIDTH_20) {
253 sdata_info(sdata,
254 "Failed to join IBSS, beacons forbidden\n");
255 return;
256 }
257 chandef.width = NL80211_CHAN_WIDTH_20;
258 chandef.center_freq1 = chan->center_freq;
259 }
260
261 ieee80211_vif_release_channel(sdata);
262 if (ieee80211_vif_use_channel(sdata, &chandef,
263 ifibss->fixed_channel ?
264 IEEE80211_CHANCTX_SHARED :
265 IEEE80211_CHANCTX_EXCLUSIVE)) {
266 sdata_info(sdata, "Failed to join IBSS, no channel context\n");
267 return;
268 }
269
270 memcpy(ifibss->bssid, bssid, ETH_ALEN);
271
272 sband = local->hw.wiphy->bands[chan->band];
273
274 presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,
275 capability, tsf, &chandef,
276 &have_higher_than_11mbit);
277 if (!presp)
246 return; 278 return;
247 279
248 rcu_assign_pointer(ifibss->presp, presp); 280 rcu_assign_pointer(ifibss->presp, presp);
281 mgmt = (void *)presp->head;
249 282
250 sdata->vif.bss_conf.enable_beacon = true; 283 sdata->vif.bss_conf.enable_beacon = true;
251 sdata->vif.bss_conf.beacon_int = beacon_int; 284 sdata->vif.bss_conf.beacon_int = beacon_int;