Add DHCP driver and element 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_interface:
68  * @dhcp: DHCP structure
69  *
70  * Get network interface of DHCP
71  */
72 char *connman_dhcp_get_interface(struct connman_dhcp *dhcp)
73 {
74         return connman_inet_ifname(dhcp->index);
75 }
76
77 /**
78  * connman_dhcp_bound:
79  * @dhcp: DHCP structure
80  *
81  * Report successful bound of the interface
82  */
83 void connman_dhcp_bound(struct connman_dhcp *dhcp)
84 {
85         DBG("dhcp %p", dhcp);
86 }
87
88 static GSList *driver_list = NULL;
89
90 static gint compare_priority(gconstpointer a, gconstpointer b)
91 {
92         const struct connman_dhcp_driver *driver1 = a;
93         const struct connman_dhcp_driver *driver2 = b;
94
95         return driver2->priority - driver1->priority;
96 }
97
98 /**
99  * connman_dhcp_driver_register:
100  * @driver: DHCP driver definition
101  *
102  * Register a new DHCP driver
103  *
104  * Returns: %0 on success
105  */
106 int connman_dhcp_driver_register(struct connman_dhcp_driver *driver)
107 {
108         DBG("driver %p name %s", driver, driver->name);
109
110         driver_list = g_slist_insert_sorted(driver_list, driver,
111                                                         compare_priority);
112
113         return 0;
114 }
115
116 /**
117  * connman_dhcp_driver_unregister:
118  * @driver: DHCP driver definition
119  *
120  * Remove a previously registered DHCP driver
121  */
122 void connman_dhcp_driver_unregister(struct connman_dhcp_driver *driver)
123 {
124         DBG("driver %p name %s", driver, driver->name);
125
126         driver_list = g_slist_remove(driver_list, driver);
127 }
128
129 static int dhcp_probe(struct connman_element *element)
130 {
131         struct connman_dhcp *dhcp;
132         GSList *list;
133
134         DBG("element %p name %s", element, element->name);
135
136         dhcp = g_try_new0(struct connman_dhcp, 1);
137         if (dhcp == NULL)
138                 return -ENOMEM;
139
140         dhcp->refcount = 1;
141         dhcp->index = element->index;
142         dhcp->state = CONNMAN_DHCP_STATE_IDLE;
143
144         dhcp->element = element;
145
146         connman_element_set_data(element, dhcp);
147
148         for (list = driver_list; list; list = list->next) {
149                 struct connman_dhcp_driver *driver = list->data;
150
151                 DBG("driver %p name %s", driver, driver->name);
152
153                 if (driver->request(dhcp) == 0) {
154                         dhcp->driver = driver;
155                         break;
156                 }
157         }
158
159         if (dhcp->driver == NULL) {
160                 connman_dhcp_unref(dhcp);
161                 return -ENOENT;
162         }
163
164         return 0;
165 }
166
167 static void dhcp_remove(struct connman_element *element)
168 {
169         struct connman_dhcp *dhcp = connman_element_get_data(element);
170
171         DBG("element %p name %s", element, element->name);
172
173         connman_element_set_data(element, NULL);
174
175         if (dhcp->driver) {
176                 dhcp->driver->release(dhcp);
177                 dhcp->driver = NULL;
178         }
179
180         connman_dhcp_unref(dhcp);
181 }
182
183 static struct connman_driver dhcp_driver = {
184         .name           = "dhcp",
185         .type           = CONNMAN_ELEMENT_TYPE_DHCP,
186         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
187         .probe          = dhcp_probe,
188         .remove         = dhcp_remove,
189 };
190
191 int __connman_dhcp_init(void)
192 {
193         return connman_driver_register(&dhcp_driver);
194 }
195
196 void __connman_dhcp_cleanup(void)
197 {
198         connman_driver_unregister(&dhcp_driver);
199 }