diff options
Diffstat (limited to 'net/mac80211/mesh.c')
-rw-r--r-- | net/mac80211/mesh.c | 155 |
1 files changed, 100 insertions, 55 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index f7364e56f1ee..6a4331429598 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,14 @@ | |||
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_CAPAB_ACCEPT_PLINKS 0x01 |
19 | #define PM_OFFSET 5 /* Path Selection Metric */ | 20 | #define MESHCONF_CAPAB_FORWARDING 0x08 |
20 | #define CC_OFFSET 9 /* Congestion Control Mode */ | ||
21 | #define SP_OFFSET 13 /* Synchronization Protocol */ | ||
22 | #define AUTH_OFFSET 17 /* Authentication Protocol */ | ||
23 | #define CAPAB_OFFSET 22 | ||
24 | #define CAPAB_ACCEPT_PLINKS 0x80 | ||
25 | #define CAPAB_FORWARDING 0x10 | ||
26 | 21 | ||
27 | #define TMR_RUNNING_HK 0 | 22 | #define TMR_RUNNING_HK 0 |
28 | #define TMR_RUNNING_MP 1 | 23 | #define TMR_RUNNING_MP 1 |
24 | #define TMR_RUNNING_MPR 2 | ||
29 | 25 | ||
30 | int mesh_allocated; | 26 | int mesh_allocated; |
31 | static struct kmem_cache *rm_cache; | 27 | static struct kmem_cache *rm_cache; |
@@ -50,7 +46,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data) | |||
50 | struct ieee80211_local *local = sdata->local; | 46 | struct ieee80211_local *local = sdata->local; |
51 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 47 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
52 | 48 | ||
53 | ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; | 49 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
54 | 50 | ||
55 | if (local->quiescing) { | 51 | if (local->quiescing) { |
56 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | 52 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); |
@@ -85,11 +81,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
85 | */ | 81 | */ |
86 | if (ifmsh->mesh_id_len == ie->mesh_id_len && | 82 | if (ifmsh->mesh_id_len == ie->mesh_id_len && |
87 | memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && | 83 | 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 && | 84 | (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) && |
89 | memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && | 85 | (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) && |
90 | memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0 && | 86 | (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) && |
91 | memcmp(ifmsh->mesh_sp_id, ie->mesh_config + SP_OFFSET, 4) == 0 && | 87 | (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) && |
92 | memcmp(ifmsh->mesh_auth_id, ie->mesh_config + AUTH_OFFSET, 4) == 0) | 88 | (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)) |
93 | return true; | 89 | return true; |
94 | 90 | ||
95 | return false; | 91 | return false; |
@@ -102,7 +98,8 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
102 | */ | 98 | */ |
103 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) | 99 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
104 | { | 100 | { |
105 | return (*(ie->mesh_config + CAPAB_OFFSET) & CAPAB_ACCEPT_PLINKS) != 0; | 101 | return (ie->mesh_config->meshconf_cap & |
102 | MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; | ||
106 | } | 103 | } |
107 | 104 | ||
108 | /** | 105 | /** |
@@ -128,18 +125,11 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) | |||
128 | 125 | ||
129 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) | 126 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) |
130 | { | 127 | { |
131 | u8 oui[3] = {0x00, 0x0F, 0xAC}; | 128 | sta->mesh_pp_id = 0; /* HWMP */ |
132 | 129 | sta->mesh_pm_id = 0; /* Airtime */ | |
133 | memcpy(sta->mesh_pp_id, oui, sizeof(oui)); | 130 | sta->mesh_cc_id = 0; /* Disabled */ |
134 | memcpy(sta->mesh_pm_id, oui, sizeof(oui)); | 131 | sta->mesh_sp_id = 0; /* Neighbor Offset */ |
135 | memcpy(sta->mesh_cc_id, oui, sizeof(oui)); | 132 | 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 | } | 133 | } |
144 | 134 | ||
145 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | 135 | int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) |
@@ -205,8 +195,8 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, | |||
205 | list_del(&p->list); | 195 | list_del(&p->list); |
206 | kmem_cache_free(rm_cache, p); | 196 | kmem_cache_free(rm_cache, p); |
207 | --entries; | 197 | --entries; |
208 | } else if ((seqnum == p->seqnum) | 198 | } else if ((seqnum == p->seqnum) && |
209 | && (memcmp(sa, p->sa, ETH_ALEN) == 0)) | 199 | (memcmp(sa, p->sa, ETH_ALEN) == 0)) |
210 | return -1; | 200 | return -1; |
211 | } | 201 | } |
212 | 202 | ||
@@ -228,6 +218,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
228 | struct ieee80211_supported_band *sband; | 218 | struct ieee80211_supported_band *sband; |
229 | u8 *pos; | 219 | u8 *pos; |
230 | int len, i, rate; | 220 | int len, i, rate; |
221 | u8 neighbors; | ||
231 | 222 | ||
232 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 223 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
233 | len = sband->n_bitrates; | 224 | len = sband->n_bitrates; |
@@ -251,46 +242,49 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
251 | } | 242 | } |
252 | } | 243 | } |
253 | 244 | ||
245 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
246 | pos = skb_put(skb, 2 + 1); | ||
247 | *pos++ = WLAN_EID_DS_PARAMS; | ||
248 | *pos++ = 1; | ||
249 | *pos++ = ieee80211_frequency_to_channel(local->hw.conf.channel->center_freq); | ||
250 | } | ||
251 | |||
254 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); | 252 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); |
255 | *pos++ = WLAN_EID_MESH_ID; | 253 | *pos++ = WLAN_EID_MESH_ID; |
256 | *pos++ = sdata->u.mesh.mesh_id_len; | 254 | *pos++ = sdata->u.mesh.mesh_id_len; |
257 | if (sdata->u.mesh.mesh_id_len) | 255 | if (sdata->u.mesh.mesh_id_len) |
258 | memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len); | 256 | memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len); |
259 | 257 | ||
260 | pos = skb_put(skb, 2 + IEEE80211_MESH_CONFIG_LEN); | 258 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_meshconf_ie)); |
261 | *pos++ = WLAN_EID_MESH_CONFIG; | 259 | *pos++ = WLAN_EID_MESH_CONFIG; |
262 | *pos++ = IEEE80211_MESH_CONFIG_LEN; | 260 | *pos++ = sizeof(struct ieee80211_meshconf_ie); |
263 | /* Version */ | ||
264 | *pos++ = 1; | ||
265 | 261 | ||
266 | /* Active path selection protocol ID */ | 262 | /* Active path selection protocol ID */ |
267 | memcpy(pos, sdata->u.mesh.mesh_pp_id, 4); | 263 | *pos++ = sdata->u.mesh.mesh_pp_id; |
268 | pos += 4; | ||
269 | 264 | ||
270 | /* Active path selection metric ID */ | 265 | /* Active path selection metric ID */ |
271 | memcpy(pos, sdata->u.mesh.mesh_pm_id, 4); | 266 | *pos++ = sdata->u.mesh.mesh_pm_id; |
272 | pos += 4; | ||
273 | 267 | ||
274 | /* Congestion control mode identifier */ | 268 | /* Congestion control mode identifier */ |
275 | memcpy(pos, sdata->u.mesh.mesh_cc_id, 4); | 269 | *pos++ = sdata->u.mesh.mesh_cc_id; |
276 | pos += 4; | ||
277 | 270 | ||
278 | /* Synchronization protocol identifier */ | 271 | /* Synchronization protocol identifier */ |
279 | memcpy(pos, sdata->u.mesh.mesh_sp_id, 4); | 272 | *pos++ = sdata->u.mesh.mesh_sp_id; |
280 | pos += 4; | ||
281 | 273 | ||
282 | /* Authentication Protocol identifier */ | 274 | /* Authentication Protocol identifier */ |
283 | memcpy(pos, sdata->u.mesh.mesh_auth_id, 4); | 275 | *pos++ = sdata->u.mesh.mesh_auth_id; |
284 | pos += 4; | ||
285 | 276 | ||
286 | /* Mesh Formation Info */ | 277 | /* Mesh Formation Info - number of neighbors */ |
287 | memset(pos, 0x00, 1); | 278 | neighbors = atomic_read(&sdata->u.mesh.mshstats.estab_plinks); |
288 | pos += 1; | 279 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ |
280 | neighbors = (neighbors > 15) ? 15 : neighbors; | ||
281 | *pos++ = neighbors << 1; | ||
289 | 282 | ||
290 | /* Mesh capability */ | 283 | /* Mesh capability */ |
291 | sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); | 284 | sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); |
292 | *pos = CAPAB_FORWARDING; | 285 | *pos = MESHCONF_CAPAB_FORWARDING; |
293 | *pos++ |= sdata->u.mesh.accepting_plinks ? CAPAB_ACCEPT_PLINKS : 0x00; | 286 | *pos++ |= sdata->u.mesh.accepting_plinks ? |
287 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | ||
294 | *pos++ = 0x00; | 288 | *pos++ = 0x00; |
295 | 289 | ||
296 | return; | 290 | return; |
@@ -355,6 +349,34 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
355 | ieee80211_queue_work(&local->hw, &ifmsh->work); | 349 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
356 | } | 350 | } |
357 | 351 | ||
352 | static void ieee80211_mesh_path_root_timer(unsigned long data) | ||
353 | { | ||
354 | struct ieee80211_sub_if_data *sdata = | ||
355 | (struct ieee80211_sub_if_data *) data; | ||
356 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
357 | struct ieee80211_local *local = sdata->local; | ||
358 | |||
359 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
360 | |||
361 | if (local->quiescing) { | ||
362 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
363 | return; | ||
364 | } | ||
365 | |||
366 | ieee80211_queue_work(&local->hw, &ifmsh->work); | ||
367 | } | ||
368 | |||
369 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) | ||
370 | { | ||
371 | if (ifmsh->mshcfg.dot11MeshHWMPRootMode) | ||
372 | set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
373 | else { | ||
374 | clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); | ||
375 | /* stop running timer */ | ||
376 | del_timer_sync(&ifmsh->mesh_path_root_timer); | ||
377 | } | ||
378 | } | ||
379 | |||
358 | /** | 380 | /** |
359 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame | 381 | * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame |
360 | * @hdr: 802.11 frame header | 382 | * @hdr: 802.11 frame header |
@@ -365,8 +387,9 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
365 | * | 387 | * |
366 | * Return the length of the 802.11 (does not include a mesh control header) | 388 | * Return the length of the 802.11 (does not include a mesh control header) |
367 | */ | 389 | */ |
368 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char | 390 | int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, |
369 | *meshda, char *meshsa) { | 391 | const u8 *meshda, const u8 *meshsa) |
392 | { | ||
370 | if (is_multicast_ether_addr(meshda)) { | 393 | if (is_multicast_ether_addr(meshda)) { |
371 | *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | 394 | *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); |
372 | /* DA TA SA */ | 395 | /* DA TA SA */ |
@@ -404,7 +427,7 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | |||
404 | char *addr5, char *addr6) | 427 | char *addr5, char *addr6) |
405 | { | 428 | { |
406 | int aelen = 0; | 429 | int aelen = 0; |
407 | memset(meshhdr, 0, sizeof(meshhdr)); | 430 | memset(meshhdr, 0, sizeof(*meshhdr)); |
408 | meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; | 431 | meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
409 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); | 432 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); |
410 | sdata->u.mesh.mesh_seqnum++; | 433 | sdata->u.mesh.mesh_seqnum++; |
@@ -448,6 +471,15 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | |||
448 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | 471 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); |
449 | } | 472 | } |
450 | 473 | ||
474 | static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) | ||
475 | { | ||
476 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
477 | |||
478 | mesh_path_tx_root_frame(sdata); | ||
479 | mod_timer(&ifmsh->mesh_path_root_timer, | ||
480 | round_jiffies(jiffies + IEEE80211_MESH_RANN_INTERVAL)); | ||
481 | } | ||
482 | |||
451 | #ifdef CONFIG_PM | 483 | #ifdef CONFIG_PM |
452 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | 484 | void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) |
453 | { | 485 | { |
@@ -462,6 +494,8 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata) | |||
462 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); | 494 | set_bit(TMR_RUNNING_HK, &ifmsh->timers_running); |
463 | if (del_timer_sync(&ifmsh->mesh_path_timer)) | 495 | if (del_timer_sync(&ifmsh->mesh_path_timer)) |
464 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); | 496 | set_bit(TMR_RUNNING_MP, &ifmsh->timers_running); |
497 | if (del_timer_sync(&ifmsh->mesh_path_root_timer)) | ||
498 | set_bit(TMR_RUNNING_MPR, &ifmsh->timers_running); | ||
465 | } | 499 | } |
466 | 500 | ||
467 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | 501 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) |
@@ -472,6 +506,9 @@ void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata) | |||
472 | add_timer(&ifmsh->housekeeping_timer); | 506 | add_timer(&ifmsh->housekeeping_timer); |
473 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) | 507 | if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running)) |
474 | add_timer(&ifmsh->mesh_path_timer); | 508 | add_timer(&ifmsh->mesh_path_timer); |
509 | if (test_and_clear_bit(TMR_RUNNING_MPR, &ifmsh->timers_running)) | ||
510 | add_timer(&ifmsh->mesh_path_root_timer); | ||
511 | ieee80211_mesh_root_setup(ifmsh); | ||
475 | } | 512 | } |
476 | #endif | 513 | #endif |
477 | 514 | ||
@@ -480,7 +517,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
480 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 517 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
481 | struct ieee80211_local *local = sdata->local; | 518 | struct ieee80211_local *local = sdata->local; |
482 | 519 | ||
483 | ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING; | 520 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
521 | ieee80211_mesh_root_setup(ifmsh); | ||
484 | ieee80211_queue_work(&local->hw, &ifmsh->work); | 522 | ieee80211_queue_work(&local->hw, &ifmsh->work); |
485 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | 523 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; |
486 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 524 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
@@ -491,6 +529,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
491 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | 529 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) |
492 | { | 530 | { |
493 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | 531 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); |
532 | del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); | ||
494 | /* | 533 | /* |
495 | * If the timer fired while we waited for it, it will have | 534 | * If the timer fired while we waited for it, it will have |
496 | * requeued the work. Now the work will be running again | 535 | * requeued the work. Now the work will be running again |
@@ -561,7 +600,7 @@ static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | |||
561 | struct ieee80211_rx_status *rx_status) | 600 | struct ieee80211_rx_status *rx_status) |
562 | { | 601 | { |
563 | switch (mgmt->u.action.category) { | 602 | switch (mgmt->u.action.category) { |
564 | case PLINK_CATEGORY: | 603 | case MESH_PLINK_CATEGORY: |
565 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | 604 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); |
566 | break; | 605 | break; |
567 | case MESH_PATH_SEL_CATEGORY: | 606 | case MESH_PATH_SEL_CATEGORY: |
@@ -628,6 +667,9 @@ static void ieee80211_mesh_work(struct work_struct *work) | |||
628 | 667 | ||
629 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) | 668 | if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags)) |
630 | ieee80211_mesh_housekeeping(sdata, ifmsh); | 669 | ieee80211_mesh_housekeeping(sdata, ifmsh); |
670 | |||
671 | if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) | ||
672 | ieee80211_mesh_rootpath(sdata); | ||
631 | } | 673 | } |
632 | 674 | ||
633 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | 675 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) |
@@ -673,7 +715,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
673 | MESH_MIN_DISCOVERY_TIMEOUT; | 715 | MESH_MIN_DISCOVERY_TIMEOUT; |
674 | ifmsh->accepting_plinks = true; | 716 | ifmsh->accepting_plinks = true; |
675 | ifmsh->preq_id = 0; | 717 | ifmsh->preq_id = 0; |
676 | ifmsh->dsn = 0; | 718 | ifmsh->sn = 0; |
677 | atomic_set(&ifmsh->mpaths, 0); | 719 | atomic_set(&ifmsh->mpaths, 0); |
678 | mesh_rmc_init(sdata); | 720 | mesh_rmc_init(sdata); |
679 | ifmsh->last_preq = jiffies; | 721 | ifmsh->last_preq = jiffies; |
@@ -684,6 +726,9 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
684 | setup_timer(&ifmsh->mesh_path_timer, | 726 | setup_timer(&ifmsh->mesh_path_timer, |
685 | ieee80211_mesh_path_timer, | 727 | ieee80211_mesh_path_timer, |
686 | (unsigned long) sdata); | 728 | (unsigned long) sdata); |
729 | setup_timer(&ifmsh->mesh_path_root_timer, | ||
730 | ieee80211_mesh_path_root_timer, | ||
731 | (unsigned long) sdata); | ||
687 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); | 732 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
688 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); | 733 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
689 | } | 734 | } |