1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (C) B.A.T.M.A.N. contributors:
3 *
4 * Simon Wunderlich, Marek Lindner
5 */
6
7#include "bitarray.h"
8#include "main.h"
9
10#include <linux/bitmap.h>
11
12#include "log.h"
13
14/* shift the packet array by n places. */
15static void batadv_bitmap_shift_left(unsigned long *seq_bits, s32 n)
16{
17	if (n <= 0 || n >= BATADV_TQ_LOCAL_WINDOW_SIZE)
18		return;
19
20	bitmap_shift_left(seq_bits, seq_bits, n, BATADV_TQ_LOCAL_WINDOW_SIZE);
21}
22
23/**
24 * batadv_bit_get_packet() - receive and process one packet within the sequence
25 *  number window
26 * @priv: the bat priv with all the soft interface information
27 * @seq_bits: pointer to the sequence number receive packet
28 * @seq_num_diff: difference between the current/received sequence number and
29 *  the last sequence number
30 * @set_mark: whether this packet should be marked in seq_bits
31 *
32 * Return: true if the window was moved (either new or very old),
33 *  false if the window was not moved/shifted.
34 */
35bool batadv_bit_get_packet(void *priv, unsigned long *seq_bits,
36			   s32 seq_num_diff, int set_mark)
37{
38	struct batadv_priv *bat_priv = priv;
39
40	/* sequence number is slightly older. We already got a sequence number
41	 * higher than this one, so we just mark it.
42	 */
43	if (seq_num_diff <= 0 && seq_num_diff > -BATADV_TQ_LOCAL_WINDOW_SIZE) {
44		if (set_mark)
45			batadv_set_bit(seq_bits, -seq_num_diff);
46		return false;
47	}
48
49	/* sequence number is slightly newer, so we shift the window and
50	 * set the mark if required
51	 */
52	if (seq_num_diff > 0 && seq_num_diff < BATADV_TQ_LOCAL_WINDOW_SIZE) {
53		batadv_bitmap_shift_left(seq_bits, seq_num_diff);
54
55		if (set_mark)
56			batadv_set_bit(seq_bits, 0);
57		return true;
58	}
59
60	/* sequence number is much newer, probably missed a lot of packets */
61	if (seq_num_diff >= BATADV_TQ_LOCAL_WINDOW_SIZE &&
62	    seq_num_diff < BATADV_EXPECTED_SEQNO_RANGE) {
63		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
64			   "We missed a lot of packets (%i) !\n",
65			   seq_num_diff - 1);
66		bitmap_zero(seq_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
67		if (set_mark)
68			batadv_set_bit(seq_bits, 0);
69		return true;
70	}
71
72	/* received a much older packet. The other host either restarted
73	 * or the old packet got delayed somewhere in the network. The
74	 * packet should be dropped without calling this function if the
75	 * seqno window is protected.
76	 *
77	 * seq_num_diff <= -BATADV_TQ_LOCAL_WINDOW_SIZE
78	 * or
79	 * seq_num_diff >= BATADV_EXPECTED_SEQNO_RANGE
80	 */
81	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
82		   "Other host probably restarted!\n");
83
84	bitmap_zero(seq_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
85	if (set_mark)
86		batadv_set_bit(seq_bits, 0);
87
88	return true;
89}
90