hnbgw: Use libosmo-netif for SCCP connection handling
diff --git a/src/Makefile.am b/src/Makefile.am
index 29daeb5..0f82404 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -50,6 +50,7 @@
 
 osmo_hnbgw_LDADD = $(OSMOCORE_LIBS) $(OSMOVTY_LIBS) $(OSMOGSM_LIBS) \
 		   $(ASN1C_LIBS) $(OSMOSIGTRAN_LIBS) $(COMMON_LDADD) \
+		   $(OSMONETIF_LIBS) \
 		   hnbap/libosmo-asn1-hnbap.a rua/libosmo-asn1-rua.a \
 		   libosmo-ranap.la
 
diff --git a/src/hnbgw.c b/src/hnbgw.c
index b3d1b63..e7dff3f 100644
--- a/src/hnbgw.c
+++ b/src/hnbgw.c
@@ -69,9 +69,6 @@
 
 	gw->config.iuh_listen_port = IUH_DEFAULT_SCTP_PORT;
 
-	gw->listen_fd.cb = listen_fd_cb;
-	gw->listen_fd.when = BSC_FD_READ;
-	gw->listen_fd.data = gw;
 	gw->next_ue_ctx_id = 23;
 	INIT_LLIST_HEAD(&gw->hnb_list);
 	INIT_LLIST_HEAD(&gw->ue_list);
@@ -137,13 +134,13 @@
 	llist_del(&ue->list);
 	talloc_free(ue);
 }
-
-
-
-static int hnb_read_cb(struct osmo_fd *fd)
+static int hnb_close_cb(struct osmo_stream_srv *conn)
 {
-	struct hnb_context *hnb = fd->data;
-	struct sctp_sndrcvinfo sinfo;
+}
+
+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;
@@ -155,20 +152,18 @@
 	 * benefit of varoius downstream processing functions */
 	msg->dst = hnb;
 
-	rc = sctp_recvmsg(fd->fd, msgb_data(msg), msgb_tailroom(msg),
-			  NULL, NULL, &sinfo, &flags);
-	if (rc < 0) {
+	rc = osmo_stream_srv_recv(conn, msg);
+	if (rc == -EAGAIN) {
+		/* Notification received */
+		msgb_free(msg);
+		return 0;
+	} else if (rc < 0) {
 		LOGP(DMAIN, LOGL_ERROR, "Error during sctp_recvmsg()\n");
 		/* FIXME: clean up after disappeared HNB */
-		close(fd->fd);
-		osmo_fd_unregister(fd);
+		hnb_context_release(hnb);
 		goto out;
 	} else if (rc == 0) {
-		LOGP(DMAIN, LOGL_ERROR, "Connection to HNB closed\n");
-		/* TODO: Remove all UEs from that connection */
-		close(fd->fd);
-		osmo_fd_unregister(fd);
-		fd->fd = -1;
+		hnb_context_release(hnb);
 		rc = -1;
 
 		goto out;
@@ -176,33 +171,25 @@
 		msgb_put(msg, rc);
 	}
 
-	if (flags & MSG_NOTIFICATION) {
-		LOGP(DMAIN, LOGL_DEBUG, "Ignoring SCTP notification\n");
-		msgb_free(msg);
-		return 0;
-	}
-
-	sinfo.sinfo_ppid = ntohl(sinfo.sinfo_ppid);
-
-	switch (sinfo.sinfo_ppid) {
+	switch (msgb_sctp_ppid(msg)) {
 	case IUH_PPI_HNBAP:
-		hnb->hnbap_stream = sinfo.sinfo_stream;
+		hnb->hnbap_stream = msgb_sctp_stream(msg);
 		rc = hnbgw_hnbap_rx(hnb, msg);
 		break;
 	case IUH_PPI_RUA:
-		hnb->rua_stream = sinfo.sinfo_stream;
+		hnb->rua_stream = msgb_sctp_stream(msg);
 		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);
+		     msgb_sctp_ppid(msg));
 		rc = 0;
 		break;
 	default:
 		LOGP(DMAIN, LOGL_ERROR, "Unknown SCTP PPID=%u received\n",
-		     sinfo.sinfo_ppid);
+		     msgb_sctp_ppid(msg));
 		rc = 0;
 		break;
 	}
@@ -227,7 +214,7 @@
 	return rc;
 }
 
-struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, int new_fd)
+struct hnb_context *hnb_context_alloc(struct hnb_gw *gw, struct osmo_stream_srv_link *link, int new_fd)
 {
 	struct hnb_context *ctx;
 
@@ -236,13 +223,12 @@
 		return NULL;
 
 	ctx->gw = gw;
-	osmo_wqueue_init(&ctx->wqueue, 16);
-	ctx->wqueue.bfd.data = ctx;
-	ctx->wqueue.bfd.fd = new_fd;
-	ctx->wqueue.bfd.when = BSC_FD_READ;
-	ctx->wqueue.read_cb = hnb_read_cb;
-	ctx->wqueue.write_cb = hnb_write_cb;
-	osmo_fd_register(&ctx->wqueue.bfd);
+	ctx->conn = osmo_stream_srv_create(tall_hnb_ctx, link, new_fd, hnb_read_cb, hnb_close_cb, ctx);
+	if (!ctx->conn) {
+		LOGP(DMAIN, LOGL_INFO, "error while creating connection\n");
+		return -1;
+	}
+
 	INIT_LLIST_HEAD(&ctx->map_list);
 
 	llist_add_tail(&ctx->list, &gw->hnb_list);
@@ -263,29 +249,18 @@
 		llist_del(&map->hnb_list);
 		context_map_deactivate(map);
 	}
-	/* FIXME: flush write queue items */
-	osmo_fd_unregister(&ctx->wqueue.bfd);
+	osmo_stream_srv_destroy(ctx->conn);
 
 	talloc_free(ctx);
 }
 
 /*! call-back when the listen FD has something to read */
-static int listen_fd_cb(struct osmo_fd *fd, unsigned int what)
+static int accept_cb(struct osmo_stream_srv_link *srv, int fd)
 {
-	struct hnb_gw *gw = fd->data;
+	struct hnb_gw *gw = osmo_stream_srv_link_get_data(srv);
 	struct hnb_context *ctx;
-	struct sockaddr_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 = hnb_context_alloc(gw, new_fd);
+	ctx = hnb_context_alloc(gw, srv, fd);
 	if (!ctx)
 		return -ENOMEM;
 
@@ -346,19 +321,6 @@
 
 static int daemonize = 0;
 
-static int sctp_sock_init(int fd)
-{
-	struct sctp_event_subscribe event;
-	int rc;
-
-	/* subscribe for all events */
-	memset((uint8_t *)&event, 1, sizeof(event));
-	rc = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
-			&event, sizeof(event));
-
-	return rc;
-}
-
 static void vty_dump_hnb_info(struct vty *vty, struct hnb_context *hnb)
 {
 	vty_out(vty, "HNB \"%s\" MCC %u MNC %u LAC %u RAC %u SAC %u CID %u%s", hnb->identity_info,
@@ -413,6 +375,7 @@
 {
 	struct osmo_sua_user *sua_user;
 	struct osmo_sua_link *sua_link;
+	struct osmo_stream_srv_link *srv;
 	int rc;
 
 	tall_hnb_ctx = talloc_named_const(NULL, 0, "hnb_context");
@@ -439,14 +402,22 @@
 	g_hnb_gw->cnlink_cs = hnbgw_cnlink_init(g_hnb_gw, "127.0.0.1", SUA_PORT);
 	g_hnb_gw->cnlink_ps = hnbgw_cnlink_init(g_hnb_gw, "127.0.0.2", SUA_PORT);
 
-	rc = osmo_sock_init_ofd(&g_hnb_gw->listen_fd, AF_INET, SOCK_STREAM,
-			   IPPROTO_SCTP, NULL,
-			   g_hnb_gw->config.iuh_listen_port, OSMO_SOCK_F_BIND);
-	if (rc < 0) {
-		perror("Error binding Iuh port");
+	srv = osmo_stream_srv_link_create(tall_hnb_ctx);
+	if (!srv) {
+		perror("cannot create server");
 		exit(1);
 	}
-	sctp_sock_init(g_hnb_gw->listen_fd.fd);
+	osmo_stream_srv_link_set_data(srv, g_hnb_gw);
+	osmo_stream_srv_link_set_proto(srv, IPPROTO_SCTP);
+	osmo_stream_srv_link_set_addr(srv, "0.0.0.0");
+	osmo_stream_srv_link_set_port(srv, g_hnb_gw->config.iuh_listen_port);
+	osmo_stream_srv_link_set_accept_cb(srv, accept_cb);
+
+	if (osmo_stream_srv_link_open(srv) < 0) {
+		perror("Cannot oper server");
+		exit(1);
+	}
+	g_hnb_gw->iuh = srv;
 
 	if (daemonize) {
 		rc = osmo_daemonize();
diff --git a/src/hnbgw.h b/src/hnbgw.h
index ad683ee..d2d4b09 100644
--- a/src/hnbgw.h
+++ b/src/hnbgw.h
@@ -80,7 +80,7 @@
 	/*! HNB-GW we are part of */
 	struct hnb_gw *gw;
 	/*! SCTP socket + write queue for Iuh to this specific HNB */
-	struct osmo_wqueue wqueue;
+	struct osmo_stream_srv *conn;
 	/*! copied from HNB-Identity-Info IE */
 	char identity_info[256];
 	/*! copied from Cell Identity IE */
@@ -115,7 +115,7 @@
 		uint16_t rnc_id;
 	} config;
 	/*! SCTP listen socket for incoming connections */
-	struct osmo_fd listen_fd;
+	struct osmo_stream_srv_link *iuh;
 	/* list of struct hnb_context */
 	struct llist_head hnb_list;
 	/* list of struct ue_context */
@@ -135,5 +135,5 @@
 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, int new_fd);
+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);
diff --git a/src/hnbgw_hnbap.c b/src/hnbgw_hnbap.c
index 4d7870e..6bc09d9 100644
--- a/src/hnbgw_hnbap.c
+++ b/src/hnbgw_hnbap.c
@@ -43,7 +43,9 @@
 		return -EINVAL;
 
 	msgb_sctp_ppid(msg) = IUH_PPI_HNBAP;
-	return osmo_wqueue_enqueue(&ctx->wqueue, msg);
+	osmo_stream_srv_send(ctx->conn, msg);
+
+	return 0;
 }
 
 static int hnbgw_tx_hnb_register_acc(struct hnb_context *ctx)
diff --git a/src/hnbgw_rua.c b/src/hnbgw_rua.c
index 9885553..4059cf8 100644
--- a/src/hnbgw_rua.c
+++ b/src/hnbgw_rua.c
@@ -44,7 +44,9 @@
 		return -EINVAL;
 
 	msgb_sctp_ppid(msg) = IUH_PPI_RUA;
-	return osmo_wqueue_enqueue(&ctx->wqueue, msg);
+	osmo_stream_srv_send(ctx->conn, msg);
+
+	return 0;
 }
 
 int rua_tx_udt(struct hnb_context *hnb, const uint8_t *data, unsigned int len)