msc: Create a dummy operation to keep the channel open for five seconds

* We should create the transaction for SMS, CC on the CM Service Request
  but for now we will use a band aid and create a dummy operarion to wait
  five seconds for the transaction to be opened.
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index 33da5e5..aa070eb 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -28,6 +28,7 @@
 int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg);
 
 int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id);
+int gsm0408_new_conn(struct gsm_subscriber_connection *conn);
 enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
 enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci);
 
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index e03ad3a..36591cf 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -179,6 +179,14 @@
 	void *cb_data;
 };
 
+/*
+ * A dummy to keep a connection up for at least
+ * a couple of seconds to work around MSC issues.
+ */
+struct gsm_anchor_operation {
+	struct timer_list timeout;
+};
+
 /* Maximum number of neighbor cells whose average we track */
 #define MAX_NEIGH_MEAS		10
 /* Maximum size of the averaging window for neighbor cells */
@@ -224,6 +232,7 @@
 	 */
 	struct gsm_loc_updating_operation *loc_operation;
 	struct gsm_security_operation *sec_operation;
+	struct gsm_anchor_operation *anch_operation;
 
 	/* Are we part of a special "silent" call */
 	int silent_call;
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index 7bf30e7..e10177d 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -63,6 +63,7 @@
 static int gsm48_tx_simple(struct gsm_subscriber_connection *conn,
 			   u_int8_t pdisc, u_int8_t msg_type);
 static void schedule_reject(struct gsm_subscriber_connection *conn);
+static void release_anchor(struct gsm_subscriber_connection *conn);
 
 struct gsm_lai {
 	u_int16_t mcc;
@@ -218,6 +219,9 @@
 	if (!conn->loc_operation)
 		return;
 
+	/* No need to keep the connection up */
+	release_anchor(conn);
+
 	bsc_del_timer(&conn->loc_operation->updating_timer);
 	talloc_free(conn->loc_operation);
 	conn->loc_operation = 0;
@@ -294,6 +298,7 @@
 	 */
 	release_loc_updating_req(conn);
 	release_security_operation(conn);
+	release_anchor(conn);
 
 	/* Free all transactions that are associated with the released lchan */
 	/* FIXME: this is not neccessarily the right thing to do, we should
@@ -3076,6 +3081,37 @@
 	return rc;
 }
 
+/* Create a dummy to wait five seconds */
+static void release_anchor(struct gsm_subscriber_connection *conn)
+{
+	if (!conn->anch_operation)
+		return;
+
+	bsc_del_timer(&conn->anch_operation->timeout);
+	talloc_free(conn->anch_operation);
+	conn->anch_operation = NULL;
+}
+
+static void anchor_timeout(void *_data)
+{
+	struct gsm_subscriber_connection *con = _data;
+
+	release_anchor(con);
+	msc_release_connection(con);
+}
+
+int gsm0408_new_conn(struct gsm_subscriber_connection *conn)
+{
+	conn->anch_operation = talloc_zero(conn, struct gsm_anchor_operation);
+	if (!conn->anch_operation)
+		return -1;
+
+	conn->anch_operation->timeout.data = conn;
+	conn->anch_operation->timeout.cb = anchor_timeout;
+	bsc_schedule_timer(&conn->anch_operation->timeout, 5, 0);
+	return 0;
+}
+
 /* here we get data from the BSC level... */
 int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg)
 {
@@ -3088,6 +3124,7 @@
 	
 	switch (pdisc) {
 	case GSM48_PDISC_CC:
+		release_anchor(conn);
 		rc = gsm0408_rcv_cc(conn, msg);
 		break;
 	case GSM48_PDISC_MM:
@@ -3097,6 +3134,7 @@
 		rc = gsm0408_rcv_rr(conn, msg);
 		break;
 	case GSM48_PDISC_SMS:
+		release_anchor(conn);
 		rc = gsm0411_rcv_sms(conn, msg);
 		break;
 	case GSM48_PDISC_MM_GPRS:
@@ -3105,6 +3143,7 @@
 			"GSM 04.08 discriminator 0x%02x\n", pdisc);
 		break;
 	case GSM48_PDISC_NC_SS:
+		release_anchor(conn);
 		rc = handle_rcv_ussd(conn, msg);
 		break;
 	default:
diff --git a/openbsc/src/osmo_msc.c b/openbsc/src/osmo_msc.c
index 6a94e7a..6543a61 100644
--- a/openbsc/src/osmo_msc.c
+++ b/openbsc/src/osmo_msc.c
@@ -44,6 +44,7 @@
 static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
 			uint16_t chosen_channel)
 {
+	gsm0408_new_conn(conn);
 	gsm0408_dispatch(conn, msg);
 
 	/* TODO: do better */
@@ -80,7 +81,7 @@
 		return;
 
 	/* check if there is a pending operation */
-	if (conn->loc_operation || conn->sec_operation)
+	if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
 		return;
 
 	llist_for_each_entry(trans, &conn->bts->network->trans_list, entry) {