aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh.c
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/mesh.c
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/mesh.c')
-rw-r--r--net/mac80211/mesh.c223
1 files changed, 164 insertions, 59 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 =