diff options
-rw-r--r-- | include/linux/ieee80211.h | 12 | ||||
-rw-r--r-- | net/mac80211/Kconfig | 11 | ||||
-rw-r--r-- | net/mac80211/Makefile | 3 | ||||
-rw-r--r-- | net/mac80211/debugfs_sta.c | 5 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 23 | ||||
-rw-r--r-- | net/mac80211/mesh.c | 21 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 19 | ||||
-rw-r--r-- | net/mac80211/mesh_sync.c | 296 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 5 | ||||
-rw-r--r-- | net/mac80211/tx.c | 5 |
10 files changed, 392 insertions, 8 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 09301b0768d0..db84e2f6b289 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h | |||
@@ -1439,6 +1439,18 @@ enum ieee80211_tdls_actioncode { | |||
1439 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 | 1439 | #define WLAN_TDLS_SNAP_RFTYPE 0x2 |
1440 | 1440 | ||
1441 | /** | 1441 | /** |
1442 | * enum - mesh synchronization method identifier | ||
1443 | * | ||
1444 | * @IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET: the default synchronization method | ||
1445 | * @IEEE80211_SYNC_METHOD_VENDOR: a vendor specific synchronization method | ||
1446 | * that will be specified in a vendor specific information element | ||
1447 | */ | ||
1448 | enum { | ||
1449 | IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET = 1, | ||
1450 | IEEE80211_SYNC_METHOD_VENDOR = 255, | ||
1451 | }; | ||
1452 | |||
1453 | /** | ||
1442 | * enum - mesh path selection protocol identifier | 1454 | * enum - mesh path selection protocol identifier |
1443 | * | 1455 | * |
1444 | * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol | 1456 | * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol |
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 96ddb72760b9..8d249d705980 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig | |||
@@ -225,6 +225,17 @@ config MAC80211_VERBOSE_MHWMP_DEBUG | |||
225 | 225 | ||
226 | Do not select this option. | 226 | Do not select this option. |
227 | 227 | ||
228 | config MAC80211_VERBOSE_MESH_SYNC_DEBUG | ||
229 | bool "Verbose mesh mesh synchronization debugging" | ||
230 | depends on MAC80211_DEBUG_MENU | ||
231 | depends on MAC80211_MESH | ||
232 | ---help--- | ||
233 | Selecting this option causes mac80211 to print out very verbose mesh | ||
234 | synchronization debugging messages (when mac80211 is taking part in a | ||
235 | mesh network). | ||
236 | |||
237 | Do not select this option. | ||
238 | |||
228 | config MAC80211_VERBOSE_TDLS_DEBUG | 239 | config MAC80211_VERBOSE_TDLS_DEBUG |
229 | bool "Verbose TDLS debugging" | 240 | bool "Verbose TDLS debugging" |
230 | depends on MAC80211_DEBUG_MENU | 241 | depends on MAC80211_DEBUG_MENU |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 1be7a454aa77..3e9d931bba35 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -38,7 +38,8 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ | |||
38 | mesh.o \ | 38 | mesh.o \ |
39 | mesh_pathtbl.o \ | 39 | mesh_pathtbl.o \ |
40 | mesh_plink.o \ | 40 | mesh_plink.o \ |
41 | mesh_hwmp.o | 41 | mesh_hwmp.o \ |
42 | mesh_sync.o | ||
42 | 43 | ||
43 | mac80211-$(CONFIG_PM) += pm.o | 44 | mac80211-$(CONFIG_PM) += pm.o |
44 | 45 | ||
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 6d45804d09bc..ceeefd424103 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -63,7 +63,7 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
63 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" | 63 | test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" |
64 | 64 | ||
65 | int res = scnprintf(buf, sizeof(buf), | 65 | int res = scnprintf(buf, sizeof(buf), |
66 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", | 66 | "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", |
67 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), | 67 | TEST(AUTH), TEST(ASSOC), TEST(PS_STA), |
68 | TEST(PS_DRIVER), TEST(AUTHORIZED), | 68 | TEST(PS_DRIVER), TEST(AUTHORIZED), |
69 | TEST(SHORT_PREAMBLE), | 69 | TEST(SHORT_PREAMBLE), |
@@ -71,7 +71,8 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, | |||
71 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), | 71 | TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), |
72 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), | 72 | TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), |
73 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), | 73 | TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT), |
74 | TEST(INSERTED), TEST(RATE_CONTROL)); | 74 | TEST(INSERTED), TEST(RATE_CONTROL), |
75 | TEST(TOFFSET_KNOWN)); | ||
75 | #undef TEST | 76 | #undef TEST |
76 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); | 77 | return simple_read_from_buffer(userbuf, count, ppos, buf, res); |
77 | } | 78 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8e7af7cee013..ea9623cbd969 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -554,6 +554,24 @@ struct ieee80211_if_ibss { | |||
554 | } state; | 554 | } state; |
555 | }; | 555 | }; |
556 | 556 | ||
557 | /** | ||
558 | * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface | ||
559 | * | ||
560 | * these declarations define the interface, which enables | ||
561 | * vendor-specific mesh synchronization | ||
562 | * | ||
563 | */ | ||
564 | struct ieee802_11_elems; | ||
565 | struct ieee80211_mesh_sync_ops { | ||
566 | void (*rx_bcn_presp)(struct ieee80211_sub_if_data *sdata, | ||
567 | u16 stype, | ||
568 | struct ieee80211_mgmt *mgmt, | ||
569 | struct ieee802_11_elems *elems, | ||
570 | struct ieee80211_rx_status *rx_status); | ||
571 | void (*adjust_tbtt)(struct ieee80211_sub_if_data *sdata); | ||
572 | /* add other framework functions here */ | ||
573 | }; | ||
574 | |||
557 | struct ieee80211_if_mesh { | 575 | struct ieee80211_if_mesh { |
558 | struct timer_list housekeeping_timer; | 576 | struct timer_list housekeeping_timer; |
559 | struct timer_list mesh_path_timer; | 577 | struct timer_list mesh_path_timer; |
@@ -602,6 +620,11 @@ struct ieee80211_if_mesh { | |||
602 | IEEE80211_MESH_SEC_AUTHED = 0x1, | 620 | IEEE80211_MESH_SEC_AUTHED = 0x1, |
603 | IEEE80211_MESH_SEC_SECURED = 0x2, | 621 | IEEE80211_MESH_SEC_SECURED = 0x2, |
604 | } security; | 622 | } security; |
623 | /* Extensible Synchronization Framework */ | ||
624 | struct ieee80211_mesh_sync_ops *sync_ops; | ||
625 | s64 sync_offset_clockdrift_max; | ||
626 | spinlock_t sync_offset_lock; | ||
627 | bool adjusting_tbtt; | ||
605 | }; | 628 | }; |
606 | 629 | ||
607 | #ifdef CONFIG_MAC80211_MESH | 630 | #ifdef CONFIG_MAC80211_MESH |
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index b05fa9ef866c..386dbca1eab3 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
@@ -13,9 +13,6 @@ | |||
13 | #include "ieee80211_i.h" | 13 | #include "ieee80211_i.h" |
14 | #include "mesh.h" | 14 | #include "mesh.h" |
15 | 15 | ||
16 | #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 | ||
17 | #define MESHCONF_CAPAB_FORWARDING 0x08 | ||
18 | |||
19 | #define TMR_RUNNING_HK 0 | 16 | #define TMR_RUNNING_HK 0 |
20 | #define TMR_RUNNING_MP 1 | 17 | #define TMR_RUNNING_MP 1 |
21 | #define TMR_RUNNING_MPR 2 | 18 | #define TMR_RUNNING_MPR 2 |
@@ -251,8 +248,10 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
251 | /* Mesh capability */ | 248 | /* Mesh capability */ |
252 | ifmsh->accepting_plinks = mesh_plink_availables(sdata); | 249 | ifmsh->accepting_plinks = mesh_plink_availables(sdata); |
253 | *pos = MESHCONF_CAPAB_FORWARDING; | 250 | *pos = MESHCONF_CAPAB_FORWARDING; |
254 | *pos++ |= ifmsh->accepting_plinks ? | 251 | *pos |= ifmsh->accepting_plinks ? |
255 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | 252 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
253 | *pos++ |= ifmsh->adjusting_tbtt ? | ||
254 | MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; | ||
256 | *pos++ = 0x00; | 255 | *pos++ = 0x00; |
257 | 256 | ||
258 | return 0; | 257 | return 0; |
@@ -573,8 +572,11 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
573 | ieee80211_configure_filter(local); | 572 | ieee80211_configure_filter(local); |
574 | 573 | ||
575 | ifmsh->mesh_cc_id = 0; /* Disabled */ | 574 | ifmsh->mesh_cc_id = 0; /* Disabled */ |
576 | ifmsh->mesh_sp_id = 0; /* Neighbor Offset */ | ||
577 | ifmsh->mesh_auth_id = 0; /* Disabled */ | 575 | ifmsh->mesh_auth_id = 0; /* Disabled */ |
576 | /* register sync ops from extensible synchronization framework */ | ||
577 | ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id); | ||
578 | ifmsh->adjusting_tbtt = false; | ||
579 | ifmsh->sync_offset_clockdrift_max = 0; | ||
578 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); | 580 | set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); |
579 | ieee80211_mesh_root_setup(ifmsh); | 581 | ieee80211_mesh_root_setup(ifmsh); |
580 | ieee80211_queue_work(&local->hw, &sdata->work); | 582 | ieee80211_queue_work(&local->hw, &sdata->work); |
@@ -616,6 +618,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
616 | struct ieee80211_rx_status *rx_status) | 618 | struct ieee80211_rx_status *rx_status) |
617 | { | 619 | { |
618 | struct ieee80211_local *local = sdata->local; | 620 | struct ieee80211_local *local = sdata->local; |
621 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
619 | struct ieee802_11_elems elems; | 622 | struct ieee802_11_elems elems; |
620 | struct ieee80211_channel *channel; | 623 | struct ieee80211_channel *channel; |
621 | u32 supp_rates = 0; | 624 | u32 supp_rates = 0; |
@@ -654,6 +657,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
654 | supp_rates = ieee80211_sta_get_rates(local, &elems, band); | 657 | supp_rates = ieee80211_sta_get_rates(local, &elems, band); |
655 | mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); | 658 | mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); |
656 | } | 659 | } |
660 | |||
661 | if (ifmsh->sync_ops) | ||
662 | ifmsh->sync_ops->rx_bcn_presp(sdata, | ||
663 | stype, mgmt, &elems, rx_status); | ||
657 | } | 664 | } |
658 | 665 | ||
659 | static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, | 666 | static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, |
@@ -721,6 +728,9 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) | |||
721 | 728 | ||
722 | if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) | 729 | if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) |
723 | ieee80211_mesh_rootpath(sdata); | 730 | ieee80211_mesh_rootpath(sdata); |
731 | |||
732 | if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) | ||
733 | mesh_sync_adjust_tbtt(sdata); | ||
724 | } | 734 | } |
725 | 735 | ||
726 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | 736 | void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) |
@@ -761,4 +771,5 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | |||
761 | (unsigned long) sdata); | 771 | (unsigned long) sdata); |
762 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); | 772 | INIT_LIST_HEAD(&ifmsh->preq_queue.list); |
763 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); | 773 | spin_lock_init(&ifmsh->mesh_preq_queue_lock); |
774 | spin_lock_init(&ifmsh->sync_offset_lock); | ||
764 | } | 775 | } |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 3e52439ed112..fa7d9704c175 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -19,6 +19,20 @@ | |||
19 | /* Data structures */ | 19 | /* Data structures */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * enum mesh_config_capab_flags - mesh config IE capability flags | ||
23 | * | ||
24 | * @MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish | ||
25 | * additional mesh peerings with other mesh STAs | ||
26 | * @MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs | ||
27 | * @MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure is ongoing | ||
28 | */ | ||
29 | enum mesh_config_capab_flags { | ||
30 | MESHCONF_CAPAB_ACCEPT_PLINKS = BIT(0), | ||
31 | MESHCONF_CAPAB_FORWARDING = BIT(3), | ||
32 | MESHCONF_CAPAB_TBTT_ADJUSTING = BIT(5), | ||
33 | }; | ||
34 | |||
35 | /** | ||
22 | * enum mesh_path_flags - mac80211 mesh path flags | 36 | * enum mesh_path_flags - mac80211 mesh path flags |
23 | * | 37 | * |
24 | * | 38 | * |
@@ -56,12 +70,15 @@ enum mesh_path_flags { | |||
56 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to | 70 | * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to |
57 | * grow | 71 | * grow |
58 | * @MESH_WORK_ROOT: the mesh root station needs to send a frame | 72 | * @MESH_WORK_ROOT: the mesh root station needs to send a frame |
73 | * @MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other | ||
74 | * mesh nodes | ||
59 | */ | 75 | */ |
60 | enum mesh_deferred_task_flags { | 76 | enum mesh_deferred_task_flags { |
61 | MESH_WORK_HOUSEKEEPING, | 77 | MESH_WORK_HOUSEKEEPING, |
62 | MESH_WORK_GROW_MPATH_TABLE, | 78 | MESH_WORK_GROW_MPATH_TABLE, |
63 | MESH_WORK_GROW_MPP_TABLE, | 79 | MESH_WORK_GROW_MPP_TABLE, |
64 | MESH_WORK_ROOT, | 80 | MESH_WORK_ROOT, |
81 | MESH_WORK_DRIFT_ADJUST, | ||
65 | }; | 82 | }; |
66 | 83 | ||
67 | /** | 84 | /** |
@@ -234,6 +251,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); | |||
234 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 251 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
235 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); | 252 | void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); |
236 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); | 253 | void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); |
254 | struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); | ||
237 | 255 | ||
238 | /* Mesh paths */ | 256 | /* Mesh paths */ |
239 | int mesh_nexthop_lookup(struct sk_buff *skb, | 257 | int mesh_nexthop_lookup(struct sk_buff *skb, |
@@ -327,6 +345,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata); | |||
327 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); | 345 | void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); |
328 | void mesh_plink_quiesce(struct sta_info *sta); | 346 | void mesh_plink_quiesce(struct sta_info *sta); |
329 | void mesh_plink_restart(struct sta_info *sta); | 347 | void mesh_plink_restart(struct sta_info *sta); |
348 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); | ||
330 | #else | 349 | #else |
331 | #define mesh_allocated 0 | 350 | #define mesh_allocated 0 |
332 | static inline void | 351 | static inline void |
diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c new file mode 100644 index 000000000000..f78b0139856f --- /dev/null +++ b/net/mac80211/mesh_sync.c | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | * Copyright 2011-2012, Pavel Zubarev <pavel.zubarev@gmail.com> | ||
3 | * Copyright 2011-2012, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de> | ||
4 | * Copyright 2011-2012, cozybit Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include "ieee80211_i.h" | ||
12 | #include "mesh.h" | ||
13 | #include "driver-ops.h" | ||
14 | |||
15 | #ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG | ||
16 | #define msync_dbg(fmt, args...) \ | ||
17 | printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args) | ||
18 | #else | ||
19 | #define msync_dbg(fmt, args...) do { (void)(0); } while (0) | ||
20 | #endif | ||
21 | |||
22 | /* This is not in the standard. It represents a tolerable tbtt drift below | ||
23 | * which we do no TSF adjustment. | ||
24 | */ | ||
25 | #define TBTT_MINIMUM_ADJUSTMENT 10 | ||
26 | |||
27 | struct sync_method { | ||
28 | u8 method; | ||
29 | struct ieee80211_mesh_sync_ops ops; | ||
30 | }; | ||
31 | |||
32 | /** | ||
33 | * mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT | ||
34 | * | ||
35 | * @ie: information elements of a management frame from the mesh peer | ||
36 | */ | ||
37 | static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie) | ||
38 | { | ||
39 | return (ie->mesh_config->meshconf_cap & | ||
40 | MESHCONF_CAPAB_TBTT_ADJUSTING) != 0; | ||
41 | } | ||
42 | |||
43 | void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | ||
44 | { | ||
45 | struct ieee80211_local *local = sdata->local; | ||
46 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
47 | /* sdata->vif.bss_conf.beacon_int in 1024us units, 0.04% */ | ||
48 | u64 beacon_int_fraction = sdata->vif.bss_conf.beacon_int * 1024 / 2500; | ||
49 | u64 tsf; | ||
50 | u64 tsfdelta; | ||
51 | |||
52 | spin_lock_bh(&ifmsh->sync_offset_lock); | ||
53 | |||
54 | if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) { | ||
55 | msync_dbg("TBTT : max clockdrift=%lld; adjusting", | ||
56 | (long long) ifmsh->sync_offset_clockdrift_max); | ||
57 | tsfdelta = -ifmsh->sync_offset_clockdrift_max; | ||
58 | ifmsh->sync_offset_clockdrift_max = 0; | ||
59 | } else { | ||
60 | msync_dbg("TBTT : max clockdrift=%lld; adjusting by %llu", | ||
61 | (long long) ifmsh->sync_offset_clockdrift_max, | ||
62 | (unsigned long long) beacon_int_fraction); | ||
63 | tsfdelta = -beacon_int_fraction; | ||
64 | ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction; | ||
65 | } | ||
66 | |||
67 | tsf = drv_get_tsf(local, sdata); | ||
68 | if (tsf != -1ULL) | ||
69 | drv_set_tsf(local, sdata, tsf + tsfdelta); | ||
70 | spin_unlock_bh(&ifmsh->sync_offset_lock); | ||
71 | } | ||
72 | |||
73 | static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | ||
74 | u16 stype, | ||
75 | struct ieee80211_mgmt *mgmt, | ||
76 | struct ieee802_11_elems *elems, | ||
77 | struct ieee80211_rx_status *rx_status) | ||
78 | { | ||
79 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
80 | struct ieee80211_local *local = sdata->local; | ||
81 | struct sta_info *sta; | ||
82 | u64 t_t, t_r; | ||
83 | |||
84 | WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET); | ||
85 | |||
86 | /* standard mentions only beacons */ | ||
87 | if (stype != IEEE80211_STYPE_BEACON) | ||
88 | return; | ||
89 | |||
90 | /* The current tsf is a first approximation for the timestamp | ||
91 | * for the received beacon. Further down we try to get a | ||
92 | * better value from the rx_status->mactime field if | ||
93 | * available. Also we have to call drv_get_tsf() before | ||
94 | * entering the rcu-read section.*/ | ||
95 | t_r = drv_get_tsf(local, sdata); | ||
96 | |||
97 | rcu_read_lock(); | ||
98 | sta = sta_info_get(sdata, mgmt->sa); | ||
99 | if (!sta) | ||
100 | goto no_sync; | ||
101 | |||
102 | /* check offset sync conditions (13.13.2.2.1) | ||
103 | * | ||
104 | * TODO also sync to | ||
105 | * dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors | ||
106 | */ | ||
107 | |||
108 | if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) { | ||
109 | clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); | ||
110 | msync_dbg("STA %pM : is adjusting TBTT", sta->sta.addr); | ||
111 | goto no_sync; | ||
112 | } | ||
113 | |||
114 | if (rx_status->flag & RX_FLAG_MACTIME_MPDU && rx_status->mactime) { | ||
115 | /* | ||
116 | * The mactime is defined as the time the first data symbol | ||
117 | * of the frame hits the PHY, and the timestamp of the beacon | ||
118 | * is defined as "the time that the data symbol containing the | ||
119 | * first bit of the timestamp is transmitted to the PHY plus | ||
120 | * the transmitting STA's delays through its local PHY from the | ||
121 | * MAC-PHY interface to its interface with the WM" (802.11 | ||
122 | * 11.1.2) | ||
123 | * | ||
124 | * T_r, in 13.13.2.2.2, is just defined as "the frame reception | ||
125 | * time" but we unless we interpret that time to be the same | ||
126 | * time of the beacon timestamp, the offset calculation will be | ||
127 | * off. Below we adjust t_r to be "the time at which the first | ||
128 | * symbol of the timestamp element in the beacon is received". | ||
129 | * This correction depends on the rate. | ||
130 | * | ||
131 | * Based on similar code in ibss.c | ||
132 | */ | ||
133 | int rate; | ||
134 | |||
135 | if (rx_status->flag & RX_FLAG_HT) { | ||
136 | /* TODO: | ||
137 | * In principle there could be HT-beacons (Dual Beacon | ||
138 | * HT Operation options), but for now ignore them and | ||
139 | * just use the primary (i.e. non-HT) beacons for | ||
140 | * synchronization. | ||
141 | * */ | ||
142 | goto no_sync; | ||
143 | } else | ||
144 | rate = local->hw.wiphy->bands[rx_status->band]-> | ||
145 | bitrates[rx_status->rate_idx].bitrate; | ||
146 | |||
147 | /* 24 bytes of header * 8 bits/byte * | ||
148 | * 10*(100 Kbps)/Mbps / rate (100 Kbps)*/ | ||
149 | t_r = rx_status->mactime + (24 * 8 * 10 / rate); | ||
150 | } | ||
151 | |||
152 | /* Timing offset calculation (see 13.13.2.2.2) */ | ||
153 | t_t = le64_to_cpu(mgmt->u.beacon.timestamp); | ||
154 | sta->t_offset = t_t - t_r; | ||
155 | |||
156 | if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { | ||
157 | s64 t_clockdrift = sta->t_offset_setpoint | ||
158 | - sta->t_offset; | ||
159 | |||
160 | msync_dbg("STA %pM : sta->t_offset=%lld," | ||
161 | " sta->t_offset_setpoint=%lld," | ||
162 | " t_clockdrift=%lld", | ||
163 | sta->sta.addr, | ||
164 | (long long) sta->t_offset, | ||
165 | (long long) | ||
166 | sta->t_offset_setpoint, | ||
167 | (long long) t_clockdrift); | ||
168 | rcu_read_unlock(); | ||
169 | |||
170 | spin_lock_bh(&ifmsh->sync_offset_lock); | ||
171 | if (t_clockdrift > | ||
172 | ifmsh->sync_offset_clockdrift_max) | ||
173 | ifmsh->sync_offset_clockdrift_max | ||
174 | = t_clockdrift; | ||
175 | spin_unlock_bh(&ifmsh->sync_offset_lock); | ||
176 | |||
177 | } else { | ||
178 | sta->t_offset_setpoint = sta->t_offset; | ||
179 | set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); | ||
180 | msync_dbg("STA %pM : offset was invalid, " | ||
181 | " sta->t_offset=%lld", | ||
182 | sta->sta.addr, | ||
183 | (long long) sta->t_offset); | ||
184 | rcu_read_unlock(); | ||
185 | } | ||
186 | return; | ||
187 | |||
188 | no_sync: | ||
189 | rcu_read_unlock(); | ||
190 | } | ||
191 | |||
192 | static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | ||
193 | { | ||
194 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
195 | |||
196 | WARN_ON(ifmsh->mesh_sp_id | ||
197 | != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET); | ||
198 | BUG_ON(!rcu_read_lock_held()); | ||
199 | |||
200 | spin_lock_bh(&ifmsh->sync_offset_lock); | ||
201 | |||
202 | if (ifmsh->sync_offset_clockdrift_max > | ||
203 | TBTT_MINIMUM_ADJUSTMENT) { | ||
204 | /* Since ajusting the tsf here would | ||
205 | * require a possibly blocking call | ||
206 | * to the driver tsf setter, we punt | ||
207 | * the tsf adjustment to the mesh tasklet | ||
208 | */ | ||
209 | msync_dbg("TBTT : kicking off TBTT " | ||
210 | "adjustment with " | ||
211 | "clockdrift_max=%lld", | ||
212 | ifmsh->sync_offset_clockdrift_max); | ||
213 | set_bit(MESH_WORK_DRIFT_ADJUST, | ||
214 | &ifmsh->wrkq_flags); | ||
215 | } else { | ||
216 | msync_dbg("TBTT : max clockdrift=%lld; " | ||
217 | "too small to adjust", | ||
218 | (long long) | ||
219 | ifmsh->sync_offset_clockdrift_max); | ||
220 | ifmsh->sync_offset_clockdrift_max = 0; | ||
221 | } | ||
222 | spin_unlock_bh(&ifmsh->sync_offset_lock); | ||
223 | } | ||
224 | |||
225 | static const u8 *mesh_get_vendor_oui(struct ieee80211_sub_if_data *sdata) | ||
226 | { | ||
227 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
228 | u8 offset; | ||
229 | |||
230 | if (!ifmsh->ie || !ifmsh->ie_len) | ||
231 | return NULL; | ||
232 | |||
233 | offset = ieee80211_ie_split_vendor(ifmsh->ie, | ||
234 | ifmsh->ie_len, 0); | ||
235 | |||
236 | if (!offset) | ||
237 | return NULL; | ||
238 | |||
239 | return ifmsh->ie + offset + 2; | ||
240 | } | ||
241 | |||
242 | static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | ||
243 | u16 stype, | ||
244 | struct ieee80211_mgmt *mgmt, | ||
245 | struct ieee802_11_elems *elems, | ||
246 | struct ieee80211_rx_status *rx_status) | ||
247 | { | ||
248 | const u8 *oui; | ||
249 | |||
250 | WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); | ||
251 | msync_dbg("called mesh_sync_vendor_rx_bcn_presp"); | ||
252 | oui = mesh_get_vendor_oui(sdata); | ||
253 | /* here you would implement the vendor offset tracking for this oui */ | ||
254 | } | ||
255 | |||
256 | static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata) | ||
257 | { | ||
258 | const u8 *oui; | ||
259 | |||
260 | WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); | ||
261 | msync_dbg("called mesh_sync_vendor_adjust_tbtt"); | ||
262 | oui = mesh_get_vendor_oui(sdata); | ||
263 | /* here you would implement the vendor tsf adjustment for this oui */ | ||
264 | } | ||
265 | |||
266 | /* global variable */ | ||
267 | static struct sync_method sync_methods[] = { | ||
268 | { | ||
269 | .method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET, | ||
270 | .ops = { | ||
271 | .rx_bcn_presp = &mesh_sync_offset_rx_bcn_presp, | ||
272 | .adjust_tbtt = &mesh_sync_offset_adjust_tbtt, | ||
273 | } | ||
274 | }, | ||
275 | { | ||
276 | .method = IEEE80211_SYNC_METHOD_VENDOR, | ||
277 | .ops = { | ||
278 | .rx_bcn_presp = &mesh_sync_vendor_rx_bcn_presp, | ||
279 | .adjust_tbtt = &mesh_sync_vendor_adjust_tbtt, | ||
280 | } | ||
281 | }, | ||
282 | }; | ||
283 | |||
284 | struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method) | ||
285 | { | ||
286 | struct ieee80211_mesh_sync_ops *ops = NULL; | ||
287 | u8 i; | ||
288 | |||
289 | for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) { | ||
290 | if (sync_methods[i].method == method) { | ||
291 | ops = &sync_methods[i].ops; | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | return ops; | ||
296 | } | ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b1b4b1413c74..f75f5d9ac06d 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -55,6 +55,7 @@ | |||
55 | * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. | 55 | * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. |
56 | * @WLAN_STA_INSERTED: This station is inserted into the hash table. | 56 | * @WLAN_STA_INSERTED: This station is inserted into the hash table. |
57 | * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. | 57 | * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station. |
58 | * @WLAN_STA_TOFFSET_KNOWN: toffset calculated for this station is valid. | ||
58 | */ | 59 | */ |
59 | enum ieee80211_sta_info_flags { | 60 | enum ieee80211_sta_info_flags { |
60 | WLAN_STA_AUTH, | 61 | WLAN_STA_AUTH, |
@@ -76,6 +77,7 @@ enum ieee80211_sta_info_flags { | |||
76 | WLAN_STA_4ADDR_EVENT, | 77 | WLAN_STA_4ADDR_EVENT, |
77 | WLAN_STA_INSERTED, | 78 | WLAN_STA_INSERTED, |
78 | WLAN_STA_RATE_CONTROL, | 79 | WLAN_STA_RATE_CONTROL, |
80 | WLAN_STA_TOFFSET_KNOWN, | ||
79 | }; | 81 | }; |
80 | 82 | ||
81 | #define STA_TID_NUM 16 | 83 | #define STA_TID_NUM 16 |
@@ -268,6 +270,7 @@ struct sta_ampdu_mlme { | |||
268 | * @plink_timeout: timeout of peer link | 270 | * @plink_timeout: timeout of peer link |
269 | * @plink_timer: peer link watch timer | 271 | * @plink_timer: peer link watch timer |
270 | * @plink_timer_was_running: used by suspend/resume to restore timers | 272 | * @plink_timer_was_running: used by suspend/resume to restore timers |
273 | * @t_offset: timing offset relative to this host | ||
271 | * @debugfs: debug filesystem info | 274 | * @debugfs: debug filesystem info |
272 | * @dead: set to true when sta is unlinked | 275 | * @dead: set to true when sta is unlinked |
273 | * @uploaded: set to true when sta is uploaded to the driver | 276 | * @uploaded: set to true when sta is uploaded to the driver |
@@ -357,6 +360,8 @@ struct sta_info { | |||
357 | enum nl80211_plink_state plink_state; | 360 | enum nl80211_plink_state plink_state; |
358 | u32 plink_timeout; | 361 | u32 plink_timeout; |
359 | struct timer_list plink_timer; | 362 | struct timer_list plink_timer; |
363 | s64 t_offset; | ||
364 | s64 t_offset_setpoint; | ||
360 | #endif | 365 | #endif |
361 | 366 | ||
362 | #ifdef CONFIG_MAC80211_DEBUGFS | 367 | #ifdef CONFIG_MAC80211_DEBUGFS |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e0b89780b472..daab5adeb93c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -2373,6 +2373,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2373 | IEEE80211_STYPE_BEACON); | 2373 | IEEE80211_STYPE_BEACON); |
2374 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2374 | } else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
2375 | struct ieee80211_mgmt *mgmt; | 2375 | struct ieee80211_mgmt *mgmt; |
2376 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||
2376 | u8 *pos; | 2377 | u8 *pos; |
2377 | int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + | 2378 | int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + |
2378 | sizeof(mgmt->u.beacon); | 2379 | sizeof(mgmt->u.beacon); |
@@ -2382,6 +2383,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2382 | goto out; | 2383 | goto out; |
2383 | #endif | 2384 | #endif |
2384 | 2385 | ||
2386 | if (ifmsh->sync_ops) | ||
2387 | ifmsh->sync_ops->adjust_tbtt( | ||
2388 | sdata); | ||
2389 | |||
2385 | skb = dev_alloc_skb(local->tx_headroom + | 2390 | skb = dev_alloc_skb(local->tx_headroom + |
2386 | hdr_len + | 2391 | hdr_len + |
2387 | 2 + /* NULL SSID */ | 2392 | 2 + /* NULL SSID */ |