summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-06-04 19:14:35 -0700
committerJakub Kicinski <kuba@kernel.org>2026-06-04 19:14:35 -0700
commitbfa3d89cc15c09f7d1581c834a5ed725189ec19f (patch)
treee5f781dd60db6f5442b1599b5fbb3e8a0ab76f3f /net
parent6ce66868d1a62cacecfec7ce628df3227c1808c2 (diff)
parent626fd14371614b7a8177f79b357fd323a7b91032 (diff)
downloadlinux-next-bfa3d89cc15c09f7d1581c834a5ed725189ec19f.tar.gz
linux-next-bfa3d89cc15c09f7d1581c834a5ed725189ec19f.zip
Merge tag 'batadv-next-pullrequest-20260603' of https://git.open-mesh.org/batadv
Simon Wunderlich says: ==================== This cleanup patchset includes the following patches, all by Sven Eckelmann: - tp_meter: fix various minor issues (8 patches) - tp_meter: split generic session type in sender and receiver type - tp_meter: consolidate locking for congestion control (2 patches) - bla: annotate lasttime access with READ/WRITE_ONCE - elp: prevent transmission interval underflow - tt: sync local and global tvlv preparation return values - tt: directly retrieve wifi flags of net_device * tag 'batadv-next-pullrequest-20260603' of https://git.open-mesh.org/batadv: batman-adv: tt: directly retrieve wifi flags of net_device batman-adv: tt: sync local and global tvlv preparation return values batman-adv: prevent ELP transmission interval underflow batman-adv: bla: annotate lasttime access with READ/WRITE_ONCE batman-adv: tp_meter: consolidate congestion control variables batman-adv: tp_meter: use locking for all congestion control variables batman-adv: tp_meter: split vars into sender and receiver types batman-adv: tp_meter: add only finished tp_vars to lists batman-adv: tp_meter: handle seqno wrap-around for fast recovery detection batman-adv: tp_meter: fix fast recovery precondition batman-adv: tp_meter: avoid divide-by-zero for dec_cwnd batman-adv: tp_meter: avoid window underflow batman-adv: tp_meter: initialize dec_cwnd explicitly batman-adv: tp_meter: initialize dup_acks explicitly batman-adv: tp_meter: keep unacked list in ascending ordered ==================== Link: https://patch.msgid.link/20260603072527.174487-1-sw@simonwunderlich.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net')
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c28
-rw-r--r--net/batman-adv/hard-interface.c25
-rw-r--r--net/batman-adv/hard-interface.h1
-rw-r--r--net/batman-adv/main.c3
-rw-r--r--net/batman-adv/netlink.c8
-rw-r--r--net/batman-adv/tp_meter.c739
-rw-r--r--net/batman-adv/translation-table.c32
-rw-r--r--net/batman-adv/types.h141
8 files changed, 572 insertions, 405 deletions
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 87d6b11161e4..0461f11227d0 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -513,7 +513,7 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, const u8 *orig,
return NULL;
entry->vid = vid;
- entry->lasttime = jiffies;
+ WRITE_ONCE(entry->lasttime, jiffies);
entry->crc = BATADV_BLA_CRC_INIT;
entry->bat_priv = bat_priv;
spin_lock_init(&entry->crc_lock);
@@ -581,7 +581,7 @@ batadv_bla_update_own_backbone_gw(struct batadv_priv *bat_priv,
if (unlikely(!backbone_gw))
return;
- backbone_gw->lasttime = jiffies;
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
batadv_backbone_gw_put(backbone_gw);
}
@@ -715,7 +715,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
ether_addr_copy(claim->addr, mac);
spin_lock_init(&claim->backbone_lock);
claim->vid = vid;
- claim->lasttime = jiffies;
+ WRITE_ONCE(claim->lasttime, jiffies);
kref_get(&backbone_gw->refcount);
claim->backbone_gw = backbone_gw;
kref_init(&claim->refcount);
@@ -737,7 +737,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
return;
}
} else {
- claim->lasttime = jiffies;
+ WRITE_ONCE(claim->lasttime, jiffies);
if (claim->backbone_gw == backbone_gw)
/* no need to register a new backbone */
goto claim_free_ref;
@@ -770,7 +770,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
spin_lock_bh(&backbone_gw->crc_lock);
backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
spin_unlock_bh(&backbone_gw->crc_lock);
- backbone_gw->lasttime = jiffies;
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
claim_free_ref:
batadv_claim_put(claim);
@@ -859,7 +859,7 @@ static bool batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr,
return true;
/* handle as ANNOUNCE frame */
- backbone_gw->lasttime = jiffies;
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
crc = ntohs(*((__force __be16 *)(&an_addr[4])));
batadv_dbg(BATADV_DBG_BLA, bat_priv,
@@ -1254,7 +1254,7 @@ static void batadv_bla_purge_backbone_gw(struct batadv_priv *bat_priv, int now)
head, hash_entry) {
if (now)
goto purge_now;
- if (!batadv_has_timed_out(backbone_gw->lasttime,
+ if (!batadv_has_timed_out(READ_ONCE(backbone_gw->lasttime),
BATADV_BLA_BACKBONE_TIMEOUT))
continue;
@@ -1335,7 +1335,7 @@ static void batadv_bla_purge_claims(struct batadv_priv *bat_priv,
primary_if->net_dev->dev_addr))
goto skip;
- if (!batadv_has_timed_out(claim->lasttime,
+ if (!batadv_has_timed_out(READ_ONCE(claim->lasttime),
BATADV_BLA_CLAIM_TIMEOUT))
goto skip;
@@ -1495,7 +1495,7 @@ static void batadv_bla_periodic_work(struct work_struct *work)
eth_random_addr(bat_priv->bla.loopdetect_addr);
bat_priv->bla.loopdetect_addr[0] = 0xba;
bat_priv->bla.loopdetect_addr[1] = 0xbe;
- bat_priv->bla.loopdetect_lasttime = jiffies;
+ WRITE_ONCE(bat_priv->bla.loopdetect_lasttime, jiffies);
atomic_set(&bat_priv->bla.loopdetect_next,
BATADV_BLA_LOOPDETECT_PERIODS);
@@ -1516,7 +1516,7 @@ static void batadv_bla_periodic_work(struct work_struct *work)
primary_if->net_dev->dev_addr))
continue;
- backbone_gw->lasttime = jiffies;
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
batadv_bla_send_announce(bat_priv, backbone_gw);
if (send_loopdetect)
@@ -1900,7 +1900,7 @@ batadv_bla_loopdetect_check(struct batadv_priv *bat_priv, struct sk_buff *skb,
/* If the packet came too late, don't forward it on the mesh
* but don't consider that as loop. It might be a coincidence.
*/
- if (batadv_has_timed_out(bat_priv->bla.loopdetect_lasttime,
+ if (batadv_has_timed_out(READ_ONCE(bat_priv->bla.loopdetect_lasttime),
BATADV_BLA_LOOPDETECT_TIMEOUT))
return true;
@@ -2015,7 +2015,7 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
if (own_claim) {
/* ... allow it in any case */
- claim->lasttime = jiffies;
+ WRITE_ONCE(claim->lasttime, jiffies);
goto allow;
}
@@ -2117,7 +2117,7 @@ bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
/* if yes, the client has roamed and we have
* to unclaim it.
*/
- if (batadv_has_timed_out(claim->lasttime, 100)) {
+ if (batadv_has_timed_out(READ_ONCE(claim->lasttime), 100)) {
/* only unclaim if the last claim entry is
* older than 100 ms to make sure we really
* have a roaming client here.
@@ -2362,7 +2362,7 @@ batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid,
backbone_crc = backbone_gw->crc;
spin_unlock_bh(&backbone_gw->crc_lock);
- msecs = jiffies_to_msecs(jiffies - backbone_gw->lasttime);
+ msecs = jiffies_to_msecs(jiffies - READ_ONCE(backbone_gw->lasttime));
if (is_own)
if (nla_put_flag(msg, BATADV_ATTR_BLA_OWN)) {
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index bb3c31b5f259..43ebf86e7b36 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -366,22 +366,19 @@ out:
}
/**
- * batadv_hardif_get_wifi_flags() - retrieve wifi flags for hard_iface
- * @hard_iface: the device to check
+ * batadv_netdev_get_wifi_flags() - retrieve wifi flags for net_device
+ * @net_dev: the device to check
*
* Return: batadv_hard_iface_wifi_flags flags of the device
*/
-u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface)
+u32 batadv_netdev_get_wifi_flags(struct net_device *net_dev)
{
struct batadv_wifi_net_device_state *device_state;
u32 wifi_flags = 0;
- if (!hard_iface)
- return 0;
-
rcu_read_lock();
device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices,
- &hard_iface->net_dev,
+ &net_dev,
batadv_wifi_net_devices_params);
if (device_state)
wifi_flags = READ_ONCE(device_state->wifi_flags);
@@ -391,6 +388,20 @@ u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface)
}
/**
+ * batadv_hardif_get_wifi_flags() - retrieve wifi flags for hard_iface
+ * @hard_iface: the device to check
+ *
+ * Return: batadv_hard_iface_wifi_flags flags of the device
+ */
+u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface)
+{
+ if (!hard_iface)
+ return 0;
+
+ return batadv_netdev_get_wifi_flags(hard_iface->net_dev);
+}
+
+/**
* batadv_is_wifi_hardif() - check if the given hardif is a wifi interface
* @hard_iface: the device to check
*
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index 089e65c8a481..822e7e378c4d 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -70,6 +70,7 @@ extern struct notifier_block batadv_hard_if_notifier;
struct net_device *__batadv_get_real_netdev(struct net_device *net_device);
struct net_device *batadv_get_real_netdev(struct net_device *net_device);
+u32 batadv_netdev_get_wifi_flags(struct net_device *net_dev);
u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface);
bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface);
struct batadv_hard_iface*
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 60d4f60066c8..3c4572284b53 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -194,7 +194,8 @@ int batadv_mesh_init(struct net_device *mesh_iface)
INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
INIT_HLIST_HEAD(&bat_priv->meshif_vlan_list);
- INIT_HLIST_HEAD(&bat_priv->tp_list);
+ INIT_HLIST_HEAD(&bat_priv->tp_sender_list);
+ INIT_HLIST_HEAD(&bat_priv->tp_receiver_list);
bat_priv->gw.generation = 0;
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index e5463003a3bd..1ba206e40273 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -919,9 +919,15 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb,
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
if (info->attrs[BATADV_ATTR_ELP_INTERVAL]) {
+ u32 elp_interval;
+
attr = info->attrs[BATADV_ATTR_ELP_INTERVAL];
+ elp_interval = nla_get_u32(attr);
+
+ elp_interval = min_t(u32, elp_interval, INT_MAX);
+ elp_interval = max_t(u32, elp_interval, BATADV_JITTER);
- WRITE_ONCE(hard_iface->bat_v.elp_interval, nla_get_u32(attr));
+ WRITE_ONCE(hard_iface->bat_v.elp_interval, elp_interval);
}
if (info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) {
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index aefe757277b2..978e32d94e6c 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -142,30 +142,27 @@ static u32 batadv_tp_cwnd(u32 base, u32 increment, u32 min)
* 2) if the session is in Congestion Avoidance, the CWND has to be
* increased by MSS * MSS / CWND for every unique received ACK
*/
-static void batadv_tp_update_cwnd(struct batadv_tp_vars *tp_vars, u32 mss)
+static void batadv_tp_update_cwnd(struct batadv_tp_sender *tp_vars, u32 mss)
+ __must_hold(&tp_vars->cc_lock)
{
- spin_lock_bh(&tp_vars->cwnd_lock);
-
/* slow start... */
- if (tp_vars->cwnd <= tp_vars->ss_threshold) {
- tp_vars->dec_cwnd = 0;
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd, mss, mss);
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ if (tp_vars->cc.cwnd <= tp_vars->cc.ss_threshold) {
+ tp_vars->cc.dec_cwnd = 0;
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd, mss, mss);
return;
}
+ /* prevent overflow in (mss * mss) << 3 */
+ mss = min_t(u32, mss, (1U << 14) - 1);
+
/* increment CWND at least of 1 (section 3.1 of RFC5681) */
- tp_vars->dec_cwnd += max_t(u32, 1U << 3,
- ((mss * mss) << 6) / (tp_vars->cwnd << 3));
- if (tp_vars->dec_cwnd < (mss << 3)) {
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ tp_vars->cc.dec_cwnd += max_t(u32, 1U << 3,
+ ((mss * mss) << 3) / tp_vars->cc.cwnd);
+ if (tp_vars->cc.dec_cwnd < (mss << 3))
return;
- }
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd, mss, mss);
- tp_vars->dec_cwnd = 0;
-
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd, mss, mss);
+ tp_vars->cc.dec_cwnd = 0;
}
/**
@@ -173,8 +170,9 @@ static void batadv_tp_update_cwnd(struct batadv_tp_vars *tp_vars, u32 mss)
* @tp_vars: the private data of the current TP meter session
* @new_rtt: new roundtrip time in msec
*/
-static void batadv_tp_update_rto(struct batadv_tp_vars *tp_vars,
+static void batadv_tp_update_rto(struct batadv_tp_sender *tp_vars,
u32 new_rtt)
+ __must_hold(&tp_vars->cc_lock)
{
long m = new_rtt;
@@ -184,24 +182,24 @@ static void batadv_tp_update_rto(struct batadv_tp_vars *tp_vars,
* It's tricky to understand. Don't lose hair please.
* Inspired by tcp_rtt_estimator() tcp_input.c
*/
- if (tp_vars->srtt != 0) {
- m -= (tp_vars->srtt >> 3); /* m is now error in rtt est */
- tp_vars->srtt += m; /* rtt = 7/8 srtt + 1/8 new */
+ if (tp_vars->cc.srtt != 0) {
+ m -= (tp_vars->cc.srtt >> 3); /* m is now error in rtt est */
+ tp_vars->cc.srtt += m; /* rtt = 7/8 srtt + 1/8 new */
if (m < 0)
m = -m;
- m -= (tp_vars->rttvar >> 2);
- tp_vars->rttvar += m; /* mdev ~= 3/4 rttvar + 1/4 new */
+ m -= (tp_vars->cc.rttvar >> 2);
+ tp_vars->cc.rttvar += m; /* mdev ~= 3/4 rttvar + 1/4 new */
} else {
/* first measure getting in */
- tp_vars->srtt = m << 3; /* take the measured time to be srtt */
- tp_vars->rttvar = m << 1; /* new_rtt / 2 */
+ tp_vars->cc.srtt = m << 3; /* take the measured time to be srtt */
+ tp_vars->cc.rttvar = m << 1; /* new_rtt / 2 */
}
/* rto = srtt + 4 * rttvar.
* rttvar is scaled by 4, therefore doesn't need to be multiplied
*/
- tp_vars->rto = (tp_vars->srtt >> 3) + tp_vars->rttvar;
+ WRITE_ONCE(tp_vars->cc.rto, (tp_vars->cc.srtt >> 3) + tp_vars->cc.rttvar);
}
/**
@@ -252,35 +250,30 @@ static void batadv_tp_batctl_error_notify(enum batadv_tp_meter_reason reason,
}
/**
- * batadv_tp_list_find() - find a tp_vars object in the global list
+ * batadv_tp_list_find_sender() - find a sender tp_vars object in the global list
* @bat_priv: the bat priv with all the mesh interface information
* @dst: the other endpoint MAC address to look for
- * @role: role of the session
*
* Look for a tp_vars object matching dst as end_point and return it after
* having increment the refcounter. Return NULL is not found
*
* Return: matching tp_vars or NULL when no tp_vars with @dst was found
*/
-static struct batadv_tp_vars *batadv_tp_list_find(struct batadv_priv *bat_priv,
- const u8 *dst,
- enum batadv_tp_meter_role role)
+static struct batadv_tp_sender *
+batadv_tp_list_find_sender(struct batadv_priv *bat_priv, const u8 *dst)
{
- struct batadv_tp_vars *pos, *tp_vars = NULL;
+ struct batadv_tp_sender *pos, *tp_vars = NULL;
rcu_read_lock();
- hlist_for_each_entry_rcu(pos, &bat_priv->tp_list, list) {
- if (!batadv_compare_eth(pos->other_end, dst))
- continue;
-
- if (pos->role != role)
+ hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) {
+ if (!batadv_compare_eth(pos->common.other_end, dst))
continue;
/* most of the time this function is invoked during the normal
* process..it makes sens to pay more when the session is
* finished and to speed the process up during the measurement
*/
- if (unlikely(!kref_get_unless_zero(&pos->refcount)))
+ if (unlikely(!kref_get_unless_zero(&pos->common.refcount)))
continue;
tp_vars = pos;
@@ -301,10 +294,16 @@ static struct batadv_tp_vars *batadv_tp_list_find(struct batadv_priv *bat_priv,
static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst)
__must_hold(&bat_priv->tp_list_lock)
{
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_receiver *tp_receiver;
+ struct batadv_tp_sender *tp_sender;
- hlist_for_each_entry_rcu(tp_vars, &bat_priv->tp_list, list) {
- if (batadv_compare_eth(tp_vars->other_end, dst))
+ hlist_for_each_entry_rcu(tp_sender, &bat_priv->tp_sender_list, common.list) {
+ if (batadv_compare_eth(tp_sender->common.other_end, dst))
+ return true;
+ }
+
+ hlist_for_each_entry_rcu(tp_receiver, &bat_priv->tp_receiver_list, common.list) {
+ if (batadv_compare_eth(tp_receiver->common.other_end, dst))
return true;
}
@@ -312,12 +311,11 @@ static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst)
}
/**
- * batadv_tp_list_find_session() - find tp_vars session object in the global
- * list
+ * batadv_tp_list_find_sender_session() - find tp_vars sender session
+ * object in the global list
* @bat_priv: the bat priv with all the mesh interface information
* @dst: the other endpoint MAC address to look for
* @session: session identifier
- * @role: role of the session
*
* Look for a tp_vars object matching dst as end_point, session as tp meter
* session and return it after having increment the refcounter. Return NULL
@@ -325,28 +323,25 @@ static bool batadv_tp_list_active(struct batadv_priv *bat_priv, const u8 *dst)
*
* Return: matching tp_vars or NULL when no tp_vars was found
*/
-static struct batadv_tp_vars *
-batadv_tp_list_find_session(struct batadv_priv *bat_priv, const u8 *dst,
- const u8 *session, enum batadv_tp_meter_role role)
+static struct batadv_tp_sender *
+batadv_tp_list_find_sender_session(struct batadv_priv *bat_priv, const u8 *dst,
+ const u8 *session)
{
- struct batadv_tp_vars *pos, *tp_vars = NULL;
+ struct batadv_tp_sender *pos, *tp_vars = NULL;
rcu_read_lock();
- hlist_for_each_entry_rcu(pos, &bat_priv->tp_list, list) {
- if (!batadv_compare_eth(pos->other_end, dst))
- continue;
-
- if (memcmp(pos->session, session, sizeof(pos->session)) != 0)
+ hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) {
+ if (!batadv_compare_eth(pos->common.other_end, dst))
continue;
- if (pos->role != role)
+ if (memcmp(pos->common.session, session, sizeof(pos->common.session)) != 0)
continue;
/* most of the time this function is invoked during the normal
* process..it makes sense to pay more when the session is
* finished and to speed the process up during the measurement
*/
- if (unlikely(!kref_get_unless_zero(&pos->refcount)))
+ if (unlikely(!kref_get_unless_zero(&pos->common.refcount)))
continue;
tp_vars = pos;
@@ -358,16 +353,16 @@ batadv_tp_list_find_session(struct batadv_priv *bat_priv, const u8 *dst,
}
/**
- * batadv_tp_vars_release() - release batadv_tp_vars from lists and queue for
- * free after rcu grace period
+ * batadv_tp_vars_common_release() - release batadv_tp_vars_common from lists
+ * and queue for free after rcu grace period
* @ref: kref pointer of the batadv_tp_vars
*/
-static void batadv_tp_vars_release(struct kref *ref)
+static void batadv_tp_vars_common_release(struct kref *ref)
{
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_vars_common *tp_vars;
struct batadv_tp_unacked *un, *safe;
- tp_vars = container_of(ref, struct batadv_tp_vars, refcount);
+ tp_vars = container_of(ref, struct batadv_tp_vars_common, refcount);
/* lock should not be needed because this object is now out of any
* context!
@@ -383,23 +378,25 @@ static void batadv_tp_vars_release(struct kref *ref)
}
/**
- * batadv_tp_vars_put() - decrement the batadv_tp_vars refcounter and possibly
- * release it
+ * batadv_tp_sender_put() - decrement the batadv_tp_sender
+ * refcounter and possibly release it
* @tp_vars: the private data of the current TP meter session to be free'd
*/
-static void batadv_tp_vars_put(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_sender_put(struct batadv_tp_sender *tp_vars)
{
if (!tp_vars)
return;
- kref_put(&tp_vars->refcount, batadv_tp_vars_release);
+ kref_put(&tp_vars->common.refcount, batadv_tp_vars_common_release);
}
/**
- * batadv_tp_list_detach() - remove tp session from mesh session list once
+ * batadv_tp_list_detach() - remove tp receiver session from mesh session list once
* @tp_vars: the private data of the current TP meter session
+ *
+ * Return: whether tp_vars was detached from list and reference must be freed
*/
-static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars)
+static bool batadv_tp_list_detach(struct batadv_tp_vars_common *tp_vars)
{
bool detached = false;
@@ -411,27 +408,27 @@ static void batadv_tp_list_detach(struct batadv_tp_vars *tp_vars)
spin_unlock_bh(&tp_vars->bat_priv->tp_list_lock);
if (!detached)
- return;
+ return false;
atomic_dec(&tp_vars->bat_priv->tp_num);
- /* drop list reference */
- batadv_tp_vars_put(tp_vars);
+ return true;
}
/**
* batadv_tp_sender_cleanup() - cleanup sender data and drop and timer
* @tp_vars: the private data of the current TP meter session to cleanup
*/
-static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_sender_cleanup(struct batadv_tp_sender *tp_vars)
{
cancel_delayed_work_sync(&tp_vars->finish_work);
- batadv_tp_list_detach(tp_vars);
+ if (batadv_tp_list_detach(&tp_vars->common))
+ batadv_tp_sender_put(tp_vars);
/* kill the timer and remove its reference */
- timer_shutdown_sync(&tp_vars->timer);
- batadv_tp_vars_put(tp_vars);
+ timer_shutdown_sync(&tp_vars->common.timer);
+ batadv_tp_sender_put(tp_vars);
}
/**
@@ -440,7 +437,7 @@ static void batadv_tp_sender_cleanup(struct batadv_tp_vars *tp_vars)
* @tp_vars: the private data of the current TP meter session
*/
static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
- struct batadv_tp_vars *tp_vars)
+ struct batadv_tp_sender *tp_vars)
{
enum batadv_tp_meter_reason reason;
u32 session_cookie;
@@ -449,21 +446,21 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Test towards %pM finished..shutting down (reason=%d)\n",
- tp_vars->other_end, reason);
+ tp_vars->common.other_end, reason);
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Last timing stats: SRTT=%ums RTTVAR=%ums RTO=%ums\n",
- tp_vars->srtt >> 3, tp_vars->rttvar >> 2, tp_vars->rto);
+ tp_vars->cc.srtt >> 3, tp_vars->cc.rttvar >> 2, tp_vars->cc.rto);
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Final values: cwnd=%u ss_threshold=%u\n",
- tp_vars->cwnd, tp_vars->ss_threshold);
+ tp_vars->cc.cwnd, tp_vars->cc.ss_threshold);
- session_cookie = batadv_tp_session_cookie(tp_vars->session,
+ session_cookie = batadv_tp_session_cookie(tp_vars->common.session,
tp_vars->icmp_uid);
batadv_tp_batctl_notify(reason,
- tp_vars->other_end,
+ tp_vars->common.other_end,
bat_priv,
tp_vars->start_time,
atomic64_read(&tp_vars->tot_sent),
@@ -475,7 +472,7 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
* @tp_vars: the private data of the current TP meter session
* @reason: reason for tp meter session stop
*/
-static void batadv_tp_sender_shutdown(struct batadv_tp_vars *tp_vars,
+static void batadv_tp_sender_shutdown(struct batadv_tp_sender *tp_vars,
enum batadv_tp_meter_reason reason)
{
atomic_cmpxchg(&tp_vars->send_result, 0, reason);
@@ -487,7 +484,7 @@ static void batadv_tp_sender_shutdown(struct batadv_tp_vars *tp_vars,
*
* Return: whether stop reason was found
*/
-static bool batadv_tp_sender_stopped(struct batadv_tp_vars *tp_vars)
+static bool batadv_tp_sender_stopped(struct batadv_tp_sender *tp_vars)
{
return atomic_read(&tp_vars->send_result) != 0;
}
@@ -499,10 +496,10 @@ static bool batadv_tp_sender_stopped(struct batadv_tp_vars *tp_vars)
static void batadv_tp_sender_finish(struct work_struct *work)
{
struct delayed_work *delayed_work;
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_sender *tp_vars;
delayed_work = to_delayed_work(work);
- tp_vars = container_of(delayed_work, struct batadv_tp_vars,
+ tp_vars = container_of(delayed_work, struct batadv_tp_sender,
finish_work);
batadv_tp_sender_shutdown(tp_vars, BATADV_TP_REASON_COMPLETE);
@@ -514,7 +511,7 @@ static void batadv_tp_sender_finish(struct work_struct *work)
*
* Reschedule the timer using tp_vars->rto as delay
*/
-static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_reset_sender_timer(struct batadv_tp_sender *tp_vars)
{
/* most of the time this function is invoked while normal packet
* reception...
@@ -523,7 +520,8 @@ static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars)
/* timer ref will be dropped in batadv_tp_sender_cleanup */
return;
- mod_timer(&tp_vars->timer, jiffies + msecs_to_jiffies(tp_vars->rto));
+ mod_timer(&tp_vars->common.timer,
+ jiffies + msecs_to_jiffies(READ_ONCE(tp_vars->cc.rto)));
}
/**
@@ -536,14 +534,17 @@ static void batadv_tp_reset_sender_timer(struct batadv_tp_vars *tp_vars)
*/
static void batadv_tp_sender_timeout(struct timer_list *t)
{
- struct batadv_tp_vars *tp_vars = timer_container_of(tp_vars, t, timer);
- struct batadv_priv *bat_priv = tp_vars->bat_priv;
+ struct batadv_tp_sender *tp_vars = timer_container_of(tp_vars, t, common.timer);
+ struct batadv_priv *bat_priv = tp_vars->common.bat_priv;
if (batadv_tp_sender_stopped(tp_vars))
return;
+ spin_lock_bh(&tp_vars->cc_lock);
+
/* if the user waited long enough...shutdown the test */
- if (unlikely(tp_vars->rto >= BATADV_TP_MAX_RTO)) {
+ if (unlikely(tp_vars->cc.rto >= BATADV_TP_MAX_RTO)) {
+ spin_unlock_bh(&tp_vars->cc_lock);
batadv_tp_sender_shutdown(tp_vars,
BATADV_TP_REASON_DST_UNREACHABLE);
return;
@@ -552,25 +553,24 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
/* RTO exponential backoff
* Details in Section 5.5 of RFC6298
*/
- tp_vars->rto <<= 1;
+ WRITE_ONCE(tp_vars->cc.rto, tp_vars->cc.rto * 2);
- spin_lock_bh(&tp_vars->cwnd_lock);
-
- tp_vars->ss_threshold = tp_vars->cwnd >> 1;
- if (tp_vars->ss_threshold < BATADV_TP_PLEN * 2)
- tp_vars->ss_threshold = BATADV_TP_PLEN * 2;
+ tp_vars->cc.ss_threshold = tp_vars->cc.cwnd >> 1;
+ if (tp_vars->cc.ss_threshold < BATADV_TP_PLEN * 2)
+ tp_vars->cc.ss_threshold = BATADV_TP_PLEN * 2;
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: RTO fired during test towards %pM! cwnd=%u new ss_thr=%u, resetting last_sent to %u\n",
- tp_vars->other_end, tp_vars->cwnd, tp_vars->ss_threshold,
- atomic_read(&tp_vars->last_acked));
+ tp_vars->common.other_end, tp_vars->cc.cwnd, tp_vars->cc.ss_threshold,
+ tp_vars->cc.last_acked);
+
+ tp_vars->cc.cwnd = BATADV_TP_PLEN * 3;
- tp_vars->cwnd = BATADV_TP_PLEN * 3;
+ WRITE_ONCE(tp_vars->cc.last_sent, tp_vars->cc.last_acked);
- spin_unlock_bh(&tp_vars->cwnd_lock);
+ spin_unlock_bh(&tp_vars->cc_lock);
/* resend the non-ACKed packets.. */
- tp_vars->last_sent = atomic_read(&tp_vars->last_acked);
wake_up(&tp_vars->more_bytes);
batadv_tp_reset_sender_timer(tp_vars);
@@ -582,7 +582,7 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
* @buf: Buffer to fill with bytes
* @nbytes: amount of pseudorandom bytes
*/
-static void batadv_tp_fill_prerandom(struct batadv_tp_vars *tp_vars,
+static void batadv_tp_fill_prerandom(struct batadv_tp_sender *tp_vars,
u8 *buf, size_t nbytes)
{
u32 local_offset;
@@ -625,7 +625,7 @@ static void batadv_tp_fill_prerandom(struct batadv_tp_vars *tp_vars,
* not reachable, BATADV_TP_REASON_MEMORY_ERROR if the packet couldn't be
* allocated
*/
-static int batadv_tp_send_msg(struct batadv_tp_vars *tp_vars, const u8 *src,
+static int batadv_tp_send_msg(struct batadv_tp_sender *tp_vars, const u8 *src,
struct batadv_orig_node *orig_node,
u32 seqno, size_t len, const u8 *session,
int uid, u32 timestamp)
@@ -669,6 +669,115 @@ static int batadv_tp_send_msg(struct batadv_tp_vars *tp_vars, const u8 *src,
}
/**
+ * enum batadv_tp_ack_reaction - expected reaction to ack packet
+ */
+enum batadv_tp_ack_reaction {
+ /** @BATADV_TP_ACK_REACTION_OLD_ACK: ignore old ack packet */
+ BATADV_TP_ACK_REACTION_OLD_ACK,
+
+ /** @BATADV_TP_ACK_REACTION_IGNORE: ignore duplicated ack but reset timer */
+ BATADV_TP_ACK_REACTION_IGNORE,
+
+ /** @BATADV_TP_ACK_REACTION_RESEND_WAKEUP: resend data and wakeup "more_bytes" */
+ BATADV_TP_ACK_REACTION_RESEND_WAKEUP,
+
+ /** @BATADV_TP_ACK_REACTION_WAKEUP: wakeup "more_bytes" */
+ BATADV_TP_ACK_REACTION_WAKEUP,
+};
+
+/**
+ * batadv_tp_handle_ack() - Calculate reaction to ACK and update congestion control
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @tp_vars: the private data of the current TP meter session
+ * @recv_ack: received ACK seqno
+ * @mss: maximum segment size for transmission
+ *
+ * Return: expected reaction to this ack
+ */
+static enum batadv_tp_ack_reaction
+batadv_tp_handle_ack(struct batadv_priv *bat_priv,
+ struct batadv_tp_sender *tp_vars,
+ u32 recv_ack, size_t mss)
+ __must_hold(&tp_vars->cc_lock)
+{
+ enum batadv_tp_ack_reaction reaction;
+
+ if (batadv_seq_before(recv_ack, tp_vars->cc.last_acked))
+ return BATADV_TP_ACK_REACTION_OLD_ACK;
+
+ /* check if this ACK is a duplicate */
+ if (tp_vars->cc.last_acked == recv_ack) {
+ /* if this is the third duplicate ACK do Fast Retransmit */
+ if (tp_vars->cc.dup_acks > 3)
+ return BATADV_TP_ACK_REACTION_IGNORE;
+
+ tp_vars->cc.dup_acks++;
+ if (tp_vars->cc.dup_acks != 3)
+ return BATADV_TP_ACK_REACTION_IGNORE;
+
+ if (!batadv_seq_before(tp_vars->cc.recover, recv_ack))
+ return BATADV_TP_ACK_REACTION_IGNORE;
+
+ /* Fast Recovery */
+ tp_vars->cc.fast_recovery = true;
+
+ /* Set recover to the last outstanding seqno when Fast Recovery
+ * is entered. RFC6582, Section 3.2, step 1
+ */
+ tp_vars->cc.recover = tp_vars->cc.last_sent;
+ tp_vars->cc.ss_threshold = tp_vars->cc.cwnd >> 1;
+ batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
+ "Meter: Fast Recovery, (cur cwnd=%u) ss_thr=%u last_sent=%u recv_ack=%u\n",
+ tp_vars->cc.cwnd, tp_vars->cc.ss_threshold,
+ tp_vars->cc.last_sent, recv_ack);
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.ss_threshold, 3 * mss,
+ mss);
+ tp_vars->cc.dec_cwnd = 0;
+ WRITE_ONCE(tp_vars->cc.last_sent, recv_ack);
+
+ return BATADV_TP_ACK_REACTION_RESEND_WAKEUP;
+ }
+
+ /* count the acked data */
+ atomic64_add(recv_ack - tp_vars->cc.last_acked, &tp_vars->tot_sent);
+
+ /* reset the duplicate ACKs counter */
+ tp_vars->cc.dup_acks = 0;
+
+ if (tp_vars->cc.fast_recovery) {
+ /* partial ACK */
+ if (batadv_seq_before(recv_ack, tp_vars->cc.recover)) {
+ /* this is another hole in the window. React
+ * immediately as specified by NewReno (see
+ * Section 3.2 of RFC6582 for details)
+ */
+ reaction = BATADV_TP_ACK_REACTION_RESEND_WAKEUP;
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.cwnd,
+ mss, mss);
+ } else {
+ tp_vars->cc.fast_recovery = false;
+ /* set cwnd to the value of ss_threshold at the
+ * moment that Fast Recovery was entered.
+ * RFC6582, Section 3.2, step 3
+ */
+ tp_vars->cc.cwnd = batadv_tp_cwnd(tp_vars->cc.ss_threshold,
+ 0, mss);
+ reaction = BATADV_TP_ACK_REACTION_WAKEUP;
+ }
+ } else {
+ if (recv_ack - tp_vars->cc.last_acked >= mss)
+ batadv_tp_update_cwnd(tp_vars, mss);
+
+ reaction = BATADV_TP_ACK_REACTION_WAKEUP;
+ }
+
+ /* move the Transmit Window */
+ WRITE_ONCE(tp_vars->cc.last_acked, recv_ack);
+
+ return reaction;
+}
+
+/**
* batadv_tp_recv_ack() - ACK receiving function
* @bat_priv: the bat priv with all the mesh interface information
* @skb: the buffer containing the received packet
@@ -681,20 +790,23 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
struct batadv_hard_iface *primary_if = NULL;
struct batadv_orig_node *orig_node = NULL;
const struct batadv_icmp_tp_packet *icmp;
- struct batadv_tp_vars *tp_vars;
- const unsigned char *dev_addr;
- size_t packet_len, mss;
- u32 rtt, recv_ack, cwnd;
+ enum batadv_tp_ack_reaction reaction;
+ struct batadv_tp_sender *tp_vars;
+ size_t packet_len;
+ u32 recv_ack;
+ size_t mss;
+ u32 rtt;
packet_len = BATADV_TP_PLEN;
mss = BATADV_TP_PLEN;
packet_len += sizeof(struct batadv_unicast_packet);
icmp = (struct batadv_icmp_tp_packet *)skb->data;
+ recv_ack = ntohl(icmp->seqno);
/* find the tp_vars */
- tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig,
- icmp->session, BATADV_TP_SENDER);
+ tp_vars = batadv_tp_list_find_sender_session(bat_priv, icmp->orig,
+ icmp->session);
if (unlikely(!tp_vars))
return;
@@ -702,8 +814,7 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
goto out;
/* old ACK? silently drop it.. */
- if (batadv_seq_before(ntohl(icmp->seqno),
- (u32)atomic_read(&tp_vars->last_acked)))
+ if (batadv_seq_before(recv_ack, READ_ONCE(tp_vars->cc.last_acked)))
goto out;
primary_if = batadv_primary_if_get_selected(bat_priv);
@@ -714,97 +825,40 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
if (unlikely(!orig_node))
goto out;
+ spin_lock_bh(&tp_vars->cc_lock);
/* update RTO with the new sampled RTT, if any */
rtt = jiffies_to_msecs(jiffies) - ntohl(icmp->timestamp);
if (icmp->timestamp && rtt)
batadv_tp_update_rto(tp_vars, rtt);
- /* ACK for new data... reset the timer */
- batadv_tp_reset_sender_timer(tp_vars);
-
- recv_ack = ntohl(icmp->seqno);
+ reaction = batadv_tp_handle_ack(bat_priv, tp_vars, recv_ack, mss);
+ spin_unlock_bh(&tp_vars->cc_lock);
- /* check if this ACK is a duplicate */
- if (atomic_read(&tp_vars->last_acked) == recv_ack) {
- atomic_inc(&tp_vars->dup_acks);
- if (atomic_read(&tp_vars->dup_acks) != 3)
- goto out;
+ if (reaction == BATADV_TP_ACK_REACTION_OLD_ACK)
+ goto out;
- if (recv_ack >= tp_vars->recover)
- goto out;
+ /* ACK for new data... reset the timer */
+ batadv_tp_reset_sender_timer(tp_vars);
- /* if this is the third duplicate ACK do Fast Retransmit */
+ switch (reaction) {
+ default:
+ case BATADV_TP_ACK_REACTION_IGNORE:
+ goto out;
+ case BATADV_TP_ACK_REACTION_RESEND_WAKEUP:
batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr,
orig_node, recv_ack, packet_len,
icmp->session, icmp->uid,
jiffies_to_msecs(jiffies));
-
- spin_lock_bh(&tp_vars->cwnd_lock);
-
- /* Fast Recovery */
- tp_vars->fast_recovery = true;
- /* Set recover to the last outstanding seqno when Fast Recovery
- * is entered. RFC6582, Section 3.2, step 1
- */
- tp_vars->recover = tp_vars->last_sent;
- tp_vars->ss_threshold = tp_vars->cwnd >> 1;
- batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
- "Meter: Fast Recovery, (cur cwnd=%u) ss_thr=%u last_sent=%u recv_ack=%u\n",
- tp_vars->cwnd, tp_vars->ss_threshold,
- tp_vars->last_sent, recv_ack);
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->ss_threshold, 3 * mss,
- mss);
- tp_vars->dec_cwnd = 0;
- tp_vars->last_sent = recv_ack;
-
- spin_unlock_bh(&tp_vars->cwnd_lock);
- } else {
- /* count the acked data */
- atomic64_add(recv_ack - atomic_read(&tp_vars->last_acked),
- &tp_vars->tot_sent);
- /* reset the duplicate ACKs counter */
- atomic_set(&tp_vars->dup_acks, 0);
-
- if (tp_vars->fast_recovery) {
- /* partial ACK */
- if (batadv_seq_before(recv_ack, tp_vars->recover)) {
- /* this is another hole in the window. React
- * immediately as specified by NewReno (see
- * Section 3.2 of RFC6582 for details)
- */
- dev_addr = primary_if->net_dev->dev_addr;
- batadv_tp_send_msg(tp_vars, dev_addr,
- orig_node, recv_ack,
- packet_len, icmp->session,
- icmp->uid,
- jiffies_to_msecs(jiffies));
- tp_vars->cwnd = batadv_tp_cwnd(tp_vars->cwnd,
- mss, mss);
- } else {
- tp_vars->fast_recovery = false;
- /* set cwnd to the value of ss_threshold at the
- * moment that Fast Recovery was entered.
- * RFC6582, Section 3.2, step 3
- */
- cwnd = batadv_tp_cwnd(tp_vars->ss_threshold, 0,
- mss);
- tp_vars->cwnd = cwnd;
- }
- goto move_twnd;
- }
-
- if (recv_ack - atomic_read(&tp_vars->last_acked) >= mss)
- batadv_tp_update_cwnd(tp_vars, mss);
-move_twnd:
- /* move the Transmit Window */
- atomic_set(&tp_vars->last_acked, recv_ack);
+ fallthrough;
+ case BATADV_TP_ACK_REACTION_WAKEUP:
+ wake_up(&tp_vars->more_bytes);
+ break;
}
- wake_up(&tp_vars->more_bytes);
out:
batadv_hardif_put(primary_if);
batadv_orig_node_put(orig_node);
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
}
/**
@@ -814,13 +868,21 @@ out:
*
* Return: true when congestion window is not full, false otherwise
*/
-static bool batadv_tp_avail(struct batadv_tp_vars *tp_vars,
+static bool batadv_tp_avail(struct batadv_tp_sender *tp_vars,
size_t payload_len)
{
u32 win_left, win_limit;
- win_limit = atomic_read(&tp_vars->last_acked) + tp_vars->cwnd;
- win_left = win_limit - tp_vars->last_sent;
+ spin_lock_bh(&tp_vars->cc_lock);
+
+ win_limit = tp_vars->cc.last_acked + tp_vars->cc.cwnd;
+
+ if (batadv_seq_before(tp_vars->cc.last_sent, win_limit))
+ win_left = win_limit - tp_vars->cc.last_sent;
+ else
+ win_left = 0;
+
+ spin_unlock_bh(&tp_vars->cc_lock);
return win_left >= payload_len;
}
@@ -836,7 +898,7 @@ static bool batadv_tp_avail(struct batadv_tp_vars *tp_vars,
* remaining jiffies (at least 1) if the condition evaluated to true before
* the timeout elapsed, or -ERESTARTSYS if it was interrupted by a signal.
*/
-static int batadv_tp_wait_available(struct batadv_tp_vars *tp_vars, size_t plen)
+static int batadv_tp_wait_available(struct batadv_tp_sender *tp_vars, size_t plen)
{
int ret;
@@ -855,20 +917,15 @@ static int batadv_tp_wait_available(struct batadv_tp_vars *tp_vars, size_t plen)
*/
static int batadv_tp_send(void *arg)
{
- struct batadv_tp_vars *tp_vars = arg;
- struct batadv_priv *bat_priv = tp_vars->bat_priv;
+ struct batadv_tp_sender *tp_vars = arg;
+ struct batadv_priv *bat_priv = tp_vars->common.bat_priv;
struct batadv_hard_iface *primary_if = NULL;
struct batadv_orig_node *orig_node = NULL;
size_t payload_len, packet_len;
+ u32 last_sent;
int err = 0;
- if (unlikely(tp_vars->role != BATADV_TP_SENDER)) {
- err = BATADV_TP_REASON_DST_UNREACHABLE;
- batadv_tp_sender_shutdown(tp_vars, err);
- goto out;
- }
-
- orig_node = batadv_orig_hash_find(bat_priv, tp_vars->other_end);
+ orig_node = batadv_orig_hash_find(bat_priv, tp_vars->common.other_end);
if (unlikely(!orig_node)) {
err = BATADV_TP_REASON_DST_UNREACHABLE;
batadv_tp_sender_shutdown(tp_vars, err);
@@ -907,11 +964,11 @@ static int batadv_tp_send(void *arg)
* the size of the unicast header
*/
packet_len = payload_len + sizeof(struct batadv_unicast_packet);
+ last_sent = READ_ONCE(tp_vars->cc.last_sent);
err = batadv_tp_send_msg(tp_vars, primary_if->net_dev->dev_addr,
- orig_node, tp_vars->last_sent,
- packet_len,
- tp_vars->session, tp_vars->icmp_uid,
+ orig_node, last_sent, packet_len,
+ tp_vars->common.session, tp_vars->icmp_uid,
jiffies_to_msecs(jiffies));
/* something went wrong during the preparation/transmission */
@@ -925,8 +982,12 @@ static int batadv_tp_send(void *arg)
}
/* right-shift the TWND */
- if (!err)
- tp_vars->last_sent += payload_len;
+ if (!err) {
+ spin_lock_bh(&tp_vars->cc_lock);
+ if (tp_vars->cc.last_sent == last_sent)
+ WRITE_ONCE(tp_vars->cc.last_sent, last_sent + payload_len);
+ spin_unlock_bh(&tp_vars->cc_lock);
+ }
cond_resched();
}
@@ -939,7 +1000,7 @@ out:
batadv_tp_sender_cleanup(tp_vars);
complete(&tp_vars->finished);
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
return 0;
}
@@ -949,24 +1010,24 @@ out:
* sender
* @tp_vars: the private data of the current TP meter session
*/
-static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_start_kthread(struct batadv_tp_sender *tp_vars)
{
struct task_struct *kthread;
- struct batadv_priv *bat_priv = tp_vars->bat_priv;
+ struct batadv_priv *bat_priv = tp_vars->common.bat_priv;
u32 session_cookie;
- kref_get(&tp_vars->refcount);
+ kref_get(&tp_vars->common.refcount);
kthread = kthread_create(batadv_tp_send, tp_vars, "kbatadv_tp_meter");
if (IS_ERR(kthread)) {
- session_cookie = batadv_tp_session_cookie(tp_vars->session,
+ session_cookie = batadv_tp_session_cookie(tp_vars->common.session,
tp_vars->icmp_uid);
pr_err("batadv: cannot create tp meter kthread\n");
batadv_tp_batctl_error_notify(BATADV_TP_REASON_MEMORY_ERROR,
- tp_vars->other_end,
+ tp_vars->common.other_end,
bat_priv, session_cookie);
/* drop reserved reference for kthread */
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
/* cleanup of failed tp meter variables */
batadv_tp_sender_cleanup(tp_vars);
@@ -987,7 +1048,7 @@ static void batadv_tp_start_kthread(struct batadv_tp_vars *tp_vars)
void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
u32 test_length, u32 *cookie)
{
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_sender *tp_vars;
u8 session_id[2];
u8 icmp_uid;
u32 session_cookie;
@@ -1037,76 +1098,78 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
}
/* initialize tp_vars */
- ether_addr_copy(tp_vars->other_end, dst);
- kref_init(&tp_vars->refcount);
- tp_vars->role = BATADV_TP_SENDER;
+ ether_addr_copy(tp_vars->common.other_end, dst);
+ kref_init(&tp_vars->common.refcount);
atomic_set(&tp_vars->send_result, 0);
- memcpy(tp_vars->session, session_id, sizeof(session_id));
+ memcpy(tp_vars->common.session, session_id, sizeof(session_id));
tp_vars->icmp_uid = icmp_uid;
- tp_vars->last_sent = BATADV_TP_FIRST_SEQ;
- atomic_set(&tp_vars->last_acked, BATADV_TP_FIRST_SEQ);
- tp_vars->fast_recovery = false;
- tp_vars->recover = BATADV_TP_FIRST_SEQ;
+ WRITE_ONCE(tp_vars->cc.last_sent, BATADV_TP_FIRST_SEQ);
+ WRITE_ONCE(tp_vars->cc.dup_acks, 0);
+ WRITE_ONCE(tp_vars->cc.last_acked, BATADV_TP_FIRST_SEQ);
+ tp_vars->cc.fast_recovery = false;
+ tp_vars->cc.recover = BATADV_TP_FIRST_SEQ;
/* initialise the CWND to 3*MSS (Section 3.1 in RFC5681).
* For batman-adv the MSS is the size of the payload received by the
* mesh_interface, hence its MTU
*/
- tp_vars->cwnd = BATADV_TP_PLEN * 3;
+ tp_vars->cc.cwnd = BATADV_TP_PLEN * 3;
+ tp_vars->cc.dec_cwnd = 0;
+
/* at the beginning initialise the SS threshold to the biggest possible
* window size, hence the AWND size
*/
- tp_vars->ss_threshold = BATADV_TP_AWND;
+ tp_vars->cc.ss_threshold = BATADV_TP_AWND;
/* RTO initial value is 3 seconds.
* Details in Section 2.1 of RFC6298
*/
- tp_vars->rto = 1000;
- tp_vars->srtt = 0;
- tp_vars->rttvar = 0;
+ WRITE_ONCE(tp_vars->cc.rto, 1000);
+ tp_vars->cc.srtt = 0;
+ tp_vars->cc.rttvar = 0;
atomic64_set(&tp_vars->tot_sent, 0);
- kref_get(&tp_vars->refcount);
- timer_setup(&tp_vars->timer, batadv_tp_sender_timeout, 0);
+ kref_get(&tp_vars->common.refcount);
+ timer_setup(&tp_vars->common.timer, batadv_tp_sender_timeout, 0);
- tp_vars->bat_priv = bat_priv;
+ tp_vars->common.bat_priv = bat_priv;
tp_vars->start_time = jiffies;
init_waitqueue_head(&tp_vars->more_bytes);
init_completion(&tp_vars->finished);
- spin_lock_init(&tp_vars->unacked_lock);
- INIT_LIST_HEAD(&tp_vars->unacked_list);
+ spin_lock_init(&tp_vars->common.unacked_lock);
+ INIT_LIST_HEAD(&tp_vars->common.unacked_list);
- spin_lock_init(&tp_vars->cwnd_lock);
+ spin_lock_init(&tp_vars->cc_lock);
tp_vars->prerandom_offset = 0;
spin_lock_init(&tp_vars->prerandom_lock);
- kref_get(&tp_vars->refcount);
- hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
- spin_unlock_bh(&bat_priv->tp_list_lock);
-
tp_vars->test_length = test_length;
if (!tp_vars->test_length)
tp_vars->test_length = BATADV_TP_DEF_TEST_LENGTH;
+ /* init work item for finished tp tests */
+ INIT_DELAYED_WORK(&tp_vars->finish_work, batadv_tp_sender_finish);
+
+ kref_get(&tp_vars->common.refcount);
+ hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_sender_list);
+ spin_unlock_bh(&bat_priv->tp_list_lock);
+
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: starting throughput meter towards %pM (length=%ums)\n",
dst, test_length);
- /* init work item for finished tp tests */
- INIT_DELAYED_WORK(&tp_vars->finish_work, batadv_tp_sender_finish);
-
/* start tp kthread. This way the write() call issued from userspace can
* happily return and avoid to block
*/
batadv_tp_start_kthread(tp_vars);
/* don't return reference to new tp_vars */
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
}
/**
@@ -1119,7 +1182,7 @@ void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
u8 return_value)
{
struct batadv_orig_node *orig_node;
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_sender *tp_vars;
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: stopping test towards %pM\n", dst);
@@ -1128,7 +1191,7 @@ void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
if (!orig_node)
return;
- tp_vars = batadv_tp_list_find(bat_priv, orig_node->orig, BATADV_TP_SENDER);
+ tp_vars = batadv_tp_list_find_sender(bat_priv, orig_node->orig);
if (!tp_vars) {
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Meter: trying to interrupt an already over connection\n");
@@ -1136,20 +1199,75 @@ void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
}
batadv_tp_sender_shutdown(tp_vars, return_value);
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
out_put_orig_node:
batadv_orig_node_put(orig_node);
}
/**
+ * batadv_tp_list_find_receiver_session() - find tp_vars receiver session
+ * object in the global list
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @dst: the other endpoint MAC address to look for
+ * @session: session identifier
+ *
+ * Look for a tp_vars object matching dst as end_point, session as tp meter
+ * session and return it after having increment the refcounter. Return NULL
+ * is not found
+ *
+ * Return: matching tp_vars or NULL when no tp_vars was found
+ */
+static struct batadv_tp_receiver *
+batadv_tp_list_find_receiver_session(struct batadv_priv *bat_priv, const u8 *dst,
+ const u8 *session)
+{
+ struct batadv_tp_receiver *pos, *tp_vars = NULL;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(pos, &bat_priv->tp_receiver_list, common.list) {
+ if (!batadv_compare_eth(pos->common.other_end, dst))
+ continue;
+
+ if (memcmp(pos->common.session, session, sizeof(pos->common.session)) != 0)
+ continue;
+
+ /* most of the time this function is invoked during the normal
+ * process..it makes sense to pay more when the session is
+ * finished and to speed the process up during the measurement
+ */
+ if (unlikely(!kref_get_unless_zero(&pos->common.refcount)))
+ continue;
+
+ tp_vars = pos;
+ break;
+ }
+ rcu_read_unlock();
+
+ return tp_vars;
+}
+
+/**
+ * batadv_tp_receiver_put() - decrement the batadv_tp_receiver
+ * refcounter and possibly release it
+ * @tp_vars: the private data of the current TP meter session to be free'd
+ */
+static void batadv_tp_receiver_put(struct batadv_tp_receiver *tp_vars)
+{
+ if (!tp_vars)
+ return;
+
+ kref_put(&tp_vars->common.refcount, batadv_tp_vars_common_release);
+}
+
+/**
* batadv_tp_reset_receiver_timer() - reset the receiver shutdown timer
* @tp_vars: the private data of the current TP meter session
*
* start the receiver shutdown timer or reset it if already started
*/
-static void batadv_tp_reset_receiver_timer(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_reset_receiver_timer(struct batadv_tp_receiver *tp_vars)
{
- mod_timer(&tp_vars->timer,
+ mod_timer(&tp_vars->common.timer,
jiffies + msecs_to_jiffies(BATADV_TP_RECV_TIMEOUT));
}
@@ -1160,11 +1278,11 @@ static void batadv_tp_reset_receiver_timer(struct batadv_tp_vars *tp_vars)
*/
static void batadv_tp_receiver_shutdown(struct timer_list *t)
{
- struct batadv_tp_vars *tp_vars = timer_container_of(tp_vars, t, timer);
+ struct batadv_tp_receiver *tp_vars = timer_container_of(tp_vars, t, common.timer);
struct batadv_tp_unacked *un, *safe;
struct batadv_priv *bat_priv;
- bat_priv = tp_vars->bat_priv;
+ bat_priv = tp_vars->common.bat_priv;
/* if there is recent activity rearm the timer */
if (!batadv_has_timed_out(tp_vars->last_recv_time,
@@ -1176,22 +1294,23 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t)
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Shutting down for inactivity (more than %dms) from %pM\n",
- BATADV_TP_RECV_TIMEOUT, tp_vars->other_end);
+ BATADV_TP_RECV_TIMEOUT, tp_vars->common.other_end);
- batadv_tp_list_detach(tp_vars);
+ if (batadv_tp_list_detach(&tp_vars->common))
+ batadv_tp_receiver_put(tp_vars);
- spin_lock_bh(&tp_vars->unacked_lock);
- list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
+ spin_lock_bh(&tp_vars->common.unacked_lock);
+ list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) {
list_del(&un->list);
kfree(un);
}
- spin_unlock_bh(&tp_vars->unacked_lock);
+ spin_unlock_bh(&tp_vars->common.unacked_lock);
/* drop reference of timer */
if (WARN_ON(atomic_xchg(&tp_vars->receiving, 0) != 1))
return;
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_receiver_put(tp_vars);
}
/**
@@ -1275,7 +1394,7 @@ out:
*
* Return: true if the packed has been successfully processed, false otherwise
*/
-static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
+static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars,
const struct sk_buff *skb)
{
const struct batadv_icmp_tp_packet *icmp;
@@ -1293,10 +1412,10 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
payload_len = skb->len - sizeof(struct batadv_unicast_packet);
new->len = payload_len;
- spin_lock_bh(&tp_vars->unacked_lock);
+ spin_lock_bh(&tp_vars->common.unacked_lock);
/* if the list is empty immediately attach this new object */
- if (list_empty(&tp_vars->unacked_list)) {
- list_add(&new->list, &tp_vars->unacked_list);
+ if (list_empty(&tp_vars->common.unacked_list)) {
+ list_add(&new->list, &tp_vars->common.unacked_list);
goto out;
}
@@ -1307,7 +1426,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
* the last received packet (the one being processed now) has a bigger
* seqno than all the others already stored.
*/
- list_for_each_entry_reverse(un, &tp_vars->unacked_list, list) {
+ list_for_each_entry_reverse(un, &tp_vars->common.unacked_list, list) {
/* check for duplicates */
if (new->seqno == un->seqno) {
if (new->len > un->len)
@@ -1325,17 +1444,17 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
* one is attached _after_ it. In this way the list is kept in
* ascending order
*/
- list_add_tail(&new->list, &un->list);
+ list_add(&new->list, &un->list);
added = true;
break;
}
/* received packet with smallest seqno out of order; add it to front */
if (!added)
- list_add(&new->list, &tp_vars->unacked_list);
+ list_add(&new->list, &tp_vars->common.unacked_list);
out:
- spin_unlock_bh(&tp_vars->unacked_lock);
+ spin_unlock_bh(&tp_vars->common.unacked_lock);
return true;
}
@@ -1345,7 +1464,7 @@ out:
* without gaps
* @tp_vars: the private data of the current TP meter session
*/
-static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)
+static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars)
{
struct batadv_tp_unacked *un, *safe;
u32 to_ack;
@@ -1353,8 +1472,8 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)
/* go through the unacked packet list and possibly ACK them as
* well
*/
- spin_lock_bh(&tp_vars->unacked_lock);
- list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
+ spin_lock_bh(&tp_vars->common.unacked_lock);
+ list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) {
/* the list is ordered, therefore it is possible to stop as soon
* there is a gap between the last acked seqno and the seqno of
* the packet under inspection
@@ -1370,7 +1489,7 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)
list_del(&un->list);
kfree(un);
}
- spin_unlock_bh(&tp_vars->unacked_lock);
+ spin_unlock_bh(&tp_vars->common.unacked_lock);
}
/**
@@ -1380,18 +1499,18 @@ static void batadv_tp_ack_unordered(struct batadv_tp_vars *tp_vars)
*
* Return: corresponding tp_vars or NULL on errors
*/
-static struct batadv_tp_vars *
+static struct batadv_tp_receiver *
batadv_tp_init_recv(struct batadv_priv *bat_priv,
const struct batadv_icmp_tp_packet *icmp)
{
- struct batadv_tp_vars *tp_vars = NULL;
+ struct batadv_tp_receiver *tp_vars = NULL;
spin_lock_bh(&bat_priv->tp_list_lock);
if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
goto out_unlock;
- tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig,
- icmp->session, BATADV_TP_RECEIVER);
+ tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig,
+ icmp->session);
if (tp_vars)
goto out_unlock;
@@ -1407,22 +1526,21 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv,
goto out_unlock;
}
- ether_addr_copy(tp_vars->other_end, icmp->orig);
- tp_vars->role = BATADV_TP_RECEIVER;
+ ether_addr_copy(tp_vars->common.other_end, icmp->orig);
atomic_set(&tp_vars->receiving, 1);
- memcpy(tp_vars->session, icmp->session, sizeof(tp_vars->session));
+ memcpy(tp_vars->common.session, icmp->session, sizeof(tp_vars->common.session));
tp_vars->last_recv = BATADV_TP_FIRST_SEQ;
- tp_vars->bat_priv = bat_priv;
- kref_init(&tp_vars->refcount);
+ tp_vars->common.bat_priv = bat_priv;
+ kref_init(&tp_vars->common.refcount);
- spin_lock_init(&tp_vars->unacked_lock);
- INIT_LIST_HEAD(&tp_vars->unacked_list);
+ spin_lock_init(&tp_vars->common.unacked_lock);
+ INIT_LIST_HEAD(&tp_vars->common.unacked_list);
- kref_get(&tp_vars->refcount);
- hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
+ kref_get(&tp_vars->common.refcount);
+ timer_setup(&tp_vars->common.timer, batadv_tp_receiver_shutdown, 0);
- kref_get(&tp_vars->refcount);
- timer_setup(&tp_vars->timer, batadv_tp_receiver_shutdown, 0);
+ kref_get(&tp_vars->common.refcount);
+ hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_receiver_list);
batadv_tp_reset_receiver_timer(tp_vars);
@@ -1443,7 +1561,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
const struct sk_buff *skb)
{
const struct batadv_icmp_tp_packet *icmp;
- struct batadv_tp_vars *tp_vars;
+ struct batadv_tp_receiver *tp_vars;
size_t packet_size;
u32 seqno;
@@ -1461,8 +1579,8 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
goto out;
}
} else {
- tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig,
- icmp->session, BATADV_TP_RECEIVER);
+ tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig,
+ icmp->session);
if (!tp_vars) {
batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
"Unexpected packet from %pM!\n",
@@ -1506,7 +1624,7 @@ send_ack:
batadv_tp_send_ack(bat_priv, icmp->orig, tp_vars->last_recv,
icmp->timestamp, icmp->session, icmp->uid);
out:
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_receiver_put(tp_vars);
}
/**
@@ -1546,45 +1664,58 @@ out:
*/
void batadv_tp_stop_all(struct batadv_priv *bat_priv)
{
- struct batadv_tp_vars *tp_vars[BATADV_TP_MAX_NUM];
- struct batadv_tp_vars *tp_var;
- size_t count = 0;
+ struct batadv_tp_receiver *tp_receivers[BATADV_TP_MAX_NUM];
+ struct batadv_tp_sender *tp_senders[BATADV_TP_MAX_NUM];
+ struct batadv_tp_receiver *tp_receiver;
+ struct batadv_tp_sender *tp_sender;
+ size_t receiver_count = 0;
+ size_t sender_count = 0;
size_t i;
spin_lock_bh(&bat_priv->tp_list_lock);
- hlist_for_each_entry(tp_var, &bat_priv->tp_list, list) {
- if (WARN_ON_ONCE(count >= BATADV_TP_MAX_NUM))
+ hlist_for_each_entry(tp_receiver, &bat_priv->tp_receiver_list, common.list) {
+ if (WARN_ON_ONCE(receiver_count >= BATADV_TP_MAX_NUM))
+ break;
+
+ if (!kref_get_unless_zero(&tp_receiver->common.refcount))
+ continue;
+
+ tp_receivers[receiver_count++] = tp_receiver;
+ }
+
+ hlist_for_each_entry(tp_sender, &bat_priv->tp_sender_list, common.list) {
+ if (WARN_ON_ONCE(sender_count >= BATADV_TP_MAX_NUM))
break;
- if (!kref_get_unless_zero(&tp_var->refcount))
+ if (!kref_get_unless_zero(&tp_sender->common.refcount))
continue;
- tp_vars[count++] = tp_var;
+ tp_senders[sender_count++] = tp_sender;
}
spin_unlock_bh(&bat_priv->tp_list_lock);
- for (i = 0; i < count; i++) {
- tp_var = tp_vars[i];
+ for (i = 0; i < receiver_count; i++) {
+ tp_receiver = tp_receivers[i];
- switch (tp_var->role) {
- case BATADV_TP_SENDER:
- batadv_tp_sender_shutdown(tp_var,
- BATADV_TP_REASON_CANCEL);
- wake_up(&tp_var->more_bytes);
- wait_for_completion(&tp_var->finished);
- break;
- case BATADV_TP_RECEIVER:
- batadv_tp_list_detach(tp_var);
- timer_shutdown_sync(&tp_var->timer);
+ if (batadv_tp_list_detach(&tp_receiver->common))
+ batadv_tp_receiver_put(tp_receiver);
- if (atomic_xchg(&tp_var->receiving, 0) != 1)
- break;
+ timer_shutdown_sync(&tp_receiver->common.timer);
- batadv_tp_vars_put(tp_var);
- break;
- }
+ if (atomic_xchg(&tp_receiver->receiving, 0) != 0)
+ batadv_tp_receiver_put(tp_receiver);
+
+ batadv_tp_receiver_put(tp_receiver);
+ }
+
+ for (i = 0; i < sender_count; i++) {
+ tp_sender = tp_senders[i];
+
+ batadv_tp_sender_shutdown(tp_sender, BATADV_TP_REASON_CANCEL);
+ wake_up(&tp_sender->more_bytes);
+ wait_for_completion(&tp_sender->finished);
- batadv_tp_vars_put(tp_var);
+ batadv_tp_sender_put(tp_sender);
}
synchronize_net();
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 5e134d08a80f..c346e43d47b9 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -596,20 +596,23 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
struct net *net = dev_net(mesh_iface);
struct batadv_meshif_vlan *vlan;
struct net_device *in_dev = NULL;
- struct batadv_hard_iface *in_hardif = NULL;
struct hlist_head *head;
struct batadv_tt_orig_list_entry *orig_entry;
int hash_added, table_size, packet_size_max;
bool ret = false;
bool roamed_back = false;
+ bool iif_is_wifi = false;
u8 remote_flags;
u32 match_mark;
if (ifindex != BATADV_NULL_IFINDEX)
in_dev = dev_get_by_index(net, ifindex);
- if (in_dev)
- in_hardif = batadv_hardif_get_by_netdev(in_dev);
+ if (in_dev) {
+ u32 wifi_flags = batadv_netdev_get_wifi_flags(in_dev);
+
+ iif_is_wifi = batadv_is_wifi(wifi_flags);
+ }
tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
@@ -684,7 +687,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
*/
tt_local->common.flags = BATADV_TT_CLIENT_NEW;
tt_local->common.vid = vid;
- if (batadv_is_wifi_hardif(in_hardif))
+ if (iif_is_wifi)
tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
kref_init(&tt_local->common.refcount);
tt_local->last_seen = jiffies;
@@ -743,7 +746,7 @@ check_roaming:
*/
remote_flags = tt_local->common.flags & BATADV_TT_REMOTE_MASK;
- if (batadv_is_wifi_hardif(in_hardif))
+ if (iif_is_wifi)
tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
else
tt_local->common.flags &= ~BATADV_TT_CLIENT_WIFI;
@@ -767,7 +770,6 @@ check_roaming:
ret = true;
out:
- batadv_hardif_put(in_hardif);
dev_put(in_dev);
batadv_tt_local_entry_put(tt_local);
batadv_tt_global_entry_put(tt_global);
@@ -797,21 +799,22 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
struct batadv_tvlv_tt_change **tt_change,
s32 *tt_len)
{
- u16 num_vlan = 0;
- u16 tvlv_len = 0;
struct batadv_tvlv_tt_vlan_data *tt_vlan;
struct batadv_orig_node_vlan *vlan;
u16 total_entries = 0;
size_t change_offset;
u8 *tt_change_ptr;
+ u16 num_vlan = 0;
int vlan_entries;
u16 sum_entries;
+ u16 tvlv_len;
spin_lock_bh(&orig_node->vlan_list_lock);
hlist_for_each_entry(vlan, &orig_node->vlan_list, list) {
vlan_entries = atomic_read(&vlan->tt.num_entries);
if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
+ tvlv_len = 0;
*tt_len = 0;
goto out;
}
@@ -827,12 +830,14 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
*tt_len = batadv_tt_len(total_entries);
if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) {
+ tvlv_len = 0;
*tt_len = 0;
goto out;
}
*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
if (!*tt_data) {
+ tvlv_len = 0;
*tt_len = 0;
goto out;
}
@@ -867,6 +872,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
out:
spin_unlock_bh(&orig_node->vlan_list_lock);
+
return tvlv_len;
}
@@ -896,13 +902,13 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
{
struct batadv_tvlv_tt_vlan_data *tt_vlan;
struct batadv_meshif_vlan *vlan;
- size_t change_offset;
- u16 num_vlan = 0;
u16 total_entries = 0;
- u16 tvlv_len;
+ size_t change_offset;
u8 *tt_change_ptr;
+ u16 num_vlan = 0;
int vlan_entries;
u16 sum_entries;
+ u16 tvlv_len;
spin_lock_bh(&bat_priv->meshif_vlan_list_lock);
hlist_for_each_entry(vlan, &bat_priv->meshif_vlan_list, list) {
@@ -910,6 +916,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
if (check_add_overflow(vlan_entries, total_entries, &sum_entries)) {
tvlv_len = 0;
+ *tt_len = 0;
goto out;
}
@@ -925,12 +932,14 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) {
tvlv_len = 0;
+ *tt_len = 0;
goto out;
}
*tt_data = kmalloc(tvlv_len, GFP_ATOMIC);
if (!*tt_data) {
tvlv_len = 0;
+ *tt_len = 0;
goto out;
}
@@ -964,6 +973,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
out:
spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
+
return tvlv_len;
}
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 19c7316889b6..5eb0371def83 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1336,21 +1336,10 @@ struct batadv_tp_unacked {
};
/**
- * enum batadv_tp_meter_role - Modus in tp meter session
+ * struct batadv_tp_vars_common - common tp meter private variables per session
*/
-enum batadv_tp_meter_role {
- /** @BATADV_TP_RECEIVER: Initialized as receiver */
- BATADV_TP_RECEIVER,
-
- /** @BATADV_TP_SENDER: Initialized as sender */
- BATADV_TP_SENDER
-};
-
-/**
- * struct batadv_tp_vars - tp meter private variables per session
- */
-struct batadv_tp_vars {
- /** @list: list node for &bat_priv.tp_list */
+struct batadv_tp_vars_common {
+ /** @list: list node for &bat_priv.tp_sender_list/&bat_priv.tp_receiver_list */
struct hlist_node list;
/** @timer: timer for ack (receiver) and retry (sender) */
@@ -1359,40 +1348,32 @@ struct batadv_tp_vars {
/** @bat_priv: pointer to the mesh object */
struct batadv_priv *bat_priv;
- /** @start_time: start time in jiffies */
- unsigned long start_time;
-
/** @other_end: mac address of remote */
u8 other_end[ETH_ALEN];
- /** @role: receiver/sender modi */
- enum batadv_tp_meter_role role;
-
- /**
- * @send_result: 0 when sending is ongoing and otherwise
- * enum batadv_tp_meter_reason
- */
- atomic_t send_result;
-
- /** @receiving: receiving binary semaphore: 1 if receiving, 0 is not */
- atomic_t receiving;
+ /** @session: TP session identifier */
+ u8 session[2];
- /** @finish_work: work item for the finishing procedure */
- struct delayed_work finish_work;
+ /** @unacked_list: list of unacked packets (meta-info only) */
+ struct list_head unacked_list;
- /** @finished: completion signaled when a sender thread exits */
- struct completion finished;
+ /** @unacked_lock: protect unacked_list */
+ spinlock_t unacked_lock;
- /** @test_length: test length in milliseconds */
- u32 test_length;
+ /** @refcount: number of context where the object is used */
+ struct kref refcount;
- /** @session: TP session identifier */
- u8 session[2];
+ /** @rcu: struct used for freeing in an RCU-safe manner */
+ struct rcu_head rcu;
+};
- /** @icmp_uid: local ICMP "socket" index */
- u8 icmp_uid;
+/** struct batadv_tp_sender_cc - congestion control variables */
+struct batadv_tp_sender_cc {
+ /** @fast_recovery: true if in Fast Recovery mode */
+ bool fast_recovery:1;
- /* sender variables */
+ /** @dup_acks: duplicate ACKs counter */
+ u8 dup_acks;
/** @dec_cwnd: decimal part of the cwnd used during linear growth */
u16 dec_cwnd;
@@ -1400,9 +1381,6 @@ struct batadv_tp_vars {
/** @cwnd: current size of the congestion window */
u32 cwnd;
- /** @cwnd_lock: lock do protect @cwnd & @dec_cwnd */
- spinlock_t cwnd_lock;
-
/**
* @ss_threshold: Slow Start threshold. Once cwnd exceeds this value the
* connection switches to the Congestion Avoidance state
@@ -1410,20 +1388,11 @@ struct batadv_tp_vars {
u32 ss_threshold;
/** @last_acked: last acked byte */
- atomic_t last_acked;
+ u32 last_acked;
/** @last_sent: last sent byte, not yet acked */
u32 last_sent;
- /** @tot_sent: amount of data sent/ACKed so far */
- atomic64_t tot_sent;
-
- /** @dup_acks: duplicate ACKs counter */
- atomic_t dup_acks;
-
- /** @fast_recovery: true if in Fast Recovery mode */
- unsigned char fast_recovery:1;
-
/** @recover: last sent seqno when entering Fast Recovery */
u32 recover;
@@ -1435,6 +1404,44 @@ struct batadv_tp_vars {
/** @rttvar: RTT variation scaled by 2^2 */
u32 rttvar;
+};
+
+/**
+ * struct batadv_tp_sender - sender tp meter private variables per session
+ */
+struct batadv_tp_sender {
+ /** @common: common batadv_tp_vars (best be first member) */
+ struct batadv_tp_vars_common common;
+
+ /** @start_time: start time in jiffies */
+ unsigned long start_time;
+
+ /**
+ * @send_result: 0 when sending is ongoing and otherwise
+ * enum batadv_tp_meter_reason
+ */
+ atomic_t send_result;
+
+ /** @finish_work: work item for the finishing procedure */
+ struct delayed_work finish_work;
+
+ /** @finished: completion signaled when a sender thread exits */
+ struct completion finished;
+
+ /** @test_length: test length in milliseconds */
+ u32 test_length;
+
+ /** @icmp_uid: local ICMP "socket" index */
+ u8 icmp_uid;
+
+ /** @cc: congestion control variables */
+ struct batadv_tp_sender_cc cc;
+
+ /** @cc_lock: lock do protect @cc */
+ spinlock_t cc_lock;
+
+ /** @tot_sent: amount of data sent/ACKed so far */
+ atomic64_t tot_sent;
/**
* @more_bytes: waiting queue anchor when waiting for more ack/retry
@@ -1447,26 +1454,23 @@ struct batadv_tp_vars {
/** @prerandom_lock: spinlock protecting access to prerandom_offset */
spinlock_t prerandom_lock;
+};
- /* receiver variables */
+/**
+ * struct batadv_tp_receiver - receiver tp meter private variables per session
+ */
+struct batadv_tp_receiver {
+ /** @common: common batadv_tp_vars (best be first member) */
+ struct batadv_tp_vars_common common;
+
+ /** @receiving: receiving binary semaphore: 1 if receiving, 0 is not */
+ atomic_t receiving;
/** @last_recv: last in-order received packet */
u32 last_recv;
- /** @unacked_list: list of unacked packets (meta-info only) */
- struct list_head unacked_list;
-
- /** @unacked_lock: protect unacked_list */
- spinlock_t unacked_lock;
-
/** @last_recv_time: time (jiffies) a msg was received */
unsigned long last_recv_time;
-
- /** @refcount: number of context where the object is used */
- struct kref refcount;
-
- /** @rcu: struct used for freeing in an RCU-safe manner */
- struct rcu_head rcu;
};
/**
@@ -1643,8 +1647,11 @@ struct batadv_priv {
*/
struct hlist_head forw_bcast_list;
- /** @tp_list: list of tp sessions */
- struct hlist_head tp_list;
+ /** @tp_sender_list: list of tp sender sessions */
+ struct hlist_head tp_sender_list;
+
+ /** @tp_receiver_list: list of tp receiver sessions */
+ struct hlist_head tp_receiver_list;
/** @orig_hash: hash table containing mesh participants (orig nodes) */
struct batadv_hashtable *orig_hash;