aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/encoding.cpp120
-rw-r--r--src/encoding.h8
-rw-r--r--src/rlc.h15
-rw-r--r--tests/edge/EdgeTest.cpp70
4 files changed, 213 insertions, 0 deletions
diff --git a/src/encoding.cpp b/src/encoding.cpp
index fdc8d0ae..0756ffcb 100644
--- a/src/encoding.cpp
+++ b/src/encoding.cpp
@@ -25,6 +25,9 @@
#include <tbf.h>
#include <gprs_debug.h>
+#include <errno.h>
+#include <string.h>
+
// GSM 04.08 9.1.18 Immediate assignment
int Encoding::write_immediate_assignment(
struct gprs_rlcmac_bts *bts,
@@ -631,3 +634,120 @@ unsigned Encoding::write_repeated_page_info(bitvec * dest, unsigned& wp, uint8_t
return wp;
}
+int Encoding::rlc_write_dl_data_header(const struct gprs_rlc_data_info *rlc,
+ uint8_t *data)
+{
+ struct gprs_rlc_dl_header_egprs_3 *egprs3;
+ struct rlc_dl_header *gprs;
+ unsigned int e_fbi_header;
+ GprsCodingScheme cs = rlc->cs;
+
+ switch(cs.headerTypeData()) {
+ case GprsCodingScheme::HEADER_GPRS_DATA:
+ gprs = static_cast<struct rlc_dl_header *>
+ ((void *)data);
+
+ gprs->usf = rlc->usf;
+ gprs->s_p = rlc->es_p != 0 ? 1 : 0;
+ gprs->rrbp = rlc->rrbp;
+ gprs->pt = 0;
+ gprs->tfi = rlc->tfi;
+ gprs->pr = rlc->pr;
+
+ gprs->fbi = rlc->block_info[0].cv == 0;
+ gprs->e = rlc->block_info[0].e;
+ gprs->bsn = rlc->block_info[0].bsn;
+ break;
+
+ case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_3:
+ egprs3 = static_cast<struct gprs_rlc_dl_header_egprs_3 *>
+ ((void *)data);
+
+ egprs3->usf = rlc->usf;
+ egprs3->es_p = rlc->es_p;
+ egprs3->rrbp = rlc->rrbp;
+ egprs3->tfi_a = rlc->tfi >> 0; /* 1 bit LSB */
+ egprs3->tfi_b = rlc->tfi >> 1; /* 4 bits */
+ egprs3->pr = rlc->pr;
+ egprs3->cps = rlc->cps;
+
+ egprs3->bsn1_a = rlc->block_info[0].bsn >> 0; /* 2 bits LSB */
+ egprs3->bsn1_b = rlc->block_info[0].bsn >> 2; /* 8 bits */
+ egprs3->bsn1_c = rlc->block_info[0].bsn >> 10; /* 1 bit */
+
+ egprs3->spb = rlc->block_info[0].spb;
+
+ e_fbi_header = rlc->block_info[0].e ? 0x01 : 0;
+ e_fbi_header |= rlc->block_info[0].cv == 0 ? 0x02 : 0; /* FBI */
+ e_fbi_header <<= 7;
+ data[3] = (data[3] & 0b01111111) | (e_fbi_header >> 0);
+ data[4] = (data[4] & 0b11111110) | (e_fbi_header >> 8);
+ break;
+
+ case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_1:
+ case GprsCodingScheme::HEADER_EGPRS_DATA_TYPE_2:
+ /* TODO: Support both header types */
+ /* fall through */
+ default:
+ LOGP(DRLCMACDL, LOGL_ERROR,
+ "Encoding of uplink %s data blocks not yet supported.\n",
+ cs.name());
+ return -ENOTSUP;
+ };
+
+ return 0;
+}
+
+/**
+ * \brief Copy LSB bitstream RLC data block from byte aligned buffer.
+ *
+ * Note that the bitstream is encoded in LSB first order, so the two octets
+ * 654321xx xxxxxx87 contain the octet 87654321 starting at bit position 3
+ * (LSB has bit position 1). This is a different order than the one used by
+ * CSN.1.
+ *
+ * \param data_block_idx The block index, 0..1 for header type 1, 0 otherwise
+ * \param src A pointer to the start of the RLC block (incl. the header)
+ * \param buffer A data area of a least the size of the RLC block
+ * \returns the number of bytes copied
+ */
+unsigned int Encoding::rlc_copy_from_aligned_buffer(
+ const struct gprs_rlc_data_info *rlc,
+ unsigned int data_block_idx,
+ uint8_t *dst, const uint8_t *buffer)
+{
+ unsigned int hdr_bytes;
+ unsigned int extra_bits;
+ unsigned int i;
+
+ uint8_t c, last_c;
+ const uint8_t *src;
+ const struct gprs_rlc_data_block_info *rdbi;
+
+ OSMO_ASSERT(data_block_idx < rlc->num_data_blocks);
+ rdbi = &rlc->block_info[data_block_idx];
+
+ hdr_bytes = rlc->data_offs_bits[data_block_idx] / 8;
+ extra_bits = (rlc->data_offs_bits[data_block_idx] % 8);
+
+ if (extra_bits == 0) {
+ /* It is aligned already */
+ memmove(dst + hdr_bytes, buffer, rdbi->data_len);
+ return rdbi->data_len;
+ }
+
+ src = buffer;
+ dst = dst + hdr_bytes;
+ last_c = *dst << (8 - extra_bits);
+
+ for (i = 0; i < rdbi->data_len; i++) {
+ c = src[i];
+ *(dst++) = (last_c >> (8 - extra_bits)) | (c << extra_bits);
+ last_c = c;
+ }
+
+ /* overwrite the lower extra_bits */
+ *dst = (*dst & (0xff << extra_bits)) | (last_c >> (8 - extra_bits));
+
+ return rdbi->data_len;
+}
diff --git a/src/encoding.h b/src/encoding.h
index ff62bc90..6764ce41 100644
--- a/src/encoding.h
+++ b/src/encoding.h
@@ -68,4 +68,12 @@ public:
uint8_t *identity, uint8_t chan_needed);
static unsigned write_packet_paging_request(bitvec * dest);
+
+ static int rlc_write_dl_data_header(
+ const struct gprs_rlc_data_info *rlc,
+ uint8_t *data);
+ static unsigned int rlc_copy_from_aligned_buffer(
+ const struct gprs_rlc_data_info *rlc,
+ unsigned int data_block_idx,
+ uint8_t *dst, const uint8_t *buffer);
};
diff --git a/src/rlc.h b/src/rlc.h
index 59176253..a11b4ce8 100644
--- a/src/rlc.h
+++ b/src/rlc.h
@@ -298,6 +298,21 @@ struct gprs_rlc_ul_header_egprs_3 {
spare:1,
dummy:1;
} __attribute__ ((packed));
+
+struct gprs_rlc_dl_header_egprs_3 {
+ uint8_t usf:3,
+ es_p:2,
+ rrbp:2,
+ tfi_a:1;
+ uint8_t tfi_b:4,
+ pr:2,
+ bsn1_a:2;
+ uint8_t bsn1_b:8;
+ uint8_t bsn1_c:1,
+ cps:4,
+ spb:2,
+ dummy:1;
+} __attribute__ ((packed));
#else
# error "Only little endian headers are supported yet. TODO: add missing structs"
#endif
diff --git a/tests/edge/EdgeTest.cpp b/tests/edge/EdgeTest.cpp
index 7bb81e47..11459457 100644
--- a/tests/edge/EdgeTest.cpp
+++ b/tests/edge/EdgeTest.cpp
@@ -23,6 +23,7 @@
#include "gprs_debug.h"
#include "gprs_coding_scheme.h"
#include "decoding.h"
+#include "encoding.h"
#include "rlc.h"
extern "C" {
@@ -36,6 +37,7 @@ extern "C" {
}
#include <errno.h>
+#include <string.h>
void *tall_pcu_ctx;
int16_t spoof_mnc = 0, spoof_mcc = 0;
@@ -481,6 +483,73 @@ static void test_rlc_unit_decoder()
printf("=== end %s ===\n", __func__);
}
+static void test_rlc_unaligned_copy()
+{
+ uint8_t bits[256];
+ uint8_t saved_block[256];
+ uint8_t test_block[256];
+ uint8_t out_block[256];
+ GprsCodingScheme::Scheme scheme;
+ int pattern;
+ volatile unsigned int block_idx, i;
+
+ for (scheme = GprsCodingScheme::CS1;
+ scheme < GprsCodingScheme::NUM_SCHEMES;
+ scheme = GprsCodingScheme::Scheme(scheme + 1))
+ {
+ GprsCodingScheme cs(scheme);
+
+ for (pattern = 0; pattern <= 0xff; pattern += 0xff) {
+ /* prepare test block */
+ test_block[0] = pattern ^ 0xff;
+ for (i = 1; i + 1 < cs.maxDataBlockBytes(); i++)
+ test_block[i] = i;
+ test_block[cs.maxDataBlockBytes()-1] = pattern ^ 0xff;
+
+ for (block_idx = 0;
+ block_idx < cs.numDataBlocks();
+ block_idx++)
+ {
+ struct gprs_rlc_data_info rlc;
+ gprs_rlc_data_info_init_dl(&rlc, cs);
+
+ memset(bits, pattern, sizeof(bits));
+ Decoding::rlc_copy_to_aligned_buffer(
+ &rlc, block_idx, bits, saved_block);
+
+ fprintf(stderr,
+ "Test data block: %s\n",
+ osmo_hexdump(test_block, cs.maxDataBlockBytes()));
+
+ Encoding::rlc_copy_from_aligned_buffer(
+ &rlc, block_idx, bits, test_block);
+
+ fprintf(stderr,
+ "Encoded message block, %s, idx %d, "
+ "pattern %02x: %s\n",
+ rlc.cs.name(), block_idx, pattern,
+ osmo_hexdump(bits, cs.sizeDL()));
+
+ Decoding::rlc_copy_to_aligned_buffer(
+ &rlc, block_idx, bits, out_block);
+
+ fprintf(stderr,
+ "Out data block: %s\n",
+ osmo_hexdump(out_block, cs.maxDataBlockBytes()));
+ /* restore original bits */
+ Encoding::rlc_copy_from_aligned_buffer(
+ &rlc, block_idx, bits, saved_block);
+
+ OSMO_ASSERT(memcmp(test_block, out_block,
+ rlc.cs.maxDataBlockBytes()) == 0);
+
+ for (i = 0; i < sizeof(bits); i++)
+ OSMO_ASSERT(bits[i] == pattern);
+ }
+ }
+ }
+}
+
static void test_rlc_info_init()
{
struct gprs_rlc_data_info rlc;
@@ -544,6 +613,7 @@ int main(int argc, char **argv)
test_coding_scheme();
test_rlc_info_init();
test_rlc_unit_decoder();
+ test_rlc_unaligned_copy();
if (getenv("TALLOC_REPORT_FULL"))
talloc_report_full(tall_pcu_ctx, stderr);