ippool: Add IP pool layer
authorDaniel Wagner <daniel.wagner@bmw-carit.de>
Thu, 26 Jan 2012 15:46:37 +0000 (16:46 +0100)
committerDaniel Wagner <daniel.wagner@bmw-carit.de>
Wed, 1 Feb 2012 09:13:19 +0000 (10:13 +0100)
This is based on Guillaume Zajac intial IP pool patches.

Makefile.am
src/connman.h
src/ippool.c [new file with mode: 0644]
src/main.c

index a046902..4bb85cf 100644 (file)
@@ -79,7 +79,8 @@ src_connmand_SOURCES = $(gdbus_sources) $(gdhcp_sources) \
                        src/storage.c src/dbus.c src/config.c \
                        src/technology.c src/counter.c src/ntp.c \
                        src/session.c src/tethering.c src/wpad.c src/wispr.c \
-                       src/stats.c src/iptables.c src/dnsproxy.c src/6to4.c
+                       src/stats.c src/iptables.c src/dnsproxy.c src/6to4.c \
+                       src/ippool.c
 
 src_connmand_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ \
                                @CAPNG_LIBS@ @XTABLES_LIBS@ -lresolv -ldl
index d60e601..557b1eb 100644 (file)
@@ -704,3 +704,27 @@ void __connman_dnsproxy_flush(void);
 int __connman_6to4_probe(struct connman_service *service);
 void __connman_6to4_remove(struct connman_ipconfig *ipconfig);
 int __connman_6to4_check(struct connman_ipconfig *ipconfig);
+
+struct connman_ippool;
+
+int __connman_ippool_init(void);
+void __connman_ippool_cleanup(void);
+
+#define __connman_ippool_ref(ipconfig) \
+       __connman_ippool_ref_debug(ipconfig, __FILE__, __LINE__, __func__)
+#define __connman_ippool_unref(ipconfig) \
+       __connman_ippool_unref_debug(ipconfig, __FILE__, __LINE__, __func__)
+
+struct connman_ippool *__connman_ippool_ref_debug(struct connman_ippool *pool,
+                       const char *file, int line, const char *caller);
+void __connman_ippool_unref_debug(struct connman_ippool *pool,
+                       const char *file, int line, const char *caller);
+
+struct connman_ippool *__connman_ippool_create(unsigned int start,
+                                       unsigned int range);
+
+const char *__connman_ippool_get_gateway(struct connman_ippool *pool);
+const char *__connman_ippool_get_broadcast(struct connman_ippool *pool);
+const char *__connman_ippool_get_subnet_mask(struct connman_ippool *pool);
+const char *__connman_ippool_get_start_ip(struct connman_ippool *pool);
+const char *__connman_ippool_get_end_ip(struct connman_ippool *pool);
diff --git a/src/ippool.c b/src/ippool.c
new file mode 100644 (file)
index 0000000..085d06c
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  BMW Car IT GmbH. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+
+#include "connman.h"
+
+struct connman_ippool {
+       unsigned int refcount;
+
+       uint32_t block;
+
+       char *gateway;
+       char *broadcast;
+       char *start_ip;
+       char *end_ip;
+       char *subnet_mask;
+};
+
+static GHashTable *hash_pool;
+static uint32_t last_block;
+static uint32_t block_16_bits;
+static uint32_t block_20_bits;
+static uint32_t block_24_bits;
+static uint32_t subnet_mask_24;
+
+struct connman_ippool *
+__connman_ippool_ref_debug(struct connman_ippool *pool,
+                               const char *file, int line, const char *caller)
+{
+       DBG("%p ref %d by %s:%d:%s()", pool, pool->refcount + 1,
+               file, line, caller);
+
+       __sync_fetch_and_add(&pool->refcount, 1);
+
+       return pool;
+}
+
+void __connman_ippool_unref_debug(struct connman_ippool *pool,
+                               const char *file, int line, const char *caller)
+{
+       if (pool == NULL)
+               return;
+
+       DBG("%p ref %d by %s:%d:%s()", pool, pool->refcount - 1,
+               file, line, caller);
+
+       if (__sync_fetch_and_sub(&pool->refcount, 1) != 1)
+               return;
+
+       g_hash_table_remove(hash_pool, GUINT_TO_POINTER(pool->block));
+}
+
+static char *get_ip(uint32_t ip)
+{
+       struct in_addr addr;
+
+       addr.s_addr = htonl(ip);
+
+       return g_strdup(inet_ntoa(addr));
+}
+
+static uint32_t next_block(uint32_t block)
+{
+       uint32_t next;
+
+       /*
+        * Return the next IP block within the private IP range
+        *
+        * 16-bit block 192.168.0.0 – 192.168.255.255
+        * 20-bit block  172.16.0.0 –  172.31.255.255
+        * 24-bit block    10.0.0.0 –  10.255.255.255
+        */
+
+       next = (block & 0x0000ff00) >> 8;
+       next += 1;
+
+       if (next == 255) {
+               if ((block & 0xffffff00) == block_16_bits) {
+                       /*
+                        * Reached the end of the 16 bit block, switch
+                        * to the 20-bit block.
+                        */
+                       return block_20_bits;
+               }
+
+               if ((block & 0xffff0000) >= block_20_bits) {
+                       next = (block & 0x00ff0000) >> 16;
+                       if (next >= 16 && next < 32)
+                               next += 1;
+
+                       if (next == 32) {
+                               /*
+                                * Reached the end of the 20 bit
+                                * block, switch to the 24-bit block.
+                                */
+                               return block_24_bits;
+                       }
+
+                       return (block & 0xff000000) |
+                               ((next << 16) & 0x00ff0000);
+               }
+
+               if ((block & 0xff000000) == block_24_bits) {
+                       next = (block & 0x00ff0000) >> 16;
+                       if (next < 255)
+                               next += 1;
+
+                       if (next == 255) {
+                               /*
+                                * Reached the end of the 24 bit
+                                * block, switch to the 16-bit block.
+                                */
+                               return block_16_bits;
+                       }
+
+                       return (block & 0xff000000) |
+                               ((next << 16) & 0x00ff0000);
+               }
+       }
+
+       return (block & 0xffff0000) | ((next << 8) & 0x0000ff00);
+}
+
+static uint32_t find_free_block()
+{
+       struct connman_ippool *pool;
+       uint32_t start;
+       uint32_t block;
+
+       if (last_block == 0)
+               return block_16_bits;
+
+       /*
+        * Instead starting always from the 16 bit block, we start
+        * from the last assigned block. This is a simple optimimazion
+        * for the case where a lot of blocks have been assigned, e.g.
+        * the first half of the private IP pool is in use and a new
+        * we need to find a new block.
+        *
+        * To only thing we have to make sure is that we terminated if
+        * there is no block left.
+        */
+       start = last_block;
+
+       block = next_block(start);
+       while (start != block) {
+               block = next_block(block);
+
+               pool = g_hash_table_lookup(hash_pool, GUINT_TO_POINTER(block));
+               if (pool != NULL)
+                       continue;
+
+               return block;
+       }
+
+       return 0;
+}
+
+struct connman_ippool *__connman_ippool_create(unsigned int start,
+                                               unsigned int range)
+{
+       struct connman_ippool *pool;
+       uint32_t block;
+
+       /*
+        * The range is at max 255 and we don't support overlapping
+        * blocks.
+        */
+       if (start + range > 254)
+               return NULL;
+
+       block = find_free_block();
+       if (block == 0)
+               return NULL;
+
+       pool = g_try_new0(struct connman_ippool, 1);
+       if (pool == NULL)
+               return NULL;
+
+       pool->refcount = 1;
+       pool->block = block;
+
+       last_block = block;
+
+       if (range == 0)
+               range = 1;
+
+       pool->gateway = get_ip(block + 1);
+       pool->broadcast = get_ip(block + 255);
+       pool->subnet_mask = get_ip(subnet_mask_24);
+       pool->start_ip = get_ip(block + start);
+       pool->end_ip = get_ip(block + start + range);
+
+       g_hash_table_insert(hash_pool, GUINT_TO_POINTER(pool->block), pool);
+
+       return pool;
+}
+
+const char *__connman_ippool_get_gateway(struct connman_ippool *pool)
+{
+       return pool->gateway;
+}
+
+const char *__connman_ippool_get_broadcast(struct connman_ippool *pool)
+{
+       return pool->broadcast;
+}
+
+const char *__connman_ippool_get_start_ip(struct connman_ippool *pool)
+{
+       return pool->start_ip;
+}
+
+const char *__connman_ippool_get_end_ip(struct connman_ippool *pool)
+{
+       return pool->end_ip;
+}
+
+const char *__connman_ippool_get_subnet_mask(struct connman_ippool *pool)
+{
+       return pool->subnet_mask;
+}
+
+static void pool_free(gpointer data)
+{
+       struct connman_ippool *pool = data;
+
+       g_free(pool->gateway);
+       g_free(pool->broadcast);
+       g_free(pool->start_ip);
+       g_free(pool->end_ip);
+       g_free(pool->subnet_mask);
+
+       g_free(pool);
+}
+
+int __connman_ippool_init(void)
+{
+       DBG("");
+
+       /* We start at 254 by default to avoid common addresses */
+       block_16_bits = ntohl(inet_addr("192.168.254.0"));
+       block_20_bits = ntohl(inet_addr("172.16.0.0"));
+       block_24_bits = ntohl(inet_addr("10.0.0.0"));
+       subnet_mask_24 = ntohl(inet_addr("255.255.255.0"));
+
+       hash_pool = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
+                                               pool_free);
+
+       return 0;
+}
+
+void __connman_ippool_cleanup(void)
+{
+       DBG("");
+
+       g_hash_table_destroy(hash_pool);
+       hash_pool = NULL;
+}
index adcef12..28337af 100644 (file)
@@ -337,6 +337,7 @@ int main(int argc, char *argv[])
        __connman_device_init(option_device, option_nodevice);
 
        __connman_agent_init();
+       __connman_ippool_init();
        __connman_iptables_init();
        __connman_tethering_init();
        __connman_counter_init();
@@ -397,6 +398,7 @@ int main(int argc, char *argv[])
        __connman_agent_cleanup();
        __connman_tethering_cleanup();
        __connman_iptables_cleanup();
+       __connman_ippool_cleanup();
        __connman_device_cleanup();
        __connman_network_cleanup();
        __connman_service_cleanup();