xref: /openbmc/linux/net/batman-adv/bitarray.c (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
2*cfa55c6dSSven Eckelmann /* Copyright (C) B.A.T.M.A.N. contributors:
3c6c8fea2SSven Eckelmann  *
4c6c8fea2SSven Eckelmann  * Simon Wunderlich, Marek Lindner
5c6c8fea2SSven Eckelmann  */
6c6c8fea2SSven Eckelmann 
7c6c8fea2SSven Eckelmann #include "bitarray.h"
81e2c2a4fSSven Eckelmann #include "main.h"
9c6c8fea2SSven Eckelmann 
101e2c2a4fSSven Eckelmann #include <linux/bitmap.h>
11c6c8fea2SSven Eckelmann 
12ba412080SSven Eckelmann #include "log.h"
13ba412080SSven Eckelmann 
14c6c8fea2SSven Eckelmann /* shift the packet array by n places. */
batadv_bitmap_shift_left(unsigned long * seq_bits,s32 n)156b5e971aSSven Eckelmann static void batadv_bitmap_shift_left(unsigned long *seq_bits, s32 n)
16c6c8fea2SSven Eckelmann {
1742d0b044SSven Eckelmann 	if (n <= 0 || n >= BATADV_TQ_LOCAL_WINDOW_SIZE)
18c6c8fea2SSven Eckelmann 		return;
19c6c8fea2SSven Eckelmann 
2042d0b044SSven Eckelmann 	bitmap_shift_left(seq_bits, seq_bits, n, BATADV_TQ_LOCAL_WINDOW_SIZE);
21c6c8fea2SSven Eckelmann }
22c6c8fea2SSven Eckelmann 
237afcbbefSSven Eckelmann /**
247e9a8c2cSSven Eckelmann  * batadv_bit_get_packet() - receive and process one packet within the sequence
257afcbbefSSven Eckelmann  *  number window
267afcbbefSSven Eckelmann  * @priv: the bat priv with all the soft interface information
277afcbbefSSven Eckelmann  * @seq_bits: pointer to the sequence number receive packet
287afcbbefSSven Eckelmann  * @seq_num_diff: difference between the current/received sequence number and
297afcbbefSSven Eckelmann  *  the last sequence number
307afcbbefSSven Eckelmann  * @set_mark: whether this packet should be marked in seq_bits
31c6c8fea2SSven Eckelmann  *
324b426b10SSven Eckelmann  * Return: true if the window was moved (either new or very old),
334b426b10SSven Eckelmann  *  false if the window was not moved/shifted.
34c6c8fea2SSven Eckelmann  */
batadv_bit_get_packet(void * priv,unsigned long * seq_bits,s32 seq_num_diff,int set_mark)354b426b10SSven Eckelmann bool batadv_bit_get_packet(void *priv, unsigned long *seq_bits,
364b426b10SSven Eckelmann 			   s32 seq_num_diff, int set_mark)
37c6c8fea2SSven Eckelmann {
3856303d34SSven Eckelmann 	struct batadv_priv *bat_priv = priv;
39c6c8fea2SSven Eckelmann 
40c6c8fea2SSven Eckelmann 	/* sequence number is slightly older. We already got a sequence number
419cfc7bd6SSven Eckelmann 	 * higher than this one, so we just mark it.
429cfc7bd6SSven Eckelmann 	 */
4342d0b044SSven Eckelmann 	if (seq_num_diff <= 0 && seq_num_diff > -BATADV_TQ_LOCAL_WINDOW_SIZE) {
44c6c8fea2SSven Eckelmann 		if (set_mark)
459b4a1159SSven Eckelmann 			batadv_set_bit(seq_bits, -seq_num_diff);
464b426b10SSven Eckelmann 		return false;
47c6c8fea2SSven Eckelmann 	}
48c6c8fea2SSven Eckelmann 
49c6c8fea2SSven Eckelmann 	/* sequence number is slightly newer, so we shift the window and
509cfc7bd6SSven Eckelmann 	 * set the mark if required
519cfc7bd6SSven Eckelmann 	 */
5242d0b044SSven Eckelmann 	if (seq_num_diff > 0 && seq_num_diff < BATADV_TQ_LOCAL_WINDOW_SIZE) {
530f5f9322SSven Eckelmann 		batadv_bitmap_shift_left(seq_bits, seq_num_diff);
54c6c8fea2SSven Eckelmann 
55c6c8fea2SSven Eckelmann 		if (set_mark)
569b4a1159SSven Eckelmann 			batadv_set_bit(seq_bits, 0);
574b426b10SSven Eckelmann 		return true;
58c6c8fea2SSven Eckelmann 	}
59c6c8fea2SSven Eckelmann 
60c6c8fea2SSven Eckelmann 	/* sequence number is much newer, probably missed a lot of packets */
6142d0b044SSven Eckelmann 	if (seq_num_diff >= BATADV_TQ_LOCAL_WINDOW_SIZE &&
6242d0b044SSven Eckelmann 	    seq_num_diff < BATADV_EXPECTED_SEQNO_RANGE) {
6339c75a51SSven Eckelmann 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
64c6c8fea2SSven Eckelmann 			   "We missed a lot of packets (%i) !\n",
65c6c8fea2SSven Eckelmann 			   seq_num_diff - 1);
6642d0b044SSven Eckelmann 		bitmap_zero(seq_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
67c6c8fea2SSven Eckelmann 		if (set_mark)
689b4a1159SSven Eckelmann 			batadv_set_bit(seq_bits, 0);
694b426b10SSven Eckelmann 		return true;
70c6c8fea2SSven Eckelmann 	}
71c6c8fea2SSven Eckelmann 
72c6c8fea2SSven Eckelmann 	/* received a much older packet. The other host either restarted
73c6c8fea2SSven Eckelmann 	 * or the old packet got delayed somewhere in the network. The
74c6c8fea2SSven Eckelmann 	 * packet should be dropped without calling this function if the
759cfc7bd6SSven Eckelmann 	 * seqno window is protected.
768e7c15d6SSven Eckelmann 	 *
778e7c15d6SSven Eckelmann 	 * seq_num_diff <= -BATADV_TQ_LOCAL_WINDOW_SIZE
788e7c15d6SSven Eckelmann 	 * or
798e7c15d6SSven Eckelmann 	 * seq_num_diff >= BATADV_EXPECTED_SEQNO_RANGE
809cfc7bd6SSven Eckelmann 	 */
8139c75a51SSven Eckelmann 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
82c6c8fea2SSven Eckelmann 		   "Other host probably restarted!\n");
83c6c8fea2SSven Eckelmann 
8442d0b044SSven Eckelmann 	bitmap_zero(seq_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
85c6c8fea2SSven Eckelmann 	if (set_mark)
869b4a1159SSven Eckelmann 		batadv_set_bit(seq_bits, 0);
87c6c8fea2SSven Eckelmann 
884b426b10SSven Eckelmann 	return true;
89c6c8fea2SSven Eckelmann }
90