Add functions for handling path value
[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 struct connman_device {
32         struct connman_element element;
33         enum connman_device_type type;
34         enum connman_device_policy policy;
35         gboolean powered;
36         gboolean carrier;
37         gboolean scanning;
38         char *path;
39         char *interface;
40
41         struct connman_device_driver *driver;
42         void *driver_data;
43
44         GSList *networks;
45 };
46
47 static const char *type2string(enum connman_device_type type)
48 {
49         switch (type) {
50         case CONNMAN_DEVICE_TYPE_ETHERNET:
51                 return "ethernet";
52         case CONNMAN_DEVICE_TYPE_WIFI:
53                 return "wifi";
54         case CONNMAN_DEVICE_TYPE_WIMAX:
55                 return "wimax";
56         case CONNMAN_DEVICE_TYPE_MODEM:
57                 return "modem";
58         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
59                 return "bluetooth";
60         default:
61                 return NULL;
62         }
63 }
64
65 static const char *policy2string(enum connman_device_policy policy)
66 {
67         switch (policy) {
68         case CONNMAN_DEVICE_POLICY_IGNORE:
69                 return "ignore";
70         case CONNMAN_DEVICE_POLICY_AUTO:
71                 return "auto";
72         case CONNMAN_DEVICE_POLICY_OFF:
73                 return "off";
74         default:
75                 return NULL;
76         }
77 }
78
79 static int set_powered(struct connman_device *device, gboolean powered)
80 {
81         struct connman_device_driver *driver = device->driver;
82         int err;
83
84         DBG("device %p powered %d", device, powered);
85
86         if (!driver)
87                 return -EINVAL;
88
89         if (powered == TRUE) {
90                 if (driver->enable)
91                         err = driver->enable(device);
92                 else
93                         err = -EINVAL;
94         } else {
95                 if (driver->disable)
96                         err = driver->disable(device);
97                 else
98                         err = -EINVAL;
99         }
100
101         return err;
102 }
103
104 static DBusMessage *get_properties(DBusConnection *conn,
105                                         DBusMessage *msg, void *data)
106 {
107         struct connman_device *device = data;
108         DBusMessage *reply;
109         DBusMessageIter array, dict;
110         const char *str;
111
112         DBG("conn %p", conn);
113
114         reply = dbus_message_new_method_return(msg);
115         if (reply == NULL)
116                 return NULL;
117
118         dbus_message_iter_init_append(reply, &array);
119
120         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
121                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
122                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
123                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
124
125         str = type2string(device->type);
126         if (str != NULL)
127                 connman_dbus_dict_append_variant(&dict, "Type",
128                                                 DBUS_TYPE_STRING, &str);
129
130         if (device->interface != NULL)
131                 connman_dbus_dict_append_variant(&dict, "Interface",
132                                         DBUS_TYPE_STRING, &device->interface);
133
134         str = policy2string(device->policy);
135         if (str != NULL)
136                 connman_dbus_dict_append_variant(&dict, "Policy",
137                                                 DBUS_TYPE_STRING, &str);
138
139         connman_dbus_dict_append_variant(&dict, "Powered",
140                                         DBUS_TYPE_BOOLEAN, &device->powered);
141
142         if (device->driver && device->driver->scan)
143                 connman_dbus_dict_append_variant(&dict, "Scanning",
144                                         DBUS_TYPE_BOOLEAN, &device->scanning);
145
146         dbus_message_iter_close_container(&array, &dict);
147
148         return reply;
149 }
150
151 static DBusMessage *set_property(DBusConnection *conn,
152                                         DBusMessage *msg, void *data)
153 {
154         struct connman_device *device = data;
155         DBusMessageIter iter, value;
156         const char *name;
157
158         DBG("conn %p", conn);
159
160         if (dbus_message_iter_init(msg, &iter) == FALSE)
161                 return __connman_error_invalid_arguments(msg);
162
163         dbus_message_iter_get_basic(&iter, &name);
164         dbus_message_iter_next(&iter);
165         dbus_message_iter_recurse(&iter, &value);
166
167         if (__connman_security_check_privileges(msg) < 0)
168                 return __connman_error_permission_denied(msg);
169
170         if (g_str_equal(name, "Powered") == TRUE) {
171                 gboolean powered;
172                 int err;
173
174                 dbus_message_iter_get_basic(&value, &powered);
175
176                 if (device->powered == powered)
177                         return __connman_error_invalid_arguments(msg);
178
179                 err = set_powered(device, powered);
180                 if (err < 0 && err != -EINPROGRESS)
181                         return __connman_error_failed(msg);
182         }
183
184         __connman_element_store(&device->element);
185
186         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
187 }
188
189 static DBusMessage *create_network(DBusConnection *conn,
190                                         DBusMessage *msg, void *data)
191 {
192         DBG("conn %p", conn);
193
194         if (__connman_security_check_privileges(msg) < 0)
195                 return __connman_error_permission_denied(msg);
196
197         return __connman_error_invalid_arguments(msg);
198 }
199
200 static DBusMessage *remove_network(DBusConnection *conn,
201                                         DBusMessage *msg, void *data)
202 {
203         DBG("conn %p", conn);
204
205         if (__connman_security_check_privileges(msg) < 0)
206                 return __connman_error_permission_denied(msg);
207
208         return __connman_error_invalid_arguments(msg);
209 }
210
211 static DBusMessage *propose_scan(DBusConnection *conn,
212                                         DBusMessage *msg, void *data)
213 {
214         DBG("conn %p", conn);
215
216         return __connman_error_failed(msg);
217 }
218
219 static GDBusMethodTable device_methods[] = {
220         { "GetProperties", "",      "a{sv}", get_properties },
221         { "SetProperty",   "sv",    "",      set_property   },
222         { "CreateNetwork", "a{sv}", "o",     create_network },
223         { "RemoveNetwork", "o",     "",      remove_network },
224         { "ProposeScan",   "",      "",      propose_scan   },
225         { },
226 };
227
228 static GDBusSignalTable device_signals[] = {
229         { "PropertyChanged", "sv" },
230         { },
231 };
232
233 static DBusConnection *connection;
234
235 static int register_interface(struct connman_element *element)
236 {
237         struct connman_device *device = element->device;
238
239         g_dbus_unregister_interface(connection, element->path,
240                                                 CONNMAN_DEVICE_INTERFACE);
241
242         if (g_dbus_register_interface(connection, element->path,
243                                         CONNMAN_DEVICE_INTERFACE,
244                                         device_methods, device_signals,
245                                         NULL, device, NULL) == FALSE) {
246                 connman_error("Failed to register %s device", element->path);
247                 return -EIO;
248         }
249
250         return 0;
251 }
252
253 static void unregister_interface(struct connman_element *element)
254 {
255         g_dbus_unregister_interface(connection, element->path,
256                                                 CONNMAN_DEVICE_INTERFACE);
257 }
258
259 static GSList *driver_list = NULL;
260
261 static gint compare_priority(gconstpointer a, gconstpointer b)
262 {
263         const struct connman_device_driver *driver1 = a;
264         const struct connman_device_driver *driver2 = b;
265
266         return driver2->priority - driver1->priority;
267 }
268
269 /**
270  * connman_device_driver_register:
271  * @driver: device driver definition
272  *
273  * Register a new device driver
274  *
275  * Returns: %0 on success
276  */
277 int connman_device_driver_register(struct connman_device_driver *driver)
278 {
279         DBG("driver %p name %s", driver, driver->name);
280
281         driver_list = g_slist_insert_sorted(driver_list, driver,
282                                                         compare_priority);
283
284         //__connman_driver_rescan(&device_driver);
285
286         return 0;
287 }
288
289 /**
290  * connman_device_driver_unregister:
291  * @driver: device driver definition
292  *
293  * Remove a previously registered device driver
294  */
295 void connman_device_driver_unregister(struct connman_device_driver *driver)
296 {
297         DBG("driver %p name %s", driver, driver->name);
298
299         driver_list = g_slist_remove(driver_list, driver);
300 }
301
302 static void device_destruct(struct connman_element *element)
303 {
304         struct connman_device *device = element->device;
305
306         DBG("element %p name %s", element, element->name);
307
308         g_free(device->interface);
309 }
310
311 /**
312  * connman_device_create:
313  * @node: device node name (for example an address)
314  * @type: device type
315  *
316  * Allocate a new device of given #type and assign the #node name to it.
317  *
318  * Returns: a newly-allocated #connman_device structure
319  */
320 struct connman_device *connman_device_create(const char *node,
321                                                 enum connman_device_type type)
322 {
323         struct connman_device *device;
324
325         DBG("node %s type %d", node, type);
326
327         device = g_try_new0(struct connman_device, 1);
328         if (device == NULL)
329                 return NULL;
330
331         DBG("device %p", device);
332
333         device->element.name = g_strdup(node);
334         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
335         device->element.index = -1;
336
337         device->element.device = device;
338         device->element.destruct = device_destruct;
339
340         device->type = type;
341         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
342
343         return device;
344 }
345
346 /**
347  * connman_device_ref:
348  * @device: device structure
349  *
350  * Increase reference counter of device
351  */
352 struct connman_device *connman_device_ref(struct connman_device *device)
353 {
354         if (connman_element_ref(&device->element) == NULL)
355                 return NULL;
356
357         return device;
358 }
359
360 /**
361  * connman_device_unref:
362  * @device: device structure
363  *
364  * Decrease reference counter of device
365  */
366 void connman_device_unref(struct connman_device *device)
367 {
368         connman_element_unref(&device->element);
369 }
370
371 /**
372  * connman_device_set_path:
373  * @device: device structure
374  * @path: path name
375  *
376  * Set path name of device
377  */
378 void connman_device_set_path(struct connman_device *device, const char *path)
379 {
380         g_free(device->element.devpath);
381         device->element.devpath = g_strdup(path);
382
383         g_free(device->path);
384         device->path = g_strdup(path);
385 }
386
387 /**
388  * connman_device_get_path:
389  * @device: device structure
390  *
391  * Get path name of device
392  */
393 const char *connman_device_get_path(struct connman_device *device)
394 {
395         return device->path;
396 }
397
398 /**
399  * connman_device_set_index:
400  * @device: device structure
401  * @index: index number
402  *
403  * Set index number of device
404  */
405 void connman_device_set_index(struct connman_device *device, int index)
406 {
407         device->element.index = index;
408 }
409
410 /**
411  * connman_device_get_index:
412  * @device: device structure
413  *
414  * Get index number of device
415  */
416 int connman_device_get_index(struct connman_device *device)
417 {
418         return device->element.index;
419 }
420
421 /**
422  * connman_device_set_interface:
423  * @device: device structure
424  * @interface: interface name
425  *
426  * Set interface name of device
427  */
428 void connman_device_set_interface(struct connman_device *device,
429                                                         const char *interface)
430 {
431         g_free(device->element.devname);
432         device->element.devname = g_strdup(interface);
433
434         g_free(device->interface);
435         device->interface = g_strdup(interface);
436 }
437
438 /**
439  * connman_device_get_interface:
440  * @device: device structure
441  *
442  * Get interface name of device
443  */
444 const char *connman_device_get_interface(struct connman_device *device)
445 {
446         return device->interface;
447 }
448
449 /**
450  * connman_device_set_powered:
451  * @device: device structure
452  * @powered: powered state
453  *
454  * Change power state of device
455  */
456 int connman_device_set_powered(struct connman_device *device,
457                                                         gboolean powered)
458 {
459         DBusMessage *signal;
460         DBusMessageIter entry, value;
461         const char *key = "Powered";
462
463         DBG("driver %p powered %d", device, powered);
464
465         if (device->powered == powered)
466                 return -EALREADY;
467
468         device->powered = powered;
469
470         signal = dbus_message_new_signal(device->element.path,
471                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
472         if (signal == NULL)
473                 return 0;
474
475         dbus_message_iter_init_append(signal, &entry);
476
477         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
478
479         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
480                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
481         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
482         dbus_message_iter_close_container(&entry, &value);
483
484         g_dbus_send_message(connection, signal);
485
486         return 0;
487 }
488
489 /**
490  * connman_device_set_carrier:
491  * @device: device structure
492  * @carrier: carrier state
493  *
494  * Change carrier state of device (only for device without scanning)
495  */
496 int connman_device_set_carrier(struct connman_device *device,
497                                                         gboolean carrier)
498 {
499         DBG("driver %p carrier %d", device, carrier);
500
501         if (!device->driver)
502                 return -EINVAL;
503
504         if (device->driver->scan)
505                 return -EINVAL;
506
507         if (device->carrier == carrier)
508                 return -EALREADY;
509
510         device->carrier = carrier;
511
512         if (carrier == TRUE) {
513                 struct connman_element *element;
514
515                 element = connman_element_create(NULL);
516                 if (element != NULL) {
517                         element->type    = CONNMAN_ELEMENT_TYPE_DEVICE;
518                         element->subtype = CONNMAN_ELEMENT_SUBTYPE_NETWORK;
519                         element->index   = device->element.index;
520
521                         if (connman_element_register(element,
522                                                         &device->element) < 0)
523                                 connman_element_unref(element);
524                 }
525         } else
526                 connman_element_unregister_children(&device->element);
527
528         return 0;
529 }
530
531 /**
532  * connman_device_set_scanning:
533  * @device: device structure
534  * @scanning: scanning state
535  *
536  * Change scanning state of device
537  */
538 int connman_device_set_scanning(struct connman_device *device,
539                                                         gboolean scanning)
540 {
541         DBusMessage *signal;
542         DBusMessageIter entry, value;
543         const char *key = "Scanning";
544
545         DBG("driver %p scanning %d", device, scanning);
546
547         if (!device->driver)
548                 return -EINVAL;
549
550         if (!device->driver->scan)
551                 return -EINVAL;
552
553         if (device->scanning == scanning)
554                 return -EALREADY;
555
556         device->scanning = scanning;
557
558         signal = dbus_message_new_signal(device->element.path,
559                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
560         if (signal == NULL)
561                 return 0;
562
563         dbus_message_iter_init_append(signal, &entry);
564
565         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
566
567         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
568                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
569         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
570         dbus_message_iter_close_container(&entry, &value);
571
572         g_dbus_send_message(connection, signal);
573
574         return 0;
575 }
576
577 /**
578  * connman_device_register:
579  * @device: device structure
580  *
581  * Register device with the system
582  */
583 int connman_device_register(struct connman_device *device)
584 {
585         return connman_element_register(&device->element, NULL);
586 }
587
588 /**
589  * connman_device_unregister:
590  * @device: device structure
591  *
592  * Unregister device with the system
593  */
594 void connman_device_unregister(struct connman_device *device)
595 {
596         connman_element_unregister(&device->element);
597 }
598
599 /**
600  * connman_device_get_data:
601  * @device: device structure
602  *
603  * Get private device data pointer
604  */
605 void *connman_device_get_data(struct connman_device *device)
606 {
607         return device->driver_data;
608 }
609
610 /**
611  * connman_device_set_data:
612  * @device: device structure
613  * @data: data pointer
614  *
615  * Set private device data pointer
616  */
617 void connman_device_set_data(struct connman_device *device, void *data)
618 {
619         device->driver_data = data;
620 }
621
622 static void device_enable(struct connman_device *device)
623 {
624         DBG("device %p", device);
625
626         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
627                 return;
628
629         if (device->powered == TRUE)
630                 return;
631
632         if (device->driver->enable)
633                 device->driver->enable(device);
634 }
635
636 static void device_disable(struct connman_device *device)
637 {
638         DBG("device %p", device);
639
640         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
641                 return;
642
643         if (device->powered == FALSE)
644                 return;
645
646         if (device->driver->disable)
647                 device->driver->disable(device);
648 }
649
650 static gboolean match_driver(struct connman_device *device,
651                                         struct connman_device_driver *driver)
652 {
653         if (device->type == driver->type ||
654                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
655                 return TRUE;
656
657         return FALSE;
658 }
659
660 static int device_probe(struct connman_element *element)
661 {
662         struct connman_device *device = element->device;
663         GSList *list;
664         int err;
665
666         DBG("element %p name %s", element, element->name);
667
668         if (device == NULL)
669                 return -ENODEV;
670
671         err = register_interface(element);
672         if (err < 0)
673                 return err;
674
675         for (list = driver_list; list; list = list->next) {
676                 struct connman_device_driver *driver = list->data;
677
678                 if (match_driver(device, driver) == FALSE)
679                         continue;
680
681                 DBG("driver %p name %s", driver, driver->name);
682
683                 if (driver->probe(device) == 0) {
684                         device->driver = driver;
685                         device_enable(device);
686                         break;
687                 }
688         }
689
690         return 0;
691 }
692
693 static void device_remove(struct connman_element *element)
694 {
695         struct connman_device *device = element->device;
696
697         DBG("element %p name %s", element, element->name);
698
699         if (device == NULL)
700                 return;
701
702         unregister_interface(element);
703
704         if (device->driver) {
705                 device_disable(device);
706
707                 if (device->driver->remove)
708                         device->driver->remove(device);
709         }
710 }
711
712 static struct connman_driver device_driver = {
713         .name           = "device",
714         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
715         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
716         .probe          = device_probe,
717         .remove         = device_remove,
718 };
719
720 int __connman_device_init(void)
721 {
722         DBG("");
723
724         connection = connman_dbus_get_connection();
725
726         return connman_driver_register(&device_driver);
727 }
728
729 void __connman_device_cleanup(void)
730 {
731         DBG("");
732
733         connman_driver_unregister(&device_driver);
734
735         dbus_connection_unref(connection);
736 }