summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorsten Alteholz <debian@alteholz.de>2018-07-16 12:34:42 +0200
committerThorsten Alteholz <debian@alteholz.de>2018-07-16 12:34:42 +0200
commit0bdaae23af07b9d02fc8cf0e56a1165a5b5987c0 (patch)
treef5c147f62bc857f126ffebb0b68b9c847c64adc4
parent1dc1480e7f024f8807f2d28a031bf9fc2040a401 (diff)
Import Upstream version 0.3.0
-rwxr-xr-xasn1/utils/asn1tostruct.py9
-rw-r--r--configure.ac49
-rwxr-xr-xcontrib/jenkins.sh9
-rw-r--r--include/osmocom/iuh/context_map.h5
-rw-r--r--include/osmocom/iuh/hnbgw.h17
-rw-r--r--include/osmocom/ranap/iu_helpers.h6
-rw-r--r--src/Makefile.am15
-rw-r--r--src/context_map.c16
-rw-r--r--src/hnbgw.c154
-rw-r--r--src/hnbgw_cn.c62
-rw-r--r--src/hnbgw_hnbap.c89
-rw-r--r--src/hnbgw_ranap.c52
-rw-r--r--src/hnbgw_rua.c39
-rw-r--r--src/hnbgw_vty.c120
-rw-r--r--src/iu_client.c227
-rw-r--r--src/iu_helpers.c53
-rw-r--r--src/ranap_common.c4
-rw-r--r--src/ranap_common_cn.c14
-rw-r--r--src/ranap_msg_factory.c62
-rw-r--r--src/tests/Makefile.am2
-rw-r--r--src/tests/hnb-test.c10
-rw-r--r--src/tests/test-helpers.c4
-rw-r--r--src/tests/test-hnbap.c4
-rw-r--r--src/tests/test-ranap.c2
-rw-r--r--src/tests/test_common.c25
-rw-r--r--src/tests/test_common.h1
26 files changed, 774 insertions, 276 deletions
diff --git a/asn1/utils/asn1tostruct.py b/asn1/utils/asn1tostruct.py
index 8364c27..0bba9dd 100755
--- a/asn1/utils/asn1tostruct.py
+++ b/asn1/utils/asn1tostruct.py
@@ -311,7 +311,12 @@ for key in iesDefs:
f.write(" memset(%s, 0, sizeof(%s_t));\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), prefix + re.sub('-', '_', key)))
f.write(" %s_DEBUG(\"Decoding message %s (%%s:%%d)\\n\", __FILE__, __LINE__);\n\n" % (fileprefix.upper(), prefix + re.sub('-', '_', keyName)))
- f.write(" ANY_to_type_aper(any_p, &asn_DEF_%s, (void**)&%s_p);\n\n" % (asn1cStruct, asn1cStructfirstlower))
+ f.write(" tempDecoded = ANY_to_type_aper(any_p, &asn_DEF_%s, (void**)&%s_p);\n\n" % (asn1cStruct, asn1cStructfirstlower))
+ f.write(" if (tempDecoded < 0 || %s_p == NULL) {\n" % (asn1cStructfirstlower))
+ f.write(" %s_DEBUG(\"Decoding of message %s failed\\n\");\n" % (fileprefix.upper(), prefix + re.sub('-', '_', keyName)))
+ f.write(" return -1;\n")
+ f.write(" }\n\n")
+
f.write(" for (i = 0; i < %s_p->%slist.count; i++) {\n" % (asn1cStructfirstlower, iesaccess))
f.write(" %sIE_t *ie_p;\n" % (prefix))
f.write(" ie_p = %s_p->%slist.array[i];\n" % (asn1cStructfirstlower, iesaccess))
@@ -384,6 +389,8 @@ for key in iesDefs:
iename = re.sub('id-', '', ie[0])
ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename))
f.write(" ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_%s, &%s->%s);\n" % (ietypeunderscore, lowerFirstCamelWord(re.sub('-', '_', key)), ienameunderscore))
+
+ f.write(" return 0;\n")
f.write("}\n\n")
for key in iesDefs:
diff --git a/configure.ac b/configure.ac
index ff0501a..bb99dfb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,18 +33,55 @@ if test "x$PKG_CONFIG_INSTALLED" = "xno"; then
fi
PKG_PROG_PKG_CONFIG([0.20])
-PKG_CHECK_MODULES(OSMOCORE, libosmocore >= 0.10.0)
-PKG_CHECK_MODULES(OSMOGSM, libosmogsm >= 0.10.0)
-PKG_CHECK_MODULES(OSMOVTY, libosmovty >= 0.10.0)
-PKG_CHECK_MODULES(OSMONETIF, libosmo-netif >= 0.1.0)
-PKG_CHECK_MODULES(OSMOSIGTRAN, libosmo-sigtran >= 0.8.0)
-PKG_CHECK_MODULES(ASN1C, libasn1c >= 0.9.28)
+PKG_CHECK_MODULES(OSMOCORE, libosmocore >= 0.11.0)
+PKG_CHECK_MODULES(OSMOGSM, libosmogsm >= 0.11.0)
+PKG_CHECK_MODULES(OSMOVTY, libosmovty >= 0.11.0)
+PKG_CHECK_MODULES(OSMOCTRL, libosmoctrl >= 0.11.0)
+PKG_CHECK_MODULES(OSMONETIF, libosmo-netif >= 0.2.0)
+PKG_CHECK_MODULES(OSMOSIGTRAN, libosmo-sigtran >= 0.9.0)
+PKG_CHECK_MODULES(ASN1C, libasn1c >= 0.9.30)
AC_CONFIG_MACRO_DIR([m4])
dnl checks for header files
AC_HEADER_STDC
+AC_ARG_ENABLE(sanitize,
+ [AS_HELP_STRING(
+ [--enable-sanitize],
+ [Compile with address sanitizer enabled],
+ )],
+ [sanitize=$enableval], [sanitize="no"])
+if test x"$sanitize" = x"yes"
+then
+ CFLAGS="$CFLAGS -fsanitize=address -fsanitize=undefined"
+ CPPFLAGS="$CPPFLAGS -fsanitize=address -fsanitize=undefined"
+fi
+
+AC_ARG_ENABLE(werror,
+ [AS_HELP_STRING(
+ [--enable-werror],
+ [Turn all compiler warnings into errors, with exceptions:
+ a) deprecation (allow upstream to mark deprecation without breaking builds);
+ b) "#warning" pragmas (allow to remind ourselves of errors without breaking builds)
+ ]
+ )],
+ [werror=$enableval], [werror="no"])
+if test x"$werror" = x"yes"
+then
+ WERROR_FLAGS="-Werror"
+ WERROR_FLAGS+=" -Wno-error=deprecated -Wno-error=deprecated-declarations"
+ WERROR_FLAGS+=" -Wno-error=cpp" # "#warning"
+ CFLAGS="$CFLAGS $WERROR_FLAGS"
+ CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
+fi
+
+CFLAGS="$CFLAGS -Wall"
+CPPFLAGS="$CPPFLAGS -Wall"
+
+AC_MSG_RESULT([CFLAGS="$CFLAGS"])
+AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"])
+
AC_OUTPUT(
libosmo-ranap.pc
src/Makefile
diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh
index cda0e2c..617aeac 100755
--- a/contrib/jenkins.sh
+++ b/contrib/jenkins.sh
@@ -7,15 +7,16 @@ deps="$base/deps"
inst="$deps/install"
export deps inst
+osmo-clean-workspace.sh
+
mkdir "$deps" || true
-rm -rf "$inst"
verify_value_string_arrays_are_terminated.py $(find . -name "*.[hc]")
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
-osmo-build-dep.sh libosmocore
+osmo-build-dep.sh libosmocore "" --disable-doxygen
osmo-build-dep.sh libosmo-abis
osmo-build-dep.sh libosmo-netif
osmo-build-dep.sh libosmo-sccp
@@ -33,7 +34,7 @@ echo
set -x
autoreconf --install --force
-./configure
+./configure --enable-sanitize
# Verify that checked-in asn1 code is identical to regenerated asn1 code
PATH="$inst/bin:$PATH" $MAKE $PARALLEL_MAKE -C src regen
@@ -54,3 +55,5 @@ $MAKE check \
|| cat-testlogs.sh
$MAKE distcheck \
|| cat-testlogs.sh
+
+osmo-clean-workspace.sh
diff --git a/include/osmocom/iuh/context_map.h b/include/osmocom/iuh/context_map.h
index 8d957d6..6279b91 100644
--- a/include/osmocom/iuh/context_map.h
+++ b/include/osmocom/iuh/context_map.h
@@ -8,8 +8,13 @@ enum hnbgw_context_map_state {
MAP_S_ACTIVE, /* currently active map */
MAP_S_RESERVED1, /* just disconnected, still resrved */
MAP_S_RESERVED2, /* still reserved */
+ MAP_S_NUM_STATES /* Number of states, keep this at the end */
};
+extern const struct value_string hnbgw_context_map_state_names[];
+static inline const char *hnbgw_context_map_state_name(enum hnbgw_context_map_state val)
+{ return get_value_string(hnbgw_context_map_state_names, val); }
+
struct hnb_context;
struct hnbgw_cnlink;
diff --git a/include/osmocom/iuh/hnbgw.h b/include/osmocom/iuh/hnbgw.h
index 58bdab4..b79bcc1 100644
--- a/include/osmocom/iuh/hnbgw.h
+++ b/include/osmocom/iuh/hnbgw.h
@@ -6,7 +6,7 @@
#include <osmocom/core/timer.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sigtran/osmo_ss7.h>
-
+#include <osmocom/ctrl/control_if.h>
#define DEBUG
#include <osmocom/core/logging.h>
@@ -18,6 +18,10 @@ enum {
DRANAP,
};
+enum hnb_ctrl_node {
+ CTRL_NODE_HNB = _LAST_CTRL_NODE,
+ _LAST_CTRL_NODE_HNB
+};
#define HNBGW_LOCAL_IP_DEFAULT "0.0.0.0"
/* TODO: CS and PS now both connect to OsmoSTP, i.e. that's always going to be the same address. Drop the
@@ -93,6 +97,10 @@ struct hnb_context {
/*! SCTP stream ID for RUA */
uint16_t rua_stream;
+ /*! True if a HNB-REGISTER-REQ from this HNB has been accepted. Note that
+ * this entire data structure is freed if the HNB sends HNB-DE-REGISTER-REQ. */
+ bool hnb_registered;
+
/* linked list of hnbgw_context_map */
struct llist_head map_list;
};
@@ -129,7 +137,7 @@ struct hnb_gw {
struct llist_head ue_list;
/* next availble UE Context ID */
uint32_t next_ue_ctx_id;
-
+ struct ctrl_handle *ctrl;
/* currently active CN links for CS and PS */
struct {
struct osmo_sccp_instance *client;
@@ -142,6 +150,9 @@ struct hnb_gw {
extern void *talloc_asn1_ctx;
+struct hnb_context *hnb_context_by_id(struct hnb_gw *gw, uint32_t cid);
+unsigned hnb_contexts(const struct hnb_gw *gw);
+
struct ue_context *ue_context_by_id(struct hnb_gw *gw, uint32_t id);
struct ue_context *ue_context_by_imsi(struct hnb_gw *gw, const char *imsi);
struct ue_context *ue_context_by_tmsi(struct hnb_gw *gw, uint32_t tmsi);
@@ -150,7 +161,7 @@ struct ue_context *ue_context_alloc(struct hnb_context *hnb, const char *imsi,
void ue_context_free(struct ue_context *ue);
struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, struct osmo_stream_srv_link *link, int new_fd);
-void hnb_context_release(struct hnb_context *ctx);
+void hnb_context_release(struct hnb_context *ctx, bool destroy_conn);
void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx);
int hnbgw_vty_go_parent(struct vty *vty);
diff --git a/include/osmocom/ranap/iu_helpers.h b/include/osmocom/ranap/iu_helpers.h
index 109b6da..9d801be 100644
--- a/include/osmocom/ranap/iu_helpers.h
+++ b/include/osmocom/ranap/iu_helpers.h
@@ -3,5 +3,11 @@
#include <stdint.h>
#include <sys/types.h>
+#include <osmocom/ranap/RANAP_IuTransportAssociation.h>
+#include <osmocom/ranap/RANAP_TransportLayerAddress.h>
+
int ranap_bcd_decode(char *out, size_t out_len, const uint8_t *in, size_t in_len);
int ranap_imsi_encode(uint8_t *out, size_t out_len, const char *in);
+int ranap_transp_assoc_decode(uint16_t *port, const RANAP_IuTransportAssociation_t *transp_assoc);
+int ranap_transp_layer_addr_decode(char *addr, unsigned int addr_len,
+ const RANAP_TransportLayerAddress_t *trasp_layer_addr);
diff --git a/src/Makefile.am b/src/Makefile.am
index d815394..7802384 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,18 +42,17 @@ gen_ranap.stamp: $(ASN1_ROOT)/ranap/RANAP-PDU-Contents.asn $(ASN1TOSTRUCT)
ranap_decoder.c ranap_encoder.c: gen_ranap.stamp
-AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include \
- $(OSMOCORE_CFLAGS) $(OSMOVTY_CFLAGS) $(OSMOGSM_CFLAGS) \
+AM_CFLAGS = -Wall -I$(top_srcdir)/include -I$(top_builddir)/include \
+ $(OSMOCORE_CFLAGS) $(OSMOVTY_CFLAGS) $(OSMOCTRL_CFLAGS) $(OSMOGSM_CFLAGS) \
$(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS)
-COMMON_LDADD = -lsctp
# build the shared RANAP library
#
-RANAP_LIBVERSION=1:0:0
+RANAP_LIBVERSION=2:0:0
lib_LTLIBRARIES = libosmo-ranap.la
libosmo_ranap_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(RANAP_LIBVERSION)
-libosmo_ranap_la_LIBADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOSIGTRAN_LIBS) \
- $(ASN1C_LIBS) $(COMMON_LDADD) ranap/libosmo-asn1-ranap.la
+libosmo_ranap_la_LIBADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOVTY_LIBS) $(OSMOSIGTRAN_LIBS) \
+ $(ASN1C_LIBS) ranap/libosmo-asn1-ranap.la
libosmo_ranap_la_SOURCES = ranap_common.c ranap_encoder.c ranap_decoder.c ranap_msg_factory.c iu_helpers.c \
ranap_common_cn.c iu_client.c iu_client_vty.c
@@ -68,8 +67,8 @@ osmo_hnbgw_SOURCES = hnbap_encoder.c hnbap_decoder.c hnbap_common.c \
hnbgw_vty.c \
context_map.c hnbgw_cn.c
-osmo_hnbgw_LDADD = $(OSMOCORE_LIBS) $(OSMOVTY_LIBS) $(OSMOGSM_LIBS) \
- $(ASN1C_LIBS) $(OSMOSIGTRAN_LIBS) $(COMMON_LDADD) \
+osmo_hnbgw_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOVTY_LIBS) $(OSMOCTRL_LIBS) \
+ $(ASN1C_LIBS) $(OSMOSIGTRAN_LIBS) \
$(OSMONETIF_LIBS) \
hnbap/libosmo-asn1-hnbap.a rua/libosmo-asn1-rua.a \
libosmo-ranap.la
diff --git a/src/context_map.c b/src/context_map.c
index 0960cb9..dc555bf 100644
--- a/src/context_map.c
+++ b/src/context_map.c
@@ -27,6 +27,14 @@
#include <osmocom/iuh/hnbgw.h>
#include <osmocom/iuh/context_map.h>
+const struct value_string hnbgw_context_map_state_names[] = {
+ {MAP_S_NULL , "not-initialized"},
+ {MAP_S_ACTIVE , "active"},
+ {MAP_S_RESERVED1, "inactive-reserved"},
+ {MAP_S_RESERVED2, "inactive-discard"},
+ {0, NULL}
+};
+
/* is a given SCCP USER SAP Connection ID in use for a given CN link? */
static int cn_id_in_use(struct hnbgw_cnlink *cn, uint32_t id)
{
@@ -138,10 +146,10 @@ static void context_map_tmr_cb(void *data)
{
struct hnb_gw *gw = data;
struct hnbgw_cnlink *cn = gw->sccp.cnlink;
- struct hnbgw_context_map *map;
+ struct hnbgw_context_map *map, *next_map;
DEBUGP(DMAIN, "Running context mapper garbage collection\n");
- llist_for_each_entry(map, &cn->map_list, cn_list) {
+ llist_for_each_entry_safe(map, next_map, &cn->map_list, cn_list) {
switch (map->state) {
case MAP_S_RESERVED1:
/* first time we see this reserved
@@ -149,7 +157,7 @@ static void context_map_tmr_cb(void *data)
map->state = MAP_S_RESERVED2;
break;
case MAP_S_RESERVED2:
- /* first time we see this reserved
+ /* second time we see this reserved
* entry: remove it */
map->state = MAP_S_NULL;
llist_del(&map->cn_list);
@@ -169,4 +177,6 @@ int context_map_init(struct hnb_gw *gw)
context_map_tmr.cb = context_map_tmr_cb;
context_map_tmr.data = gw;
osmo_timer_schedule(&context_map_tmr, EXPIRY_TIMER_SECS, 0);
+
+ return 0;
}
diff --git a/src/hnbgw.c b/src/hnbgw.c
index c9fdd53..94d8fb9 100644
--- a/src/hnbgw.c
+++ b/src/hnbgw.c
@@ -41,12 +41,19 @@
#include <osmocom/core/socket.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/write_queue.h>
-
+#include <osmocom/ctrl/control_if.h>
+#include <osmocom/ctrl/control_cmd.h>
+#include <osmocom/ctrl/control_vty.h>
+#include <osmocom/ctrl/ports.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/ports.h>
#include <osmocom/netif/stream.h>
+#include <osmocom/ranap/ranap_common.h>
+
#include <osmocom/sigtran/protocol/m3ua.h>
#include <osmocom/sigtran/sccp_sap.h>
@@ -69,8 +76,6 @@ void *talloc_asn1_ctx;
static struct hnb_gw *g_hnb_gw;
-static int listen_fd_cb(struct osmo_fd *fd, unsigned int what);
-
static struct hnb_gw *hnb_gw_create(void *ctx)
{
struct hnb_gw *gw = talloc_zero(ctx, struct hnb_gw);
@@ -88,6 +93,30 @@ static struct hnb_gw *hnb_gw_create(void *ctx)
return gw;
}
+struct hnb_context *hnb_context_by_id(struct hnb_gw *gw, uint32_t cid)
+{
+ struct hnb_context *hnb;
+
+ llist_for_each_entry(hnb, &gw->hnb_list, list) {
+ if (hnb->id.cid == cid)
+ return hnb;
+ }
+
+ return NULL;
+}
+
+unsigned hnb_contexts(const struct hnb_gw *gw)
+{
+ unsigned num_ctx = 0;
+ struct hnb_context *hnb;
+
+ llist_for_each_entry(hnb, &gw->hnb_list, list) {
+ num_ctx++;
+ }
+
+ return num_ctx;
+}
+
struct ue_context *ue_context_by_id(struct hnb_gw *gw, uint32_t id)
{
struct ue_context *ue;
@@ -175,13 +204,19 @@ void ue_context_free(struct ue_context *ue)
}
static int hnb_close_cb(struct osmo_stream_srv *conn)
{
+ struct hnb_context *hnb = osmo_stream_srv_get_data(conn);
+
+ /* This connection is about to be closed. Destroy the HNB context now. */
+ if (hnb)
+ hnb_context_release(hnb, false);
+
+ return 0;
}
static int hnb_read_cb(struct osmo_stream_srv *conn)
{
struct hnb_context *hnb = osmo_stream_srv_get_data(conn);
struct msgb *msg = msgb_alloc(IUH_MSGB_SIZE, "Iuh rx");
- int flags = 0;
int rc;
if (!msg)
@@ -199,10 +234,10 @@ static int hnb_read_cb(struct osmo_stream_srv *conn)
} else if (rc < 0) {
LOGP(DMAIN, LOGL_ERROR, "Error during sctp_recvmsg()\n");
/* FIXME: clean up after disappeared HNB */
- hnb_context_release(hnb);
+ hnb_context_release(hnb, true);
goto out;
} else if (rc == 0) {
- hnb_context_release(hnb);
+ hnb_context_release(hnb, true);
rc = -1;
goto out;
@@ -222,12 +257,12 @@ static int hnb_read_cb(struct osmo_stream_srv *conn)
case IUH_PPI_SABP:
case IUH_PPI_RNA:
case IUH_PPI_PUA:
- LOGP(DMAIN, LOGL_ERROR, "Unimplemented SCTP PPID=%u received\n",
+ LOGP(DMAIN, LOGL_ERROR, "Unimplemented SCTP PPID=%lu received\n",
msgb_sctp_ppid(msg));
rc = 0;
break;
default:
- LOGP(DMAIN, LOGL_ERROR, "Unknown SCTP PPID=%u received\n",
+ LOGP(DMAIN, LOGL_ERROR, "Unknown SCTP PPID=%lu received\n",
msgb_sctp_ppid(msg));
rc = 0;
break;
@@ -238,21 +273,6 @@ out:
return rc;
}
-static int hnb_write_cb(struct osmo_fd *fd, struct msgb *msg)
-{
- struct hnb_context *ctx = fd->data;
- struct sctp_sndrcvinfo sinfo = {
- .sinfo_ppid = htonl(msgb_sctp_ppid(msg)),
- .sinfo_stream = ctx->hnbap_stream,
- };
- int rc;
-
- rc = sctp_send(fd->fd, msgb_data(msg), msgb_length(msg),
- &sinfo, 0);
- /* we don't need to msgb_free(), write_queue does this for us */
- return rc;
-}
-
struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, struct osmo_stream_srv_link *link, int new_fd)
{
struct hnb_context *ctx;
@@ -274,7 +294,7 @@ struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, struct osmo_stream_srv_
return ctx;
}
-void hnb_context_release(struct hnb_context *ctx)
+void hnb_context_release(struct hnb_context *ctx, bool destroy_conn)
{
struct hnbgw_context_map *map, *map2;
@@ -291,7 +311,9 @@ void hnb_context_release(struct hnb_context *ctx)
context_map_deactivate(map);
}
ue_context_free_by_hnb(ctx->gw, ctx);
- osmo_stream_srv_destroy(ctx->conn);
+
+ if (destroy_conn)
+ osmo_stream_srv_destroy(ctx->conn);
talloc_free(ctx);
}
@@ -339,7 +361,7 @@ static const struct log_info hnbgw_log_info = {
static struct vty_app_info vty_info = {
.name = "OsmoHNBGW",
- .version = "0",
+ .version = PACKAGE_VERSION,
.go_parent_cb = hnbgw_vty_go_parent,
};
@@ -433,11 +455,66 @@ static void handle_options(int argc, char **argv)
}
}
+CTRL_CMD_DEFINE_RO(hnb_info, "info");
+static int get_hnb_info(struct ctrl_cmd *cmd, void *data)
+{
+ struct hnb_context *hnb = data;
+
+ cmd->reply = talloc_strdup(cmd, hnb->identity_info);
+
+ return CTRL_CMD_REPLY;
+}
+
+CTRL_CMD_DEFINE_RO(hnbs, "num-hnb");
+static int get_hnbs(struct ctrl_cmd *cmd, void *data)
+{
+ cmd->reply = talloc_asprintf(cmd, "%u", hnb_contexts(data));
+
+ return CTRL_CMD_REPLY;
+}
+
+int hnb_ctrl_cmds_install()
+{
+ int rc = 0;
+
+ rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_hnbs);
+ rc |= ctrl_cmd_install(CTRL_NODE_HNB, &cmd_hnb_info);
+
+ return rc;
+}
+
+static int hnb_ctrl_node_lookup(void *data, vector vline, int *node_type, void **node_data, int *i)
+{
+ const char *token = vector_slot(vline, *i);
+ struct hnb_context *hnb;
+ long num;
+
+ switch (*node_type) {
+ case CTRL_NODE_ROOT:
+ if (strcmp(token, "hnb") != 0)
+ return 0;
+
+ (*i)++;
+
+ if (!ctrl_parse_get_num(vline, *i, &num))
+ return -ERANGE;
+
+ hnb = hnb_context_by_id(data, num);
+ if (!hnb)
+ return -ENODEV;
+
+ *node_data = hnb;
+ *node_type = CTRL_NODE_HNB;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
int main(int argc, char **argv)
{
- struct osmo_sccp_user *sccp_user;
- struct osmo_sccp_link *sua_link;
struct osmo_stream_srv_link *srv;
int rc;
@@ -486,21 +563,36 @@ int main(int argc, char **argv)
log_set_log_level(osmo_stderr_target,
hnbgw_cmdline_config.log_level);
- rc = telnet_init_dynif(NULL, g_hnb_gw, vty_get_bind_addr(), 2323);
+ rc = telnet_init_dynif(tall_hnb_ctx, g_hnb_gw, vty_get_bind_addr(), OSMO_VTY_PORT_HNBGW);
if (rc < 0) {
perror("Error binding VTY port");
exit(1);
}
+ g_hnb_gw->ctrl = ctrl_interface_setup_dynip2(g_hnb_gw, ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_HNBGW,
+ hnb_ctrl_node_lookup, _LAST_CTRL_NODE_HNB);
+ if (!g_hnb_gw->ctrl) {
+ LOGP(DMAIN, LOGL_ERROR, "Failed to create CTRL interface on %s:%u\n",
+ ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_HNBGW);
+ exit(1);
+ } else {
+ rc = hnb_ctrl_cmds_install();
+ if (rc) {
+ LOGP(DMAIN, LOGL_ERROR, "Failed to install CTRL interface commands\n");
+ return 2;
+ }
+ }
+
ranap_set_log_area(DRANAP);
- rc = hnbgw_cnlink_init(g_hnb_gw,
- "127.0.0.1", M3UA_PORT, "127.0.0.5" /* FIXME: configurable */);
+ rc = hnbgw_cnlink_init(g_hnb_gw, "127.0.0.1", M3UA_PORT, NULL);
if (rc < 0) {
LOGP(DMAIN, LOGL_ERROR, "Failed to initialize SCCP link to CN\n");
exit(1);
}
+ LOGP(DHNBAP, LOGL_NOTICE, "Using RNC-Id %u\n", g_hnb_gw->config.rnc_id);
+
OSMO_ASSERT(g_hnb_gw->config.iuh_local_ip);
LOGP(DMAIN, LOGL_NOTICE, "Listening for Iuh at %s %d\n",
g_hnb_gw->config.iuh_local_ip,
diff --git a/src/hnbgw_cn.c b/src/hnbgw_cn.c
index 3b828b4..ede00c8 100644
--- a/src/hnbgw_cn.c
+++ b/src/hnbgw_cn.c
@@ -19,6 +19,7 @@
*/
#include <arpa/inet.h>
+#include <errno.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/utils.h>
@@ -38,13 +39,12 @@
* Outbound RANAP RESET to CN
***********************************************************************/
-int hnbgw_cnlink_change_state(struct hnbgw_cnlink *cnlink, enum hnbgw_cnlink_state state);
+void hnbgw_cnlink_change_state(struct hnbgw_cnlink *cnlink, enum hnbgw_cnlink_state state);
static int transmit_rst(struct hnb_gw *gw, RANAP_CN_DomainIndicator_t domain,
struct osmo_sccp_addr *remote_addr)
{
struct msgb *msg;
- struct msgb *msgprim;
RANAP_Cause_t cause = {
.present = RANAP_Cause_PR_transmissionNetwork,
.choice. transmissionNetwork = RANAP_CauseTransmissionNetwork_signalling_transport_resource_failure,
@@ -71,7 +71,7 @@ static void cnlink_trafc_cb(void *data)
}
/* change the state of a CN Link */
-int hnbgw_cnlink_change_state(struct hnbgw_cnlink *cnlink, enum hnbgw_cnlink_state state)
+void hnbgw_cnlink_change_state(struct hnbgw_cnlink *cnlink, enum hnbgw_cnlink_state state)
{
switch (state) {
case CNLINK_S_NULL:
@@ -127,9 +127,11 @@ static int cn_ranap_rx_paging_cmd(struct hnbgw_cnlink *cnlink,
struct hnb_gw *gw = cnlink->gw;
struct hnb_context *hnb;
RANAP_PagingIEs_t ies;
- int rc = 0;
+ int rc;
rc = ranap_decode_pagingies(&ies, &imsg->value);
+ if (rc < 0)
+ return rc;
/* FIXME: determine which HNBs to send this Paging command,
* rather than broadcasting to all HNBs */
@@ -145,8 +147,6 @@ static int cn_ranap_rx_initiating_msg(struct hnbgw_cnlink *cnlink,
RANAP_InitiatingMessage_t *imsg,
const uint8_t *data, unsigned int len)
{
- int rc;
-
switch (imsg->procedureCode) {
case RANAP_ProcedureCode_id_Reset:
return cn_ranap_rx_reset_cmd(cnlink, imsg);
@@ -161,11 +161,11 @@ static int cn_ranap_rx_initiating_msg(struct hnbgw_cnlink *cnlink,
case RANAP_ProcedureCode_id_DirectInformationTransfer:
case RANAP_ProcedureCode_id_UplinkInformationExchange:
LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
- "Procedure %u from CN, ignoring\n", imsg->procedureCode);
+ "Procedure %ld from CN, ignoring\n", imsg->procedureCode);
break;
default:
LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
- "Procedure %u from CN, ignoring\n", imsg->procedureCode);
+ "Procedure %ld from CN, ignoring\n", imsg->procedureCode);
break;
}
return 0;
@@ -174,8 +174,6 @@ static int cn_ranap_rx_initiating_msg(struct hnbgw_cnlink *cnlink,
static int cn_ranap_rx_successful_msg(struct hnbgw_cnlink *cnlink,
RANAP_SuccessfulOutcome_t *omsg)
{
- int rc;
-
switch (omsg->procedureCode) {
case RANAP_ProcedureCode_id_Reset: /* Reset acknowledge */
return cn_ranap_rx_reset_ack(cnlink, omsg);
@@ -184,11 +182,11 @@ static int cn_ranap_rx_successful_msg(struct hnbgw_cnlink *cnlink,
case RANAP_ProcedureCode_id_DirectInformationTransfer:
case RANAP_ProcedureCode_id_UplinkInformationExchange:
LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
- "Procedure %u from CN, ignoring\n", omsg->procedureCode);
+ "Procedure %ld from CN, ignoring\n", omsg->procedureCode);
break;
default:
LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
- "Procedure %u from CN, ignoring\n", omsg->procedureCode);
+ "Procedure %ld from CN, ignoring\n", omsg->procedureCode);
break;
}
return 0;
@@ -210,14 +208,18 @@ static int _cn_ranap_rx(struct hnbgw_cnlink *cnlink, RANAP_RANAP_PDU_t *pdu,
break;
case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
- "unsuccessful outcome procedure %u from CN, ignoring\n",
+ "unsuccessful outcome procedure %ld from CN, ignoring\n",
pdu->choice.unsuccessfulOutcome.procedureCode);
+ rc = -ENOTSUP;
break;
default:
LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
"presence %u from CN, ignoring\n", pdu->present);
+ rc = -EINVAL;
break;
}
+
+ return rc;
}
static int handle_cn_ranap(struct hnbgw_cnlink *cnlink, const uint8_t *data,
@@ -357,7 +359,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *ctx)
struct osmo_sccp_user *scu = ctx;
struct hnbgw_cnlink *cnlink;
struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;
- int rc;
+ int rc = 0;
LOGP(DMAIN, LOGL_DEBUG, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph));
@@ -389,7 +391,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *ctx)
case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
rc = handle_cn_disc_ind(cnlink, &prim->u.disconnect, oph);
break;
- defualt:
+ default:
LOGP(DMAIN, LOGL_ERROR,
"Received unknown prim %u from SCCP USER SAP\n",
OSMO_PRIM_HDR(oph));
@@ -398,7 +400,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *ctx)
msgb_free(oph->msg);
- return 0;
+ return rc;
}
static bool addr_has_pc_and_ssn(const struct osmo_sccp_addr *addr)
@@ -411,13 +413,16 @@ static bool addr_has_pc_and_ssn(const struct osmo_sccp_addr *addr)
}
static int resolve_addr_name(struct osmo_sccp_addr *dest, struct osmo_ss7_instance **ss7,
- const char *addr_name, const char *label)
+ const char *addr_name, const char *label,
+ uint32_t default_pc)
{
struct osmo_ss7_instance *ss7_tmp;
if (!addr_name) {
- LOGP(DMAIN, LOGL_ERROR, "Missing config: %s remote-addr\n", label);
- return -1;
+ osmo_sccp_make_addr_pc_ssn(dest, default_pc, OSMO_SCCP_SSN_RANAP);
+ LOGP(DMAIN, LOGL_INFO, "%s remote addr not configured, using default: %s\n", label,
+ osmo_sccp_addr_name(*ss7, dest));
+ return 0;
}
ss7_tmp = osmo_sccp_addr_by_name(dest, addr_name);
@@ -453,19 +458,25 @@ int hnbgw_cnlink_init(struct hnb_gw *gw, const char *stp_host, uint16_t stp_port
struct hnbgw_cnlink *cnlink;
struct osmo_ss7_instance *ss7;
uint32_t local_pc;
- int rc;
OSMO_ASSERT(!gw->sccp.client);
OSMO_ASSERT(!gw->sccp.cnlink);
ss7 = NULL;
if (resolve_addr_name(&gw->sccp.iucs_remote_addr, &ss7,
- gw->config.iucs_remote_addr_name, "IuCS"))
+ gw->config.iucs_remote_addr_name, "IuCS", (23 << 3) + 1))
return -1;
if (resolve_addr_name(&gw->sccp.iups_remote_addr, &ss7,
- gw->config.iups_remote_addr_name, "IuPS"))
+ gw->config.iups_remote_addr_name, "IuPS", (23 << 3) + 4))
return -1;
+ if (!ss7) {
+ LOGP(DRANAP, LOGL_NOTICE, "No cs7 instance configured for IuCS nor IuPS,"
+ " creating default instance\n");
+ ss7 = osmo_ss7_instance_find_or_create(gw, 0);
+ ss7->cfg.primary_pc = (23 << 3) + 5;
+ }
+
if (!osmo_ss7_pc_is_valid(ss7->cfg.primary_pc)) {
LOGP(DMAIN, LOGL_ERROR, "IuCS/IuPS uplink cannot be setup: CS7 instance %d has no point-code set\n",
ss7->cfg.id);
@@ -474,8 +485,6 @@ int hnbgw_cnlink_init(struct hnb_gw *gw, const char *stp_host, uint16_t stp_port
local_pc = ss7->cfg.primary_pc;
osmo_sccp_make_addr_pc_ssn(&gw->sccp.local_addr, local_pc, OSMO_SCCP_SSN_RANAP);
-
- LOGP(DRANAP, LOGL_NOTICE, "M3UA uplink to STP: %s %u\n", stp_host, stp_port);
LOGP(DRANAP, LOGL_NOTICE, "Local SCCP addr: %s\n", osmo_sccp_addr_name(ss7, &gw->sccp.local_addr));
gw->sccp.client = osmo_sccp_simple_client_on_ss7_id(gw, ss7->cfg.id, "OsmoHNBGW",
@@ -500,6 +509,11 @@ int hnbgw_cnlink_init(struct hnb_gw *gw, const char *stp_host, uint16_t stp_port
return -1;
}
+ LOGP(DRANAP, LOGL_NOTICE, "Remote SCCP addr: IuCS: %s\n",
+ osmo_sccp_addr_name(ss7, &gw->sccp.iucs_remote_addr));
+ LOGP(DRANAP, LOGL_NOTICE, "Remote SCCP addr: IuPS: %s\n",
+ osmo_sccp_addr_name(ss7, &gw->sccp.iups_remote_addr));
+
/* In sccp_sap_up() we expect the cnlink in the user's priv. */
osmo_sccp_user_set_priv(cnlink->sccp_user, cnlink);
diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c
index 0473482..acc5aff 100644
--- a/src/hnbgw_hnbap.c
+++ b/src/hnbgw_hnbap.c
@@ -20,6 +20,7 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/utils.h>
+#include <osmocom/core/socket.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/netif/stream.h>
@@ -48,6 +49,45 @@ static int hnbgw_hnbap_tx(struct hnb_context *ctx, struct msgb *msg)
return 0;
}
+static int hnbgw_tx_hnb_register_rej(struct hnb_context *ctx)
+{
+ HNBRegisterReject_t reject_out;
+ HNBRegisterRejectIEs_t reject;
+ struct msgb *msg;
+ int rc;
+
+ reject.presenceMask = 0,
+ reject.cause.present = Cause_PR_radioNetwork;
+ reject.cause.choice.radioNetwork = CauseRadioNetwork_unspecified;
+
+ /* encode the Information Elements */
+ memset(&reject_out, 0, sizeof(reject_out));
+ rc = hnbap_encode_hnbregisterrejecties(&reject_out, &reject);
+ if (rc < 0) {
+ LOGP(DHNBAP, LOGL_ERROR, "Failure to encode HNB-REGISTER-REJECT to %s: rc=%d\n",
+ ctx->identity_info, rc);
+ return rc;
+ }
+
+ /* generate a successfull outcome PDU */
+ msg = hnbap_generate_unsuccessful_outcome(ProcedureCode_id_HNBRegister,
+ Criticality_reject,
+ &asn_DEF_HNBRegisterReject,
+ &reject_out);
+
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_HNBRegisterReject, &reject_out);
+
+ rc = hnbgw_hnbap_tx(ctx, msg);
+ if (rc == 0) {
+ /* Tell libosmo-netif to destroy this connection when it is done
+ * sending our HNB-REGISTER-REJECT response. */
+ osmo_stream_srv_set_flush_and_destroy(ctx->conn);
+ } else {
+ /* The message was not queued. Destroy the connection right away. */
+ hnb_context_release(ctx, true);
+ }
+}
+
static int hnbgw_tx_hnb_register_acc(struct hnb_context *ctx)
{
HNBRegisterAccept_t accept_out;
@@ -63,6 +103,8 @@ static int hnbgw_tx_hnb_register_acc(struct hnb_context *ctx)
memset(&accept_out, 0, sizeof(accept_out));
rc = hnbap_encode_hnbregisteraccepties(&accept_out, &accept);
if (rc < 0) {
+ LOGP(DHNBAP, LOGL_ERROR, "Failure to encode HNB-REGISTER-ACCEPT to %s: rc=%d\n",
+ ctx->identity_info, rc);
return rc;
}
@@ -355,23 +397,27 @@ static int hnbgw_rx_hnb_deregister(struct hnb_context *ctx, ANY_t *in)
if (rc < 0)
return rc;
- DEBUGP(DHNBAP, "HNB-DE-REGISTER cause=%ld\n",
- ies.cause);
+ DEBUGP(DHNBAP, "HNB-DE-REGISTER cause=%s\n",
+ hnbap_cause_str(&ies.cause));
hnbap_free_hnbde_registeries(&ies);
- hnb_context_release(ctx);
+ hnb_context_release(ctx, true);
return 0;
}
static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in)
{
+ struct hnb_context *hnb;
HNBRegisterRequestIEs_t ies;
int rc;
rc = hnbap_decode_hnbregisterrequesties(&ies, in);
- if (rc < 0)
+ if (rc < 0) {
+ LOGP(DHNBAP, LOGL_ERROR, "Failure to decode HNB-REGISTER-REQ from %s: rc=%d\n",
+ ctx->identity_info, rc);
return rc;
+ }
/* copy all identity parameters from the message to ctx */
asn1_strncpy(ctx->identity_info, &ies.hnB_Identity.hNB_Identity_Info,
@@ -380,8 +426,21 @@ static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in)
ctx->id.sac = asn1str_to_u16(&ies.sac);
ctx->id.rac = asn1str_to_u8(&ies.rac);
ctx->id.cid = asn1bitstr_to_u28(&ies.cellIdentity);
- //ctx->id.mcc FIXME
- //ctx->id.mnc FIXME
+ gsm48_mcc_mnc_from_bcd(ies.plmNidentity.buf, &ctx->id.mcc, &ctx->id.mnc);
+
+ llist_for_each_entry(hnb, &ctx->gw->hnb_list, list) {
+ if (hnb->hnb_registered && ctx != hnb && memcmp(&ctx->id, &hnb->id, sizeof(ctx->id)) == 0) {
+ struct osmo_fd *ofd = osmo_stream_srv_get_ofd(ctx->conn);
+ char *name = osmo_sock_get_name(ctx, ofd->fd);
+ LOGP(DHNBAP, LOGL_ERROR, "rejecting HNB-REGISTER-REQ with duplicate cell identity "
+ "MCC=%u,MNC=%u,LAC=%u,RAC=%u,SAC=%u,CID=%u from %s\n",
+ ctx->id.mcc, ctx->id.mnc, ctx->id.lac, ctx->id.rac, ctx->id.sac, ctx->id.cid, name);
+ talloc_free(name);
+ return hnbgw_tx_hnb_register_rej(ctx);
+ }
+ }
+
+ ctx->hnb_registered = true;
DEBUGP(DHNBAP, "HNB-REGISTER-REQ from %s\n", ctx->identity_info);
@@ -457,7 +516,7 @@ static int hnbgw_rx_ue_deregister(struct hnb_context *ctx, ANY_t *in)
ctxid = asn1bitstr_to_u24(&ies.context_ID);
- DEBUGP(DHNBAP, "UE-DE-REGISTER context=%ld cause=%s\n",
+ DEBUGP(DHNBAP, "UE-DE-REGISTER context=%u cause=%s\n",
ctxid, hnbap_cause_str(&ies.cause));
ue = ue_context_by_id(ctx->gw, ctxid);
@@ -486,7 +545,7 @@ static int hnbgw_rx_err_ind(struct hnb_context *hnb, ANY_t *in)
static int hnbgw_rx_initiating_msg(struct hnb_context *hnb, InitiatingMessage_t *imsg)
{
- int rc;
+ int rc = 0;
switch (imsg->procedureCode) {
case ProcedureCode_id_HNBRegister: /* 8.2 */
@@ -517,16 +576,24 @@ static int hnbgw_rx_initiating_msg(struct hnb_context *hnb, InitiatingMessage_t
imsg->procedureCode);
break;
}
+
+ return rc;
}
static int hnbgw_rx_successful_outcome_msg(struct hnb_context *hnb, SuccessfulOutcome_t *msg)
{
-
+ /* We don't care much about HNBAP */
+ return 0;
}
static int hnbgw_rx_unsuccessful_outcome_msg(struct hnb_context *hnb, UnsuccessfulOutcome_t *msg)
{
-
+ /* We don't care much about HNBAP */
+ LOGP(DHNBAP, LOGL_ERROR, "Received Unsuccessful Outcome, procedureCode %ld, criticality %ld,"
+ " from '%s', cell mcc %u mnc %u lac %u rac %u sac %u cid %u\n",
+ msg->procedureCode, msg->criticality, hnb->identity_info,
+ hnb->id.mcc, hnb->id.mnc, hnb->id.lac, hnb->id.rac, hnb->id.sac, hnb->id.cid);
+ return 0;
}
@@ -581,5 +648,5 @@ int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg)
int hnbgw_hnbap_init(void)
{
-
+ return 0;
}
diff --git a/src/hnbgw_ranap.c b/src/hnbgw_ranap.c
index 7fd6d0a..6822752 100644
--- a/src/hnbgw_ranap.c
+++ b/src/hnbgw_ranap.c
@@ -77,7 +77,7 @@ static int ranap_rx_init_reset(struct hnb_context *hnb, ANY_t *in)
static int ranap_rx_error_ind(struct hnb_context *hnb, ANY_t *in)
{
RANAP_ErrorIndicationIEs_t ies;
- int rc, is_ps = 0;
+ int rc;
rc = ranap_decode_errorindicationies(&ies, in);
if (rc < 0)
@@ -92,35 +92,9 @@ static int ranap_rx_error_ind(struct hnb_context *hnb, ANY_t *in)
return 0;
}
-static int ranap_rx_dt(struct hnb_context *hnb, ANY_t *in)
-{
- RANAP_DirectTransferIEs_t ies;
- int sapi = 0;
- int rc;
-
- rc = ranap_decode_directtransferies(&ies, in);
- if (rc < 0)
- return rc;
-
- if (ies.presenceMask & DIRECTTRANSFERIES_RANAP_SAPI_PRESENT)
- sapi = ies.sapi;
-
- if (ies.presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) {
- /* FIXME: Update LAI associated with UE */
- }
-
- if (ies.presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) {
- /* FIXME: Update RAC associated with UE */
- }
-
- DEBUGP(DRANAP, "DirectTransfer: %s\n",
- osmo_hexdump(ies.nas_pdu.buf, ies.nas_pdu.size));
- /* FIXME: hand NAS PDU into MSC */
-}
-
static int ranap_rx_initiating_msg(struct hnb_context *hnb, RANAP_InitiatingMessage_t *imsg)
{
- int rc;
+ int rc = 0;
/* according tot the spec, we can primarily receive Overload,
* Reset, Reset ACK, Error Indication, reset Resource, Reset
@@ -144,19 +118,19 @@ static int ranap_rx_initiating_msg(struct hnb_context *hnb, RANAP_InitiatingMess
case RANAP_ProcedureCode_id_DirectInformationTransfer:
case RANAP_ProcedureCode_id_UplinkInformationExchange:
LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
- "Procedure %u from HNB, ignoring\n", imsg->procedureCode);
+ "Procedure %lu from HNB, ignoring\n", imsg->procedureCode);
break;
default:
LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
- "Procedure %u from HNB, ignoring\n", imsg->procedureCode);
+ "Procedure %lu from HNB, ignoring\n", imsg->procedureCode);
break;
}
+
+ return rc;
}
static int ranap_rx_successful_msg(struct hnb_context *hnb, RANAP_SuccessfulOutcome_t *imsg)
{
- int rc;
-
/* according tot the spec, we can primarily receive Overload,
* Reset, Reset ACK, Error Indication, reset Resource, Reset
* Resurce Acknowledge as connecitonless RANAP. There are some
@@ -172,20 +146,22 @@ static int ranap_rx_successful_msg(struct hnb_context *hnb, RANAP_SuccessfulOutc
case RANAP_ProcedureCode_id_DirectInformationTransfer:
case RANAP_ProcedureCode_id_UplinkInformationExchange:
LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
- "Procedure %u from HNB, ignoring\n", imsg->procedureCode);
+ "Procedure %lu from HNB, ignoring\n", imsg->procedureCode);
break;
default:
LOGP(DRANAP, LOGL_NOTICE, "Received suspicious RANAP "
- "Procedure %u from HNB, ignoring\n", imsg->procedureCode);
+ "Procedure %lu from HNB, ignoring\n", imsg->procedureCode);
break;
}
+
+ return 0;
}
static int _hnbgw_ranap_rx(struct hnb_context *hnb, RANAP_RANAP_PDU_t *pdu)
{
- int rc;
+ int rc = 0;
switch (pdu->present) {
case RANAP_RANAP_PDU_PR_initiatingMessage:
@@ -196,7 +172,7 @@ static int _hnbgw_ranap_rx(struct hnb_context *hnb, RANAP_RANAP_PDU_t *pdu)
break;
case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
LOGP(DRANAP, LOGL_NOTICE, "Received unsupported RANAP "
- "unsuccessful outcome procedure %u from HNB, ignoring\n",
+ "unsuccessful outcome procedure %lu from HNB, ignoring\n",
pdu->choice.unsuccessfulOutcome.procedureCode);
break;
default:
@@ -204,6 +180,8 @@ static int _hnbgw_ranap_rx(struct hnb_context *hnb, RANAP_RANAP_PDU_t *pdu)
"presence %u from HNB, ignoring\n", pdu->present);
break;
}
+
+ return rc;
}
@@ -228,5 +206,5 @@ int hnbgw_ranap_rx(struct msgb *msg, uint8_t *data, size_t len)
int hnbgw_ranap_init(void)
{
-
+ return 0;
}
diff --git a/src/hnbgw_rua.c b/src/hnbgw_rua.c
index 95979f5..40d1d94 100644
--- a/src/hnbgw_rua.c
+++ b/src/hnbgw_rua.c
@@ -24,6 +24,7 @@
#include <osmocom/netif/stream.h>
#include <osmocom/sigtran/sccp_sap.h>
+#include <osmocom/sigtran/sccp_helpers.h>
#include <unistd.h>
#include <errno.h>
@@ -180,10 +181,11 @@ static int rua_to_scu(struct hnb_context *hnb,
{
struct msgb *msg;
struct osmo_scu_prim *prim;
- struct hnbgw_context_map *map;
+ struct hnbgw_context_map *map = NULL;
struct hnbgw_cnlink *cn = hnb->gw->sccp.cnlink;
struct osmo_sccp_addr *remote_addr;
bool is_ps;
+ bool release_context_map = false;
int rc;
switch (cN_DomainIndicator) {
@@ -196,7 +198,7 @@ static int rua_to_scu(struct hnb_context *hnb,
is_ps = true;
break;
default:
- LOGP(DRUA, LOGL_ERROR, "Unsupported Domain %u\n",
+ LOGP(DRUA, LOGL_ERROR, "Unsupported Domain %ld\n",
cN_DomainIndicator);
return -1;
}
@@ -211,13 +213,21 @@ static int rua_to_scu(struct hnb_context *hnb,
prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim));
osmo_prim_init(&prim->oph, SCCP_SAP_USER, type, PRIM_OP_REQUEST, msg);
- map = context_map_alloc_by_hnb(hnb, context_id, is_ps, cn);
- OSMO_ASSERT(map);
-
- DEBUGP(DRUA, "rua_to_scu() %s to %s, rua_ctx_id %u scu_conn_id %u\n",
- cn_domain_indicator_to_str(cN_DomainIndicator),
- osmo_sccp_addr_dump(remote_addr),
- map->rua_ctx_id, map->scu_conn_id);
+ switch (type) {
+ case OSMO_SCU_PRIM_N_UNITDATA:
+ DEBUGP(DRUA, "rua_to_scu() %s to %s, rua_ctx_id %u (unitdata, no scu_conn_id)\n",
+ cn_domain_indicator_to_str(cN_DomainIndicator),
+ osmo_sccp_addr_dump(remote_addr),
+ context_id);
+ break;
+ default:
+ map = context_map_alloc_by_hnb(hnb, context_id, is_ps, cn);
+ OSMO_ASSERT(map);
+ DEBUGP(DRUA, "rua_to_scu() %s to %s, rua_ctx_id %u scu_conn_id %u\n",
+ cn_domain_indicator_to_str(cN_DomainIndicator),
+ osmo_sccp_addr_dump(remote_addr),
+ map->rua_ctx_id, map->scu_conn_id);
+ }
/* add primitive header */
switch (type) {
@@ -238,6 +248,7 @@ static int rua_to_scu(struct hnb_context *hnb,
case OSMO_SCU_PRIM_N_DISCONNECT:
prim->u.disconnect.conn_id = map->scu_conn_id;
prim->u.disconnect.cause = cause;
+ release_context_map = true;
break;
case OSMO_SCU_PRIM_N_UNITDATA:
prim->u.unitdata.called_addr = *remote_addr;
@@ -260,6 +271,9 @@ static int rua_to_scu(struct hnb_context *hnb,
rc = osmo_sccp_user_sap_down(cn->sccp_user, &prim->oph);
+ if (map && release_context_map)
+ context_map_deactivate(map);
+
return rc;
}
@@ -347,7 +361,7 @@ static int rua_rx_init_connect(struct msgb *msg, ANY_t *in)
rc = rua_to_scu(hnb, ies.cN_DomainIndicator, OSMO_SCU_PRIM_N_CONNECT,
context_id, 0, ies.ranaP_Message.buf,
ies.ranaP_Message.size);
- /* FIXME: what to do with the asn1c-allocated memory */
+
rua_free_connecties(&ies);
return rc;
@@ -382,7 +396,6 @@ static int rua_rx_init_disconnect(struct msgb *msg, ANY_t *in)
OSMO_SCU_PRIM_N_DISCONNECT,
context_id, scu_cause, ranap_data, ranap_len);
- /* FIXME: what to do with the asn1c-allocated memory */
rua_free_disconnecties(&ies);
return rc;
@@ -409,7 +422,6 @@ static int rua_rx_init_dt(struct msgb *msg, ANY_t *in)
context_id, 0, ies.ranaP_Message.buf,
ies.ranaP_Message.size);
- /* FIXME: what to do with the asn1c-allocated memory */
rua_free_directtransferies(&ies);
return rc;
@@ -418,7 +430,6 @@ static int rua_rx_init_dt(struct msgb *msg, ANY_t *in)
static int rua_rx_init_udt(struct msgb *msg, ANY_t *in)
{
RUA_ConnectionlessTransferIEs_t ies;
- RUA_CN_DomainIndicator_t domain;
int rc;
rc = rua_decode_connectionlesstransferies(&ies, in);
@@ -483,7 +494,7 @@ static int rua_rx_initiating_msg(struct msgb *msg, RUA_InitiatingMessage_t *imsg
rc = 0;
break;
default:
- LOGP(DRUA, LOGL_NOTICE, "Unknown RUA Procedure %u\n",
+ LOGP(DRUA, LOGL_NOTICE, "Unknown RUA Procedure %lu\n",
imsg->procedureCode);
rc = -1;
}
diff --git a/src/hnbgw_vty.c b/src/hnbgw_vty.c
index ddea578..859cd31 100644
--- a/src/hnbgw_vty.c
+++ b/src/hnbgw_vty.c
@@ -18,6 +18,9 @@
*
*/
+#include <string.h>
+
+#include <osmocom/core/socket.h>
#include <osmocom/vty/command.h>
#include <osmocom/iuh/vty.h>
@@ -25,6 +28,8 @@
#include <osmocom/iuh/hnbgw.h>
#include <osmocom/iuh/context_map.h>
#include <osmocom/sigtran/protocol/sua.h>
+#include <osmocom/sigtran/sccp_helpers.h>
+#include <osmocom/netif/stream.h>
static void *tall_hnb_ctx = NULL;
static struct hnb_gw *g_hnb_gw = NULL;
@@ -106,20 +111,88 @@ int hnbgw_vty_go_parent(struct vty *vty)
return vty->node;
}
+DEFUN(show_cnlink, show_cnlink_cmd, "show cnlink",
+ SHOW_STR "Display information on core network link\n")
+{
+ struct osmo_ss7_route *rt;
+ struct osmo_ss7_instance *ss7 = osmo_sccp_get_ss7(g_hnb_gw->sccp.client);
+ int i;
+#define GUARD(STR) \
+ STR ? STR : "", \
+ STR ? ":" : ""
+
+ vty_out(vty, "IuCS: %s <->",
+ osmo_sccp_user_name(g_hnb_gw->sccp.cnlink->sccp_user));
+ vty_out(vty, " %s%s%s%s",
+ GUARD(g_hnb_gw->config.iucs_remote_addr_name),
+ osmo_sccp_inst_addr_name(g_hnb_gw->sccp.client, &g_hnb_gw->sccp.iucs_remote_addr),
+ VTY_NEWLINE);
+
+ rt = osmo_ss7_route_lookup(ss7, g_hnb_gw->sccp.iucs_remote_addr.pc);
+ vty_out(vty, " SS7 route: %s%s", osmo_ss7_route_name(rt, true), VTY_NEWLINE);
+
+ vty_out(vty, "IuPS: %s <->",
+ osmo_sccp_user_name(g_hnb_gw->sccp.cnlink->sccp_user));
+ vty_out(vty, " %s%s%s%s",
+ GUARD(g_hnb_gw->config.iups_remote_addr_name),
+ osmo_sccp_inst_addr_name(g_hnb_gw->sccp.client, &g_hnb_gw->sccp.iups_remote_addr),
+ VTY_NEWLINE);
+
+ rt = osmo_ss7_route_lookup(ss7, g_hnb_gw->sccp.iups_remote_addr.pc);
+ vty_out(vty, " SS7 route: %s%s", osmo_ss7_route_name(rt, true), VTY_NEWLINE);
+
+#undef GUARD
+ return CMD_SUCCESS;
+}
+
+static void vty_out_ofd_addr(struct vty *vty, struct osmo_fd *ofd)
+{
+ char *name;
+ if (!ofd || ofd->fd < 0
+ || !(name = osmo_sock_get_name(vty, ofd->fd))) {
+ vty_out(vty, "(no addr)");
+ return;
+ }
+ vty_out(vty, "%s", name);
+ talloc_free(name);
+}
+
+static void vty_dump_hnb_info__map_states(struct vty *vty, const char *name, unsigned int count,
+ unsigned int state_count[])
+{
+ unsigned int i;
+ if (!count)
+ return;
+ vty_out(vty, " %s: %u contexts:", name, count);
+ for (i = 0; i <= MAP_S_NUM_STATES; i++) {
+ if (!state_count[i])
+ continue;
+ vty_out(vty, " %s:%u", hnbgw_context_map_state_name(i), state_count[i]);
+ }
+ vty_out(vty, VTY_NEWLINE);
+}
+
static void vty_dump_hnb_info(struct vty *vty, struct hnb_context *hnb)
{
struct hnbgw_context_map *map;
+ unsigned int map_count[2] = {};
+ unsigned int state_count[2][MAP_S_NUM_STATES + 1] = {};
- vty_out(vty, "HNB \"%s\" MCC %u MNC %u LAC %u RAC %u SAC %u CID %u%s", hnb->identity_info,
- hnb->id.mcc, hnb->id.mnc, hnb->id.lac, hnb->id.rac, hnb->id.sac, hnb->id.cid,
- VTY_NEWLINE);
- vty_out(vty, " HNBAP ID %u RUA ID %u%s", hnb->hnbap_stream, hnb->rua_stream, VTY_NEWLINE);
+ vty_out(vty, "HNB ");
+ vty_out_ofd_addr(vty, hnb->conn? osmo_stream_srv_get_ofd(hnb->conn) : NULL);
+ vty_out(vty, " \"%s\"%s", hnb->identity_info, VTY_NEWLINE);
+ vty_out(vty, " MCC %u MNC %u LAC %u RAC %u SAC %u CID %u SCTP-stream:HNBAP=%u,RUA=%u%s",
+ hnb->id.mcc, hnb->id.mnc, hnb->id.lac, hnb->id.rac, hnb->id.sac, hnb->id.cid,
+ hnb->hnbap_stream, hnb->rua_stream, VTY_NEWLINE);
llist_for_each_entry(map, &hnb->map_list, hnb_list) {
- vty_out(vty, " Map %u->%u (RUA->SUA) cnlink=%p state=%u%s", map->rua_ctx_id, map->scu_conn_id,
- map->cn_link, map->state, VTY_NEWLINE);
-
+ map_count[map->is_ps? 1 : 0]++;
+ state_count[map->is_ps? 1 : 0]
+ [(map->state >= 0 && map->state < MAP_S_NUM_STATES)?
+ map->state : MAP_S_NUM_STATES]++;
}
+ vty_dump_hnb_info__map_states(vty, "IuCS", map_count[0], state_count[0]);
+ vty_dump_hnb_info__map_states(vty, "IuPS", map_count[1], state_count[1]);
}
static void vty_dump_ue_info(struct vty *vty, struct ue_context *ue)
@@ -130,11 +203,20 @@ static void vty_dump_ue_info(struct vty *vty, struct ue_context *ue)
DEFUN(show_hnb, show_hnb_cmd, "show hnb all", SHOW_STR "Display information about a HNB")
{
struct hnb_context *hnb;
+ unsigned int count = 0;
+
+ if (llist_empty(&g_hnb_gw->hnb_list)) {
+ vty_out(vty, "No HNB connected%s", VTY_NEWLINE);
+ return CMD_SUCCESS;
+ }
llist_for_each_entry(hnb, &g_hnb_gw->hnb_list, list) {
vty_dump_hnb_info(vty, hnb);
+ count++;
}
+ vty_out(vty, "%u HNB connected%s", count, VTY_NEWLINE);
+
return CMD_SUCCESS;
}
@@ -157,6 +239,17 @@ DEFUN(show_talloc, show_talloc_cmd, "show talloc", SHOW_STR "Display talloc info
return CMD_SUCCESS;
}
+DEFUN(cfg_hnbgw_rnc_id, cfg_hnbgw_rnc_id_cmd,
+ "rnc-id <0-65535>",
+ "Configure the HNBGW's RNC Id, the common RNC Id used for all connected hNodeB. It is sent to"
+ " each hNodeB upon HNBAP HNB-Register-Accept, and the hNodeB will subsequently send this as"
+ " RANAP InitialUE Messages' GlobalRNC-ID IE. Takes effect as soon as the hNodeB re-registers.\n"
+ "RNC Id value\n")
+{
+ g_hnb_gw->config.rnc_id = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
DEFUN(cfg_hnbgw_iuh_local_ip, cfg_hnbgw_iuh_local_ip_cmd, "local-ip A.B.C.D",
"Accept Iuh connections on local interface\n"
"Local interface IP address (default: " HNBGW_LOCAL_IP_DEFAULT ")")
@@ -233,9 +326,6 @@ static int config_write_hnbgw_iuh(struct vty *vty)
static int config_write_hnbgw_iucs(struct vty *vty)
{
- const char *addr;
- uint16_t port;
-
if (!g_hnb_gw->config.iucs_remote_addr_name)
return CMD_SUCCESS;
@@ -248,9 +338,6 @@ static int config_write_hnbgw_iucs(struct vty *vty)
static int config_write_hnbgw_iups(struct vty *vty)
{
- const char *addr;
- uint16_t port;
-
if (!g_hnb_gw->config.iups_remote_addr_name)
return CMD_SUCCESS;
@@ -268,11 +355,11 @@ void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx)
install_element(CONFIG_NODE, &cfg_hnbgw_cmd);
install_node(&hnbgw_node, config_write_hnbgw);
- vty_install_default(HNBGW_NODE);
+
+ install_element(HNBGW_NODE, &cfg_hnbgw_rnc_id_cmd);
install_element(HNBGW_NODE, &cfg_hnbgw_iuh_cmd);
install_node(&iuh_node, config_write_hnbgw_iuh);
- vty_install_default(IUH_NODE);
install_element(IUH_NODE, &cfg_hnbgw_iuh_local_ip_cmd);
install_element(IUH_NODE, &cfg_hnbgw_iuh_local_port_cmd);
@@ -280,16 +367,15 @@ void hnbgw_vty_init(struct hnb_gw *gw, void *tall_ctx)
install_element(HNBGW_NODE, &cfg_hnbgw_iucs_cmd);
install_node(&iucs_node, config_write_hnbgw_iucs);
- vty_install_default(IUCS_NODE);
install_element(IUCS_NODE, &cfg_hnbgw_iucs_remote_addr_cmd);
install_element(HNBGW_NODE, &cfg_hnbgw_iups_cmd);
install_node(&iups_node, config_write_hnbgw_iups);
- vty_install_default(IUPS_NODE);
install_element(IUPS_NODE, &cfg_hnbgw_iups_remote_addr_cmd);
+ install_element_ve(&show_cnlink_cmd);
install_element_ve(&show_hnb_cmd);
install_element_ve(&show_ue_cmd);
install_element_ve(&show_talloc_cmd);
diff --git a/src/iu_client.c b/src/iu_client.c
index 17d955d..4aecfec 100644
--- a/src/iu_client.c
+++ b/src/iu_client.c
@@ -25,12 +25,16 @@
#include <string.h>
#include <stdbool.h>
+#include <asn1c/asn1helpers.h>
+
#include <osmocom/ranap/iu_client.h>
#include <osmocom/core/logging.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/gprs/gprs_msgb.h>
#include <osmocom/sigtran/sccp_sap.h>
+#include <osmocom/sigtran/sccp_helpers.h>
+#include <osmocom/ranap/ranap_common_cn.h>
#include <osmocom/ranap/ranap_ies_defs.h>
#include <osmocom/ranap/ranap_msg_factory.h>
@@ -38,11 +42,19 @@
* PLMN identity is a BCD representation of the MCC and MNC.
* See iu_grnc_id_parse(). */
struct iu_grnc_id {
- uint16_t mcc;
- uint16_t mnc;
+ struct osmo_plmn_id plmn;
uint16_t rnc_id;
};
+struct iu_lac_rac_entry {
+ struct llist_head entry;
+
+ /* LAC: Location Area Code (for CS and PS) */
+ uint16_t lac;
+ /* RAC: Routing Area Code (for PS only) */
+ uint8_t rac;
+};
+
/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has
* called us and is currently reachable at the given osmo_sccp_addr. So, when we
* know a LAC for a subscriber, we can page it at the RNC matching that LAC or
@@ -54,9 +66,10 @@ struct ranap_iu_rnc {
struct llist_head entry;
uint16_t rnc_id;
- uint16_t lac; /* Location Area Code (used for CS and PS) */
- uint8_t rac; /* Routing Area Code (used for PS only) */
struct osmo_sccp_addr sccp_addr;
+
+ /* A list of struct iu_lac_rac_entry */
+ struct llist_head lac_rac_list;
};
void *talloc_iu_ctx;
@@ -78,6 +91,9 @@ int iu_log_subsystem = 0;
#define LOGPIU(level, fmt, args...) \
LOGP(iu_log_subsystem, level, fmt, ## args)
+#define LOGPIUC(level, fmt, args...) \
+ LOGPC(iu_log_subsystem, level, fmt, ## args)
+
static LLIST_HEAD(ue_conn_ctx_list);
static LLIST_HEAD(rnc_list);
@@ -115,53 +131,109 @@ static struct ranap_ue_conn_ctx *ue_conn_ctx_find(uint32_t conn_id)
return NULL;
}
-static struct ranap_iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac,
- struct osmo_sccp_addr *addr)
+static struct ranap_iu_rnc *iu_rnc_alloc(uint16_t rnc_id, struct osmo_sccp_addr *addr)
{
struct ranap_iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct ranap_iu_rnc);
+ OSMO_ASSERT(rnc);
+
+ INIT_LLIST_HEAD(&rnc->lac_rac_list);
rnc->rnc_id = rnc_id;
- rnc->lac = lac;
- rnc->rac = rac;
rnc->sccp_addr = *addr;
llist_add(&rnc->entry, &rnc_list);
- LOGPIU(LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n",
- rnc->rnc_id, rnc->lac, rnc->rac);
+ LOGPIU(LOGL_NOTICE, "New RNC %d at %s\n", rnc->rnc_id, osmo_sccp_addr_dump(addr));
return rnc;
}
+/* Find a match for the given LAC (and RAC). For CS, pass rac as 0.
+ * If rnc and lre pointers are not NULL, *rnc / *lre are set to NULL if no match is found, or to the
+ * match if a match is found. Return true if a match is found. */
+static bool iu_rnc_lac_rac_find(struct ranap_iu_rnc **rnc, struct iu_lac_rac_entry **lre,
+ uint16_t lac, uint8_t rac)
+{
+ struct ranap_iu_rnc *r;
+ struct iu_lac_rac_entry *e;
+
+ if (rnc)
+ *rnc = NULL;
+ if (lre)
+ *lre = NULL;
+
+ llist_for_each_entry(r, &rnc_list, entry) {
+ llist_for_each_entry(e, &r->lac_rac_list, entry) {
+ if (e->lac == lac && e->rac == rac) {
+ if (rnc)
+ *rnc = r;
+ if (lre)
+ *lre = e;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static struct ranap_iu_rnc *iu_rnc_id_find(uint16_t rnc_id)
+{
+ struct ranap_iu_rnc *rnc;
+ llist_for_each_entry(rnc, &rnc_list, entry) {
+ if (rnc->rnc_id == rnc_id)
+ return rnc;
+ }
+ return NULL;
+}
+
+static bool same_sccp_addr(struct osmo_sccp_addr *a, struct osmo_sccp_addr *b)
+{
+ char buf[256];
+ osmo_strlcpy(buf, osmo_sccp_addr_dump(a), sizeof(buf));
+ return !strcmp(buf, osmo_sccp_addr_dump(b));
+}
+
static struct ranap_iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac,
uint8_t rac, struct osmo_sccp_addr *addr)
{
struct ranap_iu_rnc *rnc;
- llist_for_each_entry(rnc, &rnc_list, entry) {
- if (rnc->rnc_id != rnc_id)
- continue;
-
- /* We have this RNC Id registered already. Make sure that the
- * details match. */
-
- /* TODO should a mismatch be an error? */
- if (rnc->lac != lac || rnc->rac != rac)
- LOGPIU(LOGL_NOTICE, "RNC %d changes its details:"
- " LAC=%d RAC=%d --> LAC=%d RAC=%d\n",
- rnc->rnc_id, rnc->lac, rnc->rac,
- lac, rac);
- rnc->lac = lac;
- rnc->rac = rac;
-
- if (addr && memcmp(&rnc->sccp_addr, addr, sizeof(*addr)))
- LOGPIU(LOGL_NOTICE, "RNC %d on New SCCP Addr %s"
- " (LAC=%d RAC=%d)\n",
- rnc->rnc_id, osmo_sccp_addr_dump(addr), rnc->lac, rnc->rac);
- rnc->sccp_addr = *addr;
- return rnc;
+ struct ranap_iu_rnc *old_rnc;
+ struct iu_lac_rac_entry *lre;
+
+ /* Make sure we know this rnc_id and that this SCCP address is in our records */
+ rnc = iu_rnc_id_find(rnc_id);
+
+ if (rnc) {
+ if (!same_sccp_addr(&rnc->sccp_addr, addr)) {
+ LOGPIU(LOGL_NOTICE, "RNC %u changed its SCCP addr to %s (LAC=%u RAC=%u)\n",
+ rnc_id, osmo_sccp_addr_dump(addr), lac, rac);
+ rnc->sccp_addr = *addr;
+ }
+ } else
+ rnc = iu_rnc_alloc(rnc_id, addr);
+
+ /* Detect whether the LAC,RAC is already recorded in another RNC */
+ iu_rnc_lac_rac_find(&old_rnc, &lre, lac, rac);
+
+ if (old_rnc && old_rnc != rnc) {
+ /* LAC,RAC already exists in a different RNC */
+ LOGPIU(LOGL_NOTICE, "LAC %u RAC %u moved from RNC %u %s",
+ lac, rac, old_rnc->rnc_id, osmo_sccp_addr_dump(&old_rnc->sccp_addr));
+ LOGPIUC(LOGL_NOTICE, " to RNC %u %s\n",
+ rnc->rnc_id, osmo_sccp_addr_dump(&rnc->sccp_addr));
+
+ llist_del(&lre->entry);
+ llist_add(&lre->entry, &rnc->lac_rac_list);
+ } else if (!old_rnc) {
+ /* LAC,RAC not recorded yet */
+ LOGPIU(LOGL_NOTICE, "RNC %u: new LAC %u RAC %u\n", rnc_id, lac, rac);
+ lre = talloc_zero(rnc, struct iu_lac_rac_entry);
+ lre->lac = lac;
+ lre->rac = rac;
+ llist_add(&lre->entry, &rnc->lac_rac_list);
}
+ /* else, LAC,RAC already recorded with the current RNC. */
- /* Not found, make a new one. */
- return iu_rnc_alloc(rnc_id, lac, rac, addr);
+ return rnc;
}
/***********************************************************************
@@ -237,8 +309,7 @@ static int iu_grnc_id_parse(struct iu_grnc_id *dst, struct RANAP_GlobalRNC_ID *s
" should be 3, is %d\n", src->pLMNidentity.size);
return -1;
}
- gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0],
- &dst->mcc, &dst->mnc);
+ osmo_plmn_from_bcd(&src->pLMNidentity.buf[0], &dst->plmn);
dst->rnc_id = (uint16_t)src->rNC_ID;
return 0;
}
@@ -598,69 +669,44 @@ static int iu_tx_paging_cmd(struct osmo_sccp_addr *called_addr,
struct msgb *msg;
msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause);
msg->l2h = msg->data;
- osmo_sccp_tx_unitdata_msg(g_scu, &g_local_sccp_addr, called_addr, msg);
- return 0;
+ return osmo_sccp_tx_unitdata_msg(g_scu, &g_local_sccp_addr, called_addr, msg);
}
-static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi,
+static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptmsi,
uint16_t lac, uint8_t rac, bool is_ps)
{
struct ranap_iu_rnc *rnc;
- int pagings_sent = 0;
-
- if (tmsi_or_ptimsi) {
- LOGPIU(LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s"
- " (paging will use %s %x)\n",
- is_ps? "IuPS" : "IuCS",
- imsi,
- is_ps? "PTMSI" : "TMSI",
- *tmsi_or_ptimsi);
- } else {
- LOGPIU(LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s"
- " (paging will use IMSI)\n",
- is_ps? "IuPS" : "IuCS",
- imsi
- );
- }
-
- llist_for_each_entry(rnc, &rnc_list, entry) {
- if (rnc->lac != lac)
- continue;
- if (is_ps && rnc->rac != rac)
- continue;
-
- /* Found a match! */
- if (iu_tx_paging_cmd(&rnc->sccp_addr, imsi, tmsi_or_ptimsi, is_ps, 0)
- == 0) {
- LOGPIU(LOGL_DEBUG,
- "%s: Paged for IMSI %s on RNC %d, on SCCP addr %s\n",
- is_ps? "IuPS" : "IuCS",
- imsi, rnc->rnc_id, osmo_sccp_addr_dump(&rnc->sccp_addr));
- pagings_sent ++;
+ const char *log_msg;
+ int log_level;
+ int paged = 0;
+
+ iu_rnc_lac_rac_find(&rnc, NULL, lac, rac);
+ if (rnc) {
+ if (iu_tx_paging_cmd(&rnc->sccp_addr, imsi, tmsi_or_ptmsi, is_ps, 0) == 0) {
+ log_msg = "Paging";
+ log_level = LOGL_DEBUG;
+ paged = 1;
+ } else {
+ log_msg = "Paging failed";
+ log_level = LOGL_ERROR;
}
+ } else {
+ log_msg = "Found no RNC to Page";
+ log_level = LOGL_ERROR;
}
- /* Some logging... */
- if (pagings_sent > 0) {
- LOGPIU(LOGL_DEBUG,
- "%s: %d RNCs were paged for IMSI %s.\n",
- is_ps? "IuPS" : "IuCS",
- pagings_sent, imsi);
- }
- else {
- if (is_ps) {
- LOGPIU(LOGL_ERROR, "IuPS: Found no RNC to page for"
- " LAC %d RAC %d (would have paged IMSI %s)\n",
- lac, rac, imsi);
- }
- else {
- LOGPIU(LOGL_ERROR, "IuCS: Found no RNC to page for"
- " LAC %d (would have paged IMSI %s)\n",
- lac, imsi);
- }
- }
+ if (is_ps)
+ LOGPIU(log_level, "IuPS: %s on LAC %d RAC %d", log_msg, lac, rac);
+ else
+ LOGPIU(log_level, "IuCS: %s on LAC %d", log_msg, lac);
+ if (rnc)
+ LOGPIUC(log_level, " at SCCP-addr %s", osmo_sccp_addr_dump(&rnc->sccp_addr));
+ if (tmsi_or_ptmsi)
+ LOGPIUC(log_level, ", for %s %08x\n", is_ps? "PTMSI" : "TMSI", *tmsi_or_ptmsi);
+ else
+ LOGPIUC(log_level, ", for IMSI %s\n", imsi);
- return pagings_sent;
+ return paged;
}
int ranap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac)
@@ -775,4 +821,3 @@ int ranap_iu_init(void *ctx, int log_subsystem, const char *sccp_user_name, stru
return 0;
}
-
diff --git a/src/iu_helpers.c b/src/iu_helpers.c
index 2f44e93..5e78293 100644
--- a/src/iu_helpers.c
+++ b/src/iu_helpers.c
@@ -20,8 +20,12 @@
#include <stdint.h>
#include <string.h>
-
+#include <errno.h>
+#include <arpa/inet.h>
+#include "asn1helpers.h"
#include <osmocom/core/utils.h>
+#include <osmocom/ranap/RANAP_IuTransportAssociation.h>
+#include <osmocom/ranap/RANAP_TransportLayerAddress.h>
/* decode a BCD-string as used inside ASN.1 encoded Iu interface protocols */
int ranap_bcd_decode(char *out, size_t out_len, const uint8_t *in, size_t in_len)
@@ -70,3 +74,50 @@ int ranap_imsi_encode(uint8_t *out, size_t out_len, const char *in)
}
return i;
}
+
+/* decode a network port as used inside ASN.1 encoded Iu interface protocols */
+int ranap_transp_assoc_decode(uint16_t *port, const RANAP_IuTransportAssociation_t *transp_assoc)
+{
+ uint32_t result;
+
+ if (!transp_assoc)
+ return -EINVAL;
+
+ result = asn1bitstr_to_u32((BIT_STRING_t *) & transp_assoc->choice.bindingID);
+
+ /* The lower 16 bits should be zero, otherwise the decoding may
+ * have yielded some odd result */
+ if (result & 0xFFFF)
+ return -EINVAL;
+
+ *port = (uint16_t) ((result >> 16) & 0xFFFF);
+
+ if (*port == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* decode a network address as used inside ASN.1 encoded Iu interface protocols */
+int ranap_transp_layer_addr_decode(char *addr, unsigned int addr_len,
+ const RANAP_TransportLayerAddress_t *trasp_layer_addr)
+{
+ unsigned char *buf;
+ int len;
+ const char *rc;
+
+ buf = trasp_layer_addr->buf;
+ len = trasp_layer_addr->size;
+
+ if (buf[0] == 0x35 && len > 7)
+ rc = inet_ntop(AF_INET, buf + 3, addr, addr_len);
+ else if (len > 3)
+ rc = inet_ntop(AF_INET, buf, addr, addr_len);
+ else
+ return -EINVAL;
+
+ if (!rc)
+ return -EINVAL;
+
+ return 0;
+}
diff --git a/src/ranap_common.c b/src/ranap_common.c
index 13c913f..46203e0 100644
--- a/src/ranap_common.c
+++ b/src/ranap_common.c
@@ -24,6 +24,7 @@
#include <osmocom/gsm/gsm48.h>
#include <osmocom/ranap/ranap_common.h>
+#include <asn1c/asn1helpers.h>
extern int asn1_xer_print;
int _ranap_DRANAP = 0;
@@ -278,7 +279,7 @@ char *ranap_cause_str(const RANAP_Cause_t *cause)
cause->choice.misc));
break;
case RANAP_Cause_PR_non_Standard:
- snprintf(buf, sizeof(buf), "non-standard(%u)",
+ snprintf(buf, sizeof(buf), "non-standard(%ld)",
cause->choice.non_Standard);
break;
default:
@@ -542,7 +543,6 @@ void ranap_set_log_area(int log_area)
int ranap_ip_from_transp_layer_addr(const BIT_STRING_t *in, uint32_t *ip)
{
- uint32_t addr;
uint8_t x213[] = {0x35, 0x00, 0x01};
/* Only support IPv4 for now - plain and with x213 encapsulation */
diff --git a/src/ranap_common_cn.c b/src/ranap_common_cn.c
index d02eb37..d2c875e 100644
--- a/src/ranap_common_cn.c
+++ b/src/ranap_common_cn.c
@@ -319,7 +319,7 @@ int ranap_cn_rx_co(ranap_handle_cb cb, void *ctx, uint8_t *data, size_t len)
static int cn_ranap_rx_initiating_msg_cl(void *ctx, RANAP_InitiatingMessage_t *imsg,
ranap_message *message)
{
- int rc;
+ int rc = 0;
message->procedureCode = imsg->procedureCode;
message->criticality = imsg->criticality;
@@ -360,6 +360,8 @@ static int cn_ranap_rx_initiating_msg_cl(void *ctx, RANAP_InitiatingMessage_t *i
get_value_string(ranap_procedure_code_vals, imsg->procedureCode));
break;
}
+
+ return rc;
}
static void cn_ranap_free_initiating_msg_cl(ranap_message *message)
@@ -403,7 +405,7 @@ static void cn_ranap_free_initiating_msg_cl(ranap_message *message)
static int cn_ranap_rx_successful_msg_cl(void *ctx, RANAP_SuccessfulOutcome_t *imsg,
ranap_message *message)
{
- int rc;
+ int rc = 0;
message->procedureCode = imsg->procedureCode;
message->criticality = imsg->criticality;
@@ -433,6 +435,8 @@ static int cn_ranap_rx_successful_msg_cl(void *ctx, RANAP_SuccessfulOutcome_t *i
get_value_string(ranap_procedure_code_vals, imsg->procedureCode));
break;
}
+
+ return rc;
}
static void cn_ranap_free_successful_msg_cl(ranap_message *message)
@@ -463,7 +467,7 @@ static void cn_ranap_free_successful_msg_cl(ranap_message *message)
static int _cn_ranap_rx_cl(void *ctx, RANAP_RANAP_PDU_t *pdu, ranap_message *message)
{
- int rc;
+ int rc = 0;
/* Extend _cn_ranap_free_cl as well when extending this function */
@@ -488,6 +492,8 @@ static int _cn_ranap_rx_cl(void *ctx, RANAP_RANAP_PDU_t *pdu, ranap_message *mes
get_value_string(ranap_presence_vals, pdu->present));
break;
}
+
+ return rc;
}
static void _cn_ranap_free_cl(ranap_message *message)
@@ -505,7 +511,7 @@ static void _cn_ranap_free_cl(ranap_message *message)
break;
default:
LOGP(DRANAP, LOGL_NOTICE, "Suspicious RANAP "
- "presence %s (CL) from RNC, ignoring\n", message->direction);
+ "presence %d (CL) from RNC, ignoring\n", message->direction);
break;
}
}
diff --git a/src/ranap_msg_factory.c b/src/ranap_msg_factory.c
index 64d87f9..c287f02 100644
--- a/src/ranap_msg_factory.c
+++ b/src/ranap_msg_factory.c
@@ -185,6 +185,10 @@ struct msgb *ranap_new_msg_dt(uint8_t sapi, const uint8_t *nas, unsigned int nas
/* ies -> dt */
rc = ranap_encode_directtransferies(&dt, &ies);
+ if (rc < 0) {
+ LOGP(DRANAP, LOGL_ERROR, "error encoding direct transfer IEs: %d\n", rc);
+ return NULL;
+ }
/* dt -> msg */
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_DirectTransfer,
@@ -251,6 +255,11 @@ struct msgb *ranap_new_msg_sec_mod_cmd(const uint8_t *ik, const uint8_t *ck, enu
if (ck)
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_EncryptionInformation, &ies.encryptionInformation);
+ if (rc < 0) {
+ LOGP(DRANAP, LOGL_ERROR, "error encoding security mode command IEs: %d\n", rc);
+ return NULL;
+ }
+
/* out -> msg */
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_SecurityModeControl,
RANAP_Criticality_reject,
@@ -271,7 +280,7 @@ struct msgb *ranap_new_msg_sec_mod_compl(
RANAP_SecurityModeCompleteIEs_t ies;
RANAP_SecurityModeComplete_t out;
struct msgb *msg;
- int i, rc;
+ int rc;
memset(&ies, 0, sizeof(ies));
memset(&out, 0, sizeof(out));
@@ -282,6 +291,10 @@ struct msgb *ranap_new_msg_sec_mod_compl(
/* ies -> out */
rc = ranap_encode_securitymodecompleteies(&out, &ies);
+ if (rc < 0) {
+ LOGP(DRANAP, LOGL_ERROR, "error encoding security mode complete IEs: %d\n", rc);
+ return NULL;
+ }
/* out -> msg */
msg = ranap_generate_successful_outcome(RANAP_ProcedureCode_id_SecurityModeControl,
@@ -317,10 +330,14 @@ struct msgb *ranap_new_msg_common_id(const char *imsi)
/* ies -> out */
rc = ranap_encode_commonid_ies(&out, &ies);
+
/* release dynamic allocations attached to ies */
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_PermanentNAS_UE_ID, &ies.permanentNAS_UE_ID);
- if (rc < 0)
+
+ if (rc < 0) {
+ LOGP(DRANAP, LOGL_ERROR, "error encoding common id IEs: %d\n", rc);
return NULL;
+ }
/* out -> msg */
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_CommonID,
@@ -349,8 +366,10 @@ struct msgb *ranap_new_msg_iu_rel_cmd(const RANAP_Cause_t *cause_in)
/* ies -> out */
rc = ranap_encode_iu_releasecommandies(&out, &ies);
- if (rc < 0)
+ if (rc < 0) {
+ LOGP(DRANAP, LOGL_ERROR, "error encoding release command IEs: %d\n", rc);
return NULL;
+ }
/* out -> msg */
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_Iu_Release,
@@ -377,8 +396,10 @@ struct msgb *ranap_new_msg_iu_rel_compl(void)
/* ies -> out */
rc = ranap_encode_iu_releasecompleteies(&out, &ies);
- if (rc < 0)
+ if (rc < 0) {
+ LOGP(DRANAP, LOGL_ERROR, "error encoding release complete IEs: %d\n", rc);
return NULL;
+ }
/* out -> msg */
msg = ranap_generate_successful_outcome(RANAP_ProcedureCode_id_Iu_Release,
@@ -434,11 +455,15 @@ struct msgb *ranap_new_msg_paging_cmd(const char *imsi, const uint32_t *tmsi, in
/* ies -> out */
rc = ranap_encode_pagingies(&out, &ies);
+
/* release dynamic allocation attached to ies */
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_PermanentNAS_UE_ID, &ies.permanentNAS_UE_ID);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_TemporaryUE_ID, &ies.temporaryUE_ID);
- if (rc < 0)
+
+ if (rc < 0) {
+ LOGP(DRANAP, LOGL_ERROR, "error encoding paging IEs: %d\n", rc);
return NULL;
+ }
/* out -> msg */
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_Paging,
@@ -638,6 +663,7 @@ static void new_transp_layer_addr(BIT_STRING_t *out, uint32_t ip, bool use_x213_
{
uint8_t *buf;
unsigned int len;
+ uint32_t ip_h = ntohl(ip);
if (use_x213_nsap) {
len = 160/8;
@@ -645,11 +671,11 @@ static void new_transp_layer_addr(BIT_STRING_t *out, uint32_t ip, bool use_x213_
buf[0] = 0x35; /* AFI For IANA ICP */
buf[1] = 0x00; /* See A.5.2.1.2.7 of X.213 */
buf[2] = 0x01;
- *(uint32_t *)&buf[3] = ntohl(ip);
+ memcpy(&buf[3], &ip_h, sizeof(ip_h));
} else {
- len = 4;
+ len = sizeof(ip_h);
buf = CALLOC(len, sizeof(uint8_t));
- *(uint32_t *)buf = ntohl(ip);
+ memcpy(buf, &ip_h, sizeof(ip_h));
}
out->buf = buf;
out->size = len;
@@ -716,7 +742,8 @@ static void assign_new_ra_id(RANAP_RAB_ID_t *id, uint8_t rab_id)
/*! \brief generate RANAP RAB ASSIGNMENT REQUEST message for CS (voice).
* See 3GPP TS 25.413 8.2.
- * RAB ID: 3GPP TS 25.413 9.2.1.2
+ * RAB ID: 3GPP TS 25.413 9.2.1.2.
+ * \param rtp_ip MGW's RTP IPv4 address in *network* byte order.
*/
struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id, uint32_t rtp_ip,
uint16_t rtp_port,
@@ -785,7 +812,8 @@ struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id, uint32_t rtp_ip,
return msg;
}
-/*! \brief generate RANAP RAB ASSIGNMENT REQUEST message for PS (data) */
+/*! \brief generate RANAP RAB ASSIGNMENT REQUEST message for PS (data)
+ * \param gtp_ip SGSN's GTP IPv4 address in *network* byte order. */
struct msgb *ranap_new_msg_rab_assign_data(uint8_t rab_id, uint32_t gtp_ip,
uint32_t gtp_tei, bool use_x213_nsap)
{
@@ -876,13 +904,17 @@ struct msgb *ranap_new_msg_iu_rel_req(const RANAP_Cause_t *cause)
memcpy(&ies.cause, cause, sizeof(ies.cause));
rc = ranap_encode_iu_releaserequesties(&out, &ies);
- if (rc < 0)
+ if (rc < 0) {
+ LOGP(DRANAP, LOGL_ERROR, "error encoding release request IEs: %d\n", rc);
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_Iu_ReleaseRequest, &out);
return NULL;
+ }
/* encode the output into the msgb */
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_Iu_ReleaseRequest,
RANAP_Criticality_reject,
&asn_DEF_RANAP_Iu_ReleaseRequest, &out);
+
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_Iu_ReleaseRequest, &out);
return msg;
@@ -912,11 +944,15 @@ struct msgb *ranap_new_msg_rab_rel_req(uint8_t rab_id, const RANAP_Cause_t *caus
/* encoe the list IEs into the output */
rc = ranap_encode_rab_releaserequesties(&out, &ies);
- if (rc < 0)
- return NULL;
+
/* 'out' has been generated, we can release the input */
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_ReleaseList, &ies.raB_ReleaseList);
+ if (rc < 0) {
+ LOGP(DRANAP, LOGL_ERROR, "error encoding release request IEs: %d\n", rc);
+ return NULL;
+ }
+
/* encode the output into the msgb */
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_RAB_ReleaseRequest,
RANAP_Criticality_reject,
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index 28ad56c..493bc18 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -1,4 +1,4 @@
-AM_CFLAGS = -g -I$(top_srcdir)/src/tests \
+AM_CFLAGS = -g -Wall -I$(top_srcdir)/src/tests \
-I$(top_srcdir)/include -I$(top_builddir)/include \
$(OSMOVTY_CFLAGS) $(OSMOCORE_CFLAGS) $(OSMOGSM_CFLAGS) \
$(OSMONETIF_CFLAGS) $(ASN1C_CFLAGS) $(OSMOSIGTRAN_CFLAGS)
diff --git a/src/tests/hnb-test.c b/src/tests/hnb-test.c
index 68a3117..446a14a 100644
--- a/src/tests/hnb-test.c
+++ b/src/tests/hnb-test.c
@@ -267,10 +267,11 @@ int hnb_test_nas_rx_lu_accept(struct gsm48_hdr *gh, int len, int *sent_tmsi)
lai = (struct gsm48_loc_area_id *)&gh->data[0];
- uint16_t mcc, mnc, lac;
- gsm48_decode_lai(lai, &mcc, &mnc, &lac);
- printf("LU: mcc %hd mnc %hd lac %hd\n",
- mcc, mnc, lac);
+ struct osmo_location_area_id laid;
+ gsm48_decode_lai2(lai, &laid);
+ printf("LU: mcc %s mnc %s lac %hd\n",
+ osmo_mcc_name(laid.plmn.mcc), osmo_mnc_name(laid.plmn.mnc, laid.plmn.mnc_3_digits),
+ laid.lac);
struct tlv_parsed tp;
int parse_res;
@@ -904,7 +905,6 @@ static void hnbtest_vty_init(void)
install_element_ve(&chan_cmd);
install_node(&chan_node, NULL);
- vty_install_default(CHAN_NODE);
}
static void handle_options(int argc, char **argv)
diff --git a/src/tests/test-helpers.c b/src/tests/test-helpers.c
index 44fd735..f218a79 100644
--- a/src/tests/test-helpers.c
+++ b/src/tests/test-helpers.c
@@ -105,6 +105,8 @@ void test_asn1_helpers(void)
ASSERT(enc.size == 24/8);
ASSERT(enc.bits_unused == 0);
+ talloc_free(buffer);
+
rc = aper_encode_to_new_buffer(&asn_DEF_BIT_STRING, 0, &enc, (void **) &buffer);
printf("Encoded: %s\n", osmo_hexdump_nospc(buffer, rc));
@@ -118,6 +120,7 @@ void test_asn1_helpers(void)
printf("Decoding large string from asn1: %s\n", text);
ASSERT(rc == 31);
+ talloc_free(buffer);
}
void test_ranap_common(void)
@@ -211,5 +214,6 @@ int main(int argc, char **argv)
test_asn1_helpers();
test_ranap_common();
+ test_common_cleanup();
return 0;
}
diff --git a/src/tests/test-hnbap.c b/src/tests/test-hnbap.c
index ef46070..dfd5ae9 100644
--- a/src/tests/test-hnbap.c
+++ b/src/tests/test-hnbap.c
@@ -142,6 +142,8 @@ void test_asn1_decoding(void)
printf("HNBAP UE Register request from IMSI %s\n", imsi);
hnbap_free_ueregisterrequesties(&ue_req_ies);
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_HNBAP_PDU, pdu);
+
memset(pdu, 0, sizeof(*pdu));
dec_ret = aper_decode(NULL, &asn_DEF_HNBAP_PDU, (void **) &pdu,
hnbap_ue_reg_acc, sizeof(hnbap_ue_reg_acc), 0, 0);
@@ -163,6 +165,7 @@ void test_asn1_decoding(void)
printf("HNBAP UE Register accept to IMSI %s\n", imsi);
hnbap_free_ueregisteraccepties(&ue_acc_ies);
+ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_HNBAP_PDU, pdu);
}
int main(int argc, char **argv)
@@ -175,6 +178,7 @@ int main(int argc, char **argv)
test_asn1_decoding();
+ test_common_cleanup();
return 0;
}
diff --git a/src/tests/test-ranap.c b/src/tests/test-ranap.c
index c1c7003..05be874 100644
--- a/src/tests/test-ranap.c
+++ b/src/tests/test-ranap.c
@@ -197,6 +197,8 @@ int main(int argc, char **argv)
talloc_report(talloc_asn1_ctx, stdout);
talloc_report(tall_msgb_ctx, stdout);
//talloc_report(NULL, stdout);
+
+ test_common_cleanup();
printf("exit\n");
exit(0);
}
diff --git a/src/tests/test_common.c b/src/tests/test_common.c
index c8aafdd..eeb0bec 100644
--- a/src/tests/test_common.c
+++ b/src/tests/test_common.c
@@ -37,6 +37,8 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/logging.h>
+#include <osmocom/ranap/ranap_common.h>
+
#include <osmocom/iuh/hnbgw.h>
void *talloc_asn1_ctx;
@@ -69,11 +71,13 @@ static const struct log_info test_log_info = {
.num_cat = ARRAY_SIZE(log_cat),
};
+static void *msgb_ctx;
+
int test_common_init(void)
{
int rc;
- msgb_talloc_ctx_init(NULL, 0);
+ msgb_ctx = msgb_talloc_ctx_init(NULL, 0);
talloc_asn1_ctx = talloc_named_const(NULL, 0, "asn1_context");
rc = osmo_init_logging(&test_log_info);
@@ -85,3 +89,22 @@ int test_common_init(void)
log_set_print_filename(osmo_stderr_target, 0);
log_set_use_color(osmo_stderr_target, 0);
}
+
+void test_common_cleanup(void)
+{
+ if (talloc_total_blocks(msgb_ctx) != 1
+ || talloc_total_size(msgb_ctx) != 0)
+ talloc_report_full(msgb_ctx, stderr);
+
+ OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
+ OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
+ talloc_free(msgb_ctx);
+
+ if (talloc_total_blocks(talloc_asn1_ctx) != 1
+ || talloc_total_size(talloc_asn1_ctx) != 0)
+ talloc_report_full(talloc_asn1_ctx, stderr);
+
+ OSMO_ASSERT(talloc_total_blocks(talloc_asn1_ctx) == 1);
+ OSMO_ASSERT(talloc_total_size(talloc_asn1_ctx) == 0);
+ talloc_free(talloc_asn1_ctx);
+}
diff --git a/src/tests/test_common.h b/src/tests/test_common.h
index 1af1abd..836d999 100644
--- a/src/tests/test_common.h
+++ b/src/tests/test_common.h
@@ -1,3 +1,4 @@
#pragma once
int test_common_init(void);
+void test_common_cleanup(void);