diff options
author | Harald Welte <laforge@osmocom.org> | 2023-02-25 19:15:16 +0100 |
---|---|---|
committer | Harald Welte <laforge@osmocom.org> | 2023-03-01 10:23:17 +0100 |
commit | 70271423f806882285f94950c457af5474f49af2 (patch) | |
tree | 5b30bc13ab6b9197f881362a5e472b786f1cc8c4 | |
parent | 967f71b7d14d74f8558f575f5a00cc7aada38fa2 (diff) |
HACK: WIP to post-process burst_ind .dat files with 9.6 NT CSD
Change-Id: I907a4e7dae76c4aef532df44b246b3a4f66c3043
-rw-r--r-- | src/host/layer23/configure.ac | 1 | ||||
-rw-r--r-- | src/host/layer23/src/misc/Makefile.am | 8 | ||||
-rw-r--r-- | src/host/layer23/src/misc/app_ccch_scan.c | 22 | ||||
-rw-r--r-- | src/host/layer23/src/misc/burst_process.c | 285 | ||||
-rw-r--r-- | src/host/layer23/src/misc/bursts_csd_9600_nt.dat | bin | 0 -> 158600 bytes | |||
-rw-r--r-- | src/host/layer23/src/misc/rlp.c | 167 | ||||
-rw-r--r-- | src/host/layer23/src/misc/rlp.h | 77 |
7 files changed, 553 insertions, 7 deletions
diff --git a/src/host/layer23/configure.ac b/src/host/layer23/configure.ac index 34dcbff6..24653539 100644 --- a/src/host/layer23/configure.ac +++ b/src/host/layer23/configure.ac @@ -43,6 +43,7 @@ PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.5.0) PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.10.0) PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm) PKG_CHECK_MODULES(LIBOSMOCODEC, libosmocodec) +PKG_CHECK_MODULES(LIBOSMOCODING, libosmocoding) AC_CHECK_LIB(gps, gps_waiting, LIBGPS_CFLAGS=" -D_HAVE_GPSD" LIBGPS_LIBS=" -lgps ",,) AC_SUBST([LIBGPS_CFLAGS]) AC_SUBST([LIBGPS_LIBS]) diff --git a/src/host/layer23/src/misc/Makefile.am b/src/host/layer23/src/misc/Makefile.am index 1daa39d0..86cda499 100644 --- a/src/host/layer23/src/misc/Makefile.am +++ b/src/host/layer23/src/misc/Makefile.am @@ -1,8 +1,8 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBGPS_CFLAGS) -LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBGPS_LIBS) +AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOCODING_CFLAGS) $(LIBGPS_CFLAGS) +LDADD = ../common/liblayer23.a $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOCODEC_LIBS) $(LIBOSMOCODING_LIBS) $(LIBGPS_LIBS) -bin_PROGRAMS = bcch_scan ccch_scan echo_test cell_log cbch_sniff +bin_PROGRAMS = bcch_scan ccch_scan echo_test cell_log cbch_sniff burst_process noinst_HEADERS = bcch_scan.h geo.h @@ -12,3 +12,5 @@ echo_test_SOURCES = ../common/main.c app_echo_test.c cell_log_LDADD = $(LDADD) -lm cell_log_SOURCES = ../common/main.c app_cell_log.c cell_log.c geo.c cbch_sniff_SOURCES = ../common/main.c app_cbch_sniff.c + +burst_process_SOURCES = burst_process.c rlp.c diff --git a/src/host/layer23/src/misc/app_ccch_scan.c b/src/host/layer23/src/misc/app_ccch_scan.c index 3091a4b0..a335c5a1 100644 --- a/src/host/layer23/src/misc/app_ccch_scan.c +++ b/src/host/layer23/src/misc/app_ccch_scan.c @@ -231,10 +231,14 @@ static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms) ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch, ia->chan_desc.h0.tsc); +#if 0 /* request L1 to go to dedicated mode on assigned channel */ rc = l1ctl_tx_dm_est_req_h0(ms, arfcn, ia->chan_desc.chan_nr, ia->chan_desc.h0.tsc, GSM48_CMODE_SIGN, 0); +#else + rc = l1ctl_tx_dm_est_req_h0(ms, 90, 0x0C, 0, GSM48_CMODE_SIGN, 0); +#endif } else { /* Hopping */ uint8_t maio, hsn, ma_len; @@ -271,7 +275,8 @@ static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms) /* Set state */ app_state.dch_state = DCH_WAIT_EST; - app_state.dch_nr = ia->chan_desc.chan_nr; + //app_state.dch_nr = ia->chan_desc.chan_nr; + app_state.dch_nr = 0x0C; app_state.dch_badcnt = 0; return rc; @@ -695,7 +700,7 @@ void layer3_rx_burst(struct osmocom_ms *ms, struct msgb *msg) app_state.fh = fopen(gen_filename(ms, bi), "wb"); } else { /* Abandon ? */ - do_rel = (app_state.dch_badcnt++) >= 4; + //do_rel = (app_state.dch_badcnt++) >= 4; } } } @@ -712,7 +717,7 @@ void layer3_rx_burst(struct osmocom_ms *ms, struct msgb *msg) app_state.dch_badcnt = 0; /* Release condition */ - do_rel = app_state.dch_badcnt >= 6; + //do_rel = app_state.dch_badcnt >= 6; } } @@ -778,9 +783,18 @@ static int signal_cb(unsigned int subsys, unsigned int signal, case S_L1CTL_RESET: ms = signal_data; layer3_app_reset(); +#if 0 + int rc; + rc = l1ctl_tx_dm_est_req_h0(ms, 90, 0x0C, 0, GSM48_CMODE_SIGN, 0); + OSMO_ASSERT(rc == 0); + app_state.ccch_mode = CCCH_MODE_COMBINED; + app_state.dch_state = DCH_WAIT_EST; + app_state.has_si1 = 1; +#else return l1ctl_tx_fbsb_req(ms, ms->test_arfcn, L1CTL_FBSB_F_FB01SB, 100, 0, CCCH_MODE_NONE, dbm2rxlev(-85)); +#endif break; } return 0; @@ -796,7 +810,7 @@ int l23_app_init(struct osmocom_ms *ms) static int l23_cfg_supported() { - return L23_OPT_TAP | L23_OPT_DBG; + return L23_OPT_ARFCN | L23_OPT_TAP | L23_OPT_DBG; } static int l23_getopt_options(struct option **options) diff --git a/src/host/layer23/src/misc/burst_process.c b/src/host/layer23/src/misc/burst_process.c new file mode 100644 index 00000000..96039fd4 --- /dev/null +++ b/src/host/layer23/src/misc/burst_process.c @@ -0,0 +1,285 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <stdint.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> + +#include <osmocom/core/bits.h> +#include <osmocom/core/conv.h> +#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/rsl.h> +#include <osmocom/gsm/gsm0503.h> +#include <l1ctl_proto.h> + +#include "rlp.h" + +/* print a map of the de-interleaver to stdout */ +static void deinterlieve_map(void) +{ + int j, k, B; + int max_ib = 0; + + for (k = 0; k < 456; k++) { + /* upper bound for B: 4*n + 18 + 4 = 4*n + 22 */ + B = /* B0 + 4n + */ (k % 19) + (k / 114); + /* upper bound for j: 18 + 19*5 = 113 */ + j = (k % 19) + 19*(k % 6); + /* upper iB index: 4*n+23*114-1 */ + //cB[k] = iB[B * 114 + j]; + int ib = B * 114 + j; + printf("cB[%u] = iB[%u]\n", k, ib); + if (ib > max_ib) + max_ib = ib; + } + printf("max_ib=%u\n", max_ib); +} + + +/*********************************************************************** + * L2RCOP (TS 27.002) + ***********************************************************************/ + +static int decode_l2rcop(FILE *f, const uint8_t *data, size_t data_len) +{ + size_t i = 0; + + while (i < data_len) { + uint8_t status = data[i]; + uint8_t flags = status >> 5; + uint8_t addr = status & 0x1f; + + if (flags) + fprintf(f, "[%c%c%c] ", flags & 4 ? 'A' : 'a', + flags & 2 ? 'B' : 'b', flags & 1 ? 'X' : 'x'); + + switch (addr) { + case 31: + /* Last status change, remainder of L2RCOP-PDU empty. */ + goto out; + case 30: + /* Last status change, remainder of L2RCOP-PDU full of characters. */ + for (int j = i+1; j < data_len; j++) + fputc(data[j], f); + goto out; + case 29: + /* Destructive break signal, remainder of L2RCOP-PDU empty. */ + fprintf(f, "[BREAK] "); + goto out; + case 28: + /* Destructive break acknowledge, remainder of L2RCOP-PDU empty. */ + fprintf(f, "[BREAK-ACK] "); + goto out; + case 27: + case 26: + case 25: + case 24: + case 0: + /* reserved */ + return -EINVAL; + default: + /* 1 .. 23 */ + for (int j = i+1; j <= i+addr; j++) + fputc(data[j], f); + i += 1 + addr; + break; + } + } + +out: + //fputc('\n', f); + + return 0; +} + + + +/*********************************************************************** + * frame handling (call RLP decoder, print message) + ***********************************************************************/ + +static void handle_rlp_frame(const uint8_t *data, size_t data_len) +{ + struct rlp_frame_decoded _rlp, *rlp = &_rlp; + int rc; + + rc = rlp_decode(rlp, 0, data, data_len); + if (rc < 0) + return; + + uint32_t fcs_calc_int = rlp_fcs_compute(data, data_len-3); + if (fcs_calc_int != rlp->fcs) + return; + + printf("fcs_calc=%06x", fcs_calc_int); + + switch (rlp->ftype) { + case RLP_FT_U: + printf("\tRLP: U %s C/R=%u P/F=%u FCS=%06x\n", get_value_string(rlp_ftype_u_vals, rlp->u_ftype), + rlp->c_r, rlp->p_f, rlp->fcs); + break; + case RLP_FT_S: + printf("\tRLP: S %s C/R=%u P/F=%u N(R)=%u FCS=%06x\n", get_value_string(rlp_ftype_s_vals, rlp->s_ftype), + rlp->c_r, rlp->p_f, rlp->n_r, rlp->fcs); + break; + case RLP_FT_IS: + printf("\tRLP: IS %s C/R=%u P/F=%u N(S)=%u N(R)=%u FCS=%06x %s\n", get_value_string(rlp_ftype_s_vals, rlp->s_ftype), + rlp->c_r, rlp->p_f, rlp->n_s, rlp->n_r, rlp->fcs, osmo_hexdump(rlp->info, rlp->info_len)); + decode_l2rcop(stderr, rlp->info, rlp->info_len); + break; + + } +} + +static void process_one_unmapped_burst(uint32_t fn, sbit_t *sbits) +{ + static sbit_t iB[22*114]; + static uint8_t burst22_nr = 0, burst4_nr = 0; + uint8_t fn26 = fn % 26; + static bool initialized = false; + +#if 1 + if (!initialized) { + if (fn26 != 2) + return; + initialized = true; + } +#endif + +#if 0 + if (fn26 == 0) + burst22_nr = 0; +#endif + + /* copy in the new burst */ + memcpy(&iB[(18 + burst4_nr) * 114], sbits, 114); + + burst4_nr++; + if (burst4_nr == 4) { + sbit_t cB[456]; + ubit_t decoded[244]; + pbit_t dec_bytes[30]; + gsm0503_tch_f96_deinterleave(cB, iB); + printf("%10u: generated 456 deinterleaved bits\n", fn26); + burst4_nr = 0; + osmo_conv_decode(&gsm0503_tch_f96, cB, decoded); + //printf("\tdec_bin: %s\n", osmo_ubit_dump(decoded, 240)); + osmo_ubit2pbit_ext(dec_bytes, 0, decoded, 0, 240, 1); + //printf("\tdec_hex: %s\n", osmo_hexdump(dec_bytes, sizeof(dec_bytes))); + handle_rlp_frame(dec_bytes, sizeof(dec_bytes)); + + /* move remainder of iB towards head */ + memmove(&iB[0], &iB[4*114], 18*114); + } + +#if 0 + burst22_nr = (burst22_nr) + 1 % 22; +#endif +} + +static struct l1ctl_burst_ind *read_one_burst(int fd) +{ + static struct l1ctl_burst_ind bi; + int rc; + + rc = read(fd, &bi, sizeof(bi)); + if (rc < fd) { + fprintf(stderr, "Error reading from burst_fd (%d < %zu): %s\n", rc, sizeof(bi), + strerror(errno)); + return NULL; + } + + return &bi; +} + +static int read_and_process_one_burst(int burst_fd) +{ + struct l1ctl_burst_ind *bi = read_one_burst(burst_fd); + uint8_t ch_type, ch_subch, ch_ts; + static bool started = false; + char dir; + + if (!bi) + return -1; + + + /* skip initial noise before real data is received */ + if (!started) { + if (bi->snr > 50) + started = true; + } + if (!started) + return 0; + + bi->frame_nr = ntohl(bi->frame_nr); + bi->band_arfcn = ntohs(bi->band_arfcn); + + rsl_dec_chan_nr(bi->chan_nr, &ch_type, &ch_subch, &ch_ts); + + if (bi->band_arfcn & ARFCN_UPLINK) + dir = 'U'; + else + dir = 'D'; + + /* skip uplink for now */ + if (dir == 'D') + return 0; + + /* skip SACCH/gap */ + if (bi->frame_nr % 26 == 12 || bi->frame_nr % 26 == 25) + return 0; + + printf("%10u %2u %4d %c % 4d %3u %u/%u\n", bi->frame_nr, bi->frame_nr % 26, + bi->band_arfcn&~ARFCN_FLAG_MASK, + dir, rxlev2dbm(bi->rx_level), bi->snr, ch_ts, ch_subch); + + /* we know our recording was always on TCH/F of TS4 */ + if (ch_type != RSL_CHAN_Bm_ACCHs || ch_subch != 0 || ch_ts != 4) + return 0; + + /* unpack the burst; it already is just the 114 (57+57) bits */ + ubit_t burst_ub[114]; + osmo_pbit2ubit(burst_ub, bi->bits, sizeof(burst_ub)); + + /* convert from hard to soft bits */ + sbit_t burst_sb[114]; + for (int i=0; i<114; i++) + burst_sb[i] = burst_ub[i] ? - (bi->snr >> 1) : (bi->snr >> 1); + + + process_one_unmapped_burst(bi->frame_nr, burst_sb); + + return 0; +} + + + + + + + +int main(int argc, char **argv) +{ + const char *fname = argv[1]; + int rc, burst_fd; + + //deinterlieve_map(); + + if (argc < 2) { + fprintf(stderr, "Please specify burst_ind data file\n"); + exit(2); + } + + burst_fd = open(fname, O_RDONLY); + if (burst_fd < 0) { + fprintf(stderr, "Error opening %s: %s\n", fname, strerror(errno)); + exit(1); + } + + while (1) { + rc = read_and_process_one_burst(burst_fd); + if (rc < 0) + break; + } +} diff --git a/src/host/layer23/src/misc/bursts_csd_9600_nt.dat b/src/host/layer23/src/misc/bursts_csd_9600_nt.dat Binary files differnew file mode 100644 index 00000000..2704e932 --- /dev/null +++ b/src/host/layer23/src/misc/bursts_csd_9600_nt.dat diff --git a/src/host/layer23/src/misc/rlp.c b/src/host/layer23/src/misc/rlp.c new file mode 100644 index 00000000..27892bbe --- /dev/null +++ b/src/host/layer23/src/misc/rlp.c @@ -0,0 +1,167 @@ +/* RLP (Radio Link Protocol) as per 3GPP TS 24.022 */ + +#include <stdint.h> +#include <stddef.h> +#include <string.h> +#include <errno.h> + +#include "rlp.h" + +/*! decode a RLP frame into its abstract representation. Doesn't check FCS correctness. + * \returns 0 in case of success; negative on error */ +int rlp_decode(struct rlp_frame_decoded *out, uint8_t version, const uint8_t *data, size_t data_len) +{ + uint8_t n_s, n_r; + + /* we only support 240 bit so far */ + if (data_len != 240/8) + return -EINVAL; + + /* we only support version 0+1 so far */ + if (version >= 2) + return -EINVAL; + + memset(out, 0, sizeof(*out)); + out->version = version; + + out->c_r = data[0] & 1; + n_s = (data[0] >> 3) | (data[1] & 1) << 5; + n_r = (data[1] >> 2); + //out->fcs = (data[240/8-3] << 16) | (data[240/8-2]) << 8 | (data[240/8-1] << 0); + out->fcs = (data[240/8-1] << 16) | (data[240/8-2]) << 8 | (data[240/8-3] << 0); + out->p_f = (data[1] >> 1) & 1; + + if (n_s == 0x3f) { + out->ftype = RLP_FT_U; + out->u_ftype = n_r & 0x1f; + } else if (n_s == 0x3e) { + out->ftype = RLP_FT_S; + out->s_ftype = (data[0] >> 1) & 3; + out->n_r = n_r; + } else { + out->ftype = RLP_FT_IS; + out->s_ftype = (data[0] >> 1) & 3; + out->n_s = n_s; + out->n_r = n_r; + memcpy(out->info, data+2, 240/8 - 5); + out->info_len = 240/8 - 5; + } + + return 0; +} + +/*! encode a RLP frame from its abstract representation. Generates FCS. + * \returns number of output bytes used; negative on error */ +int rlp_encode(uint8_t *out, size_t out_size, const struct rlp_frame_decoded *in) +{ + uint8_t out_len = 240/8; + uint8_t n_s, n_r, s_bits; + uint32_t fcs; + + /* we only support version 0+1 so far */ + if (in->version >= 2) + return -EINVAL; + + /* we only support 240 bit so far */ + if (in->info_len != 240/8 - 5) + return -EINVAL; + + if (out_size < out_len) + return -EINVAL; + + memset(out, 0, out_len); + + if (in->c_r) + out[0] |= 0x01; + if (in->p_f) + out[1] |= 0x02; + + switch (in->ftype) { + case RLP_FT_U: + n_s = 0x3f; + n_r = in->u_ftype; + s_bits = 0; + break; + case RLP_FT_S: + n_s = 0x3e; + n_r = in->n_r; + s_bits = in->s_ftype; + break; + case RLP_FT_IS: + n_s = in->n_s; + n_r = in->n_r; + s_bits = in->s_ftype; + memcpy(out+2, in->info, in->info_len); + break; + default: + return -EINVAL; + } + + /* patch N(S) into output data */ + out[0] |= (n_s & 0x1F) << 3; + out[1] |= (n_s & 0x20) >> 5; + + /* patch N(R) / M-bits into output data */ + out[1] |= (n_r & 0x3f) << 2; + + /* patch S-bits into output data */ + out[0] |= (s_bits & 3) << 1; + + /* compute FCS + add it to end of frame */ + fcs = rlp_fcs_compute(out, out_len -3); + out[out_len - 3] = (fcs >> 0) & 0xff; + out[out_len - 2] = (fcs >> 8) & 0xff; + out[out_len - 1] = (fcs >> 16) & 0xff; + + return out_len; +} + + +static const uint32_t rlp_fcs_table[256] = { + 0x00B29D2D, 0x00643A5B, 0x0044D87A, 0x00927F0C, 0x00051C38, 0x00D3BB4E, 0x00F3596F, 0x0025FE19, + 0x008694BC, 0x005033CA, 0x0070D1EB, 0x00A6769D, 0x003115A9, 0x00E7B2DF, 0x00C750FE, 0x0011F788, + 0x00DA8E0F, 0x000C2979, 0x002CCB58, 0x00FA6C2E, 0x006D0F1A, 0x00BBA86C, 0x009B4A4D, 0x004DED3B, + 0x00EE879E, 0x003820E8, 0x0018C2C9, 0x00CE65BF, 0x0059068B, 0x008FA1FD, 0x00AF43DC, 0x0079E4AA, + 0x0062BB69, 0x00B41C1F, 0x0094FE3E, 0x00425948, 0x00D53A7C, 0x00039D0A, 0x00237F2B, 0x00F5D85D, + 0x0056B2F8, 0x0080158E, 0x00A0F7AF, 0x007650D9, 0x00E133ED, 0x0037949B, 0x001776BA, 0x00C1D1CC, + 0x000AA84B, 0x00DC0F3D, 0x00FCED1C, 0x002A4A6A, 0x00BD295E, 0x006B8E28, 0x004B6C09, 0x009DCB7F, + 0x003EA1DA, 0x00E806AC, 0x00C8E48D, 0x001E43FB, 0x008920CF, 0x005F87B9, 0x007F6598, 0x00A9C2EE, + 0x0049DA1E, 0x009F7D68, 0x00BF9F49, 0x0069383F, 0x00FE5B0B, 0x0028FC7D, 0x00081E5C, 0x00DEB92A, + 0x007DD38F, 0x00AB74F9, 0x008B96D8, 0x005D31AE, 0x00CA529A, 0x001CF5EC, 0x003C17CD, 0x00EAB0BB, + 0x0021C93C, 0x00F76E4A, 0x00D78C6B, 0x00012B1D, 0x00964829, 0x0040EF5F, 0x00600D7E, 0x00B6AA08, + 0x0015C0AD, 0x00C367DB, 0x00E385FA, 0x0035228C, 0x00A241B8, 0x0074E6CE, 0x005404EF, 0x0082A399, + 0x0099FC5A, 0x004F5B2C, 0x006FB90D, 0x00B91E7B, 0x002E7D4F, 0x00F8DA39, 0x00D83818, 0x000E9F6E, + 0x00ADF5CB, 0x007B52BD, 0x005BB09C, 0x008D17EA, 0x001A74DE, 0x00CCD3A8, 0x00EC3189, 0x003A96FF, + 0x00F1EF78, 0x0027480E, 0x0007AA2F, 0x00D10D59, 0x00466E6D, 0x0090C91B, 0x00B02B3A, 0x00668C4C, + 0x00C5E6E9, 0x0013419F, 0x0033A3BE, 0x00E504C8, 0x007267FC, 0x00A4C08A, 0x008422AB, 0x005285DD, + 0x001F18F0, 0x00C9BF86, 0x00E95DA7, 0x003FFAD1, 0x00A899E5, 0x007E3E93, 0x005EDCB2, 0x00887BC4, + 0x002B1161, 0x00FDB617, 0x00DD5436, 0x000BF340, 0x009C9074, 0x004A3702, 0x006AD523, 0x00BC7255, + 0x00770BD2, 0x00A1ACA4, 0x00814E85, 0x0057E9F3, 0x00C08AC7, 0x00162DB1, 0x0036CF90, 0x00E068E6, + 0x00430243, 0x0095A535, 0x00B54714, 0x0063E062, 0x00F48356, 0x00222420, 0x0002C601, 0x00D46177, + 0x00CF3EB4, 0x001999C2, 0x00397BE3, 0x00EFDC95, 0x0078BFA1, 0x00AE18D7, 0x008EFAF6, 0x00585D80, + 0x00FB3725, 0x002D9053, 0x000D7272, 0x00DBD504, 0x004CB630, 0x009A1146, 0x00BAF367, 0x006C5411, + 0x00A72D96, 0x00718AE0, 0x005168C1, 0x0087CFB7, 0x0010AC83, 0x00C60BF5, 0x00E6E9D4, 0x00304EA2, + 0x00932407, 0x00458371, 0x00656150, 0x00B3C626, 0x0024A512, 0x00F20264, 0x00D2E045, 0x00044733, + 0x00E45FC3, 0x0032F8B5, 0x00121A94, 0x00C4BDE2, 0x0053DED6, 0x008579A0, 0x00A59B81, 0x00733CF7, + 0x00D05652, 0x0006F124, 0x00261305, 0x00F0B473, 0x0067D747, 0x00B17031, 0x00919210, 0x00473566, + 0x008C4CE1, 0x005AEB97, 0x007A09B6, 0x00ACAEC0, 0x003BCDF4, 0x00ED6A82, 0x00CD88A3, 0x001B2FD5, + 0x00B84570, 0x006EE206, 0x004E0027, 0x0098A751, 0x000FC465, 0x00D96313, 0x00F98132, 0x002F2644, + 0x00347987, 0x00E2DEF1, 0x00C23CD0, 0x00149BA6, 0x0083F892, 0x00555FE4, 0x0075BDC5, 0x00A31AB3, + 0x00007016, 0x00D6D760, 0x00F63541, 0x00209237, 0x00B7F103, 0x00615675, 0x0041B454, 0x00971322, + 0x005C6AA5, 0x008ACDD3, 0x00AA2FF2, 0x007C8884, 0x00EBEBB0, 0x003D4CC6, 0x001DAEE7, 0x00CB0991, + 0x00686334, 0x00BEC442, 0x009E2663, 0x00488115, 0x00DFE221, 0x00094557, 0x0029A776, 0x00FF0000 +}; + +/*! compute RLP FCS according to 3GPP TS 24.022 Section 4.4 */ +uint32_t rlp_fcs_compute(const uint8_t *in, size_t in_len) +{ + uint32_t divider = 0; + size_t i; + + for (i = 0; i < in_len; i++) { + uint8_t input = in[i] ^ (divider & 0xff); + divider = (divider >> 8) ^ rlp_fcs_table[input]; + } + + return divider; +} diff --git a/src/host/layer23/src/misc/rlp.h b/src/host/layer23/src/misc/rlp.h new file mode 100644 index 00000000..4d70d7b6 --- /dev/null +++ b/src/host/layer23/src/misc/rlp.h @@ -0,0 +1,77 @@ +#pragma once +#include <stdint.h> +#include <stdbool.h> +#include <osmocom/core/utils.h> + +/* 3GPP TS 24.002 Section 5.2.1 */ +enum rlp_ftype { + RLP_FT_U, + RLP_FT_S, + RLP_FT_IS, +}; + +static const struct value_string rlp_ftype_vals[] = { + { RLP_FT_U, "U" }, + { RLP_FT_S, "S" }, + { RLP_FT_IS, "IS" }, + { 0, NULL } +}; + +/* 3GPP TS 24.002 Section 5.2.1 */ +enum rlp_u_ftype { + RLP_U_FT_SABM = 0x07, + RLP_U_FT_UA = 0x0c, + RLP_U_FT_DISC = 0x08, + RLP_U_FT_DM = 0x03, + RLP_U_FT_NULL = 0x0f, + RLP_U_FT_UI = 0x00, + RLP_U_FT_XID = 0x17, + RLP_U_FT_TEST = 0x1c, + RLP_U_FT_REMAP = 0x11, +}; +static const struct value_string rlp_ftype_u_vals[] = { + { RLP_U_FT_SABM, "SABM" }, + { RLP_U_FT_UA, "UA" }, + { RLP_U_FT_DISC, "DISC" }, + { RLP_U_FT_DM, "DM" }, + { RLP_U_FT_NULL, "NULL" }, + { RLP_U_FT_UI, "UI" }, + { RLP_U_FT_XID, "XID" }, + { RLP_U_FT_TEST, "TEST" }, + { RLP_U_FT_REMAP, "REMAP" }, + { 0, NULL } +}; + +/* 3GPP TS 24.002 Section 5.2.1 */ +enum rlp_s_ftype { + RLP_S_FT_RR = 0, + RLP_S_FT_REJ = 2, + RLP_S_FT_RNR = 1, + RLP_S_FT_SREJ = 3, +}; +static const struct value_string rlp_ftype_s_vals[] = { + { RLP_S_FT_RR, "RR" }, + { RLP_S_FT_REJ, "REJ" }, + { RLP_S_FT_RNR, "RNR" }, + { RLP_S_FT_SREJ, "SREJ" }, + { 0, NULL } +}; + +struct rlp_frame_decoded { + uint8_t version; + enum rlp_ftype ftype; + enum rlp_u_ftype u_ftype; + enum rlp_s_ftype s_ftype; + bool c_r; + bool p_f; + uint8_t s_bits; + uint16_t n_s; + uint16_t n_r; + uint32_t fcs; + uint8_t info[536/8]; + uint16_t info_len; +}; + + +int rlp_decode(struct rlp_frame_decoded *out, uint8_t version, const uint8_t *data, size_t data_len); +uint32_t rlp_fcs_compute(const uint8_t *in, size_t in_len); |