00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "ieee80211_i.h"
00012 #include "mesh.h"
00013 #include "driver-ops.h"
00014
00015 #ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG
00016 #define msync_dbg(fmt, args...) \
00017 printk(KERN_DEBUG "Mesh sync (%s): " fmt "\n", sdata->name, ##args)
00018 #else
00019 #define msync_dbg(fmt, args...) do { (void)(0); } while (0)
00020 #endif
00021
00022
00023
00024
00025 #define TOFFSET_MINIMUM_ADJUSTMENT 10
00026
00027
00028
00029
00030
00031 #define TOFFSET_SET_MARGIN 20
00032
00033
00034
00035
00036
00037
00038 #define TOFFSET_MAXIMUM_ADJUSTMENT 30000
00039
00040 struct sync_method {
00041 u8 method;
00042 struct ieee80211_mesh_sync_ops ops;
00043 };
00044
00050 static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
00051 {
00052 return (ie->mesh_config->meshconf_cap &
00053 MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
00054 }
00055
00056 void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
00057 {
00058 struct ieee80211_local *local = sdata->local;
00059 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00060
00061 u64 beacon_int_fraction = sdata->vif.bss_conf.beacon_int * 1024 / 2500;
00062 u64 tsf;
00063 u64 tsfdelta;
00064
00065 spin_lock_bh(&ifmsh->sync_offset_lock);
00066
00067 if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) {
00068 msync_dbg("TBTT : max clockdrift=%lld; adjusting",
00069 (long long) ifmsh->sync_offset_clockdrift_max);
00070 tsfdelta = -ifmsh->sync_offset_clockdrift_max;
00071 ifmsh->sync_offset_clockdrift_max = 0;
00072 } else {
00073 msync_dbg("TBTT : max clockdrift=%lld; adjusting by %llu",
00074 (long long) ifmsh->sync_offset_clockdrift_max,
00075 (unsigned long long) beacon_int_fraction);
00076 tsfdelta = -beacon_int_fraction;
00077 ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction;
00078 }
00079
00080 tsf = drv_get_tsf(local, sdata);
00081 if (tsf != -1ULL)
00082 drv_set_tsf(local, sdata, tsf + tsfdelta);
00083 spin_unlock_bh(&ifmsh->sync_offset_lock);
00084 }
00085
00086 static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
00087 u16 stype,
00088 struct ieee80211_mgmt *mgmt,
00089 struct ieee802_11_elems *elems,
00090 struct ieee80211_rx_status *rx_status)
00091 {
00092 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00093 struct ieee80211_local *local = sdata->local;
00094 struct sta_info *sta;
00095 u64 t_t, t_r;
00096
00097 WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
00098
00099
00100 if (stype != IEEE80211_STYPE_BEACON)
00101 return;
00102
00103
00104
00105
00106
00107
00108 t_r = drv_get_tsf(local, sdata);
00109
00110 rcu_read_lock();
00111 sta = sta_info_get(sdata, mgmt->sa);
00112 if (!sta)
00113 goto no_sync;
00114
00115
00116
00117
00118
00119
00120
00121 if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) {
00122 clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
00123 msync_dbg("STA %pM : is adjusting TBTT", sta->sta.addr);
00124 goto no_sync;
00125 }
00126
00127 if (rx_status->flag & RX_FLAG_MACTIME_MPDU && rx_status->mactime) {
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 int rate;
00147
00148 if (rx_status->flag & RX_FLAG_HT) {
00149
00150
00151
00152
00153
00154
00155 goto no_sync;
00156 } else
00157 rate = local->hw.wiphy->bands[rx_status->band]->
00158 bitrates[rx_status->rate_idx].bitrate;
00159
00160
00161
00162 t_r = rx_status->mactime + (24 * 8 * 10 / rate);
00163 }
00164
00165
00166 t_t = le64_to_cpu(mgmt->u.beacon.timestamp);
00167 sta->t_offset = t_t - t_r;
00168
00169 if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
00170 s64 t_clockdrift = sta->t_offset_setpoint
00171 - sta->t_offset;
00172 msync_dbg("STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld",
00173 sta->sta.addr,
00174 (long long) sta->t_offset,
00175 (long long)
00176 sta->t_offset_setpoint,
00177 (long long) t_clockdrift);
00178
00179 if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT ||
00180 t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) {
00181 msync_dbg("STA %pM : t_clockdrift=%lld too large, setpoint reset",
00182 sta->sta.addr,
00183 (long long) t_clockdrift);
00184 clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
00185 goto no_sync;
00186 }
00187
00188 rcu_read_unlock();
00189
00190 spin_lock_bh(&ifmsh->sync_offset_lock);
00191 if (t_clockdrift >
00192 ifmsh->sync_offset_clockdrift_max)
00193 ifmsh->sync_offset_clockdrift_max
00194 = t_clockdrift;
00195 spin_unlock_bh(&ifmsh->sync_offset_lock);
00196
00197 } else {
00198 sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN;
00199 set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
00200 msync_dbg("STA %pM : offset was invalid, "
00201 " sta->t_offset=%lld",
00202 sta->sta.addr,
00203 (long long) sta->t_offset);
00204 rcu_read_unlock();
00205 }
00206 return;
00207
00208 no_sync:
00209 rcu_read_unlock();
00210 }
00211
00212 static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
00213 {
00214 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00215
00216 WARN_ON(ifmsh->mesh_sp_id
00217 != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
00218 BUG_ON(!rcu_read_lock_held());
00219
00220 spin_lock_bh(&ifmsh->sync_offset_lock);
00221
00222 if (ifmsh->sync_offset_clockdrift_max >
00223 TOFFSET_MINIMUM_ADJUSTMENT) {
00224
00225
00226
00227
00228
00229 msync_dbg("TBTT : kicking off TBTT "
00230 "adjustment with "
00231 "clockdrift_max=%lld",
00232 ifmsh->sync_offset_clockdrift_max);
00233 set_bit(MESH_WORK_DRIFT_ADJUST,
00234 &ifmsh->wrkq_flags);
00235 } else {
00236 msync_dbg("TBTT : max clockdrift=%lld; "
00237 "too small to adjust",
00238 (long long)
00239 ifmsh->sync_offset_clockdrift_max);
00240 ifmsh->sync_offset_clockdrift_max = 0;
00241 }
00242 spin_unlock_bh(&ifmsh->sync_offset_lock);
00243 }
00244
00245 static const u8 *mesh_get_vendor_oui(struct ieee80211_sub_if_data *sdata)
00246 {
00247 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
00248 u8 offset;
00249
00250 if (!ifmsh->ie || !ifmsh->ie_len)
00251 return NULL;
00252
00253 offset = ieee80211_ie_split_vendor(ifmsh->ie,
00254 ifmsh->ie_len, 0);
00255
00256 if (!offset)
00257 return NULL;
00258
00259 return ifmsh->ie + offset + 2;
00260 }
00261
00262 static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
00263 u16 stype,
00264 struct ieee80211_mgmt *mgmt,
00265 struct ieee802_11_elems *elems,
00266 struct ieee80211_rx_status *rx_status)
00267 {
00268 const u8 *oui;
00269
00270 WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
00271 msync_dbg("called mesh_sync_vendor_rx_bcn_presp");
00272 oui = mesh_get_vendor_oui(sdata);
00273
00274 }
00275
00276 static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
00277 {
00278 const u8 *oui;
00279
00280 WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR);
00281 msync_dbg("called mesh_sync_vendor_adjust_tbtt");
00282 oui = mesh_get_vendor_oui(sdata);
00283
00284 }
00285
00286
00287 static struct sync_method sync_methods[] = {
00288 {
00289 .method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
00290 .ops = {
00291 .rx_bcn_presp = &mesh_sync_offset_rx_bcn_presp,
00292 .adjust_tbtt = &mesh_sync_offset_adjust_tbtt,
00293 }
00294 },
00295 {
00296 .method = IEEE80211_SYNC_METHOD_VENDOR,
00297 .ops = {
00298 .rx_bcn_presp = &mesh_sync_vendor_rx_bcn_presp,
00299 .adjust_tbtt = &mesh_sync_vendor_adjust_tbtt,
00300 }
00301 },
00302 };
00303
00304 struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method)
00305 {
00306 struct ieee80211_mesh_sync_ops *ops = NULL;
00307 u8 i;
00308
00309 for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) {
00310 if (sync_methods[i].method == method) {
00311 ops = &sync_methods[i].ops;
00312 break;
00313 }
00314 }
00315 return ops;
00316 }