diff options
author | Zhang zhengguang <zhengguang.zhang@intel.com> | 2014-07-17 10:37:39 +0800 |
---|---|---|
committer | Zhang zhengguang <zhengguang.zhang@intel.com> | 2014-07-17 10:37:39 +0800 |
commit | 1b9d0a62f59bb48c8deb2f0b98d9acdffdd9abe7 (patch) | |
tree | 6e991827d28537f7f40f20786c2354fd04a9fdad /gdhcp | |
parent | fbe905ab58ecc31fe64c410c5f580cadc30e7f04 (diff) | |
download | connman-1b9d0a62f59bb48c8deb2f0b98d9acdffdd9abe7.tar.gz connman-1b9d0a62f59bb48c8deb2f0b98d9acdffdd9abe7.tar.bz2 connman-1b9d0a62f59bb48c8deb2f0b98d9acdffdd9abe7.zip |
Imported Upstream version 1.24upstream/1.24
Diffstat (limited to 'gdhcp')
-rw-r--r-- | gdhcp/client.c | 963 | ||||
-rw-r--r-- | gdhcp/common.c | 70 | ||||
-rw-r--r-- | gdhcp/common.h | 2 | ||||
-rw-r--r-- | gdhcp/gdhcp.h | 39 | ||||
-rw-r--r-- | gdhcp/ipv4ll.c | 3 | ||||
-rw-r--r-- | gdhcp/server.c | 171 |
6 files changed, 830 insertions, 418 deletions
diff --git a/gdhcp/client.c b/gdhcp/client.c index bbd00c40..2b7202a4 100644 --- a/gdhcp/client.c +++ b/gdhcp/client.c @@ -2,7 +2,7 @@ * * DHCP client library with GLib integration * - * Copyright (C) 2009-2012 Intel Corporation. All rights reserved. + * Copyright (C) 2009-2014 Intel Corporation. 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 @@ -32,6 +32,7 @@ #include <sys/ioctl.h> #include <arpa/inet.h> #include <sys/time.h> +#include <resolv.h> #include <netpacket/packet.h> #include <netinet/if_ether.h> @@ -61,6 +62,7 @@ typedef enum _listen_mode { typedef enum _dhcp_client_state { INIT_SELECTING, + REBOOTING, REQUESTING, BOUND, RENEWING, @@ -77,6 +79,7 @@ typedef enum _dhcp_client_state { RENEW, REBIND, RELEASE, + DECLINE, } ClientState; struct _GDHCPClient { @@ -98,8 +101,10 @@ struct _GDHCPClient { uint8_t ack_retry_times; uint8_t conflicts; guint timeout; + guint t1_timeout; + guint t2_timeout; + guint lease_timeout; guint listener_watch; - GIOChannel *listener_channel; GList *require_list; GList *request_list; GHashTable *code_value_hash; @@ -134,6 +139,8 @@ struct _GDHCPClient { gpointer release_data; GDHCPClientEventFunc confirm_cb; gpointer confirm_data; + GDHCPClientEventFunc decline_cb; + gpointer decline_data; char *last_address; unsigned char *duid; int duid_len; @@ -144,10 +151,9 @@ struct _GDHCPClient { uint32_t T1, T2; struct in6_addr ia_na; struct in6_addr ia_ta; - time_t last_renew; - time_t last_rebind; - time_t expire; - gboolean retransmit; + time_t last_request; + uint32_t expire; + bool retransmit; struct timeval start_time; }; @@ -156,7 +162,7 @@ static inline void debug(GDHCPClient *client, const char *format, ...) char str[256]; va_list ap; - if (client->debug_func == NULL) + if (!client->debug_func) return; va_start(ap, format); @@ -251,7 +257,7 @@ static void copy_option(uint8_t *buf, uint16_t code, uint16_t len, buf[1] = code & 0xff; buf[2] = len >> 8; buf[3] = len & 0xff; - if (len > 0 && msg != NULL) + if (len > 0 && msg) memcpy(&buf[4], msg, len); } @@ -268,6 +274,25 @@ static int32_t get_time_diff(struct timeval *tv) return hsec; } +static void remove_timeouts(GDHCPClient *dhcp_client) +{ + + if (dhcp_client->timeout > 0) + g_source_remove(dhcp_client->timeout); + if (dhcp_client->t1_timeout > 0) + g_source_remove(dhcp_client->t1_timeout); + if (dhcp_client->t2_timeout > 0) + g_source_remove(dhcp_client->t2_timeout); + if (dhcp_client->lease_timeout > 0) + g_source_remove(dhcp_client->lease_timeout); + + dhcp_client->timeout = 0; + dhcp_client->t1_timeout = 0; + dhcp_client->t2_timeout = 0; + dhcp_client->lease_timeout = 0; + +} + static void add_dhcpv6_request_options(GDHCPClient *dhcp_client, struct dhcpv6_packet *packet, unsigned char *buf, int max_buf, @@ -275,6 +300,7 @@ static void add_dhcpv6_request_options(GDHCPClient *dhcp_client, { GList *list; uint16_t code, value; + bool added; int32_t diff; int len; @@ -283,10 +309,11 @@ static void add_dhcpv6_request_options(GDHCPClient *dhcp_client, for (list = dhcp_client->request_list; list; list = list->next) { code = (uint16_t) GPOINTER_TO_INT(list->data); + added = false; switch (code) { case G_DHCPV6_CLIENTID: - if (dhcp_client->duid == NULL) + if (!dhcp_client->duid) return; len = 2 + 2 + dhcp_client->duid_len; @@ -299,11 +326,12 @@ static void add_dhcpv6_request_options(GDHCPClient *dhcp_client, copy_option(*ptr_buf, G_DHCPV6_CLIENTID, dhcp_client->duid_len, dhcp_client->duid); (*ptr_buf) += len; + added = true; break; case G_DHCPV6_SERVERID: - if (dhcp_client->server_duid == NULL) - return; + if (!dhcp_client->server_duid) + break; len = 2 + 2 + dhcp_client->server_duid_len; if ((*ptr_buf + len) > (buf + max_buf)) { @@ -316,6 +344,7 @@ static void add_dhcpv6_request_options(GDHCPClient *dhcp_client, dhcp_client->server_duid_len, dhcp_client->server_duid); (*ptr_buf) += len; + added = true; break; case G_DHCPV6_RAPID_COMMIT: @@ -328,13 +357,14 @@ static void add_dhcpv6_request_options(GDHCPClient *dhcp_client, copy_option(*ptr_buf, G_DHCPV6_RAPID_COMMIT, 0, 0); (*ptr_buf) += len; + added = true; break; case G_DHCPV6_ORO: break; case G_DHCPV6_ELAPSED_TIME: - if (dhcp_client->retransmit == FALSE) { + if (!dhcp_client->retransmit) { /* * Initial message, elapsed time is 0. */ @@ -356,6 +386,7 @@ static void add_dhcpv6_request_options(GDHCPClient *dhcp_client, copy_option(*ptr_buf, G_DHCPV6_ELAPSED_TIME, 2, (uint8_t *)&value); (*ptr_buf) += len; + added = true; break; case G_DHCPV6_DNS_SERVERS: @@ -370,6 +401,9 @@ static void add_dhcpv6_request_options(GDHCPClient *dhcp_client, default: break; } + + if (added) + debug(dhcp_client, "option %d len %d added", code, len); } } @@ -426,63 +460,37 @@ static int send_discover(GDHCPClient *dhcp_client, uint32_t requested) MAC_BCAST_ADDR, dhcp_client->ifindex); } -static int send_select(GDHCPClient *dhcp_client) +static int send_request(GDHCPClient *dhcp_client) { struct dhcp_packet packet; - - debug(dhcp_client, "sending DHCP select request"); + debug(dhcp_client, "sending DHCP request"); init_packet(dhcp_client, &packet, DHCPREQUEST); packet.xid = dhcp_client->xid; packet.secs = dhcp_attempt_secs(dhcp_client); - dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP, - dhcp_client->requested_ip); - dhcp_add_option_uint32(&packet, DHCP_SERVER_ID, - dhcp_client->server_ip); - - add_request_options(dhcp_client, &packet); - - add_send_options(dhcp_client, &packet); - - return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, - INADDR_BROADCAST, SERVER_PORT, - MAC_BCAST_ADDR, dhcp_client->ifindex); -} - -static int send_renew(GDHCPClient *dhcp_client) -{ - struct dhcp_packet packet; + if (dhcp_client->state == REQUESTING || dhcp_client->state == REBOOTING) + dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP, + dhcp_client->requested_ip); - debug(dhcp_client, "sending DHCP renew request"); + if (dhcp_client->state == REQUESTING) + dhcp_add_option_uint32(&packet, DHCP_SERVER_ID, + dhcp_client->server_ip); - init_packet(dhcp_client , &packet, DHCPREQUEST); - packet.xid = dhcp_client->xid; - packet.ciaddr = htonl(dhcp_client->requested_ip); + dhcp_add_option_uint16(&packet, DHCP_MAX_SIZE, 576); add_request_options(dhcp_client, &packet); add_send_options(dhcp_client, &packet); - return dhcp_send_kernel_packet(&packet, - dhcp_client->requested_ip, CLIENT_PORT, - dhcp_client->server_ip, SERVER_PORT); -} - -static int send_rebound(GDHCPClient *dhcp_client) -{ - struct dhcp_packet packet; - - debug(dhcp_client, "sending DHCP rebound request"); + if (dhcp_client->state == RENEWING) { + packet.ciaddr = htonl(dhcp_client->requested_ip); - init_packet(dhcp_client , &packet, DHCPREQUEST); - packet.xid = dhcp_client->xid; - packet.ciaddr = htonl(dhcp_client->requested_ip); - - add_request_options(dhcp_client, &packet); - - add_send_options(dhcp_client, &packet); + return dhcp_send_kernel_packet(&packet, + dhcp_client->requested_ip, CLIENT_PORT, + dhcp_client->server_ip, SERVER_PORT); + } return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, SERVER_PORT, @@ -562,9 +570,7 @@ static gboolean send_announce_packet(gpointer dhcp_data) dhcp_client->requested_ip, dhcp_client->ifindex); - if (dhcp_client->timeout > 0) - g_source_remove(dhcp_client->timeout); - dhcp_client->timeout = 0; + remove_timeouts(dhcp_client); if (dhcp_client->state == IPV4LL_DEFEND) { dhcp_client->timeout = @@ -618,18 +624,18 @@ done: void g_dhcpv6_client_set_retransmit(GDHCPClient *dhcp_client) { - if (dhcp_client == NULL) + if (!dhcp_client) return; - dhcp_client->retransmit = TRUE; + dhcp_client->retransmit = true; } void g_dhcpv6_client_clear_retransmit(GDHCPClient *dhcp_client) { - if (dhcp_client == NULL) + if (!dhcp_client) return; - dhcp_client->retransmit = FALSE; + dhcp_client->retransmit = false; } int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type, @@ -641,7 +647,7 @@ int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type, case G_DHCPV6_DUID_LLT: *duid_len = 2 + 2 + 4 + ETH_ALEN; *duid = g_try_malloc(*duid_len); - if (*duid == NULL) + if (!*duid) return -ENOMEM; (*duid)[0] = 0; @@ -660,7 +666,7 @@ int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type, case G_DHCPV6_DUID_LL: *duid_len = 2 + 2 + ETH_ALEN; *duid = g_try_malloc(*duid_len); - if (*duid == NULL) + if (!*duid) return -ENOMEM; (*duid)[0] = 0; @@ -674,10 +680,21 @@ int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type, return 0; } +static gchar *convert_to_hex(unsigned char *buf, int len) +{ + gchar *ret = g_try_malloc(len * 2 + 1); + int i; + + for (i = 0; ret && i < len; i++) + g_snprintf(ret + i * 2, 3, "%02x", buf[i]); + + return ret; +} + int g_dhcpv6_client_set_duid(GDHCPClient *dhcp_client, unsigned char *duid, int duid_len) { - if (dhcp_client == NULL || dhcp_client->type != G_DHCP_IPV6) + if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6) return -EINVAL; g_free(dhcp_client->duid); @@ -685,17 +702,95 @@ int g_dhcpv6_client_set_duid(GDHCPClient *dhcp_client, unsigned char *duid, dhcp_client->duid = duid; dhcp_client->duid_len = duid_len; + if (dhcp_client->debug_func) { + gchar *hex = convert_to_hex(duid, duid_len); + debug(dhcp_client, "DUID(%d) %s", duid_len, hex); + g_free(hex); + } + + return 0; +} + +int g_dhcpv6_client_set_pd(GDHCPClient *dhcp_client, uint32_t *T1, + uint32_t *T2, GSList *prefixes) +{ + uint8_t options[1452]; + unsigned int max_buf = sizeof(options); + int len, count = g_slist_length(prefixes); + + if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6) + return -EINVAL; + + g_dhcp_client_set_request(dhcp_client, G_DHCPV6_IA_PD); + + memset(options, 0, sizeof(options)); + + options[0] = dhcp_client->iaid >> 24; + options[1] = dhcp_client->iaid >> 16; + options[2] = dhcp_client->iaid >> 8; + options[3] = dhcp_client->iaid; + + if (T1) { + uint32_t t = htonl(*T1); + memcpy(&options[4], &t, 4); + } + + if (T2) { + uint32_t t = htonl(*T2); + memcpy(&options[8], &t, 4); + } + + len = 12; + + if (count > 0) { + GSList *list; + + for (list = prefixes; list; list = list->next) { + GDHCPIAPrefix *prefix = list->data; + uint8_t sub_option[4+4+1+16]; + + if ((len + 2 + 2 + sizeof(sub_option)) >= max_buf) { + debug(dhcp_client, + "Too long dhcpv6 message " + "when writing IA prefix option"); + return -EINVAL; + } + + memset(&sub_option, 0, sizeof(sub_option)); + + /* preferred and validity time are left zero */ + + sub_option[8] = prefix->prefixlen; + memcpy(&sub_option[9], &prefix->prefix, 16); + + copy_option(&options[len], G_DHCPV6_IA_PREFIX, + sizeof(sub_option), sub_option); + len += 2 + 2 + sizeof(sub_option); + } + } + + g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_PD, + options, len); + return 0; } uint32_t g_dhcpv6_client_get_iaid(GDHCPClient *dhcp_client) { - if (dhcp_client == NULL || dhcp_client->type != G_DHCP_IPV6) + if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6) return 0; return dhcp_client->iaid; } +void g_dhcpv6_client_set_iaid(GDHCPClient *dhcp_client, uint32_t iaid) +{ + if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6) + return; + + dhcp_client->iaid = iaid; +} + void g_dhcpv6_client_create_iaid(GDHCPClient *dhcp_client, int index, unsigned char *iaid) { @@ -710,26 +805,23 @@ void g_dhcpv6_client_create_iaid(GDHCPClient *dhcp_client, int index, int g_dhcpv6_client_get_timeouts(GDHCPClient *dhcp_client, uint32_t *T1, uint32_t *T2, - time_t *last_renew, time_t *last_rebind, + time_t *started, time_t *expire) { - if (dhcp_client == NULL || dhcp_client->type != G_DHCP_IPV6) + if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6) return -EINVAL; - if (T1 != NULL) + if (T1) *T1 = dhcp_client->T1; - if (T2 != NULL) + if (T2) *T2 = dhcp_client->T2; - if (last_renew != NULL) - *last_renew = dhcp_client->last_renew; - - if (last_rebind != NULL) - *last_rebind = dhcp_client->last_rebind; + if (started) + *started = dhcp_client->last_request; - if (expire != NULL) - *expire = dhcp_client->expire; + if (expire) + *expire = dhcp_client->last_request + dhcp_client->expire; return 0; } @@ -747,6 +839,24 @@ static uint8_t *create_iaaddr(GDHCPClient *dhcp_client, uint8_t *buf, return buf; } +static uint8_t *append_iaaddr(GDHCPClient *dhcp_client, uint8_t *buf, + const char *address) +{ + struct in6_addr addr; + + if (inet_pton(AF_INET6, address, &addr) != 1) + return NULL; + + buf[0] = 0; + buf[1] = G_DHCPV6_IAADDR; + buf[2] = 0; + buf[3] = 24; + memcpy(&buf[4], &addr, 16); + memset(&buf[20], 0, 4); /* preferred */ + memset(&buf[24], 0, 4); /* valid */ + return &buf[28]; +} + static void put_iaid(GDHCPClient *dhcp_client, int index, uint8_t *buf) { uint32_t iaid; @@ -765,7 +875,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, const char *ia_na) + bool add_iaaddr, const char *ia_na) { if (code == G_DHCPV6_IA_TA) { uint8_t ia_options[4]; @@ -789,20 +899,20 @@ int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index, * 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 && + if (add_iaaddr && ((!ia_na && + !IN6_IS_ADDR_UNSPECIFIED(&dhcp_client->ia_na)) + || (ia_na && 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) + if (ia_na) memcpy(&dhcp_client->ia_na, &addr, sizeof(struct in6_addr)); put_iaid(dhcp_client, index, ia_options); - if (T1 != NULL) { + if (T1) { ia_options[4] = *T1 >> 24; ia_options[5] = *T1 >> 16; ia_options[6] = *T1 >> 8; @@ -810,7 +920,7 @@ int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index, } else memset(&ia_options[4], 0x00, 4); - if (T2 != NULL) { + if (T2) { ia_options[8] = *T2 >> 24; ia_options[9] = *T2 >> 16; ia_options[10] = *T2 >> 8; @@ -841,6 +951,67 @@ int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index, return 0; } +int g_dhcpv6_client_set_ias(GDHCPClient *dhcp_client, int index, + int code, uint32_t *T1, uint32_t *T2, + GSList *addresses) +{ + GSList *list; + uint8_t *ia_options, *pos; + int len, count, total_len; + + count = g_slist_length(addresses); + if (count == 0) + return -EINVAL; + + g_dhcp_client_set_request(dhcp_client, code); + + if (code == G_DHCPV6_IA_TA) + len = 4; /* IAID */ + else if (code == G_DHCPV6_IA_NA) + len = 4 + 4 + 4; /* IAID + T1 + T2 */ + else + return -EINVAL; + + total_len = len + count * (2 + 2 + 16 + 4 + 4); + ia_options = g_try_malloc0(total_len); + if (!ia_options) + return -ENOMEM; + + put_iaid(dhcp_client, index, ia_options); + + pos = &ia_options[len]; /* skip the IA_NA or IA_TA */ + + for (list = addresses; list; list = list->next) { + pos = append_iaaddr(dhcp_client, pos, list->data); + if (!pos) + break; + } + + if (code == G_DHCPV6_IA_NA) { + if (T1) { + ia_options[4] = *T1 >> 24; + ia_options[5] = *T1 >> 16; + ia_options[6] = *T1 >> 8; + ia_options[7] = *T1; + } else + memset(&ia_options[4], 0x00, 4); + + if (T2) { + ia_options[8] = *T2 >> 24; + ia_options[9] = *T2 >> 16; + ia_options[10] = *T2 >> 8; + ia_options[11] = *T2; + } else + memset(&ia_options[8], 0x00, 4); + } + + g_dhcpv6_client_set_send(dhcp_client, code, ia_options, total_len); + + g_free(ia_options); + + return 0; +} + int g_dhcpv6_client_set_oro(GDHCPClient *dhcp_client, int args, ...) { va_list va; @@ -848,7 +1019,7 @@ int g_dhcpv6_client_set_oro(GDHCPClient *dhcp_client, int args, ...) uint8_t *values; values = g_try_malloc(len); - if (values == NULL) + if (!values) return -ENOMEM; va_start(va, args); @@ -879,7 +1050,7 @@ static int send_dhcpv6_msg(GDHCPClient *dhcp_client, int type, char *msg) init_packet(dhcp_client, packet, type); - if (dhcp_client->retransmit == FALSE) { + if (!dhcp_client->retransmit) { dhcp_client->xid = packet->transaction_id[0] << 16 | packet->transaction_id[1] << 8 | packet->transaction_id[2]; @@ -932,6 +1103,11 @@ static int send_dhcpv6_rebind(GDHCPClient *dhcp_client) return send_dhcpv6_msg(dhcp_client, DHCPV6_REBIND, "rebind"); } +static int send_dhcpv6_decline(GDHCPClient *dhcp_client) +{ + return send_dhcpv6_msg(dhcp_client, DHCPV6_DECLINE, "decline"); +} + static int send_dhcpv6_release(GDHCPClient *dhcp_client) { return send_dhcpv6_msg(dhcp_client, DHCPV6_RELEASE, "release"); @@ -967,18 +1143,18 @@ GDHCPClient *g_dhcp_client_new(GDHCPType type, } dhcp_client = g_try_new0(GDHCPClient, 1); - if (dhcp_client == NULL) { + if (!dhcp_client) { *error = G_DHCP_CLIENT_ERROR_NOMEM; return NULL; } dhcp_client->interface = get_interface_name(ifindex); - if (dhcp_client->interface == NULL) { + if (!dhcp_client->interface) { *error = G_DHCP_CLIENT_ERROR_INTERFACE_UNAVAILABLE; goto error; } - if (interface_is_up(ifindex) == FALSE) { + if (!interface_is_up(ifindex)) { *error = G_DHCP_CLIENT_ERROR_INTERFACE_DOWN; goto error; } @@ -986,7 +1162,6 @@ GDHCPClient *g_dhcp_client_new(GDHCPType type, get_interface_mac_address(ifindex, dhcp_client->mac_address); dhcp_client->listener_sockfd = -1; - dhcp_client->listener_channel = NULL; dhcp_client->listen_mode = L_NONE; dhcp_client->ref_count = 1; dhcp_client->type = type; @@ -1008,7 +1183,7 @@ GDHCPClient *g_dhcp_client_new(GDHCPType type, dhcp_client->require_list = NULL; dhcp_client->duid = NULL; dhcp_client->duid_len = 0; - dhcp_client->last_renew = dhcp_client->last_rebind = time(NULL); + dhcp_client->last_request = time(NULL); dhcp_client->expire = 0; *error = G_DHCP_CLIENT_ERROR_NONE; @@ -1076,7 +1251,7 @@ static int dhcp_l2_socket(int ifindex) fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IP)); if (fd < 0) - return fd; + return -errno; if (SERVER_PORT == 67 && CLIENT_PORT == 68) /* Use only if standard ports are in use */ @@ -1089,31 +1264,32 @@ static int dhcp_l2_socket(int ifindex) sock.sll_ifindex = ifindex; if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) != 0) { + int err = -errno; close(fd); - return -errno; + return err; } return fd; } -static gboolean sanity_check(struct ip_udp_dhcp_packet *packet, int bytes) +static bool sanity_check(struct ip_udp_dhcp_packet *packet, int bytes) { if (packet->ip.protocol != IPPROTO_UDP) - return FALSE; + return false; if (packet->ip.version != IPVERSION) - return FALSE; + return false; if (packet->ip.ihl != sizeof(packet->ip) >> 2) - return FALSE; + return false; if (packet->udp.dest != htons(CLIENT_PORT)) - return FALSE; + return false; if (ntohs(packet->udp.len) != (uint16_t)(bytes - sizeof(packet->ip))) - return FALSE; + return false; - return TRUE; + return true; } static int dhcp_recv_l2_packet(struct dhcp_packet *dhcp_pkt, int fd) @@ -1138,7 +1314,7 @@ static int dhcp_recv_l2_packet(struct dhcp_packet *dhcp_pkt, int fd) /* ignore any extra garbage bytes */ bytes = ntohs(packet.ip.tot_len); - if (sanity_check(&packet, bytes) == FALSE) + if (!sanity_check(&packet, bytes)) return -1; check = packet.ip.check; @@ -1169,13 +1345,9 @@ static void ipv4ll_start(GDHCPClient *dhcp_client) guint timeout; int seed; - if (dhcp_client->timeout > 0) { - g_source_remove(dhcp_client->timeout); - dhcp_client->timeout = 0; - } + remove_timeouts(dhcp_client); switch_listening_mode(dhcp_client, L_NONE); - dhcp_client->type = G_DHCP_IPV4LL; dhcp_client->retry_times = 0; dhcp_client->requested_ip = 0; @@ -1199,8 +1371,7 @@ static void ipv4ll_stop(GDHCPClient *dhcp_client) switch_listening_mode(dhcp_client, L_NONE); - if (dhcp_client->timeout > 0) - g_source_remove(dhcp_client->timeout); + remove_timeouts(dhcp_client); if (dhcp_client->listener_watch > 0) { g_source_remove(dhcp_client->listener_watch); @@ -1260,7 +1431,7 @@ static int ipv4ll_recv_arp_packet(GDHCPClient *dhcp_client) if (dhcp_client->state == IPV4LL_DEFEND) { if (!source_conflict) return 0; - else if (dhcp_client->ipv4ll_lost_cb != NULL) + else if (dhcp_client->ipv4ll_lost_cb) dhcp_client->ipv4ll_lost_cb(dhcp_client, dhcp_client->ipv4ll_lost_data); } @@ -1281,42 +1452,42 @@ static int ipv4ll_recv_arp_packet(GDHCPClient *dhcp_client) * to wait RATE_LIMIT_INTERVAL before retrying, * but we just report failure. */ - else if (dhcp_client->no_lease_cb != NULL) + else if (dhcp_client->no_lease_cb) dhcp_client->no_lease_cb(dhcp_client, dhcp_client->no_lease_data); return 0; } -static gboolean check_package_owner(GDHCPClient *dhcp_client, gpointer pkt) +static bool check_package_owner(GDHCPClient *dhcp_client, gpointer pkt) { if (dhcp_client->type == G_DHCP_IPV6) { struct dhcpv6_packet *packet6 = pkt; uint32_t xid; - if (packet6 == NULL) - return FALSE; + if (!packet6) + return false; xid = packet6->transaction_id[0] << 16 | packet6->transaction_id[1] << 8 | packet6->transaction_id[2]; if (xid != dhcp_client->xid) - return FALSE; + return false; } else { struct dhcp_packet *packet = pkt; if (packet->xid != dhcp_client->xid) - return FALSE; + return false; if (packet->hlen != 6) - return FALSE; + return false; if (memcmp(packet->chaddr, dhcp_client->mac_address, 6)) - return FALSE; + return false; } - return TRUE; + return true; } static void start_request(GDHCPClient *dhcp_client); @@ -1353,7 +1524,6 @@ static int switch_listening_mode(GDHCPClient *dhcp_client, if (dhcp_client->listen_mode != L_NONE) { if (dhcp_client->listener_watch > 0) g_source_remove(dhcp_client->listener_watch); - dhcp_client->listener_channel = NULL; dhcp_client->listen_mode = L_NONE; dhcp_client->listener_sockfd = -1; dhcp_client->listener_watch = 0; @@ -1382,7 +1552,7 @@ static int switch_listening_mode(GDHCPClient *dhcp_client, return -EIO; listener_channel = g_io_channel_unix_new(listener_sockfd); - if (listener_channel == NULL) { + if (!listener_channel) { /* Failed to create listener channel */ close(listener_sockfd); return -EIO; @@ -1390,7 +1560,6 @@ static int switch_listening_mode(GDHCPClient *dhcp_client, dhcp_client->listen_mode = listen_mode; dhcp_client->listener_sockfd = listener_sockfd; - dhcp_client->listener_channel = listener_channel; g_io_channel_set_close_on_unref(listener_channel, TRUE); dhcp_client->listener_watch = @@ -1398,7 +1567,7 @@ static int switch_listening_mode(GDHCPClient *dhcp_client, G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP, listener_event, dhcp_client, NULL); - g_io_channel_unref(dhcp_client->listener_channel); + g_io_channel_unref(listener_channel); return 0; } @@ -1409,9 +1578,9 @@ static void start_request(GDHCPClient *dhcp_client) dhcp_client->retry_times); if (dhcp_client->retry_times == REQUEST_RETRIES) { - dhcp_client->state = INIT_SELECTING; - ipv4ll_start(dhcp_client); - + if (dhcp_client->no_lease_cb) + dhcp_client->no_lease_cb(dhcp_client, + dhcp_client->no_lease_data); return; } @@ -1420,7 +1589,7 @@ static void start_request(GDHCPClient *dhcp_client) switch_listening_mode(dhcp_client, L2); } - send_select(dhcp_client); + send_request(dhcp_client); dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH, REQUEST_TIMEOUT, @@ -1435,7 +1604,7 @@ static uint32_t get_lease(struct dhcp_packet *packet) uint32_t lease_seconds; option = dhcp_get_option(packet, DHCP_LEASE_TIME); - if (option == NULL) + if (!option) return 3600; lease_seconds = get_be32(option); @@ -1451,10 +1620,7 @@ static void restart_dhcp(GDHCPClient *dhcp_client, int retry_times) { debug(dhcp_client, "restart DHCP (retries %d)", retry_times); - if (dhcp_client->timeout > 0) { - g_source_remove(dhcp_client->timeout); - dhcp_client->timeout = 0; - } + remove_timeouts(dhcp_client); dhcp_client->retry_times = retry_times; dhcp_client->requested_ip = 0; @@ -1464,78 +1630,103 @@ static void restart_dhcp(GDHCPClient *dhcp_client, int retry_times) g_dhcp_client_start(dhcp_client, dhcp_client->last_address); } -static gboolean start_rebound_timeout(gpointer user_data) +static gboolean start_expire(gpointer user_data) { GDHCPClient *dhcp_client = user_data; - debug(dhcp_client, "start rebound timeout"); + debug(dhcp_client, "lease expired"); - switch_listening_mode(dhcp_client, L2); + /*remove all timeouts if they are set*/ + remove_timeouts(dhcp_client); - dhcp_client->lease_seconds >>= 1; + restart_dhcp(dhcp_client, 0); - /* We need to have enough time to receive ACK package*/ - if (dhcp_client->lease_seconds <= 6) { + /* ip need to be cleared */ + if (dhcp_client->lease_lost_cb) + dhcp_client->lease_lost_cb(dhcp_client, + dhcp_client->lease_lost_data); - /* ip need to be cleared */ - if (dhcp_client->lease_lost_cb != NULL) - dhcp_client->lease_lost_cb(dhcp_client, - dhcp_client->lease_lost_data); + return false; +} - restart_dhcp(dhcp_client, 0); - } else { - send_rebound(dhcp_client); +static gboolean continue_rebound(gpointer user_data) +{ + GDHCPClient *dhcp_client = user_data; - dhcp_client->timeout = - g_timeout_add_seconds_full(G_PRIORITY_HIGH, - dhcp_client->lease_seconds >> 1, - start_rebound_timeout, - dhcp_client, - NULL); + switch_listening_mode(dhcp_client, L2); + send_request(dhcp_client); + + if (dhcp_client->t2_timeout> 0) + g_source_remove(dhcp_client->t2_timeout); + + /*recalculate remaining rebind time*/ + dhcp_client->T2 >>= 1; + if (dhcp_client->T2 > 60) { + dhcp_client->t2_timeout = + g_timeout_add_full(G_PRIORITY_HIGH, + dhcp_client->T2 * 1000 + (rand() % 2000) - 1000, + continue_rebound, + dhcp_client, + NULL); } return FALSE; } -static void start_rebound(GDHCPClient *dhcp_client) +static gboolean start_rebound(gpointer user_data) { - debug(dhcp_client, "start rebound"); + GDHCPClient *dhcp_client = user_data; + /*remove renew timer*/ + if (dhcp_client->t1_timeout > 0) + g_source_remove(dhcp_client->t1_timeout); + + debug(dhcp_client, "start rebound"); dhcp_client->state = REBINDING; - dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH, - dhcp_client->lease_seconds >> 1, - start_rebound_timeout, - dhcp_client, - NULL); + /*calculate total rebind time*/ + dhcp_client->T2 = dhcp_client->expire - dhcp_client->T2; + + /*send the first rebound and reschedule*/ + continue_rebound(user_data); + + return FALSE; } -static gboolean start_renew_timeout(gpointer user_data) +static gboolean continue_renew (gpointer user_data) { GDHCPClient *dhcp_client = user_data; - debug(dhcp_client, "start renew timeout"); + switch_listening_mode(dhcp_client, L3); + send_request(dhcp_client); - dhcp_client->state = RENEWING; + if (dhcp_client->t1_timeout > 0) + g_source_remove(dhcp_client->t1_timeout); - dhcp_client->lease_seconds >>= 1; + dhcp_client->T1 >>= 1; - switch_listening_mode(dhcp_client, L3); - if (dhcp_client->lease_seconds <= 60) - start_rebound(dhcp_client); - else { - send_renew(dhcp_client); + if (dhcp_client->T1 > 60) { + dhcp_client->t1_timeout = g_timeout_add_full(G_PRIORITY_HIGH, + dhcp_client->T1 * 1000 + (rand() % 2000) - 1000, + continue_renew, + dhcp_client, + NULL); + } - if (dhcp_client->timeout > 0) - g_source_remove(dhcp_client->timeout); + return FALSE; +} +static gboolean start_renew(gpointer user_data) +{ + GDHCPClient *dhcp_client = user_data; - dhcp_client->timeout = - g_timeout_add_seconds_full(G_PRIORITY_HIGH, - dhcp_client->lease_seconds >> 1, - start_renew_timeout, - dhcp_client, - NULL); - } + debug(dhcp_client, "start renew"); + dhcp_client->state = RENEWING; + + /*calculate total renew period*/ + dhcp_client->T1 = dhcp_client->T2 - dhcp_client->T1; + + /*send first renew and reschedule for half the remaining time.*/ + continue_renew(user_data); return FALSE; } @@ -1546,12 +1737,30 @@ static void start_bound(GDHCPClient *dhcp_client) dhcp_client->state = BOUND; - if (dhcp_client->timeout > 0) - g_source_remove(dhcp_client->timeout); + remove_timeouts(dhcp_client); - dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH, - dhcp_client->lease_seconds >> 1, - start_renew_timeout, dhcp_client, + /* + *TODO: T1 and T2 should be set through options instead of + * defaults as they are here. + */ + + dhcp_client->T1 = dhcp_client->lease_seconds >> 1; + dhcp_client->T2 = dhcp_client->lease_seconds * 0.875; + dhcp_client->expire = dhcp_client->lease_seconds; + + dhcp_client->t1_timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH, + dhcp_client->T1, + start_renew, dhcp_client, + NULL); + + dhcp_client->t2_timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH, + dhcp_client->T2, + start_rebound, dhcp_client, + NULL); + + dhcp_client->lease_timeout= g_timeout_add_seconds_full(G_PRIORITY_HIGH, + dhcp_client->expire, + start_expire, dhcp_client, NULL); } @@ -1561,10 +1770,14 @@ static gboolean restart_dhcp_timeout(gpointer user_data) debug(dhcp_client, "restart DHCP timeout"); - dhcp_client->ack_retry_times++; - - restart_dhcp(dhcp_client, dhcp_client->ack_retry_times); - + if (dhcp_client->state == REBOOTING) { + g_free(dhcp_client->last_address); + dhcp_client->last_address = NULL; + restart_dhcp(dhcp_client, 0); + } else { + dhcp_client->ack_retry_times++; + restart_dhcp(dhcp_client, dhcp_client->ack_retry_times); + } return FALSE; } @@ -1606,7 +1819,7 @@ static char *malloc_option_value_string(uint8_t *option, GDHCPOptionType type) upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); dest = ret = g_malloc(upper_length + 1); - if (ret == NULL) + if (!ret) return NULL; while (len >= optlen) { @@ -1647,13 +1860,13 @@ static GList *get_option_value_list(char *value, GDHCPOptionType type) char *pos = value; GList *list = NULL; - if (pos == NULL) + if (!pos) return NULL; if (type == OPTION_STRING) return g_list_append(list, g_strdup(value)); - while ((pos = strchr(pos, ' ')) != NULL) { + while ((pos = strchr(pos, ' '))) { *pos = '\0'; list = g_list_append(list, g_strdup(value)); @@ -1677,6 +1890,33 @@ static inline uint16_t get_uint16(unsigned char *value) return value[0] << 8 | value[1]; } +static GList *add_prefix(GDHCPClient *dhcp_client, GList *list, + struct in6_addr *addr, + unsigned char prefixlen, uint32_t preferred, + uint32_t valid) +{ + GDHCPIAPrefix *ia_prefix; + + ia_prefix = g_try_new(GDHCPIAPrefix, 1); + if (!ia_prefix) + return list; + + if (dhcp_client->debug_func) { + char addr_str[INET6_ADDRSTRLEN + 1]; + inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN); + debug(dhcp_client, "prefix %s/%d preferred %u valid %u", + addr_str, prefixlen, preferred, valid); + } + + memcpy(&ia_prefix->prefix, addr, sizeof(struct in6_addr)); + ia_prefix->prefixlen = prefixlen; + ia_prefix->preferred = preferred; + ia_prefix->valid = valid; + ia_prefix->expire = time(NULL) + valid; + + return g_list_prepend(list, ia_prefix); +} + static GList *get_addresses(GDHCPClient *dhcp_client, int code, int len, unsigned char *value, @@ -1686,23 +1926,26 @@ static GList *get_addresses(GDHCPClient *dhcp_client, struct in6_addr addr; uint32_t iaid, T1 = 0, T2 = 0, preferred = 0, valid = 0; uint16_t option_len, option_code, st = 0, max_len; - int addr_count = 0, i, pos; + int addr_count = 0, prefix_count = 0, i, pos; + unsigned char prefixlen; + unsigned int shortest_valid = 0; uint8_t *option; char *str; - if (value == NULL || len < 4) + if (!value || len < 4) return NULL; iaid = get_uint32(&value[0]); if (dhcp_client->iaid != iaid) return NULL; - if (code == G_DHCPV6_IA_NA) { + if (code == G_DHCPV6_IA_NA || code == G_DHCPV6_IA_PD) { T1 = get_uint32(&value[4]); T2 = get_uint32(&value[8]); if (T1 > T2) - /* RFC 3315, 22.4 */ + /* IA_NA: RFC 3315, 22.4 */ + /* IA_PD: RFC 3633, ch 9 */ return NULL; pos = 12; @@ -1714,6 +1957,8 @@ static GList *get_addresses(GDHCPClient *dhcp_client, max_len = len - pos; + debug(dhcp_client, "header %d sub-option max len %d", pos, max_len); + /* We have more sub-options in this packet. */ do { option = dhcpv6_get_sub_option(&value[pos], max_len, @@ -1722,10 +1967,10 @@ static GList *get_addresses(GDHCPClient *dhcp_client, debug(dhcp_client, "pos %d option %p code %d len %d", pos, option, option_code, option_len); - if (option == NULL) + if (!option) break; - if (pos >= max_len) + if (pos >= len) break; switch (option_code) { @@ -1752,11 +1997,31 @@ static GList *get_addresses(GDHCPClient *dhcp_client, *status = st; break; + + case G_DHCPV6_IA_PREFIX: + i = 0; + preferred = get_uint32(&option[i]); + i += 4; + valid = get_uint32(&option[i]); + i += 4; + prefixlen = option[i]; + i += 1; + memcpy(&addr, &option[i], sizeof(addr)); + i += sizeof(addr); + if (preferred < valid) { + /* RFC 3633, ch 10 */ + list = add_prefix(dhcp_client, list, &addr, + prefixlen, preferred, valid); + if (shortest_valid > valid) + shortest_valid = valid; + prefix_count++; + } + break; } pos += 2 + 2 + option_len; - } while (option != NULL); + } while (pos < len); if (addr_count > 0 && st == 0) { /* We only support one address atm */ @@ -1770,7 +2035,7 @@ static GList *get_addresses(GDHCPClient *dhcp_client, dhcp_client->T2 = T2; inet_ntop(AF_INET6, &addr, addr_str, INET6_ADDRSTRLEN); - debug(dhcp_client, "count %d addr %s T1 %u T2 %u", + debug(dhcp_client, "address count %d addr %s T1 %u T2 %u", addr_count, addr_str, T1, T2); list = g_list_append(list, g_strdup(addr_str)); @@ -1782,12 +2047,59 @@ static GList *get_addresses(GDHCPClient *dhcp_client, memcpy(&dhcp_client->ia_ta, &addr, sizeof(struct in6_addr)); - g_dhcpv6_client_set_expire(dhcp_client, valid); + if (valid > dhcp_client->expire) + dhcp_client->expire = valid; } + if (prefix_count > 0 && list) { + /* + * This means we have a list of prefixes to delegate. + */ + list = g_list_reverse(list); + + debug(dhcp_client, "prefix count %d T1 %u T2 %u", + prefix_count, T1, T2); + + dhcp_client->T1 = T1; + dhcp_client->T2 = T2; + + dhcp_client->expire = shortest_valid; + } + + if (status && *status != 0) + debug(dhcp_client, "status %d", *status); + return list; } +static GList *get_domains(int maxlen, unsigned char *value) + +{ + GList *list = NULL; + int pos = 0; + unsigned char *c; + char dns_name[NS_MAXDNAME + 1]; + + if (!value || maxlen < 3) + return NULL; + + while (pos < maxlen) { + strncpy(dns_name, (char *)&value[pos], NS_MAXDNAME); + + c = (unsigned char *)dns_name; + while (c && *c) { + int jump; + jump = *c; + *c = '.'; + c += jump + 1; + } + list = g_list_prepend(list, g_strdup(&dns_name[1])); + pos += (char *)c - dns_name + 1; + } + + return g_list_reverse(list); +} + static GList *get_dhcpv6_option_value_list(GDHCPClient *dhcp_client, int code, int len, unsigned char *value, @@ -1797,7 +2109,7 @@ static GList *get_dhcpv6_option_value_list(GDHCPClient *dhcp_client, char *str; int i; - if (value == NULL) + if (!value) return NULL; switch (code) { @@ -1813,11 +2125,11 @@ static GList *get_dhcpv6_option_value_list(GDHCPClient *dhcp_client, for (i = 0; i < len; i += 16) { str = g_try_malloc0(INET6_ADDRSTRLEN+1); - if (str == NULL) + if (!str) return list; - if (inet_ntop(AF_INET6, &value[i], str, - INET6_ADDRSTRLEN) == NULL) + if (!inet_ntop(AF_INET6, &value[i], str, + INET6_ADDRSTRLEN)) g_free(str); else list = g_list_append(list, str); @@ -1826,9 +2138,14 @@ static GList *get_dhcpv6_option_value_list(GDHCPClient *dhcp_client, case G_DHCPV6_IA_NA: /* RFC 3315, chapter 22.4 */ case G_DHCPV6_IA_TA: /* RFC 3315, chapter 22.5 */ + case G_DHCPV6_IA_PD: /* RFC 3633, chapter 9 */ list = get_addresses(dhcp_client, code, len, value, status); break; + case G_DHCPV6_DOMAIN_LIST: + list = get_domains(len, value); + break; + default: break; } @@ -1850,7 +2167,7 @@ static void get_dhcpv6_request(GDHCPClient *dhcp_client, option = dhcpv6_get_option(packet, pkt_len, code, &option_len, NULL); - if (option == NULL) { + if (!option) { g_hash_table_remove(dhcp_client->code_value_hash, GINT_TO_POINTER((int) code)); continue; @@ -1862,7 +2179,7 @@ static void get_dhcpv6_request(GDHCPClient *dhcp_client, debug(dhcp_client, "code %d %p len %d list %p", code, option, option_len, value_list); - if (value_list == NULL) + if (!value_list) g_hash_table_remove(dhcp_client->code_value_hash, GINT_TO_POINTER((int) code)); else @@ -1883,7 +2200,7 @@ static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet) code = (uint8_t) GPOINTER_TO_INT(list->data); option = dhcp_get_option(packet, code); - if (option == NULL) { + if (!option) { g_hash_table_remove(dhcp_client->code_value_hash, GINT_TO_POINTER((int) code)); continue; @@ -1892,7 +2209,7 @@ static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet) type = dhcp_get_code_type(code); option_value = malloc_option_value_string(option, type); - if (option_value == NULL) + if (!option_value) g_hash_table_remove(dhcp_client->code_value_hash, GINT_TO_POINTER((int) code)); @@ -1900,7 +2217,7 @@ static void get_request(GDHCPClient *dhcp_client, struct dhcp_packet *packet) g_free(option_value); - if (value_list == NULL) + if (!value_list) g_hash_table_remove(dhcp_client->code_value_hash, GINT_TO_POINTER((int) code)); else @@ -1937,10 +2254,10 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, dhcp_client->status_code = 0; - if (dhcp_client->listen_mode == L2) + if (dhcp_client->listen_mode == L2) { re = dhcp_recv_l2_packet(&packet, dhcp_client->listener_sockfd); - else if (dhcp_client->listen_mode == L3) { + } else if (dhcp_client->listen_mode == L3) { if (dhcp_client->type == G_DHCP_IPV6) { re = dhcpv6_recv_l3_packet(&packet6, buf, sizeof(buf), dhcp_client->listener_sockfd); @@ -1957,25 +2274,24 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, } else if (dhcp_client->listen_mode == L_ARP) { ipv4ll_recv_arp_packet(dhcp_client); return TRUE; - } - else + } else re = -EIO; if (re < 0) return TRUE; - if (check_package_owner(dhcp_client, pkt) == FALSE) + if (!check_package_owner(dhcp_client, pkt)) return TRUE; if (dhcp_client->type == G_DHCP_IPV6) { - if (packet6 == NULL) + if (!packet6) return TRUE; count = 0; client_id = dhcpv6_get_option(packet6, pkt_len, G_DHCPV6_CLIENTID, &option_len, &count); - if (client_id == NULL || count == 0 || option_len == 0 || + if (!client_id || count == 0 || option_len == 0 || memcmp(dhcp_client->duid, client_id, dhcp_client->duid_len) != 0) { debug(dhcp_client, @@ -2003,11 +2319,11 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, } } else { message_type = dhcp_get_option(&packet, DHCP_MESSAGE_TYPE); - if (message_type == NULL) + if (!message_type) return TRUE; } - if (message_type == NULL && client_id == NULL) + if (!message_type && !client_id) /* No message type / client id option, ignore package */ return TRUE; @@ -2019,7 +2335,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, if (*message_type != DHCPOFFER) return TRUE; - g_source_remove(dhcp_client->timeout); + remove_timeouts(dhcp_client); dhcp_client->timeout = 0; dhcp_client->retry_times = 0; @@ -2032,15 +2348,14 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, start_request(dhcp_client); return TRUE; + case REBOOTING: case REQUESTING: case RENEWING: case REBINDING: if (*message_type == DHCPACK) { dhcp_client->retry_times = 0; - if (dhcp_client->timeout > 0) - g_source_remove(dhcp_client->timeout); - dhcp_client->timeout = 0; + remove_timeouts(dhcp_client); dhcp_client->lease_seconds = get_lease(&packet); @@ -2052,7 +2367,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, dhcp_client->assigned_ip = get_ip(packet.yiaddr); /* Address should be set up here */ - if (dhcp_client->lease_available_cb != NULL) + if (dhcp_client->lease_available_cb) dhcp_client->lease_available_cb(dhcp_client, dhcp_client->lease_available_data); @@ -2060,8 +2375,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, } else if (*message_type == DHCPNAK) { dhcp_client->retry_times = 0; - if (dhcp_client->timeout > 0) - g_source_remove(dhcp_client->timeout); + remove_timeouts(dhcp_client); dhcp_client->timeout = g_timeout_add_seconds_full( G_PRIORITY_HIGH, 3, @@ -2082,7 +2396,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, 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) { + if (!server_id || count != 1 || option_len == 0) { /* RFC 3315, 15.10 */ debug(dhcp_client, "server duid error, discarding msg %p/%d/%d", @@ -2090,7 +2404,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, return TRUE; } dhcp_client->server_duid = g_try_malloc(option_len); - if (dhcp_client->server_duid == NULL) + if (!dhcp_client->server_duid) return TRUE; memcpy(dhcp_client->server_duid, server_id, option_len); dhcp_client->server_duid_len = option_len; @@ -2102,7 +2416,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, rapid_commit = dhcpv6_get_option(packet6, pkt_len, G_DHCPV6_RAPID_COMMIT, &option_len, &count); - if (rapid_commit == NULL || option_len == 0 || + if (!rapid_commit || option_len == 0 || count != 1) /* RFC 3315, 17.1.4 */ return TRUE; @@ -2115,13 +2429,13 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, &dhcp_client->status_code); if (packet6->message == DHCPV6_ADVERTISE) { - if (dhcp_client->advertise_cb != NULL) + if (dhcp_client->advertise_cb) dhcp_client->advertise_cb(dhcp_client, dhcp_client->advertise_data); return TRUE; } - if (dhcp_client->solicitation_cb != NULL) { + if (dhcp_client->solicitation_cb) { /* * The dhcp_client might not be valid after the * callback call so just return immediately. @@ -2131,12 +2445,31 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, return TRUE; } break; + case REBIND: + if (dhcp_client->type != G_DHCP_IPV6) + return TRUE; + + server_id = dhcpv6_get_option(packet6, pkt_len, + G_DHCPV6_SERVERID, &option_len, &count); + if (!dhcp_client->server_duid && server_id && + count == 1) { + /* + * If we do not have server duid yet, then get it now. + * Prefix delegation renew support needs it. + */ + dhcp_client->server_duid = g_try_malloc(option_len); + if (!dhcp_client->server_duid) + return TRUE; + memcpy(dhcp_client->server_duid, server_id, option_len); + dhcp_client->server_duid_len = option_len; + } + /* fall through */ case INFORMATION_REQ: case REQUEST: case RENEW: - case REBIND: case RELEASE: case CONFIRM: + case DECLINE: if (dhcp_client->type != G_DHCP_IPV6) return TRUE; @@ -2147,7 +2480,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, option_len = 0; server_id = dhcpv6_get_option(packet6, pkt_len, G_DHCPV6_SERVERID, &option_len, &count); - if (server_id == NULL || count != 1 || option_len == 0 || + if (!server_id || count != 1 || option_len == 0 || (dhcp_client->server_duid_len > 0 && memcmp(dhcp_client->server_duid, server_id, dhcp_client->server_duid_len) != 0)) { @@ -2163,7 +2496,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, get_dhcpv6_request(dhcp_client, packet6, pkt_len, &dhcp_client->status_code); - if (dhcp_client->information_req_cb != NULL) { + if (dhcp_client->information_req_cb) { /* * The dhcp_client might not be valid after the * callback call so just return immediately. @@ -2172,32 +2505,37 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, dhcp_client->information_req_data); return TRUE; } - if (dhcp_client->request_cb != NULL) { + if (dhcp_client->request_cb) { dhcp_client->request_cb(dhcp_client, dhcp_client->request_data); return TRUE; } - if (dhcp_client->renew_cb != NULL) { + if (dhcp_client->renew_cb) { dhcp_client->renew_cb(dhcp_client, dhcp_client->renew_data); return TRUE; } - if (dhcp_client->rebind_cb != NULL) { + if (dhcp_client->rebind_cb) { dhcp_client->rebind_cb(dhcp_client, dhcp_client->rebind_data); return TRUE; } - if (dhcp_client->release_cb != NULL) { + if (dhcp_client->release_cb) { dhcp_client->release_cb(dhcp_client, dhcp_client->release_data); return TRUE; } - if (dhcp_client->confirm_cb != NULL) { + if (dhcp_client->decline_cb) { + dhcp_client->decline_cb(dhcp_client, + dhcp_client->decline_data); + return TRUE; + } + if (dhcp_client->confirm_cb) { count = 0; server_id = dhcpv6_get_option(packet6, pkt_len, G_DHCPV6_SERVERID, &option_len, &count); - if (server_id == NULL || count != 1 || + if (!server_id || count != 1 || option_len == 0) { /* RFC 3315, 15.10 */ debug(dhcp_client, @@ -2207,7 +2545,7 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, return TRUE; } dhcp_client->server_duid = g_try_malloc(option_len); - if (dhcp_client->server_duid == NULL) + if (!dhcp_client->server_duid) return TRUE; memcpy(dhcp_client->server_duid, server_id, option_len); dhcp_client->server_duid_len = option_len; @@ -2243,6 +2581,22 @@ static gboolean discover_timeout(gpointer user_data) return FALSE; } +static gboolean reboot_timeout(gpointer user_data) +{ + GDHCPClient *dhcp_client = user_data; + dhcp_client->retry_times = 0; + dhcp_client->requested_ip = 0; + dhcp_client->state = INIT_SELECTING; + /* + * We do not send the REQUESTED IP option because the server didn't + * respond when we send DHCPREQUEST with the REQUESTED IP option in + * init-reboot state + */ + g_dhcp_client_start(dhcp_client, NULL); + + return FALSE; +} + static gboolean ipv4ll_defend_timeout(gpointer dhcp_data) { GDHCPClient *dhcp_client = dhcp_data; @@ -2263,7 +2617,7 @@ static gboolean ipv4ll_announce_timeout(gpointer dhcp_data) debug(dhcp_client, "request timeout (retries %d)", dhcp_client->retry_times); - if (dhcp_client->retry_times != ANNOUNCE_NUM){ + if (dhcp_client->retry_times != ANNOUNCE_NUM) { dhcp_client->retry_times++; send_announce_packet(dhcp_client); return FALSE; @@ -2274,7 +2628,7 @@ static gboolean ipv4ll_announce_timeout(gpointer dhcp_data) dhcp_client->state = IPV4LL_MONITOR; dhcp_client->assigned_ip = get_ip(ip); - if (dhcp_client->ipv4ll_available_cb != NULL) + if (dhcp_client->ipv4ll_available_cb) dhcp_client->ipv4ll_available_cb(dhcp_client, dhcp_client->ipv4ll_available_data); dhcp_client->conflicts = 0; @@ -2379,16 +2733,34 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) return re; } send_dhcpv6_release(dhcp_client); + } else if (dhcp_client->decline_cb) { + dhcp_client->state = DECLINE; + 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_decline(dhcp_client); } return 0; } - if (dhcp_client->retry_times == DISCOVER_RETRIES) { + if (dhcp_client->type == G_DHCP_IPV4LL) { + dhcp_client->state = INIT_SELECTING; ipv4ll_start(dhcp_client); return 0; } + if (dhcp_client->retry_times == DISCOVER_RETRIES) { + if (dhcp_client->no_lease_cb) + dhcp_client->no_lease_cb(dhcp_client, + dhcp_client->no_lease_data); + dhcp_client->retry_times = 0; + return 0; + } + if (dhcp_client->retry_times == 0) { g_free(dhcp_client->assigned_ip); dhcp_client->assigned_ip = NULL; @@ -2402,10 +2774,10 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) dhcp_client->start = time(NULL); } - if (last_address == NULL) { + if (!last_address) { addr = 0; } else { - addr = inet_addr(last_address); + addr = ntohl(inet_addr(last_address)); if (addr == 0xFFFFFFFF) { addr = 0; } else { @@ -2413,6 +2785,21 @@ int g_dhcp_client_start(GDHCPClient *dhcp_client, const char *last_address) dhcp_client->last_address = g_strdup(last_address); } } + + if ((addr != 0) && (dhcp_client->type != G_DHCP_IPV4LL)) { + debug(dhcp_client, "DHCP client start with state init_reboot"); + dhcp_client->requested_ip = addr; + dhcp_client->state = REBOOTING; + send_request(dhcp_client); + + dhcp_client->timeout = g_timeout_add_seconds_full( + G_PRIORITY_HIGH, + REQUEST_TIMEOUT, + reboot_timeout, + dhcp_client, + NULL); + return 0; + } send_discover(dhcp_client, addr); dhcp_client->timeout = g_timeout_add_seconds_full(G_PRIORITY_HIGH, @@ -2433,18 +2820,13 @@ void g_dhcp_client_stop(GDHCPClient *dhcp_client) send_release(dhcp_client, dhcp_client->server_ip, dhcp_client->requested_ip); - if (dhcp_client->timeout > 0) { - g_source_remove(dhcp_client->timeout); - dhcp_client->timeout = 0; - } + remove_timeouts(dhcp_client); if (dhcp_client->listener_watch > 0) { g_source_remove(dhcp_client->listener_watch); dhcp_client->listener_watch = 0; } - dhcp_client->listener_channel = NULL; - dhcp_client->retry_times = 0; dhcp_client->ack_retry_times = 0; @@ -2542,6 +2924,12 @@ void g_dhcp_client_register_event(GDHCPClient *dhcp_client, dhcp_client->confirm_cb = func; dhcp_client->confirm_data = data; return; + case G_DHCP_CLIENT_EVENT_DECLINE: + if (dhcp_client->type != G_DHCP_IPV6) + return; + dhcp_client->decline_cb = func; + dhcp_client->decline_data = data; + return; } } @@ -2570,9 +2958,10 @@ char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client) case RENEWING: case REBINDING: option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET); - if (option != NULL) + if (option) return g_strdup(option->data); case INIT_SELECTING: + case REBOOTING: case REQUESTING: case RELEASED: case IPV4LL_PROBE: @@ -2584,6 +2973,7 @@ char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client) case RENEW: case REBIND: case RELEASE: + case DECLINE: break; } return NULL; @@ -2592,8 +2982,8 @@ char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client) GDHCPClientError g_dhcp_client_set_request(GDHCPClient *dhcp_client, unsigned int option_code) { - if (g_list_find(dhcp_client->request_list, - GINT_TO_POINTER((int) option_code)) == NULL) + if (!g_list_find(dhcp_client->request_list, + GINT_TO_POINTER((int)option_code))) dhcp_client->request_list = g_list_prepend( dhcp_client->request_list, (GINT_TO_POINTER((int) option_code))); @@ -2617,7 +3007,7 @@ static uint8_t *alloc_dhcp_option(int code, const uint8_t *data, unsigned size) uint8_t *storage; storage = g_try_malloc(size + OPT_DATA); - if (storage == NULL) + if (!storage) return NULL; storage[OPT_CODE] = code; @@ -2627,7 +3017,8 @@ static uint8_t *alloc_dhcp_option(int code, const uint8_t *data, unsigned size) return storage; } -static uint8_t *alloc_dhcp_data_option(int code, const uint8_t *data, unsigned size) +static uint8_t *alloc_dhcp_data_option(int code, const uint8_t *data, + unsigned size) { return alloc_dhcp_option(code, data, MIN(size, 255)); } @@ -2650,7 +3041,7 @@ GDHCPClientError g_dhcp_client_set_id(GDHCPClient *dhcp_client) memcpy(&idbuf[1], dhcp_client->mac_address, maclen); data_option = alloc_dhcp_data_option(option_code, idbuf, idlen); - if (data_option == NULL) + if (!data_option) return G_DHCP_CLIENT_ERROR_NOMEM; g_hash_table_insert(dhcp_client->send_value_hash, @@ -2665,10 +3056,10 @@ GDHCPClientError g_dhcp_client_set_send(GDHCPClient *dhcp_client, { uint8_t *binary_option; - if (option_code == G_DHCP_HOST_NAME && option_value != NULL) { + if (option_code == G_DHCP_HOST_NAME && option_value) { binary_option = alloc_dhcp_string_option(option_code, option_value); - if (binary_option == NULL) + if (!binary_option) return G_DHCP_CLIENT_ERROR_NOMEM; g_hash_table_insert(dhcp_client->send_value_hash, @@ -2684,7 +3075,7 @@ static uint8_t *alloc_dhcpv6_option(uint16_t code, uint8_t *option, uint8_t *storage; storage = g_malloc(2 + 2 + len); - if (storage == NULL) + if (!storage) return NULL; storage[0] = code >> 8; @@ -2696,12 +3087,18 @@ static uint8_t *alloc_dhcpv6_option(uint16_t code, uint8_t *option, return storage; } +gboolean g_dhcpv6_client_clear_send(GDHCPClient *dhcp_client, uint16_t code) +{ + return g_hash_table_remove(dhcp_client->send_value_hash, + GINT_TO_POINTER((int)code)); +} + void g_dhcpv6_client_set_send(GDHCPClient *dhcp_client, uint16_t option_code, uint8_t *option_value, uint16_t option_len) { - if (option_value != NULL) { + if (option_value) { uint8_t *binary_option; debug(dhcp_client, "setting option %d to %p len %d", @@ -2709,40 +3106,24 @@ void g_dhcpv6_client_set_send(GDHCPClient *dhcp_client, binary_option = alloc_dhcpv6_option(option_code, option_value, option_len); - if (binary_option != NULL) + if (binary_option) g_hash_table_insert(dhcp_client->send_value_hash, GINT_TO_POINTER((int) option_code), binary_option); } } -void g_dhcpv6_client_reset_renew(GDHCPClient *dhcp_client) +void g_dhcpv6_client_reset_request(GDHCPClient *dhcp_client) { - if (dhcp_client == NULL || dhcp_client->type != G_DHCP_IPV6) + if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6) return; - dhcp_client->last_renew = time(NULL); -} - -void g_dhcpv6_client_reset_rebind(GDHCPClient *dhcp_client) -{ - if (dhcp_client == NULL || dhcp_client->type != G_DHCP_IPV6) - return; - - dhcp_client->last_rebind = time(NULL); -} - -void g_dhcpv6_client_set_expire(GDHCPClient *dhcp_client, uint32_t timeout) -{ - if (dhcp_client == NULL || dhcp_client->type != G_DHCP_IPV6) - return; - - dhcp_client->expire = time(NULL) + timeout; + dhcp_client->last_request = time(NULL); } uint16_t g_dhcpv6_client_get_status(GDHCPClient *dhcp_client) { - if (dhcp_client == NULL || dhcp_client->type != G_DHCP_IPV6) + if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6) return 0; return dhcp_client->status_code; @@ -2750,7 +3131,7 @@ uint16_t g_dhcpv6_client_get_status(GDHCPClient *dhcp_client) GDHCPClient *g_dhcp_client_ref(GDHCPClient *dhcp_client) { - if (dhcp_client == NULL) + if (!dhcp_client) return NULL; __sync_fetch_and_add(&dhcp_client->ref_count, 1); @@ -2760,7 +3141,7 @@ GDHCPClient *g_dhcp_client_ref(GDHCPClient *dhcp_client) void g_dhcp_client_unref(GDHCPClient *dhcp_client) { - if (dhcp_client == NULL) + if (!dhcp_client) return; if (__sync_fetch_and_sub(&dhcp_client->ref_count, 1) != 1) @@ -2786,9 +3167,33 @@ void g_dhcp_client_unref(GDHCPClient *dhcp_client) void g_dhcp_client_set_debug(GDHCPClient *dhcp_client, GDHCPDebugFunc func, gpointer user_data) { - if (dhcp_client == NULL) + if (!dhcp_client) return; dhcp_client->debug_func = func; dhcp_client->debug_data = user_data; } + +static GDHCPIAPrefix *copy_prefix(gpointer data) +{ + GDHCPIAPrefix *copy, *prefix = data; + + copy = g_try_new(GDHCPIAPrefix, 1); + if (!copy) + return NULL; + + memcpy(copy, prefix, sizeof(GDHCPIAPrefix)); + + return copy; +} + +GSList *g_dhcpv6_copy_prefixes(GSList *prefixes) +{ + GSList *copy = NULL; + GSList *list; + + for (list = prefixes; list; list = list->next) + copy = g_slist_prepend(copy, copy_prefix(list->data)); + + return copy; +} diff --git a/gdhcp/common.c b/gdhcp/common.c index 0c433ddc..e1111505 100644 --- a/gdhcp/common.c +++ b/gdhcp/common.c @@ -1,7 +1,7 @@ /* * DHCP library with GLib integration * - * Copyright (C) 2007-2012 Intel Corporation. All rights reserved. + * Copyright (C) 2007-2013 Intel Corporation. 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 @@ -170,12 +170,9 @@ uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len, break; if (opt_code == code) { - if (option_len != NULL) + if (option_len) *option_len = opt_len; - if (rem < 0) - goto bad_packet; - else - found = optionptr + 2 + 2; + found = optionptr + 2 + 2; count++; } @@ -185,15 +182,15 @@ uint8_t *dhcpv6_get_option(struct dhcpv6_packet *packet, uint16_t pkt_len, optionptr += len; } - if (option_count != NULL) + if (option_count) *option_count = count; return found; bad_packet: - if (option_len != NULL) + if (option_len) *option_len = 0; - if (option_count != NULL) + if (option_count) *option_count = 0; return NULL; } @@ -371,34 +368,6 @@ void dhcpv6_init_header(struct dhcpv6_packet *packet, uint8_t type) packet->transaction_id[2] = id & 0xff; } -static gboolean check_vendor(uint8_t *option_vendor, const char *vendor) -{ - uint8_t vendor_length = sizeof(vendor) - 1; - - if (option_vendor[OPT_LEN - OPT_DATA] != vendor_length) - return FALSE; - - if (memcmp(option_vendor, vendor, vendor_length) != 0) - return FALSE; - - return TRUE; -} - -static void check_broken_vendor(struct dhcp_packet *packet) -{ - uint8_t *vendor; - - if (packet->op != BOOTREQUEST) - return; - - vendor = dhcp_get_option(packet, DHCP_VENDOR); - if (vendor == NULL) - return; - - if (check_vendor(vendor, "MSFT 98") == TRUE) - packet->flags |= htons(BROADCAST_FLAG); -} - int dhcp_recv_l3_packet(struct dhcp_packet *packet, int fd) { int n; @@ -412,8 +381,6 @@ int dhcp_recv_l3_packet(struct dhcp_packet *packet, int fd) if (packet->cookie != htonl(DHCP_MAGIC)) return -EPROTO; - check_broken_vendor(packet); - return n; } @@ -496,7 +463,7 @@ int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len) control_buf_len = CMSG_SPACE(sizeof(struct in6_pktinfo)); control_buf = g_try_malloc0(control_buf_len); - if (control_buf == NULL) { + if (!control_buf) { close(fd); return -ENOMEM; } @@ -525,8 +492,17 @@ int dhcpv6_send_packet(int index, struct dhcpv6_packet *dhcp_pkt, int len) m.msg_controllen = cmsg->cmsg_len; ret = sendmsg(fd, &m, 0); - if (ret < 0) - perror("DHCPv6 msg send failed"); + if (ret < 0) { + char *msg = "DHCPv6 msg send failed"; + + if (errno == EADDRNOTAVAIL) { + char *str = g_strdup_printf("%s (index %d)", + msg, index); + perror(str); + g_free(str); + } else + perror(msg); + } g_free(control_buf); close(fd); @@ -553,6 +529,8 @@ int dhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, if (fd < 0) return -errno; + dhcp_pkt->flags |= htons(BROADCAST_FLAG); + memset(&dest, 0, sizeof(dest)); memset(&packet, 0, sizeof(packet)); packet.data = *dhcp_pkt; @@ -718,16 +696,16 @@ char *get_interface_name(int index) return g_strdup(ifr.ifr_name); } -gboolean interface_is_up(int index) +bool interface_is_up(int index) { int sk, err; struct ifreq ifr; - gboolean ret = FALSE; + bool ret = false; sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (sk < 0) { perror("Open socket error"); - return FALSE; + return false; } memset(&ifr, 0, sizeof(ifr)); @@ -746,7 +724,7 @@ gboolean interface_is_up(int index) } if (ifr.ifr_flags & IFF_UP) - ret = TRUE; + ret = true; done: close(sk); diff --git a/gdhcp/common.h b/gdhcp/common.h index 740eb9cd..e4a42519 100644 --- a/gdhcp/common.h +++ b/gdhcp/common.h @@ -208,4 +208,4 @@ int dhcpv6_recv_l3_packet(struct dhcpv6_packet **packet, unsigned char *buf, int dhcp_l3_socket_send(int index, int port, int family); char *get_interface_name(int index); -gboolean interface_is_up(int index); +bool interface_is_up(int index); diff --git a/gdhcp/gdhcp.h b/gdhcp/gdhcp.h index 4f0a16ba..f3e47bf6 100644 --- a/gdhcp/gdhcp.h +++ b/gdhcp/gdhcp.h @@ -2,7 +2,7 @@ * * DHCP library with GLib integration * - * Copyright (C) 2009-2012 Intel Corporation. All rights reserved. + * Copyright (C) 2009-2013 Intel Corporation. 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 @@ -22,7 +22,9 @@ #ifndef __G_DHCP_H #define __G_DHCP_H +#include <stdbool.h> #include <stdint.h> +#include <arpa/inet.h> #include <glib.h> @@ -60,6 +62,7 @@ typedef enum { G_DHCP_CLIENT_EVENT_REBIND, G_DHCP_CLIENT_EVENT_RELEASE, G_DHCP_CLIENT_EVENT_CONFIRM, + G_DHCP_CLIENT_EVENT_DECLINE, } GDHCPClientEvent; typedef enum { @@ -83,11 +86,14 @@ typedef enum { #define G_DHCPV6_IA_TA 4 #define G_DHCPV6_IAADDR 5 #define G_DHCPV6_ORO 6 +#define G_DHCPV6_PREFERENCE 7 #define G_DHCPV6_ELAPSED_TIME 8 #define G_DHCPV6_STATUS_CODE 13 #define G_DHCPV6_RAPID_COMMIT 14 #define G_DHCPV6_DNS_SERVERS 23 #define G_DHCPV6_DOMAIN_LIST 24 +#define G_DHCPV6_IA_PD 25 +#define G_DHCPV6_IA_PREFIX 26 #define G_DHCPV6_SNTP_SERVERS 31 #define G_DHCPV6_ERROR_SUCCESS 0 @@ -96,6 +102,7 @@ typedef enum { #define G_DHCPV6_ERROR_BINDING 3 #define G_DHCPV6_ERROR_LINK 4 #define G_DHCPV6_ERROR_MCAST 5 +#define G_DHCPV6_ERROR_NO_PREFIX 6 typedef enum { G_DHCPV6_DUID_LLT = 1, @@ -103,6 +110,19 @@ typedef enum { G_DHCPV6_DUID_LL = 3, } GDHCPDuidType; +typedef struct { + /* + * Note that no field in this struct can be allocated + * from heap or there will be a memory leak when the + * struct is freed by client.c:remove_option_value() + */ + struct in6_addr prefix; + unsigned char prefixlen; + uint32_t preferred; + uint32_t valid; + time_t expire; +} GDHCPIAPrefix; + typedef void (*GDHCPClientEventFunc) (GDHCPClient *client, gpointer user_data); typedef void (*GDHCPDebugFunc)(const char *str, gpointer user_data); @@ -142,6 +162,10 @@ int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type, unsigned char **duid, int *duid_len); int g_dhcpv6_client_set_duid(GDHCPClient *dhcp_client, unsigned char *duid, int duid_len); +int g_dhcpv6_client_set_pd(GDHCPClient *dhcp_client, uint32_t *T1, uint32_t *T2, + GSList *prefixes); +GSList *g_dhcpv6_copy_prefixes(GSList *prefixes); +gboolean g_dhcpv6_client_clear_send(GDHCPClient *dhcp_client, uint16_t code); void g_dhcpv6_client_set_send(GDHCPClient *dhcp_client, uint16_t option_code, uint8_t *option_value, uint16_t option_len); uint16_t g_dhcpv6_client_get_status(GDHCPClient *dhcp_client); @@ -150,15 +174,16 @@ void g_dhcpv6_client_create_iaid(GDHCPClient *dhcp_client, int index, unsigned char *iaid); int g_dhcpv6_client_get_timeouts(GDHCPClient *dhcp_client, uint32_t *T1, uint32_t *T2, - time_t *last_renew, time_t *last_rebind, - time_t *expire); + time_t *started, time_t *expire); uint32_t g_dhcpv6_client_get_iaid(GDHCPClient *dhcp_client); +void g_dhcpv6_client_set_iaid(GDHCPClient *dhcp_client, uint32_t iaid); int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index, 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); + bool add_addresses, const char *address); +int g_dhcpv6_client_set_ias(GDHCPClient *dhcp_client, int index, + int code, uint32_t *T1, uint32_t *T2, + GSList *addresses); +void g_dhcpv6_client_reset_request(GDHCPClient *dhcp_client); void g_dhcpv6_client_set_retransmit(GDHCPClient *dhcp_client); void g_dhcpv6_client_clear_retransmit(GDHCPClient *dhcp_client); diff --git a/gdhcp/ipv4ll.c b/gdhcp/ipv4ll.c index 033ef816..9bf52b0a 100644 --- a/gdhcp/ipv4ll.c +++ b/gdhcp/ipv4ll.c @@ -122,10 +122,13 @@ int ipv4ll_arp_socket(int ifindex) { int fd; struct sockaddr_ll sock; + fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_ARP)); if (fd < 0) return fd; + memset(&sock, 0, sizeof(sock)); + sock.sll_family = AF_PACKET; sock.sll_protocol = htons(ETH_P_ARP); sock.sll_ifindex = ifindex; diff --git a/gdhcp/server.c b/gdhcp/server.c index 0c5f2950..728992da 100644 --- a/gdhcp/server.c +++ b/gdhcp/server.c @@ -51,7 +51,7 @@ struct _GDHCPServer { int ref_count; GDHCPType type; - gboolean started; + bool started; int ifindex; char *interface; uint32_t start_ip; @@ -80,7 +80,7 @@ static inline void debug(GDHCPServer *server, const char *format, ...) char str[256]; va_list ap; - if (server->debug_func == NULL) + if (!server->debug_func) return; va_start(ap, format); @@ -143,14 +143,14 @@ static int get_lease(GDHCPServer *dhcp_server, uint32_t yiaddr, GINT_TO_POINTER((int) ntohl(yiaddr))); debug(dhcp_server, "lease_mac %p lease_nip %p", lease_mac, lease_nip); - if (lease_nip != NULL) { + if (lease_nip) { dhcp_server->lease_list = g_list_remove(dhcp_server->lease_list, lease_nip); g_hash_table_remove(dhcp_server->nip_lease_hash, GINT_TO_POINTER((int) ntohl(yiaddr))); - if (lease_mac == NULL) + if (!lease_mac) *lease = lease_nip; else if (lease_nip != lease_mac) { remove_lease(dhcp_server, lease_mac); @@ -161,7 +161,7 @@ static int get_lease(GDHCPServer *dhcp_server, uint32_t yiaddr, return 0; } - if (lease_mac != NULL) { + if (lease_mac) { dhcp_server->lease_list = g_list_remove(dhcp_server->lease_list, lease_mac); @@ -173,7 +173,7 @@ static int get_lease(GDHCPServer *dhcp_server, uint32_t yiaddr, } *lease = g_try_new0(struct dhcp_lease, 1); - if (*lease == NULL) + if (!*lease) return -ENOMEM; return 0; @@ -224,18 +224,18 @@ static struct dhcp_lease *find_lease_by_nip(GDHCPServer *dhcp_server, } /* Check if the IP is taken; if it is, add it to the lease table */ -static gboolean arp_check(uint32_t nip, const uint8_t *safe_mac) +static bool arp_check(uint32_t nip, const uint8_t *safe_mac) { /* TODO: Add ARP checking */ - return TRUE; + return true; } -static gboolean is_expired_lease(struct dhcp_lease *lease) +static bool is_expired_lease(struct dhcp_lease *lease) { if (lease->expire < time(NULL)) - return TRUE; + return true; - return FALSE; + return false; } static uint32_t find_free_or_expired_nip(GDHCPServer *dhcp_server, @@ -255,26 +255,26 @@ static uint32_t find_free_or_expired_nip(GDHCPServer *dhcp_server, continue; lease = find_lease_by_nip(dhcp_server, ip_addr); - if (lease != NULL) + if (lease) continue; - if (arp_check(htonl(ip_addr), safe_mac) == TRUE) + if (arp_check(htonl(ip_addr), safe_mac)) return ip_addr; } /* The last lease is the oldest one */ list = g_list_last(dhcp_server->lease_list); - if (list == NULL) + if (!list) return 0; lease = list->data; - if (lease == NULL) + if (!lease) return 0; - if (is_expired_lease(lease) == FALSE) + if (!is_expired_lease(lease)) return 0; - if (arp_check(lease->lease_nip, safe_mac) == FALSE) + if (!arp_check(lease->lease_nip, safe_mac)) return 0; return lease->lease_nip; @@ -357,18 +357,18 @@ GDHCPServer *g_dhcp_server_new(GDHCPType type, } dhcp_server = g_try_new0(GDHCPServer, 1); - if (dhcp_server == NULL) { + if (!dhcp_server) { *error = G_DHCP_SERVER_ERROR_NOMEM; return NULL; } dhcp_server->interface = get_interface_name(ifindex); - if (dhcp_server->interface == NULL) { + if (!dhcp_server->interface) { *error = G_DHCP_SERVER_ERROR_INTERFACE_UNAVAILABLE; goto error; } - if (interface_is_up(ifindex) == FALSE) { + if (!interface_is_up(ifindex)) { *error = G_DHCP_SERVER_ERROR_INTERFACE_DOWN; goto error; } @@ -424,7 +424,7 @@ static uint8_t check_packet_type(struct dhcp_packet *packet) type = dhcp_get_option(packet, DHCP_MESSAGE_TYPE); - if (type == NULL) + if (!type) return 0; if (*type < DHCP_MINTYPE) @@ -460,7 +460,7 @@ static void add_option(gpointer key, gpointer value, gpointer user_data) struct in_addr nip; struct dhcp_packet *packet = user_data; - if (option_value == NULL) + if (!option_value) return; switch (option_code) { @@ -485,28 +485,28 @@ static void add_server_options(GDHCPServer *dhcp_server, add_option, packet); } -static gboolean check_requested_nip(GDHCPServer *dhcp_server, +static bool check_requested_nip(GDHCPServer *dhcp_server, uint32_t requested_nip) { struct dhcp_lease *lease; if (requested_nip == 0) - return FALSE; + return false; if (requested_nip < dhcp_server->start_ip) - return FALSE; + return false; if (requested_nip > dhcp_server->end_ip) - return FALSE; + return false; lease = find_lease_by_nip(dhcp_server, requested_nip); - if (lease == NULL) - return TRUE; + if (!lease) + return true; - if (is_expired_lease(lease) == FALSE) - return FALSE; + if (!is_expired_lease(lease)) + return false; - return TRUE; + return true; } static void send_packet_to_client(GDHCPServer *dhcp_server, @@ -544,7 +544,7 @@ static void send_offer(GDHCPServer *dhcp_server, if (lease) packet.yiaddr = htonl(lease->lease_nip); - else if (check_requested_nip(dhcp_server, requested_nip) == TRUE) + else if (check_requested_nip(dhcp_server, requested_nip)) packet.yiaddr = htonl(requested_nip); else packet.yiaddr = htonl(find_free_or_expired_nip( @@ -559,7 +559,7 @@ static void send_offer(GDHCPServer *dhcp_server, lease = add_lease(dhcp_server, OFFER_TIME, packet.chaddr, packet.yiaddr); - if (lease == NULL) { + if (!lease) { debug(dhcp_server, "Err: No free IP addresses. OFFER abandoned"); return; @@ -579,7 +579,7 @@ static void save_lease(GDHCPServer *dhcp_server) { GList *list; - if (dhcp_server->save_lease_func == NULL) + if (!dhcp_server->save_lease_func) return; for (list = dhcp_server->lease_list; list; list = list->next) { @@ -677,65 +677,65 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, lease = find_lease_by_mac(dhcp_server, packet.chaddr); switch (type) { - case DHCPDISCOVER: - debug(dhcp_server, "Received DISCOVER"); + case DHCPDISCOVER: + debug(dhcp_server, "Received DISCOVER"); - send_offer(dhcp_server, &packet, lease, requested_nip); + send_offer(dhcp_server, &packet, lease, requested_nip); break; - case DHCPREQUEST: - debug(dhcp_server, "Received REQUEST NIP %d", + case DHCPREQUEST: + debug(dhcp_server, "Received REQUEST NIP %d", requested_nip); - if (requested_nip == 0) { - requested_nip = packet.ciaddr; - if (requested_nip == 0) - break; - } - - if (lease && requested_nip == lease->lease_nip) { - debug(dhcp_server, "Sending ACK"); - send_ACK(dhcp_server, &packet, - lease->lease_nip); + if (requested_nip == 0) { + requested_nip = packet.ciaddr; + if (requested_nip == 0) break; - } + } + + if (lease && requested_nip == lease->lease_nip) { + debug(dhcp_server, "Sending ACK"); + send_ACK(dhcp_server, &packet, + lease->lease_nip); + break; + } - if (server_id_option || lease == NULL) { - debug(dhcp_server, "Sending NAK"); - send_NAK(dhcp_server, &packet); - } + if (server_id_option || !lease) { + debug(dhcp_server, "Sending NAK"); + send_NAK(dhcp_server, &packet); + } break; - case DHCPDECLINE: - debug(dhcp_server, "Received DECLINE"); + case DHCPDECLINE: + debug(dhcp_server, "Received DECLINE"); - if (server_id_option == NULL) - break; + if (!server_id_option) + break; - if (request_ip_option == NULL) - break; + if (!request_ip_option) + break; - if (lease == NULL) - break; + if (!lease) + break; - if (requested_nip == lease->lease_nip) - remove_lease(dhcp_server, lease); + if (requested_nip == lease->lease_nip) + remove_lease(dhcp_server, lease); break; - case DHCPRELEASE: - debug(dhcp_server, "Received RELEASE"); + case DHCPRELEASE: + debug(dhcp_server, "Received RELEASE"); - if (server_id_option == NULL) - break; + if (!server_id_option) + break; - if (lease == NULL) - break; + if (!lease) + break; - if (packet.ciaddr == lease->lease_nip) - lease_set_expire(dhcp_server, lease, - time(NULL)); + if (packet.ciaddr == lease->lease_nip) + lease_set_expire(dhcp_server, lease, + time(NULL)); break; - case DHCPINFORM: - debug(dhcp_server, "Received INFORM"); - send_inform(dhcp_server, &packet); + case DHCPINFORM: + debug(dhcp_server, "Received INFORM"); + send_inform(dhcp_server, &packet); break; } @@ -748,7 +748,7 @@ int g_dhcp_server_start(GDHCPServer *dhcp_server) GIOChannel *listener_channel; int listener_sockfd; - if (dhcp_server->started == TRUE) + if (dhcp_server->started) return 0; listener_sockfd = dhcp_l3_socket(SERVER_PORT, @@ -757,7 +757,7 @@ int g_dhcp_server_start(GDHCPServer *dhcp_server) return -EIO; listener_channel = g_io_channel_unix_new(listener_sockfd); - if (listener_channel == NULL) { + if (!listener_channel) { close(listener_sockfd); return -EIO; } @@ -783,7 +783,7 @@ int g_dhcp_server_set_option(GDHCPServer *dhcp_server, { struct in_addr nip; - if (option_value == NULL) + if (!option_value) return -EINVAL; debug(dhcp_server, "option_code %d option_value %s", @@ -808,7 +808,7 @@ int g_dhcp_server_set_option(GDHCPServer *dhcp_server, void g_dhcp_server_set_save_lease(GDHCPServer *dhcp_server, GDHCPSaveLeaseFunc func, gpointer user_data) { - if (dhcp_server == NULL) + if (!dhcp_server) return; dhcp_server->save_lease_func = func; @@ -816,7 +816,7 @@ void g_dhcp_server_set_save_lease(GDHCPServer *dhcp_server, GDHCPServer *g_dhcp_server_ref(GDHCPServer *dhcp_server) { - if (dhcp_server == NULL) + if (!dhcp_server) return NULL; __sync_fetch_and_add(&dhcp_server->ref_count, 1); @@ -841,7 +841,7 @@ void g_dhcp_server_stop(GDHCPServer *dhcp_server) void g_dhcp_server_unref(GDHCPServer *dhcp_server) { - if (dhcp_server == NULL) + if (!dhcp_server) return; if (__sync_fetch_and_sub(&dhcp_server->ref_count, 1) != 1) @@ -876,9 +876,10 @@ int g_dhcp_server_set_ip_range(GDHCPServer *dhcp_server, return 0; } -void g_dhcp_server_set_lease_time(GDHCPServer *dhcp_server, unsigned int lease_time) +void g_dhcp_server_set_lease_time(GDHCPServer *dhcp_server, + unsigned int lease_time) { - if (dhcp_server == NULL) + if (!dhcp_server) return; dhcp_server->lease_seconds = lease_time; @@ -887,7 +888,7 @@ void g_dhcp_server_set_lease_time(GDHCPServer *dhcp_server, unsigned int lease_t void g_dhcp_server_set_debug(GDHCPServer *dhcp_server, GDHCPDebugFunc func, gpointer user_data) { - if (dhcp_server == NULL) + if (!dhcp_server) return; dhcp_server->debug_func = func; |