libmsc/gsm_04_11.c: properly handle MMTS indication

According to 3GPP TS 29.002, section 7.6.8.7, MMS (More Messages to Send)
is an optional IE of MT-ForwardSM-Req message which is used by SMSC to
indicate that there are more (multi-part) MT SMS messages to be sent.

The MSC needs to use this indication in order to decide whether to
keep the RAN connection with a given subscriber open.

Related Change-Id: (TTCN) I6308586a70c4fb3254c519330a61a9667372149f
Change-Id: Ic46b04913b2e8cc5d11a39426dcc1bfe11f1d31e
Related: OS#3587
diff --git a/include/osmocom/msc/gsm_04_11.h b/include/osmocom/msc/gsm_04_11.h
index be8bff3..c504c7f 100644
--- a/include/osmocom/msc/gsm_04_11.h
+++ b/include/osmocom/msc/gsm_04_11.h
@@ -45,7 +45,8 @@
 		    struct gsm_sms *sms);
 int gsm411_send_rp_data(struct gsm_network *net, struct vlr_subscr *vsub,
 			size_t sm_rp_oa_len, const uint8_t *sm_rp_oa,
-			size_t sm_rp_ud_len, const uint8_t *sm_rp_ud);
+			size_t sm_rp_ud_len, const uint8_t *sm_rp_ud,
+			bool sm_rp_mmts_ind);
 
 void gsm411_sapi_n_reject(struct msc_a *msc_a);
 
diff --git a/include/osmocom/msc/msc_a.h b/include/osmocom/msc/msc_a.h
index c732695..a4d3226 100644
--- a/include/osmocom/msc/msc_a.h
+++ b/include/osmocom/msc/msc_a.h
@@ -45,6 +45,7 @@
 #define MSC_A_USE_PAGING_RESPONSE	"paging-response"
 #define MSC_A_USE_CC		"cc"
 #define MSC_A_USE_SMS		"sms"
+#define MSC_A_USE_SMS_MMTS	"sms_mmts"
 #define MSC_A_USE_NC_SS		"nc_ss"
 #define MSC_A_USE_SILENT_CALL	"silent_call"
 
diff --git a/include/osmocom/msc/transaction.h b/include/osmocom/msc/transaction.h
index 9278b64..ba609ea 100644
--- a/include/osmocom/msc/transaction.h
+++ b/include/osmocom/msc/transaction.h
@@ -110,6 +110,8 @@
 
 			/* SM-RP-MR, Message Reference (see GSM TS 04.11, section 8.2.3) */
 			uint8_t sm_rp_mr;
+			/* More Messages to Send (see 3GPP TS 29.002, section 7.6.8.7) */
+			bool sm_rp_mmts_ind;
 
 			struct gsm_sms *sms;
 		} sms;
diff --git a/src/libmsc/gsm_04_11.c b/src/libmsc/gsm_04_11.c
index a3b3830..3a3ec8c 100644
--- a/src/libmsc/gsm_04_11.c
+++ b/src/libmsc/gsm_04_11.c
@@ -129,6 +129,28 @@
 	return msc_a_tx_dtap_to_i(trans->msc_a, msg);
 }
 
+/* Handle MMTS (More Messages to Send) indication */
+static void gsm411_handle_mmts_ind(const struct gsm_trans *trans)
+{
+	int32_t use_count;
+
+	OSMO_ASSERT(trans);
+	OSMO_ASSERT(trans->msc_a);
+
+	use_count = osmo_use_count_by(&trans->msc_a->use_count, MSC_A_USE_SMS_MMTS);
+	OSMO_ASSERT(use_count >= 0); /* Shall not be negative */
+
+	if (trans->sms.sm_rp_mmts_ind && use_count == 0) {
+		LOG_TRANS(trans, LOGL_INFO, "Multi-part SMS delivery is initiated\n");
+		msc_a_get(trans->msc_a, MSC_A_USE_SMS_MMTS);
+	} else if (trans->sms.sm_rp_mmts_ind && use_count > 0) {
+		LOG_TRANS(trans, LOGL_INFO, "Continuing multi-part SMS delivery\n");
+	} else if (!trans->sms.sm_rp_mmts_ind && use_count > 0) {
+		LOG_TRANS(trans, LOGL_INFO, "Multi-part SMS delivery has been completed\n");
+		msc_a_put(trans->msc_a, MSC_A_USE_SMS_MMTS);
+	}
+}
+
 /* Paging callback for MT SMS (Paging is triggered by SMC) */
 static void mmsms_paging_cb(struct msc_a *msc_a, struct gsm_trans *trans)
 {
@@ -141,6 +163,10 @@
 		/* Associate transaction with established connection */
 		msc_a_get(msc_a, MSC_A_USE_SMS);
 		trans->msc_a = msc_a;
+
+		/* Multi-part SMS: handle MMTS (More Messages to Send) indication */
+		gsm411_handle_mmts_ind(trans);
+
 		/* Confirm successful connection establishment */
 		gsm411_smc_recv(&trans->sms.smc_inst, GSM411_MMSMS_EST_CNF, NULL, 0);
 	} else {
@@ -1180,7 +1206,8 @@
 /* Low-level function to send raw RP-DATA to a given subscriber */
 int gsm411_send_rp_data(struct gsm_network *net, struct vlr_subscr *vsub,
 			size_t sm_rp_oa_len, const uint8_t *sm_rp_oa,
-			size_t sm_rp_ud_len, const uint8_t *sm_rp_ud)
+			size_t sm_rp_ud_len, const uint8_t *sm_rp_ud,
+			bool sm_rp_mmts_ind)
 {
 	struct gsm_trans *trans;
 	struct msgb *msg;
@@ -1190,6 +1217,11 @@
 	if (!trans)
 		return -ENOMEM;
 
+	/* Multi-part SMS: handle MMTS (More Messages to Send) indication */
+	trans->sms.sm_rp_mmts_ind = sm_rp_mmts_ind;
+	if (trans->msc_a != NULL)
+		gsm411_handle_mmts_ind(trans);
+
 	/* Allocate a message buffer for to be encoded SMS */
 	msg = gsm411_msgb_alloc();
 	if (!msg) {
diff --git a/src/libmsc/gsm_04_11_gsup.c b/src/libmsc/gsm_04_11_gsup.c
index 9f5175b..a1ec634 100644
--- a/src/libmsc/gsm_04_11_gsup.c
+++ b/src/libmsc/gsm_04_11_gsup.c
@@ -234,6 +234,7 @@
 	const struct osmo_gsup_message *gsup_msg)
 {
 	struct gsm_network *net;
+	bool sm_rp_mmts_ind;
 	int rc;
 
 	/* Obtain required pointers */
@@ -267,10 +268,17 @@
 	if (gsup_msg->sm_rp_oa_type != OSMO_GSUP_SMS_SM_RP_ODA_SMSC_ADDR)
 		goto msg_error;
 
+	/* MMS (More Messages to Send) IE is optional */
+	if (gsup_msg->sm_rp_mms)
+		sm_rp_mmts_ind = *gsup_msg->sm_rp_mms > 0;
+	else
+		sm_rp_mmts_ind = false;
+
 	/* Send RP-DATA */
 	rc = gsm411_send_rp_data(net, vsub,
 		gsup_msg->sm_rp_oa_len, gsup_msg->sm_rp_oa,
-		gsup_msg->sm_rp_ui_len, gsup_msg->sm_rp_ui);
+		gsup_msg->sm_rp_ui_len, gsup_msg->sm_rp_ui,
+		sm_rp_mmts_ind);
 	if (rc) {
 		LOGP(DLSMS, LOGL_NOTICE, "Failed to send MT SMS, "
 			"ignoring MT-forwardSM-Req message...\n");