aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am6
-rw-r--r--src/decoding.cpp27
-rw-r--r--src/egprs_rlc_compression.cpp332
-rw-r--r--src/egprs_rlc_compression.h64
-rw-r--r--tests/Makefile.am15
-rw-r--r--tests/bitcomp/BitcompTest.cpp246
-rw-r--r--tests/bitcomp/BitcompTest.err92
-rw-r--r--tests/bitcomp/BitcompTest.ok2
-rw-r--r--tests/testsuite.at8
9 files changed, 774 insertions, 18 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 9bdec2f8..9b047e70 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,7 +62,8 @@ libgprs_la_SOURCES = \
rlc.cpp \
osmobts_sock.cpp \
gprs_codel.c \
- gprs_coding_scheme.cpp
+ gprs_coding_scheme.cpp \
+ egprs_rlc_compression.cpp
bin_PROGRAMS = \
osmo-pcu
@@ -94,7 +95,8 @@ noinst_HEADERS = \
pcu_utils.h \
cxx_linuxlist.h \
gprs_codel.h \
- gprs_coding_scheme.h
+ gprs_coding_scheme.h \
+ egprs_rlc_compression.h
osmo_pcu_SOURCES = pcu_main.cpp
diff --git a/src/decoding.cpp b/src/decoding.cpp
index 7c00ff71..2b00a07b 100644
--- a/src/decoding.cpp
+++ b/src/decoding.cpp
@@ -20,6 +20,7 @@
#include <decoding.h>
#include <rlc.h>
#include <gprs_debug.h>
+#include <egprs_rlc_compression.h>
extern "C" {
#include <osmocom/core/utils.h>
@@ -652,10 +653,10 @@ int Decoding::decode_egprs_acknack_bits(const EGPRS_AckNack_Desc_t *desc,
int num_blocks = 0;
struct bitvec urbb;
int i;
+ int rc;
bool have_bitmap;
int implicitly_acked_blocks;
int ssn = desc->STARTING_SEQUENCE_NUMBER;
- int rc;
if (desc->FINAL_ACK_INDICATION)
return handle_final_ack(bits, bsn_begin, bsn_end, window);
@@ -695,24 +696,20 @@ int Decoding::decode_egprs_acknack_bits(const EGPRS_AckNack_Desc_t *desc,
if (crbb_len > 0) {
int old_len = bits->cur_bit;
- struct bitvec crbb;
-
- crbb.data = (uint8_t *)desc->CRBB;
- crbb.data_len = sizeof(desc->CRBB);
- crbb.cur_bit = desc->CRBB_LENGTH;
-
- rc = osmo_t4_decode(&crbb, desc->CRBB_STARTING_COLOR_CODE,
- bits);
+ LOGP(DRLCMACDL, LOGL_DEBUG, "Compress bitmap exist,"
+ "CRBB LEN =%d and Starting color code =%d",
+ desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE);
+ rc = decompress_crbb(desc->CRBB_LENGTH, desc->CRBB_STARTING_COLOR_CODE,
+ desc->CRBB, bits);
if (rc < 0) {
LOGP(DRLCMACUL, LOGL_NOTICE,
- "Failed to decode CRBB: "
- "length %d, data '%s'\n",
- desc->CRBB_LENGTH,
- osmo_hexdump(crbb.data, crbb.data_len));
+ "Failed to decode CRBB: length %d, data '%s'\n",
+ desc->CRBB_LENGTH, osmo_hexdump(
+ desc->CRBB, (desc->CRBB_LENGTH + 7)/8));
/* We don't know the SSN offset for the URBB,
- * return what we have so far and assume the
- * bitmap has stopped here */
+ * return what we have so far and assume the
+ * bitmap has stopped here */
goto aborted;
}
diff --git a/src/egprs_rlc_compression.cpp b/src/egprs_rlc_compression.cpp
new file mode 100644
index 00000000..b781331e
--- /dev/null
+++ b/src/egprs_rlc_compression.cpp
@@ -0,0 +1,332 @@
+/* egprs_rlc_compression.h
+* Routines for EGPRS RLC bitmap compression handling
+*/
+#include <egprs_rlc_compression.h>
+#include <errno.h>
+#include <decoding.h>
+
+extern "C" {
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/stats.h>
+}
+
+egprs_compress *egprs_compress::s_instance = 0;
+
+/* Function to create tree node */
+Node *egprs_compress::create_tree_node(void *parent)
+{
+ Node *new_node;
+
+ new_node = talloc_zero(parent, Node);
+ new_node->left = NULL;
+ new_node->right = NULL;
+ new_node->run_length = -1;
+ return new_node;
+}
+
+/* Function to build the codeword tree
+ * \param iter[in] Iterate the node on the tree
+ * \param len[in] Length of the code word
+ * \param i[in] Iterator
+ * \param idx[in] Iterate index of the code word table
+ */
+void egprs_compress::build_codeword(Node *root, const char *cdwd[])
+{
+ Node *iter;
+ int len;
+ int i;
+ int idx;
+
+ for (idx = 0; idx < MAX_CDWDTBL_LEN; idx++) {
+ len = strlen((const char *)cdwd[idx]);
+ iter = root;
+ for (i = 0; i < len; i++) {
+ if (cdwd[idx][i] == '0') {
+ if (!iter->left)
+ iter->left = create_tree_node(root);
+ iter = iter->left;
+ } else if (cdwd[idx][i] == '1') {
+ if (!iter->right)
+ iter->right = create_tree_node(root);
+ iter = iter->right;
+ }
+ }
+ if (iter) {
+ if (idx < 64)
+ (iter->run_length) = idx;
+ else
+ (iter->run_length) = (idx - 63) * 64;
+ }
+ }
+}
+
+const char *one_run_len_code_list[MAX_CDWDTBL_LEN] = {
+ "00110101",
+ "000111",
+ "0111",
+ "1000",
+ "1011",
+ "1100",
+ "1110",
+ "1111",
+ "10011",
+ "10100",
+ "00111",
+ "01000",
+ "001000",
+ "000011",
+ "110100",
+ "110101",
+ "101010",
+ "101011",
+ "0100111",
+ "0001100",
+ "0001000",
+ "0010111",
+ "0000011",
+ "0000100",
+ "0101000",
+ "0101011",
+ "0010011",
+ "0100100",
+ "0011000",
+ "00000010",
+ "00000011",
+ "00011010",
+ "00011011",
+ "00010010",
+ "00010011",
+ "00010100",
+ "00010101",
+ "00010110",
+ "00010111",
+ "00101000",
+ "00101001",
+ "00101010",
+ "00101011",
+ "00101100",
+ "00101101",
+ "00000100",
+ "00000101",
+ "00001010",
+ "00001011",
+ "01010010",
+ "01010011",
+ "01010100",
+ "01010101",
+ "00100100",
+ "00100101",
+ "01011000",
+ "01011001",
+ "01011010",
+ "01011011",
+ "01001010",
+ "01001011",
+ "00110010",
+ "00110011",
+ "00110100",
+ "11011",
+ "10010",
+ "010111",
+ "0110111",
+ "00110110",
+ "00110111",
+ "01100100",
+ "01100101",
+ "01101000",
+ "01100111",
+ "011001100",
+ "011001101",
+ "011010010",
+ "011010011",
+ "011010100"
+};
+
+const char *zero_run_len_code_list[MAX_CDWDTBL_LEN] = {
+ "0000110111",
+ "10",
+ "11",
+ "010",
+ "011",
+ "0011",
+ "0010",
+ "00011",
+ "000101",
+ "000100",
+ "0000100",
+ "0000101",
+ "0000111",
+ "00000100",
+ "00000111",
+ "000011000",
+ "0000010111",
+ "0000011000",
+ "0000001000",
+ "00001100111",
+ "00001101000",
+ "00001101100",
+ "00000110111",
+ "00000101000",
+ "00000010111",
+ "00000011000",
+ "000011001010",
+ "000011001011",
+ "000011001100",
+ "000011001101",
+ "000001101000",
+ "000001101001",
+ "000001101010",
+ "000001101011",
+ "000011010010",
+ "000011010011",
+ "000011010100",
+ "000011010101",
+ "000011010110",
+ "000011010111",
+ "000001101100",
+ "000001101101",
+ "000011011010",
+ "000011011011",
+ "000001010100",
+ "000001010101",
+ "000001010110",
+ "000001010111",
+ "000001100100",
+ "000001100101",
+ "000001010010",
+ "000001010011",
+ "000000100100",
+ "000000110111",
+ "000000111000",
+ "000000100111",
+ "000000101000",
+ "000001011000",
+ "000001011001",
+ "000000101011",
+ "000000101100",
+ "000001011010",
+ "000001100110",
+ "000001100111",
+ "0000001111",
+ "000011001000",
+ "000011001001",
+ "000001011011",
+ "000000110011",
+ "000000110100",
+ "000000110101",
+ "0000001101100",
+ "0000001101101",
+ "0000001001010",
+ "0000001001011",
+ "0000001001100",
+ "0000001001101",
+ "0000001110010",
+ "0000001110011"
+};
+
+/* search_runlen function will return the runlength for the codeword
+ * \param root[in] Root of Ones or Zeros tree
+ * \param bmbuf[in] Recevied compressed bitmap buf
+ * \param bit_pos[in] The start bit pos to read codeword
+ * \param len_codewd[in] Length of code word
+ * \param rlen[out] Run length value
+ */
+static int search_runlen(
+ Node *root,
+ const uint8_t *bmbuf,
+ uint8_t bit_pos,
+ uint8_t *len_codewd,
+ uint16_t *rlen)
+{
+ Node *iter;
+ uint8_t dir;
+
+ iter = root;
+ *len_codewd = 0;
+
+ while (iter->run_length == -1) {
+ if ((!iter->left) && (!iter->right))
+ return -1;
+ /* get the bit value at the bitpos and put it in right most of dir */
+ dir = ((bmbuf[BITS_TO_BYTES(bit_pos)-1]
+ >>(7-(MOD8(bit_pos)))) & 0x01);
+ (bit_pos)++;
+ (*len_codewd)++;
+ if (((dir&0x01) == 0) && (iter->left != NULL))
+ iter = iter->left;
+ else if (((dir&0x01) == 1) && (iter->right != NULL))
+ iter = iter->right;
+ else
+ return -1;
+ }
+ (*rlen) = (iter->run_length);
+ return 1;
+}
+
+/* Function to decompress crbb
+ * \param[in] Compressed bitmap length
+ * \clr_code_bit[in] Color code 1 for Ones runlength 0 for Zero runlength
+ * \orig_crbb_buf[in] Received block crbb bitmap
+ * \dest[out] Uncompressed bitvector
+ */
+int decompress_crbb(
+ int8_t compress_bmap_len,
+ uint8_t clr_code_bit,
+ const uint8_t *orig_crbb_buf,
+ bitvec *dest)
+{
+
+ uint8_t bit_pos = 0;
+ uint8_t data = 0x0;
+ node *list = NULL;
+ uint8_t nbits = 0; /* number of bits of codeword */
+ uint16_t run_length = 0;
+ uint16_t cbmaplen = 0; /* compressed bitmap part after decompression */
+ unsigned wp = dest->cur_bit;
+ int rc = 0;
+ egprs_compress *compress = egprs_compress::instance();
+
+ while (compress_bmap_len > 0) {
+ if (clr_code_bit == 1) {
+ data = 0xff;
+ list = compress->ones_list;
+ } else {
+ data = 0x00;
+ list = compress->zeros_list;
+ }
+ rc = search_runlen(list, orig_crbb_buf,
+ bit_pos, &nbits, &run_length);
+ if (rc == -1)
+ return -1;
+ /* If run length > 64, need makeup and terminating code */
+ if (run_length < 64)
+ clr_code_bit ? clr_code_bit = 0 : clr_code_bit = 1;
+ cbmaplen = cbmaplen + run_length;
+ /* put run length of Ones in uncompressed bitmap */
+ while (run_length != 0) {
+ if (run_length > 8) {
+ bitvec_write_field(dest, wp, data, 8);
+ run_length = run_length - 8;
+ } else {
+ bitvec_write_field(dest, wp, data, run_length);
+ run_length = 0;
+ }
+ }
+ bit_pos = bit_pos + nbits;
+ compress_bmap_len = compress_bmap_len - nbits;
+ }
+ return 0;
+}
+
+/* init function to build codeword */
+int egprs_compress::decode_tree_init()
+{
+ ones_list = create_tree_node(tall_pcu_ctx);
+ zeros_list = create_tree_node(tall_pcu_ctx);
+ build_codeword(
+ ones_list, one_run_len_code_list);
+ build_codeword(
+ zeros_list, zero_run_len_code_list);
+ return 0;
+}
diff --git a/src/egprs_rlc_compression.h b/src/egprs_rlc_compression.h
new file mode 100644
index 00000000..cf563503
--- /dev/null
+++ b/src/egprs_rlc_compression.h
@@ -0,0 +1,64 @@
+/* egprs_rlc_compression.h
+ * Routines for EGPRS RLC bitmap compression handling
+ */
+
+#pragma once
+
+#include <gprs_rlcmac.h>
+#include <gprs_debug.h>
+
+extern "C" {
+#include <osmocom/core/talloc.h>
+}
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <string.h>
+
+#define MAX_CDWDTBL_LEN 79 /* total number of codewords */
+#define BITS_TO_BYTES(X) ((X ? (X/8):0)+1)
+#define MOD8(X) (((X)+8) & (0x07))
+
+typedef struct node {
+ struct node *left;
+ struct node *right;
+ int run_length;
+} Node;
+
+extern const char *one_run_len_code_list[MAX_CDWDTBL_LEN];
+extern const char *zero_run_len_code_list[MAX_CDWDTBL_LEN];
+extern void *tall_pcu_ctx;
+
+int decompress_crbb(int8_t compress_bmap_len, uint8_t clr_code_bit,
+ const uint8_t *orig_buf, bitvec *dest);
+
+/* Creating singleton class
+ */
+class egprs_compress
+{
+ static egprs_compress *s_instance;
+
+ egprs_compress()
+ {
+ if (decode_tree_init() < 0) {
+ fprintf(stderr, "Error initializing tree\n");
+ exit(1);
+ }
+ }
+ Node *create_tree_node(void *);
+ void build_codeword(Node *root, const char *cdwd[]);
+ ~egprs_compress();
+public:
+ Node *ones_list;
+ Node *zeros_list;
+
+ int decode_tree_init(void);
+
+ static egprs_compress *instance()
+ {
+ if (!s_instance)
+ s_instance = new egprs_compress;
+
+ return s_instance;
+ }
+};
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2a3415e0..5c68bea9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,7 +1,7 @@
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/
AM_LDFLAGS = -lrt
-check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest
+check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest codel/codel_test edge/EdgeTest bitcomp/BitcompTest
noinst_PROGRAMS = emu/pcu_emu
rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp
@@ -26,6 +26,18 @@ tbf_TbfTest_LDADD = \
$(LIBOSMOCORE_LIBS) \
$(COMMON_LA)
+bitcomp_BitcompTest_SOURCES = bitcomp/BitcompTest.cpp
+bitcomp_BitcompTest_LDADD = \
+ $(top_builddir)/src/libgprs.la \
+ $(LIBOSMOCORE_LIBS) \
+ $(LIBOSMOGB_LIBS) \
+ $(LIBOSMOGSM_LIBS) \
+ $(COMMON_LA)
+
+bitcomp_BitcompTest_LDFLAGS = \
+ -Wl,-u,bssgp_prim_cb
+
+
edge_EdgeTest_SOURCES = edge/EdgeTest.cpp
edge_EdgeTest_LDADD = \
$(top_builddir)/src/libgprs.la \
@@ -108,6 +120,7 @@ EXTRA_DIST = \
rlcmac/RLCMACTest.ok rlcmac/RLCMACTest.err \
alloc/AllocTest.ok alloc/AllocTest.err \
tbf/TbfTest.ok tbf/TbfTest.err \
+ bitcomp/BitcompTest.ok bitcomp/BitcompTest.err \
types/TypesTest.ok types/TypesTest.err \
ms/MsTest.ok ms/MsTest.err \
llc/LlcTest.ok llc/LlcTest.err \
diff --git a/tests/bitcomp/BitcompTest.cpp b/tests/bitcomp/BitcompTest.cpp
new file mode 100644
index 00000000..00d6ea8b
--- /dev/null
+++ b/tests/bitcomp/BitcompTest.cpp
@@ -0,0 +1,246 @@
+#include "egprs_rlc_compression.h"
+#include "decoding.h"
+#include "bts.h"
+#include "tbf.h"
+#include "gprs_debug.h"
+#include "pcu_utils.h"
+#include "gprs_bssgp_pcu.h"
+#include "pcu_l1_if.h"
+
+extern "C" {
+#include "pcu_vty.h"
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/vty/vty.h>
+#include <osmocom/gprs/protocol/gsm_04_60.h>
+}
+
+#define NEW 1
+#define MASK(n) (0xFF << (8-n))
+#define MAX_CRBB_LEN 23
+#define MAX_URBB_LEN 40
+
+void *tall_pcu_ctx;
+int16_t spoof_mnc = 0, spoof_mcc = 0;
+
+struct test_data {
+ int8_t crbb_len;
+ uint8_t cc;
+ uint8_t crbb_data[MAX_CRBB_LEN]; /* compressed data */
+ uint8_t ucmp_data[MAX_URBB_LEN]; /* uncompressed data */
+ int ucmp_len;
+ int verify;
+} test[] = {
+ { .crbb_len = 67, .cc = 1,
+ .crbb_data = {
+ 0x02, 0x0c, 0xa0, 0x30, 0xcb, 0x1a, 0x0c, 0xe3, 0x6c
+ },
+ .ucmp_data = {
+ 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff,
+ 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe,
+ 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xdb
+ },
+ .ucmp_len = 194, .verify = 1
+ },
+ { .crbb_len = 40, .cc = 1,
+ .crbb_data = {
+ 0x53, 0x06, 0xc5, 0x40, 0x6d
+ },
+ .ucmp_data = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
+ 0x00, 0x00, 0x00, 0x00, 0x03
+ },
+ .ucmp_len = 182, .verify = 1
+ },
+ { .crbb_len = 8, .cc = 1,
+ .crbb_data = {0x02},
+ .ucmp_data = {0xff, 0xff, 0xff, 0xf8},
+ .ucmp_len = 29, .verify = 1
+ },
+ { .crbb_len = 103, .cc = 1,
+ .crbb_data = {
+ 0x02, 0x0c, 0xe0, 0x41, 0xa0, 0x0c, 0x36, 0x0d, 0x03,
+ 0x71, 0xb0, 0x6e, 0x24
+ },
+ .ucmp_data = {
+ 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00,
+ 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff,
+ 0xff, 0xff, 0x80, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff
+ },
+ .ucmp_len = 288, .verify = 1
+ },
+ /* Test vector from libosmocore test */
+ { .crbb_len = 35, .cc = 0,
+ .crbb_data = {0xde, 0x88, 0x75, 0x65, 0x80},
+ .ucmp_data = {0x37, 0x47, 0x81, 0xf0},
+ .ucmp_len = 28, .verify = 1
+ },
+ { .crbb_len = 18, .cc = 1,
+ .crbb_data = {0xdd, 0x41, 0x00},
+ .ucmp_data = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00
+ },
+ .ucmp_len = 90, .verify = 1
+ },
+ /*Invalid inputs*/
+ { .crbb_len = 18, .cc = 1,
+ .crbb_data = {0x1E, 0x70, 0xc0},
+ .ucmp_data = {0x0},
+ .ucmp_len = 0, .verify = 0
+ },
+ { .crbb_len = 14, .cc = 1,
+ .crbb_data = {0x00, 0x1E, 0x7c},
+ .ucmp_data = {0x0},
+ .ucmp_len = 0, .verify = 0
+ },
+ { .crbb_len = 24, .cc = 0,
+ .crbb_data = {0x00, 0x00, 0x00},
+ .ucmp_data = {0x0},
+ .ucmp_len = 0, .verify = 0
+ }
+ };
+
+static const struct log_info_cat default_categories[] = {
+ {"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_INFO, 0},
+ {"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_DEBUG, 1},
+ {"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1},
+ {"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1},
+ {"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Downlink (RLCMAC)", LOGL_DEBUG, 1},
+ {"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Uplink (RLCMAC)", LOGL_DEBUG, 1},
+ {"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Scheduling (RLCMAC)", LOGL_DEBUG, 1},
+ {"DRLCMACMEAS", "\033[1;31m", "GPRS RLC/MAC layer Measurements (RLCMAC)", LOGL_INFO, 1},
+ {"DNS", "\033[1;34m", "GPRS Network Service Protocol (NS)", LOGL_INFO, 1},
+ {"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_INFO, 1},
+ {"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1},
+};
+
+static int filter_fn(const struct log_context *ctx,
+ struct log_target *tar)
+{
+ return 1;
+}
+
+/* To verify the result with expected result */
+int check_result(bitvec bits, uint8_t *exp_data, int exp_len)
+{
+ if (bits.cur_bit != exp_len)
+ return 0;
+ size_t n = (exp_len / 8);
+ int rem = (exp_len % 8);
+
+ if (memcmp(exp_data, bits.data, n) == 0) {
+ if (rem == 0)
+ return 1;
+ if ((bits.data[n] & MASK(rem)) == ((*(exp_data + n)) & MASK(rem)))
+ return 1;
+ else
+ return 0;
+ } else
+ return 0;
+}
+
+/* To test decoding of compressed bitmap by Tree based method
+ * and to verify the result with expected result
+ * for invalid input verfication is suppressed
+ */
+static void test_EPDAN_decode_tree(void)
+{
+ bitvec dest;
+ int init_flag = 1;
+ int itr;
+ int rc;
+ uint8_t bits_data[RLC_EGPRS_MAX_WS/8];
+
+ printf("=== start %s ===\n", __func__);
+
+ for (itr = 0 ; itr < (sizeof(test) / sizeof(test_data)) ; itr++) {
+ dest.data = bits_data;
+ dest.data_len = sizeof(bits_data);
+ dest.cur_bit = 0;
+ memset(dest.data, 0, sizeof(bits_data));
+ LOGP(DRLCMACDL, LOGL_DEBUG, "\nTest:%d\nTree based decoding:"
+ "\nuncompressed data = %s\nlen = %d\n", itr + 1,
+ osmo_hexdump(test[itr].crbb_data,
+ (test[itr].crbb_len + 7)/8), test[itr].crbb_len
+ );
+ rc = decompress_crbb(test[itr].crbb_len, test[itr].cc,
+ test[itr].crbb_data, &dest
+ );
+ if (rc < 0) {
+ LOGP(DRLCMACUL, LOGL_NOTICE,
+ "\nFailed to decode CRBB: length %d, data %s",
+ test[itr].crbb_len, osmo_hexdump(
+ test[itr].crbb_data, (test[itr].crbb_len + 7)/8));
+ }
+ if (init_flag)
+ init_flag = 0;
+ if (test[itr].verify) {
+ if (check_result(dest, test[itr].ucmp_data,
+ test[itr].ucmp_len) == 0) {
+ LOGP(DRLCMACDL, LOGL_DEBUG, "\nTree based decoding"
+ ":Error\nexpected data = %s\nexpected"
+ " len = %d\ndecoded data = %s\n"
+ "decoded len = %d\n",
+ osmo_hexdump(test[itr].ucmp_data,
+ (test[itr].ucmp_len + 7)/8),
+ test[itr].ucmp_len, osmo_hexdump(dest.data,
+ (dest.cur_bit + 7)/8), dest.cur_bit
+ );
+ OSMO_ASSERT(0);
+ }
+ }
+ LOGP(DRLCMACDL, LOGL_DEBUG, "\nexpected data = %s\nexpected len = %d"
+ "\ndecoded data = %s\ndecoded len = %d\n",
+ osmo_hexdump(test[itr].ucmp_data,
+ (test[itr].ucmp_len + 7)/8),
+ test[itr].ucmp_len, osmo_hexdump(dest.data,
+ (dest.cur_bit + 7)/8), dest.cur_bit
+ );
+ }
+
+ printf("=== end %s ===\n", __func__);
+}
+
+const struct log_info debug_log_info = {
+ filter_fn,
+ (struct log_info_cat *)default_categories,
+ ARRAY_SIZE(default_categories),
+};
+
+int main(int argc, char **argv)
+{
+ struct vty_app_info pcu_vty_info = {0};
+
+ osmo_init_logging(&debug_log_info);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_filename(osmo_stderr_target, 0);
+ bssgp_set_log_ss(DBSSGP);
+
+ vty_init(&pcu_vty_info);
+ pcu_vty_init(&debug_log_info);
+
+ tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile TbfTest context");
+ if (!tall_pcu_ctx)
+ abort();
+ test_EPDAN_decode_tree();
+ if (getenv("TALLOC_REPORT_FULL"))
+ talloc_report_full(tall_pcu_ctx, stderr);
+ talloc_free(tall_pcu_ctx);
+ return EXIT_SUCCESS;
+}
+/*
+ * stubs that should not be reached
+ */
+extern "C" {
+void l1if_pdch_req() { abort(); }
+void l1if_connect_pdch() { abort(); }
+void l1if_close_pdch() { abort(); }
+void l1if_open_pdch() { abort(); }
+}
+
diff --git a/tests/bitcomp/BitcompTest.err b/tests/bitcomp/BitcompTest.err
new file mode 100644
index 00000000..a9078d0e
--- /dev/null
+++ b/tests/bitcomp/BitcompTest.err
@@ -0,0 +1,92 @@
+
+Test:1
+Tree based decoding:
+uncompressed data = 02 0c a0 30 cb 1a 0c e3 6c
+len = 67
+
+expected data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db
+expected len = 194
+decoded data = ff ff ff f8 00 00 01 ff ff ff f8 00 00 00 ff ff ff fe 00 00 3f ff ff ff db
+decoded len = 194
+
+Test:2
+Tree based decoding:
+uncompressed data = 53 06 c5 40 6d
+len = 40
+
+expected data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03
+expected len = 182
+decoded data = ff ff ff ff ff ff c0 00 00 00 00 3f ff ff ff ff ff f8 00 00 00 00 03
+decoded len = 182
+
+Test:3
+Tree based decoding:
+uncompressed data = 02
+len = 8
+
+expected data = ff ff ff f8
+expected len = 29
+decoded data = ff ff ff f8
+decoded len = 29
+
+Test:4
+Tree based decoding:
+uncompressed data = 02 0c e0 41 a0 0c 36 0d 03 71 b0 6e 24
+len = 103
+
+expected data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff
+expected len = 288
+decoded data = ff ff ff f8 00 00 ff ff ff f8 00 00 7f ff ff fe 00 00 0f ff ff ff e0 00 00 7f ff ff ff 80 00 01 ff ff ff ff
+decoded len = 288
+
+Test:5
+Tree based decoding:
+uncompressed data = de 88 75 65 80
+len = 35
+
+expected data = 37 47 81 f0
+expected len = 28
+decoded data = 37 47 81 f0
+decoded len = 28
+
+Test:6
+Tree based decoding:
+uncompressed data = dd 41 00
+len = 18
+
+expected data = ff ff ff ff ff ff ff ff ff ff 00 00
+expected len = 90
+decoded data = ff ff ff ff ff ff ff ff ff ff 00 00
+decoded len = 90
+
+Test:7
+Tree based decoding:
+uncompressed data = 1e 70 c0
+len = 18
+
+expected data =
+expected len = 0
+decoded data =
+decoded len = 19
+
+Test:8
+Tree based decoding:
+uncompressed data = 00 1e
+len = 14
+
+Failed to decode CRBB: length 14, data 00 1e
+expected data =
+expected len = 0
+decoded data =
+decoded len = 0
+
+Test:9
+Tree based decoding:
+uncompressed data = 00 00 00
+len = 24
+
+Failed to decode CRBB: length 24, data 00 00 00
+expected data =
+expected len = 0
+decoded data =
+decoded len = 0
diff --git a/tests/bitcomp/BitcompTest.ok b/tests/bitcomp/BitcompTest.ok
new file mode 100644
index 00000000..f7720fc9
--- /dev/null
+++ b/tests/bitcomp/BitcompTest.ok
@@ -0,0 +1,2 @@
+=== start test_EPDAN_decode_tree ===
+=== end test_EPDAN_decode_tree ===
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 1049b318..3ab39ccb 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -23,6 +23,14 @@ cat $abs_srcdir/tbf/TbfTest.err > experr
AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/tbf/TbfTest], [0], [expout], [experr])
AT_CLEANUP
+
+AT_SETUP([bitcomp])
+AT_KEYWORDS([bitcomp])
+cat $abs_srcdir/bitcomp/BitcompTest.ok > expout
+cat $abs_srcdir/bitcomp/BitcompTest.err > experr
+AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/bitcomp/BitcompTest], [0], [expout], [experr])
+AT_CLEANUP
+
AT_SETUP([edge])
AT_KEYWORDS([edge])
cat $abs_srcdir/edge/EdgeTest.ok > expout