Add support for GTP IE's from 3GPP R7

This adds support for the followng new GTP Information Elements:
	RAT_TYPE, USER_LOC, MS_TZ, IMEI_SV

Furthermore, it allows to specify those fields as sgsnemu command line
arguments.
diff --git a/gtp/gtp.c b/gtp/gtp.c
index 3ffdb60..133e2aa 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -1136,6 +1136,23 @@
     gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID,
 	      pdp->omcid.l, pdp->omcid.v);
   
+  /* new R7 fields */
+  if (pdp->rattype_given == 1)
+    gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_RAT_TYPE,
+              pdp->rattype.l, pdp->rattype.v);
+
+  if (pdp->userloc_given == 1)
+    gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_USER_LOC,
+              pdp->userloc.l, pdp->userloc.v);
+
+  if (pdp->mstz_given == 1)
+    gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MS_TZ,
+              pdp->mstz.l, pdp->mstz.v);
+
+  if (pdp->imeisv_given == 1)
+    gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_IMEI_SV,
+              pdp->imeisv.l, pdp->imeisv.v);
+
   /* TODO hisaddr0 */
   gtp_req(gsn, pdp->version, pdp, &packet, length, &pdp->hisaddr0, cbp);
 
diff --git a/gtp/gtpie.c b/gtp/gtpie.c
index c75408e..80370a5 100644
--- a/gtp/gtpie.c
+++ b/gtp/gtpie.c
@@ -328,6 +328,10 @@
     case GTPIE_TRIGGER_ID:
     case GTPIE_OMC_ID:
     case GTPIE_CHARGING_ADDR:
+    case GTPIE_RAT_TYPE:
+    case GTPIE_USER_LOC:
+    case GTPIE_MS_TZ:
+    case GTPIE_IMEI_SV:
     case GTPIE_PRIVATE:
       if (j<GTPIE_SIZE) {
 	ie[j] = (union gtpie_member*) p;
diff --git a/gtp/gtpie.h b/gtp/gtpie.h
index 83886f5..b8fe1e7 100644
--- a/gtp/gtpie.h
+++ b/gtp/gtpie.h
@@ -104,6 +104,10 @@
 #define GTPIE_EXT_HEADER_T  141 /* Extension Header Type List */
 #define GTPIE_TRIGGER_ID    142 /* Trigger Id */
 #define GTPIE_OMC_ID        143 /* OMC Identity */
+#define GTPIE_RAT_TYPE      151 /* Radio Access Technology Type */
+#define GTPIE_USER_LOC      152 /* User Location Information  */
+#define GTPIE_MS_TZ         153 /* MS Time Zone */
+#define GTPIE_IMEI_SV       154 /* IMEI Software Version */
 /* 239-250 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */
 #define GTPIE_CHARGING_ADDR 251 /* Charging Gateway Address */
 /* 252-254 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */
diff --git a/gtp/pdp.h b/gtp/pdp.h
index 624c4ac..d826d77 100644
--- a/gtp/pdp.h
+++ b/gtp/pdp.h
@@ -188,6 +188,14 @@
   struct ul255_t pco_req;  /* Requested packet control options. */
   struct ul255_t pco_neg;  /* Negotiated packet control options. */
   uint32_t    selmode;  /* Selection mode. */
+  struct ul255_t    rattype;  /* Radio Access Technology Type */
+  int    rattype_given;  /* Radio Access Technology Type given*/
+  struct ul255_t    userloc;  /* User Location Information  */
+  int    userloc_given;  /* User Location Information  given*/
+  struct ul255_t    mstz;  /* MS Time Zone */
+  int    mstz_given;  /* MS Time Zone given*/
+  struct ul255_t    imeisv;  /* IMEI Software Version */
+  int    imeisv_given;  /* IMEI Software Version given*/
 
   /* Additional parameters used by library */
 
diff --git a/sgsnemu/cmdline.c b/sgsnemu/cmdline.c
index 0bf6332..f40c583 100644
--- a/sgsnemu/cmdline.c
+++ b/sgsnemu/cmdline.c
@@ -40,6 +40,10 @@
   "      --gtpversion=INT   GTP version to use  (default=`1')",
   "  -a, --apn=STRING       Access point name  (default=`internet')",
   "      --selmode=INT      Selection mode  (default=`0x01')",
+  "      --rattype=INT      Radio Access Technology Type (optional-1to5)",
+  "      --userloc=STRING   User Location Information (optional-type.MCC.MNC.LAC.CIorSACorRAC)",
+  "      --mstz=STRING      MS Time Zone (optional- sign.NbQuartersOfAnHour.DSTAdjustment)",
+  "      --imeisv=STRING    IMEI(SV) International Mobile Equipment Identity (and Software Version) (optional,16 digits)",
   "  -i, --imsi=STRING      IMSI  (default=`240010123456789')",
   "      --nsapi=INT        NSAPI  (default=`0')",
   "  -m, --msisdn=STRING    Mobile Station ISDN number  (default=`46702123456')",
@@ -113,6 +117,10 @@
   args_info->gtpversion_given = 0 ;
   args_info->apn_given = 0 ;
   args_info->selmode_given = 0 ;
+  args_info->rattype_given = 0 ;
+  args_info->userloc_given = 0 ;
+  args_info->mstz_given = 0 ;
+  args_info->imeisv_given = 0 ;
   args_info->imsi_given = 0 ;
   args_info->nsapi_given = 0 ;
   args_info->msisdn_given = 0 ;
@@ -158,6 +166,14 @@
   args_info->apn_orig = NULL;
   args_info->selmode_arg = 0x01;
   args_info->selmode_orig = NULL;
+  args_info->rattype_arg = "1";
+  args_info->rattype_orig = NULL;
+  args_info->userloc_arg = strdup("02509946241207");
+  args_info->userloc_orig = NULL;
+  args_info->mstz_arg = strdup("0");
+  args_info->mstz_orig = NULL;
+  args_info->imeisv_arg = strdup("2143658709214365");
+  args_info->imeisv_orig = NULL;
   args_info->imsi_arg = gengetopt_strdup ("240010123456789");
   args_info->imsi_orig = NULL;
   args_info->nsapi_arg = 0;
@@ -768,6 +784,10 @@
         { "gtpversion",	1, NULL, 0 },
         { "apn",	1, NULL, 'a' },
         { "selmode",	1, NULL, 0 },
+        { "rattype",   1, NULL, 0},
+        { "userloc",   1, NULL, 0},
+        { "mstz",      1, NULL, 0},
+        { "imeisv",    1, NULL, 0},
         { "imsi",	1, NULL, 'i' },
         { "nsapi",	1, NULL, 0 },
         { "msisdn",	1, NULL, 'm' },
@@ -1143,6 +1163,55 @@
               free (args_info->selmode_orig); /* free previous string */
             args_info->selmode_orig = gengetopt_strdup (optarg);
           }
+         /* Radio Access Technology Type.  */
+          else if (strcmp (long_options[option_index].name, "rattype") == 0)
+          {
+            if (args_info->rattype_given)
+              {
+                fprintf (stderr, "%s: `--rattype' option given more than once\n", PACKAGE);
+                exit (EXIT_FAILURE);
+              }
+            args_info->rattype_given = 1;
+            /* args_info->rattype_arg = strtol (optarg,&stop_char,0); */
+            args_info->rattype_arg = strdup (optarg);
+            break;
+          }
+         /* User Location Information.  */
+          else if (strcmp (long_options[option_index].name, "userloc") == 0)
+          {
+            if (args_info->userloc_given)
+              {
+                fprintf (stderr, "%s: `--userloc' option given more than once\n", PACKAGE);
+                exit (EXIT_FAILURE);
+              }
+            args_info->userloc_given = 1;
+            args_info->userloc_arg = strdup (optarg);
+            break;
+          }
+         /* MS Time Zone  */
+          else if (strcmp (long_options[option_index].name, "mstz") == 0)
+          {
+            if (args_info->mstz_given)
+              {
+                fprintf (stderr, "%s: `--mstz' option given more than once\n", PACKAGE);
+                exit (EXIT_FAILURE);
+              }
+            args_info->mstz_given = 1;
+            args_info->mstz_arg = strdup (optarg);
+            break;
+          }
+          /* IMEI(SV)  */
+          else if (strcmp (long_options[option_index].name, "imeisv") == 0)
+          {
+            if (args_info->imeisv_given)
+              {
+                fprintf (stderr, "%s: `--imeisv' option given more than once\n", PACKAGE);
+                exit (EXIT_FAILURE);
+              }
+            args_info->imeisv_given = 1;
+            args_info->imeisv_arg = strdup (optarg);
+            break;
+          }
           /* NSAPI.  */
           else if (strcmp (long_options[option_index].name, "nsapi") == 0)
           {
diff --git a/sgsnemu/cmdline.h b/sgsnemu/cmdline.h
index a15480d..0871f3e 100644
--- a/sgsnemu/cmdline.h
+++ b/sgsnemu/cmdline.h
@@ -61,6 +61,18 @@
   int selmode_arg;	/* Selection mode (default='0x01').  */
   char * selmode_orig;	/* Selection mode original value given at command line.  */
   const char *selmode_help; /* Selection mode help description.  */
+  char *  rattype_arg; /* Radio Access Technology Type (optional).  */
+  char *  rattype_orig;
+  char *  rattype_help;
+  char *  userloc_arg; /* User Location Information (optional).  */
+  char *  userloc_orig;
+  char *  userloc_help;
+  char *  mstz_arg;    /* MS Time Zone (optional).  */
+  char *  mstz_orig;
+  char *  mstz_help;
+  char *  imeisv_arg;  /* IMEI(SV) (optional).  */
+  char *  imeisv_orig;
+  char *  imeisv_help;
   char * imsi_arg;	/* IMSI (default='240010123456789').  */
   char * imsi_orig;	/* IMSI original value given at command line.  */
   const char *imsi_help; /* IMSI help description.  */
@@ -124,6 +136,10 @@
   int gtpversion_given ;	/* Whether gtpversion was given.  */
   int apn_given ;	/* Whether apn was given.  */
   int selmode_given ;	/* Whether selmode was given.  */
+  int rattype_given ;  /* Whether rattype was given.  */
+  int userloc_given ;  /* Whether userloc was given.  */
+  int mstz_given ;     /* Whether mstz was given.  */
+  int imeisv_given ;   /* Whether imeisv was given.  */
   int imsi_given ;	/* Whether imsi was given.  */
   int nsapi_given ;	/* Whether nsapi was given.  */
   int msisdn_given ;	/* Whether msisdn was given.  */
diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c
index 2675c0f..9a15d32 100644
--- a/sgsnemu/sgsnemu.c
+++ b/sgsnemu/sgsnemu.c
@@ -104,6 +104,14 @@
   uint16_t cch;
   struct ul255_t apn;
   uint8_t selmode;
+  struct ul255_t rattype;
+  int rattype_given;
+  struct ul255_t userloc;
+  int userloc_given;
+  struct ul255_t mstz;
+  int mstz_given;
+  struct ul255_t imeisv;
+  int imeisv_given;
   struct ul16_t msisdn;
 } options;
 
@@ -211,6 +219,23 @@
 
   struct hostent *host;
   unsigned int n;
+  uint16_t i;
+  uint8_t a;
+  uint8_t b;
+  char * tmp;
+  char * pch;
+  char * type;
+  char * mcc;
+  char * mnc;
+  char * lac;
+  int lac_d;
+  char * rest;
+  char *userloc_el[] = {"TYPE","MCC","MNC","LAC","REST"};
+  char *mstz_el[] = {"SIGN","QUARTERS","DST"};
+  int sign ;
+  int nbquarters ;
+  int DST ;
+
 
   if (cmdline_parser (argc, argv, &args_info) != 0)
     return -1;
@@ -449,6 +474,174 @@
   options.selmode = args_info.selmode_arg;
   printf("Using selection mode:  %d\n", args_info.selmode_arg);
 
+  /* rattype */
+  if (args_info.rattype_given == 1 ) {
+    options.rattype_given = 1 ;
+    options.rattype.l = strlen(args_info.rattype_arg) ;
+    options.rattype.v[0] = atoi(args_info.rattype_arg) ;
+    printf("Using RAT Type:  %s\n", args_info.rattype_arg);
+  }
+
+  /* userloc */
+  if (args_info.userloc_given == 1 ) {
+    printf("Using User Location Information:  %s\n", args_info.userloc_arg);
+    tmp = args_info.userloc_arg ;
+    n=0;
+    pch = strtok (tmp,".");
+    while (pch != NULL) {
+      userloc_el[n] = pch ;
+      pch = strtok (NULL, ".");
+      n++;
+    }
+
+    options.userloc_given = 1 ;
+    options.userloc.l = 8 ;
+
+    /* 3GPP Geographic Location Type t0 / t1 / t2 */
+    type = userloc_el[0];
+    printf("->type : %c\n", type[0]);
+    if ( (strlen(type)!=1) || (!isdigit(type[0])) ) {
+       printf("Invalid type \n");
+      return -1;
+    }
+    /* options.userloc.v[0] = 0x00 */
+    options.userloc.v[0] = type[0] - 48;
+
+    /* MCC */
+    mcc = userloc_el[1] ;
+    printf("->mcc : %s\n", mcc);
+    if (strlen(mcc)!=3) {
+      printf("Invalid MCC lenght\n");
+      return -1;
+    }
+
+    /* MNC */
+    mnc = userloc_el[2] ;
+    printf("->mnc : %s\n", mnc);
+
+    /* octet 5 - MCC Digit 2 - MCC Digit 1 */
+    /* options.userloc.v[1] = 0x52 */
+    a = (uint8_t) (mcc[0] - 48);
+    b = (uint8_t) (mcc[1] - 48);
+    options.userloc.v[1] = 16*b+a ;
+
+    /* octet 6 - MNC Digit 3 - MCC Digit 3 */
+    /* options.userloc.v[2] = 0xf0 */
+    a = (uint8_t) (mcc[2] - 48);
+
+    if ( (strlen(mnc) > 3) || (strlen(mnc) < 2)) {
+      printf("Invalid MNC lenght\n");
+      return -1;
+    }
+    if (strlen(mnc)==2) {
+      b = 15 ;
+    }
+    if (strlen(mnc)==3) {
+      b = (uint8_t) (mnc[2] - 48);
+    }
+    options.userloc.v[2] = 16*b+a ;
+
+    /* octet 7 - MNC Digit 2 - MNC Digit 1 */
+    /* options.userloc.v[3] = 0x99*/
+    a = (uint8_t) (mnc[0]- 48);
+    b = (uint8_t) (mnc[1]- 48);
+    options.userloc.v[3] = 16*b+a ;
+
+    /* LAC */
+    lac = userloc_el[3] ;
+    /*options.userloc.v[4] = 0x12 ;  */
+    /*options.userloc.v[5] = 0x10 ;  */
+    printf("->LAC: %s\n", lac);
+    lac_d = atoi(lac);
+    if (lac_d>65535 || lac_d<1) {
+      printf("Invalid LAC\n");
+      return -1;
+    }
+    i = lac_d >> 8 ;
+    options.userloc.v[4] = i;          /* octet 8 - LAC */
+    options.userloc.v[5] = lac_d;      /* octet 9 - LAC */
+
+    /* CI/SAC/RAC */
+    rest = userloc_el[4] ;
+    printf("->CI/SAC/RAC : %s\n", rest);
+    lac_d = atoi(rest);
+    if (lac_d>65535 || lac_d<1) {
+      printf("Invalid CI/SAC/RAC\n");
+      return -1;
+    }
+    /*options.userloc.v[6] = 0x04 ; */
+    /*options.userloc.v[7] = 0xb7 ; */
+    i = lac_d >> 8 ;
+    options.userloc.v[6] = i;          /* octet 10 - t0,CI / t1,SAC / t2,RAC  */
+    options.userloc.v[7] = lac_d;      /* octet 11 - t0,CI / t1,SAC / t2,RAC  */
+  }
+  /* mstz */
+  if (args_info.mstz_given == 1 ) {
+    options.mstz_given = 1 ;
+    options.mstz.l = 2 ;
+
+    printf("Using MS Time Zone:  %s\n", args_info.mstz_arg);
+    tmp = args_info.mstz_arg ;
+    n=0;
+    pch = strtok (tmp,".");
+    while (pch != NULL) {
+      mstz_el[n] = pch ;
+      pch = strtok (NULL, ".");
+      n++;
+    }
+
+    /* sign */
+    sign = atoi(mstz_el[0]) ;
+    printf("->Sign (0=+ / 1=-): %d\n", sign);
+    if ( sign!=0 && sign!=1 ) {
+       printf("Invalid Sign \n");
+      return -1;
+    }
+    /* nbquarters */
+    nbquarters = atoi(mstz_el[1]) ;
+    printf("->Number of Quarters of an Hour : %d\n", nbquarters);
+    if ( nbquarters<0 || nbquarters>79 ) {
+       printf("Invalid Number of Quarters \n");
+      return -1;
+    }
+    /* DST */
+    DST = atoi(mstz_el[2]) ;
+    printf("->Daylight Saving Time Adjustment : %d\n", DST);
+    if ( DST<0 || DST>3 ) {
+       printf("Invalid DST Adjustment \n");
+      return -1;
+    }
+    /* 12345678
+    bits 123 = unit of # of quarters of an hour
+    bits 678 = # of quarters of an hour / 10
+    bit 5 = sign
+    */
+    i= nbquarters % 10 ;
+    i = i << 4 ;
+    i = i + nbquarters / 10 + 8 * sign;
+    /* options.mstz.v[0] = 0x69 ; */
+    /* options.mstz.v[1] = 0x01 ; */
+    options.mstz.v[0] = i ;
+    options.mstz.v[1] = DST ;
+    n = (i & 0x08) ? '-' : '+';
+    printf("->Human Readable MS Time Zone  : GMT %c %d hours %d minutes\n", n , nbquarters / 4, nbquarters % 4 * 15);
+  }
+
+  /* imeisv */
+  if (args_info.imeisv_given == 1 ) {
+    options.imeisv_given = 1 ;
+    if (strlen(args_info.imeisv_arg)!=16) {
+      printf("Invalid IMEI(SV)\n");
+      return -1;
+    }
+    options.imeisv.l = 8 ;
+    for(n=0; n<8; n++) {
+      a = (uint8_t) (args_info.imeisv_arg [2*n] - 48) ;
+      b = (uint8_t) (args_info.imeisv_arg [2*n + 1] - 48) ;
+      options.imeisv.v[n] = 16*b+a ;
+    }
+    printf("Using IMEI(SV):  %s\n", args_info.imeisv_arg);
+  }
   
   /* msisdn                                                          */
   if (strlen(args_info.msisdn_arg)>(sizeof(options.msisdn.v)-1)) {
@@ -1138,6 +1331,22 @@
     
     pdp->selmode = options.selmode;
     
+    pdp->rattype.l = options.rattype.l;
+    memcpy(pdp->rattype.v, options.rattype.v, options.rattype.l);
+    pdp->rattype_given = options.rattype_given;
+
+    pdp->userloc.l = options.userloc.l;
+    memcpy(pdp->userloc.v, options.userloc.v, options.userloc.l);
+    pdp->userloc_given = options.userloc_given;
+
+    pdp->mstz.l = options.mstz.l;
+    memcpy(pdp->mstz.v, options.mstz.v, options.mstz.l);
+    pdp->mstz_given = options.mstz_given;
+
+    pdp->imeisv.l = options.imeisv.l;
+    memcpy(pdp->imeisv.v, options.imeisv.v, options.imeisv.l);
+    pdp->imeisv_given = options.imeisv_given;
+
     if (options.apn.l > sizeof(pdp->apn_use.v)) {
       sys_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
       exit(1);