aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mesh.c')
-rw-r--r--net/mac80211/mesh.c259
1 files changed, 190 insertions, 69 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 29e9980c8e60..28ab510e621a 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -13,10 +13,6 @@
13#include "ieee80211_i.h" 13#include "ieee80211_i.h"
14#include "mesh.h" 14#include "mesh.h"
15 15
16#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
17#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
18#define IEEE80211_MESH_RANN_INTERVAL (1 * HZ)
19
20#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 16#define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01
21#define MESHCONF_CAPAB_FORWARDING 0x08 17#define MESHCONF_CAPAB_FORWARDING 0x08
22 18
@@ -27,6 +23,17 @@
27int mesh_allocated; 23int mesh_allocated;
28static struct kmem_cache *rm_cache; 24static struct kmem_cache *rm_cache;
29 25
26#ifdef CONFIG_MAC80211_MESH
27bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
28{
29 return (mgmt->u.action.u.mesh_action.action_code ==
30 WLAN_MESH_ACTION_HWMP_PATH_SELECTION);
31}
32#else
33bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt)
34{ return false; }
35#endif
36
30void ieee80211s_init(void) 37void ieee80211s_init(void)
31{ 38{
32 mesh_pathtbl_init(); 39 mesh_pathtbl_init();
@@ -204,36 +211,185 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
204 return 0; 211 return 0;
205} 212}
206 213
207void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) 214int
215mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
216{
217 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
218 u8 *pos, neighbors;
219 u8 meshconf_len = sizeof(struct ieee80211_meshconf_ie);
220
221 if (skb_tailroom(skb) < 2 + meshconf_len)
222 return -ENOMEM;
223
224 pos = skb_put(skb, 2 + meshconf_len);
225 *pos++ = WLAN_EID_MESH_CONFIG;
226 *pos++ = meshconf_len;
227
228 /* Active path selection protocol ID */
229 *pos++ = ifmsh->mesh_pp_id;
230 /* Active path selection metric ID */
231 *pos++ = ifmsh->mesh_pm_id;
232 /* Congestion control mode identifier */
233 *pos++ = ifmsh->mesh_cc_id;
234 /* Synchronization protocol identifier */
235 *pos++ = ifmsh->mesh_sp_id;
236 /* Authentication Protocol identifier */
237 *pos++ = ifmsh->mesh_auth_id;
238 /* Mesh Formation Info - number of neighbors */
239 neighbors = atomic_read(&ifmsh->mshstats.estab_plinks);
240 /* Number of neighbor mesh STAs or 15 whichever is smaller */
241 neighbors = (neighbors > 15) ? 15 : neighbors;
242 *pos++ = neighbors << 1;
243 /* Mesh capability */
244 ifmsh->accepting_plinks = mesh_plink_availables(sdata);
245 *pos = MESHCONF_CAPAB_FORWARDING;
246 *pos++ |= ifmsh->accepting_plinks ?
247 MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
248 *pos++ = 0x00;
249
250 return 0;
251}
252
253int
254mesh_add_meshid_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
255{
256 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
257 u8 *pos;
258
259 if (skb_tailroom(skb) < 2 + ifmsh->mesh_id_len)
260 return -ENOMEM;
261
262 pos = skb_put(skb, 2 + ifmsh->mesh_id_len);
263 *pos++ = WLAN_EID_MESH_ID;
264 *pos++ = ifmsh->mesh_id_len;
265 if (ifmsh->mesh_id_len)
266 memcpy(pos, ifmsh->mesh_id, ifmsh->mesh_id_len);
267
268 return 0;
269}
270
271int
272mesh_add_vendor_ies(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
273{
274 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
275 u8 offset, len;
276 const u8 *data;
277
278 if (!ifmsh->ie || !ifmsh->ie_len)
279 return 0;
280
281 /* fast-forward to vendor IEs */
282 offset = ieee80211_ie_split_vendor(ifmsh->ie, ifmsh->ie_len, 0);
283
284 if (offset) {
285 len = ifmsh->ie_len - offset;
286 data = ifmsh->ie + offset;
287 if (skb_tailroom(skb) < len)
288 return -ENOMEM;
289 memcpy(skb_put(skb, len), data, len);
290 }
291
292 return 0;
293}
294
295int
296mesh_add_rsn_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
297{
298 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
299 u8 len = 0;
300 const u8 *data;
301
302 if (!ifmsh->ie || !ifmsh->ie_len)
303 return 0;
304
305 /* find RSN IE */
306 data = ifmsh->ie;
307 while (data < ifmsh->ie + ifmsh->ie_len) {
308 if (*data == WLAN_EID_RSN) {
309 len = data[1] + 2;
310 break;
311 }
312 data++;
313 }
314
315 if (len) {
316 if (skb_tailroom(skb) < len)
317 return -ENOMEM;
318 memcpy(skb_put(skb, len), data, len);
319 }
320
321 return 0;
322}
323
324int
325mesh_add_srates_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
208{ 326{
209 struct ieee80211_local *local = sdata->local; 327 struct ieee80211_local *local = sdata->local;
210 struct ieee80211_supported_band *sband; 328 struct ieee80211_supported_band *sband;
211 u8 *pos; 329 int rate;
212 int len, i, rate; 330 u8 i, rates, *pos;
213 u8 neighbors;
214 331
215 sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; 332 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
216 len = sband->n_bitrates; 333 rates = sband->n_bitrates;
217 if (len > 8) 334 if (rates > 8)
218 len = 8; 335 rates = 8;
219 pos = skb_put(skb, len + 2); 336
337 if (skb_tailroom(skb) < rates + 2)
338 return -ENOMEM;
339
340 pos = skb_put(skb, rates + 2);
220 *pos++ = WLAN_EID_SUPP_RATES; 341 *pos++ = WLAN_EID_SUPP_RATES;
221 *pos++ = len; 342 *pos++ = rates;
222 for (i = 0; i < len; i++) { 343 for (i = 0; i < rates; i++) {
223 rate = sband->bitrates[i].bitrate; 344 rate = sband->bitrates[i].bitrate;
224 *pos++ = (u8) (rate / 5); 345 *pos++ = (u8) (rate / 5);
225 } 346 }
226 347
227 if (sband->n_bitrates > len) { 348 return 0;
228 pos = skb_put(skb, sband->n_bitrates - len + 2); 349}
350
351int
352mesh_add_ext_srates_ie(struct sk_buff *skb,
353 struct ieee80211_sub_if_data *sdata)
354{
355 struct ieee80211_local *local = sdata->local;
356 struct ieee80211_supported_band *sband;
357 int rate;
358 u8 i, exrates, *pos;
359
360 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
361 exrates = sband->n_bitrates;
362 if (exrates > 8)
363 exrates -= 8;
364 else
365 exrates = 0;
366
367 if (skb_tailroom(skb) < exrates + 2)
368 return -ENOMEM;
369
370 if (exrates) {
371 pos = skb_put(skb, exrates + 2);
229 *pos++ = WLAN_EID_EXT_SUPP_RATES; 372 *pos++ = WLAN_EID_EXT_SUPP_RATES;
230 *pos++ = sband->n_bitrates - len; 373 *pos++ = exrates;
231 for (i = len; i < sband->n_bitrates; i++) { 374 for (i = 8; i < sband->n_bitrates; i++) {
232 rate = sband->bitrates[i].bitrate; 375 rate = sband->bitrates[i].bitrate;
233 *pos++ = (u8) (rate / 5); 376 *pos++ = (u8) (rate / 5);
234 } 377 }
235 } 378 }
379 return 0;
380}
236 381
382int mesh_add_ds_params_ie(struct sk_buff *skb,
383 struct ieee80211_sub_if_data *sdata)
384{
385 struct ieee80211_local *local = sdata->local;
386 struct ieee80211_supported_band *sband;
387 u8 *pos;
388
389 if (skb_tailroom(skb) < 3)
390 return -ENOMEM;
391
392 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
237 if (sband->band == IEEE80211_BAND_2GHZ) { 393 if (sband->band == IEEE80211_BAND_2GHZ) {
238 pos = skb_put(skb, 2 + 1); 394 pos = skb_put(skb, 2 + 1);
239 *pos++ = WLAN_EID_DS_PARAMS; 395 *pos++ = WLAN_EID_DS_PARAMS;
@@ -241,53 +397,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); 397 *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq);
242 } 398 }
243 399
244 pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); 400 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} 401}
289 402
290
291static void ieee80211_mesh_path_timer(unsigned long data) 403static void ieee80211_mesh_path_timer(unsigned long data)
292{ 404{
293 struct ieee80211_sub_if_data *sdata = 405 struct ieee80211_sub_if_data *sdata =
@@ -425,7 +537,8 @@ static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata)
425 537
426 mesh_path_tx_root_frame(sdata); 538 mesh_path_tx_root_frame(sdata);
427 mod_timer(&ifmsh->mesh_path_root_timer, 539 mod_timer(&ifmsh->mesh_path_root_timer,
428 round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL)); 540 round_jiffies(TU_TO_EXP_TIME(
541 ifmsh->mshcfg.dot11MeshHWMPRannInterval)));
429} 542}
430 543
431#ifdef CONFIG_PM 544#ifdef CONFIG_PM
@@ -433,7 +546,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
433{ 546{
434 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 547 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
435 548
436 /* use atomic bitops in case both timers fire at the same time */ 549 /* use atomic bitops in case all timers fire at the same time */
437 550
438 if (del_timer_sync(&ifmsh->housekeeping_timer)) 551 if (del_timer_sync(&ifmsh->housekeeping_timer))
439 set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); 552 set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -557,11 +670,18 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata,
557 struct ieee80211_rx_status *rx_status) 670 struct ieee80211_rx_status *rx_status)
558{ 671{
559 switch (mgmt->u.action.category) { 672 switch (mgmt->u.action.category) {
560 case WLAN_CATEGORY_MESH_ACTION: 673 case WLAN_CATEGORY_SELF_PROTECTED:
561 mesh_rx_plink_frame(sdata, mgmt, len, rx_status); 674 switch (mgmt->u.action.u.self_prot.action_code) {
675 case WLAN_SP_MESH_PEERING_OPEN:
676 case WLAN_SP_MESH_PEERING_CLOSE:
677 case WLAN_SP_MESH_PEERING_CONFIRM:
678 mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
679 break;
680 }
562 break; 681 break;
563 case WLAN_CATEGORY_MESH_PATH_SEL: 682 case WLAN_CATEGORY_MESH_ACTION:
564 mesh_rx_path_sel_frame(sdata, mgmt, len); 683 if (mesh_action_is_path_sel(mgmt))
684 mesh_rx_path_sel_frame(sdata, mgmt, len);
565 break; 685 break;
566 } 686 }
567} 687}
@@ -633,6 +753,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
633 ifmsh->accepting_plinks = true; 753 ifmsh->accepting_plinks = true;
634 ifmsh->preq_id = 0; 754 ifmsh->preq_id = 0;
635 ifmsh->sn = 0; 755 ifmsh->sn = 0;
756 ifmsh->num_gates = 0;
636 atomic_set(&ifmsh->mpaths, 0); 757 atomic_set(&ifmsh->mpaths, 0);
637 mesh_rmc_init(sdata); 758 mesh_rmc_init(sdata);
638 ifmsh->last_preq = jiffies; 759 ifmsh->last_preq = jiffies;