Improved GTP error handling
diff --git a/gtp/gtp.c b/gtp/gtp.c
index fb98be1..fa87364 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -54,6 +54,55 @@
 #include "gtpie.h"
 #include "queue.h"
 
+
+/* Error reporting functions */
+
+void gtp_err(int priority, char *filename, int linenum, char *fmt, ...) {
+  va_list args;
+  char buf[ERRMSG_SIZE];
+
+  va_start(args, fmt);
+  vsnprintf(buf, ERRMSG_SIZE, fmt, args);
+  va_end(args);
+  buf[ERRMSG_SIZE-1] = 0;
+  syslog(priority, "%s: %d: %s", filename, linenum, buf); 
+}
+
+void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer,
+		 void *pack, unsigned len, char *fmt, ...) {
+  
+  va_list args;
+  char buf[ERRMSG_SIZE];
+  char buf2[ERRMSG_SIZE];
+  int n;
+  int pos;
+  
+  va_start(args, fmt);
+  vsnprintf(buf, ERRMSG_SIZE, fmt, args);
+  va_end(args);
+  buf[ERRMSG_SIZE-1] = 0;
+
+  snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:",
+	   inet_ntoa(peer->sin_addr),
+	   ntohs(peer->sin_port),
+	   len);
+  buf2[ERRMSG_SIZE-1] = 0;
+  pos = strlen(buf2);
+  for(n=0; n<len; n++) {
+    if ((pos+4)<ERRMSG_SIZE) {
+      sprintf((buf2+pos), " %02hhx", ((unsigned char*)pack)[n]);
+      pos += 3;
+    }
+  }
+  buf2[pos] = 0;
+  
+  syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
+
+}
+
+
+
+
 /* API Functions */
 
 const char* gtp_version()
@@ -80,6 +129,65 @@
   return gtp_create_pdp_req(gsn, version, aid, inetaddr, pdp);
 }
 
+int gtp_create_context2(struct gsn_t *gsn, void *aid, 
+			struct in_addr* inetaddr,
+			int selmode, uint64_t imsi, int nsapi,
+			uint8_t *qos, int qoslen,
+			char *apn, int apnlen,
+			char *msisdn, int msisdnlen,
+			uint8_t *pco, int pcolen) {
+  int version = 0;
+
+  struct pdp_t *pdp;
+
+  if (qoslen > sizeof(pdp->qos_req0)) {
+    gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big");
+    return -1;
+  }
+
+  if (apnlen > sizeof(pdp->apn_use.v)) {
+    gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big");
+    return -1;
+  }
+
+  if (msisdnlen > sizeof(pdp->msisdn.v)) {
+    gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big");
+    return -1;
+  }
+
+  if (pcolen > sizeof(pdp->pco_req.v)) {
+    gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big");
+    return -1;
+  }
+
+  /* New pdp allocated here:*/
+  pdp_newpdp(&pdp, imsi, nsapi, NULL); 
+
+  pdp->peer = aid;
+  pdp->ipif = NULL;
+
+  pdp->selmode = selmode; 
+
+  memcpy(pdp->qos_req0, qos, qoslen);  /* Length checked above */
+  pdp->apn_use.l = apnlen;
+  memcpy(pdp->apn_use.v, apn, apnlen); /* Length checked above */
+
+  pdp->gsnlc.l = sizeof(gsn->gsnc);
+  memcpy(pdp->gsnlc.v, &gsn->gsnc, sizeof(gsn->gsnc));
+  pdp->gsnlu.l = sizeof(gsn->gsnc);
+  memcpy(pdp->gsnlu.v, &gsn->gsnc, sizeof(gsn->gsnc));
+
+  pdp->msisdn.l = msisdnlen;
+  memcpy(pdp->msisdn.v, msisdn, msisdnlen);
+
+  ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */
+
+  pdp->pco_req.l = pcolen;
+  memcpy(pdp->pco_req.v, pco, pcolen);
+
+  return gtp_create_pdp_req(gsn, version, aid, inetaddr, pdp);
+}
+
 int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid,
 		       struct in_addr* inetaddr) {
   int version = 0;
@@ -213,49 +321,6 @@
   return buf;
 }
 
-void gtp_err(int priority, char *filename, int linenum, char *fmt, ...) {
-  va_list args;
-  char buf[ERRMSG_SIZE];
-
-  va_start(args, fmt);
-  vsnprintf(buf, ERRMSG_SIZE, fmt, args);
-  va_end(args);
-  buf[ERRMSG_SIZE-1] = 0;
-  syslog(priority, "%s: %d: %s", filename, linenum, buf); 
-}
-
-void gtp_errpack(int pri, char *fn, int ln, struct sockaddr_in *peer,
-		 void *pack, unsigned len, char *fmt, ...) {
-  
-  va_list args;
-  char buf[ERRMSG_SIZE];
-  char buf2[ERRMSG_SIZE];
-  int n;
-  int pos;
-  
-  va_start(args, fmt);
-  vsnprintf(buf, ERRMSG_SIZE, fmt, args);
-  va_end(args);
-  buf[ERRMSG_SIZE-1] = 0;
-
-  snprintf(buf2, ERRMSG_SIZE, "Packet from %s:%u, length: %d, content:",
-	   inet_ntoa(peer->sin_addr),
-	   ntohs(peer->sin_port),
-	   len);
-  buf2[ERRMSG_SIZE-1] = 0;
-  pos = strlen(buf2);
-  for(n=0; n<len; n++) {
-    if ((pos+4)<ERRMSG_SIZE) {
-      sprintf((buf2+pos), " %02hhx", ((unsigned char*)pack)[n]);
-      pos += 3;
-    }
-  }
-  buf2[pos] = 0;
-  
-  syslog(pri, "%s: %d: %s. %s", fn, ln, buf, buf2);
-
-}
-
 
 /* ***********************************************************
  * Reliable delivery of signalling messages
@@ -560,7 +625,8 @@
 
 
 
-int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen) 
+int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
+	    int mode) 
 {
   struct sockaddr_in addr;
   int gtp_fd;
@@ -1720,6 +1786,14 @@
     return gtp_error_ind_resp(gsn, version, peer, pack, len);
  
   }
+
+  /* If the GPDU was not from the peer GSN tell him to delete context */
+  if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */
+    gsn->err_unknownpdp++;
+    gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len,
+		"Unknown PDP context");
+    return gtp_error_ind_resp(gsn, version, peer, pack, len);
+  }
   
   /* Callback function */
   if (gsn->cb_gpdu !=0)
@@ -1801,6 +1875,28 @@
 		  "GTP0 packet too short");
       continue;  /* Silently discard 29.60: 11.1.2 */
     }
+
+    if ((gsn->mode == GTP_MODE_GGSN) && 
+	((pheader->type == GTP_CREATE_PDP_RSP) ||
+	 (pheader->type == GTP_UPDATE_PDP_RSP) ||
+	 (pheader->type == GTP_DELETE_PDP_RSP))) {
+      gsn->unexpect++;
+      gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
+		  "Unexpected GTP Signalling Message");
+      continue;  /* Silently discard 29.60: 11.1.4 */
+    }
+
+    if ((gsn->mode == GTP_MODE_SGSN) && 
+	((pheader->type == GTP_CREATE_PDP_REQ) ||
+	 (pheader->type == GTP_UPDATE_PDP_REQ) ||
+	 (pheader->type == GTP_DELETE_PDP_REQ))) {
+      gsn->unexpect++;
+      gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status,
+		  "Unexpected GTP Signalling Message");
+      continue;  /* Silently discard 29.60: 11.1.4 */
+    }
+
+
     
     switch (pheader->type) {
     case GTP_ECHO_REQ:
diff --git a/gtp/gtp.h b/gtp/gtp.h
index 5c6706d..d21cbb4 100644
--- a/gtp/gtp.h
+++ b/gtp/gtp.h
@@ -19,6 +19,9 @@
 
 #define GTP_DEBUG 0              /* Print debug information */
 
+#define GTP_MODE_GGSN 1
+#define GTP_MODE_SGSN 2
+
 #define GTP0_PORT	3386
 #define GTP1C_PORT	2123
 #define GTP1U_PORT	2152
@@ -186,6 +189,7 @@
   /* Parameters related to the network interface */
 
   int         fd;       /* File descriptor to network interface */
+  int       mode;       /* Mode of operation: GGSN or SGSN */
   struct in_addr gsnc;  /* IP address of this gsn for signalling */
   struct in_addr gsnu;  /* IP address of this gsn for user traffic */
 
@@ -234,7 +238,9 @@
 /* External API functions */
 
 extern const char* gtp_version();
-extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen);
+extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen,
+		   int mode);
+
 extern int gtp_free(struct gsn_t *gsn);
 
 extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp,
@@ -247,6 +253,15 @@
 			      struct in_addr* inetaddr);
 extern int gtp_delete_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid);
 
+extern int 
+gtp_create_context2(struct gsn_t *gsn, void *aid, 
+		    struct in_addr* inetaddr,
+		    int selmode, uint64_t imsi, int nsapi,
+		    uint8_t *qos, int qoslen,
+		    char *apn, int apnlen,
+		    char *msisdn, int msisdnlen,
+		    uint8_t *pco, int pcolen);
+
 extern int gtp_gpdu(struct gsn_t *gsn, struct pdp_t *pdp,
 		    void *pack, unsigned len);