further tiny steps of progress on the hnb-gw infrastructure
diff --git a/src/hnbgw.c b/src/hnbgw.c
new file mode 100644
index 0000000..fc26d0d
--- /dev/null
+++ b/src/hnbgw.c
@@ -0,0 +1,97 @@
+
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/linuxlist.h>
+
+#include "hnbgw.h"
+
+struct hnb_gw g_hnb_gw = {
+	.config = {
+		.iuh_listen_port = IUH_DEFAULT_SCTP_PORT,
+	},
+};
+
+static int hnb_socket_cb(struct osmo_fd *fd, unsigned int what)
+{
+	struct hnb_context *hnb = fd->data;
+	struct sctp_sndrcvinfo sinfo;
+	struct msgb *msg = msgb_alloc(IUH_MSGB_SIZE, "Iuh rx");
+	int flags;
+	int rc;
+
+	if (!msg)
+		return -ENOMEM;
+
+	rc = sctp_recvmsg(fd->fd, msgb_data(msg), msgb_tailroom(msg),
+			  NULL, NULL, &sinfo, &flags);
+	if (rc < 0) {
+		LOGP(DMAIN, LOGL_ERROR, "Error during sctp_recvmsg()\n");
+		return rc;
+	} else
+		msgb_put(msg, rc);
+
+	switch (sinfo.sinfo_ppid) {
+	case IUH_PPI_HNBAP:
+		rc = hnbgw_hnbap_rx(hnb, msg);
+		break;
+	case IUH_PPI_RUA:
+		rc = hnbgw_rua_rx(hnb, msg);
+		break;
+	case IUH_PPI_SABP:
+	case IUH_PPI_RNA:
+	case IUH_PPI_PUA:
+		LOGP(DMAIN, LOGL_ERROR, "Unimplemented SCTP PPID=%u received\n",
+		     sinfo.sinfo_ppid);
+		rc = 0;
+		break;
+	default:
+		LOGP(DMAIN, LOGL_ERROR, "Unknown SCTP PPID=%u received\n",
+		     sinfo.sinfo_ppid);
+		rc = 0;
+		break;
+	}
+
+	return rc;
+}
+
+/*! call-back when the listen FD has something to read */
+static int listen_fd_cb(struct osmo_fd *fd, unsigned int what)
+{
+	struct hnb_gw *gw = fd->data;
+	struct hmb_context *ctx;
+	struct sokaddr_storage sockaddr;
+	socklen_t len = sizeof(sockaddr);
+
+	int new_fd = accept(fd->fd, (struct sockaddr *)&sockaddr, &len);
+	if (new_fd < 0) {
+		LOGP(DMAIN, LOGL_ERROR, "Iuh accept() failed\n");
+		return new_fd;
+	}
+
+	LOGP(DMAIN, LOGL_INFO, "SCTP Connection accept()ed\n");
+
+	ctx = talloc_zero(tall_hnb_ctx, struct hnb_context);
+	if (!ctx)
+		return -ENOMEM;
+
+	ctx->gw = gw;
+	ctx->socket.data = ctx;
+	ctx->socket.fd = new_fd;
+	ctx->socket.when = BSC_FD_READ;
+	ctx->socket.cb = hnb_socket_cb;
+	osmo_fd_register(&cttx->socket);
+
+	return 0;
+}
+
+
+
+{
+	g_hnb_gw.listen_fd.cb = listen_fd_cb;
+	g_hnb_gw.listen_fd.when = BSC_FD_READ;
+	g_hnb_gw.listen_fd.data = &g_hnb_gw;
+
+	osmo_sock_init_ofd(&g_hnb_gw.listen_fd, AF_INET, SOCK_STREAM,
+			   IPPROTO_SCTP, "127.0.0.1",
+			   g_hnb_gw.config.iuh_listen_port, OSMO_SOCK_F_BIND);
+}
diff --git a/src/hnbgw.h b/src/hnbgw.h
index 87a5a2f..7b69a10 100644
--- a/src/hnbgw.h
+++ b/src/hnbgw.h
@@ -3,27 +3,63 @@
 #include <osmocom/core/select.h>
 #include <osmocom/core/linuxlist.h>
 
+/* 25.467 Section 7.1 */
+#define IUH_DEFAULT_SCTP_PORT	29169
+#define RNA_DEFAULT_SCTP_PORT	25471
+
+#define IUH_PPI_RUA		19
+#define IUH_PPI_HNBAP		20
+#define IUH_PPI_SABP		31
+#define IUH_PPI_RNA		42
+#define IUH_PPI_PUA		55
+
+#define IHU_MSGB_SIZE	2048
+
+struct umts_cell_id {
+	uint16_t mcc;	/*!< Mobile Country Code */
+	uint16_t mnc;	/*!< Mobile Network Code */
+	uint16_t lac;	/*!< Locaton Area Code */
+	uint16_t rac;	/*!< Routing Area Code */
+	uint16_t sac;	/*!< Service Area Code */
+	uint32_t cid;	/*!< Cell ID */
+};
+
+struct hnb_gw;
+
 struct hnb_context {
 	/*! Entry in HNB-global list of HNB */
 	struct llist_head list;
+	/*! HNB-GW we are part of */
+	struct hnb_gw *gw;
 	/*! SCTP socket for Iuh to this specific HNB */
 	struct osmo_fd socket;
-
-	/*! copied from HNB-Identity-Info */
-	char identity[256];
+	/*! copied from HNB-Identity-Info IE */
+	char identity_info[256];
+	/*! copied from Cell Identity IE */
+	struct umts_cell_id id;
 };
 
 struct ue_context {
+	/*! Entry in the HNB-global list of UE */
 	struct llist_head list;
+	/*! Unique Context ID for this UE */
 	uint32_t context_id;
+	/*! UE is serviced via this HNB */
+	struct hnb_context *hnb;
 };
 
 struct hnb_gw {
 	struct {
 		/*! SCTP port for Iuh listening */
 		uint16_t iuh_listen_port;
+		/*! The UDP port where we receive multiplexed CS user
+		 * plane traffic from HNBs */
+		uint16_t iuh_cs_mux_port;
+		uint16_t rnc_id;
 	} config;
 	/*! SCTP listen socket for incoming connections */
 	struct osmo_fd listen_fd;
 	struct llist_head hnb_list;
 };
+
+extern struct hnb_gw g_hnb_gw;
diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c
index 9b674ad..ce41222 100644
--- a/src/hnbgw_hnbap.c
+++ b/src/hnbgw_hnbap.c
@@ -29,7 +29,31 @@
 	return NULL;
 }
 
-static int hnbgw_rx_hnb_register_req(struct HNBRegisterRequest *req)
+static inline uint16_t asn1str_to_u16(ASN1String *as)
+{
+	if (as->len < 2)
+		return 0;
+	else
+		return *(uint16_t *)as->buf;
+}
+
+static inline uint8_t asn1str_to_u8(ASN1String *as)
+{
+	if (as->len < 1)
+		return 0;
+	else
+		return *(uint8_t *)as->buf;
+}
+
+static inline uint8_t asn1bitstr_to_u32(ASN1BitString *as)
+{
+	if (as->len < 25)
+		return 0;
+	else
+		return *(uint32_t *)as->buf;
+}
+
+static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, struct HNBRegisterRequest *req)
 {
 	HNB_Identity *identity =
 		FIND_IE(req->protocolIEs, HNBAP_IEI_HNB_Identity);
@@ -47,10 +71,19 @@
 	if(!identity || !loc || !plmn_id || !cell_id || !lac || !rac || !sac)
 		return -1;
 
+	/* copy all identity parameters from the message to ctx */
+	strncpy(ctx->identity_info, sizeof(ctx->identity_info, identity_info->buf);
+	ctx->id.lac = asn1str_to_u16(lac);
+	ctx->id.sac = asn1str_to_u16(sac);
+	ctx->id.rac = asn1str_to_u8(rac);
+	ctx->id.cid = asn1bitstr_to_u32(cell_id);
+	ctx->id.mcc FIXME
+	ctx->id.mnc FIXME
+
 	/* FIXME: Send HNBRegisterAccept */
 }
 
-static int hnbgw_rx_ue_register_req(struct UERegisterRequest *req)
+static int hnbgw_rx_ue_register_req(struct hnb_context *ctx, struct UERegisterRequest *req)
 {
 	UE_Identity *id =
 		FIND_IE(req->protocolIEs, HNBAP_IEI_UE_Identity);
@@ -65,7 +98,7 @@
 	/* FIXME: Send UERegisterAccept */
 }
 
-static int hnbgw_rx_initiating_msg(struct InitiatingMessage *msg)
+static int hnbgw_rx_initiating_msg(struct hnb_context *hnb, struct InitiatingMessage *msg)
 {
 	int rc;
 
@@ -73,14 +106,14 @@
 	case HNBAP_PC_HNBRegister:	/* 8.2 */
 		if (msg->value.type != asn1_type_HNBRegisterRequest)
 			return -1;
-		rc = hnbgw_rx_hnb_register_req();
+		rc = hnbgw_rx_hnb_register_req(hnb, FIXME);
 		break;
 	case HNBAP_PC_HNBDe_Register:	/* 8.3 */
 		break;
 	case HNBAP_PC_UERegister: 	/* 8.4 */
 		if (msg->value.type != asn1_type_UERegisterRequest)
 			return -1;
-		rc = hnbgw_rx_ue_register_req();
+		rc = hnbgw_rx_ue_register_req(hnb, FIXME);
 		break;
 	case HNBAP_PC_UEDe_Register:	/* 8.5 */
 		break;
@@ -107,7 +140,7 @@
 }
 
 
-static int _hnbgw_hnbap_rx(struct HNBAP_PDU *pdu)
+static int _hnbgw_hnbap_rx(struct hnb_context *hnb, struct HNBAP_PDU *pdu)
 {
 	/* it's a bit odd that we can't dispatch on procedure code, but
 	 * that's not possible */
@@ -126,7 +159,7 @@
 	}
 }
 
-int hnbgw_hnbap_rx(struct msgb *msg)
+int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg)
 {
 	/* FIXME: decode and handle to _hnbgw_hnbap_rx() */
 }