From c92a03edebc7e3e37a71d3e1350619031bc17ddf Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Thu, 26 Jan 2012 14:30:17 +0100 Subject: [PATCH] ippool: Add API to notify when IP is externally assigned --- src/connman.h | 13 +++++++-- src/ippool.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++--- src/tethering.c | 6 +++-- unit/test-ippool.c | 6 ++--- 4 files changed, 93 insertions(+), 10 deletions(-) diff --git a/src/connman.h b/src/connman.h index 557b1eb..db58316 100644 --- a/src/connman.h +++ b/src/connman.h @@ -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); diff --git a/src/ippool.c b/src/ippool.c index 085d06c..a4819ee 100644 --- a/src/ippool.c +++ b/src/ippool.c @@ -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; } diff --git a/src/tethering.c b/src/tethering.c index f7d40a1..5c359dd 100644 --- a/src/tethering.c +++ b/src/tethering.c @@ -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; diff --git a/unit/test-ippool.c b/unit/test-ippool.c index 8cbcf64..e7f6de0 100644 --- a/unit/test-ippool.c +++ b/unit/test-ippool.c @@ -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; -- 2.7.4