nat: Copy the IMSI, then free it or move the context to the connection

Extract the IMSI from the first message as well and safe it
in the connection structure. The problem is that we do not
have this structure at this point, so we will allocate the
imsi as child of the bsc_connection and then move/steal it.
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index 2792f00..6fc0e65 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -265,7 +265,7 @@
  * Content filtering.
  */
 int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
-			   struct bsc_nat_parsed *, int *con_type);
+			   struct bsc_nat_parsed *, int *con_type, char **imsi);
 int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg,
 		      struct sccp_connections *con, struct bsc_nat_parsed *parsed);
 
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index b8a6cfc..b82c4ef 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -784,6 +784,7 @@
 static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
 {
 	int con_filter = 0;
+	char *imsi = NULL;
 	struct bsc_msc_connection *con_msc = NULL;
 	struct bsc_connection *con_bsc = NULL;
 	int con_type;
@@ -818,7 +819,7 @@
 		struct sccp_connections *con;
 		switch (parsed->sccp_type) {
 		case SCCP_MSG_TYPE_CR:
-			filter = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &con_type);
+			filter = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &con_type, &imsi);
 			if (filter < 0) {
 				bsc_stat_reject(filter, bsc, 0);
 				goto exit3;
@@ -831,6 +832,9 @@
 			con_msc = con->msc_con;
 			con->con_type = con_type;
 			con->imsi_checked = filter;
+			if (imsi)
+				con->imsi = talloc_steal(con, imsi);
+			imsi = NULL;
 			con_bsc = con->bsc;
 			handle_con_stats(con);
 			break;
@@ -927,12 +931,16 @@
 	}
 
 exit2:
+	if (imsi)
+		talloc_free(imsi);
 	talloc_free(parsed);
 	msgb_free(msg);
 	return -1;
 
 exit3:
 	/* send a SCCP Connection Refused */
+	if (imsi)
+		talloc_free(imsi);
 	bsc_send_con_refuse(bsc, parsed, con_type);
 	talloc_free(parsed);
 	msgb_free(msg);
diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c
index 9e4ccc6..674de41 100644
--- a/openbsc/src/nat/bsc_nat_utils.c
+++ b/openbsc/src/nat/bsc_nat_utils.c
@@ -360,7 +360,9 @@
 	return 1;
 }
 
-static int _cr_check_loc_upd(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
+static int _cr_check_loc_upd(struct bsc_connection *bsc,
+			     uint8_t *data, unsigned int length,
+			     char **imsi)
 {
 	uint8_t mi_type;
 	struct gsm48_loc_upd_req *lu;
@@ -383,10 +385,13 @@
 		return 0;
 
 	gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
+	*imsi = talloc_strdup(bsc, mi_string);
 	return auth_imsi(bsc, mi_string);
 }
 
-static int _cr_check_cm_serv_req(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
+static int _cr_check_cm_serv_req(struct bsc_connection *bsc,
+				 uint8_t *data, unsigned int length,
+				 char **imsi)
 {
 	static const uint32_t classmark_offset =
 				offsetof(struct gsm48_service_request, classmark);
@@ -416,10 +421,13 @@
 	if (mi_type != GSM_MI_TYPE_IMSI)
 		return 0;
 
+	*imsi = talloc_strdup(bsc, mi_string);
 	return auth_imsi(bsc, mi_string);
 }
 
-static int _cr_check_pag_resp(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
+static int _cr_check_pag_resp(struct bsc_connection *bsc,
+			      uint8_t *data, unsigned int length,
+			      char **imsi)
 {
 	struct gsm48_pag_resp *resp;
 	char mi_string[GSM48_MI_SIZE];
@@ -440,6 +448,7 @@
 	if (mi_type != GSM_MI_TYPE_IMSI)
 		return 0;
 
+	*imsi = talloc_strdup(bsc, mi_string);
 	return auth_imsi(bsc, mi_string);
 }
 
@@ -474,7 +483,9 @@
 }
 
 /* Filter out CR data... */
-int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed, int *con_type)
+int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
+			   struct bsc_nat_parsed *parsed, int *con_type,
+			   char **imsi)
 {
 	struct tlv_parsed tp;
 	struct gsm48_hdr *hdr48;
@@ -483,6 +494,7 @@
 	uint8_t msg_type;
 
 	*con_type = NAT_CON_TYPE_NONE;
+	*imsi = NULL;
 
 	if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
 		LOGP(DNAT, LOGL_ERROR,
@@ -521,15 +533,15 @@
 	if (hdr48->proto_discr == GSM48_PDISC_MM &&
 	    msg_type == GSM48_MT_MM_LOC_UPD_REQUEST) {
 		*con_type = NAT_CON_TYPE_LU;
-		return _cr_check_loc_upd(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
+		return _cr_check_loc_upd(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48), imsi);
 	} else if (hdr48->proto_discr == GSM48_PDISC_MM &&
 		  msg_type == GSM48_MT_MM_CM_SERV_REQ) {
 		*con_type = NAT_CON_TYPE_CM_SERV_REQ;
-		return _cr_check_cm_serv_req(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
+		return _cr_check_cm_serv_req(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48), imsi);
 	} else if (hdr48->proto_discr == GSM48_PDISC_RR &&
 		   msg_type == GSM48_MT_RR_PAG_RESP) {
 		*con_type = NAT_CON_TYPE_PAG_RESP;
-		return _cr_check_pag_resp(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
+		return _cr_check_pag_resp(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48), imsi);
 	} else {
 		/* We only want to filter the above, let other things pass */
 		*con_type = NAT_CON_TYPE_OTHER;
diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c
index 75bd803..141775c 100644
--- a/openbsc/tests/bsc-nat/bsc_nat_test.c
+++ b/openbsc/tests/bsc-nat/bsc_nat_test.c
@@ -705,6 +705,7 @@
 	nat_entry = bsc_nat_acc_lst_entry_create(nat_lst);
 
 	for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
+		char *imsi;
 		msgb_reset(msg);
 		copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
 
@@ -727,7 +728,7 @@
 			abort();
 		}
 
-		res = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &contype);
+		res = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &contype, &imsi);
 		if (res != cr_filter[i].result) {
 			fprintf(stderr, "FAIL: Wrong result %d for test %d.\n", res, i);
 			abort();
@@ -738,6 +739,7 @@
 			abort();
 		}
 
+		talloc_steal(parsed, imsi);
 		talloc_free(parsed);
 	}