Add interface index and state variables
[framework/connectivity/connman.git] / src / iface.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007  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 <string.h>
27 #include <arpa/inet.h>
28
29 #include <glib.h>
30 #include <gdbus.h>
31
32 #include <hal/libhal.h>
33
34 #include "connman.h"
35
36 static GSList *drivers = NULL;
37
38 int connman_iface_register(struct connman_iface_driver *driver)
39 {
40         DBG("driver %p", driver);
41
42         drivers = g_slist_append(drivers, driver);
43
44         return 0;
45 }
46
47 void connman_iface_unregister(struct connman_iface_driver *driver)
48 {
49         DBG("driver %p", driver);
50
51         drivers = g_slist_remove(drivers, driver);
52 }
53
54 static GSList *interfaces = NULL;
55
56 int connman_iface_update(struct connman_iface *iface,
57                                         enum connman_iface_state state)
58 {
59         switch (state) {
60         case CONNMAN_IFACE_STATE_ACTIVE:
61                 if (iface->type == CONNMAN_IFACE_TYPE_80211) {
62                         if (iface->driver->scan)
63                                 iface->driver->scan(iface);
64
65                         if (iface->driver->connect)
66                                 iface->driver->connect(iface, NULL);
67                 }
68                 break;
69
70         case CONNMAN_IFACE_STATE_CONNECTED:
71                 __connman_dhcp_request(iface);
72                 break;
73
74         default:
75                 break;
76         }
77
78         iface->state = state;
79
80         return 0;
81 }
82
83 static void device_free(void *data)
84 {
85         struct connman_iface *iface = data;
86
87         DBG("iface %p", iface);
88
89         if (iface->driver && iface->driver->remove)
90                 iface->driver->remove(iface);
91
92         g_free(iface->path);
93         g_free(iface->udi);
94         g_free(iface->sysfs);
95         g_free(iface);
96 }
97
98 static int probe_device(LibHalContext *ctx,
99                         struct connman_iface_driver *driver, const char *udi)
100 {
101         DBusConnection *conn;
102         struct connman_iface *iface;
103         char *temp, *sysfs;
104         int err;
105
106         DBG("ctx %p driver %p udi %s", ctx, driver, udi);
107
108         if (!driver->probe)
109                 return -1;
110
111         iface = g_try_new0(struct connman_iface, 1);
112         if (iface == NULL)
113                 return -1;
114
115         temp = g_path_get_basename(udi);
116         iface->path = g_strdup_printf("%s/%s", CONNMAN_IFACE_BASEPATH, temp);
117         g_free(temp);
118
119         iface->udi = g_strdup(udi);
120
121         DBG("path %s", iface->path);
122
123         sysfs = libhal_device_get_property_string(ctx, udi,
124                                                 "linux.sysfs_path", NULL);
125         if (sysfs != NULL)
126                 iface->sysfs = g_strdup(sysfs);
127
128         iface->index = -1;
129
130         if (g_str_has_prefix(driver->capability, "net") == TRUE)
131                 iface->index = libhal_device_get_property_int(ctx, udi,
132                                                 "net.linux.ifindex", NULL);
133
134         iface->type = CONNMAN_IFACE_TYPE_UNKNOWN;
135         iface->flags = 0;
136         iface->state = CONNMAN_IFACE_STATE_UNKNOWN;
137
138         DBG("iface %p", iface);
139
140         err = driver->probe(iface);
141         if (err < 0) {
142                 device_free(iface);
143                 return -1;
144         }
145
146         iface->driver = driver;
147
148         conn = libhal_ctx_get_dbus_connection(ctx);
149
150         g_dbus_register_object(conn, iface->path, iface, device_free);
151
152         interfaces = g_slist_append(interfaces, iface);
153
154         if ((iface->flags & CONNMAN_IFACE_FLAG_IPV4) &&
155                                                 driver->get_ipv4) {
156                 driver->get_ipv4(iface, &iface->ipv4);
157
158                 DBG("address %s", inet_ntoa(iface->ipv4.address));
159         }
160
161         if (driver->activate)
162                 driver->activate(iface);
163
164         return 0;
165 }
166
167 static void device_added(LibHalContext *ctx, const char *udi)
168 {
169         GSList *list;
170
171         DBG("ctx %p udi %s", ctx, udi);
172
173         for (list = drivers; list; list = list->next) {
174                 struct connman_iface_driver *driver = list->data;
175
176                 if (driver->capability == NULL)
177                         continue;
178
179                 if (libhal_device_query_capability(ctx, udi,
180                                         driver->capability, NULL) == TRUE) {
181                         if (probe_device(ctx, driver, udi) == 0)
182                                 break;
183                 }
184         }
185 }
186
187 static void device_removed(LibHalContext *ctx, const char *udi)
188 {
189         DBusConnection *conn;
190         GSList *list;
191
192         DBG("ctx %p udi %s", ctx, udi);
193
194         conn = libhal_ctx_get_dbus_connection(ctx);
195
196         for (list = interfaces; list; list = list->next) {
197                 struct connman_iface *iface = list->data;
198
199                 if (strcmp(udi, iface->udi) == 0) {
200                         interfaces = g_slist_remove(interfaces, iface);
201                         g_dbus_unregister_object(conn, iface->path);
202                         break;
203                 }
204         }
205 }
206
207 static void probe_driver(LibHalContext *ctx,
208                                 struct connman_iface_driver *driver)
209 {
210         char **list;
211         int num;
212
213         DBG("ctx %p driver %p", ctx, driver);
214
215         list = libhal_find_device_by_capability(ctx,
216                                         driver->capability, &num, NULL);
217         if (list) {
218                 char **tmp = list;
219
220                 while (*tmp) {
221                         probe_device(ctx, driver, *tmp);
222                         tmp++;
223                 }
224
225                 libhal_free_string_array(list);
226         }
227 }
228
229 static void find_devices(LibHalContext *ctx)
230 {
231         GSList *list;
232
233         DBG("ctx %p", ctx);
234
235         for (list = drivers; list; list = list->next) {
236                 struct connman_iface_driver *driver = list->data;
237
238                 DBG("driver %p", driver);
239
240                 if (driver->capability == NULL)
241                         continue;
242
243                 probe_driver(ctx, driver);
244         }
245 }
246
247 static LibHalContext *hal_ctx = NULL;
248
249 static void hal_init(void *data)
250 {
251         DBusConnection *conn = data;
252
253         DBG("conn %p", conn);
254
255         if (hal_ctx != NULL)
256                 return;
257
258         hal_ctx = libhal_ctx_new();
259         if (hal_ctx == NULL)
260                 return;
261
262         if (libhal_ctx_set_dbus_connection(hal_ctx, conn) == FALSE) {
263                 libhal_ctx_free(hal_ctx);
264                 return;
265         }
266
267         if (libhal_ctx_init(hal_ctx, NULL) == FALSE) {
268                 libhal_ctx_free(hal_ctx);
269                 return ;
270         }
271
272         libhal_ctx_set_device_added(hal_ctx, device_added);
273         libhal_ctx_set_device_removed(hal_ctx, device_removed);
274
275         //libhal_ctx_set_device_new_capability(hal_ctx, new_capability);
276         //libhal_ctx_set_device_lost_capability(hal_ctx, lost_capability);
277
278         find_devices(hal_ctx);
279 }
280
281 static void hal_cleanup(void *data)
282 {
283         DBusConnection *conn = data;
284         GSList *list;
285
286         DBG("conn %p", conn);
287
288         if (hal_ctx == NULL)
289                 return;
290
291         for (list = interfaces; list; list = list->next) {
292                 struct connman_iface *iface = list->data;
293
294                 DBG("path %s", iface->path);
295
296                 g_dbus_unregister_object(conn, iface->path);
297         }
298
299         g_slist_free(interfaces);
300
301         interfaces = NULL;
302
303         libhal_ctx_shutdown(hal_ctx, NULL);
304
305         libhal_ctx_free(hal_ctx);
306
307         hal_ctx = NULL;
308 }
309
310 static DBusConnection *connection = NULL;
311 static guint hal_watch = 0;
312
313 int __connman_iface_init(DBusConnection *conn)
314 {
315         DBG("conn %p", conn);
316
317         connection = dbus_connection_ref(conn);
318         if (connection == NULL)
319                 return -1;
320
321         hal_init(connection);
322
323         hal_watch = g_dbus_add_watch(connection, "org.freedesktop.Hal",
324                                 hal_init, hal_cleanup, connection, NULL);
325
326         return 0;
327 }
328
329 void __connman_iface_cleanup(void)
330 {
331         DBG("conn %p", connection);
332
333         g_dbus_remove_watch(connection, hal_watch);
334
335         hal_cleanup(connection);
336
337         dbus_connection_unref(connection);
338 }