aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/mesh.c223
-rw-r--r--net/mac80211/mesh.h14
-rw-r--r--net/mac80211/mesh_plink.c7
-rw-r--r--net/mac80211/tx.c14
4 files changed, 196 insertions, 62 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 29e9980c8e60..1990869033e1 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -204,36 +204,185 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
204 return 0; 204 return 0;
205} 205}
206 206
207void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) 207int
208mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
209{
210 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
211 u8 *pos, neighbors;
212 u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
213
214 if (skb_tailroom(skb) < 2 + meshconf_len)
215 return -ENOMEM;
216
217 pos = skb_put(skb, 2 + meshconf_len);
218 *pos++ = WLAN_EID_MESH_CONFIG;
219 *pos++ = meshconf_len;
220
221 /* Active path selection protocol ID */
222 *pos++ = ifmsh->mesh_pp_id;
223 /* Active path selection metric ID */
224 *pos++ = ifmsh->mesh_pm_id;
225 /* Congestion control mode identifier */
226 *pos++ = ifmsh->mesh_cc_id;
227 /* Synchronization protocol identifier */
228 *pos++ = ifmsh->mesh_sp_id;
229 /* Authentication Protocol identifier */
230 *pos++ = ifmsh->mesh_auth_id;
231 /* Mesh Formation Info - number of neighbors */
232 neighbors = atomic_read(&ifmsh->mshstats.estab_plinks);
233 /* Number of neighbor mesh STAs or 15 whichever is smaller */
234 neighbors = (neighbors > 15) ? 15 : neighbors;
235 *pos++ = neighbors << 1;
236 /* Mesh capability */
237 ifmsh->accepting_plinks = mesh_plink_availables(sdata);
238 *pos = MESHCONF_CAPAB_FORWARDING;
239 *pos++ |= ifmsh->accepting_plinks ?
240 MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
241 *pos++ = 0x00;
242
243 return 0;
244}
245
246int
247mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
248{
249 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
250 u8 *pos;
251
252 if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
253 return -ENOMEM;
254
255 pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
256 *pos++ = WLAN_EID_MESH_ID;
257 *pos++ = ifmsh->mesh_id_len;
258 if (ifmsh->mesh_id_len)
259 memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
260
261 return 0;
262}
263
264int
265mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
266{
267 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
268 u8 offset, len;
269 const u8 *data;
270
271 if (!ifmsh->ie || !ifmsh->ie_len)
272 return 0;
273
274 /* fast-forward to vendor IEs */
275 offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
276
277 if (offset) {
278 len = ifmsh->ie_len - offset;
279 data = ifmsh->ie + offset;
280 if (skb_tailroom(skb) < len)
281 return -ENOMEM;
282 memcpy(skb_put(skb, len), data, len);
283 }
284
285 return 0;
286}
287
288int
289mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
290{
291 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
292 u8 len = 0;
293 const u8 *data;
294
295 if (!ifmsh->ie || !ifmsh->ie_len)
296 return 0;
297
298 /* find RSN IE */
299 data = ifmsh->ie;
300 while (data < ifmsh->ie + ifmsh->ie_len) {
301 if (*data == WLAN_EID_RSN) {
302 len = data[1] + 2;
303 break;
304 }
305 data++;
306 }
307
308 if (len) {
309 if (skb_tailroom(skb) < len)
310 return -ENOMEM;
311 memcpy(skb_put(skb, len), data, len);
312 }
313
314 return 0;
315}
316
317int
318mesh_add_srates_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
208{ 319{
209 struct ieee80211_local *local = sdata->local; 320 struct ieee80211_local *local = sdata->local;
210 struct ieee80211_supported_band *sband; 321 struct ieee80211_supported_band *sband;
211 u8 *pos; 322 int rate;
212 int len, i, rate; 323 u8 i, rates, *pos;
213 u8 neighbors;
214 324
215 sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 325 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
216 len = sband->n_bitrates; 326 rates = sband->n_bitrates;
217 if (len > 8) 327 if (rates > 8)
218 len = 8; 328 rates = 8;
219 pos = skb_put(skb, len + 2); 329
330 if (skb_tailroom(skb) < rates + 2)
331 return -ENOMEM;
332
333 pos = skb_put(skb, rates + 2);
220 *pos++ = WLAN_EID_SUPP_RATES; 334 *pos++ = WLAN_EID_SUPP_RATES;
221 *pos++ = len; 335 *pos++ = rates;
222 for (i = 0; i < len; i++) { 336 for (i = 0; i < rates; i++) {
223 rate = sband->bitrates[i].bitrate; 337 rate = sband->bitrates[i].bitrate;
224 *pos++ = (u8) (rate / 5); 338 *pos++ = (u8) (rate / 5);
225 } 339 }
226 340
227 if (sband->n_bitrates > len) { 341 return 0;
228 pos = skb_put(skb, sband->n_bitrates - len + 2); 342}
343
344int
345mesh_add_ext_srates_ie(struct sk_buff *skb,
346 struct ieee80211_sub_if_data *sdata)
347{
348 struct ieee80211_local *local = sdata->local;
349 struct ieee80211_supported_band *sband;
350 int rate;
351 u8 i, exrates, *pos;
352
353 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
354 exrates = sband->n_bitrates;
355 if (exrates > 8)
356 exrates -= 8;
357 else
358 exrates = 0;
359
360 if (skb_tailroom(skb) < exrates + 2)
361 return -ENOMEM;
362
363 if (exrates) {
364 pos = skb_put(skb, exrates + 2);
229 *pos++ = WLAN_EID_EXT_SUPP_RATES; 365 *pos++ = WLAN_EID_EXT_SUPP_RATES;
230 *pos++ = sband->n_bitrates - len; 366 *pos++ = exrates;
231 for (i = len; i < sband->n_bitrates; i++) { 367 for (i = 8; i < sband->n_bitrates; i++) {
232 rate = sband->bitrates[i].bitrate; 368 rate = sband->bitrates[i].bitrate;
233 *pos++ = (u8) (rate / 5); 369 *pos++ = (u8) (rate / 5);
234 } 370 }
235 } 371 }
372 return 0;
373}
374
375int mesh_add_ds_params_ie(struct sk_buff *skb,
376 struct ieee80211_sub_if_data *sdata)
377{
378 struct ieee80211_local *local = sdata->local;
379 struct ieee80211_supported_band *sband;
380 u8 *pos;
381
382 if (skb_tailroom(skb) < 3)
383 return -ENOMEM;
236 384
385 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
237 if (sband->band == IEEE80211_BAND_2GHZ) { 386 if (sband->band == IEEE80211_BAND_2GHZ) {
238 pos = skb_put(skb, 2 + 1); 387 pos = skb_put(skb, 2 + 1);
239 *pos++ = WLAN_EID_DS_PARAMS; 388 *pos++ = WLAN_EID_DS_PARAMS;
@@ -241,53 +390,9 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
241 *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); 390 *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
242 } 391 }
243 392
244 pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); 393 return 0;
245 *pos++ = WLAN_EID_MESH_ID;
246 *pos++ = sdata->u.mesh.mesh_id_len;
247 if (sdata->u.mesh.mesh_id_len)
248 memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len);
249
250 pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie));
251 *pos++ = WLAN_EID_MESH_CONFIG;
252 *pos++ = sizeof(struct ieee80211_meshconf_ie);
253
254 /* Active path selection protocol ID */
255 *pos++ = sdata->u.mesh.mesh_pp_id;
256
257 /* Active path selection metric ID */
258 *pos++ = sdata->u.mesh.mesh_pm_id;
259
260 /* Congestion control mode identifier */
261 *pos++ = sdata->u.mesh.mesh_cc_id;
262
263 /* Synchronization protocol identifier */
264 *pos++ = sdata->u.mesh.mesh_sp_id;
265
266 /* Authentication Protocol identifier */
267 *pos++ = sdata->u.mesh.mesh_auth_id;
268
269 /* Mesh Formation Info - number of neighbors */
270 neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks);
271 /* Number of neighbor mesh STAs or 15 whichever is smaller */
272 neighbors = (neighbors > 15) ? 15 : neighbors;
273 *pos++ = neighbors << 1;
274
275 /* Mesh capability */
276 sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata);
277 *pos = MESHCONF_CAPAB_FORWARDING;
278 *pos++ |= sdata->u.mesh.accepting_plinks ?
279 MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
280 *pos++ = 0x00;
281
282 if (sdata->u.mesh.ie) {
283 int len = sdata->u.mesh.ie_len;
284 const u8 *data = sdata->u.mesh.ie;
285 if (skb_tailroom(skb) > len)
286 memcpy(skb_put(skb, len), data, len);
287 }
288} 394}
289 395
290
291static void ieee80211_mesh_path_timer(unsigned long data) 396static void ieee80211_mesh_path_timer(unsigned long data)
292{ 397{
293 struct ieee80211_sub_if_data *sdata = 398 struct ieee80211_sub_if_data *sdata =
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 249e733362e7..b794360d0dfb 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -199,6 +199,20 @@ bool mesh_matches_local(struct ieee802_11_elems *ie,
199void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); 199void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
200void mesh_mgmt_ies_add(struct sk_buff *skb, 200void mesh_mgmt_ies_add(struct sk_buff *skb,
201 struct ieee80211_sub_if_data *sdata); 201 struct ieee80211_sub_if_data *sdata);
202int mesh_add_meshconf_ie(struct sk_buff *skb,
203 struct ieee80211_sub_if_data *sdata);
204int mesh_add_meshid_ie(struct sk_buff *skb,
205 struct ieee80211_sub_if_data *sdata);
206int mesh_add_rsn_ie(struct sk_buff *skb,
207 struct ieee80211_sub_if_data *sdata);
208int mesh_add_vendor_ies(struct sk_buff *skb,
209 struct ieee80211_sub_if_data *sdata);
210int mesh_add_srates_ie(struct sk_buff *skb,
211 struct ieee80211_sub_if_data *sdata);
212int mesh_add_ext_srates_ie(struct sk_buff *skb,
213 struct ieee80211_sub_if_data *sdata);
214int mesh_add_ds_params_ie(struct sk_buff *skb,
215 struct ieee80211_sub_if_data *sdata);
202void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); 216void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
203int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); 217int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
204void ieee80211s_init(void); 218void ieee80211s_init(void);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index f4adc0917888..e4113f243fc4 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -195,7 +195,12 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
195 memset(pos, 0, 2); 195 memset(pos, 0, 2);
196 memcpy(pos + 2, &plid, 2); 196 memcpy(pos + 2, &plid, 2);
197 } 197 }
198 mesh_mgmt_ies_add(skb, sdata); 198 if (mesh_add_srates_ie(skb, sdata) ||
199 mesh_add_ext_srates_ie(skb, sdata) ||
200 mesh_add_rsn_ie(skb, sdata) ||
201 mesh_add_meshid_ie(skb, sdata) ||
202 mesh_add_meshconf_ie(skb, sdata))
203 return -1;
199 } 204 }
200 205
201 /* Add Peer Link Management element */ 206 /* Add Peer Link Management element */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 69fd494f32f9..01072639666f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2295,13 +2295,23 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2295 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 2295 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
2296 mgmt->u.beacon.beacon_int = 2296 mgmt->u.beacon.beacon_int =
2297 cpu_to_le16(sdata->vif.bss_conf.beacon_int); 2297 cpu_to_le16(sdata->vif.bss_conf.beacon_int);
2298 mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ 2298 mgmt->u.beacon.capab_info |= cpu_to_le16(
2299 sdata->u.mesh.security ? WLAN_CAPABILITY_PRIVACY : 0);
2299 2300
2300 pos = skb_put(skb, 2); 2301 pos = skb_put(skb, 2);
2301 *pos++ = WLAN_EID_SSID; 2302 *pos++ = WLAN_EID_SSID;
2302 *pos++ = 0x0; 2303 *pos++ = 0x0;
2303 2304
2304 mesh_mgmt_ies_add(skb, sdata); 2305 if (mesh_add_srates_ie(skb, sdata) ||
2306 mesh_add_ds_params_ie(skb, sdata) ||
2307 mesh_add_ext_srates_ie(skb, sdata) ||
2308 mesh_add_rsn_ie(skb, sdata) ||
2309 mesh_add_meshid_ie(skb, sdata) ||
2310 mesh_add_meshconf_ie(skb, sdata) ||
2311 mesh_add_vendor_ies(skb, sdata)) {
2312 pr_err("o11s: couldn't add ies!\n");
2313 goto out;
2314 }
2305 } else { 2315 } else {
2306 WARN_ON(1); 2316 WARN_ON(1);
2307 goto out; 2317 goto out;