ippool: Add API to notify when IP is externally assigned
authorDaniel Wagner <daniel.wagner@bmw-carit.de>
Thu, 26 Jan 2012 13:30:17 +0000 (14:30 +0100)
committerDaniel Wagner <daniel.wagner@bmw-carit.de>
Wed, 1 Feb 2012 09:13:19 +0000 (10:13 +0100)
src/connman.h
src/ippool.c
src/tethering.c
unit/test-ippool.c

index 557b1eb..db58316 100644 (file)
@@ -707,6 +707,9 @@ int __connman_6to4_check(struct connman_ipconfig *ipconfig);
 
 struct connman_ippool;
 
+typedef void (*ippool_collision_cb_t) (struct connman_ippool *pool,
+                                       void *user_data);
+
 int __connman_ippool_init(void);
 void __connman_ippool_cleanup(void);
 
@@ -720,11 +723,17 @@ struct connman_ippool *__connman_ippool_ref_debug(struct connman_ippool *pool,
 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);
+struct connman_ippool *__connman_ippool_create(int index,
+                                       unsigned int start,
+                                       unsigned int range,
+                                       ippool_collision_cb_t collision_cb,
+                                       void *user_data);
 
 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);
+
+void __connman_ippool_newaddr(int index, const char *address);
+void __connman_ippool_deladdr(int index, const char *address);
index 085d06c..a4819ee 100644 (file)
@@ -37,6 +37,7 @@
 struct connman_ippool {
        unsigned int refcount;
 
+       int index;
        uint32_t block;
 
        char *gateway;
@@ -44,9 +45,13 @@ struct connman_ippool {
        char *start_ip;
        char *end_ip;
        char *subnet_mask;
+
+       ippool_collision_cb_t collision_cb;
+       void *user_data;
 };
 
 static GHashTable *hash_pool;
+static GHashTable *hash_addresses;
 static uint32_t last_block;
 static uint32_t block_16_bits;
 static uint32_t block_20_bits;
@@ -156,6 +161,7 @@ static uint32_t find_free_block()
        struct connman_ippool *pool;
        uint32_t start;
        uint32_t block;
+       uint32_t *key;
 
        if (last_block == 0)
                return block_16_bits;
@@ -176,18 +182,76 @@ static uint32_t find_free_block()
        while (start != block) {
                block = next_block(block);
 
-               pool = g_hash_table_lookup(hash_pool, GUINT_TO_POINTER(block));
+               key = GUINT_TO_POINTER(block);
+               pool = g_hash_table_lookup(hash_pool, key);
                if (pool != NULL)
                        continue;
 
+               if (g_hash_table_lookup(hash_addresses, key) != NULL)
+                       continue;
+
                return block;
        }
 
        return 0;
 }
 
-struct connman_ippool *__connman_ippool_create(unsigned int start,
-                                               unsigned int range)
+void __connman_ippool_newaddr(int index, const char *address)
+{
+       struct connman_ippool *pool;
+       struct in_addr inp;
+       uint32_t block;
+       uint32_t *key;
+       unsigned int count;
+
+       if (inet_aton(address, &inp) == 0)
+               return;
+
+       block = ntohl(inp.s_addr) & 0xffffff00;
+
+       key = GUINT_TO_POINTER(block);
+       count = GPOINTER_TO_UINT(g_hash_table_lookup(hash_addresses, key));
+       count = count + 1;
+       g_hash_table_replace(hash_addresses, key, GUINT_TO_POINTER(count));
+
+       pool = g_hash_table_lookup(hash_pool, key);
+       if (pool == NULL)
+               return;
+
+       if (pool->index == index)
+               return;
+
+       if (pool->collision_cb != NULL)
+               pool->collision_cb(pool, pool->user_data);
+}
+
+void __connman_ippool_deladdr(int index, const char *address)
+{
+       struct in_addr inp;
+       uint32_t block;
+       uint32_t *key;
+       unsigned int count;
+
+       if (inet_aton(address, &inp) == 0)
+               return;
+
+       block = ntohl(inp.s_addr) & 0xffffff00;
+
+       key = GUINT_TO_POINTER(block);
+       count = GPOINTER_TO_UINT(g_hash_table_lookup(hash_addresses, key));
+       count = count - 1;
+
+       if (count == 0)
+               g_hash_table_remove(hash_addresses, key);
+       else
+               g_hash_table_replace(hash_addresses, key, GUINT_TO_POINTER(count));
+}
+
+struct connman_ippool *__connman_ippool_create(int index,
+                                       unsigned int start,
+                                       unsigned int range,
+                                       ippool_collision_cb_t collision_cb,
+                                       void *user_data)
 {
        struct connman_ippool *pool;
        uint32_t block;
@@ -208,7 +272,10 @@ struct connman_ippool *__connman_ippool_create(unsigned int start,
                return NULL;
 
        pool->refcount = 1;
+       pool->index = index;
        pool->block = block;
+       pool->collision_cb = collision_cb;
+       pool->user_data = user_data;
 
        last_block = block;
 
@@ -276,6 +343,8 @@ int __connman_ippool_init(void)
 
        hash_pool = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
                                                pool_free);
+       hash_addresses = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                                               NULL, NULL);
 
        return 0;
 }
@@ -286,4 +355,7 @@ void __connman_ippool_cleanup(void)
 
        g_hash_table_destroy(hash_pool);
        hash_pool = NULL;
+
+       g_hash_table_destroy(hash_addresses);
+       hash_addresses = NULL;
 }
index f7d40a1..5c359dd 100644 (file)
@@ -329,6 +329,7 @@ static void disable_nat(const char *interface)
 
 void __connman_tethering_set_enabled(void)
 {
+       int index;
        int err;
        const char *gateway;
        const char *broadcast;
@@ -346,7 +347,8 @@ void __connman_tethering_set_enabled(void)
        if (err < 0)
                return;
 
-       dhcp_ippool = __connman_ippool_create(1, 253);
+       index = connman_inet_ifindex(BRIDGE_NAME);
+       dhcp_ippool = __connman_ippool_create(index, 1, 253, NULL, NULL);
        if (dhcp_ippool == NULL) {
                connman_error("Fail to create IP pool");
                return;
@@ -583,7 +585,7 @@ int __connman_private_network_request(DBusMessage *msg, const char *owner)
        pn->fd = fd;
        pn->interface = iface;
        pn->index = index;
-       pn->pool = __connman_ippool_create(1, 1);
+       pn->pool = __connman_ippool_create(pn->fd, 1, 1, NULL, NULL);
        if (pn->pool == NULL) {
                errno = -ENOMEM;
                goto error;
index 8cbcf64..e7f6de0 100644 (file)
@@ -51,11 +51,11 @@ static void test_ippool_basic0(void)
 
        /* Test the IP range */
 
-       pool = __connman_ippool_create(1, 500);
+       pool = __connman_ippool_create(23, 1, 500, NULL, NULL);
        g_assert(pool == NULL);
 
        for (i = 1; i < 254; i++) {
-               pool = __connman_ippool_create(1, i);
+               pool = __connman_ippool_create(23, 1, i, NULL, NULL);
                g_assert(pool);
 
                gateway = __connman_ippool_get_gateway(pool);
@@ -103,7 +103,7 @@ static void test_ippool_basic1(void)
         */
 
        while (TRUE) {
-               pool = __connman_ippool_create(1, 100);
+               pool = __connman_ippool_create(23, 1, 100, NULL, NULL);
                if (pool == NULL)
                        break;
                i += 1;