]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
batman-adv: tp_meter: handle overlapping packets
authorSven Eckelmann <sven@narfation.org>
Wed, 10 Jun 2026 22:21:37 +0000 (00:21 +0200)
committerSven Eckelmann <sven@narfation.org>
Sat, 13 Jun 2026 05:57:52 +0000 (07:57 +0200)
If the size of the packets would change during the transmission, it could
happen that some retries of packets are overlapping. In this case, precise
comparisons of sequence numbers by the receiver would be wrong. It is then
necessary to check if the start sequence number to the end sequence number
("seqno + length") would contain a new range.

If this is the case then this is enough to accept this packet. In all other
cases, the packet still has to be dropped (and not acked).

Cc: stable@kernel.org
Fixes: 33a3bb4a3345 ("batman-adv: throughput meter implementation")
Signed-off-by: Sven Eckelmann <sven@narfation.org>
net/batman-adv/tp_meter.c

index 055aa1ee6ac5c72be5a7e332a766d666463d0a35..c2eea7dbc4883392e28c9a56f20d1981562ab768 100644 (file)
@@ -1392,7 +1392,8 @@ out:
 /**
  * batadv_tp_handle_out_of_order() - store an out of order packet
  * @tp_vars: the private data of the current TP meter session
- * @skb: the buffer containing the received packet
+ * @seqno: sequence number of new received packet
+ * @payload_len: length of the received packet
  *
  * Store the out of order packet in the unacked list for late processing. This
  * packets are kept in this list so that they can be ACKed at once as soon as
@@ -1401,22 +1402,17 @@ out:
  * Return: true if the packed has been successfully processed, false otherwise
  */
 static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars,
-                                         const struct sk_buff *skb)
+                                         u32 seqno, u32 payload_len)
        __must_hold(&tp_vars->common.unacked_lock)
 {
-       const struct batadv_icmp_tp_packet *icmp;
        struct batadv_tp_unacked *un, *new;
-       u32 payload_len;
        bool added = false;
 
        new = kmalloc_obj(*new, GFP_ATOMIC);
        if (unlikely(!new))
                return false;
 
-       icmp = (struct batadv_icmp_tp_packet *)skb->data;
-
-       new->seqno = ntohl(icmp->seqno);
-       payload_len = skb->len - sizeof(struct batadv_unicast_packet);
+       new->seqno = seqno;
        new->len = payload_len;
 
        /* if the list is empty immediately attach this new object */
@@ -1583,7 +1579,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
 {
        const struct batadv_icmp_tp_packet *icmp;
        struct batadv_tp_receiver *tp_vars;
-       size_t packet_size;
+       u32 payload_len;
        u32 to_ack;
        u32 seqno;
 
@@ -1618,15 +1614,17 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
        /* if the packet is a duplicate, it may be the case that an ACK has been
         * lost. Resend the ACK
         */
-       if (batadv_seq_before(seqno, tp_vars->last_recv))
+       payload_len = skb->len - sizeof(struct batadv_unicast_packet);
+       to_ack = seqno + payload_len;
+       if (batadv_seq_before(to_ack, tp_vars->last_recv))
                goto send_ack;
 
        /* if the packet is out of order enqueue it */
-       if (ntohl(icmp->seqno) != tp_vars->last_recv) {
+       if (batadv_seq_before(tp_vars->last_recv, seqno)) {
                /* exit immediately (and do not send any ACK) if the packet has
                 * not been enqueued correctly
                 */
-               if (!batadv_tp_handle_out_of_order(tp_vars, skb)) {
+               if (!batadv_tp_handle_out_of_order(tp_vars, seqno, payload_len)) {
                        spin_unlock_bh(&tp_vars->common.unacked_lock);
                        goto out;
                }
@@ -1636,8 +1634,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
        }
 
        /* if everything was fine count the ACKed bytes */
-       packet_size = skb->len - sizeof(struct batadv_unicast_packet);
-       tp_vars->last_recv += packet_size;
+       tp_vars->last_recv = to_ack;
 
        /* check if this ordered message filled a gap.... */
        batadv_tp_ack_unordered(tp_vars);