Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: Implement mesh synchronization framework

This patch adds MBSS extensible synchronization framework (Sec.
13.13.2 of IEEE Std. 802.11-2012).

The framework is implemented via an ops table which defines the
following functions:

rx_bcn_presp() - this is called every time a mesh beacon is
received.
adjust_tbtt() - this is called immediately before a beacon is about
to be transmitted.

The default neighbor offset synchronization defined in the standard is
implemented. We also provide template functions for vendor specific
methods.

When neighbor offset synchronization is active (which is the default)
mesh neighbors in the same MBSS will track timing offsets to each other
and compensate clock drift.

In our tests we observed that this mesh synchronization implementation
successfully corrected drifts between stations of ~2PPM while
introducing a jitter of ~20us.

It is also possible to test this framework on mac80211_hwsim simulated
phys to see how it behaves under different topologies, over poor links,
etc.

Signed-off-by: Marco Porsch <marco.porsch@s2005.tu-chemnitz.de>
Signed-off-by: Pavel Zubarev <pavel.zubarev@gmail.com>
Signed-off-by: Javier Cardona <javier@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Javier Cardona and committed by
John W. Linville
dbf498fb 9bdd3a6b

+392 -8
+12
include/linux/ieee80211.h
··· 1439 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 1454 * enum - mesh path selection protocol identifier 1443 1455 * 1444 1456 * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol
+11
net/mac80211/Kconfig
··· 225 225 226 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 239 config MAC80211_VERBOSE_TDLS_DEBUG 229 240 bool "Verbose TDLS debugging" 230 241 depends on MAC80211_DEBUG_MENU
+2 -1
net/mac80211/Makefile
··· 38 38 mesh.o \ 39 39 mesh_pathtbl.o \ 40 40 mesh_plink.o \ 41 - mesh_hwmp.o 41 + mesh_hwmp.o \ 42 + mesh_sync.o 42 43 43 44 mac80211-$(CONFIG_PM) += pm.o 44 45
+3 -2
net/mac80211/debugfs_sta.c
··· 63 63 test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : "" 64 64 65 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 67 TEST(AUTH), TEST(ASSOC), TEST(PS_STA), 68 68 TEST(PS_DRIVER), TEST(AUTHORIZED), 69 69 TEST(SHORT_PREAMBLE), ··· 71 71 TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL), 72 72 TEST(UAPSD), TEST(SP), TEST(TDLS_PEER), 73 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 76 #undef TEST 76 77 return simple_read_from_buffer(userbuf, count, ppos, buf, res); 77 78 }
+23
net/mac80211/ieee80211_i.h
··· 554 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 575 struct ieee80211_if_mesh { 558 576 struct timer_list housekeeping_timer; 559 577 struct timer_list mesh_path_timer; ··· 620 602 IEEE80211_MESH_SEC_AUTHED = 0x1, 621 603 IEEE80211_MESH_SEC_SECURED = 0x2, 622 604 } security; 605 + /* Extensible Synchronization Framework */ 606 + struct ieee80211_mesh_sync_ops *sync_ops; 607 + s64 sync_offset_clockdrift_max; 608 + spinlock_t sync_offset_lock; 609 + bool adjusting_tbtt; 623 610 }; 624 611 625 612 #ifdef CONFIG_MAC80211_MESH
+16 -5
net/mac80211/mesh.c
··· 13 13 #include "ieee80211_i.h" 14 14 #include "mesh.h" 15 15 16 - #define MESHCONF_CAPAB_ACCEPT_PLINKS 0x01 17 - #define MESHCONF_CAPAB_FORWARDING 0x08 18 - 19 16 #define TMR_RUNNING_HK 0 20 17 #define TMR_RUNNING_MP 1 21 18 #define TMR_RUNNING_MPR 2 ··· 248 251 /* Mesh capability */ 249 252 ifmsh->accepting_plinks = mesh_plink_availables(sdata); 250 253 *pos = MESHCONF_CAPAB_FORWARDING; 251 - *pos++ |= ifmsh->accepting_plinks ? 254 + *pos |= ifmsh->accepting_plinks ? 252 255 MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; 256 + *pos++ |= ifmsh->adjusting_tbtt ? 257 + MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; 253 258 *pos++ = 0x00; 254 259 255 260 return 0; ··· 572 573 ieee80211_configure_filter(local); 573 574 574 575 ifmsh->mesh_cc_id = 0; /* Disabled */ 575 - ifmsh->mesh_sp_id = 0; /* Neighbor Offset */ 576 576 ifmsh->mesh_auth_id = 0; /* Disabled */ 577 + /* register sync ops from extensible synchronization framework */ 578 + ifmsh->sync_ops = ieee80211_mesh_sync_ops_get(ifmsh->mesh_sp_id); 579 + ifmsh->adjusting_tbtt = false; 580 + ifmsh->sync_offset_clockdrift_max = 0; 577 581 set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags); 578 582 ieee80211_mesh_root_setup(ifmsh); 579 583 ieee80211_queue_work(&local->hw, &sdata->work); ··· 618 616 struct ieee80211_rx_status *rx_status) 619 617 { 620 618 struct ieee80211_local *local = sdata->local; 619 + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 621 620 struct ieee802_11_elems elems; 622 621 struct ieee80211_channel *channel; 623 622 u32 supp_rates = 0; ··· 657 654 supp_rates = ieee80211_sta_get_rates(local, &elems, band); 658 655 mesh_neighbour_update(mgmt->sa, supp_rates, sdata, &elems); 659 656 } 657 + 658 + if (ifmsh->sync_ops) 659 + ifmsh->sync_ops->rx_bcn_presp(sdata, 660 + stype, mgmt, &elems, rx_status); 660 661 } 661 662 662 663 static void ieee80211_mesh_rx_mgmt_action(struct ieee80211_sub_if_data *sdata, ··· 728 721 729 722 if (test_and_clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags)) 730 723 ieee80211_mesh_rootpath(sdata); 724 + 725 + if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) 726 + mesh_sync_adjust_tbtt(sdata); 731 727 } 732 728 733 729 void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) ··· 771 761 (unsigned long) sdata); 772 762 INIT_LIST_HEAD(&ifmsh->preq_queue.list); 773 763 spin_lock_init(&ifmsh->mesh_preq_queue_lock); 764 + spin_lock_init(&ifmsh->sync_offset_lock); 774 765 }
+19
net/mac80211/mesh.h
··· 19 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 36 * enum mesh_path_flags - mac80211 mesh path flags 23 37 * 24 38 * ··· 70 56 * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to 71 57 * grow 72 58 * @MESH_WORK_ROOT: the mesh root station needs to send a frame 59 + * @MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other 60 + * mesh nodes 73 61 */ 74 62 enum mesh_deferred_task_flags { 75 63 MESH_WORK_HOUSEKEEPING, 76 64 MESH_WORK_GROW_MPATH_TABLE, 77 65 MESH_WORK_GROW_MPP_TABLE, 78 66 MESH_WORK_ROOT, 67 + MESH_WORK_DRIFT_ADJUST, 79 68 }; 80 69 81 70 /** ··· 251 234 void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); 252 235 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata); 253 236 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh); 237 + struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method); 254 238 255 239 /* Mesh paths */ 256 240 int mesh_nexthop_lookup(struct sk_buff *skb, ··· 345 327 void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata); 346 328 void mesh_plink_quiesce(struct sta_info *sta); 347 329 void mesh_plink_restart(struct sta_info *sta); 330 + void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); 348 331 #else 349 332 #define mesh_allocated 0 350 333 static inline void
+296
net/mac80211/mesh_sync.c
··· 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 + }
+5
net/mac80211/sta_info.h
··· 55 55 * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame. 56 56 * @WLAN_STA_INSERTED: This station is inserted into the hash table. 57 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 60 enum ieee80211_sta_info_flags { 60 61 WLAN_STA_AUTH, ··· 77 76 WLAN_STA_4ADDR_EVENT, 78 77 WLAN_STA_INSERTED, 79 78 WLAN_STA_RATE_CONTROL, 79 + WLAN_STA_TOFFSET_KNOWN, 80 80 }; 81 81 82 82 #define STA_TID_NUM 16 ··· 270 268 * @plink_timeout: timeout of peer link 271 269 * @plink_timer: peer link watch timer 272 270 * @plink_timer_was_running: used by suspend/resume to restore timers 271 + * @t_offset: timing offset relative to this host 273 272 * @debugfs: debug filesystem info 274 273 * @dead: set to true when sta is unlinked 275 274 * @uploaded: set to true when sta is uploaded to the driver ··· 360 357 enum nl80211_plink_state plink_state; 361 358 u32 plink_timeout; 362 359 struct timer_list plink_timer; 360 + s64 t_offset; 361 + s64 t_offset_setpoint; 363 362 #endif 364 363 365 364 #ifdef CONFIG_MAC80211_DEBUGFS
+5
net/mac80211/tx.c
··· 2373 2373 IEEE80211_STYPE_BEACON); 2374 2374 } else if (ieee80211_vif_is_mesh(&sdata->vif)) { 2375 2375 struct ieee80211_mgmt *mgmt; 2376 + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 2376 2377 u8 *pos; 2377 2378 int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) + 2378 2379 sizeof(mgmt->u.beacon); ··· 2382 2381 if (!sdata->u.mesh.mesh_id_len) 2383 2382 goto out; 2384 2383 #endif 2384 + 2385 + if (ifmsh->sync_ops) 2386 + ifmsh->sync_ops->adjust_tbtt( 2387 + sdata); 2385 2388 2386 2389 skb = dev_alloc_skb(local->tx_headroom + 2387 2390 hdr_len +