Discussion:
[PATCH 1/2] gprs/test: Add BSSGP tests
Jacob Erlbeck
2014-10-16 07:11:35 UTC
Permalink
This patch adds a test suite for the BSSGP protocol.
The first (and only) test checks the handling of BSSGP
SUSPEND/RESUME.

Sponsored-by: On-Waves ehf
---
tests/Makefile.am | 8 ++-
tests/gb/gprs_bssgp_test.c | 151 ++++++++++++++++++++++++++++++++++++++++++++
tests/gb/gprs_bssgp_test.ok | 5 ++
tests/testsuite.at | 6 ++
4 files changed, 168 insertions(+), 2 deletions(-)
create mode 100644 tests/gb/gprs_bssgp_test.c
create mode 100644 tests/gb/gprs_bssgp_test.ok

diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3f7db1f..b7ae607 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -5,8 +5,8 @@ check_PROGRAMS = timer/timer_test sms/sms_test ussd/ussd_test \
smscb/smscb_test bits/bitrev_test a5/a5_test \
conv/conv_test auth/milenage_test lapd/lapd_test \
gsm0808/gsm0808_test gsm0408/gsm0408_test \
- gb/bssgp_fc_test gb/gprs_ns_test kasumi/kasumi_test \
- logging/logging_test fr/fr_test \
+ gb/bssgp_fc_test gb/gprs_bssgp_test gb/gprs_ns_test \
+ kasumi/kasumi_test logging/logging_test fr/fr_test \
loggingrb/loggingrb_test strrb/strrb_test \
vty/vty_test comp128/comp128_test utils/utils_test

@@ -62,6 +62,9 @@ ussd_ussd_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gs
gb_bssgp_fc_test_SOURCES = gb/bssgp_fc_test.c
gb_bssgp_fc_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gb/libosmogb.la

+gb_gprs_bssgp_test_SOURCES = gb/gprs_bssgp_test.c
+gb_gprs_bssgp_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gb/libosmogb.la $(LIBRARY_DL)
+
gb_gprs_ns_test_SOURCES = gb/gprs_ns_test.c
gb_gprs_ns_test_LDADD = $(top_builddir)/src/libosmocore.la $(top_builddir)/src/gb/libosmogb.la $(LIBRARY_DL)

@@ -106,6 +109,7 @@ EXTRA_DIST = testsuite.at $(srcdir)/package.m4 $(TESTSUITE) \
lapd/lapd_test.ok gsm0408/gsm0408_test.ok \
gsm0808/gsm0808_test.ok gb/bssgp_fc_tests.err \
gb/bssgp_fc_tests.ok gb/bssgp_fc_tests.sh \
+ gb/gprs_bssgp_test.ok \
gb/gprs_ns_test.ok kasumi/kasumi_test.ok \
msgfile/msgfile_test.ok msgfile/msgconfig.cfg \
logging/logging_test.ok logging/logging_test.err \
diff --git a/tests/gb/gprs_bssgp_test.c b/tests/gb/gprs_bssgp_test.c
new file mode 100644
index 0000000..a2a4068
--- /dev/null
+++ b/tests/gb/gprs_bssgp_test.c
@@ -0,0 +1,151 @@
+/* Test routines for the BSSGP implementation in libosmogb
+ *
+ * (C) 2014 by sysmocom s.f.m.c. GmbH
+ * Author: Jacob Erlbeck <jerlbeck at sysmocom.de>
+ *
+ * Skeleton based on bssgp_fc_test.c
+ * (C) 2012 by Harald Welte <laforge at gnumonks.org>
+ */
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/prim.h>
+#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/gprs/gprs_ns.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <netinet/ip.h>
+#include <dlfcn.h>
+
+#define BSS_NSEI 0x0b55
+
+static struct osmo_prim_hdr last_oph = {0};
+
+/* override */
+ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
+ const struct sockaddr *dest_addr, socklen_t addrlen)
+{
+ typedef ssize_t (*sendto_t)(int, const void *, size_t, int,
+ const struct sockaddr *, socklen_t);
+ static sendto_t real_sendto = NULL;
+ uint32_t dest_host = htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
+
+ if (!real_sendto)
+ real_sendto = dlsym(RTLD_NEXT, "sendto");
+
+ fprintf(stderr, "MESSAGE to 0x%08x, msg length %d\n%s\n",
+ dest_host, len, osmo_hexdump(buf, len));
+
+ return len;
+}
+
+/* override */
+int gprs_ns_callback(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
+ struct msgb *msg, uint16_t bvci)
+{
+ fprintf(stderr, "CALLBACK, event %d, msg length %d, bvci 0x%04x\n%s\n\n",
+ event, msgb_bssgp_len(msg), bvci,
+ osmo_hexdump(msgb_bssgph(msg), msgb_bssgp_len(msg)));
+ return 0;
+}
+
+int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
+{
+ printf("BSSGP primitive, SAP %d, prim = %d, op = %d, msg = %s\n",
+ oph->sap, oph->primitive, oph->operation, msgb_hexdump(oph->msg));
+
+ last_oph.sap = oph->sap;
+ last_oph.primitive = oph->primitive;
+ last_oph.operation = oph->operation;
+ last_oph.msg = NULL;
+ return -1;
+}
+
+static void msgb_bssgp_send_and_free(struct msgb *msg)
+{
+ msgb_nsei(msg) = BSS_NSEI;
+
+ bssgp_rcvmsg(msg);
+
+ msgb_free(msg);
+}
+
+static void send_bssgp_supend(enum bssgp_pdu_type pdu_type, uint32_t tlli)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ uint32_t tlli_be = htonl(tlli);
+ uint8_t rai[] = {0x0f, 0xf1, 0x80, 0x20, 0x37, 0x00};
+
+ msgb_v_put(msg, pdu_type);
+ msgb_tvlv_put(msg, BSSGP_IE_TLLI, sizeof(tlli_be), (uint8_t *)&tlli_be);
+ msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, sizeof(rai), &rai[0]);
+
+ msgb_bssgp_send_and_free(msg);
+}
+
+static void send_bssgp_resume(enum bssgp_pdu_type pdu_type, uint32_t tlli)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ uint32_t tlli_be = htonl(tlli);
+ uint8_t rai[] = {0x0f, 0xf1, 0x80, 0x20, 0x37, 0x00};
+ uint8_t suspend_ref = 1;
+
+ msgb_v_put(msg, pdu_type);
+ msgb_tvlv_put(msg, BSSGP_IE_TLLI, sizeof(tlli_be), (uint8_t *)&tlli_be);
+ msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, sizeof(rai), &rai[0]);
+ msgb_tvlv_put(msg, BSSGP_IE_SUSPEND_REF_NR, 1, &suspend_ref);
+
+ msgb_bssgp_send_and_free(msg);
+}
+
+static void test_bssgp_suspend_resume(void)
+{
+ const uint32_t tlli = 0xf0123456;
+
+ printf("----- %s START\n", __func__);
+ memset(&last_oph, 0, sizeof(last_oph));
+
+ send_bssgp_supend(BSSGP_PDUT_SUSPEND, tlli);
+ /* OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_SUSPEND); */
+
+ send_bssgp_resume(BSSGP_PDUT_RESUME, tlli);
+ /* OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_RESUME); */
+
+ printf("----- %s END\n", __func__);
+}
+
+static struct log_info info = {};
+
+int main(int argc, char **argv)
+{
+ struct sockaddr_in bss_peer= {0};
+
+ osmo_init_logging(&info);
+ log_set_use_color(osmo_stderr_target, 0);
+ log_set_print_filename(osmo_stderr_target, 0);
+
+ bssgp_nsi = gprs_ns_instantiate(gprs_ns_callback, NULL);
+
+ bss_peer.sin_family = AF_INET;
+ bss_peer.sin_port = htons(32000);
+ bss_peer.sin_addr.s_addr = htonl(0x7f0000ff);
+
+ gprs_ns_nsip_connect(bssgp_nsi, &bss_peer, BSS_NSEI, BSS_NSEI+1);
+
+
+ printf("===== BSSGP test START\n");
+ test_bssgp_suspend_resume();
+ printf("===== BSSGP test END\n\n");
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/gb/gprs_bssgp_test.ok b/tests/gb/gprs_bssgp_test.ok
new file mode 100644
index 0000000..9c7b4c0
--- /dev/null
+++ b/tests/gb/gprs_bssgp_test.ok
@@ -0,0 +1,5 @@
+===== BSSGP test START
+----- test_bssgp_suspend_resume START
+----- test_bssgp_suspend_resume END
+===== BSSGP test END
+
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 7ce2ee8..fe30363 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -118,6 +118,12 @@ cat $abs_srcdir/vty/vty_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/vty/vty_test], [0], [expout], [ignore])
AT_CLEANUP

+AT_SETUP([gprs-bssgp])
+AT_KEYWORDS([gprs-bssgp])
+cat $abs_srcdir/gb/gprs_bssgp_test.ok > expout
+AT_CHECK([$abs_top_builddir/tests/gb/gprs_bssgp_test], [0], [expout], [ignore])
+AT_CLEANUP
+
AT_SETUP([gprs-ns])
AT_KEYWORDS([gprs-ns])
cat $abs_srcdir/gb/gprs_ns_test.ok > expout
--
1.9.1
Jacob Erlbeck
2014-10-16 07:11:36 UTC
Permalink
Currently sending SUSPEND/RESUME messages to this function (like it
is done in the osmo-sgsn) results in STATUS messages complaining
about an unknown BVCI. The reason is, that these messages rely on a
TLLI/RAI pair to identify the context and do not contain an explicit
BVCI.

This patch modifies bssgp_rcvmsg() to only complain about and unknown
BVCI if one is given but a matching context is not found (except for
RESET messages). The ctx argument is removed from the functions
handling SUSPEND and RESUME since it will always be NULL then.

Sponsored-by: On-Waves ehf
---
src/gb/gprs_bssgp.c | 44 ++++++++++++++++++++++++++------------------
tests/gb/gprs_bssgp_test.c | 4 ++--
tests/gb/gprs_bssgp_test.ok | 2 ++
3 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/src/gb/gprs_bssgp.c b/src/gb/gprs_bssgp.c
index 7a5d628..506efdf 100644
--- a/src/gb/gprs_bssgp.c
+++ b/src/gb/gprs_bssgp.c
@@ -398,32 +398,32 @@ static int bssgp_rx_ul_ud(struct msgb *msg, struct tlv_parsed *tp,
return bssgp_prim_cb(&gbp.oph, NULL);
}

-static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp,
- struct bssgp_bvc_ctx *ctx)
+static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp)
{
struct osmo_bssgp_prim gbp;
struct gprs_ra_id raid;
uint32_t tlli;
+ uint16_t ns_bvci = msgb_bvci(msg);
int rc;

if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) ||
!TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx SUSPEND "
- "missing mandatory IE\n", ctx->bvci);
+ "missing mandatory IE\n", ns_bvci);
return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
}

tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI));

DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x Rx SUSPEND\n",
- ctx->bvci, tlli);
+ ns_bvci, tlli);

gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));

/* Inform GMM about the SUSPEND request */
memset(&gbp, 0, sizeof(gbp));
gbp.nsei = msgb_nsei(msg);
- gbp.bvci = ctx->bvci;
+ gbp.bvci = ns_bvci;
gbp.tlli = tlli;
gbp.ra_id = &raid;
osmo_prim_init(&gbp.oph, SAP_BSSGP_GMM, PRIM_BSSGP_GMM_SUSPEND,
@@ -438,34 +438,34 @@ static int bssgp_rx_suspend(struct msgb *msg, struct tlv_parsed *tp,
return 0;
}

-static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp,
- struct bssgp_bvc_ctx *ctx)
+static int bssgp_rx_resume(struct msgb *msg, struct tlv_parsed *tp)
{
struct osmo_bssgp_prim gbp;
struct gprs_ra_id raid;
uint32_t tlli;
uint8_t suspend_ref;
+ uint16_t ns_bvci = msgb_bvci(msg);
int rc;

if (!TLVP_PRESENT(tp, BSSGP_IE_TLLI) ||
!TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA) ||
!TLVP_PRESENT(tp, BSSGP_IE_SUSPEND_REF_NR)) {
LOGP(DBSSGP, LOGL_ERROR, "BSSGP BVCI=%u Rx RESUME "
- "missing mandatory IE\n", ctx->bvci);
+ "missing mandatory IE\n", ns_bvci);
return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
}

tlli = ntohl(*(uint32_t *)TLVP_VAL(tp, BSSGP_IE_TLLI));
suspend_ref = *TLVP_VAL(tp, BSSGP_IE_SUSPEND_REF_NR);

- DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x Rx RESUME\n", ctx->bvci, tlli);
+ DEBUGP(DBSSGP, "BSSGP BVCI=%u TLLI=0x%08x Rx RESUME\n", ns_bvci, tlli);

gsm48_parse_ra(&raid, TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA));

/* Inform GMM about the RESUME request */
memset(&gbp, 0, sizeof(gbp));
gbp.nsei = msgb_nsei(msg);
- gbp.bvci = ctx->bvci;
+ gbp.bvci = ns_bvci;
gbp.tlli = tlli;
gbp.ra_id = &raid;
gbp.u.resume.suspend_ref = suspend_ref;
@@ -886,23 +886,29 @@ static int bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp,
uint8_t pdu_type = bgph->pdu_type;
int rc = 0;
uint16_t ns_bvci = msgb_bvci(msg);
+ uint16_t bvci = bctx ? bctx->bvci : ns_bvci;

switch (bgph->pdu_type) {
case BSSGP_PDUT_SUSPEND:
/* MS wants to suspend */
- rc = bssgp_rx_suspend(msg, tp, bctx);
+ rc = bssgp_rx_suspend(msg, tp);
break;
case BSSGP_PDUT_RESUME:
/* MS wants to resume */
- rc = bssgp_rx_resume(msg, tp, bctx);
+ rc = bssgp_rx_resume(msg, tp);
break;
case BSSGP_PDUT_FLUSH_LL_ACK:
/* BSS informs us it has performed LL FLUSH */
- DEBUGP(DBSSGP, "BSSGP Rx BVCI=%u FLUSH LL ACK\n", bctx->bvci);
+ DEBUGP(DBSSGP, "BSSGP Rx BVCI=%u FLUSH LL ACK\n", bvci);
/* FIXME: send NM_FLUSH_LL.res to NM */
break;
case BSSGP_PDUT_LLC_DISCARD:
/* BSS informs that some LLC PDU's have been discarded */
+ if (!bctx) {
+ LOGP(DBSSGP, LOGL_ERROR,
+ "BSSGP Rx LLC-DISCARD missing mandatory BVCI\n");
+ goto err_mand_ie;
+ }
rc = bssgp_rx_llc_disc(msg, tp, bctx);
break;
case BSSGP_PDUT_BVC_BLOCK:
@@ -936,7 +942,7 @@ static int bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp,
break;
case BSSGP_PDUT_STATUS:
/* Some exception has occurred */
- DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC STATUS\n", bctx->bvci);
+ DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC STATUS\n", bvci);
/* FIXME: send NM_STATUS.ind to NM */
break;
/* those only exist in the SGSN -> BSS direction */
@@ -951,13 +957,13 @@ static int bssgp_rx_sign(struct msgb *msg, struct tlv_parsed *tp,
case BSSGP_PDUT_BVC_UNBLOCK_ACK:
case BSSGP_PDUT_SGSN_INVOKE_TRACE:
DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x only exists "
- "in DL\n", bctx->bvci, pdu_type);
+ "in DL\n", bvci, pdu_type);
bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
rc = -EINVAL;
break;
default:
DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx PDU type 0x%02x unknown\n",
- bctx->bvci, pdu_type);
+ bvci, pdu_type);
rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg);
break;
}
@@ -998,8 +1004,10 @@ int bssgp_rcvmsg(struct msgb *msg)

/* look-up or create the BTS context for this BVC */
bctx = btsctx_by_bvci_nsei(bvci, msgb_nsei(msg));
- /* Only a RESET PDU can create a new BVC context */
- if (!bctx && pdu_type != BSSGP_PDUT_BVC_RESET) {
+ /* Only a RESET PDU can create a new BVC context,
+ * otherwise it must be registered if a BVCI is given */
+ if (!bctx && bvci != BVCI_SIGNALLING &&
+ pdu_type != BSSGP_PDUT_BVC_RESET) {
LOGP(DBSSGP, LOGL_NOTICE, "NSEI=%u/BVCI=%u Rejecting PDU "
"type %u for unknown BVCI\n", msgb_nsei(msg), bvci,
pdu_type);
diff --git a/tests/gb/gprs_bssgp_test.c b/tests/gb/gprs_bssgp_test.c
index a2a4068..d24250d 100644
--- a/tests/gb/gprs_bssgp_test.c
+++ b/tests/gb/gprs_bssgp_test.c
@@ -116,10 +116,10 @@ static void test_bssgp_suspend_resume(void)
memset(&last_oph, 0, sizeof(last_oph));

send_bssgp_supend(BSSGP_PDUT_SUSPEND, tlli);
- /* OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_SUSPEND); */
+ OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_SUSPEND);

send_bssgp_resume(BSSGP_PDUT_RESUME, tlli);
- /* OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_RESUME); */
+ OSMO_ASSERT(last_oph.primitive == PRIM_BSSGP_GMM_RESUME);

printf("----- %s END\n", __func__);
}
diff --git a/tests/gb/gprs_bssgp_test.ok b/tests/gb/gprs_bssgp_test.ok
index 9c7b4c0..c9ec83d 100644
--- a/tests/gb/gprs_bssgp_test.ok
+++ b/tests/gb/gprs_bssgp_test.ok
@@ -1,5 +1,7 @@
===== BSSGP test START
----- test_bssgp_suspend_resume START
+BSSGP primitive, SAP 16777219, prim = 3, op = 0, msg = 0b 1f 84 f0 12 34 56 1b 86 0f f1 80 20 37 00
+BSSGP primitive, SAP 16777219, prim = 4, op = 0, msg = 0e 1f 84 f0 12 34 56 1b 86 0f f1 80 20 37 00 1d 81 01
----- test_bssgp_suspend_resume END
===== BSSGP test END
--
1.9.1
Loading...