gprs: Support the full cancellation procedure

Currently no GSUP LocationCancellationResult message is sent back to
the peer (HLR), if the procedure succeeded at the SGSN's side.

This patch adds the missing message and put the whole request
handling of this procedure into a separate function.

Ticket: OW#1338
Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/gprs/gprs_subscriber.c b/openbsc/src/gprs/gprs_subscriber.c
index 271cc78..a30729d 100644
--- a/openbsc/src/gprs/gprs_subscriber.c
+++ b/openbsc/src/gprs/gprs_subscriber.c
@@ -490,6 +490,22 @@
 	return -gsup_msg->cause;
 }
 
+static int gprs_subscr_handle_loc_cancel_req(struct gsm_subscriber *subscr,
+					     struct gprs_gsup_message *gsup_msg)
+{
+	struct gprs_gsup_message gsup_reply = {0};
+
+	LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
+
+	gsup_reply.message_type = GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT;
+	gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
+
+	subscr->sgsn_data->error_cause = 0;
+	gprs_subscr_put_and_cancel(subscr_get(subscr));
+
+	return 0;
+}
+
 static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg)
 {
 	if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
@@ -546,9 +562,7 @@
 
 	switch (gsup_msg.message_type) {
 	case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
-		subscr->sgsn_data->error_cause = 0;
-		gprs_subscr_put_and_cancel(subscr);
-		subscr = NULL;
+		rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg);
 		break;
 
 	case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
@@ -596,8 +610,7 @@
 		break;
 	};
 
-	if (subscr)
-		subscr_put(subscr);
+	subscr_put(subscr);
 
 	return rc;
 }
diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c
index c09b169..662227d 100644
--- a/openbsc/tests/sgsn/sgsn_test.c
+++ b/openbsc/tests/sgsn/sgsn_test.c
@@ -468,6 +468,12 @@
 		0x06, 0x01, 0x00,
 	};
 
+	static const uint8_t location_cancellation_req_other[] = {
+		0x1c,
+		0x01, 0x05, 0x11, 0x11, 0x11, 0x11, 0x01,
+		0x06, 0x01, 0x00,
+	};
+
 	static const uint8_t insert_data_req[] = {
 		0x10,
 		TEST_GSUP_IMSI1_IE,
@@ -554,6 +560,17 @@
 	OSMO_ASSERT(rc == -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
 	OSMO_ASSERT(last_updated_subscr == NULL);
 
+	/* Inject wrong LocCancelReq GSUP message */
+	last_updated_subscr = NULL;
+	rc = rx_gsup_message(location_cancellation_req_other,
+			     sizeof(location_cancellation_req_other));
+	OSMO_ASSERT(rc == -GMM_CAUSE_IMSI_UNKNOWN);
+	OSMO_ASSERT(last_updated_subscr == NULL);
+
+	/* Check cancellation result */
+	OSMO_ASSERT(!(s1->flags & GPRS_SUBSCRIBER_CANCELLED));
+	OSMO_ASSERT(s1->sgsn_data->mm != NULL);
+
 	/* Inject LocCancelReq GSUP message */
 	rc = rx_gsup_message(location_cancellation_req,
 			     sizeof(location_cancellation_req));