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