summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--net/batman-adv/main.c3
-rw-r--r--net/batman-adv/tp_meter.c396
-rw-r--r--net/batman-adv/types.h101
3 files changed, 281 insertions, 219 deletions
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/tp_meter.c b/net/batman-adv/tp_meter.c
index 5498cdc972e9..c088d8880453 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -142,7 +142,7 @@ 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)
{
spin_lock_bh(&tp_vars->cwnd_lock);
@@ -176,7 +176,7 @@ 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)
{
long m = new_rtt;
@@ -255,35 +255,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;
@@ -304,10 +299,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_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_vars, &bat_priv->tp_list, list) {
- if (batadv_compare_eth(tp_vars->other_end, dst))
+ 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;
}
@@ -315,12 +316,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
@@ -328,28 +328,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))
+ hlist_for_each_entry_rcu(pos, &bat_priv->tp_sender_list, common.list) {
+ if (!batadv_compare_eth(pos->common.other_end, dst))
continue;
- if (memcmp(pos->session, session, sizeof(pos->session)) != 0)
- 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;
@@ -361,16 +358,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!
@@ -386,23 +383,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;
@@ -414,27 +413,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);
}
/**
@@ -443,7 +442,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;
@@ -452,7 +451,7 @@ 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",
@@ -462,11 +461,11 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
"Final values: cwnd=%u ss_threshold=%u\n",
tp_vars->cwnd, tp_vars->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),
@@ -478,7 +477,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);
@@ -490,7 +489,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;
}
@@ -502,10 +501,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);
@@ -517,7 +516,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...
@@ -526,7 +525,7 @@ 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(tp_vars->rto));
}
/**
@@ -539,8 +538,8 @@ 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;
@@ -565,7 +564,7 @@ static void batadv_tp_sender_timeout(struct timer_list *t)
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,
+ tp_vars->common.other_end, tp_vars->cwnd, tp_vars->ss_threshold,
atomic_read(&tp_vars->last_acked));
tp_vars->cwnd = BATADV_TP_PLEN * 3;
@@ -585,7 +584,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;
@@ -628,7 +627,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)
@@ -684,7 +683,7 @@ 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;
+ struct batadv_tp_sender *tp_vars;
const unsigned char *dev_addr;
size_t packet_len, mss;
u32 rtt, recv_ack, cwnd;
@@ -696,8 +695,8 @@ static void batadv_tp_recv_ack(struct batadv_priv *bat_priv,
icmp = (struct batadv_icmp_tp_packet *)skb->data;
/* 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;
@@ -807,7 +806,7 @@ move_twnd:
out:
batadv_hardif_put(primary_if);
batadv_orig_node_put(orig_node);
- batadv_tp_vars_put(tp_vars);
+ batadv_tp_sender_put(tp_vars);
}
/**
@@ -817,7 +816,7 @@ 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 last_sent = READ_ONCE(tp_vars->last_sent);
@@ -844,7 +843,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;
@@ -863,20 +862,14 @@ 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;
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);
@@ -919,7 +912,7 @@ static int batadv_tp_send(void *arg)
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,
+ tp_vars->common.session, tp_vars->icmp_uid,
jiffies_to_msecs(jiffies));
/* something went wrong during the preparation/transmission */
@@ -947,7 +940,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;
}
@@ -957,24 +950,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);
@@ -995,7 +988,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;
@@ -1045,11 +1038,10 @@ 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;
@@ -1079,17 +1071,17 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
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);
@@ -1103,8 +1095,8 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
/* init work item for finished tp tests */
INIT_DELAYED_WORK(&tp_vars->finish_work, batadv_tp_sender_finish);
- kref_get(&tp_vars->refcount);
- hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
+ 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,
@@ -1117,7 +1109,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
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);
}
/**
@@ -1130,7 +1122,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);
@@ -1139,7 +1131,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");
@@ -1147,20 +1139,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));
}
@@ -1171,11 +1218,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,
@@ -1187,22 +1234,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);
}
/**
@@ -1286,7 +1334,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;
@@ -1304,10 +1352,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;
}
@@ -1318,7 +1366,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)
@@ -1343,10 +1391,10 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_vars *tp_vars,
/* 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;
}
@@ -1356,7 +1404,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;
@@ -1364,8 +1412,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
@@ -1381,7 +1429,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);
}
/**
@@ -1391,18 +1439,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;
@@ -1418,22 +1466,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);
- timer_setup(&tp_vars->timer, batadv_tp_receiver_shutdown, 0);
+ kref_get(&tp_vars->common.refcount);
+ timer_setup(&tp_vars->common.timer, batadv_tp_receiver_shutdown, 0);
- kref_get(&tp_vars->refcount);
- hlist_add_head_rcu(&tp_vars->list, &bat_priv->tp_list);
+ 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);
@@ -1454,7 +1501,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;
@@ -1472,8 +1519,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",
@@ -1517,7 +1564,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);
}
/**
@@ -1557,45 +1604,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_var->refcount))
+ if (!kref_get_unless_zero(&tp_receiver->common.refcount))
continue;
- tp_vars[count++] = tp_var;
+ 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_sender->common.refcount))
+ continue;
+
+ 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/types.h b/net/batman-adv/types.h
index 19c7316889b6..f7817a68a29c 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,14 +1348,34 @@ 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;
+ /** @session: TP session identifier */
+ u8 session[2];
+
+ /** @unacked_list: list of unacked packets (meta-info only) */
+ struct list_head unacked_list;
+
+ /** @unacked_lock: protect unacked_list */
+ spinlock_t unacked_lock;
+
+ /** @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;
+};
+
+/**
+ * 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
@@ -1374,8 +1383,14 @@ struct batadv_tp_vars {
*/
atomic_t send_result;
- /** @receiving: receiving binary semaphore: 1 if receiving, 0 is not */
- atomic_t receiving;
+ /** @last_sent: last sent byte, not yet acked */
+ u32 last_sent;
+
+ /** @fast_recovery: true if in Fast Recovery mode */
+ unsigned char fast_recovery:1;
+
+ /** @recover: last sent seqno when entering Fast Recovery */
+ u32 recover;
/** @finish_work: work item for the finishing procedure */
struct delayed_work finish_work;
@@ -1386,14 +1401,9 @@ struct batadv_tp_vars {
/** @test_length: test length in milliseconds */
u32 test_length;
- /** @session: TP session identifier */
- u8 session[2];
-
/** @icmp_uid: local ICMP "socket" index */
u8 icmp_uid;
- /* sender variables */
-
/** @dec_cwnd: decimal part of the cwnd used during linear growth */
u16 dec_cwnd;
@@ -1412,21 +1422,12 @@ struct batadv_tp_vars {
/** @last_acked: last acked byte */
atomic_t 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;
-
/** @rto: sender timeout */
u32 rto;
@@ -1447,26 +1448,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 +1641,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;