18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (C) 2006-2020  B.A.T.M.A.N. contributors:
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Simon Wunderlich, Marek Lindner
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "bitarray.h"
88c2ecf20Sopenharmony_ci#include "main.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "log.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/* shift the packet array by n places. */
158c2ecf20Sopenharmony_cistatic void batadv_bitmap_shift_left(unsigned long *seq_bits, s32 n)
168c2ecf20Sopenharmony_ci{
178c2ecf20Sopenharmony_ci	if (n <= 0 || n >= BATADV_TQ_LOCAL_WINDOW_SIZE)
188c2ecf20Sopenharmony_ci		return;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	bitmap_shift_left(seq_bits, seq_bits, n, BATADV_TQ_LOCAL_WINDOW_SIZE);
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/**
248c2ecf20Sopenharmony_ci * batadv_bit_get_packet() - receive and process one packet within the sequence
258c2ecf20Sopenharmony_ci *  number window
268c2ecf20Sopenharmony_ci * @priv: the bat priv with all the soft interface information
278c2ecf20Sopenharmony_ci * @seq_bits: pointer to the sequence number receive packet
288c2ecf20Sopenharmony_ci * @seq_num_diff: difference between the current/received sequence number and
298c2ecf20Sopenharmony_ci *  the last sequence number
308c2ecf20Sopenharmony_ci * @set_mark: whether this packet should be marked in seq_bits
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * Return: true if the window was moved (either new or very old),
338c2ecf20Sopenharmony_ci *  false if the window was not moved/shifted.
348c2ecf20Sopenharmony_ci */
358c2ecf20Sopenharmony_cibool batadv_bit_get_packet(void *priv, unsigned long *seq_bits,
368c2ecf20Sopenharmony_ci			   s32 seq_num_diff, int set_mark)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct batadv_priv *bat_priv = priv;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	/* sequence number is slightly older. We already got a sequence number
418c2ecf20Sopenharmony_ci	 * higher than this one, so we just mark it.
428c2ecf20Sopenharmony_ci	 */
438c2ecf20Sopenharmony_ci	if (seq_num_diff <= 0 && seq_num_diff > -BATADV_TQ_LOCAL_WINDOW_SIZE) {
448c2ecf20Sopenharmony_ci		if (set_mark)
458c2ecf20Sopenharmony_ci			batadv_set_bit(seq_bits, -seq_num_diff);
468c2ecf20Sopenharmony_ci		return false;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	/* sequence number is slightly newer, so we shift the window and
508c2ecf20Sopenharmony_ci	 * set the mark if required
518c2ecf20Sopenharmony_ci	 */
528c2ecf20Sopenharmony_ci	if (seq_num_diff > 0 && seq_num_diff < BATADV_TQ_LOCAL_WINDOW_SIZE) {
538c2ecf20Sopenharmony_ci		batadv_bitmap_shift_left(seq_bits, seq_num_diff);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci		if (set_mark)
568c2ecf20Sopenharmony_ci			batadv_set_bit(seq_bits, 0);
578c2ecf20Sopenharmony_ci		return true;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	/* sequence number is much newer, probably missed a lot of packets */
618c2ecf20Sopenharmony_ci	if (seq_num_diff >= BATADV_TQ_LOCAL_WINDOW_SIZE &&
628c2ecf20Sopenharmony_ci	    seq_num_diff < BATADV_EXPECTED_SEQNO_RANGE) {
638c2ecf20Sopenharmony_ci		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
648c2ecf20Sopenharmony_ci			   "We missed a lot of packets (%i) !\n",
658c2ecf20Sopenharmony_ci			   seq_num_diff - 1);
668c2ecf20Sopenharmony_ci		bitmap_zero(seq_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
678c2ecf20Sopenharmony_ci		if (set_mark)
688c2ecf20Sopenharmony_ci			batadv_set_bit(seq_bits, 0);
698c2ecf20Sopenharmony_ci		return true;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/* received a much older packet. The other host either restarted
738c2ecf20Sopenharmony_ci	 * or the old packet got delayed somewhere in the network. The
748c2ecf20Sopenharmony_ci	 * packet should be dropped without calling this function if the
758c2ecf20Sopenharmony_ci	 * seqno window is protected.
768c2ecf20Sopenharmony_ci	 *
778c2ecf20Sopenharmony_ci	 * seq_num_diff <= -BATADV_TQ_LOCAL_WINDOW_SIZE
788c2ecf20Sopenharmony_ci	 * or
798c2ecf20Sopenharmony_ci	 * seq_num_diff >= BATADV_EXPECTED_SEQNO_RANGE
808c2ecf20Sopenharmony_ci	 */
818c2ecf20Sopenharmony_ci	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
828c2ecf20Sopenharmony_ci		   "Other host probably restarted!\n");
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	bitmap_zero(seq_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
858c2ecf20Sopenharmony_ci	if (set_mark)
868c2ecf20Sopenharmony_ci		batadv_set_bit(seq_bits, 0);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return true;
898c2ecf20Sopenharmony_ci}
90