Add support for disconnecting networks first
[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         connman_bool_t powered;
37         connman_bool_t carrier;
38         connman_bool_t scanning;
39         connman_uint8_t priority;
40         char *name;
41         char *node;
42         char *interface;
43         unsigned int connections;
44
45         struct connman_device_driver *driver;
46         void *driver_data;
47
48         connman_bool_t registered;
49
50         GHashTable *networks;
51 };
52
53 static const char *type2description(enum connman_device_type type)
54 {
55         switch (type) {
56         case CONNMAN_DEVICE_TYPE_UNKNOWN:
57         case CONNMAN_DEVICE_TYPE_VENDOR:
58                 break;
59         case CONNMAN_DEVICE_TYPE_ETHERNET:
60                 return "Ethernet";
61         case CONNMAN_DEVICE_TYPE_WIFI:
62                 return "Wireless";
63         case CONNMAN_DEVICE_TYPE_WIMAX:
64                 return "WiMAX";
65         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
66                 return "Bluetooth";
67         case CONNMAN_DEVICE_TYPE_HSO:
68         case CONNMAN_DEVICE_TYPE_NOZOMI:
69         case CONNMAN_DEVICE_TYPE_HUAWEI:
70         case CONNMAN_DEVICE_TYPE_NOVATEL:
71                 return "Cellular";
72         }
73
74         return NULL;
75 }
76
77 static const char *type2string(enum connman_device_type type)
78 {
79         switch (type) {
80         case CONNMAN_DEVICE_TYPE_UNKNOWN:
81         case CONNMAN_DEVICE_TYPE_VENDOR:
82                 break;
83         case CONNMAN_DEVICE_TYPE_ETHERNET:
84                 return "ethernet";
85         case CONNMAN_DEVICE_TYPE_WIFI:
86                 return "wifi";
87         case CONNMAN_DEVICE_TYPE_WIMAX:
88                 return "wimax";
89         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
90                 return "bluetooth";
91         case CONNMAN_DEVICE_TYPE_HSO:
92         case CONNMAN_DEVICE_TYPE_HUAWEI:
93         case CONNMAN_DEVICE_TYPE_NOZOMI:
94         case CONNMAN_DEVICE_TYPE_NOVATEL:
95                 return "cellular";
96         }
97
98         return NULL;
99 }
100
101 static const char *policy2string(enum connman_device_policy policy)
102 {
103         switch (policy) {
104         case CONNMAN_DEVICE_POLICY_UNKNOWN:
105                 break;
106         case CONNMAN_DEVICE_POLICY_IGNORE:
107                 return "ignore";
108         case CONNMAN_DEVICE_POLICY_OFF:
109                 return "off";
110         case CONNMAN_DEVICE_POLICY_AUTO:
111                 return "auto";
112         case CONNMAN_DEVICE_POLICY_MANUAL:
113                 return "manual";
114         }
115
116         return NULL;
117 }
118
119 static enum connman_device_policy string2policy(const char *policy)
120 {
121         if (g_str_equal(policy, "ignore") == TRUE)
122                 return CONNMAN_DEVICE_POLICY_IGNORE;
123         else if (g_str_equal(policy, "off") == TRUE)
124                 return CONNMAN_DEVICE_POLICY_OFF;
125         else if (g_str_equal(policy, "auto") == TRUE)
126                 return CONNMAN_DEVICE_POLICY_AUTO;
127         else if (g_str_equal(policy, "manual") == TRUE)
128                 return CONNMAN_DEVICE_POLICY_MANUAL;
129         else
130                 return CONNMAN_DEVICE_POLICY_UNKNOWN;
131 }
132
133 static int set_powered(struct connman_device *device, connman_bool_t powered)
134 {
135         struct connman_device_driver *driver = device->driver;
136         int err;
137
138         DBG("device %p powered %d", device, powered);
139
140         if (!driver)
141                 return -EINVAL;
142
143         if (powered == TRUE) {
144                 if (driver->enable)
145                         err = driver->enable(device);
146                 else
147                         err = -EINVAL;
148         } else {
149                 g_hash_table_remove_all(device->networks);
150
151                 if (driver->disable)
152                         err = driver->disable(device);
153                 else
154                         err = -EINVAL;
155         }
156
157         return err;
158 }
159
160 static int set_policy(DBusConnection *connection,
161                                 struct connman_device *device,
162                                         enum connman_device_policy policy)
163 {
164         DBusMessage *signal;
165         DBusMessageIter entry, value;
166         const char *str, *key = "Policy";
167         int err = 0;
168
169         DBG("device %p policy %d", device, policy);
170
171         if (device->policy == policy)
172                 return 0;
173
174         switch (policy) {
175         case CONNMAN_DEVICE_POLICY_UNKNOWN:
176                 return -EINVAL;
177         case CONNMAN_DEVICE_POLICY_IGNORE:
178                 break;
179         case CONNMAN_DEVICE_POLICY_OFF:
180                 if (device->powered == TRUE)
181                         err = set_powered(device, FALSE);
182                 break;
183         case CONNMAN_DEVICE_POLICY_AUTO:
184         case CONNMAN_DEVICE_POLICY_MANUAL:
185                 if (device->powered == FALSE)
186                         err = set_powered(device, TRUE);
187                 break;
188         }
189
190         if (err < 0)
191                 return err;
192
193         device->policy = policy;
194
195         signal = dbus_message_new_signal(device->element.path,
196                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
197         if (signal == NULL)
198                 return 0;
199
200         dbus_message_iter_init_append(signal, &entry);
201
202         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
203
204         str = policy2string(policy);
205
206         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
207                                         DBUS_TYPE_STRING_AS_STRING, &value);
208         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
209         dbus_message_iter_close_container(&entry, &value);
210
211         g_dbus_send_message(connection, signal);
212
213         return 0;
214 }
215
216 static void append_networks(struct connman_device *device,
217                                                 DBusMessageIter *entry)
218 {
219         DBusMessageIter value, iter;
220         const char *key = "Networks";
221
222         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
223
224         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
225                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
226                                                                 &value);
227
228         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
229                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
230         __connman_element_list((struct connman_element *) device,
231                                         CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
232         dbus_message_iter_close_container(&value, &iter);
233
234         dbus_message_iter_close_container(entry, &value);
235 }
236
237 static DBusMessage *get_properties(DBusConnection *conn,
238                                         DBusMessage *msg, void *data)
239 {
240         struct connman_device *device = data;
241         DBusMessage *reply;
242         DBusMessageIter array, dict, entry;
243         const char *str;
244
245         DBG("conn %p", conn);
246
247         if (__connman_security_check_privilege(msg,
248                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
249                 return __connman_error_permission_denied(msg);
250
251         reply = dbus_message_new_method_return(msg);
252         if (reply == NULL)
253                 return NULL;
254
255         dbus_message_iter_init_append(reply, &array);
256
257         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
258                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
259                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
260                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
261
262         str = type2description(device->type);
263         if (str != NULL && device->interface != NULL) {
264                 char *name = g_strdup_printf("%s (%s)", str, device->interface);
265                 if (name != NULL)
266                         connman_dbus_dict_append_variant(&dict, "Name",
267                                                 DBUS_TYPE_STRING, &name);
268                 g_free(name);
269         }
270
271         str = type2string(device->type);
272         if (str != NULL)
273                 connman_dbus_dict_append_variant(&dict, "Type",
274                                                 DBUS_TYPE_STRING, &str);
275
276         if (device->interface != NULL)
277                 connman_dbus_dict_append_variant(&dict, "Interface",
278                                         DBUS_TYPE_STRING, &device->interface);
279
280         str = policy2string(device->policy);
281         if (str != NULL)
282                 connman_dbus_dict_append_variant(&dict, "Policy",
283                                                 DBUS_TYPE_STRING, &str);
284
285         if (device->priority > 0)
286                 connman_dbus_dict_append_variant(&dict, "Priority",
287                                         DBUS_TYPE_BYTE, &device->priority);
288
289         connman_dbus_dict_append_variant(&dict, "Powered",
290                                         DBUS_TYPE_BOOLEAN, &device->powered);
291
292         if (device->driver && device->driver->scan)
293                 connman_dbus_dict_append_variant(&dict, "Scanning",
294                                         DBUS_TYPE_BOOLEAN, &device->scanning);
295
296         switch (device->mode) {
297         case CONNMAN_DEVICE_MODE_UNKNOWN:
298         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
299                 break;
300         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
301         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
302                 dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
303                                                                 NULL, &entry);
304                 append_networks(device, &entry);
305                 dbus_message_iter_close_container(&dict, &entry);
306                 break;
307         }
308
309         dbus_message_iter_close_container(&array, &dict);
310
311         return reply;
312 }
313
314 static DBusMessage *set_property(DBusConnection *conn,
315                                         DBusMessage *msg, void *data)
316 {
317         struct connman_device *device = data;
318         DBusMessageIter iter, value;
319         const char *name;
320         int type;
321
322         DBG("conn %p", conn);
323
324         if (dbus_message_iter_init(msg, &iter) == FALSE)
325                 return __connman_error_invalid_arguments(msg);
326
327         dbus_message_iter_get_basic(&iter, &name);
328         dbus_message_iter_next(&iter);
329         dbus_message_iter_recurse(&iter, &value);
330
331         if (__connman_security_check_privilege(msg,
332                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
333                 return __connman_error_permission_denied(msg);
334
335         type = dbus_message_iter_get_arg_type(&value);
336
337         if (g_str_equal(name, "Powered") == TRUE) {
338                 connman_bool_t powered;
339                 int err;
340
341                 if (type != DBUS_TYPE_BOOLEAN)
342                         return __connman_error_invalid_arguments(msg);
343
344                 dbus_message_iter_get_basic(&value, &powered);
345
346                 if (device->powered == powered)
347                         return __connman_error_invalid_arguments(msg);
348
349                 err = set_powered(device, powered);
350                 if (err < 0 && err != -EINPROGRESS)
351                         return __connman_error_failed(msg);
352         } else if (g_str_equal(name, "Policy") == TRUE) {
353                 enum connman_device_policy policy;
354                 const char *str;
355                 int err;
356
357                 if (type != DBUS_TYPE_STRING)
358                         return __connman_error_invalid_arguments(msg);
359
360                 dbus_message_iter_get_basic(&value, &str);
361                 policy = string2policy(str);
362                 if (policy == CONNMAN_DEVICE_POLICY_UNKNOWN)
363                         return __connman_error_invalid_arguments(msg);
364
365                 err = set_policy(conn, device, policy);
366                 if (err < 0)
367                         return __connman_error_failed(msg);
368         } else if (g_str_equal(name, "Priority") == TRUE) {
369                 connman_uint8_t priority;
370
371                 if (type != DBUS_TYPE_BYTE)
372                         return __connman_error_invalid_arguments(msg);
373
374                 dbus_message_iter_get_basic(&value, &priority);
375
376                 device->priority = priority;
377         }
378
379         __connman_storage_save_device(device);
380
381         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
382 }
383
384 static DBusMessage *create_network(DBusConnection *conn,
385                                         DBusMessage *msg, void *data)
386 {
387         DBG("conn %p", conn);
388
389         if (__connman_security_check_privilege(msg,
390                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
391                 return __connman_error_permission_denied(msg);
392
393         return __connman_error_invalid_arguments(msg);
394 }
395
396 static DBusMessage *remove_network(DBusConnection *conn,
397                                         DBusMessage *msg, void *data)
398 {
399         DBG("conn %p", conn);
400
401         if (__connman_security_check_privilege(msg,
402                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
403                 return __connman_error_permission_denied(msg);
404
405         return __connman_error_invalid_arguments(msg);
406 }
407
408 static DBusMessage *propose_scan(DBusConnection *conn,
409                                         DBusMessage *msg, void *data)
410 {
411         struct connman_device *device = data;
412         int err;
413
414         DBG("conn %p", conn);
415
416         switch (device->mode) {
417         case CONNMAN_DEVICE_MODE_UNKNOWN:
418         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
419                 return __connman_error_not_supported(msg);
420         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
421         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
422                 break;
423         }
424
425         if (!device->driver || !device->driver->scan)
426                 return __connman_error_not_supported(msg);
427
428         if (device->powered == FALSE)
429                 return __connman_error_failed(msg);
430
431         err = device->driver->scan(device);
432         if (err < 0)
433                 return __connman_error_failed(msg);
434
435         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
436 }
437
438 static GDBusMethodTable device_methods[] = {
439         { "GetProperties", "",      "a{sv}", get_properties },
440         { "SetProperty",   "sv",    "",      set_property   },
441         { "CreateNetwork", "a{sv}", "o",     create_network },
442         { "RemoveNetwork", "o",     "",      remove_network },
443         { "ProposeScan",   "",      "",      propose_scan   },
444         { },
445 };
446
447 static GDBusSignalTable device_signals[] = {
448         { "PropertyChanged", "sv" },
449         { },
450 };
451
452 static DBusConnection *connection;
453
454 static void append_devices(DBusMessageIter *entry)
455 {
456         DBusMessageIter value, iter;
457         const char *key = "Devices";
458
459         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
460
461         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
462                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
463                                                                 &value);
464
465         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
466                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
467         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
468         dbus_message_iter_close_container(&value, &iter);
469
470         dbus_message_iter_close_container(entry, &value);
471 }
472
473 static void emit_devices_signal(void)
474 {
475         DBusMessage *signal;
476         DBusMessageIter entry;
477
478         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
479                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
480         if (signal == NULL)
481                 return;
482
483         dbus_message_iter_init_append(signal, &entry);
484
485         append_devices(&entry);
486
487         g_dbus_send_message(connection, signal);
488 }
489
490 static int register_interface(struct connman_element *element)
491 {
492         struct connman_device *device = element->device;
493
494         DBG("element %p name %s", element, element->name);
495
496         if (g_dbus_register_interface(connection, element->path,
497                                         CONNMAN_DEVICE_INTERFACE,
498                                         device_methods, device_signals,
499                                         NULL, device, NULL) == FALSE) {
500                 connman_error("Failed to register %s device", element->path);
501                 return -EIO;
502         }
503
504         device->registered = TRUE;
505
506         emit_devices_signal();
507
508         return 0;
509 }
510
511 static void unregister_interface(struct connman_element *element)
512 {
513         struct connman_device *device = element->device;
514
515         DBG("element %p name %s", element, element->name);
516
517         device->registered = FALSE;
518
519         emit_devices_signal();
520
521         g_dbus_unregister_interface(connection, element->path,
522                                                 CONNMAN_DEVICE_INTERFACE);
523 }
524
525 static void device_enable(struct connman_device *device)
526 {
527         DBG("device %p", device);
528
529         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE ||
530                                 device->policy == CONNMAN_DEVICE_POLICY_OFF)
531                 return;
532
533         if (device->powered == TRUE)
534                 return;
535
536         if (device->driver->enable)
537                 device->driver->enable(device);
538 }
539
540 static void device_disable(struct connman_device *device)
541 {
542         DBG("device %p", device);
543
544         if (device->policy == CONNMAN_DEVICE_POLICY_IGNORE)
545                 return;
546
547         if (device->powered == FALSE)
548                 return;
549
550         g_hash_table_remove_all(device->networks);
551
552         if (device->driver->disable)
553                 device->driver->disable(device);
554 }
555
556 static int setup_device(struct connman_device *device)
557 {
558         int err;
559
560         DBG("device %p", device);
561
562         err = register_interface(&device->element);
563         if (err < 0) {
564                 if (device->driver->remove)
565                         device->driver->remove(device);
566                 device->driver = NULL;
567                 return err;
568         }
569
570         device_enable(device);
571
572         return 0;
573 }
574
575 static void probe_driver(struct connman_element *element, gpointer user_data)
576 {
577         struct connman_device_driver *driver = user_data;
578
579         DBG("element %p name %s", element, element->name);
580
581         if (element->device == NULL)
582                 return;
583
584         if (element->device->driver != NULL)
585                 return;
586
587         if (driver->probe(element->device) < 0)
588                 return;
589
590         element->device->driver = driver;
591
592         setup_device(element->device);
593 }
594
595 static void remove_device(struct connman_device *device)
596 {
597         DBG("device %p", device);
598
599         device_disable(device);
600
601         unregister_interface(&device->element);
602
603         if (device->driver->remove)
604                 device->driver->remove(device);
605
606         device->driver = NULL;
607 }
608
609 static void remove_driver(struct connman_element *element, gpointer user_data)
610 {
611         struct connman_device_driver *driver = user_data;
612
613         DBG("element %p name %s", element, element->name);
614
615         if (element->device == NULL)
616                 return;
617
618         if (element->device->driver == driver)
619                 remove_device(element->device);
620 }
621
622 connman_bool_t __connman_device_has_driver(struct connman_device *device)
623 {
624         if (device == NULL || device->driver == NULL)
625                 return FALSE;
626
627         return device->registered;
628 }
629
630 static GSList *driver_list = NULL;
631
632 static gint compare_priority(gconstpointer a, gconstpointer b)
633 {
634         const struct connman_device_driver *driver1 = a;
635         const struct connman_device_driver *driver2 = b;
636
637         return driver2->priority - driver1->priority;
638 }
639
640 /**
641  * connman_device_driver_register:
642  * @driver: device driver definition
643  *
644  * Register a new device driver
645  *
646  * Returns: %0 on success
647  */
648 int connman_device_driver_register(struct connman_device_driver *driver)
649 {
650         DBG("driver %p name %s", driver, driver->name);
651
652         driver_list = g_slist_insert_sorted(driver_list, driver,
653                                                         compare_priority);
654
655         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
656                                                 probe_driver, driver);
657
658         return 0;
659 }
660
661 /**
662  * connman_device_driver_unregister:
663  * @driver: device driver definition
664  *
665  * Remove a previously registered device driver
666  */
667 void connman_device_driver_unregister(struct connman_device_driver *driver)
668 {
669         DBG("driver %p name %s", driver, driver->name);
670
671         driver_list = g_slist_remove(driver_list, driver);
672
673         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
674                                                 remove_driver, driver);
675 }
676
677 static void unregister_network(gpointer data)
678 {
679         struct connman_network *network = data;
680
681         DBG("network %p", network);
682
683         connman_element_unregister((struct connman_element *) network);
684
685         connman_network_unref(network);
686 }
687
688 static void device_destruct(struct connman_element *element)
689 {
690         struct connman_device *device = element->device;
691
692         DBG("element %p name %s", element, element->name);
693
694         g_free(device->node);
695         g_free(device->name);
696         g_free(device->interface);
697
698         g_hash_table_destroy(device->networks);
699         device->networks = NULL;
700 }
701
702 /**
703  * connman_device_create:
704  * @node: device node name (for example an address)
705  * @type: device type
706  *
707  * Allocate a new device of given #type and assign the #node name to it.
708  *
709  * Returns: a newly-allocated #connman_device structure
710  */
711 struct connman_device *connman_device_create(const char *node,
712                                                 enum connman_device_type type)
713 {
714         struct connman_device *device;
715         const char *str;
716
717         DBG("node %s type %d", node, type);
718
719         device = g_try_new0(struct connman_device, 1);
720         if (device == NULL)
721                 return NULL;
722
723         DBG("device %p", device);
724
725         __connman_element_initialize(&device->element);
726
727         device->element.name = g_strdup(node);
728         device->element.type = CONNMAN_ELEMENT_TYPE_DEVICE;
729
730         device->element.device = device;
731         device->element.destruct = device_destruct;
732
733         str = type2string(type);
734         if (str != NULL)
735                 connman_element_add_static_property(&device->element,
736                                         "Type", DBUS_TYPE_STRING, &str);
737
738         device->type   = type;
739         device->mode   = CONNMAN_DEVICE_MODE_UNKNOWN;
740         device->policy = CONNMAN_DEVICE_POLICY_AUTO;
741
742         switch (type) {
743         case CONNMAN_DEVICE_TYPE_UNKNOWN:
744         case CONNMAN_DEVICE_TYPE_VENDOR:
745                 device->priority = 0;
746                 break;
747         case CONNMAN_DEVICE_TYPE_ETHERNET:
748         case CONNMAN_DEVICE_TYPE_WIFI:
749                 device->priority = 100;
750                 break;
751         case CONNMAN_DEVICE_TYPE_WIMAX:
752                 device->priority = 20;
753                 break;
754         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
755                 device->priority = 50;
756                 break;
757         case CONNMAN_DEVICE_TYPE_HSO:
758         case CONNMAN_DEVICE_TYPE_NOZOMI:
759         case CONNMAN_DEVICE_TYPE_HUAWEI:
760         case CONNMAN_DEVICE_TYPE_NOVATEL:
761                 device->priority = 60;
762                 break;
763         }
764
765         device->networks = g_hash_table_new_full(g_str_hash, g_str_equal,
766                                                 g_free, unregister_network);
767
768         return device;
769 }
770
771 /**
772  * connman_device_ref:
773  * @device: device structure
774  *
775  * Increase reference counter of device
776  */
777 struct connman_device *connman_device_ref(struct connman_device *device)
778 {
779         if (connman_element_ref(&device->element) == NULL)
780                 return NULL;
781
782         return device;
783 }
784
785 /**
786  * connman_device_unref:
787  * @device: device structure
788  *
789  * Decrease reference counter of device
790  */
791 void connman_device_unref(struct connman_device *device)
792 {
793         connman_element_unref(&device->element);
794 }
795
796 /**
797  * connman_device_get_name:
798  * @device: device structure
799  *
800  * Get unique name of device
801  */
802 const char *connman_device_get_name(struct connman_device *device)
803 {
804         return device->element.name;
805 }
806
807 /**
808  * connman_device_get_path:
809  * @device: device structure
810  *
811  * Get path name of device
812  */
813 const char *connman_device_get_path(struct connman_device *device)
814 {
815         return device->element.path;
816 }
817
818 /**
819  * connman_device_set_index:
820  * @device: device structure
821  * @index: index number
822  *
823  * Set index number of device
824  */
825 void connman_device_set_index(struct connman_device *device, int index)
826 {
827         device->element.index = index;
828 }
829
830 /**
831  * connman_device_get_index:
832  * @device: device structure
833  *
834  * Get index number of device
835  */
836 int connman_device_get_index(struct connman_device *device)
837 {
838         return device->element.index;
839 }
840
841 /**
842  * connman_device_set_interface:
843  * @device: device structure
844  * @interface: interface name
845  *
846  * Set interface name of device
847  */
848 void connman_device_set_interface(struct connman_device *device,
849                                                         const char *interface)
850 {
851         g_free(device->element.devname);
852         device->element.devname = g_strdup(interface);
853
854         g_free(device->interface);
855         device->interface = g_strdup(interface);
856 }
857
858 /**
859  * connman_device_get_interface:
860  * @device: device structure
861  *
862  * Get interface name of device
863  */
864 const char *connman_device_get_interface(struct connman_device *device)
865 {
866         return device->interface;
867 }
868
869 /**
870  * connman_device_set_policy:
871  * @device: device structure
872  * @policy: power and connection policy
873  *
874  * Change power and connection policy of device
875  */
876 void connman_device_set_policy(struct connman_device *device,
877                                         enum connman_device_policy policy)
878 {
879         device->policy = policy;
880 }
881
882 /**
883  * connman_device_set_mode:
884  * @device: device structure
885  * @mode: network mode
886  *
887  * Change network mode of device
888  */
889 void connman_device_set_mode(struct connman_device *device,
890                                                 enum connman_device_mode mode)
891 {
892         device->mode = mode;
893 }
894
895 /**
896  * connman_device_get_mode:
897  * @device: device structure
898  *
899  * Get network mode of device
900  */
901 enum connman_device_mode connman_device_get_mode(struct connman_device *device)
902 {
903         return device->mode;
904 }
905
906 /**
907  * connman_device_set_powered:
908  * @device: device structure
909  * @powered: powered state
910  *
911  * Change power state of device
912  */
913 int connman_device_set_powered(struct connman_device *device,
914                                                 connman_bool_t powered)
915 {
916         DBusMessage *signal;
917         DBusMessageIter entry, value;
918         const char *key = "Powered";
919
920         DBG("driver %p powered %d", device, powered);
921
922         if (device->powered == powered)
923                 return -EALREADY;
924
925         device->powered = powered;
926
927         signal = dbus_message_new_signal(device->element.path,
928                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
929         if (signal == NULL)
930                 return 0;
931
932         dbus_message_iter_init_append(signal, &entry);
933
934         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
935
936         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
937                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
938         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &powered);
939         dbus_message_iter_close_container(&entry, &value);
940
941         g_dbus_send_message(connection, signal);
942
943         if (powered == FALSE)
944                 return 0;
945
946         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
947                 return 0;
948
949         if (device->driver->scan)
950                 device->driver->scan(device);
951
952         return 0;
953 }
954
955 /**
956  * connman_device_set_carrier:
957  * @device: device structure
958  * @carrier: carrier state
959  *
960  * Change carrier state of device (only for device without scanning)
961  */
962 int connman_device_set_carrier(struct connman_device *device,
963                                                 connman_bool_t carrier)
964 {
965         DBG("driver %p carrier %d", device, carrier);
966
967         switch (device->mode) {
968         case CONNMAN_DEVICE_MODE_UNKNOWN:
969         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
970         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
971                 return -EINVAL;
972         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
973                 break;
974         }
975
976         if (device->carrier == carrier)
977                 return -EALREADY;
978
979         device->carrier = carrier;
980
981         if (carrier == TRUE) {
982                 struct connman_element *element;
983
984                 element = connman_element_create(NULL);
985                 if (element != NULL) {
986                         element->type  = CONNMAN_ELEMENT_TYPE_DHCP;
987                         element->index = device->element.index;
988
989                         if (connman_element_register(element,
990                                                         &device->element) < 0)
991                                 connman_element_unref(element);
992                 }
993         } else
994                 connman_element_unregister_children(&device->element);
995
996         return 0;
997 }
998
999 void __connman_device_disconnect(struct connman_device *device)
1000 {
1001         GHashTableIter iter;
1002         gpointer key, value;
1003
1004         DBG("device %p", device);
1005
1006         g_hash_table_iter_init(&iter, device->networks);
1007
1008         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1009                 struct connman_network *network = value;
1010
1011                 if (connman_network_get_connected(network) == FALSE)
1012                         continue;
1013
1014                 __connman_network_disconnect(network);
1015         }
1016 }
1017
1018 static void connect_known_network(struct connman_device *device)
1019 {
1020         struct connman_network *network = NULL;
1021         GHashTableIter iter;
1022         gpointer key, value;
1023         unsigned int count = 0;
1024
1025         DBG("device %p", device);
1026
1027         g_hash_table_iter_init(&iter, device->networks);
1028
1029         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
1030                 connman_uint8_t old_priority, new_priority;
1031                 connman_uint8_t old_strength, new_strength;
1032
1033                 count++;
1034
1035                 if (connman_network_get_remember(value) == FALSE)
1036                         continue;
1037
1038                 if (network == NULL) {
1039                         network = value;
1040                         continue;
1041                 }
1042
1043                 old_priority = connman_network_get_uint8(network, "Priority");
1044                 new_priority = connman_network_get_uint8(value, "Priority");
1045
1046                 if (new_priority != old_priority) {
1047                         if (new_priority > old_priority)
1048                                 network = value;
1049                         continue;
1050                 }
1051
1052                 old_strength = connman_network_get_uint8(network, "Strength");
1053                 new_strength = connman_network_get_uint8(value, "Strength");
1054
1055                 if (new_strength > old_strength)
1056                         network = value;
1057         }
1058
1059         if (network != NULL) {
1060                 int err;
1061
1062                 err = connman_network_connect(network);
1063                 if (err == 0 || err == -EINPROGRESS)
1064                         return;
1065         }
1066
1067         if (count > 0)
1068                 return;
1069
1070         if (device->driver && device->driver->scan)
1071                 device->driver->scan(device);
1072 }
1073
1074 static void mark_network_unavailable(gpointer key, gpointer value,
1075                                                         gpointer user_data)
1076 {
1077         struct connman_network *network = value;
1078
1079         if (connman_network_get_remember(network) == TRUE)
1080                 return;
1081
1082         connman_network_set_available(network, FALSE);
1083 }
1084
1085 static gboolean remove_unavailable_network(gpointer key, gpointer value,
1086                                                         gpointer user_data)
1087 {
1088         struct connman_network *network = value;
1089
1090         if (connman_network_get_remember(network) == TRUE)
1091                 return FALSE;
1092
1093         if (connman_network_get_available(network) == TRUE)
1094                 return FALSE;
1095
1096         return TRUE;
1097 }
1098
1099 /**
1100  * connman_device_set_scanning:
1101  * @device: device structure
1102  * @scanning: scanning state
1103  *
1104  * Change scanning state of device
1105  */
1106 int connman_device_set_scanning(struct connman_device *device,
1107                                                 connman_bool_t scanning)
1108 {
1109         DBusMessage *signal;
1110         DBusMessageIter entry, value;
1111         const char *key = "Scanning";
1112
1113         DBG("driver %p scanning %d", device, scanning);
1114
1115         if (!device->driver || !device->driver->scan)
1116                 return -EINVAL;
1117
1118         if (device->scanning == scanning)
1119                 return -EALREADY;
1120
1121         device->scanning = scanning;
1122
1123         signal = dbus_message_new_signal(device->element.path,
1124                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
1125         if (signal == NULL)
1126                 return 0;
1127
1128         dbus_message_iter_init_append(signal, &entry);
1129
1130         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1131
1132         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1133                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
1134         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &scanning);
1135         dbus_message_iter_close_container(&entry, &value);
1136
1137         g_dbus_send_message(connection, signal);
1138
1139         if (scanning == TRUE) {
1140                 g_hash_table_foreach(device->networks,
1141                                         mark_network_unavailable, NULL);
1142                 return 0;
1143         }
1144
1145         g_hash_table_foreach_remove(device->networks,
1146                                         remove_unavailable_network, NULL);
1147
1148         if (device->connections > 0)
1149                 return 0;
1150
1151         if (device->policy != CONNMAN_DEVICE_POLICY_AUTO)
1152                 return 0;
1153
1154         connect_known_network(device);
1155
1156         return 0;
1157 }
1158
1159 /**
1160  * connman_device_set_string:
1161  * @device: device structure
1162  * @key: unique identifier
1163  * @value: string value
1164  *
1165  * Set string value for specific key
1166  */
1167 int connman_device_set_string(struct connman_device *device,
1168                                         const char *key, const char *value)
1169 {
1170         DBG("device %p key %s value %s", device, key, value);
1171
1172         if (g_str_equal(key, "Name") == TRUE) {
1173                 g_free(device->name);
1174                 device->name = g_strdup(value);
1175         } else if (g_str_equal(key, "Node") == TRUE) {
1176                 g_free(device->node);
1177                 device->node = g_strdup(value);
1178         }
1179
1180         return 0;
1181 }
1182
1183 /**
1184  * connman_device_get_string:
1185  * @device: device structure
1186  * @key: unique identifier
1187  *
1188  * Get string value for specific key
1189  */
1190 const char *connman_device_get_string(struct connman_device *device,
1191                                                         const char *key)
1192 {
1193         DBG("device %p key %s", device, key);
1194
1195         if (g_str_equal(key, "Name") == TRUE)
1196                 return device->name;
1197         else if (g_str_equal(key, "Node") == TRUE)
1198                 return device->node;
1199
1200         return NULL;
1201 }
1202
1203 static void set_offlinemode(struct connman_element *element, gpointer user_data)
1204 {
1205         struct connman_device *device = element->device;
1206         connman_bool_t offlinemode = GPOINTER_TO_UINT(user_data);
1207         connman_bool_t powered;
1208
1209         DBG("element %p name %s", element, element->name);
1210
1211         if (device == NULL)
1212                 return;
1213
1214         powered = (offlinemode == TRUE) ? FALSE : TRUE;
1215
1216         if (device->powered == powered)
1217                 return;
1218
1219         set_powered(device, powered);
1220 }
1221
1222 int __connman_device_set_offlinemode(connman_bool_t offlinemode)
1223 {
1224         DBG("offlinmode %d", offlinemode);
1225
1226         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_DEVICE,
1227                         set_offlinemode, GUINT_TO_POINTER(offlinemode));
1228
1229         return 0;
1230 }
1231
1232 void __connman_device_increase_connections(struct connman_device *device)
1233 {
1234         device->connections++;
1235 }
1236
1237 void __connman_device_decrease_connections(struct connman_device *device)
1238 {
1239         device->connections--;
1240 }
1241
1242 /**
1243  * connman_device_add_network:
1244  * @device: device structure
1245  * @network: network structure
1246  *
1247  * Add new network to the device
1248  */
1249 int connman_device_add_network(struct connman_device *device,
1250                                         struct connman_network *network)
1251 {
1252         const char *identifier = connman_network_get_identifier(network);
1253         int err;
1254
1255         DBG("device %p network %p", device, network);
1256
1257         switch (device->mode) {
1258         case CONNMAN_DEVICE_MODE_UNKNOWN:
1259         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1260                 return -EINVAL;
1261         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1262         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1263                 break;
1264         }
1265
1266         __connman_network_set_device(network, device);
1267
1268         __connman_storage_load_network(network);
1269
1270         err = connman_element_register((struct connman_element *) network,
1271                                                         &device->element);
1272         if (err < 0) {
1273                 __connman_network_set_device(network, NULL);
1274                 return err;
1275         }
1276
1277         g_hash_table_insert(device->networks, g_strdup(identifier),
1278                                                                 network);
1279
1280         return 0;
1281 }
1282
1283 /**
1284  * connman_device_get_network:
1285  * @device: device structure
1286  * @identifier: network identifier
1287  *
1288  * Get network for given identifier
1289  */
1290 struct connman_network *connman_device_get_network(struct connman_device *device,
1291                                                         const char *identifier)
1292 {
1293         DBG("device %p identifier %s", device, identifier);
1294
1295         return g_hash_table_lookup(device->networks, identifier);
1296 }
1297
1298 /**
1299  * connman_device_remove_network:
1300  * @device: device structure
1301  * @identifier: network identifier
1302  *
1303  * Remove network for given identifier
1304  */
1305 int connman_device_remove_network(struct connman_device *device,
1306                                                         const char *identifier)
1307 {
1308         DBG("device %p identifier %s", device, identifier);
1309
1310         g_hash_table_remove(device->networks, identifier);
1311
1312         return 0;
1313 }
1314
1315 /**
1316  * connman_device_register:
1317  * @device: device structure
1318  *
1319  * Register device with the system
1320  */
1321 int connman_device_register(struct connman_device *device)
1322 {
1323         __connman_storage_load_device(device);
1324
1325         switch (device->mode) {
1326         case CONNMAN_DEVICE_MODE_UNKNOWN:
1327         case CONNMAN_DEVICE_MODE_TRANSPORT_IP:
1328                 break;
1329         case CONNMAN_DEVICE_MODE_NETWORK_SINGLE:
1330         case CONNMAN_DEVICE_MODE_NETWORK_MULTIPLE:
1331                 __connman_storage_init_network(device);
1332                 break;
1333         }
1334
1335         return connman_element_register(&device->element, NULL);
1336 }
1337
1338 /**
1339  * connman_device_unregister:
1340  * @device: device structure
1341  *
1342  * Unregister device with the system
1343  */
1344 void connman_device_unregister(struct connman_device *device)
1345 {
1346         __connman_storage_save_device(device);
1347
1348         connman_element_unregister(&device->element);
1349 }
1350
1351 /**
1352  * connman_device_get_data:
1353  * @device: device structure
1354  *
1355  * Get private device data pointer
1356  */
1357 void *connman_device_get_data(struct connman_device *device)
1358 {
1359         return device->driver_data;
1360 }
1361
1362 /**
1363  * connman_device_set_data:
1364  * @device: device structure
1365  * @data: data pointer
1366  *
1367  * Set private device data pointer
1368  */
1369 void connman_device_set_data(struct connman_device *device, void *data)
1370 {
1371         device->driver_data = data;
1372 }
1373
1374 static gboolean match_driver(struct connman_device *device,
1375                                         struct connman_device_driver *driver)
1376 {
1377         if (device->type == driver->type ||
1378                         driver->type == CONNMAN_DEVICE_TYPE_UNKNOWN)
1379                 return TRUE;
1380
1381         return FALSE;
1382 }
1383
1384 static int device_probe(struct connman_element *element)
1385 {
1386         struct connman_device *device = element->device;
1387         GSList *list;
1388
1389         DBG("element %p name %s", element, element->name);
1390
1391         if (device == NULL)
1392                 return -ENODEV;
1393
1394         if (device->driver != NULL)
1395                 return -EALREADY;
1396
1397         for (list = driver_list; list; list = list->next) {
1398                 struct connman_device_driver *driver = list->data;
1399
1400                 if (match_driver(device, driver) == FALSE)
1401                         continue;
1402
1403                 DBG("driver %p name %s", driver, driver->name);
1404
1405                 if (driver->probe(device) == 0) {
1406                         device->driver = driver;
1407                         break;
1408                 }
1409         }
1410
1411         if (device->driver == NULL)
1412                 return -ENODEV;
1413
1414         return setup_device(device);
1415 }
1416
1417 static void device_remove(struct connman_element *element)
1418 {
1419         struct connman_device *device = element->device;
1420
1421         DBG("element %p name %s", element, element->name);
1422
1423         if (device == NULL)
1424                 return;
1425
1426         if (device->driver == NULL)
1427                 return;
1428
1429         remove_device(device);
1430 }
1431
1432 static struct connman_driver device_driver = {
1433         .name           = "device",
1434         .type           = CONNMAN_ELEMENT_TYPE_DEVICE,
1435         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1436         .probe          = device_probe,
1437         .remove         = device_remove,
1438 };
1439
1440 static int device_load(struct connman_device *device)
1441 {
1442         GKeyFile *keyfile;
1443         gchar *pathname, *data = NULL;
1444         gsize length;
1445         char *str;
1446         int val;
1447
1448         DBG("device %p", device);
1449
1450         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1451                                                         device->element.name);
1452         if (pathname == NULL)
1453                 return -ENOMEM;
1454
1455         keyfile = g_key_file_new();
1456
1457         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1458                 g_free(pathname);
1459                 return -ENOENT;
1460         }
1461
1462         g_free(pathname);
1463
1464         if (g_key_file_load_from_data(keyfile, data, length,
1465                                                         0, NULL) == FALSE) {
1466                 g_free(data);
1467                 return -EILSEQ;
1468         }
1469
1470         g_free(data);
1471
1472         str = g_key_file_get_string(keyfile, "Configuration", "Policy", NULL);
1473         if (str != NULL) {
1474                 device->policy = string2policy(str);
1475                 g_free(str);
1476         }
1477
1478         val = g_key_file_get_integer(keyfile, "Configuration",
1479                                                         "Priority", NULL);
1480         if (val > 0)
1481                 device->priority = val;
1482
1483         g_key_file_free(keyfile);
1484
1485         return 0;
1486 }
1487
1488 static int device_save(struct connman_device *device)
1489 {
1490         GKeyFile *keyfile;
1491         gchar *pathname, *data = NULL;
1492         gsize length;
1493         const char *str;
1494
1495         DBG("device %p", device);
1496
1497         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR,
1498                                                         device->element.name);
1499         if (pathname == NULL)
1500                 return -ENOMEM;
1501
1502         keyfile = g_key_file_new();
1503
1504         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1505                 goto update;
1506
1507         if (length > 0) {
1508                 if (g_key_file_load_from_data(keyfile, data, length,
1509                                                         0, NULL) == FALSE)
1510                         goto done;
1511         }
1512
1513         g_free(data);
1514
1515 update:
1516         str = policy2string(device->policy);
1517         if (str != NULL)
1518                 g_key_file_set_string(keyfile, "Configuration", "Policy", str);
1519
1520         if (device->priority > 0)
1521                 g_key_file_set_integer(keyfile, "Configuration",
1522                                                 "Priority", device->priority);
1523
1524         data = g_key_file_to_data(keyfile, &length, NULL);
1525
1526         g_file_set_contents(pathname, data, length, NULL);
1527
1528 done:
1529         g_free(data);
1530
1531         g_key_file_free(keyfile);
1532
1533         g_free(pathname);
1534
1535         return 0;
1536 }
1537
1538 static struct connman_storage device_storage = {
1539         .name           = "device",
1540         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1541         .device_load    = device_load,
1542         .device_save    = device_save,
1543 };
1544
1545 int __connman_device_init(void)
1546 {
1547         DBG("");
1548
1549         connection = connman_dbus_get_connection();
1550
1551         if (connman_storage_register(&device_storage) < 0)
1552                 connman_error("Failed to register device storage");
1553
1554         return connman_driver_register(&device_driver);
1555 }
1556
1557 void __connman_device_cleanup(void)
1558 {
1559         DBG("");
1560
1561         connman_driver_unregister(&device_driver);
1562
1563         connman_storage_unregister(&device_storage);
1564
1565         dbus_connection_unref(connection);
1566 }