aboutsummaryrefslogtreecommitdiffstats
path: root/src/rlc_window_ul.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/rlc_window_ul.h')
-rw-r--r--src/rlc_window_ul.h180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/rlc_window_ul.h b/src/rlc_window_ul.h
new file mode 100644
index 00000000..8a48af92
--- /dev/null
+++ b/src/rlc_window_ul.h
@@ -0,0 +1,180 @@
+/* RLC Window (UL TBF), 3GPP TS 44.060
+ *
+ * Copyright (C) 2012 Ivan Klyuchnikov
+ * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
+ * Copyright (C) 2023 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#pragma once
+
+#include "rlc.h"
+#include "rlc_window.h"
+
+/* The state of a BSN in the send/receive window */
+enum gprs_rlc_ul_bsn_state {
+ GPRS_RLC_UL_BSN_INVALID,
+ GPRS_RLC_UL_BSN_RECEIVED,
+ GPRS_RLC_UL_BSN_MISSING,
+ GPRS_RLC_UL_BSN_MAX,
+};
+
+struct gprs_rlc_v_n {
+ void reset(void);
+
+ void mark_received(int bsn);
+ void mark_missing(int bsn);
+ void mark_invalid(int bsn);
+
+ bool is_received(int bsn) const;
+
+ gprs_rlc_ul_bsn_state state(int bsn) const;
+private:
+ bool is_state(int bsn, const gprs_rlc_ul_bsn_state state) const;
+ void mark(int bsn, const gprs_rlc_ul_bsn_state state);
+ gprs_rlc_ul_bsn_state m_v_n[RLC_MAX_SNS/2]; /* receive state array */
+};
+
+
+inline void gprs_rlc_v_n::mark_received(int bsn)
+{
+ return mark(bsn, GPRS_RLC_UL_BSN_RECEIVED);
+}
+
+inline void gprs_rlc_v_n::mark_missing(int bsn)
+{
+ return mark(bsn, GPRS_RLC_UL_BSN_MISSING);
+}
+
+inline void gprs_rlc_v_n::mark_invalid(int bsn)
+{
+ return mark(bsn, GPRS_RLC_UL_BSN_INVALID);
+}
+
+inline bool gprs_rlc_v_n::is_received(int bsn) const
+{
+ return is_state(bsn, GPRS_RLC_UL_BSN_RECEIVED);
+}
+
+inline bool gprs_rlc_v_n::is_state(int bsn, gprs_rlc_ul_bsn_state type) const
+{
+ return m_v_n[bsn & mod_sns_half()] == type;
+}
+
+inline void gprs_rlc_v_n::mark(int bsn, gprs_rlc_ul_bsn_state type)
+{
+ m_v_n[bsn & mod_sns_half()] = type;
+}
+
+inline gprs_rlc_ul_bsn_state gprs_rlc_v_n::state(int bsn) const
+{
+ return m_v_n[bsn & mod_sns_half()];
+}
+
+struct gprs_rlc_ul_window : public gprs_rlc_window {
+ const uint16_t v_r(void) const;
+ const uint16_t v_q(void) const;
+
+ const void set_v_r(int v_r);
+ const void set_v_q(int v_q);
+ void reset_state(void);
+
+ const uint16_t ssn(void) const;
+
+ bool is_in_window(uint16_t bsn) const;
+ bool is_received(uint16_t bsn) const;
+
+ void update_rbb(char *rbb);
+ uint16_t update_egprs_rbb(uint8_t *rbb);
+ void raise_v_r_to(int moves);
+ void raise_v_r(const uint16_t bsn);
+ uint16_t raise_v_q(void);
+
+ void raise_v_q(int incr);
+
+ void receive_bsn(const uint16_t bsn);
+ bool invalidate_bsn(const uint16_t bsn);
+
+ uint16_t m_v_r; /* receive state */
+ uint16_t m_v_q; /* receive window state */
+
+ gprs_rlc_v_n m_v_n;
+
+ gprs_rlc_ul_window(void);
+};
+
+
+inline gprs_rlc_ul_window::gprs_rlc_ul_window(void)
+{
+ reset_state();
+}
+
+inline bool gprs_rlc_ul_window::is_in_window(uint16_t bsn) const
+{
+ uint16_t offset_v_q;
+
+ /* current block relative to lowest unreceived block */
+ offset_v_q = (bsn - m_v_q) & mod_sns();
+ /* If out of window (may happen if blocks below V(Q) are received
+ * again. */
+ return offset_v_q < ws();
+}
+
+inline bool gprs_rlc_ul_window::is_received(uint16_t bsn) const
+{
+ uint16_t offset_v_r;
+
+ /* Offset to the end of the received window */
+ offset_v_r = (m_v_r - 1 - bsn) & mod_sns();
+ return is_in_window(bsn) && m_v_n.is_received(bsn) && offset_v_r < ws();
+}
+
+inline void gprs_rlc_ul_window::reset_state(void)
+{
+ m_v_r = 0;
+ m_v_q = 0;
+ m_v_n.reset();
+}
+
+inline const void gprs_rlc_ul_window::set_v_r(int v_r)
+{
+ m_v_r = v_r;
+}
+
+inline const void gprs_rlc_ul_window::set_v_q(int v_q)
+{
+ m_v_q = v_q;
+}
+
+inline const uint16_t gprs_rlc_ul_window::v_r(void) const
+{
+ return m_v_r;
+}
+
+inline const uint16_t gprs_rlc_ul_window::v_q(void) const
+{
+ return m_v_q;
+}
+
+inline const uint16_t gprs_rlc_ul_window::ssn(void) const
+{
+ return m_v_r;
+}
+
+inline void gprs_rlc_ul_window::raise_v_r_to(int moves)
+{
+ m_v_r = mod_sns(m_v_r + moves);
+}
+
+inline void gprs_rlc_ul_window::raise_v_q(int incr)
+{
+ m_v_q = mod_sns(m_v_q + incr);
+}