aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorThomas Pedersen <thomas@cozybit.com>2011-08-11 22:35:10 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-22 14:45:59 -0400
commit082ebb0c258d28af7452b19df9ef8b7553f37690 (patch)
treea7cb2f8e5cf55c4000b549b6ff29c1c99f447825 /net/mac80211
parentf6a3e99da82167e066ebde975ec604638b42d816 (diff)
mac80211: fix mesh beacon format
Correct ordering of IEs in the mesh beacon while removing unneeded IEs from mesh peering frames. Set privacy bit in capability info if security is enabled. Add utility functions to aid in construction of IEs and reduce code duplication. Signed-off-by: Thomas Pedersen <thomas@cozybit.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-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;