diff options
Diffstat (limited to 'net/mac80211/mesh.c')
-rw-r--r-- | net/mac80211/mesh.c | 143 |
1 files changed, 97 insertions, 46 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9a733890eb4..bbd56b08789 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Authors: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * Javier Cardona <javier@cozybit.com> | 4 | * Javier Cardona <javier@cozybit.com> |
5 | * | 5 | * |
@@ -14,18 +14,20 @@ | |||
14 | 14 | ||
15 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) | 15 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) |
16 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) | 16 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) |
17 | #define IEEE80211_MESH_RANN_INTERVAL (1 * HZ) | ||
17 | 18 | ||
18 | #define PP_OFFSET 1 /* Path Selection Protocol */ | 19 | #define MESHCONF_PP_OFFSET 0 /* Path Selection Protocol */ |
19 | #define PM_OFFSET 5 /* Path Selection Metric */ | 20 | #define MESHCONF_PM_OFFSET 1 /* Path Selection Metric */ |
20 | #define CC_OFFSET 9 /* Congestion Control Mode */ | 21 | #define MESHCONF_CC_OFFSET 2 /* Congestion Control Mode */ |
21 | #define SP_OFFSET 13 /* Synchronization Protocol */ | 22 | #define MESHCONF_SP_OFFSET 3 /* Synchronization Protocol */ |
22 | #define AUTH_OFFSET 17 /* Authentication Protocol */ | 23 | #define MESHCONF_AUTH_OFFSET 4 /* Authentication Protocol */ |
23 | #define CAPAB_OFFSET 22 | 24 | #define MESHCONF_CAPAB_OFFSET 6 |
24 | #define CAPAB_ACCEPT_PLINKS 0x80 | 25 | #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 |
25 | #define CAPAB_FORWARDING 0x10 | 26 | #define MESHCONF_CAPAB_FORWARDING 0x08 |
26 | 27 | ||
27 | #define TMR_RUNNING_HK 0 | 28 | #define TMR_RUNNING_HK 0 |
28 | #define TMR_RUNNING_MP 1 | 29 | #define TMR_RUNNING_MP 1 |
30 | #define TMR_RUNNING_MPR 2 | ||
29 | 31 | ||
30 | int mesh_allocated; | 32 | int mesh_allocated; |
31 | static struct kmem_cache *rm_cache; | 33 | static struct kmem_cache *rm_cache; |
@@ -85,11 +87,12 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
85 | */ | 87 | */ |
86 | if (ifmsh->mesh_id_len == ie->mesh_id_len && | 88 | if (ifmsh->mesh_id_len == ie->mesh_id_len && |
87 | memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && | 89 | memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && |
88 | memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && | 90 | (ifmsh->mesh_pp_id == *(ie->mesh_config + MESHCONF_PP_OFFSET))&& |
89 | memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && | 91 | (ifmsh->mesh_pm_id == *(ie->mesh_config + MESHCONF_PM_OFFSET))&& |
90 | memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0 && | 92 | (ifmsh->mesh_cc_id == *(ie->mesh_config + MESHCONF_CC_OFFSET))&& |
91 | memcmp(ifmsh->mesh_sp_id, ie->mesh_config + SP_OFFSET, 4) == 0 && | 93 | (ifmsh->mesh_sp_id == *(ie->mesh_config + MESHCONF_SP_OFFSET))&& |
92 | memcmp(ifmsh->mesh_auth_id, ie->mesh_config + AUTH_OFFSET, 4) == 0) | 94 | (ifmsh->mesh_auth_id == *(ie->mesh_config + |
95 | MESHCONF_AUTH_OFFSET))) | ||
93 | return true; | 96 | return true; |
94 | 97 | ||
95 | return false; | 98 | return false; |
@@ -102,7 +105,8 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
102 | */ | 105 | */ |
103 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) | 106 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
104 | { | 107 | { |
105 | return (*(ie->mesh_config + CAPAB_OFFSET) & CAPAB_ACCEPT_PLINKS) != 0; | 108 | return (*(ie->mesh_config + MESHCONF_CAPAB_OFFSET) & |
109 | MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; | ||
106 | } | 110 | } |
107 | 111 | ||
108 | /** | 112 | /** |
@@ -128,18 +132,11 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) | |||
128 | 132 | ||
129 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) | 133 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) |
130 | { | 134 | { |
131 | u8 oui[3] = {0x00, 0x0F, 0xAC}; | 135 | sta->mesh_pp_id = 0; /* HWMP */ |
132 | 136 | sta->mesh_pm_id = 0; /* Airtime */ | |
133 | memcpy(sta->mesh_pp_id, oui, sizeof(oui)); | 137 | sta->mesh_cc_id = 0; /* Disabled */ |
134 | memcpy(sta->mesh_pm_id, oui, sizeof(oui)); | 138 | sta->mesh_sp_id = 0; /* Neighbor Offset */ |
135 | memcpy(sta->mesh_cc_id, oui, sizeof(oui)); | 139 | sta->mesh_auth_id = 0; /* Disabled */ |
136 | memcpy(sta->mesh_sp_id, oui, sizeof(oui)); | ||
137 | memcpy(sta->mesh_auth_id, oui, sizeof(oui)); | ||
138 | sta->mesh_pp_id[sizeof(oui)] = 0; | ||
139 | sta->mesh_pm_id[sizeof(oui)] = 0; | ||
140 | sta->mesh_cc_id[sizeof(oui)] = 0xff; | ||
141 | sta->mesh_sp_id[sizeof(oui)] = 0xff; | ||
142 | sta->mesh_auth_id[sizeof(oui)] = 0x0; | ||
143 | } | 140 | } |
144 | 141 | ||
145 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 142 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
@@ -228,6 +225,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
228 | struct ieee80211_supported_band *sband; | 225 | struct ieee80211_supported_band *sband; |
229 | u8 *pos; | 226 | u8 *pos; |
230 | int len, i, rate; | 227 | int len, i, rate; |
228 | u8 neighbors; | ||
231 | 229 | ||
232 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 230 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
233 | len = sband->n_bitrates; | 231 | len = sband->n_bitrates; |
@@ -251,6 +249,13 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
251 | } | 249 | } |
252 | } | 250 | } |
253 | 251 | ||
252 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
253 | pos = skb_put(skb, 2 + 1); | ||
254 | *pos++ = WLAN_EID_DS_PARAMS; | ||
255 | *pos++ = 1; | ||
256 | *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); | ||
257 | } | ||
258 | |||
254 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); | 259 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); |
255 | *pos++ = WLAN_EID_MESH_ID; | 260 | *pos++ = WLAN_EID_MESH_ID; |
256 | *pos++ = sdata->u.mesh.mesh_id_len; | 261 | *pos++ = sdata->u.mesh.mesh_id_len; |
@@ -260,37 +265,33 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
260 | pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); | 265 | pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); |
261 | *pos++ = WLAN_EID_MESH_CONFIG; | 266 | *pos++ = WLAN_EID_MESH_CONFIG; |
262 | *pos++ = IEEE80211_MESH_CONFIG_LEN; | 267 | *pos++ = IEEE80211_MESH_CONFIG_LEN; |
263 | /* Version */ | ||
264 | *pos++ = 1; | ||
265 | 268 | ||
266 | /* Active path selection protocol ID */ | 269 | /* Active path selection protocol ID */ |
267 | memcpy(pos, sdata->u.mesh.mesh_pp_id, 4); | 270 | *pos++ = sdata->u.mesh.mesh_pp_id; |
268 | pos += 4; | ||
269 | 271 | ||
270 | /* Active path selection metric ID */ | 272 | /* Active path selection metric ID */ |
271 | memcpy(pos, sdata->u.mesh.mesh_pm_id, 4); | 273 | *pos++ = sdata->u.mesh.mesh_pm_id; |
272 | pos += 4; | ||
273 | 274 | ||
274 | /* Congestion control mode identifier */ | 275 | /* Congestion control mode identifier */ |
275 | memcpy(pos, sdata->u.mesh.mesh_cc_id, 4); | 276 | *pos++ = sdata->u.mesh.mesh_cc_id; |
276 | pos += 4; | ||
277 | 277 | ||
278 | /* Synchronization protocol identifier */ | 278 | /* Synchronization protocol identifier */ |
279 | memcpy(pos, sdata->u.mesh.mesh_sp_id, 4); | 279 | *pos++ = sdata->u.mesh.mesh_sp_id; |
280 | pos += 4; | ||
281 | 280 | ||
282 | /* Authentication Protocol identifier */ | 281 | /* Authentication Protocol identifier */ |
283 | memcpy(pos, sdata->u.mesh.mesh_auth_id, 4); | 282 | *pos++ = sdata->u.mesh.mesh_auth_id; |
284 | pos += 4; | ||
285 | 283 | ||
286 | /* Mesh Formation Info */ | 284 | /* Mesh Formation Info - number of neighbors */ |
287 | memset(pos, 0x00, 1); | 285 | neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks); |
288 | pos += 1; | 286 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ |
287 | neighbors = (neighbors > 15) ? 15 : neighbors; | ||
288 | *pos++ = neighbors << 1; | ||
289 | 289 | ||
290 | /* Mesh capability */ | 290 | /* Mesh capability */ |
291 | sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); | 291 | sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); |
292 | *pos = CAPAB_FORWARDING; | 292 | *pos = MESHCONF_CAPAB_FORWARDING; |
293 | *pos++ |= sdata->u.mesh.accepting_plinks ? CAPAB_ACCEPT_PLINKS : 0x00; | 293 | *pos++ |= sdata->u.mesh.accepting_plinks ? |
294 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | ||
294 | *pos++ = 0x00; | 295 | *pos++ = 0x00; |
295 | 296 | ||
296 | return; | 297 | return; |
@@ -355,6 +356,34 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
355 | ieee80211_queue_work(&local->hw, &ifmsh->work); | 356 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
356 | } | 357 | } |
357 | 358 | ||
359 | static void ieee80211_mesh_path_root_timer(unsigned long data) | ||
360 | { | ||
361 | struct ieee80211_sub_if_data *sdata = | ||
362 | (struct ieee80211_sub_if_data *) data; | ||
363 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
364 | struct ieee80211_local *local = sdata->local; | ||
365 | |||
366 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
367 | |||
368 | if (local->quiescing) { | ||
369 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
370 | return; | ||
371 | } | ||
372 | |||
373 | ieee80211_queue_work(&local->hw, &ifmsh->work); | ||
374 | } | ||
375 | |||
376 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) | ||
377 | { | ||
378 | if (ifmsh->mshcfg.dot11MeshHWMPRootMode) | ||
379 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
380 | else { | ||
381 | clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
382 | /* stop running timer */ | ||
383 | del_timer_sync(&ifmsh->mesh_path_root_timer); | ||
384 | } | ||
385 | } | ||
386 | |||
358 | /** | 387 | /** |
359 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame | 388 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame |
360 | * @hdr: 802.11 frame header | 389 | * @hdr: 802.11 frame header |
@@ -448,6 +477,15 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
448 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | 477 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
449 | } | 478 | } |
450 | 479 | ||
480 | static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) | ||
481 | { | ||
482 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
483 | |||
484 | mesh_path_tx_root_frame(sdata); | ||
485 | mod_timer(&ifmsh->mesh_path_root_timer, | ||
486 | round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL)); | ||
487 | } | ||
488 | |||
451 | #ifdef CONFIG_PM | 489 | #ifdef CONFIG_PM |
452 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | 490 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) |
453 | { | 491 | { |
@@ -462,6 +500,8 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | |||
462 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | 500 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); |
463 | if (del_timer_sync(&ifmsh->mesh_path_timer)) | 501 | if (del_timer_sync(&ifmsh->mesh_path_timer)) |
464 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | 502 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); |
503 | if (del_timer_sync(&ifmsh->mesh_path_root_timer)) | ||
504 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
465 | } | 505 | } |
466 | 506 | ||
467 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | 507 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) |
@@ -472,6 +512,9 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | |||
472 | add_timer(&ifmsh->housekeeping_timer); | 512 | add_timer(&ifmsh->housekeeping_timer); |
473 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) | 513 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) |
474 | add_timer(&ifmsh->mesh_path_timer); | 514 | add_timer(&ifmsh->mesh_path_timer); |
515 | if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) | ||
516 | add_timer(&ifmsh->mesh_path_root_timer); | ||
517 | ieee80211_mesh_root_setup(ifmsh); | ||
475 | } | 518 | } |
476 | #endif | 519 | #endif |
477 | 520 | ||
@@ -481,6 +524,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
481 | struct ieee80211_local *local = sdata->local; | 524 | struct ieee80211_local *local = sdata->local; |
482 | 525 | ||
483 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); | 526 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
527 | ieee80211_mesh_root_setup(ifmsh); | ||
484 | ieee80211_queue_work(&local->hw, &ifmsh->work); | 528 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
485 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | 529 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; |
486 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 530 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
@@ -491,6 +535,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
491 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 535 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
492 | { | 536 | { |
493 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 537 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
538 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | ||
494 | /* | 539 | /* |
495 | * If the timer fired while we waited for it, it will have | 540 | * If the timer fired while we waited for it, it will have |
496 | * requeued the work. Now the work will be running again | 541 | * requeued the work. Now the work will be running again |
@@ -561,7 +606,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
561 | struct ieee80211_rx_status *rx_status) | 606 | struct ieee80211_rx_status *rx_status) |
562 | { | 607 | { |
563 | switch (mgmt->u.action.category) { | 608 | switch (mgmt->u.action.category) { |
564 | case PLINK_CATEGORY: | 609 | case MESH_PLINK_CATEGORY: |
565 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | 610 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); |
566 | break; | 611 | break; |
567 | case MESH_PATH_SEL_CATEGORY: | 612 | case MESH_PATH_SEL_CATEGORY: |
@@ -628,6 +673,9 @@ static void ieee80211_mesh_work(struct work_struct *work) | |||
628 | 673 | ||
629 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) | 674 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) |
630 | ieee80211_mesh_housekeeping(sdata, ifmsh); | 675 | ieee80211_mesh_housekeeping(sdata, ifmsh); |
676 | |||
677 | if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) | ||
678 | ieee80211_mesh_rootpath(sdata); | ||
631 | } | 679 | } |
632 | 680 | ||
633 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | 681 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) |
@@ -673,7 +721,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
673 | MESH_MIN_DISCOVERY_TIMEOUT; | 721 | MESH_MIN_DISCOVERY_TIMEOUT; |
674 | ifmsh->accepting_plinks = true; | 722 | ifmsh->accepting_plinks = true; |
675 | ifmsh->preq_id = 0; | 723 | ifmsh->preq_id = 0; |
676 | ifmsh->dsn = 0; | 724 | ifmsh->sn = 0; |
677 | atomic_set(&ifmsh->mpaths, 0); | 725 | atomic_set(&ifmsh->mpaths, 0); |
678 | mesh_rmc_init(sdata); | 726 | mesh_rmc_init(sdata); |
679 | ifmsh->last_preq = jiffies; | 727 | ifmsh->last_preq = jiffies; |
@@ -684,6 +732,9 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
684 | setup_timer(&ifmsh->mesh_path_timer, | 732 | setup_timer(&ifmsh->mesh_path_timer, |
685 | ieee80211_mesh_path_timer, | 733 | ieee80211_mesh_path_timer, |
686 | (unsigned long) sdata); | 734 | (unsigned long) sdata); |
735 | setup_timer(&ifmsh->mesh_path_root_timer, | ||
736 | ieee80211_mesh_path_root_timer, | ||
737 | (unsigned long) sdata); | ||
687 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); | 738 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
688 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); | 739 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
689 | } | 740 | } |