diff options
author | Zhang zhengguang <zhengguang.zhang@intel.com> | 2014-10-29 11:03:47 +0800 |
---|---|---|
committer | Zhang zhengguang <zhengguang.zhang@intel.com> | 2014-10-29 11:03:47 +0800 |
commit | bcae74da8fa2958b3fec9153fc33e41f0e0317bf (patch) | |
tree | 06a00f6457307467fee4f6580dce4a1a857751c1 /src/dhcp.c | |
parent | 1b9d0a62f59bb48c8deb2f0b98d9acdffdd9abe7 (diff) | |
download | connman-bcae74da8fa2958b3fec9153fc33e41f0e0317bf.tar.gz connman-bcae74da8fa2958b3fec9153fc33e41f0e0317bf.tar.bz2 connman-bcae74da8fa2958b3fec9153fc33e41f0e0317bf.zip |
Imported Upstream version 1.26upstream/1.26
Diffstat (limited to 'src/dhcp.c')
-rw-r--r-- | src/dhcp.c | 413 |
1 files changed, 221 insertions, 192 deletions
@@ -39,8 +39,10 @@ #define RATE_LIMIT_INTERVAL 60 /* delay between successive attempts */ struct connman_dhcp { + struct connman_ipconfig *ipconfig; struct connman_network *network; dhcp_cb callback; + gpointer user_data; char **nameservers; char **timeservers; @@ -54,7 +56,7 @@ struct connman_dhcp { char *dhcp_debug_prefix; }; -static GHashTable *network_table; +static GHashTable *ipconfig_table; static bool ipv4ll_running; static void dhcp_free(struct connman_dhcp *dhcp) @@ -70,41 +72,36 @@ static void dhcp_free(struct connman_dhcp *dhcp) g_free(dhcp); } -/** - * dhcp_invalidate: Invalidate an existing DHCP lease - * @dhcp: pointer to the DHCP lease to invalidate. - * @callback: flag indicating whether or not to invoke the client callback - * if present. - * - * Invalidates an existing DHCP lease, optionally invoking the client - * callback. The caller may wish to avoid the client callback invocation - * when the invocation of that callback might otherwise unnecessarily upset - * service state due to the IP configuration change implied by this - * invalidation. - */ -static void dhcp_invalidate(struct connman_dhcp *dhcp, bool callback) +static void ipv4ll_stop_client(struct connman_dhcp *dhcp) { - struct connman_service *service; - struct connman_ipconfig *ipconfig; - int i; + if (!dhcp->ipv4ll_client) + return; - DBG("dhcp %p callback %u", dhcp, callback); + g_dhcp_client_stop(dhcp->ipv4ll_client); + g_dhcp_client_unref(dhcp->ipv4ll_client); + dhcp->ipv4ll_client = NULL; + ipv4ll_running = false; - if (!dhcp) - return; + g_free(dhcp->ipv4ll_debug_prefix); + dhcp->ipv4ll_debug_prefix = NULL; +} - service = connman_service_lookup_from_network(dhcp->network); - if (!service) - return; +static bool apply_dhcp_invalidate_on_network(struct connman_dhcp *dhcp) +{ + struct connman_service *service; + int i; - ipconfig = __connman_service_get_ip4config(service); - if (!ipconfig) - return; + if (!dhcp->network) + return true; - __connman_6to4_remove(ipconfig); + service = connman_service_lookup_from_network(dhcp->network); + if (!service) { + connman_error("Can not lookup service"); + return false; + } __connman_service_set_domainname(service, NULL); - __connman_service_set_pac(service, NULL); + __connman_ipconfig_set_proxy_autoconfig(dhcp->ipconfig, NULL); if (dhcp->timeservers) { for (i = 0; dhcp->timeservers[i]; i++) { @@ -112,7 +109,6 @@ static void dhcp_invalidate(struct connman_dhcp *dhcp, bool callback) dhcp->timeservers[i]); } } - if (dhcp->nameservers) { for (i = 0; dhcp->nameservers[i]; i++) { __connman_service_nameserver_remove(service, @@ -120,25 +116,55 @@ static void dhcp_invalidate(struct connman_dhcp *dhcp, bool callback) } } - __connman_ipconfig_set_dhcp_address(ipconfig, - __connman_ipconfig_get_local(ipconfig)); - DBG("last address %s", __connman_ipconfig_get_dhcp_address(ipconfig)); + return true; +} - __connman_ipconfig_address_remove(ipconfig); +/** + * dhcp_invalidate: Invalidate an existing DHCP lease + * @dhcp: pointer to the DHCP lease to invalidate. + * @callback: flag indicating whether or not to invoke the client callback + * if present. + * + * Invalidates an existing DHCP lease, optionally invoking the client + * callback. The caller may wish to avoid the client callback invocation + * when the invocation of that callback might otherwise unnecessarily upset + * service state due to the IP configuration change implied by this + * invalidation. + */ +static void dhcp_invalidate(struct connman_dhcp *dhcp, bool callback) +{ + DBG("dhcp %p callback %u", dhcp, callback); + + if (!dhcp) + return; + + __connman_6to4_remove(dhcp->ipconfig); - __connman_ipconfig_set_local(ipconfig, NULL); - __connman_ipconfig_set_broadcast(ipconfig, NULL); - __connman_ipconfig_set_gateway(ipconfig, NULL); - __connman_ipconfig_set_prefixlen(ipconfig, 0); + if (!apply_dhcp_invalidate_on_network(dhcp)) + return; + + __connman_ipconfig_set_dhcp_address(dhcp->ipconfig, + __connman_ipconfig_get_local(dhcp->ipconfig)); + DBG("last address %s", + __connman_ipconfig_get_dhcp_address(dhcp->ipconfig)); + + __connman_ipconfig_address_remove(dhcp->ipconfig); + + __connman_ipconfig_set_local(dhcp->ipconfig, NULL); + __connman_ipconfig_set_broadcast(dhcp->ipconfig, NULL); + __connman_ipconfig_set_gateway(dhcp->ipconfig, NULL); + __connman_ipconfig_set_prefixlen(dhcp->ipconfig, 0); if (dhcp->callback && callback) - dhcp->callback(dhcp->network, false, NULL); + dhcp->callback(dhcp->ipconfig, dhcp->network, + false, dhcp->user_data); } static void dhcp_valid(struct connman_dhcp *dhcp) { if (dhcp->callback) - dhcp->callback(dhcp->network, true, NULL); + dhcp->callback(dhcp->ipconfig, dhcp->network, + true, dhcp->user_data); } static void dhcp_debug(const char *str, void *data) @@ -146,20 +172,6 @@ static void dhcp_debug(const char *str, void *data) connman_info("%s: %s", (const char *) data, str); } -static void ipv4ll_stop_client(struct connman_dhcp *dhcp) -{ - if (!dhcp->ipv4ll_client) - return; - - g_dhcp_client_stop(dhcp->ipv4ll_client); - g_dhcp_client_unref(dhcp->ipv4ll_client); - dhcp->ipv4ll_client = NULL; - ipv4ll_running = false; - - g_free(dhcp->ipv4ll_debug_prefix); - dhcp->ipv4ll_debug_prefix = NULL; -} - static void ipv4ll_lost_cb(GDHCPClient *dhcp_client, gpointer user_data); static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data); @@ -174,7 +186,7 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp) if (dhcp->ipv4ll_client) return -EALREADY; - index = connman_network_get_index(dhcp->network); + index = __connman_ipconfig_get_index(dhcp->ipconfig); ipv4ll_client = g_dhcp_client_new(G_DHCP_IPV4LL, index, &error); if (error != G_DHCP_CLIENT_ERROR_NONE) @@ -189,10 +201,12 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp) g_dhcp_client_set_id(ipv4ll_client); - hostname = connman_utsname_get_hostname(); - if (hostname) - g_dhcp_client_set_send(ipv4ll_client, G_DHCP_HOST_NAME, - hostname); + if (dhcp->network) { + hostname = connman_utsname_get_hostname(); + if (hostname) + g_dhcp_client_set_send(ipv4ll_client, + G_DHCP_HOST_NAME, hostname); + } g_dhcp_client_register_event(ipv4ll_client, G_DHCP_CLIENT_EVENT_IPV4LL_LOST, ipv4ll_lost_cb, dhcp); @@ -216,16 +230,11 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp) static gboolean dhcp_retry_cb(gpointer user_data) { struct connman_dhcp *dhcp = user_data; - struct connman_service *service; - struct connman_ipconfig *ipconfig; dhcp->timeout = 0; - service = connman_service_lookup_from_network(dhcp->network); - ipconfig = __connman_service_get_ip4config(service); - g_dhcp_client_start(dhcp->dhcp_client, - __connman_ipconfig_get_dhcp_address(ipconfig)); + __connman_ipconfig_get_dhcp_address(dhcp->ipconfig)); return FALSE; } @@ -296,78 +305,33 @@ static bool compare_string_arrays(char **array_a, char **array_b) return true; } -static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data) +static bool apply_lease_available_on_network(GDHCPClient *dhcp_client, + struct connman_dhcp *dhcp) { - struct connman_dhcp *dhcp = user_data; - GList *list, *option = NULL; - char *address, *netmask = NULL, *gateway = NULL; - const char *c_address, *c_gateway; char **nameservers, **timeservers, *pac = NULL; - int ns_entries; - struct connman_ipconfig *ipconfig; struct connman_service *service; - unsigned char prefixlen, c_prefixlen; - bool ip_change; + GList *list, *option = NULL; + int ns_entries; int i; - DBG("Lease available"); - - if (dhcp->ipv4ll_client) { - ipv4ll_stop_client(dhcp); - dhcp_invalidate(dhcp, false); - } + if (!dhcp->network) + return true; service = connman_service_lookup_from_network(dhcp->network); if (!service) { connman_error("Can not lookup service"); - return; - } - - ipconfig = __connman_service_get_ip4config(service); - if (!ipconfig) { - connman_error("Could not lookup ipconfig"); - return; + return false; } - c_address = __connman_ipconfig_get_local(ipconfig); - c_gateway = __connman_ipconfig_get_gateway(ipconfig); - c_prefixlen = __connman_ipconfig_get_prefixlen(ipconfig); - - address = g_dhcp_client_get_address(dhcp_client); - - __connman_ipconfig_set_dhcp_address(ipconfig, address); - DBG("last address %s", address); - - option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET); - if (option) - netmask = g_strdup(option->data); - - option = g_dhcp_client_get_option(dhcp_client, G_DHCP_ROUTER); + option = g_dhcp_client_get_option(dhcp_client, 252); if (option) - gateway = g_strdup(option->data); - - prefixlen = __connman_ipaddress_netmask_prefix_len(netmask); - if (prefixlen == 255) - connman_warn("netmask: %s is invalid", netmask); - - DBG("c_address %s", c_address); - - if (address && c_address && g_strcmp0(address, c_address) != 0) - ip_change = true; - else if (gateway && c_gateway && g_strcmp0(gateway, c_gateway) != 0) - ip_change = true; - else if (prefixlen != c_prefixlen) - ip_change = true; - else if (!c_address || !c_gateway) - ip_change = true; - else - ip_change = false; + pac = g_strdup(option->data); option = g_dhcp_client_get_option(dhcp_client, G_DHCP_DNS_SERVER); ns_entries = g_list_length(option); nameservers = g_try_new0(char *, ns_entries + 1); if (nameservers) { - for (i = 0, list = option; list; list = list->next, i++) + for (i = 0, list = option;list; list = list->next, i++) nameservers[i] = g_strdup(list->data); nameservers[ns_entries] = NULL; } @@ -389,18 +353,6 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data) timeservers[ns_entries] = NULL; } - option = g_dhcp_client_get_option(dhcp_client, 252); - if (option) - pac = g_strdup(option->data); - - __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP); - - if (ip_change) { - __connman_ipconfig_set_local(ipconfig, address); - __connman_ipconfig_set_prefixlen(ipconfig, prefixlen); - __connman_ipconfig_set_gateway(ipconfig, gateway); - } - if (!compare_string_arrays(nameservers, dhcp->nameservers)) { if (dhcp->nameservers) { for (i = 0; dhcp->nameservers[i]; i++) { @@ -412,8 +364,7 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data) dhcp->nameservers = nameservers; - for (i = 0; dhcp->nameservers && - dhcp->nameservers[i]; i++) { + for (i = 0; dhcp->nameservers && dhcp->nameservers[i]; i++) { __connman_service_nameserver_append(service, dhcp->nameservers[i], false); } @@ -432,8 +383,7 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data) dhcp->timeservers = timeservers; - for (i = 0; dhcp->timeservers && - dhcp->timeservers[i]; i++) { + for (i = 0; dhcp->timeservers && dhcp->timeservers[i]; i++) { __connman_service_timeserver_append(service, dhcp->timeservers[i]); } @@ -445,14 +395,77 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data) g_free(dhcp->pac); dhcp->pac = pac; - __connman_service_set_pac(service, dhcp->pac); + __connman_ipconfig_set_proxy_autoconfig(dhcp->ipconfig, + dhcp->pac); + } + + __connman_6to4_probe(service); + + return true; +} + +static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data) +{ + struct connman_dhcp *dhcp = user_data; + GList *option = NULL; + char *address, *netmask = NULL, *gateway = NULL; + const char *c_address, *c_gateway; + unsigned char prefixlen, c_prefixlen; + bool ip_change; + + DBG("Lease available"); + + if (dhcp->ipv4ll_client) { + ipv4ll_stop_client(dhcp); + dhcp_invalidate(dhcp, false); + } + + c_address = __connman_ipconfig_get_local(dhcp->ipconfig); + c_gateway = __connman_ipconfig_get_gateway(dhcp->ipconfig); + c_prefixlen = __connman_ipconfig_get_prefixlen(dhcp->ipconfig); + + address = g_dhcp_client_get_address(dhcp_client); + + __connman_ipconfig_set_dhcp_address(dhcp->ipconfig, address); + DBG("last address %s", address); + + option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET); + if (option) + netmask = g_strdup(option->data); + + option = g_dhcp_client_get_option(dhcp_client, G_DHCP_ROUTER); + if (option) + gateway = g_strdup(option->data); + + prefixlen = connman_ipaddress_calc_netmask_len(netmask); + if (prefixlen == 255) + connman_warn("netmask: %s is invalid", netmask); + + DBG("c_address %s", c_address); + + if (g_strcmp0(address, c_address)) + ip_change = true; + else if (g_strcmp0(gateway, c_gateway)) + ip_change = true; + else if (prefixlen != c_prefixlen) + ip_change = true; + else + ip_change = false; + + __connman_ipconfig_set_method(dhcp->ipconfig, + CONNMAN_IPCONFIG_METHOD_DHCP); + if (ip_change) { + __connman_ipconfig_set_local(dhcp->ipconfig, address); + __connman_ipconfig_set_prefixlen(dhcp->ipconfig, prefixlen); + __connman_ipconfig_set_gateway(dhcp->ipconfig, gateway); } + if (!apply_lease_available_on_network(dhcp_client, dhcp)) + return; + if (ip_change) dhcp_valid(dhcp); - __connman_6to4_probe(service); - g_free(address); g_free(netmask); g_free(gateway); @@ -462,29 +475,20 @@ static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data) { struct connman_dhcp *dhcp = user_data; char *address, *netmask; - struct connman_service *service; - struct connman_ipconfig *ipconfig; unsigned char prefixlen; DBG("IPV4LL available"); - service = connman_service_lookup_from_network(dhcp->network); - if (!service) - return; - - ipconfig = __connman_service_get_ip4config(service); - if (!ipconfig) - return; - address = g_dhcp_client_get_address(ipv4ll_client); netmask = g_dhcp_client_get_netmask(ipv4ll_client); - prefixlen = __connman_ipaddress_netmask_prefix_len(netmask); + prefixlen = connman_ipaddress_calc_netmask_len(netmask); - __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP); - __connman_ipconfig_set_local(ipconfig, address); - __connman_ipconfig_set_prefixlen(ipconfig, prefixlen); - __connman_ipconfig_set_gateway(ipconfig, NULL); + __connman_ipconfig_set_method(dhcp->ipconfig, + CONNMAN_IPCONFIG_METHOD_DHCP); + __connman_ipconfig_set_local(dhcp->ipconfig, address); + __connman_ipconfig_set_prefixlen(dhcp->ipconfig, prefixlen); + __connman_ipconfig_set_gateway(dhcp->ipconfig, NULL); dhcp_valid(dhcp); @@ -494,15 +498,13 @@ static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data) static int dhcp_initialize(struct connman_dhcp *dhcp) { - struct connman_service *service; GDHCPClient *dhcp_client; GDHCPClientError error; - const char *hostname; int index; DBG("dhcp %p", dhcp); - index = connman_network_get_index(dhcp->network); + index = __connman_ipconfig_get_index(dhcp->ipconfig); dhcp_client = g_dhcp_client_new(G_DHCP_IPV4, index, &error); if (error != G_DHCP_CLIENT_ERROR_NONE) @@ -517,22 +519,29 @@ static int dhcp_initialize(struct connman_dhcp *dhcp) g_dhcp_client_set_id(dhcp_client); - service = connman_service_lookup_from_network(dhcp->network); + if (dhcp->network) { + struct connman_service *service; + const char *hostname; - hostname = __connman_service_get_hostname(service); - if (!hostname) - hostname = connman_utsname_get_hostname(); + service = connman_service_lookup_from_network(dhcp->network); + + hostname = __connman_service_get_hostname(service); + if (!hostname) + hostname = connman_utsname_get_hostname(); - if (hostname) - g_dhcp_client_set_send(dhcp_client, G_DHCP_HOST_NAME, hostname); + if (hostname) + g_dhcp_client_set_send(dhcp_client, + G_DHCP_HOST_NAME, hostname); + + g_dhcp_client_set_request(dhcp_client, G_DHCP_HOST_NAME); + g_dhcp_client_set_request(dhcp_client, G_DHCP_DNS_SERVER); + g_dhcp_client_set_request(dhcp_client, G_DHCP_DOMAIN_NAME); + g_dhcp_client_set_request(dhcp_client, G_DHCP_NTP_SERVER); + g_dhcp_client_set_request(dhcp_client, 252); + } - g_dhcp_client_set_request(dhcp_client, G_DHCP_HOST_NAME); g_dhcp_client_set_request(dhcp_client, G_DHCP_SUBNET); - g_dhcp_client_set_request(dhcp_client, G_DHCP_DNS_SERVER); - g_dhcp_client_set_request(dhcp_client, G_DHCP_DOMAIN_NAME); - g_dhcp_client_set_request(dhcp_client, G_DHCP_NTP_SERVER); g_dhcp_client_set_request(dhcp_client, G_DHCP_ROUTER); - g_dhcp_client_set_request(dhcp_client, 252); g_dhcp_client_register_event(dhcp_client, G_DHCP_CLIENT_EVENT_LEASE_AVAILABLE, @@ -553,8 +562,10 @@ static int dhcp_release(struct connman_dhcp *dhcp) { DBG("dhcp %p", dhcp); - if (dhcp->timeout > 0) + if (dhcp->timeout > 0) { g_source_remove(dhcp->timeout); + dhcp->timeout = 0; + } if (dhcp->dhcp_client) { g_dhcp_client_stop(dhcp->dhcp_client); @@ -571,56 +582,74 @@ static int dhcp_release(struct connman_dhcp *dhcp) return 0; } -int __connman_dhcp_start(struct connman_network *network, dhcp_cb callback) +int __connman_dhcp_start(struct connman_ipconfig *ipconfig, + struct connman_network *network, dhcp_cb callback, + gpointer user_data) { - struct connman_service *service; - struct connman_ipconfig *ipconfig; const char *last_addr = NULL; struct connman_dhcp *dhcp; + int err; DBG(""); - service = connman_service_lookup_from_network(network); - if (!service) - return -EINVAL; + if (network) { + struct connman_service *service; - ipconfig = __connman_service_get_ip4config(service); - if (ipconfig) - last_addr = __connman_ipconfig_get_dhcp_address(ipconfig); + service = connman_service_lookup_from_network(network); + if (!service) + return -EINVAL; + } + + last_addr = __connman_ipconfig_get_dhcp_address(ipconfig); - dhcp = g_hash_table_lookup(network_table, network); + dhcp = g_hash_table_lookup(ipconfig_table, ipconfig); if (!dhcp) { dhcp = g_try_new0(struct connman_dhcp, 1); if (!dhcp) return -ENOMEM; - dhcp->network = network; - connman_network_ref(network); + dhcp->ipconfig = ipconfig; + __connman_ipconfig_ref(ipconfig); + + if (network) { + dhcp->network = network; + connman_network_ref(network); + } + + err = dhcp_initialize(dhcp); - g_hash_table_insert(network_table, network, dhcp); + if (err < 0) { + if (network) + connman_network_unref(network); + g_free(dhcp); + return err; + } - dhcp_initialize(dhcp); + g_hash_table_insert(ipconfig_table, ipconfig, dhcp); } dhcp->callback = callback; + dhcp->user_data = user_data; return g_dhcp_client_start(dhcp->dhcp_client, last_addr); } -void __connman_dhcp_stop(struct connman_network *network) +void __connman_dhcp_stop(struct connman_ipconfig *ipconfig) { struct connman_dhcp *dhcp; - DBG("network_table %p network %p", network_table, network); + DBG("ipconfig_table %p ipconfig %p", ipconfig_table, ipconfig); - if (!network_table) + if (!ipconfig_table) return; - dhcp = g_hash_table_lookup(network_table, network); + dhcp = g_hash_table_lookup(ipconfig_table, ipconfig); if (dhcp) { - g_hash_table_remove(network_table, network); - connman_network_unref(network); + g_hash_table_remove(ipconfig_table, ipconfig); + __connman_ipconfig_unref(ipconfig); + if (dhcp->network) + connman_network_unref(dhcp->network); dhcp_release(dhcp); dhcp_invalidate(dhcp, false); dhcp_free(dhcp); @@ -631,8 +660,8 @@ int __connman_dhcp_init(void) { DBG(""); - network_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, NULL); + ipconfig_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, NULL); return 0; } @@ -641,6 +670,6 @@ void __connman_dhcp_cleanup(void) { DBG(""); - g_hash_table_destroy(network_table); - network_table = NULL; + g_hash_table_destroy(ipconfig_table); + ipconfig_table = NULL; } |