ippool: Add IPv6 support to IP pool implementation

Extend the IP pool implementation to be able to manage both pools
of 32bit addresses (IPv4) as well as pools of 128bit addresses (IPv6)

Change-Id: Ib98cc4bf634d6be9a7bf8c03a24e629455fcafc8
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c
index 168e907..0d0e569 100644
--- a/ggsn/ggsn.c
+++ b/ggsn/ggsn.c
@@ -56,6 +56,7 @@
 #include "../lib/tun.h"
 #include "../lib/ippool.h"
 #include "../lib/syserr.h"
+#include "../lib/in46_addr.h"
 #include "../gtp/pdp.h"
 #include "../gtp/gtp.h"
 #include "cmdline.h"
@@ -65,7 +66,8 @@
 int maxfd = 0;			/* For select()            */
 
 struct in_addr listen_;
-struct in_addr netaddr, destaddr, net, mask;	/* Network interface       */
+struct in_addr netaddr, destaddr, net;	/* Network interface       */
+size_t prefixlen;
 struct in_addr dns1, dns2;	/* PCO DNS address         */
 char *ipup, *ipdown;		/* Filename of scripts     */
 int debug;			/* Print debug output      */
@@ -135,9 +137,12 @@
 
 static bool send_trap(const struct gsn_t *gsn, const struct pdp_t *pdp, const struct ippoolm_t *member, const char *var)
 {
+	char addrbuf[256];
 	char val[NAMESIZE];
 
-	snprintf(val, sizeof(val), "%" PRIu64 ",%s", pdp->imsi, inet_ntoa(member->addr));
+	const char *addrstr = in46a_ntop(&member->addr, addrbuf, sizeof(addrbuf));
+
+	snprintf(val, sizeof(val), "%" PRIu64 ",%s", pdp->imsi, addrstr);
 
 	if (ctrl_cmd_send_trap(gsn->ctrl, var, val) < 0) {
 		LOGP(DGGSN, LOGL_ERROR, "Failed to create and send TRAP for IMSI %" PRIu64 " [%s].\n", pdp->imsi, var);
@@ -168,7 +173,7 @@
 
 int create_context_ind(struct pdp_t *pdp)
 {
-	struct in_addr addr;
+	struct in46_addr addr;
 	struct ippoolm_t *member;
 
 	DEBUGP(DGGSN, "Received create PDP context request\n");
@@ -183,8 +188,8 @@
 	memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l);	/* TODO */
 	pdp->qos_neg.l = pdp->qos_req.l;
 
-	if (pdp_euaton(&pdp->eua, &addr)) {
-		addr.s_addr = 0;	/* Request dynamic */
+	if (pdp_euaton(&pdp->eua, &addr.v4)) {
+		addr.v4.s_addr = 0;	/* Request dynamic */
 	}
 
 	if (ippool_newip(ippool, &member, &addr, 0)) {
@@ -192,7 +197,7 @@
 		return 0;	/* Allready in use, or no more available */
 	}
 
-	pdp_ntoeua(&member->addr, &pdp->eua);
+	pdp_ntoeua(&member->addr.v4, &pdp->eua);
 	pdp->peer = member;
 	pdp->ipif = tun;	/* TODO */
 	member->peer = pdp;
@@ -215,10 +220,18 @@
 int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
 {
 	struct ippoolm_t *ipm;
-	struct in_addr dst;
+	struct in46_addr dst;
 	struct tun_packet_t *iph = (struct tun_packet_t *)pack;
 
-	dst.s_addr = iph->dst;
+	if (iph->ver == 4) {
+		if (len < sizeof(*iph) || len < 4*iph->ihl)
+			return -1;
+		dst.len = 4;
+		dst.v4.s_addr = iph->dst;
+	} else {
+		LOGP(DGGSN, LOGL_NOTICE, "non-IPv4 packet received from tun\n");
+		return -1;
+	}
 
 	DEBUGP(DGGSN, "Received packet from tun!\n");
 
@@ -383,12 +396,14 @@
 	/* net                                                          */
 	/* Store net as in_addr net and mask                            */
 	if (args_info.net_arg) {
-		if (ippool_aton(&net, &mask, args_info.net_arg, 0)) {
+		struct in46_addr in46;
+		if (ippool_aton(&in46, &prefixlen, args_info.net_arg, 0)) {
 			SYS_ERR(DGGSN, LOGL_ERROR, 0,
 				"Invalid network address: %s!",
 				args_info.net_arg);
 			exit(1);
 		}
+		net.s_addr = in46.v4.s_addr;
 		netaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
 		destaddr.s_addr = htonl(ntohl(net.s_addr) + 1);
 	} else {
@@ -547,7 +562,7 @@
 		maxfd = gsn->fd1u;
 
 	/* use GTP kernel module for data packet encapsulation */
-	if (gtp_kernel_init(gsn, &net, &mask, &args_info) < 0)
+	if (gtp_kernel_init(gsn, &net, prefixlen, &args_info) < 0)
 		goto err;
 
 	gtp_set_cb_data_ind(gsn, encaps_tun);
@@ -572,7 +587,7 @@
 	}
 
 	DEBUGP(DGGSN, "Setting tun IP address\n");
-	if (tun_setaddr(tun, &netaddr, &destaddr, &mask)) {
+	if (tun_setaddr(tun, &netaddr, &destaddr, &prefixlen)) {
 		SYS_ERR(DGGSN, LOGL_ERROR, 0, "Failed to set tun IP address");
 		exit(1);
 	}