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