cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mesh_sync.c (6510B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright 2011-2012, Pavel Zubarev <pavel.zubarev@gmail.com>
      4 * Copyright 2011-2012, Marco Porsch <marco.porsch@s2005.tu-chemnitz.de>
      5 * Copyright 2011-2012, cozybit Inc.
      6 * Copyright (C) 2021 Intel Corporation
      7 */
      8
      9#include "ieee80211_i.h"
     10#include "mesh.h"
     11#include "driver-ops.h"
     12
     13/* This is not in the standard.  It represents a tolerable tsf drift below
     14 * which we do no TSF adjustment.
     15 */
     16#define TOFFSET_MINIMUM_ADJUSTMENT 10
     17
     18/* This is not in the standard. It is a margin added to the
     19 * Toffset setpoint to mitigate TSF overcorrection
     20 * introduced by TSF adjustment latency.
     21 */
     22#define TOFFSET_SET_MARGIN 20
     23
     24/* This is not in the standard.  It represents the maximum Toffset jump above
     25 * which we'll invalidate the Toffset setpoint and choose a new setpoint.  This
     26 * could be, for instance, in case a neighbor is restarted and its TSF counter
     27 * reset.
     28 */
     29#define TOFFSET_MAXIMUM_ADJUSTMENT 800		/* 0.8 ms */
     30
     31struct sync_method {
     32	u8 method;
     33	struct ieee80211_mesh_sync_ops ops;
     34};
     35
     36/**
     37 * mesh_peer_tbtt_adjusting - check if an mp is currently adjusting its TBTT
     38 *
     39 * @cfg: mesh config element from the mesh peer (or %NULL)
     40 */
     41static bool mesh_peer_tbtt_adjusting(const struct ieee80211_meshconf_ie *cfg)
     42{
     43	return cfg &&
     44	       (cfg->meshconf_cap & IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING);
     45}
     46
     47void mesh_sync_adjust_tsf(struct ieee80211_sub_if_data *sdata)
     48{
     49	struct ieee80211_local *local = sdata->local;
     50	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
     51	/* sdata->vif.bss_conf.beacon_int in 1024us units, 0.04% */
     52	u64 beacon_int_fraction = sdata->vif.bss_conf.beacon_int * 1024 / 2500;
     53	u64 tsf;
     54	u64 tsfdelta;
     55
     56	spin_lock_bh(&ifmsh->sync_offset_lock);
     57	if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) {
     58		msync_dbg(sdata, "TSF : max clockdrift=%lld; adjusting\n",
     59			  (long long) ifmsh->sync_offset_clockdrift_max);
     60		tsfdelta = -ifmsh->sync_offset_clockdrift_max;
     61		ifmsh->sync_offset_clockdrift_max = 0;
     62	} else {
     63		msync_dbg(sdata, "TSF : max clockdrift=%lld; adjusting by %llu\n",
     64			  (long long) ifmsh->sync_offset_clockdrift_max,
     65			  (unsigned long long) beacon_int_fraction);
     66		tsfdelta = -beacon_int_fraction;
     67		ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction;
     68	}
     69	spin_unlock_bh(&ifmsh->sync_offset_lock);
     70
     71	if (local->ops->offset_tsf) {
     72		drv_offset_tsf(local, sdata, tsfdelta);
     73	} else {
     74		tsf = drv_get_tsf(local, sdata);
     75		if (tsf != -1ULL)
     76			drv_set_tsf(local, sdata, tsf + tsfdelta);
     77	}
     78}
     79
     80static void
     81mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, u16 stype,
     82			      struct ieee80211_mgmt *mgmt, unsigned int len,
     83			      const struct ieee80211_meshconf_ie *mesh_cfg,
     84			      struct ieee80211_rx_status *rx_status)
     85{
     86	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
     87	struct ieee80211_local *local = sdata->local;
     88	struct sta_info *sta;
     89	u64 t_t, t_r;
     90
     91	WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
     92
     93	/* standard mentions only beacons */
     94	if (stype != IEEE80211_STYPE_BEACON)
     95		return;
     96
     97	/*
     98	 * Get time when timestamp field was received.  If we don't
     99	 * have rx timestamps, then use current tsf as an approximation.
    100	 * drv_get_tsf() must be called before entering the rcu-read
    101	 * section.
    102	 */
    103	if (ieee80211_have_rx_timestamp(rx_status))
    104		t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
    105						       len + FCS_LEN, 24);
    106	else
    107		t_r = drv_get_tsf(local, sdata);
    108
    109	rcu_read_lock();
    110	sta = sta_info_get(sdata, mgmt->sa);
    111	if (!sta)
    112		goto no_sync;
    113
    114	/* check offset sync conditions (13.13.2.2.1)
    115	 *
    116	 * TODO also sync to
    117	 * dot11MeshNbrOffsetMaxNeighbor non-peer non-MBSS neighbors
    118	 */
    119
    120	if (mesh_peer_tbtt_adjusting(mesh_cfg)) {
    121		msync_dbg(sdata, "STA %pM : is adjusting TBTT\n",
    122			  sta->sta.addr);
    123		goto no_sync;
    124	}
    125
    126	/* Timing offset calculation (see 13.13.2.2.2) */
    127	t_t = le64_to_cpu(mgmt->u.beacon.timestamp);
    128	sta->mesh->t_offset = t_t - t_r;
    129
    130	if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
    131		s64 t_clockdrift = sta->mesh->t_offset_setpoint - sta->mesh->t_offset;
    132		msync_dbg(sdata,
    133			  "STA %pM : t_offset=%lld, t_offset_setpoint=%lld, t_clockdrift=%lld\n",
    134			  sta->sta.addr, (long long) sta->mesh->t_offset,
    135			  (long long) sta->mesh->t_offset_setpoint,
    136			  (long long) t_clockdrift);
    137
    138		if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT ||
    139		    t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) {
    140			msync_dbg(sdata,
    141				  "STA %pM : t_clockdrift=%lld too large, setpoint reset\n",
    142				  sta->sta.addr,
    143				  (long long) t_clockdrift);
    144			clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
    145			goto no_sync;
    146		}
    147
    148		spin_lock_bh(&ifmsh->sync_offset_lock);
    149		if (t_clockdrift > ifmsh->sync_offset_clockdrift_max)
    150			ifmsh->sync_offset_clockdrift_max = t_clockdrift;
    151		spin_unlock_bh(&ifmsh->sync_offset_lock);
    152	} else {
    153		sta->mesh->t_offset_setpoint = sta->mesh->t_offset - TOFFSET_SET_MARGIN;
    154		set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN);
    155		msync_dbg(sdata,
    156			  "STA %pM : offset was invalid, t_offset=%lld\n",
    157			  sta->sta.addr,
    158			  (long long) sta->mesh->t_offset);
    159	}
    160
    161no_sync:
    162	rcu_read_unlock();
    163}
    164
    165static void mesh_sync_offset_adjust_tsf(struct ieee80211_sub_if_data *sdata,
    166					 struct beacon_data *beacon)
    167{
    168	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
    169
    170	WARN_ON(ifmsh->mesh_sp_id != IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET);
    171	WARN_ON(!rcu_read_lock_held());
    172
    173	spin_lock_bh(&ifmsh->sync_offset_lock);
    174
    175	if (ifmsh->sync_offset_clockdrift_max > TOFFSET_MINIMUM_ADJUSTMENT) {
    176		/* Since ajusting the tsf here would
    177		 * require a possibly blocking call
    178		 * to the driver tsf setter, we punt
    179		 * the tsf adjustment to the mesh tasklet
    180		 */
    181		msync_dbg(sdata,
    182			  "TSF : kicking off TSF adjustment with clockdrift_max=%lld\n",
    183			  ifmsh->sync_offset_clockdrift_max);
    184		set_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags);
    185	} else {
    186		msync_dbg(sdata,
    187			  "TSF : max clockdrift=%lld; too small to adjust\n",
    188			  (long long)ifmsh->sync_offset_clockdrift_max);
    189		ifmsh->sync_offset_clockdrift_max = 0;
    190	}
    191	spin_unlock_bh(&ifmsh->sync_offset_lock);
    192}
    193
    194static const struct sync_method sync_methods[] = {
    195	{
    196		.method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
    197		.ops = {
    198			.rx_bcn_presp = &mesh_sync_offset_rx_bcn_presp,
    199			.adjust_tsf = &mesh_sync_offset_adjust_tsf,
    200		}
    201	},
    202};
    203
    204const struct ieee80211_mesh_sync_ops *ieee80211_mesh_sync_ops_get(u8 method)
    205{
    206	int i;
    207
    208	for (i = 0 ; i < ARRAY_SIZE(sync_methods); ++i) {
    209		if (sync_methods[i].method == method)
    210			return &sync_methods[i].ops;
    211	}
    212	return NULL;
    213}