5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <gdhcp/gdhcp.h>
36 enum connman_dhcp_state {
37 CONNMAN_DHCP_STATE_UNKNOWN = 0,
38 CONNMAN_DHCP_STATE_IDLE = 1,
39 CONNMAN_DHCP_STATE_BOUND = 2,
40 CONNMAN_DHCP_STATE_RENEW = 3,
41 CONNMAN_DHCP_STATE_FAIL = 4,
45 GDHCPClient *dhcp_client;
48 enum connman_dhcp_state state;
50 struct connman_element *element;
53 static void dhcp_set_value(struct connman_dhcp *dhcp,
54 const char *key, const char *value)
58 if (g_strcmp0(key, "Address") == 0) {
59 g_free(dhcp->element->ipv4.address);
60 dhcp->element->ipv4.address = g_strdup(value);
61 } else if (g_strcmp0(key, "Netmask") == 0) {
62 g_free(dhcp->element->ipv4.netmask);
63 dhcp->element->ipv4.netmask = g_strdup(value);
64 } else if (g_strcmp0(key, "Gateway") == 0) {
65 g_free(dhcp->element->ipv4.gateway);
66 dhcp->element->ipv4.gateway = g_strdup(value);
67 } else if (g_strcmp0(key, "Network") == 0) {
68 g_free(dhcp->element->ipv4.network);
69 dhcp->element->ipv4.network = g_strdup(value);
70 } else if (g_strcmp0(key, "Broadcast") == 0) {
71 g_free(dhcp->element->ipv4.broadcast);
72 dhcp->element->ipv4.broadcast = g_strdup(value);
73 } else if (g_strcmp0(key, "Nameserver") == 0) {
74 g_free(dhcp->element->ipv4.nameserver);
75 nameservers = g_strsplit_set(value, " ", 0);
76 /* FIXME: The ipv4 structure can only hold one nameserver, so
77 * we are only able to pass along the first nameserver sent by
78 * the DHCP server. If this situation changes, we should
81 dhcp->element->ipv4.nameserver = g_strdup(nameservers[0]);
82 g_strfreev(nameservers);
83 } else if (g_strcmp0(key, "Domainname") == 0) {
84 g_free(dhcp->element->domainname);
85 dhcp->element->domainname = g_strdup(value);
87 __connman_utsname_set_domainname(value);
88 } else if (g_strcmp0(key, "Hostname") == 0) {
89 g_free(dhcp->element->hostname);
90 dhcp->element->hostname = g_strdup(value);
92 __connman_utsname_set_hostname(value);
93 } else if (g_strcmp0(key, "Timeserver") == 0) {
94 connman_info("Timeserver %s", value);
96 g_free(dhcp->element->ipv4.timeserver);
97 dhcp->element->ipv4.timeserver = g_strdup(value);
98 } else if (g_strcmp0(key, "MTU") == 0) {
99 } else if (g_strcmp0(key, "PAC") == 0) {
100 connman_info("PAC configuration %s", value);
102 g_free(dhcp->element->ipv4.pac);
103 dhcp->element->ipv4.pac = g_strdup(value);
107 static void dhcp_bound(struct connman_dhcp *dhcp)
109 struct connman_element *element;
111 DBG("dhcp %p", dhcp);
113 element = connman_element_create(NULL);
117 element->type = CONNMAN_ELEMENT_TYPE_IPV4;
118 element->index = dhcp->index;
120 connman_element_update(dhcp->element);
122 if (connman_element_register(element, dhcp->element) < 0)
123 connman_element_unref(element);
126 static void no_lease_cb(GDHCPClient *dhcp_client, gpointer user_data)
128 struct connman_dhcp *dhcp = user_data;
130 DBG("No lease available");
132 connman_element_set_error(dhcp->element,
133 CONNMAN_ELEMENT_ERROR_FAILED);
136 static void lease_lost_cb(GDHCPClient *dhcp_client, gpointer user_data)
141 static void ipv4ll_lost_cb(GDHCPClient *dhcp_client, gpointer user_data)
143 struct connman_dhcp *dhcp = user_data;
147 connman_element_unregister_children(dhcp->element);
150 static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
152 struct connman_dhcp *dhcp = user_data;
153 GList *list, *option = NULL;
154 char *address, *nameservers;
155 size_t ns_strlen = 0;
157 DBG("Lease available");
159 address = g_dhcp_client_get_address(dhcp_client);
161 dhcp_set_value(dhcp, "Address", address);
164 option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET);
166 dhcp_set_value(dhcp, "Netmask", option->data);
168 option = g_dhcp_client_get_option(dhcp_client, G_DHCP_DNS_SERVER);
169 for (list = option; list; list = list->next)
170 ns_strlen += strlen((char *) list->data) + 2;
171 nameservers = g_try_malloc0(ns_strlen);
173 char *ns_index = nameservers;
175 for (list = option; list; list = list->next) {
176 sprintf(ns_index, "%s ", (char *) list->data);
177 ns_index += strlen((char *) list->data) + 1;
180 dhcp_set_value(dhcp, "Nameserver", nameservers);
184 option = g_dhcp_client_get_option(dhcp_client, G_DHCP_DOMAIN_NAME);
186 dhcp_set_value(dhcp, "Domainname", option->data);
188 option = g_dhcp_client_get_option(dhcp_client, G_DHCP_ROUTER);
190 dhcp_set_value(dhcp, "Gateway", option->data);
192 option = g_dhcp_client_get_option(dhcp_client, G_DHCP_HOST_NAME);
194 dhcp_set_value(dhcp, "Hostname", option->data);
196 option = g_dhcp_client_get_option(dhcp_client, G_DHCP_NTP_SERVER);
198 dhcp_set_value(dhcp, "Timeserver", option->data);
200 option = g_dhcp_client_get_option(dhcp_client, 252);
202 dhcp_set_value(dhcp, "PAC", option->data);
207 static void ipv4ll_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
209 struct connman_dhcp *dhcp = user_data;
210 char *address, *netmask;
212 DBG("IPV4LL available");
214 address = g_dhcp_client_get_address(dhcp_client);
216 dhcp_set_value(dhcp, "Address", address);
218 netmask = g_dhcp_client_get_netmask(dhcp_client);
220 dhcp_set_value(dhcp, "Netmask", netmask);
228 static void dhcp_debug(const char *str, void *data)
230 connman_info("%s: %s\n", (const char *) data, str);
233 static int dhcp_request(struct connman_dhcp *dhcp)
235 GDHCPClient *dhcp_client;
236 GDHCPClientError error;
237 const char *hostname;
240 DBG("dhcp %p", dhcp);
244 dhcp_client = g_dhcp_client_new(G_DHCP_IPV4, index, &error);
245 if (error != G_DHCP_CLIENT_ERROR_NONE)
248 if (getenv("CONNMAN_DHCP_DEBUG"))
249 g_dhcp_client_set_debug(dhcp_client, dhcp_debug, "DHCP");
251 hostname = connman_utsname_get_hostname();
252 if (hostname != NULL)
253 g_dhcp_client_set_send(dhcp_client, G_DHCP_HOST_NAME, hostname);
255 g_dhcp_client_set_request(dhcp_client, G_DHCP_HOST_NAME);
256 g_dhcp_client_set_request(dhcp_client, G_DHCP_SUBNET);
257 g_dhcp_client_set_request(dhcp_client, G_DHCP_DNS_SERVER);
258 g_dhcp_client_set_request(dhcp_client, G_DHCP_DOMAIN_NAME);
259 g_dhcp_client_set_request(dhcp_client, G_DHCP_NTP_SERVER);
260 g_dhcp_client_set_request(dhcp_client, G_DHCP_ROUTER);
261 g_dhcp_client_set_request(dhcp_client, 252);
263 g_dhcp_client_register_event(dhcp_client,
264 G_DHCP_CLIENT_EVENT_LEASE_AVAILABLE,
265 lease_available_cb, dhcp);
267 g_dhcp_client_register_event(dhcp_client,
268 G_DHCP_CLIENT_EVENT_IPV4LL_AVAILABLE,
269 ipv4ll_available_cb, dhcp);
271 g_dhcp_client_register_event(dhcp_client,
272 G_DHCP_CLIENT_EVENT_LEASE_LOST, lease_lost_cb, dhcp);
274 g_dhcp_client_register_event(dhcp_client,
275 G_DHCP_CLIENT_EVENT_IPV4LL_LOST, ipv4ll_lost_cb, dhcp);
277 g_dhcp_client_register_event(dhcp_client,
278 G_DHCP_CLIENT_EVENT_NO_LEASE, no_lease_cb, dhcp);
280 dhcp->dhcp_client = dhcp_client;
282 return g_dhcp_client_start(dhcp_client);
285 static int dhcp_release(struct connman_dhcp *dhcp)
287 DBG("dhcp %p", dhcp);
289 g_dhcp_client_stop(dhcp->dhcp_client);
290 g_dhcp_client_unref(dhcp->dhcp_client);
295 static int dhcp_probe(struct connman_element *element)
297 struct connman_dhcp *dhcp;
299 DBG("element %p name %s", element, element->name);
301 dhcp = g_try_new0(struct connman_dhcp, 1);
305 dhcp->index = element->index;
306 dhcp->state = CONNMAN_DHCP_STATE_IDLE;
308 dhcp->element = element;
310 connman_element_set_data(element, dhcp);
317 static void dhcp_remove(struct connman_element *element)
319 struct connman_dhcp *dhcp = connman_element_get_data(element);
321 DBG("element %p name %s", element, element->name);
323 connman_element_set_data(element, NULL);
328 connman_element_unref(element);
331 static void dhcp_change(struct connman_element *element)
333 DBG("element %p name %s", element, element->name);
335 if (element->state == CONNMAN_ELEMENT_STATE_ERROR)
336 connman_element_set_error(element->parent,
337 CONNMAN_ELEMENT_ERROR_DHCP_FAILED);
340 static struct connman_driver dhcp_driver = {
342 .type = CONNMAN_ELEMENT_TYPE_DHCP,
343 .priority = CONNMAN_DRIVER_PRIORITY_LOW,
345 .remove = dhcp_remove,
346 .change = dhcp_change,
349 int __connman_dhcp_init(void)
351 return connman_driver_register(&dhcp_driver);
354 void __connman_dhcp_cleanup(void)
356 connman_driver_unregister(&dhcp_driver);