aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPau Espin Pedrol <pespin@sysmocom.de>2023-07-25 17:43:36 +0200
committerPau Espin Pedrol <pespin@sysmocom.de>2023-07-26 17:03:53 +0200
commitc1278288b5d4a5dbcfcf4ab615cbf75193222762 (patch)
tree789d9f9fd5d5960ea3eba48109920d1cbfee718e
parentff33597e4bec2ab97440d3ff860013412e5d62a5 (diff)
gprs_rlc_ul_window: Mark received BSNs falling out of the V(N)/RBB when V(R) is raised
This is a port of libosmo-gprs.git commit 49535bec37caddcea5718ed4e526c477c71f1b3a applied to osmo-pcu. Problem this patch is fixing: The current RLCMAC code is never invalidating the BSNs which have been received after they are not needed. This is somehow workaround by the following check when eg BSN wraps around 127->0 and the BSN=0 is received: """" rcv_data_block_acknowledged() m_window.m_v_n.is_received(rdbi->bsn) /* Offset to the end of the received window */ offset_v_r = (m_v_r - 1 - bsn) & mod_sns(); return m_v_n.is_received(bsn) && offset_v_r < ws(); """ The first m_v_n_is_received() would return true because the BSN has never been invalidated, which is wrong, but fortunately the extra check "offset_v_r < ws()" returns > ws() since: v_r=0, bsn=0: "(0 - 1 - 0) & 127" ----> 0xffff & 0x007f ---> 0x007f > 64 So thanks to the above the BSN is considered not received, but looking at the V(N) array would say the opposite. Hence, this commit aims at fixing the V(N) array to contain proper values (marked "invalid") for BSNs becoming out of the window when it rolls forward. Explanation of the solution: The V(N) array contains the status of the previous WS (64 in GPRS) data blocks. This array is used to construct the RRB signaled to the peer during PKT UL ACK/NACK messages together with the SSN (start sequence number), which in our case is mainly V(R), aka one block higher than the highest received block in the rx window. Hence, whenever PKT UL ACK/NACK is transmitted, it contains an RRB ranging [V(R)-1,...V(R)-WS)] mod SNS (SNS=128 in GPRS). The receive window is basically [V(Q) <= BSN < V(R)] mod SNS, as is of size 64. The V(R) is increased whenever a highest new block arrives which is in the receive window (guaranteeing it will be increased to at most V(Q)+64. Since we are only announcing state of blocks from V(R)..V(R)-WS, and blocks received which are before that BSN are dropped since don't fall inside the rx window, we can securely mark as invalid those blocks falling behind V(R)-WS whenever we increase V(R). Related: OS#6102 Change-Id: I5ef4dcb0c5eac07a892114897f9e4f565b1dcc2c
-rw-r--r--src/rlc_window_ul.cpp10
-rw-r--r--src/rlc_window_ul.h6
-rw-r--r--src/tbf_ul.cpp2
3 files changed, 15 insertions, 3 deletions
diff --git a/src/rlc_window_ul.cpp b/src/rlc_window_ul.cpp
index 568e126e..32810d1b 100644
--- a/src/rlc_window_ul.cpp
+++ b/src/rlc_window_ul.cpp
@@ -37,8 +37,14 @@ void gprs_rlc_ul_window::raise_v_r(const uint16_t bsn)
/* Positive offset, so raise. */
if (offset_v_r < (sns() >> 1)) {
while (offset_v_r--) {
- if (offset_v_r) /* all except the received block */
- m_v_n.mark_missing(v_r());
+ const uint16_t _v_r = v_r();
+ const uint16_t bsn_no_longer_in_ws = mod_sns(_v_r - ws());
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Mark BSN %u as INVALID\n", bsn_no_longer_in_ws);
+ m_v_n.mark_invalid(bsn_no_longer_in_ws);
+ if (offset_v_r) {/* all except the received block */
+ LOGP(DRLCMACUL, LOGL_DEBUG, "- Mark BSN %u as MISSING\n", _v_r);
+ m_v_n.mark_missing(_v_r);
+ }
raise_v_r_to(1);
}
LOGP(DRLCMACUL, LOGL_DEBUG, "- Raising V(R) to %d\n", v_r());
diff --git a/src/rlc_window_ul.h b/src/rlc_window_ul.h
index a2e60c0d..8a48af92 100644
--- a/src/rlc_window_ul.h
+++ b/src/rlc_window_ul.h
@@ -32,6 +32,7 @@ struct gprs_rlc_v_n {
void mark_received(int bsn);
void mark_missing(int bsn);
+ void mark_invalid(int bsn);
bool is_received(int bsn) const;
@@ -53,6 +54,11 @@ 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);
diff --git a/src/tbf_ul.cpp b/src/tbf_ul.cpp
index 5ae0d495..3746130f 100644
--- a/src/tbf_ul.cpp
+++ b/src/tbf_ul.cpp
@@ -303,7 +303,7 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(
rdbi->bsn,
m_window.v_q(), m_window.mod_sns(m_window.v_q() + ws - 1));
continue;
- } else if (m_window.is_received(rdbi->bsn)) {
+ } else if (m_window.m_v_n.is_received(rdbi->bsn)) {
LOGPTBFUL(this, LOGL_DEBUG,
"BSN %d already received\n", rdbi->bsn);
continue;