WIP

Change-Id: Ia8d595095462c30a56b8a0b30c8d24632776e4cc
diff --git a/gtp/gsn.c b/gtp/gsn.c
index 2b8d9c5..5c63c17 100644
--- a/gtp/gsn.c
+++ b/gtp/gsn.c
@@ -245,7 +245,7 @@
 	return 0;
 }
 int gtp_set_cb_sgsn_context_request_ind(struct gsn_t *gsn,
-			     int (*cb) (struct gsn_t *gsn, struct sockaddr_in *peer, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie))
+			     int (*cb) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie))
 {
 	gsn->cb_sgsn_context_request_ind = cb;
 	return 0;
diff --git a/gtp/gsn.h b/gtp/gsn.h
index be7cd53..0e4f71c 100644
--- a/gtp/gsn.h
+++ b/gtp/gsn.h
@@ -109,7 +109,7 @@
 	int (*cb_recovery) (struct sockaddr_in * peer, uint8_t recovery);
 	int (*cb_recovery2) (struct sockaddr_in * peer, struct pdp_t * pdp, uint8_t recovery);
 	int (*cb_recovery3) (struct gsn_t *gsn, struct sockaddr_in *peer, struct pdp_t *pdp, uint8_t recovery);
-	int (*cb_sgsn_context_request_ind) (struct gsn_t *gsn, struct sockaddr_in *peer, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie); /* Pass RAI and TLLI/TMSI/IMSI directly */
+	int (*cb_sgsn_context_request_ind) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie); /* Pass RAI and TLLI/TMSI/IMSI directly */
 
 	/* Counters */
 	struct rate_ctr_group *ctrg;
@@ -158,7 +158,7 @@
 				    int (*cb) (struct sockaddr_in * peer, union gtpie_member **ie));
 
 extern int gtp_set_cb_sgsn_context_request_ind(struct gsn_t *gsn,
-			     int (*cb) (struct gsn_t *gsn, struct sockaddr_in *peer, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie));
+			     int (*cb) (struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq, const struct osmo_routing_area_id *rai, uint32_t teic, struct osmo_mobile_identity *mi, union gtpie_member **ie));
 
 extern int gtp_set_cb_conf(struct gsn_t *gsn,
 			   int (*cb) (int type, int cause, struct pdp_t * pdp,
diff --git a/gtp/gtp.c b/gtp/gtp.c
index bd777d9..e0d186f 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -537,8 +537,9 @@
 		return -1;
 	}
 
-	gtp_resp2(gsn, packet, len, peer, fd, seq, tid, flow, tei);
+	return gtp_resp2(gsn, packet, len, peer, fd, seq, tid, flow, tei);
 }
+
 static int gtp_notification(struct gsn_t *gsn, uint8_t version,
 		     union gtp_packet *packet, int len,
 		     const struct sockaddr_in *peer, int fd, uint16_t seq)
@@ -840,8 +841,9 @@
 
 #define GSM_MI_TYPE_TLLI 0x05
 
+/* Send an SGSN Context Request for an MI */
 int gtp_sgsn_context_req(struct gsn_t *gsn, const struct in_addr *peer,
-			 const struct osmo_mobile_identity *mi, uint32_t teic,
+			 const struct osmo_mobile_identity *mi, uint16_t tlli, uint32_t teic,
 			 const struct ul16_t *sgsn_addr, const struct ul255_t *rai, void *cbp)
 {
 	union gtp_packet packet;
@@ -855,8 +857,12 @@
 
 	switch (mi->type) {
 	case GSM_MI_TYPE_IMSI:
-		gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, *(uint64_t *)mi->imsi); /* FIXME: proper decoding*/
+	{
+		uint64_t imsi = gtp_imsi_str2gtp(mi->imsi);
+		imsi = ntoh64(imsi);
+		gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, imsi);
 		break;
+	}
 	case GSM_MI_TYPE_TLLI:
 		gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TLLI, mi->tmsi);
 		break;
@@ -864,6 +870,7 @@
 		gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_P_TMSI, mi->tmsi);
 		break;
 	default:
+		return -1;
 		/* TODO: Error */
 		break;
 	}
@@ -941,8 +948,9 @@
 	}
 
 	if (!gtpie_gettv8(ie, GTPIE_IMSI, 0, &imsi)) {
-		imsi = ntoh64(imsi);
 		mi.type = GSM_MI_TYPE_IMSI;
+		/* NOTE: gtpie_gettv8 already converts to host byte order, but imsi_gtp2str seems to prefer big endian */
+		imsi = ntoh64(imsi);
 		const char *imsi_str = imsi_gtp2str(&imsi);
 		memcpy(mi.imsi, imsi_str, sizeof(mi.imsi));
 	} else {
@@ -953,7 +961,7 @@
 
 done:
 	if (gsn->cb_sgsn_context_request_ind)
-		gsn->cb_sgsn_context_request_ind(gsn, peer, &rai_parsed, teic, &mi, ie);
+		gsn->cb_sgsn_context_request_ind(gsn, peer, seq, &rai_parsed, teic, &mi, ie);
 
 	return 0;
 
@@ -1029,9 +1037,9 @@
 	*ptr++ = pdp->pdp_id;
 	// PDP Type Org
 	*ptr++ = PDP_EUA_ORG_IETF;
+
 	// PDP Type No.
 	// PDP Address
-
 	switch (pdp->eua.v[1]) {
 	case PDP_EUA_TYPE_v4:
 	case PDP_EUA_TYPE_v4v6:
@@ -1079,7 +1087,7 @@
 }
 
 int gtp_sgsn_context_conf(struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq,
-			 uint32_t teic, uint8_t cause, const struct in_addr *sgsn_addr, struct pdp_t *pdpctx, uint16_t sapi, struct ul255_t *mmctx, void *cbp)
+			 uint32_t teic, uint8_t cause, uint64_t imsi, const struct in_addr *sgsn_addr, struct pdp_t *pdpctx, uint16_t sapi, uint8_t *mmctx, int mm_len, void *cbp)
 {
 	union gtp_packet packet;
 	struct ul255_t pdp;
@@ -1089,14 +1097,18 @@
 
 	// Cause - TV1
 	gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause);
+
+	if (cause != GTPCAUSE_ACC_REQ)
+		return gtp_resp2(gsn, &packet, length, peer, gsn->fd1c, seq, 0, 0, teic);
+
 	// IMSI - TV8
-	//gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, imsi);
+	gtpie_tv8(&packet, &length, GTP_MAX, GTPIE_IMSI, imsi);
 
 	// TEIC - TV4
 	gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, pdpctx->teic_own);
 
 	// MM Ctx - TLV
-	gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MM_CONTEXT, mmctx->l, mmctx->v);
+	gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MM_CONTEXT, mm_len, mmctx);
 
 	// PDP Ctx - TLV
 	if (pdpctx) {
@@ -1129,7 +1141,6 @@
 	uint8_t cause;
 	union gtpie_member *ie[GTPIE_SIZE];
 	struct pdp_t *pdp = NULL;
-	uint64_t imsi;
 	uint32_t teic;
 	struct ul16_t sgsn_addr;
 
diff --git a/gtp/gtp.h b/gtp/gtp.h
index d3ddea0..933de24 100644
--- a/gtp/gtp.h
+++ b/gtp/gtp.h
@@ -263,10 +263,10 @@
 				  uint8_t rim_route_addr_discr);
 
 extern int gtp_sgsn_context_req(struct gsn_t *gsn, const struct in_addr *peer,
-			 const struct osmo_mobile_identity *mi, uint32_t teic,
+			 const struct osmo_mobile_identity *mi, uint16_t tlli, uint32_t teic,
 			 const struct ul16_t *sgsn_addr, const struct ul255_t *rai, void *cbp);
 extern int gtp_sgsn_context_conf(struct gsn_t *gsn, struct sockaddr_in *peer, uint16_t seq,
-			 uint32_t teic, uint8_t cause, const struct in_addr *sgsn_addr, struct pdp_t *pdpctx, uint16_t sapi, struct ul255_t *mmctx, void *cbp);
+			 uint32_t teic, uint8_t cause, uint64_t imsi, const struct in_addr *sgsn_addr, struct pdp_t *pdpctx, uint16_t sapi, uint8_t *mmctx, int mm_len, void *cbp);
 
 extern int gtp_decaps0(struct gsn_t *gsn);
 extern int gtp_decaps1c(struct gsn_t *gsn);