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);
 	}
diff --git a/ggsn/gtp-kernel.c b/ggsn/gtp-kernel.c
index dbe5a9f..458ac27 100644
--- a/ggsn/gtp-kernel.c
+++ b/ggsn/gtp-kernel.c
@@ -70,17 +70,6 @@
 	printf("\n");
 }
 
-static int mask2prefix(struct in_addr *mask)
-{
-	uint32_t tmp = ntohl(mask->s_addr);
-	int k;
-
-	for (k=0; tmp > 0; k++)
-		tmp = (tmp << 1);
-
-	return k;
-}
-
 static struct {
 	int			genl_id;
 	struct mnl_socket	*nl;
@@ -91,7 +80,7 @@
 #define GTP_DEVNAME	"gtp0"
 
 int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
-		    struct in_addr *mask,
+		    size_t prefixlen,
 		    struct gengetopt_args_info *args_info)
 {
 	if (!args_info->gtp_linux_given)
@@ -126,7 +115,7 @@
 	DEBUGP(DGGSN, "Setting route to reach %s via %s\n",
 	       args_info->net_arg, GTP_DEVNAME);
 
-	if (gtp_dev_config(GTP_DEVNAME, net, mask2prefix(mask)) < 0) {
+	if (gtp_dev_config(GTP_DEVNAME, net, prefixlen) < 0) {
 		SYS_ERR(DGGSN, LOGL_ERROR, 0,
 			"Cannot add route to reach network %s\n",
 			args_info->net_arg);
diff --git a/ggsn/gtp-kernel.h b/ggsn/gtp-kernel.h
index 83280a0..b3b29e3 100644
--- a/ggsn/gtp-kernel.h
+++ b/ggsn/gtp-kernel.h
@@ -8,7 +8,7 @@
 
 #ifdef GTP_KERNEL
 int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
-		    struct in_addr *mask,
+		    size_t prefixlen,
 		    struct gengetopt_args_info *args_info);
 void gtp_kernel_stop(void);
 
@@ -19,7 +19,7 @@
 
 #else
 static inline int gtp_kernel_init(struct gsn_t *gsn, struct in_addr *net,
-				  struct in_addr *mask,
+				  size_t prefixlen,
 				  struct gengetopt_args_info *args_info)
 {
 	if (args_info->gtp_linux_given) {