Add DHCP bound, renew and fail handling
[framework/connectivity/connman.git] / src / dhcp.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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_bound:
90  * @dhcp: DHCP structure
91  *
92  * Report successful bound of the interface
93  */
94 void connman_dhcp_bound(struct connman_dhcp *dhcp)
95 {
96         struct connman_element *element;
97
98         DBG("dhcp %p", dhcp);
99
100         element = connman_element_create(NULL);
101         if (element == NULL)
102                 return;
103
104         element->type = CONNMAN_ELEMENT_TYPE_IPV4;
105         element->index = dhcp->index;
106
107         connman_element_update(dhcp->element);
108
109         if (connman_element_register(element, dhcp->element) < 0)
110                 connman_element_unref(element);
111 }
112
113 /**
114  * connman_dhcp_renew:
115  * @dhcp: DHCP structure
116  *
117  * Report successful renew of the interface
118  */
119 void connman_dhcp_renew(struct connman_dhcp *dhcp)
120 {
121         DBG("dhcp %p", dhcp);
122
123         connman_element_update(dhcp->element);
124 }
125
126 /**
127  * connman_dhcp_fail:
128  * @dhcp: DHCP structure
129  *
130  * Report DHCP failure of the interface
131  */
132 void connman_dhcp_fail(struct connman_dhcp *dhcp)
133 {
134         DBG("dhcp %p", dhcp);
135
136         connman_element_set_error(dhcp->element,
137                                         CONNMAN_ELEMENT_ERROR_FAILED);
138 }
139
140 static GSList *driver_list = NULL;
141
142 static gint compare_priority(gconstpointer a, gconstpointer b)
143 {
144         const struct connman_dhcp_driver *driver1 = a;
145         const struct connman_dhcp_driver *driver2 = b;
146
147         return driver2->priority - driver1->priority;
148 }
149
150 /**
151  * connman_dhcp_driver_register:
152  * @driver: DHCP driver definition
153  *
154  * Register a new DHCP driver
155  *
156  * Returns: %0 on success
157  */
158 int connman_dhcp_driver_register(struct connman_dhcp_driver *driver)
159 {
160         DBG("driver %p name %s", driver, driver->name);
161
162         driver_list = g_slist_insert_sorted(driver_list, driver,
163                                                         compare_priority);
164
165         return 0;
166 }
167
168 /**
169  * connman_dhcp_driver_unregister:
170  * @driver: DHCP driver definition
171  *
172  * Remove a previously registered DHCP driver
173  */
174 void connman_dhcp_driver_unregister(struct connman_dhcp_driver *driver)
175 {
176         DBG("driver %p name %s", driver, driver->name);
177
178         driver_list = g_slist_remove(driver_list, driver);
179 }
180
181 static int dhcp_probe(struct connman_element *element)
182 {
183         struct connman_dhcp *dhcp;
184         GSList *list;
185
186         DBG("element %p name %s", element, element->name);
187
188         dhcp = g_try_new0(struct connman_dhcp, 1);
189         if (dhcp == NULL)
190                 return -ENOMEM;
191
192         dhcp->refcount = 1;
193         dhcp->index = element->index;
194         dhcp->state = CONNMAN_DHCP_STATE_IDLE;
195
196         dhcp->element = element;
197
198         connman_element_set_data(element, dhcp);
199
200         for (list = driver_list; list; list = list->next) {
201                 struct connman_dhcp_driver *driver = list->data;
202
203                 DBG("driver %p name %s", driver, driver->name);
204
205                 if (driver->request(dhcp) == 0) {
206                         dhcp->driver = driver;
207                         break;
208                 }
209         }
210
211         if (dhcp->driver == NULL) {
212                 connman_dhcp_unref(dhcp);
213                 return -ENOENT;
214         }
215
216         return 0;
217 }
218
219 static void dhcp_remove(struct connman_element *element)
220 {
221         struct connman_dhcp *dhcp = connman_element_get_data(element);
222
223         DBG("element %p name %s", element, element->name);
224
225         connman_element_set_data(element, NULL);
226
227         if (dhcp->driver) {
228                 dhcp->driver->release(dhcp);
229                 dhcp->driver = NULL;
230         }
231
232         connman_dhcp_unref(dhcp);
233 }
234
235 static void dhcp_change(struct connman_element *element)
236 {
237         DBG("element %p name %s", element, element->name);
238
239         if (element->state == CONNMAN_ELEMENT_STATE_ERROR)
240                 connman_element_set_error(element->parent,
241                                         CONNMAN_ELEMENT_ERROR_DHCP_FAILED);
242 }
243
244 static struct connman_driver dhcp_driver = {
245         .name           = "dhcp",
246         .type           = CONNMAN_ELEMENT_TYPE_DHCP,
247         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
248         .probe          = dhcp_probe,
249         .remove         = dhcp_remove,
250         .change         = dhcp_change,
251 };
252
253 int __connman_dhcp_init(void)
254 {
255         return connman_driver_register(&dhcp_driver);
256 }
257
258 void __connman_dhcp_cleanup(void)
259 {
260         connman_driver_unregister(&dhcp_driver);
261 }