diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/mesh.c | 223 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 14 | ||||
-rw-r--r-- | net/mac80211/mesh_plink.c | 7 | ||||
-rw-r--r-- | net/mac80211/tx.c | 14 |
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 | ||
207 | void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | 207 | int |
208 | mesh_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 | |||
246 | int | ||
247 | mesh_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 | |||
264 | int | ||
265 | mesh_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 | |||
288 | int | ||
289 | mesh_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 | |||
317 | int | ||
318 | mesh_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 | |||
344 | int | ||
345 | mesh_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 | |||
375 | int 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 | |||
291 | static void ieee80211_mesh_path_timer(unsigned long data) | 396 | static 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, | |||
199 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); | 199 | void mesh_ids_set_default(struct ieee80211_if_mesh *mesh); |
200 | void mesh_mgmt_ies_add(struct sk_buff *skb, | 200 | void mesh_mgmt_ies_add(struct sk_buff *skb, |
201 | struct ieee80211_sub_if_data *sdata); | 201 | struct ieee80211_sub_if_data *sdata); |
202 | int mesh_add_meshconf_ie(struct sk_buff *skb, | ||
203 | struct ieee80211_sub_if_data *sdata); | ||
204 | int mesh_add_meshid_ie(struct sk_buff *skb, | ||
205 | struct ieee80211_sub_if_data *sdata); | ||
206 | int mesh_add_rsn_ie(struct sk_buff *skb, | ||
207 | struct ieee80211_sub_if_data *sdata); | ||
208 | int mesh_add_vendor_ies(struct sk_buff *skb, | ||
209 | struct ieee80211_sub_if_data *sdata); | ||
210 | int mesh_add_srates_ie(struct sk_buff *skb, | ||
211 | struct ieee80211_sub_if_data *sdata); | ||
212 | int mesh_add_ext_srates_ie(struct sk_buff *skb, | ||
213 | struct ieee80211_sub_if_data *sdata); | ||
214 | int mesh_add_ds_params_ie(struct sk_buff *skb, | ||
215 | struct ieee80211_sub_if_data *sdata); | ||
202 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); | 216 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); |
203 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); | 217 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); |
204 | void ieee80211s_init(void); | 218 | void 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; |