gprs: Honor GSM 04.64 8.4.2 Receipt of unacknowledged information
GSM 04.64 8.4.2 asks to ignore UI frames if the DLCI is not known, or if the "(V(UR)- 32) <= N(U) < V(UR)". E.g. if we want to have V(UR) == 511 and this frame is dropped, we would ignore N(U)'s 0 to 510. Calculate the delta. The code is based on Jonathan Santos's "LLC UI window" fix but the issue was discovered independly.changes/88/3188/1
parent
26d0fe3c89
commit
faf1f64a2d
|
@ -51,6 +51,7 @@ tests/mgcp/mgcp_test
|
|||
tests/sccp/sccp_test
|
||||
tests/sms/sms_test
|
||||
tests/timer/timer_test
|
||||
tests/gprs/gprs_test
|
||||
|
||||
tests/atconfig
|
||||
tests/package.m4
|
||||
|
|
|
@ -112,6 +112,7 @@ AC_OUTPUT(
|
|||
tests/channel/Makefile
|
||||
tests/bsc-nat/Makefile
|
||||
tests/mgcp/Makefile
|
||||
tests/gprs/Makefile
|
||||
doc/Makefile
|
||||
doc/examples/Makefile
|
||||
Makefile)
|
||||
|
|
|
@ -179,4 +179,20 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
|
|||
int gprs_llc_init(const char *cipher_plugin_path);
|
||||
int gprs_llc_vty_init(void);
|
||||
|
||||
/**
|
||||
* \short Check if N(U) should be considered a retransmit
|
||||
*
|
||||
* Implements the range check as of GSM 04.64 8.4.2
|
||||
* Receipt of unacknowledged information.
|
||||
*
|
||||
* @returns Returns 1 if (V(UR)-32) <= N(U) < V(UR)
|
||||
* @param nu N(U) unconfirmed sequence number of the UI frame
|
||||
* @param vur V(UR) unconfirmend received state variable
|
||||
*/
|
||||
static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur)
|
||||
{
|
||||
int delta = (vur - nu) & 0x1ff;
|
||||
return 0 < delta && delta < 32;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -518,8 +518,9 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
|
|||
rx_llc_xid(lle, gph);
|
||||
break;
|
||||
case GPRS_LLC_UI:
|
||||
if (gph->seq_tx < lle->vu_recv) {
|
||||
LOGP(DLLC, LOGL_NOTICE, "TLLI=%08x dropping UI, vurecv %u <= %u\n",
|
||||
if (gprs_llc_is_retransmit(gph->seq_tx, lle->vu_recv)) {
|
||||
LOGP(DLLC, LOGL_NOTICE,
|
||||
"TLLI=%08x dropping UI, N(U=%d) not in window V(URV(UR:%d).\n",
|
||||
lle->llme ? lle->llme->tlli : -1,
|
||||
gph->seq_tx, lle->vu_recv);
|
||||
return -EIO;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
SUBDIRS = debug gsm0408 db channel mgcp
|
||||
SUBDIRS = debug gsm0408 db channel mgcp gprs
|
||||
|
||||
if BUILD_NAT
|
||||
SUBDIRS += bsc-nat
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
||||
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS)
|
||||
|
||||
EXTRA_DIST = gprs_test.ok
|
||||
|
||||
noinst_PROGRAMS = gprs_test
|
||||
|
||||
gprs_test_SOURCES = gprs_test.c
|
|
@ -0,0 +1,51 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <openbsc/gprs_llc.h>
|
||||
|
||||
#define ASSERT_FALSE(x) if (x) { printf("Should have returned false.\n"); abort(); }
|
||||
#define ASSERT_TRUE(x) if (!x) { printf("Should have returned true.\n"); abort(); }
|
||||
|
||||
/**
|
||||
* GSM 04.64 8.4.2 Receipt of unacknowledged information
|
||||
*/
|
||||
static int nu_is_retransmission(uint16_t nu, uint16_t vur)
|
||||
{
|
||||
int ret = gprs_llc_is_retransmit(nu, vur);
|
||||
printf("N(U) = %d, V(UR) = %d => %s\n", nu, vur,
|
||||
ret == 1 ? "retransmit" : "new");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_8_4_2()
|
||||
{
|
||||
printf("Testing gprs_llc_is_retransmit.\n");
|
||||
|
||||
ASSERT_FALSE(nu_is_retransmission(0, 0));
|
||||
ASSERT_TRUE (nu_is_retransmission(0, 1));
|
||||
|
||||
/* expect 1... check for retransmissions */
|
||||
ASSERT_TRUE (nu_is_retransmission(0, 1));
|
||||
ASSERT_TRUE (nu_is_retransmission(511, 1));
|
||||
ASSERT_TRUE (nu_is_retransmission(483, 1));
|
||||
ASSERT_TRUE (nu_is_retransmission(482, 1));
|
||||
ASSERT_FALSE(nu_is_retransmission(481, 1));
|
||||
|
||||
/* expect 511... check for retransmissions */
|
||||
ASSERT_FALSE(nu_is_retransmission(0, 240)); // ahead
|
||||
ASSERT_FALSE(nu_is_retransmission(0, 511)); // ahead
|
||||
ASSERT_FALSE(nu_is_retransmission(1, 511)); // ahead
|
||||
ASSERT_FALSE(nu_is_retransmission(511, 511)); // same
|
||||
ASSERT_TRUE (nu_is_retransmission(510, 511)); // behind
|
||||
ASSERT_TRUE (nu_is_retransmission(481, 511)); // behind
|
||||
ASSERT_FALSE(nu_is_retransmission(479, 511)); // wrapped
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_8_4_2();
|
||||
|
||||
printf("Done.\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
Testing gprs_llc_is_retransmit.
|
||||
N(U) = 0, V(UR) = 0 => new
|
||||
N(U) = 0, V(UR) = 1 => retransmit
|
||||
N(U) = 0, V(UR) = 1 => retransmit
|
||||
N(U) = 511, V(UR) = 1 => retransmit
|
||||
N(U) = 483, V(UR) = 1 => retransmit
|
||||
N(U) = 482, V(UR) = 1 => retransmit
|
||||
N(U) = 481, V(UR) = 1 => new
|
||||
N(U) = 0, V(UR) = 240 => new
|
||||
N(U) = 0, V(UR) = 511 => new
|
||||
N(U) = 1, V(UR) = 511 => new
|
||||
N(U) = 511, V(UR) = 511 => new
|
||||
N(U) = 510, V(UR) = 511 => retransmit
|
||||
N(U) = 481, V(UR) = 511 => retransmit
|
||||
N(U) = 479, V(UR) = 511 => new
|
||||
Done.
|
Loading…
Reference in New Issue