Add Type property to generic device driver
[connman] / src / device.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2008  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 <errno.h>
27 #include <gdbus.h>
28
29 #include "connman.h"
30
31 static const char *type2string(enum connman_device_type type)
32 {
33         switch (type) {
34         case CONNMAN_DEVICE_TYPE_ETHERNET:
35                 return "ethernet";
36         case CONNMAN_DEVICE_TYPE_WIFI:
37                 return "wifi";
38         case CONNMAN_DEVICE_TYPE_WIMAX:
39                 return "wimax";
40         case CONNMAN_DEVICE_TYPE_MODEM:
41                 return "modem";
42         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
43                 return "bluetooth";
44         default:
45                 return NULL;
46         }
47 }
48
49 static int set_powered(struct connman_device *device, gboolean powered)
50 {
51         struct connman_device_driver *driver = device->driver;
52         int err;
53
54         DBG("device %p powered %d", device, powered);
55
56         if (!driver)
57                 return -EINVAL;
58
59         if (powered == TRUE) {
60                 if (driver->enable)
61                         err = driver->enable(device);
62                 else
63                         err = -EINVAL;
64         } else {
65                 if (driver->disable)
66                         err = driver->disable(device);
67                 else
68                         err = -EINVAL;
69         }
70
71         return err;
72 }
73
74 static DBusMessage *get_properties(DBusConnection *conn,
75                                         DBusMessage *msg, void *data)
76 {
77         struct connman_device *device = data;
78         DBusMessage *reply;
79         DBusMessageIter array, dict;
80         const char *str;
81
82         DBG("conn %p", conn);
83
84         reply = dbus_message_new_method_return(msg);
85         if (reply == NULL)
86                 return NULL;
87
88         dbus_message_iter_init_append(reply, &array);
89
90         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
91                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
92                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
93                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
94
95         str = type2string(device->type);
96         if (str != NULL)
97                 connman_dbus_dict_append_variant(&dict, "Type",
98                                                 DBUS_TYPE_STRING, &str);
99
100         connman_dbus_dict_append_variant(&dict, "Powered",
101                                         DBUS_TYPE_BOOLEAN, &device->powered);
102
103         if (device->driver && device->driver->scan)
104                 connman_dbus_dict_append_variant(&dict, "Scanning",
105                                         DBUS_TYPE_BOOLEAN, &device->scanning);
106
107         dbus_message_iter_close_container(&array, &dict);
108
109         return reply;
110 }
111
112 static DBusMessage *set_property(DBusConnection *conn,
113                                         DBusMessage *msg, void *data)
114 {
115         struct connman_device *device = data;
116         DBusMessageIter iter, value;
117         const char *name;
118
119         DBG("conn %p", conn);
120
121         if (dbus_message_iter_init(msg, &iter) == FALSE)
122                 return __connman_error_invalid_arguments(msg);
123
124         dbus_message_iter_get_basic(&iter, &name);
125         dbus_message_iter_next(&iter);
126         dbus_message_iter_recurse(&iter, &value);
127
128         if (__connman_security_check_privileges(msg) < 0)
129                 return __connman_error_permission_denied(msg);
130
131         if (g_str_equal(name, "Powered") == TRUE) {
132                 gboolean powered;
133                 int err;
134
135                 dbus_message_iter_get_basic(&value, &powered);
136
137                 if (device->powered == powered)
138                         return __connman_error_invalid_arguments(msg);
139
140                 err = set_powered(device, powered);
141                 if (err < 0 && err != -EINPROGRESS)
142                         return __connman_error_failed(msg);
143         }
144
145         __connman_element_store(device->element);
146
147         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
148 }
149
150 static DBusMessage *create_network(DBusConnection *conn,
151                                         DBusMessage *msg, void *data)
152 {
153         DBG("conn %p", conn);
154
155         if (__connman_security_check_privileges(msg) < 0)
156                 return __connman_error_permission_denied(msg);
157
158         return __connman_error_invalid_arguments(msg);
159 }
160
161 static DBusMessage *remove_network(DBusConnection *conn,
162                                         DBusMessage *msg, void *data)
163 {
164         DBG("conn %p", conn);
165
166         if (__connman_security_check_privileges(msg) < 0)
167                 return __connman_error_permission_denied(msg);
168
169         return __connman_error_invalid_arguments(msg);
170 }
171
172 static DBusMessage *propose_scan(DBusConnection *conn,
173                                         DBusMessage *msg, void *data)
174 {
175         DBG("conn %p", conn);
176
177         return __connman_error_failed(msg);
178 }
179
180 static GDBusMethodTable device_methods[] = {
181         { "GetProperties", "",      "a{sv}", get_properties },
182         { "SetProperty",   "sv",    "",      set_property   },
183         { "CreateNetwork", "a{sv}", "o",     create_network },
184         { "RemoveNetwork", "o",     "",      remove_network },
185         { "ProposeScan",   "",      "",      propose_scan   },
186         { },
187 };
188
189 static GDBusSignalTable device_signals[] = {
190         { "PropertyChanged", "sv" },
191         { },
192 };
193
194 static DBusConnection *connection;
195
196 static int register_interface(struct connman_element *element)
197 {
198         struct connman_device *device = connman_element_get_data(element);
199
200         g_dbus_unregister_interface(connection, element->path,
201                                                 CONNMAN_DEVICE_INTERFACE);
202
203         if (g_dbus_register_interface(connection, element->path,
204                                         CONNMAN_DEVICE_INTERFACE,
205                                         device_methods, device_signals,
206                                         NULL, device, NULL) == FALSE) {
207                 connman_error("Failed to register %s device", element->path);
208                 return -EIO;
209         }
210
211         return 0;
212 }
213
214 static void unregister_interface(struct connman_element *element)
215 {
216         g_dbus_unregister_interface(connection, element->path,
217                                                 CONNMAN_DEVICE_INTERFACE);
218 }
219
220 static GSList *driver_list = NULL;
221
222 static gint compare_priority(gconstpointer a, gconstpointer b)
223 {
224         const struct connman_device_driver *driver1 = a;
225         const struct connman_device_driver *driver2 = b;
226
227         return driver2->priority - driver1->priority;
228 }
229
230 /**
231  * connman_device_driver_register:
232  * @driver: device driver definition
233  *
234  * Register a new device driver
235  *
236  * Returns: %0 on success
237  */
238 int connman_device_driver_register(struct connman_device_driver *driver)
239 {
240         DBG("driver %p name %s", driver, driver->name);
241
242         driver_list = g_slist_insert_sorted(driver_list, driver,
243                                                         compare_priority);
244
245         //__connman_driver_rescan(&device_driver);
246
247         return 0;
248 }
249
250 /**
251  * connman_device_driver_unregister:
252  * @driver: device driver definition
253  *
254  * Remove a previously registered device driver
255  */
256 void connman_device_driver_unregister(struct connman_device_driver *driver)
257 {
258         DBG("driver %p name %s", driver, driver->name);
259
260         driver_list = g_slist_remove(driver_list, driver);
261 }
262
263 /**
264  * connman_device_set_powered:
265  * @device: device structure
266  *
267  * Change power state of device
268  */
269 int connman_device_set_powered(struct connman_device *device,
270                                                         gboolean powered)
271 {
272         DBusMessage *signal;
273         DBusMessageIter entry, value;
274         const char *key = "Powered";
275
276         DBG("driver %p powered %d", device, powered);
277
278         if (device->powered == powered)
279                 return -EALREADY;
280
281         device->powered = powered;
282
283         signal = dbus_message_new_signal(device->element->path,
284                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
285         if (signal == NULL)
286                 return 0;
287
288         dbus_message_iter_init_append(signal, &entry);
289
290         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
291
292         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
293                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
294         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
295         dbus_message_iter_close_container(&entry, &value);
296
297         g_dbus_send_message(connection, signal);
298
299         return 0;
300 }
301
302 /**
303  * connman_device_set_scanning:
304  * @device: device structure
305  *
306  * Change scanning state of device
307  */
308 int connman_device_set_scanning(struct connman_device *device,
309                                                         gboolean scanning)
310 {
311         DBusMessage *signal;
312         DBusMessageIter entry, value;
313         const char *key = "Scanning";
314
315         DBG("driver %p scanning %d", device, scanning);
316
317         if (!device->driver)
318                 return -EINVAL;
319
320         if (!device->driver->scan)
321                 return -EINVAL;
322
323         if (device->scanning == scanning)
324                 return -EALREADY;
325
326         device->scanning = scanning;
327
328         signal = dbus_message_new_signal(device->element->path,
329                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
330         if (signal == NULL)
331                 return 0;
332
333         dbus_message_iter_init_append(signal, &entry);
334
335         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
336
337         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
338                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
339         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
340         dbus_message_iter_close_container(&entry, &value);
341
342         g_dbus_send_message(connection, signal);
343
344         return 0;
345 }
346
347 static gboolean match_driver(struct connman_device *device,
348                                         struct connman_device_driver *driver)
349 {
350         if (device->element->subtype == driver->type ||
351                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
352                 return TRUE;
353
354         return FALSE;
355 }
356
357 static int device_probe(struct connman_element *element)
358 {
359         struct connman_device *device;
360         GSList *list;
361         int err;
362
363         DBG("element %p name %s", element, element->name);
364
365         if (element->subtype == CONNMAN_ELEMENT_SUBTYPE_NETWORK)
366                 return -ENODEV;
367
368         device = g_try_new0(struct connman_device, 1);
369         if (device == NULL)
370                 return -ENOMEM;
371
372         device->element = element;
373         device->type = element->subtype;
374
375         connman_element_set_data(element, device);
376
377         err = register_interface(element);
378         if (err < 0) {
379                 g_free(device);
380                 return err;
381         }
382
383         for (list = driver_list; list; list = list->next) {
384                 struct connman_device_driver *driver = list->data;
385
386                 if (match_driver(device, driver) == FALSE)
387                         continue;
388
389                 DBG("driver %p name %s", driver, driver->name);
390
391                 if (driver->probe(device) == 0) {
392                         device->driver = driver;
393                         break;
394                 }
395         }
396
397         return 0;
398 }
399
400 static void device_remove(struct connman_element *element)
401 {
402         struct connman_device *device = connman_element_get_data(element);
403
404         DBG("element %p name %s", element, element->name);
405
406         unregister_interface(element);
407
408         if (device->driver && device->driver->remove)
409                 device->driver->remove(device);
410
411         connman_element_set_data(element, NULL);
412
413         g_free(device);
414 }
415
416 static struct connman_driver device_driver = {
417         .name           = "device",
418         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
419         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
420         .probe          = device_probe,
421         .remove         = device_remove,
422 };
423
424 int __connman_device_init(void)
425 {
426         DBG("");
427
428         connection = connman_dbus_get_connection();
429
430         return connman_driver_register(&device_driver);
431 }
432
433 void __connman_device_cleanup(void)
434 {
435         DBG("");
436
437         connman_driver_unregister(&device_driver);
438
439         dbus_connection_unref(connection);
440 }