added ippool.h and ippool.c
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 3f9767b..322cc9d 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -1,16 +1,16 @@
 /* 
- *  OpenGGSN - Gateway GPRS Support Node
- *  Copyright (C) 2002 Mondru AB.
+ * OpenGGSN - Gateway GPRS Support Node
+ * Copyright (C) 2002, 2003 Mondru AB.
  * 
- *  The contents of this file may be used under the terms of the GNU
- *  General Public License Version 2, provided that the above copyright
- *  notice and this permission notice is included in all copies or
- *  substantial portions of the software.
+ * The contents of this file may be used under the terms of the GNU
+ * General Public License Version 2, provided that the above copyright
+ * notice and this permission notice is included in all copies or
+ * substantial portions of the software.
  * 
- *  The initial developer of the original code is
- *  Jens Jakobsen <jj@openggsn.org>
+ * The initial developer of the original code is
+ * Jens Jakobsen <jj@openggsn.org>
  * 
- *  Contributor(s):
+ * Contributor(s):
  * 
  */
 
@@ -52,17 +52,29 @@
 #include <time.h>
 
 #include "tun.h"
+#include "ippool.h"
+#include "syserr.h"
 #include "../gtp/pdp.h"
 #include "../gtp/gtp.h"
 #include "cmdline.h"
 
 
-int maxfd = 0;	                /* For select() */
-int tun_fd = -1;		/* Network file descriptor */
+int maxfd = 0;	                /* For select()            */
 struct tun_t *tun;              /* TUN instance            */
+
+struct in_addr listen_;
 struct in_addr net, mask;       /* Network interface       */
-char *ipup, *ipdown;            /* Filename of scripts */
-int debug;                      /* Print debug output */
+struct in_addr dns1, dns2;      /* PCO DNS address         */
+char *ipup, *ipdown;            /* Filename of scripts     */
+int debug;                      /* Print debug output      */
+struct ul255_t pco;
+struct ul255_t qos;
+struct ul255_t apn;
+
+struct tun_t *tun;              /* TUN instance            */
+struct ippool_t *ippool;        /* Pool of IP addresses    */
+struct gsn_t *gsn;              /* GSN instance            */
+
 
 
 /* Used to write process ID to file. Assume someone else will delete */
@@ -94,60 +106,16 @@
   return 0;
 }
 
-int getip(struct pdp_t *pdp, void* ipif, struct ul66_t *eua,
-	  struct in_addr *net, struct in_addr *mask) {
-  struct in_addr addr;
-  uint32_t ip_start, ip_end, ip_cur;
-  struct pdp_t *pdp_;
-  struct ul66_t eua_;
-
-  if (debug) {
-  printf("Begin getip %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l, 
-	 eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
-  }
-
-  ip_start = ntoh32(net->s_addr & mask->s_addr);
-  ip_end   = ntoh32(hton32(ip_start) | ~mask->s_addr);
-
-  /* By convention the first address is the network address, and the last */
-  /* address is the broadcast address. This way two IP addresses are "lost" */
-  ip_start++; 
-  
-  if (eua->l == 0) { /* No address supplied. Find one that is available! */
-    /* This routine does linear search. In order to support millions of 
-     * addresses we should instead keep a linked list of available adresses */
-    for (ip_cur = ip_start; ip_cur < ip_end; ip_cur++) {
-      addr.s_addr = hton32(ip_cur);
-      pdp_ntoeua(&addr, &eua_);
-      if (pdp_ipget(&pdp_, ipif, &eua_) == -1) {
-	pdp_ntoeua(&addr, &pdp->eua);
-	pdp->ipif = ipif;
-	return 0;
-      };
-    }
-    return EOF; /* No addresses available */
-  }
-  else { /* Address supplied */
-    if (pdp_ipget(&pdp_, ipif, eua) == -1) {
-      pdp->ipif = ipif;
-      pdp->eua.l = eua->l;
-      memcpy(pdp->eua.v, eua->v, eua->l);
-      return 0;
-    }
-    else return EOF; /* Specified address not available */
-  }
-}
-
-
 int delete_context(struct pdp_t *pdp) {
   if (debug) printf("Deleting PDP context\n");
-  pdp_ipdel(pdp);
+  ippool_freeip((struct ippoolm_t *) pdp->peer);
   return 0;
 }
 
 
-
 int create_context(struct pdp_t *pdp) {
+  struct in_addr addr;
+  struct ippoolm_t *member;
 
   if (debug) printf("Received create PDP context request\n");
 
@@ -155,69 +123,43 @@
 
   /* ulcpy(&pdp->qos_neg, &pdp->qos_req, sizeof(pdp->qos_req.v)); */
   memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_neg));
+  memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg));
 
-  getip(pdp, tun, &pdp->eua, &net, &mask);
-  pdp_ipset(pdp, pdp->ipif, &pdp->eua);
+  if (pdp_euaton(&pdp->eua, &addr)) {
+    addr.s_addr = 0; /* Request dynamic */
+  }
+
+  if (ippool_newip(ippool, &member, &addr)) {
+    return EOF; /* Allready in use, or no more available */
+  }
+
+  pdp_ntoeua(&member->addr, &pdp->eua);
+  pdp->peer = &member;
+  pdp->ipif = tun; /* TODO */
+  member->peer = pdp;
 
   return 0; /* Success */
 }
 
 
-
-int create_tun() {
-  char buf[1024];
-  char snet[100], smask[100];
-
-  if ((tun_fd = tun_newtun((struct tun_t**) &tun)) > maxfd)
-    maxfd = tun_fd;
-
-  if (tun_fd == -1) {
-    printf("Failed to open tun\n");
-    exit(1);
-  }
-
-  strncpy(snet, inet_ntoa(net), sizeof(snet)); 
-  snet[sizeof(snet)-1] = 0;
-  strncpy(smask, inet_ntoa(mask), sizeof(smask));
-  smask[sizeof(smask)-1] = 0;
-
-  snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s mtu 1450 netmask %s",
-	  tun->devname, snet, smask);
-  buf[sizeof(buf)-1] = 0;
-  if (debug) printf("%s\n", buf);
-  system(buf);
-
-  if (ipup) {
-    /* system("ipup /dev/tun0 192.168.0.10"); */
-    snprintf(buf, sizeof(buf), "%s %s %s %s",
-	     ipup, tun->devname, snet, smask);
-    buf[sizeof(buf)-1] = 0;
-    if (debug) printf("%s\n", buf);
-    system(buf);
-  }
-
-  return 0;
-}
-
-
-int encaps_gtp(void *gsn, struct tun_t *tun, void *pack, unsigned len) {
-  struct pdp_t *pdp;
-  struct in_addr addr;
-  struct ul66_t eua;
-  /*printf("encaps_gtp. Packet received: forwarding to gtp.\n");*/
-  /* First we need to extract the IP destination address */
-  memcpy(&addr.s_addr, pack+16, 4); /* This ought to be dest addr */
-  pdp_ntoeua(&addr, &eua);
-  if (pdp_ipget(&pdp, tun, &eua) == 0) {
-    return gtp_gpdu((struct gsn_t*) gsn, pdp, pack, len);
-  }
-  else {
+/* Callback for receiving messages from tun */
+int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) {
+  struct ippoolm_t *ipm;
+  struct in_addr dst;
+  struct tun_packet_t *iph = (struct tun_packet_t*) pack;
+  
+  dst.s_addr = iph->dst;
+  
+  if (ippool_getip(ippool, &ipm, &dst)) {
     if (debug) printf("Received packet with no destination!!!\n");
     return 0;
   }
+  
+  if (ipm->peer) /* Check if a peer protocol is defined */
+    gtp_gpdu(gsn, (struct pdp_t*) ipm->peer, pack, len);
+  return 0;
 }
 
-
 int encaps_tun(struct pdp_t *pdp, void *pack, unsigned len) {
   /*  printf("encaps_tun. Packet received: forwarding to tun\n");*/
   return tun_encaps((struct tun_t*) pdp->ipif, pack, len);
@@ -231,16 +173,10 @@
 
   struct hostent *host;
 
-  struct in_addr listen;
 	
-  int gtpfd = -1;		/* Network file descriptor */
-  struct gsn_t *gsn;            /* GSN instance            */
-
   fd_set fds;			/* For select() */
   struct timeval idleTime;	/* How long to select() */
 
-  struct ul_t qos, apn;
-  unsigned char qosh[3], apnh[256];
 
   int timelimit; /* Number of seconds to be connected */
   int starttime; /* Time program was started */
@@ -259,7 +195,8 @@
     printf("qos: %#08x\n", args_info.qos_arg);
     printf("apn: %s\n", args_info.apn_arg);
     printf("net: %s\n", args_info.net_arg);
-    printf("mask: %s\n", args_info.mask_arg);
+    printf("dynip: %s\n", args_info.dynip_arg);
+    printf("statip: %s\n", args_info.statip_arg);
     printf("ipup: %s\n", args_info.ipup_arg);
     printf("ipdown: %s\n", args_info.ipdown_arg);
     printf("pidfile: %s\n", args_info.pidfile_arg);
@@ -280,7 +217,8 @@
     printf("qos: %#08x\n", args_info.qos_arg);
     printf("apn: %s\n", args_info.apn_arg);
     printf("net: %s\n", args_info.net_arg);
-    printf("mask: %s\n", args_info.mask_arg);
+    printf("dynip: %s\n", args_info.dynip_arg);
+    printf("statip: %s\n", args_info.statip_arg);
     printf("ipup: %s\n", args_info.ipup_arg);
     printf("ipdown: %s\n", args_info.ipdown_arg);
     printf("pidfile: %s\n", args_info.pidfile_arg);
@@ -326,37 +264,62 @@
       return 1;
     }
     else {
-      memcpy(&listen.s_addr, host->h_addr, host->h_length);
+      memcpy(&listen_.s_addr, host->h_addr, host->h_length);
     }
   }
   else {
-    listen.s_addr = htonl(INADDR_ANY);
+    listen_.s_addr = htonl(INADDR_ANY);
   }
   
   /* net                                                          */
-  /* Store net as in_addr                                         */
+  /* Store net as in_addr net and mask                            */
   if (args_info.net_arg) {
-    if (!inet_aton(args_info.net_arg, &net)) {
-      fprintf(stderr, "%s: Invalid network address: %s!\n", 
-	      PACKAGE, args_info.net_arg);
-      syslog(LOG_ERR, "Invalid network address: %s!", 
-	     args_info.net_arg);
-      return 1;
+    if(ippool_aton(&net, &mask, args_info.net_arg, 0)) {
+      sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+	      "Invalid network address: %s!", args_info.net_arg);
+      return -1;
     }
   }
 
-  /* mask                                                         */
-  /* Store mask as in_addr                                        */
-  if (args_info.mask_arg) {
-    if (!inet_aton(args_info.mask_arg, &mask)) {
-      fprintf(stderr, "%s: Invalid network mask: %s!\n", 
-	      PACKAGE, args_info.mask_arg);
-      syslog(LOG_ERR, "Invalid network mask: %s!", 
-	     args_info.mask_arg);
-      return 1;
+  /* dynip                                                        */
+  if (!args_info.dynip_arg) {
+    sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+	    "No dynamic address pool given!");
+    return -1;
+  }
+  else {
+    if (ippool_new(&ippool, args_info.dynip_arg, 
+		   IPPOOL_NONETWORK | IPPOOL_NOBROADCAST)) {
+      sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+	      "Failed to allocate IP pool!");
     }
   }
 
+  /* DNS1 and DNS2 */
+  dns1.s_addr = 0;
+  if (args_info.pcodns1_arg)
+    inet_aton(args_info.pcodns1_arg, &dns1);
+
+  dns2.s_addr = 0;
+  if (args_info.pcodns2_arg)
+    inet_aton(args_info.pcodns2_arg, &dns2);
+
+  pco.l = 20;
+  pco.v[0] = 0x80; /* x0000yyy x=1, yyy=000: PPP */
+  pco.v[1] = 0x80; /* IPCP */
+  pco.v[2] = 0x21; 
+  pco.v[3] = 0x10; /* Length of contents */
+  pco.v[4] = 0x02; /* ACK */
+  pco.v[5] = 0x00; /* ID: Need to match request */
+  pco.v[6] = 0x00; /* Length */
+  pco.v[7] = 0x10;
+  pco.v[8] = 0x81; /* DNS 1 */
+  pco.v[9] = 0x06;
+  memcpy(&pco.v[10], &dns1, sizeof(dns1));
+  pco.v[14] = 0x83;
+  pco.v[15] = 0x06; /* DNS 2 */
+  memcpy(&pco.v[16], &dns2, sizeof(dns2));
+
   /* ipup */
   ipup = args_info.ipup_arg;
 
@@ -369,35 +332,64 @@
   
   /* qos                                                             */
   qos.l = 3;
-  qos.v = qosh;
   qos.v[2] = (args_info.qos_arg) & 0xff;
   qos.v[1] = ((args_info.qos_arg) >> 8) & 0xff;
   qos.v[0] = ((args_info.qos_arg) >> 16) & 0xff;
-  
+
   /* apn                                                             */
-  if (strlen(args_info.apn_arg)>(sizeof(apnh)-1)) {
-    printf("invalid APN\n");
-    exit(1);
+  if (strlen(args_info.apn_arg) > (sizeof(apn.v)-1)) {
+    printf("Invalid APN\n");
+    return -1;
   }
   apn.l = strlen(args_info.apn_arg) + 1;
-  apn.v = apnh;
   apn.v[0] = (char) strlen(args_info.apn_arg);
-  strncpy(&apn.v[1], args_info.apn_arg, (sizeof(apnh)-1));
+  strncpy(&apn.v[1], args_info.apn_arg, sizeof(apn.v)-1);
+  
+  
 
   if (debug) printf("gtpclient: Initialising GTP tunnel\n");
   
-  if ((gtpfd = gtp_new(&gsn, args_info.statedir_arg, &listen)) > maxfd)
-    maxfd = gtpfd;
-
-  if ((gtpfd = gtp_fd(gsn)) > maxfd)
-    maxfd = gtpfd;
+  if (gtp_new(&gsn, args_info.statedir_arg,  &listen_)) {
+    sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+	    "Failed to create gtp");
+    exit(1);
+  }
+  if (gsn->fd > maxfd) maxfd = gsn->fd;
     
 
   gtp_set_cb_gpdu(gsn, encaps_tun);
   gtp_set_cb_delete_context(gsn, delete_context);
-  
   gtp_set_cb_create_context(gsn, create_context);
-  create_tun();
+
+
+  /* Create a tunnel interface */
+  if (tun_new((struct tun_t**) &tun)) {
+    sys_err(LOG_ERR, __FILE__, __LINE__, 0,
+	    "Failed to create tun");
+    exit(1);
+  }
+
+  tun_setaddr(tun, &net,  &net, &mask);
+  tun_set_cb_ind(tun, cb_tun_ind);
+  if (tun->fd > maxfd) maxfd = tun->fd;
+
+  if (ipup) {
+    char buf[1024];
+    char snet[100];
+    char smask[100];
+
+    strncpy(snet, inet_ntoa(net), sizeof(snet));
+    snet[sizeof(snet)-1] = 0;
+    strncpy(smask, inet_ntoa(mask), sizeof(smask));
+    smask[sizeof(smask)-1] = 0;
+    
+    /* system("ipup /dev/tun0 192.168.0.10"); */
+    snprintf(buf, sizeof(buf), "%s %s %s %s",
+	     ipup, tun->devname, snet, smask);
+    buf[sizeof(buf)-1] = 0;
+    if (debug) printf("%s\n", buf);
+    system(buf);
+  }
 
   /******************************************************************/
   /* Main select loop                                               */
@@ -406,8 +398,8 @@
   while (((starttime + timelimit) > time(NULL)) || (0 == timelimit)) {
 	
     FD_ZERO(&fds);
-    if (tun_fd != -1) FD_SET(tun_fd, &fds);
-    if (gtpfd != -1) FD_SET(gtpfd, &fds);
+    if (tun) FD_SET(tun->fd, &fds);
+    FD_SET(gsn->fd, &fds);
     
     gtp_retranstimeout(gsn, &idleTime);
     switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) {
@@ -418,26 +410,25 @@
       syslog(LOG_ERR, "GGSN: select = -1");
       break;  
     case 0:
+      /* printf("Select returned 0\n"); */
       gtp_retrans(gsn); /* Only retransmit if nothing else */
       break; 
     default:
       break;
     }
 
-    if (tun_fd != -1 && FD_ISSET(tun_fd, &fds) && 
-	tun_decaps(tun, encaps_gtp, gsn) < 0) {
-      syslog(LOG_ERR, "TUN read failed (fd)=(%d)", tun_fd);
+    if (tun->fd != -1 && FD_ISSET(tun->fd, &fds) && 
+	tun_decaps(tun) < 0) {
+      syslog(LOG_ERR, "TUN read failed (fd)=(%d)", tun->fd);
     }
 
-    if (gtpfd != -1 && FD_ISSET(gtpfd, &fds) && 
-	gtp_decaps(gsn) < 0) {
-      syslog(LOG_ERR, "GTP read failed (gtpfd)=(%d)", gtpfd);
-    }
-    
+    if (FD_ISSET(gsn->fd, &fds))
+      gtp_decaps(gsn);
     
   }
 
   gtp_free(gsn);
+  tun_free(tun);
   
   return 1;