[PATCH] osmo-iuh[master]: move openbsc.git's iu.h, iu.c, iu_vty.c here as iu_client* N...

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Tue Jul 18 17:27:26 UTC 2017


Hello Harald Welte, Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/3187

to look at the new patch set (#2).

move openbsc.git's iu.h, iu.c, iu_vty.c here as iu_client* NOT FOR MERGE

*** NOT FOR MERGE: use SCCP address book: the libsccp address book code is
currently in flux, will follow in the next patch set when pmaier is ready with
it ***

To help split openbsc.git to separate MSC and SGSN repositories, place the
common Iu interface related code here in libosmo-ranap. Also apply various
improvements while moving (from intermittent code review).

The code depends on libosmo-ranap tightly. One reason to want this separate
from libosmo-ranap could be that it uses libosmo-sigtran, accepting an sccp
instance. However, including in libosmo-ranap is the simplest way to go. The
osmo-iuh build depends on libosmo-sigtran anyway because of OsmoHNBGW, and all
current users of libosmo-ranap also naturally link libosmo-sigtran already.

Apply prefix ranap_iu_ and RANAP_IU_ to allow smooth transition from the
openbsc.git iu_ to the libranap ranap_iu_ implementations.

Prune unneeded #include statements.

Instead of sccp_addr, store an rnc pointer in the ue_conn_ctx. To facilitate,
also:
- Move iu_rnc struct to iu_client.h (as ranap_iu_rnc).
- Instead of sccp_addr, pass rnc to ue_conn_ctx_alloc().
- Pass a local struct new_ue_conn_ctx containing the sccp_addr and conn_id up
  the RANAP handling stack in case of an InitialUE message.
- Separate the InitialUE message handling from cn_ranap_handle_co(), by moving
  to new and separate cn_ranap_handle_co_initial(), so we can still pass a
  looked-up ue_conn_ctx to all other cn_ranap_handle_co() code paths.
- Allocate the ue_conn_ctx only in ranap_handle_co_initial_ue(), not as early
  as before.
Note that we are not actually ever using the rnc pointer now present in
ue_conn_ctx. It could be used for more concise paging, to first page only the
RNC where we last saw the subscriber. So far we page all matching LAC/RACs.

Tweak error logging: use __func__ instead of writing the function names as
string constants.

In iu_client_vty.c:
- Move the asn.1 debug commands from logging over to the iu node. They are not
  specific to the logging target. They could qualify for an entirely separate
  'asn1' root node, but for simplicity place under 'iu'.
- Add the 'asn1' commands to ranap_iu_vty_config_write(), so far missing.
- remove the legacy "net." from a VTY error message, it is not known which name
  the parent node of 'iu' has.

Change-Id: I6a3f7ad15be03fb94689b4af6ccfa828c25f45c0
---
M include/osmocom/ranap/Makefile.am
A include/osmocom/ranap/iu_client.h
M src/Makefile.am
A src/iu_client.c
A src/iu_client_vty.c
5 files changed, 999 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/87/3187/2

diff --git a/include/osmocom/ranap/Makefile.am b/include/osmocom/ranap/Makefile.am
index 0f83e03..1606928 100644
--- a/include/osmocom/ranap/Makefile.am
+++ b/include/osmocom/ranap/Makefile.am
@@ -12,6 +12,7 @@
 	ranap_common_cn.h \
 	ranap_msg_factory.h \
 	iu_helpers.h \
+	iu_client.h \
 	RANAP_AccuracyFulfilmentIndicator.h \
 	RANAP_AllocationOrRetentionPriority.h \
 	RANAP_AlternativeRABConfigurationRequest.h \
diff --git a/include/osmocom/ranap/iu_client.h b/include/osmocom/ranap/iu_client.h
new file mode 100644
index 0000000..873b2d2
--- /dev/null
+++ b/include/osmocom/ranap/iu_client.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <stdbool.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/sigtran/sccp_sap.h>
+
+struct msgb;
+struct osmo_auth_vector;
+
+struct RANAP_RAB_SetupOrModifiedItemIEs_s;
+struct RANAP_Cause;
+
+struct ranap_iu_rnc;
+
+/* Debugging switches from asn1c and osmo-iuh */
+extern int asn_debug;
+extern int asn1_xer_print;
+
+enum ranap_nsap_addr_enc {
+	RANAP_NSAP_ADDR_ENC_X213,
+	RANAP_NSAP_ADDR_ENC_V4RAW,
+};
+
+struct ranap_ue_conn_ctx {
+	struct llist_head list;
+	struct ranap_iu_rnc *rnc;
+	uint32_t conn_id;
+	int integrity_active;
+	struct gprs_ra_id ra_id;
+	enum ranap_nsap_addr_enc rab_assign_addr_enc;
+};
+
+enum ranap_iu_event_type {
+	RANAP_IU_EVENT_RAB_ASSIGN,
+	RANAP_IU_EVENT_SECURITY_MODE_COMPLETE,
+	RANAP_IU_EVENT_IU_RELEASE, /* An actual Iu Release message was received */
+	RANAP_IU_EVENT_LINK_INVALIDATED, /* A SUA link was lost or closed down */
+};
+
+extern const struct value_string ranap_iu_event_type_names[];
+static inline const char *ranap_iu_event_type_str(enum ranap_iu_event_type e)
+{
+	return get_value_string(ranap_iu_event_type_names, e);
+}
+
+/* Implementations of iu_recv_cb_t shall find the ranap_ue_conn_ctx in msg->dst. */
+typedef int (* ranap_iu_recv_cb_t )(struct msgb *msg, struct gprs_ra_id *ra_id,
+				    uint16_t *sai);
+
+typedef int (* ranap_iu_event_cb_t )(struct ranap_ue_conn_ctx *ue_ctx,
+				     enum ranap_iu_event_type type, void *data);
+
+typedef int (* ranap_iu_rab_ass_resp_cb_t )(struct ranap_ue_conn_ctx *ue_ctx, uint8_t rab_id,
+					    struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies);
+
+int ranap_iu_init(void *ctx, int log_subsystem, const char *sccp_user_name, struct osmo_sccp_instance *sccp,
+		  ranap_iu_recv_cb_t iu_recv_cb, ranap_iu_event_cb_t iu_event_cb);
+
+int ranap_iu_tx(struct msgb *msg, uint8_t sapi);
+
+int ranap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac);
+int ranap_iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac);
+
+int ranap_iu_rab_act(struct ranap_ue_conn_ctx *ue_ctx, struct msgb *msg);
+int ranap_iu_rab_deact(struct ranap_ue_conn_ctx *ue_ctx, uint8_t rab_id);
+int ranap_iu_tx_sec_mode_cmd(struct ranap_ue_conn_ctx *uectx, struct osmo_auth_vector *vec,
+			     int send_ck, int new_key);
+int ranap_iu_tx_common_id(struct ranap_ue_conn_ctx *ue_ctx, const char *imsi);
+int ranap_iu_tx_release(struct ranap_ue_conn_ctx *ctx, const struct RANAP_Cause *cause);
+
+void ranap_iu_vty_init(int iu_parent_node, enum ranap_nsap_addr_enc *rab_assign_addr_enc);
+int ranap_iu_vty_config_write(struct vty *vty, const char *indent);
diff --git a/src/Makefile.am b/src/Makefile.am
index bb1ebbd..48918b0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -54,7 +54,7 @@
 libosmo_ranap_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(RANAP_LIBVERSION)
 libosmo_ranap_la_LIBADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(ASN1C_LIBS) $(COMMON_LDADD) 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
+			   ranap_common_cn.c iu_client.c iu_client_vty.c
 
 # build the actual HomeNodeB gateway
 #
diff --git a/src/iu_client.c b/src/iu_client.c
new file mode 100644
index 0000000..83ed276
--- /dev/null
+++ b/src/iu_client.c
@@ -0,0 +1,783 @@
+/* Common parts of IuCS and IuPS interfaces implementation */
+
+/* (C) 2016-2017 by sysmocom s.f.m.c. GmbH <info at sysmocom.de>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.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/ranap/ranap_ies_defs.h>
+#include <osmocom/ranap/ranap_msg_factory.h>
+
+/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the
+ * 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;
+	uint16_t rnc_id;
+};
+
+/* 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
+ * RAC. An HNB-GW typically presents itself as if it were a single RNC, even
+ * though it may have several RNCs in hNodeBs connected to it. Those will then
+ * share the same RNC id, which they actually receive and adopt from the HNB-GW
+ * in the HNBAP HNB REGISTER ACCEPT message. */
+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;
+};
+
+void *talloc_iu_ctx;
+void *talloc_asn1_ctx;
+
+/* Implement the extern asn_debug from libasn1c to indicate whether to print
+ * asn.1 debug messages (see libasn1c). */
+int asn_debug = 0;
+
+/* Implement the extern asn1_xer_print to indicate whether the ASN.1 binary
+ * code decoded and encoded during Iu communication should be logged to stderr
+ * (see asn.1 generated code in osmo-iuh). */
+int asn1_xer_print = 0;
+
+ranap_iu_recv_cb_t global_iu_recv_cb = NULL;
+ranap_iu_event_cb_t global_iu_event_cb = NULL;
+int iu_log_subsystem = 0;
+
+#define LOGPIU(level, fmt, args...) \
+	LOGP(iu_log_subsystem, level, fmt, ## args)
+
+static LLIST_HEAD(ue_conn_ctx_list);
+static LLIST_HEAD(rnc_list);
+
+static struct osmo_sccp_instance *g_sccp;
+static struct osmo_sccp_user *g_scu;
+
+const struct value_string ranap_iu_event_type_names[] = {
+	OSMO_VALUE_STRING(RANAP_IU_EVENT_RAB_ASSIGN),
+	OSMO_VALUE_STRING(RANAP_IU_EVENT_SECURITY_MODE_COMPLETE),
+	OSMO_VALUE_STRING(RANAP_IU_EVENT_IU_RELEASE),
+	OSMO_VALUE_STRING(RANAP_IU_EVENT_LINK_INVALIDATED),
+	{ 0, NULL }
+};
+
+static struct ranap_ue_conn_ctx *ue_conn_ctx_alloc(struct ranap_iu_rnc *rnc, uint32_t conn_id)
+{
+	struct ranap_ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ranap_ue_conn_ctx);
+
+	ctx->rnc = rnc;
+	ctx->conn_id = conn_id;
+	llist_add(&ctx->list, &ue_conn_ctx_list);
+
+	return ctx;
+}
+
+static struct ranap_ue_conn_ctx *ue_conn_ctx_find(uint32_t conn_id)
+{
+	struct ranap_ue_conn_ctx *ctx;
+
+	llist_for_each_entry(ctx, &ue_conn_ctx_list, list) {
+		if (ctx->conn_id == conn_id)
+			return ctx;
+	}
+	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)
+{
+	struct ranap_iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct ranap_iu_rnc);
+
+	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);
+
+	return rnc;
+}
+
+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;
+	}
+
+	/* Not found, make a new one. */
+	return iu_rnc_alloc(rnc_id, lac, rac, addr);
+}
+
+/***********************************************************************
+ * RANAP handling
+ ***********************************************************************/
+
+int ranap_iu_rab_act(struct ranap_ue_conn_ctx *ue_ctx, struct msgb *msg)
+{
+	struct osmo_scu_prim *prim;
+
+	/* wrap RANAP message in SCCP N-DATA.req */
+	prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
+	prim->u.data.conn_id = ue_ctx->conn_id;
+	osmo_prim_init(&prim->oph,
+		       SCCP_SAP_USER,
+		       OSMO_SCU_PRIM_N_DATA,
+		       PRIM_OP_REQUEST,
+		       msg);
+	return osmo_sccp_user_sap_down(g_scu, &prim->oph);
+}
+
+int ranap_iu_rab_deact(struct ranap_ue_conn_ctx *ue_ctx, uint8_t rab_id)
+{
+	/* FIXME */
+	return -1;
+}
+
+int ranap_iu_tx_sec_mode_cmd(struct ranap_ue_conn_ctx *uectx, struct osmo_auth_vector *vec,
+			     int send_ck, int new_key)
+{
+	struct osmo_scu_prim *prim;
+	struct msgb *msg;
+
+	/* create RANAP message */
+	msg = ranap_new_msg_sec_mod_cmd(vec->ik, send_ck? vec->ck : NULL,
+			new_key ? RANAP_KeyStatus_new : RANAP_KeyStatus_old);
+	msg->l2h = msg->data;
+	/* wrap RANAP message in SCCP N-DATA.req */
+	prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
+	prim->u.data.conn_id = uectx->conn_id;
+	osmo_prim_init(&prim->oph, SCCP_SAP_USER,
+			OSMO_SCU_PRIM_N_DATA,
+			PRIM_OP_REQUEST, msg);
+	osmo_sccp_user_sap_down(g_scu, &prim->oph);
+
+	return 0;
+}
+
+int ranap_iu_tx_common_id(struct ranap_ue_conn_ctx *uectx, const char *imsi)
+{
+	struct msgb *msg;
+	struct osmo_scu_prim *prim;
+
+	LOGPIU(LOGL_INFO, "Transmitting RANAP CommonID (SCCP conn_id %u)\n",
+	       uectx->conn_id);
+
+	msg = ranap_new_msg_common_id(imsi);
+	msg->l2h = msg->data;
+	prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
+	prim->u.data.conn_id = uectx->conn_id;
+	osmo_prim_init(&prim->oph, SCCP_SAP_USER,
+			OSMO_SCU_PRIM_N_DATA,
+			PRIM_OP_REQUEST, msg);
+	osmo_sccp_user_sap_down(g_scu, &prim->oph);
+	return 0;
+}
+
+static int iu_grnc_id_parse(struct iu_grnc_id *dst, struct RANAP_GlobalRNC_ID *src)
+{
+	/* The size is coming from arbitrary sender, check it gracefully */
+	if (src->pLMNidentity.size != 3) {
+		LOGPIU(LOGL_ERROR, "Invalid PLMN Identity size:"
+		       " should be 3, is %d\n", src->pLMNidentity.size);
+		return -1;
+	}
+	gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0],
+			       &dst->mcc, &dst->mnc);
+	dst->rnc_id = (uint16_t)src->rNC_ID;
+	return 0;
+}
+
+#if 0
+ -- not used at present --
+static int iu_grnc_id_compose(struct iu_grnc_id *src, struct RANAP_GlobalRNC_ID *dst)
+{
+	/* The caller must ensure proper size */
+	OSMO_ASSERT(dst->pLMNidentity.size == 3);
+	gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0],
+			     src->mcc, src->mnc);
+	dst->rNC_ID = src->rnc_id;
+	return 0;
+}
+#endif
+
+struct new_ue_conn_ctx {
+	struct osmo_sccp_addr sccp_addr;
+	uint32_t conn_id;
+};
+
+static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies)
+{
+	struct new_ue_conn_ctx *new_ctx = ctx;
+	struct gprs_ra_id ra_id;
+	struct iu_grnc_id grnc_id;
+	uint16_t sai;
+	struct ranap_ue_conn_ctx *ue;
+	struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
+	struct ranap_iu_rnc *rnc;
+
+	if (ranap_parse_lai(&ra_id, &ies->lai) != 0) {
+		LOGPIU(LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
+		return -1;
+	}
+
+	if (ies->presenceMask & INITIALUE_MESSAGEIES_RANAP_RAC_PRESENT) {
+		ra_id.rac = asn1str_to_u8(&ies->rac);
+	}
+
+	if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) {
+		LOGPIU(LOGL_ERROR,
+		       "Failed to parse RANAP Global-RNC-ID IE\n");
+		return -1;
+	}
+
+	sai = asn1str_to_u16(&ies->sai.sAC);
+	msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size);
+	memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
+
+	/* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */
+	rnc = iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, &new_ctx->sccp_addr);
+
+	ue = ue_conn_ctx_alloc(rnc, new_ctx->conn_id);
+	OSMO_ASSERT(ue);
+	ue->ra_id = ra_id;
+
+	/* Feed into the MM layer */
+	msg->dst = ue;
+	global_iu_recv_cb(msg, &ra_id, &sai);
+
+	msgb_free(msg);
+
+	return 0;
+}
+
+static int ranap_handle_co_dt(void *ctx, RANAP_DirectTransferIEs_t *ies)
+{
+	struct gprs_ra_id _ra_id, *ra_id = NULL;
+	uint16_t _sai, *sai = NULL;
+	struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
+
+	if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) {
+		if (ranap_parse_lai(&_ra_id, &ies->lai) != 0) {
+			LOGPIU(LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
+			return -1;
+		}
+		ra_id = &_ra_id;
+		if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) {
+			_ra_id.rac = asn1str_to_u8(&ies->rac);
+		}
+		if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_SAI_PRESENT) {
+			_sai = asn1str_to_u16(&ies->sai.sAC);
+			sai = &_sai;
+		}
+	}
+
+	msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size);
+	memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
+
+	/* Feed into the MM/CC/SMS-CP layer */
+	msg->dst = ctx;
+	global_iu_recv_cb(msg, ra_id, sai);
+
+	msgb_free(msg);
+
+	return 0;
+}
+
+static int ranap_handle_co_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies)
+{
+	if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT)
+		LOGPIU(LOGL_ERROR, "Rx Error Indication (%s)\n",
+		       ranap_cause_str(&ies->cause));
+	else
+		LOGPIU(LOGL_ERROR, "Rx Error Indication\n");
+
+	return 0;
+}
+
+int ranap_iu_tx(struct msgb *msg_nas, uint8_t sapi)
+{
+	struct ranap_ue_conn_ctx *uectx = msg_nas->dst;
+	struct msgb *msg;
+	struct osmo_scu_prim *prim;
+
+	LOGPIU(LOGL_INFO, "Transmitting L3 Message as RANAP DT (SCCP conn_id %u)\n",
+	       uectx->conn_id);
+
+	msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas));
+	msgb_free(msg_nas);
+	msg->l2h = msg->data;
+	prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
+	prim->u.data.conn_id = uectx->conn_id;
+	osmo_prim_init(&prim->oph, SCCP_SAP_USER,
+			OSMO_SCU_PRIM_N_DATA,
+			PRIM_OP_REQUEST, msg);
+	osmo_sccp_user_sap_down(g_scu, &prim->oph);
+	return 0;
+}
+
+/* Send Iu Release for the given UE connection.
+ * If cause is NULL, the standard "No remaining RAB" cause is sent, otherwise
+ * the provided cause. */
+int ranap_iu_tx_release(struct ranap_ue_conn_ctx *ctx, const struct RANAP_Cause *cause)
+{
+	struct msgb *msg;
+	struct osmo_scu_prim *prim;
+	static const struct RANAP_Cause default_cause = {
+		.present = RANAP_Cause_PR_radioNetwork,
+		.choice.radioNetwork = RANAP_CauseRadioNetwork_no_remaining_rab,
+	};
+
+	if (!cause)
+		cause = &default_cause;
+
+	msg = ranap_new_msg_iu_rel_cmd(cause);
+	msg->l2h = msg->data;
+	prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
+	prim->u.data.conn_id = ctx->conn_id;
+	osmo_prim_init(&prim->oph, SCCP_SAP_USER,
+			OSMO_SCU_PRIM_N_DATA,
+			PRIM_OP_REQUEST, msg);
+	return osmo_sccp_user_sap_down(g_scu, &prim->oph);
+}
+
+static int ranap_handle_co_iu_rel_req(struct ranap_ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies)
+{
+	LOGPIU(LOGL_INFO, "Received Iu Release Request, Sending Release Command\n");
+	ranap_iu_tx_release(ctx, &ies->cause);
+	return 0;
+}
+
+static int ranap_handle_co_rab_ass_resp(struct ranap_ue_conn_ctx *ctx, RANAP_RAB_AssignmentResponseIEs_t *ies)
+{
+	int rc = -1;
+
+	LOGPIU(LOGL_INFO,
+	       "Rx RAB Assignment Response for UE conn_id %u\n", ctx->conn_id);
+	if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) {
+		/* TODO: Iterate over list of SetupOrModifiedList IEs and handle each one */
+		RANAP_IE_t *ranap_ie = ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0];
+		RANAP_RAB_SetupOrModifiedItemIEs_t setup_ies;
+
+		rc = ranap_decode_rab_setupormodifieditemies_fromlist(&setup_ies, &ranap_ie->value);
+		if (rc) {
+			LOGPIU(LOGL_ERROR, "Error in ranap_decode_rab_setupormodifieditemies()\n");
+			return rc;
+		}
+
+		rc = global_iu_event_cb(ctx, RANAP_IU_EVENT_RAB_ASSIGN, &setup_ies);
+
+		ranap_free_rab_setupormodifieditemies(&setup_ies);
+	}
+	/* FIXME: handle RAB Ass failure? */
+
+	return rc;
+}
+
+static void cn_ranap_handle_co_initial(void *ctx, ranap_message *message)
+{
+	int rc;
+
+	LOGPIU(LOGL_NOTICE, "handle_co_initial(dir=%u, proc=%u)\n", message->direction, message->procedureCode);
+
+	if (message->direction != RANAP_RANAP_PDU_PR_initiatingMessage
+	    || message->procedureCode != RANAP_ProcedureCode_id_InitialUE_Message) {
+		LOGPIU(LOGL_ERROR, "Expected direction 'InitiatingMessage',"
+		       " procedureCode 'InitialUE_Message', instead got %u and %u\n",
+		       message->direction, message->procedureCode);
+		rc = -1;
+	}
+	else
+		rc = ranap_handle_co_initial_ue(ctx, &message->msg.initialUE_MessageIEs);
+
+	if (rc) {
+		LOGPIU(LOGL_ERROR, "Error in %s (%d)\n", __func__, rc);
+		/* TODO handling of the error? */
+	}
+}
+
+/* Entry point for connection-oriented RANAP message */
+static void cn_ranap_handle_co(void *ctx, ranap_message *message)
+{
+	int rc;
+
+	LOGPIU(LOGL_NOTICE, "handle_co(dir=%u, proc=%u)\n", message->direction, message->procedureCode);
+
+	switch (message->direction) {
+	case RANAP_RANAP_PDU_PR_initiatingMessage:
+		switch (message->procedureCode) {
+		case RANAP_ProcedureCode_id_InitialUE_Message:
+			LOGPIU(LOGL_ERROR, "Got InitialUE_Message but this is not a new conn\n");
+			rc = -1;
+			break;
+		case RANAP_ProcedureCode_id_DirectTransfer:
+			rc = ranap_handle_co_dt(ctx, &message->msg.directTransferIEs);
+			break;
+		case RANAP_ProcedureCode_id_ErrorIndication:
+			rc = ranap_handle_co_err_ind(ctx, &message->msg.errorIndicationIEs);
+			break;
+		case RANAP_ProcedureCode_id_Iu_ReleaseRequest:
+			/* Iu Release Request */
+			rc = ranap_handle_co_iu_rel_req(ctx, &message->msg.iu_ReleaseRequestIEs);
+			break;
+		default:
+			LOGPIU(LOGL_ERROR, "Received Initiating Message: unknown Procedure Code %d\n",
+			       message->procedureCode);
+			rc = -1;
+			break;
+		}
+		break;
+	case RANAP_RANAP_PDU_PR_successfulOutcome:
+		switch (message->procedureCode) {
+		case RANAP_ProcedureCode_id_SecurityModeControl:
+			/* Security Mode Complete */
+			rc = global_iu_event_cb(ctx, RANAP_IU_EVENT_SECURITY_MODE_COMPLETE, NULL);
+			break;
+		case RANAP_ProcedureCode_id_Iu_Release:
+			/* Iu Release Complete */
+			rc = global_iu_event_cb(ctx, RANAP_IU_EVENT_IU_RELEASE, NULL);
+			if (rc) {
+				LOGPIU(LOGL_ERROR, "Iu Release event: Iu Event callback returned %d\n",
+				       rc);
+			}
+			break;
+		default:
+			LOGPIU(LOGL_ERROR, "Received Successful Outcome: unknown Procedure Code %d\n",
+			       message->procedureCode);
+			rc = -1;
+			break;
+		}
+		break;
+	case RANAP_RANAP_PDU_PR_outcome:
+		switch (message->procedureCode) {
+		case RANAP_ProcedureCode_id_RAB_Assignment:
+			/* RAB Assignment Response */
+			rc = ranap_handle_co_rab_ass_resp(ctx, &message->msg.raB_AssignmentResponseIEs);
+			break;
+		default:
+			LOGPIU(LOGL_ERROR, "Received Outcome: unknown Procedure Code %d\n",
+			       message->procedureCode);
+			rc = -1;
+			break;
+		}
+		break;
+	case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
+	default:
+		LOGPIU(LOGL_ERROR, "Received Unsuccessful Outcome: Procedure Code %d\n",
+		       message->procedureCode);
+		rc = -1;
+		break;
+	}
+
+	if (rc) {
+		LOGPIU(LOGL_ERROR, "Error in %s (%d)\n", __func__, rc);
+		/* TODO handling of the error? */
+	}
+}
+
+static int ranap_handle_cl_reset_req(void *ctx, RANAP_ResetIEs_t *ies)
+{
+	/* FIXME: send reset response */
+	return -1;
+}
+
+static int ranap_handle_cl_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies)
+{
+	if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT)
+		LOGPIU(LOGL_ERROR, "Rx Error Indication (%s)\n",
+		       ranap_cause_str(&ies->cause));
+	else
+		LOGPIU(LOGL_ERROR, "Rx Error Indication\n");
+
+	return 0;
+}
+
+/* Entry point for connection-less RANAP message */
+static void cn_ranap_handle_cl(void *ctx, ranap_message *message)
+{
+	int rc;
+
+	switch (message->direction) {
+	case RANAP_RANAP_PDU_PR_initiatingMessage:
+		switch (message->procedureCode) {
+		case RANAP_ProcedureCode_id_Reset:
+			/* received reset.req, send reset.resp */
+			rc = ranap_handle_cl_reset_req(ctx, &message->msg.resetIEs);
+			break;
+		case RANAP_ProcedureCode_id_ErrorIndication:
+			rc = ranap_handle_cl_err_ind(ctx, &message->msg.errorIndicationIEs);
+			break;
+		default:
+			rc = -1;
+			break;
+		}
+		break;
+	case RANAP_RANAP_PDU_PR_successfulOutcome:
+	case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
+	case RANAP_RANAP_PDU_PR_outcome:
+	default:
+		rc = -1;
+		break;
+	}
+
+	if (rc) {
+		LOGPIU(LOGL_ERROR, "Error in %s (%d)\n", __func__, rc);
+		/* TODO handling of the error? */
+	}
+}
+
+/***********************************************************************
+ * Paging
+ ***********************************************************************/
+
+struct osmo_sccp_addr local_sccp_addr = {
+	.presence = OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC,
+	.ri = OSMO_SCCP_RI_SSN_PC,
+	.ssn = OSMO_SCCP_SSN_RANAP,
+	.pc = 1,
+};
+
+/* Send a paging command down a given SCCP User. tmsi and paging_cause are
+ * optional and may be passed NULL and 0, respectively, to disable their use.
+ * See enum RANAP_PagingCause.
+ *
+ * If TMSI is given, the IMSI is not sent over the air interface. Nevertheless,
+ * the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */
+static int iu_tx_paging_cmd(struct osmo_sccp_addr *called_addr,
+			    const char *imsi, const uint32_t *tmsi,
+			    bool is_ps, uint32_t paging_cause)
+{
+	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, &local_sccp_addr, called_addr, msg);
+	return 0;
+}
+
+static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi,
+		   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 ++;
+		}
+	}
+
+	/* 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);
+		}
+	}
+
+	return pagings_sent;
+}
+
+int ranap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac)
+{
+	return iu_page(imsi, tmsi, lac, 0, false);
+}
+
+int ranap_iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac)
+{
+	return iu_page(imsi, ptmsi, lac, rac, true);
+}
+
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+
+int tx_unitdata(struct osmo_sccp_user *scu);
+int tx_conn_req(struct osmo_sccp_user *scu, uint32_t conn_id);
+
+struct osmo_prim_hdr *make_conn_req(uint32_t conn_id);
+struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len);
+
+static struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param)
+{
+	struct msgb *msg = msgb_alloc(1024, "conn_resp");
+	struct osmo_scu_prim *prim;
+
+	prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim));
+	osmo_prim_init(&prim->oph, SCCP_SAP_USER,
+			OSMO_SCU_PRIM_N_CONNECT,
+			PRIM_OP_RESPONSE, msg);
+	memcpy(&prim->u.connect, param, sizeof(prim->u.connect));
+	return &prim->oph;
+}
+
+static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
+{
+	struct osmo_sccp_user *scu = _scu;
+	struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;
+	struct osmo_prim_hdr *resp = NULL;
+	int rc;
+	struct ranap_ue_conn_ctx *ue;
+	struct new_ue_conn_ctx new_ctx = {};
+
+	LOGPIU(LOGL_DEBUG, "sccp_sap_up(%s)\n", osmo_scu_prim_name(oph));
+
+	switch (OSMO_PRIM_HDR(oph)) {
+	case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
+		/* confirmation of outbound connection */
+		rc = -1;
+		break;
+	case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION):
+		/* indication of new inbound connection request*/
+		LOGPIU(LOGL_DEBUG, "N-CONNECT.ind(X->%u)\n", prim->u.connect.conn_id);
+		if (/*  prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */
+		    !msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) {
+			LOGPIU(LOGL_NOTICE,
+			     "Received invalid N-CONNECT.ind\n");
+			return 0;
+		}
+		new_ctx.sccp_addr = prim->u.connect.calling_addr;
+		new_ctx.conn_id = prim->u.connect.conn_id;
+		/* first ensure the local SCCP socket is ACTIVE */
+		resp = make_conn_resp(&prim->u.connect);
+		osmo_sccp_user_sap_down(scu, resp);
+		/* then handle the RANAP payload */
+		rc = ranap_cn_rx_co(cn_ranap_handle_co_initial, &new_ctx, msgb_l2(oph->msg), msgb_l2len(oph->msg));
+		break;
+	case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
+		/* indication of disconnect */
+		LOGPIU(LOGL_DEBUG, "N-DISCONNECT.ind(%u)\n",
+		       prim->u.disconnect.conn_id);
+		ue = ue_conn_ctx_find(prim->u.disconnect.conn_id);
+		rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
+		break;
+	case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
+		/* connection-oriented data received */
+		LOGPIU(LOGL_DEBUG, "N-DATA.ind(%u, %s)\n", prim->u.data.conn_id,
+		       osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+		/* resolve UE context */
+		ue = ue_conn_ctx_find(prim->u.data.conn_id);
+		rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
+		break;
+	case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
+		/* connection-less data received */
+		LOGPIU(LOGL_DEBUG, "N-UNITDATA.ind(%s)\n",
+		       osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
+		rc = ranap_cn_rx_cl(cn_ranap_handle_cl, scu, msgb_l2(oph->msg), msgb_l2len(oph->msg));
+		break;
+	default:
+		rc = -1;
+		break;
+	}
+
+	msgb_free(oph->msg);
+	return rc;
+}
+
+int ranap_iu_init(void *ctx, int log_subsystem, const char *sccp_user_name, struct osmo_sccp_instance *sccp,
+		  ranap_iu_recv_cb_t iu_recv_cb, ranap_iu_event_cb_t iu_event_cb)
+{
+	iu_log_subsystem = log_subsystem;
+	talloc_iu_ctx = talloc_named_const(ctx, 1, "iu");
+	talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1");
+
+	global_iu_recv_cb = iu_recv_cb;
+	global_iu_event_cb = iu_event_cb;
+	g_sccp = sccp;
+	g_scu = osmo_sccp_user_bind(g_sccp, sccp_user_name, sccp_sap_up, OSMO_SCCP_SSN_RANAP);
+
+	return 0;
+}
+
diff --git a/src/iu_client_vty.c b/src/iu_client_vty.c
new file mode 100644
index 0000000..b809b2a
--- /dev/null
+++ b/src/iu_client_vty.c
@@ -0,0 +1,140 @@
+/* OpenBSC Iu related interface to quagga VTY */
+/* (C) 2016 by sysmocom s.m.f.c. GmbH <info at sysmocom.de>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/logging.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+#include <osmocom/sigtran/sccp_sap.h>
+
+#include <osmocom/ranap/iu_client.h>
+
+static enum ranap_nsap_addr_enc *g_rab_assign_addr_enc = NULL;
+
+DEFUN(cfg_iu_asn1_debug,
+      cfg_iu_asn1_debug_cmd,
+      "asn1 debug (1|0)",
+      "ASN.1 settings\n"
+      "Enable ASN.1 debug messages\n"
+      "Log ASN.1 debug messages to stderr\n"
+      "Do not log ASN.1 debug messages to stderr\n")
+{
+	asn_debug = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_iu_asn1_xer_print,
+      cfg_iu_asn1_xer_print_cmd,
+      "asn1 xer-print (1|0)",
+      "ASN.1 settings\n"
+      "Log human readable representations of all ASN.1 messages to stderr\n"
+      "Log XML representation of all ASN.1 messages to stderr\n"
+      "Do not log decoded ASN.1 messages to stderr\n")
+{
+	asn1_xer_print = atoi(argv[0]);
+	return CMD_SUCCESS;
+}
+
+#define IU_STR "Iu interface protocol options\n"
+DEFUN(cfg_iu_rab_assign_addr_enc, cfg_iu_rab_assign_addr_enc_cmd,
+      "iu rab-assign-addr-enc (x213|v4raw)",
+      IU_STR
+      "Choose RAB Assignment's Transport Layer Address encoding\n"
+      "ITU-T X.213 compliant address encoding (default)\n"
+      "32bit length raw IPv4 address (for ip.access nano3G)\n")
+{
+	if (!g_rab_assign_addr_enc) {
+		vty_out(vty, "%%RAB Assignment Transport Layer Address"
+			" encoding not available%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	if (strcmp(argv[0], "v4raw") == 0)
+		*g_rab_assign_addr_enc = RANAP_NSAP_ADDR_ENC_V4RAW;
+	else
+		*g_rab_assign_addr_enc = RANAP_NSAP_ADDR_ENC_X213;
+	return CMD_SUCCESS;
+}
+
+extern struct osmo_sccp_addr local_sccp_addr;
+
+DEFUN(cfg_iu_local_addr_pc, cfg_iu_local_addr_pc_cmd,
+	"iu local-address point-code PC",
+	IU_STR "Local SCCP Address\n")
+{
+	local_sccp_addr.presence = OSMO_SCCP_ADDR_T_PC | OSMO_SCCP_ADDR_T_SSN;
+	local_sccp_addr.ri = OSMO_SCCP_RI_SSN_PC;
+	local_sccp_addr.pc = osmo_ss7_pointcode_parse(NULL, argv[0]);
+
+	return CMD_SUCCESS;
+}
+
+/* TODO: GT address configuration, in line with 4.5.1.1.1 of TS 25.410 */
+
+int ranap_iu_vty_config_write(struct vty *vty, const char *indent)
+{
+	if (!g_rab_assign_addr_enc) {
+		vty_out(vty, "%%RAB Assignment Transport Layer Address"
+			" encoding not available%s", VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	switch (*g_rab_assign_addr_enc) {
+	case RANAP_NSAP_ADDR_ENC_V4RAW:
+		vty_out(vty, "%siu rab-assign-addr-enc v4raw%s", indent,
+			VTY_NEWLINE);
+		break;
+	case RANAP_NSAP_ADDR_ENC_X213:
+		/* default value, no need to write anything */
+		break;
+	default:
+		LOGP(0, LOGL_ERROR, "Invalid value for"
+		     " iu.rab_assign_addr_enc: %d\n",
+		     *g_rab_assign_addr_enc);
+		return CMD_WARNING;
+	}
+
+	vty_out(vty, "%siu local-address point-code %s%s", indent,
+		osmo_ss7_pointcode_print(NULL, local_sccp_addr.pc), VTY_NEWLINE);
+
+	if (asn_debug)
+		vty_out(vty, "%sasn1 debug 1%s", indent, VTY_NEWLINE);
+
+	if (asn1_xer_print)
+		vty_out(vty, "%sasn1 xer-print 1%s", indent, VTY_NEWLINE);
+
+	return CMD_SUCCESS;
+}
+
+void ranap_iu_vty_init(int iu_parent_node, enum ranap_nsap_addr_enc *rab_assign_addr_enc)
+{
+	g_rab_assign_addr_enc = rab_assign_addr_enc;
+
+	install_element(iu_parent_node, &cfg_iu_rab_assign_addr_enc_cmd);
+	install_element(iu_parent_node, &cfg_iu_local_addr_pc_cmd);
+
+	/* Technically, these are global ASN.1 settings and not necessarily limited to the Iu interface.
+	 * Practically, only Iu users will use ASN.1 in Osmocom programs -- at least so far. So it is
+	 * easiest to have these commands under 'iu'. */
+	install_element(iu_parent_node, &cfg_iu_asn1_debug_cmd);
+	install_element(iu_parent_node, &cfg_iu_asn1_xer_print_cmd);
+}

-- 
To view, visit https://gerrit.osmocom.org/3187
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: I6a3f7ad15be03fb94689b4af6ccfa828c25f45c0
Gerrit-PatchSet: 2
Gerrit-Project: osmo-iuh
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr at sysmocom.de>



More information about the gerrit-log mailing list