Merge branch 'zecke/ussd-side-channel'
diff --git a/openbsc/configure.in b/openbsc/configure.in
index c0ec3cd..f98bb70 100644
--- a/openbsc/configure.in
+++ b/openbsc/configure.in
@@ -43,7 +43,7 @@
     ])
 AM_CONDITIONAL(BUILD_BSC, test "x$osmo_ac_build_bsc" = "xyes")
 
-PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.24)
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.27)
 PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.1.19)
 
 dnl checks for header files
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index acecba7..7c7dde3 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -337,5 +337,6 @@
 /** USSD filtering */
 int bsc_ussd_init(struct bsc_nat *nat);
 int bsc_check_ussd(struct sccp_connections *con, struct bsc_nat_parsed *parsed, struct msgb *msg);
+int bsc_close_ussd_connections(struct bsc_nat *nat);
 
 #endif
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index daabf09..a428e82 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -208,7 +208,7 @@
 	bsc_send_data(bsc, id_req, sizeof(id_req), IPAC_PROTO_IPACCESS);
 }
 
-static void nat_send_rlsd(struct sccp_connections *conn)
+static void nat_send_rlsd_msc(struct sccp_connections *conn)
 {
 	struct sccp_connection_released *rel;
 	struct msgb *msg;
@@ -231,6 +231,49 @@
 	queue_for_msc(conn->msc_con, msg);
 }
 
+static void nat_send_rlsd_bsc(struct sccp_connections *conn)
+{
+	struct sccp_connection_released *rel;
+	struct msgb *msg;
+
+	msg = msgb_alloc_headroom(4096, 128, "rlsd");
+	if (!msg) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n");
+		return;
+	}
+
+	msg->l2h = msgb_put(msg, sizeof(*rel));
+	rel = (struct sccp_connection_released *) msg->l2h;
+	rel->type = SCCP_MSG_TYPE_RLSD;
+	rel->release_cause = SCCP_RELEASE_CAUSE_SCCP_FAILURE;
+	rel->destination_local_reference = conn->real_ref;
+	rel->source_local_reference = conn->remote_ref;
+
+	bsc_write(conn->bsc, msg, IPAC_PROTO_SCCP);
+}
+
+static void nat_send_clrc_bsc(struct sccp_connections *conn)
+{
+	struct msgb *msg;
+	struct msgb *sccp;
+
+	msg = gsm0808_create_clear_command(0x20);
+	if (!msg) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n");
+		return;
+	}
+
+	sccp = sccp_create_dt1(&conn->real_ref, msg->data, msg->len);
+	if (!sccp) {
+		LOGP(DNAT, LOGL_ERROR, "Failed to allocate SCCP msg.\n");
+		msgb_free(msg);
+		return;
+	}
+
+	msgb_free(msg);
+	bsc_write(conn->bsc, sccp, IPAC_PROTO_SCCP);
+}
+
 static void nat_send_rlc(struct bsc_msc_connection *msc_con,
 			 struct sccp_source_reference *src,
 			 struct sccp_source_reference *dst)
@@ -709,7 +752,7 @@
 		if (ctr)
 			rate_ctr_inc(ctr);
 		if (sccp_patch->has_remote_ref && !sccp_patch->con_local)
-			nat_send_rlsd(sccp_patch);
+			nat_send_rlsd_msc(sccp_patch);
 		sccp_connection_destroy(sccp_patch);
 	}
 
@@ -1307,3 +1350,20 @@
 
 	return 0;
 }
+
+/* Close all connections handed out to the USSD module */
+int bsc_close_ussd_connections(struct bsc_nat *nat)
+{
+	struct sccp_connections *con;
+	llist_for_each_entry(con, &nat->sccp_connections, list_entry) {
+		if (con->con_local != 2)
+			continue;
+		if (!con->bsc)
+			continue;
+
+		nat_send_clrc_bsc(con);
+		nat_send_rlsd_bsc(con);
+	}
+
+	return 0;
+}
diff --git a/openbsc/src/nat/bsc_ussd.c b/openbsc/src/nat/bsc_ussd.c
index 3729d91..f10a871 100644
--- a/openbsc/src/nat/bsc_ussd.c
+++ b/openbsc/src/nat/bsc_ussd.c
@@ -61,8 +61,11 @@
 
 static void bsc_nat_ussd_destroy(struct bsc_nat_ussd_con *con)
 {
-	if (con->nat->ussd_con == con)
+	if (con->nat->ussd_con == con) {
+		bsc_close_ussd_connections(con->nat);
 		con->nat->ussd_con = NULL;
+	}
+
 	close(con->queue.bfd.fd);
 	bsc_unregister_fd(&con->queue.bfd);
 	bsc_del_timer(&con->auth_timeout);