Call disable and remove callbacks when unregistering a driver
[connman] / src / device.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 <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_mode mode;
35         enum connman_device_policy policy;
36         gboolean powered;
37         gboolean carrier;
38         gboolean scanning;
39         char *path;
40         char *interface;
41
42         struct connman_device_driver *driver;
43         void *driver_data;
44
45         GHashTable *networks;
46 };
47
48 static const char *type2description(enum connman_device_type type)
49 {
50         switch (type) {
51         case CONNMAN_DEVICE_TYPE_UNKNOWN:
52         case CONNMAN_DEVICE_TYPE_VENDOR:
53                 break;
54         case CONNMAN_DEVICE_TYPE_ETHERNET:
55                 return "Ethernet";
56         case CONNMAN_DEVICE_TYPE_WIFI:
57                 return "Wireless";
58         case CONNMAN_DEVICE_TYPE_WIMAX:
59                 return "WiMAX";
60         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
61                 return "Bluetooth";
62         case CONNMAN_DEVICE_TYPE_HSO:
63         case CONNMAN_DEVICE_TYPE_HUAWEI:
64                 return "Cellular";
65         }
66
67         return NULL;
68 }
69
70 static const char *type2string(enum connman_device_type type)
71 {
72         switch (type) {
73         case CONNMAN_DEVICE_TYPE_UNKNOWN:
74         case CONNMAN_DEVICE_TYPE_VENDOR:
75                 break;
76         case CONNMAN_DEVICE_TYPE_ETHERNET:
77                 return "ethernet";
78         case CONNMAN_DEVICE_TYPE_WIFI:
79                 return "wifi";
80         case CONNMAN_DEVICE_TYPE_WIMAX:
81                 return "wimax";
82         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
83                 return "bluetooth";
84         case CONNMAN_DEVICE_TYPE_HSO:
85         case CONNMAN_DEVICE_TYPE_HUAWEI:
86                 return "cellular";
87         }
88
89         return NULL;
90 }
91
92 static const char *policy2string(enum connman_device_policy policy)
93 {
94         switch (policy) {
95         case CONNMAN_DEVICE_POLICY_UNKNOWN:
96                 break;
97         case CONNMAN_DEVICE_POLICY_IGNORE:
98                 return "ignore";
99         case CONNMAN_DEVICE_POLICY_OFF:
100                 return "off";
101         case CONNMAN_DEVICE_POLICY_AUTO:
102                 return "auto";
103         case CONNMAN_DEVICE_POLICY_MANUAL:
104                 return "manual";
105         }
106
107         return NULL;
108 }
109
110 static enum connman_device_policy string2policy(const char *policy)
111 {
112         if (g_str_equal(policy, "ignore") == TRUE)
113                 return CONNMAN_DEVICE_POLICY_IGNORE;
114         else if (g_str_equal(policy, "off") == TRUE)
115                 return CONNMAN_DEVICE_POLICY_OFF;
116         else if (g_str_equal(policy, "auto") == TRUE)
117                 return CONNMAN_DEVICE_POLICY_AUTO;
118         else if (g_str_equal(policy, "manual") == TRUE)
119                 return CONNMAN_DEVICE_POLICY_MANUAL;
120         else
121                 return CONNMAN_DEVICE_POLICY_UNKNOWN;
122 }
123
124 static int set_powered(struct connman_device *device, gboolean powered)
125 {
126         struct connman_device_driver *driver = device->driver;
127         int err;
128
129         DBG("device %p powered %d", device, powered);
130
131         if (!driver)
132                 return -EINVAL;
133
134         if (powered == TRUE) {
135                 if (driver->enable)
136                         err = driver->enable(device);
137                 else
138                         err = -EINVAL;
139         } else {
140                 g_hash_table_remove_all(device->networks);
141
142                 if (driver->disable)
143                         err = driver->disable(device);
144                 else
145                         err = -EINVAL;
146         }
147
148         return err;
149 }
150
151 static int set_policy(DBusConnection *connection,
152                                 struct connman_device *device,
153                                         enum connman_device_policy policy)
154 {
155         DBusMessage *signal;
156         DBusMessageIter entry, value;
157         const char *str, *key = "Policy";
158         int err = 0;
159
160         DBG("device %p policy %d", device, policy);
161
162         if (device->policy == policy)
163                 return 0;
164
165         switch (policy) {
166         case CONNMAN_DEVICE_POLICY_UNKNOWN:
167                 return -EINVAL;
168         case CONNMAN_DEVICE_POLICY_IGNORE:
169                 break;
170         case CONNMAN_DEVICE_POLICY_OFF:
171                 if (device->powered == TRUE)
172                         err = set_powered(device, FALSE);
173                 break;
174         case CONNMAN_DEVICE_POLICY_AUTO:
175         case CONNMAN_DEVICE_POLICY_MANUAL:
176                 if (device->powered == FALSE)
177                         err = set_powered(device, TRUE);
178                 break;
179         }
180
181         if (err < 0)
182                 return err;
183
184         device->policy = policy;
185
186         signal = dbus_message_new_signal(device->element.path,
187                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
188         if (signal == NULL)
189                 return 0;
190
191         dbus_message_iter_init_append(signal, &entry);
192
193         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
194
195         str = policy2string(policy);
196
197         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
198                                         DBUS_TYPE_STRING_AS_STRING, &value);
199         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
200         dbus_message_iter_close_container(&entry, &value);
201
202         g_dbus_send_message(connection, signal);
203
204         return 0;
205 }
206
207 static void append_networks(struct connman_device *device,
208                                                 DBusMessageIter *entry)
209 {
210         DBusMessageIter value, iter;
211         const char *key = "Networks";
212
213         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
214
215         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
216                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
217                                                                 &value);
218
219         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
220                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
221         __connman_element_list((struct connman_element *) device,
222                                         CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
223         dbus_message_iter_close_container(&value, &iter);
224
225         dbus_message_iter_close_container(entry, &value);
226 }
227
228 static DBusMessage *get_properties(DBusConnection *conn,
229                                         DBusMessage *msg, void *data)
230 {
231         struct connman_device *device = data;
232         DBusMessage *reply;
233         DBusMessageIter array, dict, entry;
234         const char *str;
235
236         DBG("conn %p", conn);
237
238         reply = dbus_message_new_method_return(msg);
239         if (reply == NULL)
240                 return NULL;
241
242         dbus_message_iter_init_append(reply, &array);
243
244         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
245                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
246                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
247                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
248
249         str = type2description(device->type);
250         if (str != NULL && device->interface != NULL) {
251                 char *name = g_strdup_printf("%s (%s)", str, device->interface);
252                 if (name != NULL)
253                         connman_dbus_dict_append_variant(&dict, "Name",
254                                                 DBUS_TYPE_STRING, &name);
255                 g_free(name);
256         }
257
258         str = type2string(device->type);
259         if (str != NULL)
260                 connman_dbus_dict_append_variant(&dict, "Type",
261                                                 DBUS_TYPE_STRING, &str);
262
263         if (device->interface != NULL)
264                 connman_dbus_dict_append_variant(&dict, "Interface",
265                                         DBUS_TYPE_STRING, &device->interface);
266
267         str = policy2string(device->policy);
268         if (str != NULL)
269                 connman_dbus_dict_append_variant(&dict, "Policy",
270                                                 DBUS_TYPE_STRING, &str);
271
272         connman_dbus_dict_append_variant(&dict, "Powered",
273                                         DBUS_TYPE_BOOLEAN, &device->powered);
274
275         if (device->driver && device->driver->scan)
276                 connman_dbus_dict_append_variant(&dict, "Scanning",
277                                         DBUS_TYPE_BOOLEAN, &device->scanning);
278
279         switch (device->mode) {
280         case CONNMAN_DEVICE_MODE_UNKNOWN:
281         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
282                 break;
283         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
284         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
285                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
286                                                                 NULL, &entry);
287                 append_networks(device, &entry);
288                 dbus_message_iter_close_container(&dict, &entry);
289                 break;
290         }
291
292         dbus_message_iter_close_container(&array, &dict);
293
294         return reply;
295 }
296
297 static DBusMessage *set_property(DBusConnection *conn,
298                                         DBusMessage *msg, void *data)
299 {
300         struct connman_device *device = data;
301         DBusMessageIter iter, value;
302         const char *name;
303
304         DBG("conn %p", conn);
305
306         if (dbus_message_iter_init(msg, &iter) == FALSE)
307                 return __connman_error_invalid_arguments(msg);
308
309         dbus_message_iter_get_basic(&iter, &name);
310         dbus_message_iter_next(&iter);
311         dbus_message_iter_recurse(&iter, &value);
312
313         if (__connman_security_check_privileges(msg) < 0)
314                 return __connman_error_permission_denied(msg);
315
316         if (g_str_equal(name, "Powered") == TRUE) {
317                 gboolean powered;
318                 int err;
319
320                 dbus_message_iter_get_basic(&value, &powered);
321
322                 if (device->powered == powered)
323                         return __connman_error_invalid_arguments(msg);
324
325                 err = set_powered(device, powered);
326                 if (err < 0 && err != -EINPROGRESS)
327                         return __connman_error_failed(msg);
328         } else if (g_str_equal(name, "Policy") == TRUE) {
329                 enum connman_device_policy policy;
330                 const char *str;
331                 int err;
332
333                 dbus_message_iter_get_basic(&value, &str);
334                 policy = string2policy(str);
335                 if (policy == CONNMAN_DEVICE_POLICY_UNKNOWN)
336                         return __connman_error_invalid_arguments(msg);
337
338                 err = set_policy(conn, device, policy);
339                 if (err < 0)
340                         return __connman_error_failed(msg);
341         }
342
343         __connman_element_store(&device->element);
344
345         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
346 }
347
348 static DBusMessage *create_network(DBusConnection *conn,
349                                         DBusMessage *msg, void *data)
350 {
351         DBG("conn %p", conn);
352
353         if (__connman_security_check_privileges(msg) < 0)
354                 return __connman_error_permission_denied(msg);
355
356         return __connman_error_invalid_arguments(msg);
357 }
358
359 static DBusMessage *remove_network(DBusConnection *conn,
360                                         DBusMessage *msg, void *data)
361 {
362         DBG("conn %p", conn);
363
364         if (__connman_security_check_privileges(msg) < 0)
365                 return __connman_error_permission_denied(msg);
366
367         return __connman_error_invalid_arguments(msg);
368 }
369
370 static DBusMessage *propose_scan(DBusConnection *conn,
371                                         DBusMessage *msg, void *data)
372 {
373         struct connman_device *device = data;
374         int err;
375
376         DBG("conn %p", conn);
377
378         switch (device->mode) {
379         case CONNMAN_DEVICE_MODE_UNKNOWN:
380         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
381                 return __connman_error_not_supported(msg);
382         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
383         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
384                 break;
385         }
386
387         if (!device->driver || !device->driver->scan)
388                 return __connman_error_not_supported(msg);
389
390         err = device->driver->scan(device);
391         if (err < 0)
392                 return __connman_error_failed(msg);
393
394         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
395 }
396
397 static GDBusMethodTable device_methods[] = {
398         { "GetProperties", "",      "a{sv}", get_properties },
399         { "SetProperty",   "sv",    "",      set_property   },
400         { "CreateNetwork", "a{sv}", "o",     create_network },
401         { "RemoveNetwork", "o",     "",      remove_network },
402         { "ProposeScan",   "",      "",      propose_scan   },
403         { },
404 };
405
406 static GDBusSignalTable device_signals[] = {
407         { "PropertyChanged", "sv" },
408         { },
409 };
410
411 static DBusConnection *connection;
412
413 static void append_devices(DBusMessageIter *entry)
414 {
415         DBusMessageIter value, iter;
416         const char *key = "Devices";
417
418         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
419
420         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
421                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
422                                                                 &value);
423
424         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
425                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
426         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
427         dbus_message_iter_close_container(&value, &iter);
428
429         dbus_message_iter_close_container(entry, &value);
430 }
431
432 static void emit_devices_signal(void)
433 {
434         DBusMessage *signal;
435         DBusMessageIter entry;
436
437         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
438                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
439         if (signal == NULL)
440                 return;
441
442         dbus_message_iter_init_append(signal, &entry);
443
444         append_devices(&entry);
445
446         g_dbus_send_message(connection, signal);
447 }
448
449 static int register_interface(struct connman_element *element)
450 {
451         struct connman_device *device = element->device;
452
453         DBG("element %p name %s", element, element->name);
454
455         if (g_dbus_register_interface(connection, element->path,
456                                         CONNMAN_DEVICE_INTERFACE,
457                                         device_methods, device_signals,
458                                         NULL, device, NULL) == FALSE) {
459                 connman_error("Failed to register %s device", element->path);
460                 return -EIO;
461         }
462
463         emit_devices_signal();
464
465         return 0;
466 }
467
468 static void unregister_interface(struct connman_element *element)
469 {
470         DBG("element %p name %s", element, element->name);
471
472         emit_devices_signal();
473
474         g_dbus_unregister_interface(connection, element->path,
475                                                 CONNMAN_DEVICE_INTERFACE);
476 }
477
478 static void device_enable(struct connman_device *device)
479 {
480         DBG("device %p", device);
481
482         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE ||
483                                 device->policy == CONNMAN_DEVICE_POLICY_OFF)
484                 return;
485
486         if (device->powered == TRUE)
487                 return;
488
489         if (device->driver->enable)
490                 device->driver->enable(device);
491 }
492
493 static void device_disable(struct connman_device *device)
494 {
495         DBG("device %p", device);
496
497         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE)
498                 return;
499
500         if (device->powered == FALSE)
501                 return;
502
503         g_hash_table_remove_all(device->networks);
504
505         if (device->driver->disable)
506                 device->driver->disable(device);
507 }
508
509 static GSList *driver_list = NULL;
510
511 static gint compare_priority(gconstpointer a, gconstpointer b)
512 {
513         const struct connman_device_driver *driver1 = a;
514         const struct connman_device_driver *driver2 = b;
515
516         return driver2->priority - driver1->priority;
517 }
518
519 /**
520  * connman_device_driver_register:
521  * @driver: device driver definition
522  *
523  * Register a new device driver
524  *
525  * Returns: %0 on success
526  */
527 int connman_device_driver_register(struct connman_device_driver *driver)
528 {
529         DBG("driver %p name %s", driver, driver->name);
530
531         driver_list = g_slist_insert_sorted(driver_list, driver,
532                                                         compare_priority);
533
534         //__connman_driver_rescan(&device_driver);
535
536         return 0;
537 }
538
539 static void remove_driver(struct connman_element *element, gpointer user_data)
540 {
541         struct connman_device_driver *driver = user_data;
542
543         DBG("element %p name %s", element, element->name);
544
545         if (element->device == NULL)
546                 return;
547
548         if (element->device->driver == driver) {
549                 device_disable(element->device);
550
551                 if (driver->remove)
552                         driver->remove(element->device);
553
554                 element->device->driver = NULL;
555         }
556 }
557
558 /**
559  * connman_device_driver_unregister:
560  * @driver: device driver definition
561  *
562  * Remove a previously registered device driver
563  */
564 void connman_device_driver_unregister(struct connman_device_driver *driver)
565 {
566         DBG("driver %p name %s", driver, driver->name);
567
568         driver_list = g_slist_remove(driver_list, driver);
569
570         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
571                                                 remove_driver, driver);
572 }
573
574 static void unregister_network(gpointer data)
575 {
576         struct connman_network *network = data;
577
578         DBG("network %p", network);
579
580         connman_element_unregister((struct connman_element *) network);
581
582         connman_network_unref(network);
583 }
584
585 static void device_destruct(struct connman_element *element)
586 {
587         struct connman_device *device = element->device;
588
589         DBG("element %p name %s", element, element->name);
590
591         g_free(device->path);
592         g_free(device->interface);
593
594         g_hash_table_destroy(device->networks);
595         device->networks = NULL;
596 }
597
598 /**
599  * connman_device_create:
600  * @node: device node name (for example an address)
601  * @type: device type
602  *
603  * Allocate a new device of given #type and assign the #node name to it.
604  *
605  * Returns: a newly-allocated #connman_device structure
606  */
607 struct connman_device *connman_device_create(const char *node,
608                                                 enum connman_device_type type)
609 {
610         struct connman_device *device;
611
612         DBG("node %s type %d", node, type);
613
614         device = g_try_new0(struct connman_device, 1);
615         if (device == NULL)
616                 return NULL;
617
618         DBG("device %p", device);
619
620         device->element.refcount = 1;
621
622         device->element.name = g_strdup(node);
623         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
624         device->element.index = -1;
625
626         switch (type) {
627         case CONNMAN_DEVICE_TYPE_UNKNOWN:
628         case CONNMAN_DEVICE_TYPE_VENDOR:
629         case CONNMAN_DEVICE_TYPE_WIFI:
630         case CONNMAN_DEVICE_TYPE_WIMAX:
631         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
632         case CONNMAN_DEVICE_TYPE_HSO:
633         case CONNMAN_DEVICE_TYPE_HUAWEI:
634                 device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
635                 break;
636         case CONNMAN_DEVICE_TYPE_ETHERNET:
637                 device->element.subtype = CONNMAN_ELEMENT_SUBTYPE_ETHERNET;
638                 break;
639         }
640
641         device->element.device = device;
642         device->element.destruct = device_destruct;
643
644         device->type   = type;
645         device->mode   = CONNMAN_DEVICE_MODE_UNKNOWN;
646         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
647
648         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
649                                                 g_free, unregister_network);
650
651         return device;
652 }
653
654 /**
655  * connman_device_ref:
656  * @device: device structure
657  *
658  * Increase reference counter of device
659  */
660 struct connman_device *connman_device_ref(struct connman_device *device)
661 {
662         if (connman_element_ref(&device->element) == NULL)
663                 return NULL;
664
665         return device;
666 }
667
668 /**
669  * connman_device_unref:
670  * @device: device structure
671  *
672  * Decrease reference counter of device
673  */
674 void connman_device_unref(struct connman_device *device)
675 {
676         connman_element_unref(&device->element);
677 }
678
679 /**
680  * connman_device_set_path:
681  * @device: device structure
682  * @path: path name
683  *
684  * Set path name of device
685  */
686 void connman_device_set_path(struct connman_device *device, const char *path)
687 {
688         g_free(device->element.devpath);
689         device->element.devpath = g_strdup(path);
690
691         g_free(device->path);
692         device->path = g_strdup(path);
693 }
694
695 /**
696  * connman_device_get_path:
697  * @device: device structure
698  *
699  * Get path name of device
700  */
701 const char *connman_device_get_path(struct connman_device *device)
702 {
703         return device->path;
704 }
705
706 /**
707  * connman_device_set_index:
708  * @device: device structure
709  * @index: index number
710  *
711  * Set index number of device
712  */
713 void connman_device_set_index(struct connman_device *device, int index)
714 {
715         device->element.index = index;
716 }
717
718 /**
719  * connman_device_get_index:
720  * @device: device structure
721  *
722  * Get index number of device
723  */
724 int connman_device_get_index(struct connman_device *device)
725 {
726         return device->element.index;
727 }
728
729 /**
730  * connman_device_set_interface:
731  * @device: device structure
732  * @interface: interface name
733  *
734  * Set interface name of device
735  */
736 void connman_device_set_interface(struct connman_device *device,
737                                                         const char *interface)
738 {
739         g_free(device->element.devname);
740         device->element.devname = g_strdup(interface);
741
742         g_free(device->interface);
743         device->interface = g_strdup(interface);
744 }
745
746 /**
747  * connman_device_get_interface:
748  * @device: device structure
749  *
750  * Get interface name of device
751  */
752 const char *connman_device_get_interface(struct connman_device *device)
753 {
754         return device->interface;
755 }
756
757 /**
758  * connman_device_set_policy:
759  * @device: device structure
760  * @policy: power and connection policy
761  *
762  * Change power and connection policy of device
763  */
764 void connman_device_set_policy(struct connman_device *device,
765                                         enum connman_device_policy policy)
766 {
767         device->policy = policy;
768 }
769
770 /**
771  * connman_device_set_mode:
772  * @device: device structure
773  * @mode: network mode
774  *
775  * Change network mode of device
776  */
777 void connman_device_set_mode(struct connman_device *device,
778                                                 enum connman_device_mode mode)
779 {
780         device->mode = mode;
781 }
782
783 /**
784  * connman_device_set_powered:
785  * @device: device structure
786  * @powered: powered state
787  *
788  * Change power state of device
789  */
790 int connman_device_set_powered(struct connman_device *device,
791                                                 connman_bool_t powered)
792 {
793         DBusMessage *signal;
794         DBusMessageIter entry, value;
795         const char *key = "Powered";
796
797         DBG("driver %p powered %d", device, powered);
798
799         if (device->powered == powered)
800                 return -EALREADY;
801
802         device->powered = powered;
803
804         signal = dbus_message_new_signal(device->element.path,
805                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
806         if (signal == NULL)
807                 return 0;
808
809         dbus_message_iter_init_append(signal, &entry);
810
811         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
812
813         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
814                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
815         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
816         dbus_message_iter_close_container(&entry, &value);
817
818         g_dbus_send_message(connection, signal);
819
820         return 0;
821 }
822
823 /**
824  * connman_device_set_carrier:
825  * @device: device structure
826  * @carrier: carrier state
827  *
828  * Change carrier state of device (only for device without scanning)
829  */
830 int connman_device_set_carrier(struct connman_device *device,
831                                                 connman_bool_t carrier)
832 {
833         DBG("driver %p carrier %d", device, carrier);
834
835         switch (device->mode) {
836         case CONNMAN_DEVICE_MODE_UNKNOWN:
837         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
838         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
839                 return -EINVAL;
840         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
841                 break;
842         }
843
844         if (device->carrier == carrier)
845                 return -EALREADY;
846
847         device->carrier = carrier;
848
849         if (carrier == TRUE) {
850                 struct connman_element *element;
851
852                 element = connman_element_create(NULL);
853                 if (element != NULL) {
854                         element->type    = CONNMAN_ELEMENT_TYPE_DHCP;
855                         element->subtype = device->element.subtype;
856                         element->index   = device->element.index;
857
858                         if (connman_element_register(element,
859                                                         &device->element) < 0)
860                                 connman_element_unref(element);
861                 }
862         } else
863                 connman_element_unregister_children(&device->element);
864
865         return 0;
866 }
867
868 /**
869  * connman_device_set_scanning:
870  * @device: device structure
871  * @scanning: scanning state
872  *
873  * Change scanning state of device
874  */
875 int connman_device_set_scanning(struct connman_device *device,
876                                                 connman_bool_t scanning)
877 {
878         DBusMessage *signal;
879         DBusMessageIter entry, value;
880         const char *key = "Scanning";
881
882         DBG("driver %p scanning %d", device, scanning);
883
884         if (!device->driver || !device->driver->scan)
885                 return -EINVAL;
886
887         if (device->scanning == scanning)
888                 return -EALREADY;
889
890         device->scanning = scanning;
891
892         signal = dbus_message_new_signal(device->element.path,
893                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
894         if (signal == NULL)
895                 return 0;
896
897         dbus_message_iter_init_append(signal, &entry);
898
899         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
900
901         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
902                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
903         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
904         dbus_message_iter_close_container(&entry, &value);
905
906         g_dbus_send_message(connection, signal);
907
908         return 0;
909 }
910
911 /**
912  * connman_device_add_network:
913  * @device: device structure
914  * @network: network structure
915  *
916  * Add new network to the device
917  */
918 int connman_device_add_network(struct connman_device *device,
919                                         struct connman_network *network)
920 {
921         const char *identifier = connman_network_get_identifier(network);
922         int err;
923
924         DBG("device %p network %p", device, network);
925
926         switch (device->mode) {
927         case CONNMAN_DEVICE_MODE_UNKNOWN:
928         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
929                 return -EINVAL;
930         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
931         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
932                 break;
933         }
934
935         __connman_network_set_device(network, device);
936
937         err = connman_element_register((struct connman_element *) network,
938                                                         &device->element);
939         if (err < 0) {
940                 __connman_network_set_device(network, NULL);
941                 return err;
942         }
943
944         g_hash_table_insert(device->networks, g_strdup(identifier),
945                                                                 network);
946
947         return 0;
948 }
949
950 /**
951  * connman_device_get_network:
952  * @device: device structure
953  * @identifier: network identifier
954  *
955  * Get network for given identifier
956  */
957 struct connman_network *connman_device_get_network(struct connman_device *device,
958                                                         const char *identifier)
959 {
960         DBG("device %p identifier %s", device, identifier);
961
962         return g_hash_table_lookup(device->networks, identifier);
963 }
964
965 /**
966  * connman_device_remove_network:
967  * @device: device structure
968  * @identifier: network identifier
969  *
970  * Remove network for given identifier
971  */
972 int connman_device_remove_network(struct connman_device *device,
973                                                         const char *identifier)
974 {
975         DBG("device %p identifier %s", device, identifier);
976
977         g_hash_table_remove(device->networks, identifier);
978
979         return 0;
980 }
981
982 /**
983  * connman_device_register:
984  * @device: device structure
985  *
986  * Register device with the system
987  */
988 int connman_device_register(struct connman_device *device)
989 {
990         return connman_element_register(&device->element, NULL);
991 }
992
993 /**
994  * connman_device_unregister:
995  * @device: device structure
996  *
997  * Unregister device with the system
998  */
999 void connman_device_unregister(struct connman_device *device)
1000 {
1001         connman_element_unregister(&device->element);
1002 }
1003
1004 /**
1005  * connman_device_get_data:
1006  * @device: device structure
1007  *
1008  * Get private device data pointer
1009  */
1010 void *connman_device_get_data(struct connman_device *device)
1011 {
1012         return device->driver_data;
1013 }
1014
1015 /**
1016  * connman_device_set_data:
1017  * @device: device structure
1018  * @data: data pointer
1019  *
1020  * Set private device data pointer
1021  */
1022 void connman_device_set_data(struct connman_device *device, void *data)
1023 {
1024         device->driver_data = data;
1025 }
1026
1027 static gboolean match_driver(struct connman_device *device,
1028                                         struct connman_device_driver *driver)
1029 {
1030         if (device->type == driver->type ||
1031                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1032                 return TRUE;
1033
1034         return FALSE;
1035 }
1036
1037 static int device_probe(struct connman_element *element)
1038 {
1039         struct connman_device *device = element->device;
1040         GSList *list;
1041         int err;
1042
1043         DBG("element %p name %s", element, element->name);
1044
1045         if (device == NULL)
1046                 return -ENODEV;
1047
1048         for (list = driver_list; list; list = list->next) {
1049                 struct connman_device_driver *driver = list->data;
1050
1051                 if (match_driver(device, driver) == FALSE)
1052                         continue;
1053
1054                 DBG("driver %p name %s", driver, driver->name);
1055
1056                 if (driver->probe(device) == 0) {
1057                         device->driver = driver;
1058                         break;
1059                 }
1060         }
1061
1062         if (device->driver == NULL)
1063                 return -ENODEV;
1064
1065         err = register_interface(element);
1066         if (err < 0) {
1067                 if (device->driver->remove)
1068                         device->driver->remove(device);
1069                 return err;
1070         }
1071
1072         device_enable(device);
1073
1074         return 0;
1075 }
1076
1077 static void device_remove(struct connman_element *element)
1078 {
1079         struct connman_device *device = element->device;
1080
1081         DBG("element %p name %s", element, element->name);
1082
1083         if (device == NULL)
1084                 return;
1085
1086         if (device->driver == NULL)
1087                 return;
1088
1089         device_disable(device);
1090
1091         unregister_interface(element);
1092
1093         if (device->driver->remove)
1094                 device->driver->remove(device);
1095 }
1096
1097 static struct connman_driver device_driver = {
1098         .name           = "device",
1099         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1100         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1101         .probe          = device_probe,
1102         .remove         = device_remove,
1103 };
1104
1105 int __connman_device_init(void)
1106 {
1107         DBG("");
1108
1109         connection = connman_dbus_get_connection();
1110
1111         return connman_driver_register(&device_driver);
1112 }
1113
1114 void __connman_device_cleanup(void)
1115 {
1116         DBG("");
1117
1118         connman_driver_unregister(&device_driver);
1119
1120         dbus_connection_unref(connection);
1121 }