ussd: Keep track of used TIs for USSD and forward messages

Keep track of the used transaction identifier and always forward
messages to the USSD provider. E.g. this can be used to have a
dialogue going. Right now it is still possible that the MSC will
close down the connection.
diff --git a/openbsc/include/openbsc/bsc_nat_sccp.h b/openbsc/include/openbsc/bsc_nat_sccp.h
index a66732d..20db2c1 100644
--- a/openbsc/include/openbsc/bsc_nat_sccp.h
+++ b/openbsc/include/openbsc/bsc_nat_sccp.h
@@ -80,6 +80,9 @@
 	int imsi_checked;
 	char *imsi;
 
+	/* remember which Transactions we run over the bypass */
+	char ussd_ti[8];
+
 	/*
 	 * audio handling. Remember if we have ever send a CRCX,
 	 * remember the endpoint used by the MSC and BSC.
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c
index c9c9b7b..4a6e36d 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c
@@ -981,6 +981,8 @@
 					msg = bsc_nat_rewrite_setup(bsc->nat, msg, parsed, con->imsi);
 					talloc_free(parsed);
 					parsed = NULL;
+				} else if (con->con_local == NAT_CON_END_USSD) {
+					bsc_check_ussd(con, parsed, msg);
 				}
 
 				con_bsc = con->bsc;
diff --git a/openbsc/src/osmo-bsc_nat/bsc_ussd.c b/openbsc/src/osmo-bsc_nat/bsc_ussd.c
index 8c8963e..0392e9b 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_ussd.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_ussd.c
@@ -252,6 +252,30 @@
 			 ntohl(addr.s_addr), 5001, 0, ussd_listen_cb, nat);
 }
 
+static int forward_ussd_simple(struct sccp_connections *con, struct msgb *input)
+{
+	struct msgb *copy;
+	struct bsc_nat_ussd_con *ussd;
+
+	if (!con->bsc->nat->ussd_con)
+		return -1;
+
+	copy = msgb_alloc_headroom(4096, 128, "forward bts");
+	if (!copy) {
+		LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n");
+		return -1;
+	}
+
+	/* copy the data into the copy */
+	copy->l2h = msgb_put(copy, msgb_l2len(input));
+	memcpy(copy->l2h, input->l2h, msgb_l2len(input));
+
+	/* send it out */
+	ussd = con->bsc->nat->ussd_con;
+	bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP);
+	return 0;
+}
+
 static int forward_ussd(struct sccp_connections *con, const struct ussd_request *req,
 			struct msgb *input)
 {
@@ -302,6 +326,7 @@
 	uint32_t len;
 	uint8_t msg_type;
 	uint8_t proto;
+	uint8_t ti;
 	struct gsm48_hdr *hdr48;
 	struct bsc_nat_acc_lst *lst;
 	struct ussd_request req;
@@ -338,30 +363,45 @@
 
 	proto = hdr48->proto_discr & 0x0f;
 	msg_type = hdr48->msg_type & 0xbf;
-	if (proto != GSM48_PDISC_NC_SS || msg_type != GSM0480_MTYPE_REGISTER)
+	ti = (hdr48->proto_discr & 0x70) >> 4;
+	if (proto != GSM48_PDISC_NC_SS)
 		return 0;
 
-	/* now check if it is a IMSI we care about */
-	lst = bsc_nat_acc_lst_find(con->bsc->nat, con->bsc->nat->ussd_lst_name);
-	if (!lst)
-		return 0;
+	if (msg_type == GSM0480_MTYPE_REGISTER) {
 
-	if (bsc_nat_lst_check_allow(lst, con->imsi) != 0)
-		return 0;
+		/* now check if it is a IMSI we care about */
+		lst = bsc_nat_acc_lst_find(con->bsc->nat,
+					   con->bsc->nat->ussd_lst_name);
+		if (!lst)
+			return 0;
 
-	/* now decode the message and see if we really want to handle it */
-	memset(&req, 0, sizeof(req));
-	if (gsm0480_decode_ussd_request(hdr48, len, &req) != 1)
-		return 0;
-	if (req.text[0] == 0xff)
-		return 0;
+		if (bsc_nat_lst_check_allow(lst, con->imsi) != 0)
+			return 0;
 
-	if (regexec(&con->bsc->nat->ussd_query_re, req.text, 0, NULL, 0) == REG_NOMATCH)
-		return 0;
+		/* now decode the message and see if we really want to handle it */
+		memset(&req, 0, sizeof(req));
+		if (gsm0480_decode_ussd_request(hdr48, len, &req) != 1)
+			return 0;
+		if (req.text[0] == 0xff)
+			return 0;
 
-	/* found a USSD query for our subscriber */
-	LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n", con->imsi);
-	if (forward_ussd(con, &req, msg) != 0)
-		return 0;
-	return 1;
+		if (regexec(&con->bsc->nat->ussd_query_re,
+			    req.text, 0, NULL, 0) == REG_NOMATCH)
+			return 0;
+
+		/* found a USSD query for our subscriber */
+		LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n", con->imsi);
+		con->ussd_ti[ti] = 1;
+		if (forward_ussd(con, &req, msg) != 0)
+			return 0;
+		return 1;
+	} else if (msg_type == GSM0480_MTYPE_FACILITY && con->ussd_ti[ti]) {
+		LOGP(DNAT, LOGL_NOTICE, "Forwarding message part of TI: %d %s\n",
+		     ti, con->imsi);
+		if (forward_ussd_simple(con, msg) != 0)
+			return 0;
+		return 1;
+	}
+
+	return 0;
 }