bsc: Add a ctrl command to send a ussdNotify for a call

Send a non-call related SS message for an active call indentified
by the CIC of that call. As an ugly hack the order of the SS
release and the invocation are changed. That was necessary for the
E71 on a TCH. The time between notify and release was just too short.
The right would be to wait for the returnResultLast but this would
involve keeping more local state. Let's see how far we get here. It
might be necessary to change the order in the other call sites as
well.
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c
index 8832057..6b6b8a1 100644
--- a/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c
+++ b/openbsc/src/osmo-bsc/osmo_bsc_ctrl.c
@@ -25,6 +25,7 @@
 #include <openbsc/osmo_bsc_rf.h>
 #include <openbsc/osmo_msc_data.h>
 #include <openbsc/signal.h>
+#include <openbsc/gsm_04_80.h>
 
 #include <osmocom/core/linuxlist.h>
 #include <osmocom/core/signal.h>
@@ -631,6 +632,78 @@
 	return 0;
 }
 
+CTRL_CMD_DEFINE(net_ussd_notify, "ussd-notify-v1");
+static int get_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
+{
+	cmd->reply = "There is nothing to read";
+	return CTRL_CMD_ERROR;
+}
+
+static int set_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
+{
+	struct gsm_subscriber_connection *conn;
+	struct gsm_network *net;
+	char *saveptr = NULL;
+	char *cic_str, *alert_str, *text_str;
+	int cic, alert;
+
+	/* Verify has done the test for us */
+	cic_str = strtok_r(cmd->value, ",", &saveptr);
+	alert_str = strtok_r(NULL, ",", &saveptr);
+	text_str = strtok_r(NULL, ",", &saveptr);
+
+	if (!cic_str || !alert_str || !text_str) {
+		cmd->reply = "Programming issue. How did this pass verify?";
+		return CTRL_CMD_ERROR;
+	}
+
+	cmd->reply = "No connection found";
+
+	cic = atoi(cic_str);
+	alert = atoi(alert_str);
+
+	net = cmd->node;
+	llist_for_each_entry(conn, bsc_api_sub_connections(net), entry) {
+		if (!conn->sccp_con)
+			continue;
+
+		if (conn->sccp_con->cic != cic)
+			continue;
+
+		/*
+		 * This is a hack. My E71 does not like to immediately
+		 * receive a release complete on a TCH. So schedule a
+		 * release complete to clear any previous attempt. The
+		 * right thing would be to track invokeId and only send
+		 * the release complete when we get a returnResultLast
+		 * for this invoke id.
+		 */
+		gsm0480_send_releaseComplete(conn);
+		gsm0480_send_ussdNotify(conn, alert, text_str);
+		cmd->reply = "Found a connection";
+		break;
+	}
+
+	return CTRL_CMD_REPLY;
+}
+
+static int verify_net_ussd_notify(struct ctrl_cmd *cmd, const char *value, void *data)
+{
+	char *saveptr = NULL;
+	char *inp, *cic, *alert, *text;
+
+	inp = talloc_strdup(cmd, value);
+
+	cic = strtok_r(inp, ",", &saveptr);
+	alert = strtok_r(NULL, ",", &saveptr);
+	text = strtok_r(NULL, ",", &saveptr);
+
+	talloc_free(inp);
+	if (!cic || !alert || !text)
+		return 1;
+	return 0;
+}
+
 static int msc_signal_handler(unsigned int subsys, unsigned int signal,
 			void *handler_data, void *signal_data)
 {
@@ -689,6 +762,9 @@
 	rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_inform_msc);
 	if (rc)
 		goto end;
+	rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_ussd_notify);
+	if (rc)
+		goto end;
 	rc = osmo_signal_register_handler(SS_L_INPUT, &bts_connection_status_trap_cb, net);
 
 end: