8b9a39b6c9d0024ed57ae6c09e032ce11a7c6f6a
[platform/upstream/connman.git] / src / dhcp.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <glib.h>
27
28 #include "connman.h"
29
30 struct connman_dhcp {
31         gint refcount;
32         int index;
33         enum connman_dhcp_state state;
34
35         struct connman_element *element;
36
37         struct connman_dhcp_driver *driver;
38         void *driver_data;
39 };
40
41 /**
42  * connman_dhcp_ref:
43  * @dhcp: DHCP structure
44  *
45  * Increase reference counter of DHCP
46  */
47 struct connman_dhcp *connman_dhcp_ref(struct connman_dhcp *dhcp)
48 {
49         g_atomic_int_inc(&dhcp->refcount);
50
51         return dhcp;
52 }
53
54 /**
55  * connman_dhcp_unref:
56  * @dhcp: DHCP structure
57  *
58  * Decrease reference counter of DHCP
59  */
60 void connman_dhcp_unref(struct connman_dhcp *dhcp)
61 {
62         if (g_atomic_int_dec_and_test(&dhcp->refcount) == TRUE)
63                 g_free(dhcp);
64 }
65
66 /**
67  * connman_dhcp_get_index:
68  * @dhcp: DHCP structure
69  *
70  * Get network index of DHCP
71  */
72 int connman_dhcp_get_index(struct connman_dhcp *dhcp)
73 {
74         return dhcp->index;
75 }
76
77 /**
78  * connman_dhcp_get_interface:
79  * @dhcp: DHCP structure
80  *
81  * Get network interface of DHCP
82  */
83 char *connman_dhcp_get_interface(struct connman_dhcp *dhcp)
84 {
85         return connman_inet_ifname(dhcp->index);
86 }
87
88 /**
89  * connman_dhcp_set_value:
90  * @dhcp: DHCP structure
91  * @key: unique identifier
92  * @value: string value
93  *
94  * Set string value for specific key
95  */
96 void connman_dhcp_set_value(struct connman_dhcp *dhcp,
97                                         const char *key, const char *value)
98 {
99         if (g_strcmp0(key, "Address") == 0) {
100                 g_free(dhcp->element->ipv4.address);
101                 dhcp->element->ipv4.address = g_strdup(value);
102         } else if (g_strcmp0(key, "Netmask") == 0) {
103                 g_free(dhcp->element->ipv4.netmask);
104                 dhcp->element->ipv4.netmask = g_strdup(value);
105         } else if (g_strcmp0(key, "Gateway") == 0) {
106                 g_free(dhcp->element->ipv4.gateway);
107                 dhcp->element->ipv4.gateway = g_strdup(value);
108         } else if (g_strcmp0(key, "Network") == 0) {
109                 g_free(dhcp->element->ipv4.network);
110                 dhcp->element->ipv4.network = g_strdup(value);
111         } else if (g_strcmp0(key, "Broadcast") == 0) {
112                 g_free(dhcp->element->ipv4.broadcast);
113                 dhcp->element->ipv4.broadcast = g_strdup(value);
114         } else if (g_strcmp0(key, "Nameserver") == 0) {
115                 g_free(dhcp->element->ipv4.nameserver);
116                 dhcp->element->ipv4.nameserver = g_strdup(value);
117         } else if (g_strcmp0(key, "Domainname") == 0) {
118                 __connman_utsname_set_domainname(value);
119         } else if (g_strcmp0(key, "Hostname") == 0) {
120                 __connman_utsname_set_hostname(value);
121         } else if (g_strcmp0(key, "Timeserver") == 0) {
122                 g_free(dhcp->element->ipv4.timeserver);
123                 dhcp->element->ipv4.timeserver = g_strdup(value);
124         } else if (g_strcmp0(key, "MTU") == 0) {
125         } else if (g_strcmp0(key, "PAC") == 0) {
126                 connman_info("PAC configuration %s", value);
127
128                 g_free(dhcp->element->ipv4.pac);
129                 dhcp->element->ipv4.pac = g_strdup(value);
130         }
131 }
132
133 /**
134  * connman_dhcp_bound:
135  * @dhcp: DHCP structure
136  *
137  * Report successful bound of the interface
138  */
139 void connman_dhcp_bound(struct connman_dhcp *dhcp)
140 {
141         struct connman_element *element;
142
143         DBG("dhcp %p", dhcp);
144
145         element = connman_element_create(NULL);
146         if (element == NULL)
147                 return;
148
149         element->type = CONNMAN_ELEMENT_TYPE_IPV4;
150         element->index = dhcp->index;
151
152         connman_element_update(dhcp->element);
153
154         if (connman_element_register(element, dhcp->element) < 0)
155                 connman_element_unref(element);
156 }
157
158 /**
159  * connman_dhcp_renew:
160  * @dhcp: DHCP structure
161  *
162  * Report successful renew of the interface
163  */
164 void connman_dhcp_renew(struct connman_dhcp *dhcp)
165 {
166         DBG("dhcp %p", dhcp);
167
168         connman_element_update(dhcp->element);
169 }
170
171 /**
172  * connman_dhcp_fail:
173  * @dhcp: DHCP structure
174  *
175  * Report DHCP failure of the interface
176  */
177 void connman_dhcp_fail(struct connman_dhcp *dhcp)
178 {
179         DBG("dhcp %p", dhcp);
180
181         connman_element_set_error(dhcp->element,
182                                         CONNMAN_ELEMENT_ERROR_FAILED);
183 }
184
185 /**
186  * connman_dhcp_get_data:
187  * @dhcp: DHCP structure
188  *
189  * Get private DHCP data pointer
190  */
191 void *connman_dhcp_get_data(struct connman_dhcp *dhcp)
192 {
193         return dhcp->driver_data;
194 }
195
196 /**
197  * connman_dhcp_set_data:
198  * @dhcp: DHCP structure
199  * @data: data pointer
200  *
201  * Set private DHCP data pointer
202  */
203 void connman_dhcp_set_data(struct connman_dhcp *dhcp, void *data)
204 {
205         dhcp->driver_data = data;
206 }
207
208 static GSList *driver_list = NULL;
209
210 static gint compare_priority(gconstpointer a, gconstpointer b)
211 {
212         const struct connman_dhcp_driver *driver1 = a;
213         const struct connman_dhcp_driver *driver2 = b;
214
215         return driver2->priority - driver1->priority;
216 }
217
218 /**
219  * connman_dhcp_driver_register:
220  * @driver: DHCP driver definition
221  *
222  * Register a new DHCP driver
223  *
224  * Returns: %0 on success
225  */
226 int connman_dhcp_driver_register(struct connman_dhcp_driver *driver)
227 {
228         DBG("driver %p name %s", driver, driver->name);
229
230         driver_list = g_slist_insert_sorted(driver_list, driver,
231                                                         compare_priority);
232
233         return 0;
234 }
235
236 /**
237  * connman_dhcp_driver_unregister:
238  * @driver: DHCP driver definition
239  *
240  * Remove a previously registered DHCP driver
241  */
242 void connman_dhcp_driver_unregister(struct connman_dhcp_driver *driver)
243 {
244         DBG("driver %p name %s", driver, driver->name);
245
246         driver_list = g_slist_remove(driver_list, driver);
247 }
248
249 static int dhcp_probe(struct connman_element *element)
250 {
251         struct connman_dhcp *dhcp;
252         GSList *list;
253
254         DBG("element %p name %s", element, element->name);
255
256         dhcp = g_try_new0(struct connman_dhcp, 1);
257         if (dhcp == NULL)
258                 return -ENOMEM;
259
260         dhcp->refcount = 1;
261         dhcp->index = element->index;
262         dhcp->state = CONNMAN_DHCP_STATE_IDLE;
263
264         dhcp->element = element;
265
266         connman_element_set_data(element, dhcp);
267
268         for (list = driver_list; list; list = list->next) {
269                 struct connman_dhcp_driver *driver = list->data;
270
271                 DBG("driver %p name %s", driver, driver->name);
272
273                 if (driver->request(dhcp) == 0) {
274                         dhcp->driver = driver;
275                         break;
276                 }
277         }
278
279         if (dhcp->driver == NULL) {
280                 connman_dhcp_unref(dhcp);
281                 return -ENOENT;
282         }
283
284         return 0;
285 }
286
287 static void dhcp_remove(struct connman_element *element)
288 {
289         struct connman_dhcp *dhcp = connman_element_get_data(element);
290
291         DBG("element %p name %s", element, element->name);
292
293         connman_element_set_data(element, NULL);
294
295         if (dhcp->driver) {
296                 dhcp->driver->release(dhcp);
297                 dhcp->driver = NULL;
298         }
299
300         connman_dhcp_unref(dhcp);
301 }
302
303 static void dhcp_change(struct connman_element *element)
304 {
305         DBG("element %p name %s", element, element->name);
306
307         if (element->state == CONNMAN_ELEMENT_STATE_ERROR)
308                 connman_element_set_error(element->parent,
309                                         CONNMAN_ELEMENT_ERROR_DHCP_FAILED);
310 }
311
312 static struct connman_driver dhcp_driver = {
313         .name           = "dhcp",
314         .type           = CONNMAN_ELEMENT_TYPE_DHCP,
315         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
316         .probe          = dhcp_probe,
317         .remove         = dhcp_remove,
318         .change         = dhcp_change,
319 };
320
321 int __connman_dhcp_init(void)
322 {
323         return connman_driver_register(&dhcp_driver);
324 }
325
326 void __connman_dhcp_cleanup(void)
327 {
328         connman_driver_unregister(&dhcp_driver);
329 }