fixeria has submitted this change. ( https://gerrit.osmocom.org/c/libosmo-gprs/+/29402 )
Change subject: llc: implement LLC PDU codec based on code from osmo-sgsn.git ......................................................................
llc: implement LLC PDU codec based on code from osmo-sgsn.git
osmo-sgsn.git 13ccbc1e6120fe78f6f9f950d7242090920ca41b
Change-Id: I61d7e2e6d0a8f2cdfc2113e637e447dc428cc70d --- M configure.ac M include/osmocom/gprs/llc/llc.h M src/llc/llc_pdu.c M tests/Makefile.am A tests/llc_pdu_codec/Makefile.am A tests/llc_pdu_codec/pdu_codec_test.c A tests/llc_pdu_codec/pdu_codec_test.err A tests/llc_pdu_codec/pdu_codec_test.ok M tests/testsuite.at 9 files changed, 626 insertions(+), 0 deletions(-)
Approvals: fixeria: Looks good to me, approved; Verified laforge: Looks good to me, but someone else must approve pespin: Looks good to me, but someone else must approve
diff --git a/configure.ac b/configure.ac index 6e9bcb4..b9b2d81 100644 --- a/configure.ac +++ b/configure.ac @@ -86,6 +86,7 @@ src/llc/Makefile src/rlcmac/Makefile tests/Makefile + tests/llc_pdu_codec/Makefile tests/ts_44_018/Makefile tests/ts_44_060/Makefile Makefile diff --git a/include/osmocom/gprs/llc/llc.h b/include/osmocom/gprs/llc/llc.h index 8c5134b..b035acc 100644 --- a/include/osmocom/gprs/llc/llc.h +++ b/include/osmocom/gprs/llc/llc.h @@ -130,4 +130,36 @@ uint16_t kU; };
+#define OSMO_GPRS_LLC_PDU_F_CMD_RSP (1 << 0) /* 6.2.2 Commmand/Response bit (C/R) */ +#define OSMO_GPRS_LLC_PDU_F_FOLL_FIN (1 << 1) /* 6.3.5.1 Poll/Final bit (P/F) */ +#define OSMO_GPRS_LLC_PDU_F_ACK_REQ (1 << 2) /* 6.3.5.2 Acknowledgement request bit (A) */ +#define OSMO_GPRS_LLC_PDU_F_MAC_PRES (1 << 3) /* 6.3.5.2a Integrity Protection bit (IP) */ +#define OSMO_GPRS_LLC_PDU_F_ENC_MODE (1 << 4) /* 6.3.5.5.1 Encryption mode bit (E) */ +#define OSMO_GPRS_LLC_PDU_F_PROT_MODE (1 << 5) /* 6.3.5.5.2 Protected Mode bit (PM) */ + +struct osmo_gprs_llc_pdu_decoded { + enum osmo_gprs_llc_sapi sapi; + enum osmo_gprs_llc_frame_fmt fmt; + enum osmo_gprs_llc_frame_func func; + uint32_t flags; /* see OSMO_GPRS_LLC_PDU_F_* above */ + uint32_t seq_rx; /* 6.3.5.4.5 Receive sequence number N(R) */ + uint32_t seq_tx; /* 6.3.5.4.3 Send sequence number N(S) */ + uint32_t fcs; /* 5.5 Frame Check Sequence (FCS) field */ + uint32_t mac; /* 5.5a Message Authentication Code (MAC) field */ + struct { + uint8_t len; /* Indicates the number of octets in the bitmap */ + uint8_t r[32]; /* The R(n) bitmap */ + } sack; /* 6.3.5.4.6 SACK bitmap R(n) */ + size_t data_len; + const uint8_t *data; +}; + +void osmo_gprs_llc_pdu_hdr_dump_buf(char *buf, size_t buf_size, + const struct osmo_gprs_llc_pdu_decoded *pdu); +const char *osmo_gprs_llc_pdu_hdr_dump(const struct osmo_gprs_llc_pdu_decoded *pdu); + +int osmo_gprs_llc_pdu_decode(struct osmo_gprs_llc_pdu_decoded *pdu, + const uint8_t *data, size_t data_len); +int osmo_gprs_llc_pdu_encode(struct msgb *msg, const struct osmo_gprs_llc_pdu_decoded *pdu); + uint32_t osmo_gprs_llc_fcs(const uint8_t *data, size_t len); diff --git a/src/llc/llc_pdu.c b/src/llc/llc_pdu.c index 0a936a8..8f5353e 100644 --- a/src/llc/llc_pdu.c +++ b/src/llc/llc_pdu.c @@ -20,10 +20,22 @@ * */
+#include <stdint.h> +#include <errno.h> + +#include <osmocom/core/msgb.h> #include <osmocom/core/utils.h> +#include <osmocom/core/logging.h>
#include <osmocom/gprs/llc/llc.h>
+/* TODO: make logging category configurable */ +#define DLLC DLGLOBAL + +#define UI_HDR_LEN 3 +#define N202 4 +#define CRC24_LENGTH 3 + const struct value_string osmo_gprs_llc_frame_fmt_names[] = { { OSMO_GPRS_LLC_FMT_I, "I" }, { OSMO_GPRS_LLC_FMT_S, "U" }, @@ -64,3 +76,410 @@
return fcs_calc; } + +void osmo_gprs_llc_pdu_hdr_dump_buf(char *buf, size_t buf_size, + const struct osmo_gprs_llc_pdu_decoded *pdu) +{ + struct osmo_strbuf sb = { .buf = buf, .len = buf_size }; + + OSMO_STRBUF_PRINTF(sb, "SAPI=%u, %s func=%s C/R=%c", + pdu->sapi, /* TODO: print value_string */ + osmo_gprs_llc_frame_fmt_name(pdu->fmt), + osmo_gprs_llc_frame_func_name(pdu->func), + pdu->flags & OSMO_GPRS_LLC_PDU_F_CMD_RSP ? '1' : '0'); + + switch (pdu->fmt) { + case OSMO_GPRS_LLC_FMT_I: + OSMO_STRBUF_PRINTF(sb, " A=%c N(R)=%u N(S)=%u", + pdu->flags & OSMO_GPRS_LLC_PDU_F_ACK_REQ ? '1' : '0', + pdu->seq_rx, pdu->seq_tx); + break; + case OSMO_GPRS_LLC_FMT_S: + OSMO_STRBUF_PRINTF(sb, " A=%c N(R)=%u", + pdu->flags & OSMO_GPRS_LLC_PDU_F_ACK_REQ ? '1' : '0', + pdu->seq_rx); + break; + case OSMO_GPRS_LLC_FMT_UI: + OSMO_STRBUF_PRINTF(sb, " PM=%c E=%c IP=%c N(U)=%u", + pdu->flags & OSMO_GPRS_LLC_PDU_F_PROT_MODE ? '1' : '0', + pdu->flags & OSMO_GPRS_LLC_PDU_F_ENC_MODE ? '1' : '0', + pdu->flags & OSMO_GPRS_LLC_PDU_F_MAC_PRES ? '1' : '0', + pdu->seq_tx); + break; + case OSMO_GPRS_LLC_FMT_U: + OSMO_STRBUF_PRINTF(sb, " P/F=%c", + pdu->flags & OSMO_GPRS_LLC_PDU_F_FOLL_FIN ? '1' : '0'); + break; + } + + if (pdu->flags & OSMO_GPRS_LLC_PDU_F_MAC_PRES) + OSMO_STRBUF_PRINTF(sb, " MAC=%08x", pdu->mac); + OSMO_STRBUF_PRINTF(sb, " FCS=%06x", pdu->fcs); +} + +const char *osmo_gprs_llc_pdu_hdr_dump(const struct osmo_gprs_llc_pdu_decoded *pdu) +{ + static __thread char buf[256]; + osmo_gprs_llc_pdu_hdr_dump_buf(&buf[0], sizeof(buf), pdu); + return buf; +} + +/* 6.4.1 Unnumbered (U) frames */ +#define GPRS_LLC_U_NULL_CMD 0x00 +#define GPRS_LLC_U_DM_RESP 0x01 +#define GPRS_LLC_U_DISC_CMD 0x04 +#define GPRS_LLC_U_UA_RESP 0x06 +#define GPRS_LLC_U_SABM_CMD 0x07 +#define GPRS_LLC_U_FRMR_RESP 0x08 +#define GPRS_LLC_U_XID 0x0b + +int osmo_gprs_llc_pdu_encode(struct msgb *msg, const struct osmo_gprs_llc_pdu_decoded *pdu) +{ + uint8_t *addr = msgb_put(msg, 1); + uint8_t *ctrl = NULL; + size_t crc_len; + uint32_t fcs; + + /* 6.2.3 Service Access Point Identifier (SAPI) */ + addr[0] = pdu->sapi & 0x0f; + + /* 6.2.2 Commmand/Response bit (C/R) */ + if (pdu->flags & OSMO_GPRS_LLC_PDU_F_CMD_RSP) + addr[0] |= (1 << 6); + + switch (pdu->fmt) { + case OSMO_GPRS_LLC_FMT_I: + ctrl = msgb_put(msg, 3); + + ctrl[0] = 0x00; /* 0xxxxxxx */ + ctrl[1] = ctrl[2] = 0x00; + + if (pdu->flags & OSMO_GPRS_LLC_PDU_F_ACK_REQ) + ctrl[0] |= (1 << 6); + + ctrl[0] |= (pdu->seq_tx >> 4) & 0x1f; + ctrl[1] |= (pdu->seq_tx & 0x0f) << 4; + + ctrl[1] |= (pdu->seq_rx >> 6) & 0x07; + ctrl[2] |= (pdu->seq_rx & 0x3f) << 2; + + ctrl[2] |= (pdu->func - OSMO_GPRS_LLC_FUNC_RR) & 0x03; + + if (pdu->func == OSMO_GPRS_LLC_FUNC_SACK) { + if (pdu->sack.len == 0) + return -EINVAL; + msgb_put_u8(msg, pdu->sack.len - 1); + memcpy(msgb_put(msg, pdu->sack.len), + &pdu->sack.r[0], pdu->sack.len); + } + break; + case OSMO_GPRS_LLC_FMT_S: + ctrl = msgb_put(msg, 2); + + ctrl[0] = 0x80; /* 10xxxxxx */ + ctrl[1] = 0x00; + + if (pdu->flags & OSMO_GPRS_LLC_PDU_F_ACK_REQ) + ctrl[1] |= 0x20; + + ctrl[0] |= (pdu->seq_rx >> 6) & 0x07; + ctrl[1] |= (pdu->seq_rx & 0x3f) << 2; + + ctrl[1] |= (pdu->func - OSMO_GPRS_LLC_FUNC_RR) & 0x03; + + if (pdu->func == OSMO_GPRS_LLC_FUNC_SACK) { + if (pdu->sack.len == 0) + return -EINVAL; + memcpy(msgb_put(msg, pdu->sack.len), + &pdu->sack.r[0], pdu->sack.len); + } + break; + case OSMO_GPRS_LLC_FMT_UI: + ctrl = msgb_put(msg, 2); + + ctrl[0] = 0xc0; /* 110xxxxx */ + ctrl[1] = 0x00; + + if (pdu->flags & OSMO_GPRS_LLC_PDU_F_MAC_PRES) + ctrl[0] |= (1 << 4); + + ctrl[0] |= (pdu->seq_tx >> 6) & 0x07; + ctrl[1] |= (pdu->seq_tx & 0x3f) << 2; + + if (pdu->flags & OSMO_GPRS_LLC_PDU_F_ENC_MODE) + ctrl[1] |= (1 << 1); + if (pdu->flags & OSMO_GPRS_LLC_PDU_F_PROT_MODE) + ctrl[1] |= (1 << 0); + break; + case OSMO_GPRS_LLC_FMT_U: + ctrl = msgb_put(msg, 1); + + ctrl[0] = 0xe0; /* 111xxxxx */ + + if (pdu->flags & OSMO_GPRS_LLC_PDU_F_FOLL_FIN) + ctrl[0] |= (1 << 4); + + switch (pdu->func) { + case OSMO_GPRS_LLC_FUNC_NULL: + ctrl[0] |= GPRS_LLC_U_NULL_CMD; + break; + case OSMO_GPRS_LLC_FUNC_DM: + ctrl[0] |= GPRS_LLC_U_DM_RESP; + break; + case OSMO_GPRS_LLC_FUNC_DISC: + ctrl[0] |= GPRS_LLC_U_DISC_CMD; + break; + case OSMO_GPRS_LLC_FUNC_UA: + ctrl[0] |= GPRS_LLC_U_UA_RESP; + break; + case OSMO_GPRS_LLC_FUNC_SABM: + ctrl[0] |= GPRS_LLC_U_SABM_CMD; + break; + case OSMO_GPRS_LLC_FUNC_FRMR: + ctrl[0] |= GPRS_LLC_U_FRMR_RESP; + break; + case OSMO_GPRS_LLC_FUNC_XID: + ctrl[0] |= GPRS_LLC_U_XID; + break; + default: + LOGP(DLLC, LOGL_ERROR, + "Unknown UI func=0x%02x\n", pdu->func); + return -EINVAL; + } + break; + } + + if (pdu->data_len > 0) { + uint8_t *data = msgb_put(msg, pdu->data_len); + memcpy(data, pdu->data, pdu->data_len); + } + + /* 5.5a Message Authentication Code (MAC) field */ + if (pdu->flags & OSMO_GPRS_LLC_PDU_F_MAC_PRES) { + /* TODO: calculate MAC (see 3GPP TS 43.020) */ + LOGP(DLLC, LOGL_ERROR, + "Message Authentication Code (MAC) is not implemented\n"); + return -ENOTSUP; + } + + /* 5.5 Frame Check Sequence (FCS) field */ + crc_len = msg->tail - addr; + if (~pdu->flags & OSMO_GPRS_LLC_PDU_F_PROT_MODE) + crc_len = OSMO_MIN(crc_len, UI_HDR_LEN + N202); + fcs = osmo_gprs_llc_fcs(addr, crc_len); + + msgb_put_u8(msg, fcs & 0xff); + msgb_put_u8(msg, (fcs >> 8) & 0xff); + msgb_put_u8(msg, (fcs >> 16) & 0xff); + + return 0; +} + +int osmo_gprs_llc_pdu_decode(struct osmo_gprs_llc_pdu_decoded *pdu, + const uint8_t *data, size_t data_len) +{ + const uint8_t *addr = &data[0]; + const uint8_t *ctrl = &data[1]; + +#define check_len(len, text) \ + do { \ + if (data_len < (len)) { \ + LOGP(DLLC, LOGL_ERROR, "Failed to parse LLC PDU: %s\n", text); \ + return -EINVAL; \ + } \ + } while (0) + + /* 5.5 Frame Check Sequence (FCS) field */ + check_len(CRC24_LENGTH, "missing Frame Check Sequence (FCS) field"); + pdu->fcs = data[data_len - 3]; + pdu->fcs |= data[data_len - 2] << 8; + pdu->fcs |= data[data_len - 1] << 16; + data_len -= CRC24_LENGTH; + + /* 6.2.0 Address field format */ + check_len(1, "missing Address field"); + data_len -= 1; + + /* Initial assumption: FCS covers hdr + all inf fields */ + pdu->flags |= OSMO_GPRS_LLC_PDU_F_PROT_MODE; + + /* 6.2.1 Protocol Discriminator bit (PD): shall be 0 */ + if (*addr & 0x80) { + LOGP(DLLC, LOGL_ERROR, "Protocol Discriminator shall be 0\n"); + return -EINVAL; + } + + /* 6.2.2 Commmand/Response bit (C/R) */ + if (*addr & 0x40) + pdu->flags |= OSMO_GPRS_LLC_PDU_F_CMD_RSP; + + /* 6.2.3 Service Access Point Identifier (SAPI) */ + pdu->sapi = *addr & 0x0f; + + /* Check for reserved SAPI */ + switch (*addr & 0x0f) { + case 0x00: + case 0x04: + case 0x06: + case 0x0a: + case 0x0c: + case 0x0d: + case 0x0f: + LOGP(DLLC, LOGL_ERROR, "Unknown SAPI=%u\n", pdu->sapi); + return -EINVAL; + } + + /* U format has the shortest control field length=1 */ + check_len(1, "missing Control field"); + + /* 6.3.0 Control field formats */ + if ((ctrl[0] & 0x80) == 0) { + /* 6.3.1 Information transfer format - I */ + pdu->fmt = OSMO_GPRS_LLC_FMT_I; + + check_len(3, "I format Control field is too short"); + data_len -= 3; + + pdu->data = ctrl + 3; + /* pdu->data_len is set below */ + + if (ctrl[0] & 0x40) + pdu->flags |= OSMO_GPRS_LLC_PDU_F_ACK_REQ; + + pdu->seq_tx = (ctrl[0] & 0x1f) << 4; + pdu->seq_tx |= (ctrl[1] >> 4); + + pdu->seq_rx = (ctrl[1] & 0x7) << 6; + pdu->seq_rx |= (ctrl[2] >> 2); + + switch (ctrl[2] & 0x03) { + case 0: + pdu->func = OSMO_GPRS_LLC_FUNC_RR; + break; + case 1: + pdu->func = OSMO_GPRS_LLC_FUNC_ACK; + break; + case 2: + pdu->func = OSMO_GPRS_LLC_FUNC_RNR; + break; + case 3: + pdu->func = OSMO_GPRS_LLC_FUNC_SACK; + check_len(1, "I func=SACK is too short"); + pdu->sack.len = (ctrl[3] & 0x1f) + 1; /* 1 .. 32 */ + /* The R(n) bitmask takes len=(K + 1) octets */ + check_len(pdu->sack.len, "I func=SACK is too short"); + memcpy(&pdu->sack.r[0], ctrl + 4, pdu->sack.len); + pdu->data += 1 + pdu->sack.len; + data_len -= 1 + pdu->sack.len; + break; + } + pdu->data_len = data_len; + } else if ((ctrl[0] & 0xc0) == 0x80) { + /* 6.3.2 Supervisory format - S */ + pdu->fmt = OSMO_GPRS_LLC_FMT_S; + + check_len(2, "S format Control field is too short"); + data_len -= 2; + + pdu->data = NULL; + pdu->data_len = 0; + + if (ctrl[0] & 0x20) + pdu->flags |= OSMO_GPRS_LLC_PDU_F_ACK_REQ; + + pdu->seq_rx = (ctrl[0] & 0x7) << 6; + pdu->seq_rx |= (ctrl[1] >> 2); + + switch (ctrl[1] & 0x03) { + case 0: + pdu->func = OSMO_GPRS_LLC_FUNC_RR; + break; + case 1: + pdu->func = OSMO_GPRS_LLC_FUNC_ACK; + break; + case 2: + pdu->func = OSMO_GPRS_LLC_FUNC_RNR; + break; + case 3: + pdu->func = OSMO_GPRS_LLC_FUNC_SACK; + /* The R(n) bitmask takes all remaining octets */ + check_len(1, "S func=SACK is too short"); + pdu->sack.len = data_len; /* 1 .. 32 */ + memcpy(&pdu->sack.r[0], ctrl + 2, pdu->sack.len); + break; + } + } else if ((ctrl[0] & 0xe0) == 0xc0) { + /* 6.3.3 Unconfirmed Information format - UI */ + pdu->fmt = OSMO_GPRS_LLC_FMT_UI; + pdu->func = OSMO_GPRS_LLC_FUNC_UI; + + check_len(2, "UI format Control field is too short"); + data_len -= 2; + + pdu->data = ctrl + 2; + pdu->data_len = data_len; + + pdu->seq_tx = (ctrl[0] & 0x7) << 6; + pdu->seq_tx |= (ctrl[1] >> 2); + + if (ctrl[0] & 0x10) { + check_len(sizeof(pdu->mac), "missing MAC field"); + pdu->data_len -= sizeof(pdu->mac); + data_len -= sizeof(pdu->mac); + + pdu->mac = osmo_load32le(&pdu->data[data_len]); + pdu->flags |= OSMO_GPRS_LLC_PDU_F_MAC_PRES; + } + + if (ctrl[1] & 0x02) + pdu->flags |= OSMO_GPRS_LLC_PDU_F_ENC_MODE; + + if (~ctrl[1] & 0x01) /* FCS covers hdr + N202 octets */ + pdu->flags &= ~OSMO_GPRS_LLC_PDU_F_PROT_MODE; + } else { + /* 6.3.4 Unnumbered format - U */ + pdu->fmt = OSMO_GPRS_LLC_FMT_U; + + check_len(1, "U format Control field is too short"); + data_len -= 1; + + pdu->data = NULL; + pdu->data_len = 0; + + if (ctrl[0] & 0x10) + pdu->flags |= OSMO_GPRS_LLC_PDU_F_FOLL_FIN; + + switch (ctrl[0] & 0x0f) { + case GPRS_LLC_U_NULL_CMD: + pdu->func = OSMO_GPRS_LLC_FUNC_NULL; + break; + case GPRS_LLC_U_DM_RESP: + pdu->func = OSMO_GPRS_LLC_FUNC_DM; + break; + case GPRS_LLC_U_DISC_CMD: + pdu->func = OSMO_GPRS_LLC_FUNC_DISC; + break; + case GPRS_LLC_U_UA_RESP: + pdu->func = OSMO_GPRS_LLC_FUNC_UA; + break; + case GPRS_LLC_U_SABM_CMD: + pdu->func = OSMO_GPRS_LLC_FUNC_SABM; + break; + case GPRS_LLC_U_FRMR_RESP: + pdu->func = OSMO_GPRS_LLC_FUNC_FRMR; + break; + case GPRS_LLC_U_XID: + pdu->func = OSMO_GPRS_LLC_FUNC_XID; + pdu->data = ctrl + 1; + pdu->data_len = data_len; + break; + default: + LOGP(DLLC, LOGL_ERROR, "Unknown U func=0x%02x\n", ctrl[0] & 0x0f); + return -ENOTSUP; + } + } + +#undef check_len + + return 0; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index f4b4dbf..15660c9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,5 @@ SUBDIRS = \ + llc_pdu_codec \ ts_44_018 \ ts_44_060 \ $(NULL) diff --git a/tests/llc_pdu_codec/Makefile.am b/tests/llc_pdu_codec/Makefile.am new file mode 100644 index 0000000..0079964 --- /dev/null +++ b/tests/llc_pdu_codec/Makefile.am @@ -0,0 +1,24 @@ +AM_CFLAGS = \ + -Wall \ + $(LIBOSMOCORE_CFLAGS) \ + -I$(top_srcdir)/include/ \ + $(NULL) + +AM_LDFLAGS = \ + -no-install \ + $(NULL) + +check_PROGRAMS = \ + pdu_codec_test \ + $(NULL) + +EXTRA_DIST = \ + pdu_codec_test.ok \ + pdu_codec_test.err \ + $(NULL) + +pdu_codec_test_SOURCES = pdu_codec_test.c +pdu_codec_test_LDADD = \ + $(LIBOSMOCORE_LIBS) \ + $(top_builddir)/src/llc/libosmo-gprs-llc.la \ + $(NULL) diff --git a/tests/llc_pdu_codec/pdu_codec_test.c b/tests/llc_pdu_codec/pdu_codec_test.c new file mode 100644 index 0000000..ed4e8bd --- /dev/null +++ b/tests/llc_pdu_codec/pdu_codec_test.c @@ -0,0 +1,102 @@ +/* LLC PDU codec tests + * + * (C) 2022 by sysmocom - s.f.m.c. GmbH info@sysmocom.de + * Author: Vadim Yanitskiy vyanitskiy@sysmocom.de + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdint.h> +#include <stdio.h> + +#include <osmocom/core/application.h> +#include <osmocom/core/logging.h> +#include <osmocom/core/utils.h> +#include <osmocom/core/msgb.h> + +#include <osmocom/gprs/llc/llc.h> + +static void *tall_ctx = NULL; + +static void test_pdu_dec_enc(void) +{ + static const char *testData[] = { + /* SAPI=1 (GMM), UI func=UI C/R=0 PM=0 N(U)=4 */ + "01c010080509afe633", + /* SAPI=1 (GMM), UI func=UI C/R=1 PM=1 N(U)=0 */ + "41c001081502de8e9a", + /* SAPI=1 (GMM), U func=NULL C/R=0 P/F=0 */ + "01e01ca2b3", + /* SAPI=3 (SNDCP3), U func=XID C/R=1 P/F=1 */ + "43fb01001601f41a05df8c7c4e", + /* SAPI=3 (SNDCP3), U func=XID C/R=1 P/F=1 */ + "03fb1604d216f984", + }; + + struct msgb *msg = msgb_alloc(1024, "LLC-PDU"); + OSMO_ASSERT(msg != NULL); + + for (unsigned int i = 0; i < ARRAY_SIZE(testData); i++) { + struct osmo_gprs_llc_pdu_decoded hdr = { 0 }; + uint8_t pdu[256]; + size_t pdu_len; + int rc; + + printf("%s(): decoding testData[%u] = %s\n", __func__, i, testData[i]); + + rc = osmo_hexparse(testData[i], &pdu[0], sizeof(pdu)); + pdu_len = strlen(testData[i]) / 2; + OSMO_ASSERT(rc == pdu_len); + + rc = osmo_gprs_llc_pdu_decode(&hdr, &pdu[0], pdu_len); + printf(" osmo_gprs_llc_pdu_decode() returns %d\n", rc); + printf(" osmo_gprs_llc_pdu_hdr_dump(): %s\n", osmo_gprs_llc_pdu_hdr_dump(&hdr)); + if (hdr.data_len > 0) { + printf(" hdr.data[] (len=%zu): %s\n", hdr.data_len, + osmo_hexdump_nospc(hdr.data, hdr.data_len)); + } + + printf("%s(): encoding decoded testData[%u]\n", __func__, i); + + msgb_reset(msg); + rc = osmo_gprs_llc_pdu_encode(msg, &hdr); + printf(" osmo_gprs_llc_pdu_encode() returns %d\n", rc); + printf(" osmo_gprs_llc_pdu_encode(): %s\n", osmo_hexdump_nospc(msg->data, msg->len)); + printf(" memcmp() returns %d\n", memcmp(&pdu, msg->data, pdu_len)); + } + + msgb_free(msg); + printf("\n"); +} + +static const struct log_info_cat test_log_categories[] = { }; +static const struct log_info test_log_info = { + .cat = test_log_categories, + .num_cat = ARRAY_SIZE(test_log_categories), +}; + +int main(int argc, char *argv[]) +{ + tall_ctx = talloc_named_const(NULL, 1, __FILE__); + + osmo_init_logging2(tall_ctx, &test_log_info); + log_parse_category_mask(osmo_stderr_target, "DLGLOBAL,1:"); + + log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE); + log_set_print_category_hex(osmo_stderr_target, 0); + log_set_print_category(osmo_stderr_target, 1); + log_set_print_level(osmo_stderr_target, 1); + log_set_use_color(osmo_stderr_target, 0); + + test_pdu_dec_enc(); + + talloc_free(tall_ctx); +} diff --git a/tests/llc_pdu_codec/pdu_codec_test.err b/tests/llc_pdu_codec/pdu_codec_test.err new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/llc_pdu_codec/pdu_codec_test.err diff --git a/tests/llc_pdu_codec/pdu_codec_test.ok b/tests/llc_pdu_codec/pdu_codec_test.ok new file mode 100644 index 0000000..5eb5045 --- /dev/null +++ b/tests/llc_pdu_codec/pdu_codec_test.ok @@ -0,0 +1,40 @@ +test_pdu_dec_enc(): decoding testData[0] = 01c010080509afe633 + osmo_gprs_llc_pdu_decode() returns 0 + osmo_gprs_llc_pdu_hdr_dump(): SAPI=1, UI func=UI C/R=0 PM=0 E=0 IP=0 N(U)=4 FCS=33e6af + hdr.data[] (len=3): 080509 +test_pdu_dec_enc(): encoding decoded testData[0] + osmo_gprs_llc_pdu_encode() returns 0 + osmo_gprs_llc_pdu_encode(): 01c010080509afe633 + memcmp() returns 0 +test_pdu_dec_enc(): decoding testData[1] = 41c001081502de8e9a + osmo_gprs_llc_pdu_decode() returns 0 + osmo_gprs_llc_pdu_hdr_dump(): SAPI=1, UI func=UI C/R=1 PM=1 E=0 IP=0 N(U)=0 FCS=9a8ede + hdr.data[] (len=3): 081502 +test_pdu_dec_enc(): encoding decoded testData[1] + osmo_gprs_llc_pdu_encode() returns 0 + osmo_gprs_llc_pdu_encode(): 41c001081502de8e9a + memcmp() returns 0 +test_pdu_dec_enc(): decoding testData[2] = 01e01ca2b3 + osmo_gprs_llc_pdu_decode() returns 0 + osmo_gprs_llc_pdu_hdr_dump(): SAPI=1, U func=NULL C/R=0 P/F=0 FCS=b3a21c +test_pdu_dec_enc(): encoding decoded testData[2] + osmo_gprs_llc_pdu_encode() returns 0 + osmo_gprs_llc_pdu_encode(): 01e01ca2b3 + memcmp() returns 0 +test_pdu_dec_enc(): decoding testData[3] = 43fb01001601f41a05df8c7c4e + osmo_gprs_llc_pdu_decode() returns 0 + osmo_gprs_llc_pdu_hdr_dump(): SAPI=3, U func=XID C/R=1 P/F=1 FCS=4e7c8c + hdr.data[] (len=8): 01001601f41a05df +test_pdu_dec_enc(): encoding decoded testData[3] + osmo_gprs_llc_pdu_encode() returns 0 + osmo_gprs_llc_pdu_encode(): 43fb01001601f41a05df8c7c4e + memcmp() returns 0 +test_pdu_dec_enc(): decoding testData[4] = 03fb1604d216f984 + osmo_gprs_llc_pdu_decode() returns 0 + osmo_gprs_llc_pdu_hdr_dump(): SAPI=3, U func=XID C/R=0 P/F=1 FCS=84f916 + hdr.data[] (len=3): 1604d2 +test_pdu_dec_enc(): encoding decoded testData[4] + osmo_gprs_llc_pdu_encode() returns 0 + osmo_gprs_llc_pdu_encode(): 03fb1604d216f984 + memcmp() returns 0 + diff --git a/tests/testsuite.at b/tests/testsuite.at index 53e5ab2..703fd7a 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -1,6 +1,13 @@ AT_INIT AT_BANNER([Regression tests])
+AT_SETUP([llc/pdu_codec]) +AT_KEYWORDS([llc pdu codec]) +cat $abs_srcdir/llc_pdu_codec/pdu_codec_test.ok > expout +cat $abs_srcdir/llc_pdu_codec/pdu_codec_test.err > experr +AT_CHECK([$abs_top_builddir/tests/llc_pdu_codec/pdu_codec_test], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([rlcmac/ts_44_018]) AT_KEYWORDS([rlcmac ts_44_018]) cat $abs_srcdir/ts_44_018/ts_44_018_test.ok > expout