diff options
author | Jukka Rissanen <jukka.rissanen@linux.intel.com> | 2013-05-06 13:06:34 +0300 |
---|---|---|
committer | Patrik Flykt <patrik.flykt@linux.intel.com> | 2013-05-06 14:34:20 +0300 |
commit | fd415b40a2219cfc99dca8789496ec9df8e116e6 (patch) | |
tree | 3be2c38177c6de3a2f3b896fb9050fc913319c56 /gdhcp | |
parent | 68ce7d3019b847c655bac4764b2b0a7d4e32ce69 (diff) | |
download | connman-fd415b40a2219cfc99dca8789496ec9df8e116e6.tar.gz connman-fd415b40a2219cfc99dca8789496ec9df8e116e6.tar.bz2 connman-fd415b40a2219cfc99dca8789496ec9df8e116e6.zip |
dhcpv6: Implement CONFIRM message support
See RFC 3315 Chapter 18.1.2. Creation and Transmission of Confirm
Messages for details
Diffstat (limited to 'gdhcp')
-rw-r--r-- | gdhcp/client.c | 70 | ||||
-rw-r--r-- | gdhcp/gdhcp.h | 4 |
2 files changed, 71 insertions, 3 deletions
diff --git a/gdhcp/client.c b/gdhcp/client.c index 305533f0..fca5fff7 100644 --- a/gdhcp/client.c +++ b/gdhcp/client.c @@ -73,6 +73,7 @@ typedef enum _dhcp_client_state { INFORMATION_REQ, SOLICITATION, REQUEST, + CONFIRM, RENEW, REBIND, RELEASE, @@ -131,6 +132,8 @@ struct _GDHCPClient { gpointer rebind_data; GDHCPClientEventFunc release_cb; gpointer release_data; + GDHCPClientEventFunc confirm_cb; + gpointer confirm_data; char *last_address; unsigned char *duid; int duid_len; @@ -759,7 +762,7 @@ static void put_iaid(GDHCPClient *dhcp_client, int index, uint8_t *buf) int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index, int code, uint32_t *T1, uint32_t *T2, - gboolean add_iaaddr) + gboolean add_iaaddr, const char *ia_na) { if (code == G_DHCPV6_IA_TA) { uint8_t ia_options[4]; @@ -771,13 +774,29 @@ int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index, ia_options, sizeof(ia_options)); } else if (code == G_DHCPV6_IA_NA) { + struct in6_addr addr; g_dhcp_client_set_request(dhcp_client, G_DHCPV6_IA_NA); - if (add_iaaddr == TRUE) { + /* + * If caller has specified the IPv6 address it wishes to + * to use (ia_na != NULL and address is valid), then send + * the address to server. + * If caller did not specify the address (ia_na == NULL) and + * if the current address is not set, then we should not send + * the address sub-option. + */ + if (add_iaaddr == TRUE && ((ia_na == NULL && + IN6_IS_ADDR_UNSPECIFIED(&dhcp_client->ia_na) == FALSE) + || (ia_na != NULL && + inet_pton(AF_INET6, ia_na, &addr) == 1))) { #define IAADDR_LEN (16+4+4) uint8_t ia_options[4+4+4+2+2+IAADDR_LEN]; + if (ia_na != NULL) + memcpy(&dhcp_client->ia_na, &addr, + sizeof(struct in6_addr)); + put_iaid(dhcp_client, index, ia_options); if (T1 != NULL) { @@ -895,6 +914,11 @@ static int send_dhcpv6_request(GDHCPClient *dhcp_client) return send_dhcpv6_msg(dhcp_client, DHCPV6_REQUEST, "request"); } +static int send_dhcpv6_confirm(GDHCPClient *dhcp_client) +{ + return send_dhcpv6_msg(dhcp_client, DHCPV6_CONFIRM, "confirm"); +} + static int send_dhcpv6_renew(GDHCPClient *dhcp_client) { return send_dhcpv6_msg(dhcp_client, DHCPV6_RENEW, "renew"); @@ -2109,6 +2133,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, case RENEW: case REBIND: case RELEASE: + case CONFIRM: if (dhcp_client->type != G_DHCP_IPV6) return TRUE; @@ -2164,6 +2189,30 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, dhcp_client->release_data); return TRUE; } + if (dhcp_client->confirm_cb != NULL) { + count = 0; + server_id = dhcpv6_get_option(packet6, pkt_len, + G_DHCPV6_SERVERID, &option_len, + &count); + if (server_id == NULL || count != 1 || + option_len == 0) { + /* RFC 3315, 15.10 */ + debug(dhcp_client, + "confirm server duid error, " + "discarding msg %p/%d/%d", + server_id, option_len, count); + return TRUE; + } + dhcp_client->server_duid = g_try_malloc(option_len); + if (dhcp_client->server_duid == NULL) + return TRUE; + memcpy(dhcp_client->server_duid, server_id, option_len); + dhcp_client->server_duid_len = option_len; + + dhcp_client->confirm_cb(dhcp_client, + dhcp_client->confirm_data); + return TRUE; + } break; default: break; @@ -2288,6 +2337,16 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) } send_dhcpv6_request(dhcp_client); + } else if (dhcp_client->confirm_cb) { + dhcp_client->state = CONFIRM; + 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_confirm(dhcp_client); + } else if (dhcp_client->renew_cb) { dhcp_client->state = RENEW; re = switch_listening_mode(dhcp_client, L3); @@ -2474,6 +2533,12 @@ void g_dhcp_client_register_event(GDHCPClient *dhcp_client, dhcp_client->release_cb = func; dhcp_client->release_data = data; return; + case G_DHCP_CLIENT_EVENT_CONFIRM: + if (dhcp_client->type == G_DHCP_IPV4) + return; + dhcp_client->confirm_cb = func; + dhcp_client->confirm_data = data; + return; } } @@ -2512,6 +2577,7 @@ char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client) case INFORMATION_REQ: case SOLICITATION: case REQUEST: + case CONFIRM: case RENEW: case REBIND: case RELEASE: diff --git a/gdhcp/gdhcp.h b/gdhcp/gdhcp.h index 0820cdd5..ba47eaff 100644 --- a/gdhcp/gdhcp.h +++ b/gdhcp/gdhcp.h @@ -59,6 +59,7 @@ typedef enum { G_DHCP_CLIENT_EVENT_RENEW, G_DHCP_CLIENT_EVENT_REBIND, G_DHCP_CLIENT_EVENT_RELEASE, + G_DHCP_CLIENT_EVENT_CONFIRM, } GDHCPClientEvent; typedef enum { @@ -152,7 +153,8 @@ int g_dhcpv6_client_get_timeouts(GDHCPClient *dhcp_client, time_t *expire); uint32_t g_dhcpv6_client_get_iaid(GDHCPClient *dhcp_client); int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index, - int code, uint32_t *T1, uint32_t *T2, gboolean add_iaaddr); + int code, uint32_t *T1, uint32_t *T2, + gboolean add_addresses, const char *address); void g_dhcpv6_client_reset_renew(GDHCPClient *dhcp_client); void g_dhcpv6_client_reset_rebind(GDHCPClient *dhcp_client); void g_dhcpv6_client_set_expire(GDHCPClient *dhcp_client, uint32_t timeout); |