diff options
Diffstat (limited to 'net/mac80211/mesh.c')
-rw-r--r-- | net/mac80211/mesh.c | 328 |
1 files changed, 273 insertions, 55 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 3ccb3599c04f..9e47725cc592 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -12,6 +12,9 @@ | |||
12 | #include "ieee80211_i.h" | 12 | #include "ieee80211_i.h" |
13 | #include "mesh.h" | 13 | #include "mesh.h" |
14 | 14 | ||
15 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) | ||
16 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) | ||
17 | |||
15 | #define PP_OFFSET 1 /* Path Selection Protocol */ | 18 | #define PP_OFFSET 1 /* Path Selection Protocol */ |
16 | #define PM_OFFSET 5 /* Path Selection Metric */ | 19 | #define PM_OFFSET 5 /* Path Selection Metric */ |
17 | #define CC_OFFSET 9 /* Congestion Control Mode */ | 20 | #define CC_OFFSET 9 /* Congestion Control Mode */ |
@@ -35,6 +38,16 @@ void ieee80211s_stop(void) | |||
35 | kmem_cache_destroy(rm_cache); | 38 | kmem_cache_destroy(rm_cache); |
36 | } | 39 | } |
37 | 40 | ||
41 | static void ieee80211_mesh_housekeeping_timer(unsigned long data) | ||
42 | { | ||
43 | struct ieee80211_sub_if_data *sdata = (void *) data; | ||
44 | struct ieee80211_local *local = sdata->local; | ||
45 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
46 | |||
47 | ifmsh->housekeeping = true; | ||
48 | queue_work(local->hw.workqueue, &ifmsh->work); | ||
49 | } | ||
50 | |||
38 | /** | 51 | /** |
39 | * mesh_matches_local - check if the config of a mesh point matches ours | 52 | * mesh_matches_local - check if the config of a mesh point matches ours |
40 | * | 53 | * |
@@ -46,7 +59,7 @@ void ieee80211s_stop(void) | |||
46 | */ | 59 | */ |
47 | bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata) | 60 | bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata) |
48 | { | 61 | { |
49 | struct ieee80211_if_sta *sta = &sdata->u.sta; | 62 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
50 | 63 | ||
51 | /* | 64 | /* |
52 | * As support for each feature is added, check for matching | 65 | * As support for each feature is added, check for matching |
@@ -58,11 +71,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat | |||
58 | * - MDA enabled | 71 | * - MDA enabled |
59 | * - Power management control on fc | 72 | * - Power management control on fc |
60 | */ | 73 | */ |
61 | if (sta->mesh_id_len == ie->mesh_id_len && | 74 | if (ifmsh->mesh_id_len == ie->mesh_id_len && |
62 | memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && | 75 | memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && |
63 | memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && | 76 | memcmp(ifmsh->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && |
64 | memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && | 77 | memcmp(ifmsh->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && |
65 | memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0) | 78 | memcmp(ifmsh->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0) |
66 | return true; | 79 | return true; |
67 | 80 | ||
68 | return false; | 81 | return false; |
@@ -95,11 +108,11 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) | |||
95 | */ | 108 | */ |
96 | free_plinks = mesh_plink_availables(sdata); | 109 | free_plinks = mesh_plink_availables(sdata); |
97 | 110 | ||
98 | if (free_plinks != sdata->u.sta.accepting_plinks) | 111 | if (free_plinks != sdata->u.mesh.accepting_plinks) |
99 | ieee80211_sta_timer((unsigned long) sdata); | 112 | ieee80211_mesh_housekeeping_timer((unsigned long) sdata); |
100 | } | 113 | } |
101 | 114 | ||
102 | void mesh_ids_set_default(struct ieee80211_if_sta *sta) | 115 | void mesh_ids_set_default(struct ieee80211_if_mesh *sta) |
103 | { | 116 | { |
104 | u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff}; | 117 | u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff}; |
105 | 118 | ||
@@ -112,22 +125,22 @@ int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | |||
112 | { | 125 | { |
113 | int i; | 126 | int i; |
114 | 127 | ||
115 | sdata->u.sta.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); | 128 | sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); |
116 | if (!sdata->u.sta.rmc) | 129 | if (!sdata->u.mesh.rmc) |
117 | return -ENOMEM; | 130 | return -ENOMEM; |
118 | sdata->u.sta.rmc->idx_mask = RMC_BUCKETS - 1; | 131 | sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; |
119 | for (i = 0; i < RMC_BUCKETS; i++) | 132 | for (i = 0; i < RMC_BUCKETS; i++) |
120 | INIT_LIST_HEAD(&sdata->u.sta.rmc->bucket[i].list); | 133 | INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list); |
121 | return 0; | 134 | return 0; |
122 | } | 135 | } |
123 | 136 | ||
124 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) | 137 | void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) |
125 | { | 138 | { |
126 | struct mesh_rmc *rmc = sdata->u.sta.rmc; | 139 | struct mesh_rmc *rmc = sdata->u.mesh.rmc; |
127 | struct rmc_entry *p, *n; | 140 | struct rmc_entry *p, *n; |
128 | int i; | 141 | int i; |
129 | 142 | ||
130 | if (!sdata->u.sta.rmc) | 143 | if (!sdata->u.mesh.rmc) |
131 | return; | 144 | return; |
132 | 145 | ||
133 | for (i = 0; i < RMC_BUCKETS; i++) | 146 | for (i = 0; i < RMC_BUCKETS; i++) |
@@ -137,7 +150,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) | |||
137 | } | 150 | } |
138 | 151 | ||
139 | kfree(rmc); | 152 | kfree(rmc); |
140 | sdata->u.sta.rmc = NULL; | 153 | sdata->u.mesh.rmc = NULL; |
141 | } | 154 | } |
142 | 155 | ||
143 | /** | 156 | /** |
@@ -155,7 +168,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) | |||
155 | int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, | 168 | int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, |
156 | struct ieee80211_sub_if_data *sdata) | 169 | struct ieee80211_sub_if_data *sdata) |
157 | { | 170 | { |
158 | struct mesh_rmc *rmc = sdata->u.sta.rmc; | 171 | struct mesh_rmc *rmc = sdata->u.mesh.rmc; |
159 | u32 seqnum = 0; | 172 | u32 seqnum = 0; |
160 | int entries = 0; | 173 | int entries = 0; |
161 | u8 idx; | 174 | u8 idx; |
@@ -217,11 +230,11 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
217 | } | 230 | } |
218 | } | 231 | } |
219 | 232 | ||
220 | pos = skb_put(skb, 2 + sdata->u.sta.mesh_id_len); | 233 | pos = skb_put(skb, 2 + sdata->u.mesh.mesh_id_len); |
221 | *pos++ = WLAN_EID_MESH_ID; | 234 | *pos++ = WLAN_EID_MESH_ID; |
222 | *pos++ = sdata->u.sta.mesh_id_len; | 235 | *pos++ = sdata->u.mesh.mesh_id_len; |
223 | if (sdata->u.sta.mesh_id_len) | 236 | if (sdata->u.mesh.mesh_id_len) |
224 | memcpy(pos, sdata->u.sta.mesh_id, sdata->u.sta.mesh_id_len); | 237 | memcpy(pos, sdata->u.mesh.mesh_id, sdata->u.mesh.mesh_id_len); |
225 | 238 | ||
226 | pos = skb_put(skb, 21); | 239 | pos = skb_put(skb, 21); |
227 | *pos++ = WLAN_EID_MESH_CONFIG; | 240 | *pos++ = WLAN_EID_MESH_CONFIG; |
@@ -230,15 +243,15 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
230 | *pos++ = 1; | 243 | *pos++ = 1; |
231 | 244 | ||
232 | /* Active path selection protocol ID */ | 245 | /* Active path selection protocol ID */ |
233 | memcpy(pos, sdata->u.sta.mesh_pp_id, 4); | 246 | memcpy(pos, sdata->u.mesh.mesh_pp_id, 4); |
234 | pos += 4; | 247 | pos += 4; |
235 | 248 | ||
236 | /* Active path selection metric ID */ | 249 | /* Active path selection metric ID */ |
237 | memcpy(pos, sdata->u.sta.mesh_pm_id, 4); | 250 | memcpy(pos, sdata->u.mesh.mesh_pm_id, 4); |
238 | pos += 4; | 251 | pos += 4; |
239 | 252 | ||
240 | /* Congestion control mode identifier */ | 253 | /* Congestion control mode identifier */ |
241 | memcpy(pos, sdata->u.sta.mesh_cc_id, 4); | 254 | memcpy(pos, sdata->u.mesh.mesh_cc_id, 4); |
242 | pos += 4; | 255 | pos += 4; |
243 | 256 | ||
244 | /* Channel precedence: | 257 | /* Channel precedence: |
@@ -248,8 +261,8 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
248 | pos += 4; | 261 | pos += 4; |
249 | 262 | ||
250 | /* Mesh capability */ | 263 | /* Mesh capability */ |
251 | sdata->u.sta.accepting_plinks = mesh_plink_availables(sdata); | 264 | sdata->u.mesh.accepting_plinks = mesh_plink_availables(sdata); |
252 | *pos++ = sdata->u.sta.accepting_plinks ? ACCEPT_PLINKS : 0x00; | 265 | *pos++ = sdata->u.mesh.accepting_plinks ? ACCEPT_PLINKS : 0x00; |
253 | *pos++ = 0x00; | 266 | *pos++ = 0x00; |
254 | 267 | ||
255 | return; | 268 | return; |
@@ -337,10 +350,10 @@ static void ieee80211_mesh_path_timer(unsigned long data) | |||
337 | { | 350 | { |
338 | struct ieee80211_sub_if_data *sdata = | 351 | struct ieee80211_sub_if_data *sdata = |
339 | (struct ieee80211_sub_if_data *) data; | 352 | (struct ieee80211_sub_if_data *) data; |
340 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 353 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
341 | struct ieee80211_local *local = wdev_priv(&sdata->wdev); | 354 | struct ieee80211_local *local = wdev_priv(&sdata->wdev); |
342 | 355 | ||
343 | queue_work(local->hw.workqueue, &ifsta->work); | 356 | queue_work(local->hw.workqueue, &ifmsh->work); |
344 | } | 357 | } |
345 | 358 | ||
346 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl) | 359 | struct mesh_table *mesh_table_grow(struct mesh_table *tbl) |
@@ -392,50 +405,255 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, | |||
392 | struct ieee80211_sub_if_data *sdata) | 405 | struct ieee80211_sub_if_data *sdata) |
393 | { | 406 | { |
394 | meshhdr->flags = 0; | 407 | meshhdr->flags = 0; |
395 | meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL; | 408 | meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL; |
396 | put_unaligned(cpu_to_le32(sdata->u.sta.mesh_seqnum), &meshhdr->seqnum); | 409 | put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum); |
397 | sdata->u.sta.mesh_seqnum++; | 410 | sdata->u.mesh.mesh_seqnum++; |
398 | 411 | ||
399 | return 6; | 412 | return 6; |
400 | } | 413 | } |
401 | 414 | ||
415 | static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, | ||
416 | struct ieee80211_if_mesh *ifmsh) | ||
417 | { | ||
418 | bool free_plinks; | ||
419 | |||
420 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
421 | printk(KERN_DEBUG "%s: running mesh housekeeping\n", | ||
422 | sdata->dev->name); | ||
423 | #endif | ||
424 | |||
425 | ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); | ||
426 | mesh_path_expire(sdata); | ||
427 | |||
428 | free_plinks = mesh_plink_availables(sdata); | ||
429 | if (free_plinks != sdata->u.mesh.accepting_plinks) | ||
430 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | ||
431 | |||
432 | ifmsh->housekeeping = false; | ||
433 | mod_timer(&ifmsh->housekeeping_timer, | ||
434 | round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL)); | ||
435 | } | ||
436 | |||
437 | |||
438 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | ||
439 | { | ||
440 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
441 | struct ieee80211_local *local = sdata->local; | ||
442 | |||
443 | ifmsh->housekeeping = true; | ||
444 | queue_work(local->hw.workqueue, &ifmsh->work); | ||
445 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | ||
446 | } | ||
447 | |||
448 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) | ||
449 | { | ||
450 | del_timer_sync(&sdata->u.mesh.housekeeping_timer); | ||
451 | /* | ||
452 | * When we get here, the interface is marked down. | ||
453 | * Call synchronize_rcu() to wait for the RX path | ||
454 | * should it be using the interface and enqueuing | ||
455 | * frames at this very time on another CPU. | ||
456 | */ | ||
457 | synchronize_rcu(); | ||
458 | skb_queue_purge(&sdata->u.mesh.skb_queue); | ||
459 | } | ||
460 | |||
461 | static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | ||
462 | u16 stype, | ||
463 | struct ieee80211_mgmt *mgmt, | ||
464 | size_t len, | ||
465 | struct ieee80211_rx_status *rx_status) | ||
466 | { | ||
467 | struct ieee80211_local *local= sdata->local; | ||
468 | struct ieee802_11_elems elems; | ||
469 | struct ieee80211_channel *channel; | ||
470 | u64 supp_rates = 0; | ||
471 | size_t baselen; | ||
472 | int freq; | ||
473 | enum ieee80211_band band = rx_status->band; | ||
474 | |||
475 | /* ignore ProbeResp to foreign address */ | ||
476 | if (stype == IEEE80211_STYPE_PROBE_RESP && | ||
477 | compare_ether_addr(mgmt->da, sdata->dev->dev_addr)) | ||
478 | return; | ||
479 | |||
480 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | ||
481 | if (baselen > len) | ||
482 | return; | ||
483 | |||
484 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | ||
485 | &elems); | ||
486 | |||
487 | if (elems.ds_params && elems.ds_params_len == 1) | ||
488 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); | ||
489 | else | ||
490 | freq = rx_status->freq; | ||
491 | |||
492 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
493 | |||
494 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
495 | return; | ||
496 | |||
497 | if (elems.mesh_id && elems.mesh_config && | ||
498 | mesh_matches_local(&elems, sdata)) { | ||
499 | supp_rates = ieee80211_sta_get_rates(local, &elems, band); | ||
500 | |||
501 | mesh_neighbour_update(mgmt->sa, supp_rates, sdata, | ||
502 | mesh_peer_accepts_plinks(&elems)); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | ||
507 | struct ieee80211_mgmt *mgmt, | ||
508 | size_t len, | ||
509 | struct ieee80211_rx_status *rx_status) | ||
510 | { | ||
511 | switch (mgmt->u.action.category) { | ||
512 | case PLINK_CATEGORY: | ||
513 | mesh_rx_plink_frame(sdata, mgmt, len, rx_status); | ||
514 | break; | ||
515 | case MESH_PATH_SEL_CATEGORY: | ||
516 | mesh_rx_path_sel_frame(sdata, mgmt, len); | ||
517 | break; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | static void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | ||
522 | struct sk_buff *skb) | ||
523 | { | ||
524 | struct ieee80211_rx_status *rx_status; | ||
525 | struct ieee80211_if_mesh *ifmsh; | ||
526 | struct ieee80211_mgmt *mgmt; | ||
527 | u16 stype; | ||
528 | |||
529 | ifmsh = &sdata->u.mesh; | ||
530 | |||
531 | rx_status = (struct ieee80211_rx_status *) skb->cb; | ||
532 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
533 | stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; | ||
534 | |||
535 | switch (stype) { | ||
536 | case IEEE80211_STYPE_PROBE_RESP: | ||
537 | case IEEE80211_STYPE_BEACON: | ||
538 | ieee80211_mesh_rx_bcn_presp(sdata, stype, mgmt, skb->len, | ||
539 | rx_status); | ||
540 | break; | ||
541 | case IEEE80211_STYPE_ACTION: | ||
542 | ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); | ||
543 | break; | ||
544 | } | ||
545 | |||
546 | kfree_skb(skb); | ||
547 | } | ||
548 | |||
549 | static void ieee80211_mesh_work(struct work_struct *work) | ||
550 | { | ||
551 | struct ieee80211_sub_if_data *sdata = | ||
552 | container_of(work, struct ieee80211_sub_if_data, u.mesh.work); | ||
553 | struct ieee80211_local *local = sdata->local; | ||
554 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
555 | struct sk_buff *skb; | ||
556 | |||
557 | if (!netif_running(sdata->dev)) | ||
558 | return; | ||
559 | |||
560 | if (local->sta_sw_scanning || local->sta_hw_scanning) | ||
561 | return; | ||
562 | |||
563 | while ((skb = skb_dequeue(&ifmsh->skb_queue))) | ||
564 | ieee80211_mesh_rx_queued_mgmt(sdata, skb); | ||
565 | |||
566 | if (ifmsh->preq_queue_len && | ||
567 | time_after(jiffies, | ||
568 | ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) | ||
569 | mesh_path_start_discovery(sdata); | ||
570 | |||
571 | if (ifmsh->housekeeping) | ||
572 | ieee80211_mesh_housekeeping(sdata, ifmsh); | ||
573 | } | ||
574 | |||
575 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | ||
576 | { | ||
577 | struct ieee80211_sub_if_data *sdata; | ||
578 | |||
579 | rcu_read_lock(); | ||
580 | list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||
581 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
582 | queue_work(local->hw.workqueue, &sdata->u.mesh.work); | ||
583 | rcu_read_unlock(); | ||
584 | } | ||
585 | |||
402 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | 586 | void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) |
403 | { | 587 | { |
404 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 588 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
405 | 589 | ||
406 | ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; | 590 | INIT_WORK(&ifmsh->work, ieee80211_mesh_work); |
407 | ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; | 591 | setup_timer(&ifmsh->housekeeping_timer, |
408 | ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; | 592 | ieee80211_mesh_housekeeping_timer, |
409 | ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; | 593 | (unsigned long) sdata); |
410 | ifsta->mshcfg.dot11MeshTTL = MESH_TTL; | 594 | skb_queue_head_init(&sdata->u.mesh.skb_queue); |
411 | ifsta->mshcfg.auto_open_plinks = true; | 595 | |
412 | ifsta->mshcfg.dot11MeshMaxPeerLinks = | 596 | ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; |
597 | ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; | ||
598 | ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; | ||
599 | ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; | ||
600 | ifmsh->mshcfg.dot11MeshTTL = MESH_TTL; | ||
601 | ifmsh->mshcfg.auto_open_plinks = true; | ||
602 | ifmsh->mshcfg.dot11MeshMaxPeerLinks = | ||
413 | MESH_MAX_ESTAB_PLINKS; | 603 | MESH_MAX_ESTAB_PLINKS; |
414 | ifsta->mshcfg.dot11MeshHWMPactivePathTimeout = | 604 | ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout = |
415 | MESH_PATH_TIMEOUT; | 605 | MESH_PATH_TIMEOUT; |
416 | ifsta->mshcfg.dot11MeshHWMPpreqMinInterval = | 606 | ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval = |
417 | MESH_PREQ_MIN_INT; | 607 | MESH_PREQ_MIN_INT; |
418 | ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = | 608 | ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = |
419 | MESH_DIAM_TRAVERSAL_TIME; | 609 | MESH_DIAM_TRAVERSAL_TIME; |
420 | ifsta->mshcfg.dot11MeshHWMPmaxPREQretries = | 610 | ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries = |
421 | MESH_MAX_PREQ_RETRIES; | 611 | MESH_MAX_PREQ_RETRIES; |
422 | ifsta->mshcfg.path_refresh_time = | 612 | ifmsh->mshcfg.path_refresh_time = |
423 | MESH_PATH_REFRESH_TIME; | 613 | MESH_PATH_REFRESH_TIME; |
424 | ifsta->mshcfg.min_discovery_timeout = | 614 | ifmsh->mshcfg.min_discovery_timeout = |
425 | MESH_MIN_DISCOVERY_TIMEOUT; | 615 | MESH_MIN_DISCOVERY_TIMEOUT; |
426 | ifsta->accepting_plinks = true; | 616 | ifmsh->accepting_plinks = true; |
427 | ifsta->preq_id = 0; | 617 | ifmsh->preq_id = 0; |
428 | ifsta->dsn = 0; | 618 | ifmsh->dsn = 0; |
429 | atomic_set(&ifsta->mpaths, 0); | 619 | atomic_set(&ifmsh->mpaths, 0); |
430 | mesh_rmc_init(sdata); | 620 | mesh_rmc_init(sdata); |
431 | ifsta->last_preq = jiffies; | 621 | ifmsh->last_preq = jiffies; |
432 | /* Allocate all mesh structures when creating the first mesh interface. */ | 622 | /* Allocate all mesh structures when creating the first mesh interface. */ |
433 | if (!mesh_allocated) | 623 | if (!mesh_allocated) |
434 | ieee80211s_init(); | 624 | ieee80211s_init(); |
435 | mesh_ids_set_default(ifsta); | 625 | mesh_ids_set_default(ifmsh); |
436 | setup_timer(&ifsta->mesh_path_timer, | 626 | setup_timer(&ifmsh->mesh_path_timer, |
437 | ieee80211_mesh_path_timer, | 627 | ieee80211_mesh_path_timer, |
438 | (unsigned long) sdata); | 628 | (unsigned long) sdata); |
439 | INIT_LIST_HEAD(&ifsta->preq_queue.list); | 629 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
440 | spin_lock_init(&ifsta->mesh_preq_queue_lock); | 630 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
631 | } | ||
632 | |||
633 | ieee80211_rx_result | ||
634 | ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
635 | struct ieee80211_rx_status *rx_status) | ||
636 | { | ||
637 | struct ieee80211_local *local = sdata->local; | ||
638 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
639 | struct ieee80211_mgmt *mgmt; | ||
640 | u16 fc; | ||
641 | |||
642 | if (skb->len < 24) | ||
643 | return RX_DROP_MONITOR; | ||
644 | |||
645 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
646 | fc = le16_to_cpu(mgmt->frame_control); | ||
647 | |||
648 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
649 | case IEEE80211_STYPE_PROBE_RESP: | ||
650 | case IEEE80211_STYPE_BEACON: | ||
651 | case IEEE80211_STYPE_ACTION: | ||
652 | memcpy(skb->cb, rx_status, sizeof(*rx_status)); | ||
653 | skb_queue_tail(&ifmsh->skb_queue, skb); | ||
654 | queue_work(local->hw.workqueue, &ifmsh->work); | ||
655 | return RX_QUEUED; | ||
656 | } | ||
657 | |||
658 | return RX_CONTINUE; | ||
441 | } | 659 | } |