aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/Kconfig11
-rw-r--r--net/mac80211/Makefile3
-rw-r--r--net/mac80211/debugfs_sta.c5
-rw-r--r--net/mac80211/ieee80211_i.h23
-rw-r--r--net/mac80211/mesh.c21
-rw-r--r--net/mac80211/mesh.h19
-rw-r--r--net/mac80211/mesh_sync.c296
-rw-r--r--net/mac80211/sta_info.h5
-rw-r--r--net/mac80211/tx.c5
9 files changed, 380 insertions, 8 deletions
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
228config 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
228config MAC80211_VERBOSE_TDLS_DEBUG 239config 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
43mac80211-$(CONFIG_PM) += pm.o 44mac80211-$(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 */
564struct ieee802_11_elems;
565struct 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
557struct ieee80211_if_mesh { 575struct 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
659static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, 666static 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
726void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) 736void 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 */
29enum 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 */
60enum mesh_deferred_task_flags { 76enum 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);
234void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); 251void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata);
235void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); 252void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata);
236void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); 253void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh);
254struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method);
237 255
238/* Mesh paths */ 256/* Mesh paths */
239int mesh_nexthop_lookup(struct sk_buff *skb, 257int mesh_nexthop_lookup(struct sk_buff *skb,
@@ -327,6 +345,7 @@ void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
327void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); 345void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata);
328void mesh_plink_quiesce(struct sta_info *sta); 346void mesh_plink_quiesce(struct sta_info *sta);
329void mesh_plink_restart(struct sta_info *sta); 347void mesh_plink_restart(struct sta_info *sta);
348void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata);
330#else 349#else
331#define mesh_allocated 0 350#define mesh_allocated 0
332static inline void 351static 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
27struct 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 */
37static 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
43void 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
73static 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
188no_sync:
189 rcu_read_unlock();
190}
191
192static 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
225static 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
242static 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
256static 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 */
267static 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
284struct 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 */
59enum ieee80211_sta_info_flags { 60enum 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 */