Fix vty PDP lookups by IMSI

The PDP context is searched on the hash which is generated
on context creation from the IMSI in gtp format. - A hash
created from "human-readable" IMSI does not match.
Check user input for length then convert the IMSI to gtp format
before continuing.

Change-Id: Icd2e2bc6068c06fbf5d5fe905ebcda8954f33f04
diff --git a/ggsn/ggsn_vty.c b/ggsn/ggsn_vty.c
index cb92a8a..91ffe4e 100644
--- a/ggsn/ggsn_vty.c
+++ b/ggsn/ggsn_vty.c
@@ -894,7 +894,12 @@
 		return CMD_WARNING;
 	}
 
-	imsi = strtoull(argv[1], NULL, 10);
+	if (strlen(argv[1]) < 6 || strlen(argv[1]) > 15) {
+		vty_out(vty, "%% Invalid IMSI '%s'%s", argv[1], VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	imsi = imsi_str2gtp(argv[1]);
 
 	if (argc > 2) {
 		nsapi = atoi(argv[2]);
diff --git a/gtp/gtp.c b/gtp/gtp.c
index ec83041..d4c83d9 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -3492,3 +3492,17 @@
 	buf[j++] = '\0';
 	return buf;
 }
+
+/* Encode an IMSI with gtp encoding according to TS 29.060 - the
+   reverse of imsi_gtp2str(). The hash index used for context
+   lookups is generated from the IMSI in gtp format. User input
+   in the vty (for example) needs to be converted to match. */
+const uint64_t imsi_str2gtp(const char *imsi)
+{
+	uint64_t ret = 0xf000000000000000ull;
+	unsigned int i, imsi_length = strlen(imsi);
+
+	for (i = 0; i < imsi_length; i++)
+		ret |= ((uint64_t) (imsi[i] - '0')) << (i * 4);
+	return ret;
+}
\ No newline at end of file
diff --git a/gtp/gtp.h b/gtp/gtp.h
index e03d77d..95566fa 100644
--- a/gtp/gtp.h
+++ b/gtp/gtp.h
@@ -441,5 +441,6 @@
 extern int gsna2in_addr(struct in_addr *dst, struct ul16_t *gsna);
 extern int in_addr2gsna(struct ul16_t *gsna, struct in_addr *src);
 extern const char *imsi_gtp2str(const uint64_t *imsi);
+extern const uint64_t imsi_str2gtp(const char *imsi);
 
 #endif /* !_GTP_H */