diff options
author | Jukka Rissanen <jukka.rissanen@linux.intel.com> | 2012-01-05 13:38:14 +0200 |
---|---|---|
committer | Daniel Wagner <daniel.wagner@bmw-carit.de> | 2012-01-05 13:17:26 +0100 |
commit | 53f38ce0bc6505c8b8a7342b0243df442b7db5a4 (patch) | |
tree | ed3550a683f4f77ab7936374f4464ce19d1fbc5d | |
parent | 5f5b3609c4f9884954623d7e6bf2ae1ae7096637 (diff) | |
download | connman-53f38ce0bc6505c8b8a7342b0243df442b7db5a4.tar.gz connman-53f38ce0bc6505c8b8a7342b0243df442b7db5a4.tar.bz2 connman-53f38ce0bc6505c8b8a7342b0243df442b7db5a4.zip |
dhcpv6: Release message implemented.
-rw-r--r-- | gdhcp/client.c | 31 | ||||
-rw-r--r-- | gdhcp/gdhcp.h | 1 | ||||
-rw-r--r-- | src/connman.h | 2 | ||||
-rw-r--r-- | src/dhcpv6.c | 64 | ||||
-rw-r--r-- | src/network.c | 17 |
5 files changed, 114 insertions, 1 deletions
diff --git a/gdhcp/client.c b/gdhcp/client.c index 7743aa50..99f99510 100644 --- a/gdhcp/client.c +++ b/gdhcp/client.c @@ -74,6 +74,7 @@ typedef enum _dhcp_client_state { REQUEST, RENEW, REBIND, + RELEASE, } ClientState; struct _GDHCPClient { @@ -126,6 +127,8 @@ struct _GDHCPClient { gpointer renew_data; GDHCPClientEventFunc rebind_cb; gpointer rebind_data; + GDHCPClientEventFunc release_cb; + gpointer release_data; char *last_address; unsigned char *duid; int duid_len; @@ -817,6 +820,11 @@ static int send_dhcpv6_rebind(GDHCPClient *dhcp_client) return send_dhcpv6_msg(dhcp_client, DHCPV6_REBIND, "rebind"); } +static int send_dhcpv6_release(GDHCPClient *dhcp_client) +{ + return send_dhcpv6_msg(dhcp_client, DHCPV6_RELEASE, "release"); +} + static int send_information_req(GDHCPClient *dhcp_client) { return send_dhcpv6_msg(dhcp_client, DHCPV6_INFORMATION_REQ, @@ -2002,6 +2010,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, case REQUEST: case RENEW: case REBIND: + case RELEASE: if (dhcp_client->type != G_DHCP_IPV6) return TRUE; @@ -2053,6 +2062,11 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, dhcp_client->rebind_data); return TRUE; } + if (dhcp_client->release_cb != NULL) { + dhcp_client->release_cb(dhcp_client, + dhcp_client->release_data); + return TRUE; + } break; default: break; @@ -2196,6 +2210,16 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) return re; } send_dhcpv6_rebind(dhcp_client); + + } else if (dhcp_client->release_cb) { + dhcp_client->state = RENEW; + re = switch_listening_mode(dhcp_client, L3); + if (re != 0) { + switch_listening_mode(dhcp_client, L_NONE); + dhcp_client->state = 0; + return re; + } + send_dhcpv6_release(dhcp_client); } return 0; @@ -2346,6 +2370,12 @@ void g_dhcp_client_register_event(GDHCPClient *dhcp_client, dhcp_client->rebind_cb = func; dhcp_client->rebind_data = data; return; + case G_DHCP_CLIENT_EVENT_RELEASE: + if (dhcp_client->type == G_DHCP_IPV4) + return; + dhcp_client->release_cb = func; + dhcp_client->release_data = data; + return; } } @@ -2386,6 +2416,7 @@ char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client) case REQUEST: case RENEW: case REBIND: + case RELEASE: break; } return NULL; diff --git a/gdhcp/gdhcp.h b/gdhcp/gdhcp.h index 49b06b1a..edebc9e1 100644 --- a/gdhcp/gdhcp.h +++ b/gdhcp/gdhcp.h @@ -58,6 +58,7 @@ typedef enum { G_DHCP_CLIENT_EVENT_REQUEST, G_DHCP_CLIENT_EVENT_RENEW, G_DHCP_CLIENT_EVENT_REBIND, + G_DHCP_CLIENT_EVENT_RELEASE, } GDHCPClientEvent; typedef enum { diff --git a/src/connman.h b/src/connman.h index d99d4b4d..5dc588a6 100644 --- a/src/connman.h +++ b/src/connman.h @@ -286,6 +286,8 @@ int __connman_dhcpv6_start(struct connman_network *network, GSList *prefixes, dhcp_cb callback); int __connman_dhcpv6_start_renew(struct connman_network *network, dhcp_cb callback); +int __connman_dhcpv6_start_release(struct connman_network *network, + dhcp_cb callback); int __connman_ipv4_init(void); void __connman_ipv4_cleanup(void); diff --git a/src/dhcpv6.c b/src/dhcpv6.c index fd6e0ebe..f2c7da60 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -66,6 +66,7 @@ struct connman_dhcpv6 { gboolean use_ta; /* set to TRUE if IPv6 privacy is enabled */ GSList *prefixes; /* network prefixes from radvd */ int request_count; /* how many times REQUEST have been sent */ + gboolean stateless; /* TRUE if stateless DHCPv6 is used */ }; static GHashTable *network_table; @@ -236,6 +237,10 @@ static void clear_callbacks(GDHCPClient *dhcp_client) NULL, NULL); g_dhcp_client_register_event(dhcp_client, + G_DHCP_CLIENT_EVENT_RELEASE, + NULL, NULL); + + g_dhcp_client_register_event(dhcp_client, G_DHCP_CLIENT_EVENT_INFORMATION_REQ, NULL, NULL); } @@ -854,6 +859,64 @@ int __connman_dhcpv6_start_renew(struct connman_network *network, return 0; } +static void release_cb(GDHCPClient *dhcp_client, gpointer user_data) +{ + struct connman_dhcpv6 *dhcp = user_data; + + DBG("dhcpv6 release msg %p", dhcp); + + if (dhcp->callback != NULL) { + uint16_t status = g_dhcpv6_client_get_status(dhcp_client); + dhcp->callback(dhcp->network, status == 0 ? TRUE : FALSE); + } +} + +int __connman_dhcpv6_start_release(struct connman_network *network, + dhcp_cb callback) +{ + struct connman_dhcpv6 *dhcp; + GDHCPClient *dhcp_client; + + if (network_table == NULL) + return 0; /* we are already released */ + + dhcp = g_hash_table_lookup(network_table, network); + if (dhcp == NULL) + return -ENOENT; + + DBG("dhcp %p stateless %d", dhcp, dhcp->stateless); + + if (dhcp->stateless == TRUE) + return -EINVAL; + + if (dhcp->timeout > 0) { + g_source_remove(dhcp->timeout); + dhcp->timeout = 0; + } + + dhcp_client = dhcp->dhcp_client; + + g_dhcp_client_clear_requests(dhcp_client); + g_dhcp_client_clear_values(dhcp_client); + + g_dhcp_client_set_request(dhcp_client, G_DHCPV6_CLIENTID); + g_dhcp_client_set_request(dhcp_client, G_DHCPV6_SERVERID); + + g_dhcpv6_client_set_ia(dhcp_client, + connman_network_get_index(dhcp->network), + dhcp->use_ta == TRUE ? G_DHCPV6_IA_TA : G_DHCPV6_IA_NA, + NULL, NULL, TRUE); + + clear_callbacks(dhcp_client); + + g_dhcp_client_register_event(dhcp_client, G_DHCP_CLIENT_EVENT_RELEASE, + release_cb, dhcp); + + dhcp->dhcp_client = dhcp_client; + + return g_dhcp_client_start(dhcp_client, NULL); +} + static int dhcpv6_release(struct connman_dhcpv6 *dhcp) { DBG("dhcp %p", dhcp); @@ -932,6 +995,7 @@ int __connman_dhcpv6_start_info(struct connman_network *network, dhcp->network = network; dhcp->callback = callback; + dhcp->stateless = TRUE; connman_network_ref(network); diff --git a/src/network.c b/src/network.c index bff0e7e2..2637ba5d 100644 --- a/src/network.c +++ b/src/network.c @@ -974,6 +974,21 @@ static void stop_dhcpv6(struct connman_network *network) __connman_dhcpv6_stop(network); } +static void dhcpv6_release_callback(struct connman_network *network, + connman_bool_t success) +{ + DBG("success %d", success); + + stop_dhcpv6(network); +} + +static void release_dhcpv6(struct connman_network *network) +{ + if (__connman_dhcpv6_start_release(network, + dhcpv6_release_callback) < 0) + stop_dhcpv6(network); +} + static void dhcpv6_info_callback(struct connman_network *network, connman_bool_t success) { @@ -1211,7 +1226,7 @@ static gboolean set_connected(gpointer user_data) break; case CONNMAN_IPCONFIG_METHOD_DHCP: case CONNMAN_IPCONFIG_METHOD_AUTO: - stop_dhcpv6(network); + release_dhcpv6(network); break; } |