Check connected state and improve disconnect
[connman] / src / network.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 <string.h>
27
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 struct connman_network {
33         struct connman_element element;
34         enum connman_network_type type;
35         enum connman_network_protocol protocol;
36         connman_bool_t connected;
37         connman_bool_t remember;
38         connman_uint8_t strength;
39         char *identifier;
40         char *name;
41         char *node;
42
43         struct connman_network_driver *driver;
44         void *driver_data;
45
46         connman_bool_t registered;
47
48         struct connman_device *device;
49
50         struct {
51                 void *ssid;
52                 int ssid_len;
53                 char *mode;
54                 char *security;
55                 char *passphrase;
56         } wifi;
57 };
58
59 static DBusMessage *get_properties(DBusConnection *conn,
60                                         DBusMessage *msg, void *data)
61 {
62         struct connman_network *network = data;
63         DBusMessage *reply;
64         DBusMessageIter array, dict;
65
66         DBG("conn %p", conn);
67
68         reply = dbus_message_new_method_return(msg);
69         if (reply == NULL)
70                 return NULL;
71
72         dbus_message_iter_init_append(reply, &array);
73
74         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
75                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
76                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
77                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
78
79         if (network->device) {
80                 const char *path = connman_device_get_path(network->device);
81                 if (path != NULL)
82                         connman_dbus_dict_append_variant(&dict, "Device",
83                                                 DBUS_TYPE_OBJECT_PATH, &path);
84         }
85
86         if (network->name != NULL)
87                 connman_dbus_dict_append_variant(&dict, "Name",
88                                         DBUS_TYPE_STRING, &network->name);
89
90         connman_dbus_dict_append_variant(&dict, "Connected",
91                                 DBUS_TYPE_BOOLEAN, &network->connected);
92
93         connman_dbus_dict_append_variant(&dict, "Remember",
94                                 DBUS_TYPE_BOOLEAN, &network->remember);
95
96         if (network->strength > 0)
97                 connman_dbus_dict_append_variant(&dict, "Strength",
98                                         DBUS_TYPE_BYTE, &network->strength);
99
100         if (network->wifi.ssid != NULL && network->wifi.ssid_len > 0)
101                 connman_dbus_dict_append_array(&dict, "WiFi.SSID",
102                                 DBUS_TYPE_BYTE, &network->wifi.ssid,
103                                                 network->wifi.ssid_len);
104
105         if (network->wifi.mode != NULL)
106                 connman_dbus_dict_append_variant(&dict, "WiFi.Mode",
107                                 DBUS_TYPE_STRING, &network->wifi.mode);
108
109         if (network->wifi.security != NULL)
110                 connman_dbus_dict_append_variant(&dict, "WiFi.Security",
111                                 DBUS_TYPE_STRING, &network->wifi.security);
112
113         if (network->wifi.passphrase != NULL)
114                 connman_dbus_dict_append_variant(&dict, "WiFi.Passphrase",
115                                 DBUS_TYPE_STRING, &network->wifi.passphrase);
116
117         dbus_message_iter_close_container(&array, &dict);
118
119         return reply;
120 }
121
122 static DBusMessage *set_property(DBusConnection *conn,
123                                         DBusMessage *msg, void *data)
124 {
125         struct connman_network *network = data;
126         DBusMessageIter iter, value;
127         const char *name;
128
129         DBG("conn %p", conn);
130
131         if (dbus_message_iter_init(msg, &iter) == FALSE)
132                 return __connman_error_invalid_arguments(msg);
133
134         dbus_message_iter_get_basic(&iter, &name);
135         dbus_message_iter_next(&iter);
136         dbus_message_iter_recurse(&iter, &value);
137
138         if (__connman_security_check_privileges(msg) < 0)
139                 return __connman_error_permission_denied(msg);
140
141         if (g_str_equal(name, "Remember") == TRUE) {
142                 connman_bool_t remember;
143
144                 dbus_message_iter_get_basic(&value, &remember);
145
146                 if (network->remember == remember)
147                         return __connman_error_invalid_arguments(msg);
148         } else if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
149                 const char *passphrase;
150
151                 dbus_message_iter_get_basic(&value, &passphrase);
152
153                 g_free(network->wifi.passphrase);
154                 network->wifi.passphrase = g_strdup(passphrase);
155         }
156
157         __connman_storage_save_network(network);
158
159         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
160 }
161
162 static DBusMessage *do_connect(DBusConnection *conn,
163                                         DBusMessage *msg, void *data)
164 {
165         struct connman_network *network = data;
166         int err;
167
168         DBG("conn %p", conn);
169
170         if (network->connected == TRUE)
171                 return __connman_error_failed(msg);
172
173         if (network->driver && network->driver->connect) {
174                 err = network->driver->connect(network);
175                 if (err < 0 && err != -EINPROGRESS)
176                         return __connman_error_failed(msg);
177         } else
178                 network->connected = TRUE;
179
180         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
181 }
182
183 static DBusMessage *do_disconnect(DBusConnection *conn,
184                                         DBusMessage *msg, void *data)
185 {
186         struct connman_network *network = data;
187         int err;
188
189         DBG("conn %p", conn);
190
191         if (network->connected == FALSE)
192                 return __connman_error_failed(msg);
193
194         connman_element_unregister_children(&network->element);
195
196         if (network->driver && network->driver->disconnect) {
197                 err = network->driver->disconnect(network);
198                 if (err < 0 && err != -EINPROGRESS)
199                         return __connman_error_failed(msg);
200         } else
201                 network->connected = FALSE;
202
203         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
204 }
205
206 static GDBusMethodTable network_methods[] = {
207         { "GetProperties", "",   "a{sv}", get_properties },
208         { "SetProperty",   "sv", "",      set_property   },
209         { "Connect",       "",   "",      do_connect     },
210         { "Disconnect",    "",   "",      do_disconnect  },
211         { },
212 };
213
214 static GDBusSignalTable network_signals[] = {
215         { "PropertyChanged", "sv" },
216         { },
217 };
218
219 static DBusConnection *connection;
220
221 static void emit_networks_signal(void)
222 {
223 }
224
225 static int register_interface(struct connman_element *element)
226 {
227         struct connman_network *network = element->network;
228
229         DBG("element %p name %s", element, element->name);
230
231         if (g_dbus_register_interface(connection, element->path,
232                                         CONNMAN_NETWORK_INTERFACE,
233                                         network_methods, network_signals,
234                                         NULL, network, NULL) == FALSE) {
235                 connman_error("Failed to register %s network", element->path);
236                 return -EIO;
237         }
238
239         network->registered = TRUE;
240
241         emit_networks_signal();
242
243         return 0;
244 }
245
246 static void unregister_interface(struct connman_element *element)
247 {
248         struct connman_network * network = element->network;
249
250         DBG("element %p name %s", element, element->name);
251
252         network->registered = FALSE;
253
254         emit_networks_signal();
255
256         g_dbus_unregister_interface(connection, element->path,
257                                                 CONNMAN_NETWORK_INTERFACE);
258 }
259
260 connman_bool_t __connman_network_has_driver(struct connman_network *network)
261 {
262         if (network == NULL || network->driver == NULL)
263                 return FALSE;
264
265         return network->registered;
266 }
267
268 static GSList *driver_list = NULL;
269
270 static gint compare_priority(gconstpointer a, gconstpointer b)
271 {
272         const struct connman_network_driver *driver1 = a;
273         const struct connman_network_driver *driver2 = b;
274
275         return driver2->priority - driver1->priority;
276 }
277
278 /**
279  * connman_network_driver_register:
280  * @driver: network driver definition
281  *
282  * Register a new network driver
283  *
284  * Returns: %0 on success
285  */
286 int connman_network_driver_register(struct connman_network_driver *driver)
287 {
288         DBG("driver %p name %s", driver, driver->name);
289
290         driver_list = g_slist_insert_sorted(driver_list, driver,
291                                                         compare_priority);
292
293         return 0;
294 }
295
296 /**
297  * connman_network_driver_unregister:
298  * @driver: network driver definition
299  *
300  * Remove a previously registered network driver
301  */
302 void connman_network_driver_unregister(struct connman_network_driver *driver)
303 {
304         DBG("driver %p name %s", driver, driver->name);
305
306         driver_list = g_slist_remove(driver_list, driver);
307 }
308
309 static void network_destruct(struct connman_element *element)
310 {
311         struct connman_network *network = element->network;
312
313         DBG("element %p name %s", element, element->name);
314
315         g_free(network->wifi.ssid);
316         g_free(network->wifi.mode);
317         g_free(network->wifi.security);
318         g_free(network->wifi.passphrase);
319
320         g_free(network->node);
321         g_free(network->name);
322         g_free(network->identifier);
323 }
324
325 /**
326  * connman_network_create:
327  * @identifier: network identifier (for example an unqiue name)
328  *
329  * Allocate a new network and assign the #identifier to it.
330  *
331  * Returns: a newly-allocated #connman_network structure
332  */
333 struct connman_network *connman_network_create(const char *identifier,
334                                                 enum connman_network_type type)
335 {
336         struct connman_network *network;
337
338         DBG("identifier %s type %d", identifier, type);
339
340         network = g_try_new0(struct connman_network, 1);
341         if (network == NULL)
342                 return NULL;
343
344         DBG("network %p", network);
345
346         network->element.refcount = 1;
347
348         network->element.name = g_strdup(identifier);
349         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
350         network->element.index = -1;
351
352         switch (type) {
353         case CONNMAN_NETWORK_TYPE_UNKNOWN:
354         case CONNMAN_NETWORK_TYPE_VENDOR:
355                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_UNKNOWN;
356                 break;
357         case CONNMAN_NETWORK_TYPE_WIFI:
358                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_WIFI;
359                 break;
360         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
361         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
362                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_BLUETOOTH;
363                 break;
364         case CONNMAN_NETWORK_TYPE_HSO:
365                 network->element.subtype = CONNMAN_ELEMENT_SUBTYPE_CELLULAR;
366                 break;
367         }
368
369         network->element.network = network;
370         network->element.destruct = network_destruct;
371
372         network->type = type;
373         network->identifier = g_strdup(identifier);
374
375         return network;
376 }
377
378 /**
379  * connman_network_ref:
380  * @network: network structure
381  *
382  * Increase reference counter of  network
383  */
384 struct connman_network *connman_network_ref(struct connman_network *network)
385 {
386         if (connman_element_ref(&network->element) == NULL)
387                 return NULL;
388
389         return network;
390 }
391
392 /**
393  * connman_network_unref:
394  * @network: network structure
395  *
396  * Decrease reference counter of network
397  */
398 void connman_network_unref(struct connman_network *network)
399 {
400         connman_element_unref(&network->element);
401 }
402
403 /**
404  * connman_network_get_identifier:
405  * @network: network structure
406  *
407  * Get identifier of network
408  */
409 const char *connman_network_get_identifier(struct connman_network *network)
410 {
411         return network->identifier;
412 }
413
414 /**
415  * connman_network_get_path:
416  * @network: network structure
417  *
418  * Get path name of network
419  */
420 const char *connman_network_get_path(struct connman_network *network)
421 {
422         return network->element.path;
423 }
424
425 /**
426  * connman_network_set_index:
427  * @network: network structure
428  * @index: index number
429  *
430  * Set index number of network
431  */
432 void connman_network_set_index(struct connman_network *network, int index)
433 {
434         network->element.index = index;
435 }
436
437 /**
438  * connman_network_get_index:
439  * @network: network structure
440  *
441  * Get index number of network
442  */
443 int connman_network_get_index(struct connman_network *network)
444 {
445         return network->element.index;
446 }
447
448 /**
449  * connman_network_set_protocol:
450  * @network: network structure
451  * @protocol: network protocol
452  *
453  * Change protocol of network
454  */
455 void connman_network_set_protocol(struct connman_network *network,
456                                         enum connman_network_protocol protocol)
457 {
458         network->protocol = protocol;
459 }
460
461 /**
462  * connman_network_set_connected:
463  * @network: network structure
464  * @connected: connected state
465  *
466  * Change connected state of network
467  */
468 int connman_network_set_connected(struct connman_network *network,
469                                                 connman_bool_t connected)
470 {
471         DBG("network %p connected %d", network, connected);
472
473         if (network->connected == connected)
474                 return -EALREADY;
475
476         network->connected = connected;
477
478         if (connected == TRUE) {
479                 struct connman_element *element;
480                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
481
482                 switch (network->protocol) {
483                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
484                         return 0;
485                 case CONNMAN_NETWORK_PROTOCOL_IP:
486                         type = CONNMAN_ELEMENT_TYPE_DHCP;
487                         break;
488                 case CONNMAN_NETWORK_PROTOCOL_PPP:
489                         type = CONNMAN_ELEMENT_TYPE_PPP;
490                         break;
491                 }
492
493                 element = connman_element_create(NULL);
494                 if (element != NULL) {
495                         element->type    = type;
496                         element->subtype = network->element.subtype;
497                         element->index   = network->element.index;
498
499                         if (connman_element_register(element,
500                                                         &network->element) < 0)
501                                 connman_element_unref(element);
502                 }
503         } else
504                 connman_element_unregister_children(&network->element);
505
506         return 0;
507 }
508
509 /**
510  * connman_network_set_string:
511  * @network: network structure
512  * @key: unique identifier
513  * @value: string value
514  *
515  * Set string value for specific key
516  */
517 int connman_network_set_string(struct connman_network *network,
518                                         const char *key, const char *value)
519 {
520         DBG("network %p key %s value %s", network, key, value);
521
522         if (g_str_equal(key, "Name") == TRUE) {
523                 g_free(network->name);
524                 network->name = g_strdup(value);
525         } else if (g_str_equal(key, "Node") == TRUE) {
526                 g_free(network->node);
527                 network->node = g_strdup(value);
528         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
529                 g_free(network->wifi.mode);
530                 network->wifi.mode = g_strdup(value);
531         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
532                 g_free(network->wifi.security);
533                 network->wifi.security = g_strdup(value);
534         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
535                 g_free(network->wifi.passphrase);
536                 network->wifi.passphrase = g_strdup(value);
537         }
538
539         return 0;
540 }
541
542 /**
543  * connman_network_get_string:
544  * @network: network structure
545  * @key: unique identifier
546  *
547  * Get string value for specific key
548  */
549 const char *connman_network_get_string(struct connman_network *network,
550                                                         const char *key)
551 {
552         DBG("network %p key %s", network, key);
553
554         if (g_str_equal(key, "Name") == TRUE)
555                 return network->name;
556         else if (g_str_equal(key, "Node") == TRUE)
557                 return network->node;
558         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
559                 return network->wifi.mode;
560         else if (g_str_equal(key, "WiFi.Security") == TRUE)
561                 return network->wifi.security;
562         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
563                 return network->wifi.passphrase;
564
565         return NULL;
566 }
567
568 /**
569  * connman_network_set_uint8:
570  * @network: network structure
571  * @key: unique identifier
572  * @value: integer value
573  *
574  * Set integer value for specific key
575  */
576 int connman_network_set_uint8(struct connman_network *network,
577                                         const char *key, connman_uint8_t value)
578 {
579         DBG("network %p key %s value %d", network, key, value);
580
581         if (g_str_equal(key, "Strength") == TRUE)
582                 network->strength = value;
583
584         return 0;
585 }
586
587 /**
588  * connman_network_set_blob:
589  * @network: network structure
590  * @key: unique identifier
591  * @data: blob data
592  * @size: blob size
593  *
594  * Set binary blob value for specific key
595  */
596 int connman_network_set_blob(struct connman_network *network,
597                         const char *key, const void *data, unsigned int size)
598 {
599         DBG("network %p key %s size %d", network, key, size);
600
601         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
602                 g_free(network->wifi.ssid);
603                 network->wifi.ssid = g_try_malloc(size);
604                 if (network->wifi.ssid != NULL) {
605                         memcpy(network->wifi.ssid, data, size);
606                         network->wifi.ssid_len = size;
607                 } else
608                         network->wifi.ssid_len = 0;
609         }
610
611         return 0;
612 }
613
614 /**
615  * connman_network_get_blob:
616  * @network: network structure
617  * @key: unique identifier
618  * @size: pointer to blob size
619  *
620  * Get binary blob value for specific key
621  */
622 const void *connman_network_get_blob(struct connman_network *network,
623                                         const char *key, unsigned int *size)
624 {
625         DBG("network %p key %s", network, key);
626
627         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
628                 if (size != NULL)
629                         *size = network->wifi.ssid_len;
630                 return network->wifi.ssid;
631         }
632
633         return NULL;
634 }
635
636 void __connman_network_set_device(struct connman_network *network,
637                                         struct connman_device *device)
638 {
639         network->device = device;
640 }
641
642 /**
643  * connman_network_get_device:
644  * @network: network structure
645  *
646  * Get parent device of network
647  */
648 struct connman_device *connman_network_get_device(struct connman_network *network)
649 {
650         return network->device;
651 }
652
653 /**
654  * connman_network_get_data:
655  * @network: network structure
656  *
657  * Get private network data pointer
658  */
659 void *connman_network_get_data(struct connman_network *network)
660 {
661         return network->driver_data;
662 }
663
664 /**
665  * connman_network_set_data:
666  * @network: network structure
667  * @data: data pointer
668  *
669  * Set private network data pointer
670  */
671 void connman_network_set_data(struct connman_network *network, void *data)
672 {
673         network->driver_data = data;
674 }
675
676 static gboolean match_driver(struct connman_network *network,
677                                         struct connman_network_driver *driver)
678 {
679         if (network->type == driver->type ||
680                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
681                 return TRUE;
682
683         return FALSE;
684 }
685
686 static int network_probe(struct connman_element *element)
687 {
688         struct connman_network *network = element->network;
689         GSList *list;
690         int err;
691
692         DBG("element %p name %s", element, element->name);
693
694         if (network == NULL)
695                 return -ENODEV;
696
697         for (list = driver_list; list; list = list->next) {
698                 struct connman_network_driver *driver = list->data;
699
700                 if (match_driver(network, driver) == FALSE)
701                         continue;
702
703                 DBG("driver %p name %s", driver, driver->name);
704
705                 if (driver->probe(network) == 0) {
706                         network->driver = driver;
707                         break;
708                 }
709         }
710
711         if (network->driver == NULL)
712                 return -ENODEV;
713
714         err = register_interface(element);
715         if (err < 0) {
716                 if (network->driver->remove)
717                         network->driver->remove(network);
718                 return err;
719         }
720
721         return 0;
722 }
723
724 static void network_remove(struct connman_element *element)
725 {
726         struct connman_network *network = element->network;
727
728         DBG("element %p name %s", element, element->name);
729
730         if (network == NULL)
731                 return;
732
733         if (network->driver == NULL)
734                 return;
735
736         unregister_interface(element);
737
738         if (network->driver->remove)
739                 network->driver->remove(network);
740 }
741
742 static struct connman_driver network_driver = {
743         .name           = "network",
744         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
745         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
746         .probe          = network_probe,
747         .remove         = network_remove,
748 };
749
750 static int network_load(struct connman_network *network)
751 {
752         GKeyFile *keyfile;
753         gchar *pathname, *data = NULL;
754         gsize length;
755         const char *name;
756
757         DBG("network %p", network);
758
759         name = connman_device_get_name(network->device);
760         if (name == NULL)
761                 return -EINVAL;
762
763         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
764         if (pathname == NULL)
765                 return -ENOMEM;
766
767         keyfile = g_key_file_new();
768
769         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
770                 g_free(pathname);
771                 return -ENOENT;
772         }
773
774         g_free(pathname);
775
776         if (g_key_file_load_from_data(keyfile, data, length,
777                                                         0, NULL) == FALSE) {
778                 g_free(data);
779                 return -EILSEQ;
780         }
781
782         g_free(data);
783
784         network->remember = g_key_file_get_boolean(keyfile,
785                                         network->identifier, "Remember", NULL);
786
787         g_free(network->wifi.security);
788         network->wifi.security = g_key_file_get_string(keyfile,
789                                 network->identifier, "WiFi.Security", NULL);
790
791         g_free(network->wifi.passphrase);
792         network->wifi.passphrase = g_key_file_get_string(keyfile,
793                                 network->identifier, "WiFi.Passphrase", NULL);
794
795         g_key_file_free(keyfile);
796
797         return 0;
798 }
799
800 static int network_save(struct connman_network *network)
801 {
802         GKeyFile *keyfile;
803         gchar *pathname, *data = NULL;
804         gsize length;
805         const char *name;
806
807         DBG("network %p", network);
808
809         name = connman_device_get_name(network->device);
810         if (name == NULL)
811                 return -EINVAL;
812
813         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
814         if (pathname == NULL)
815                 return -ENOMEM;
816
817         keyfile = g_key_file_new();
818
819         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
820                 goto update;
821
822         if (length > 0) {
823                 if (g_key_file_load_from_data(keyfile, data, length,
824                                                         0, NULL) == FALSE)
825                         goto done;
826         }
827
828         g_free(data);
829
830 update:
831         g_key_file_set_boolean(keyfile, network->identifier,
832                                         "Remember", network->remember);
833
834         if (network->wifi.security != NULL)
835                 g_key_file_set_string(keyfile, network->identifier,
836                                 "WiFi.Security", network->wifi.security);
837
838         if (network->wifi.passphrase != NULL)
839                 g_key_file_set_string(keyfile, network->identifier,
840                                 "WiFi.Passphrase", network->wifi.passphrase);
841
842         data = g_key_file_to_data(keyfile, &length, NULL);
843
844         g_file_set_contents(pathname, data, length, NULL);
845
846 done:
847         g_free(data);
848
849         g_key_file_free(keyfile);
850
851         g_free(pathname);
852
853         return 0;
854 }
855
856 static struct connman_storage network_storage = {
857         .name           = "network",
858         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
859         .network_load   = network_load,
860         .network_save   = network_save,
861 };
862
863 int __connman_network_init(void)
864 {
865         DBG("");
866
867         connection = connman_dbus_get_connection();
868
869         if (connman_storage_register(&network_storage) < 0)
870                 connman_error("Failed to register network storage");
871
872         return connman_driver_register(&network_driver);
873 }
874
875 void __connman_network_cleanup(void)
876 {
877         DBG("");
878
879         connman_driver_unregister(&network_driver);
880
881         connman_storage_unregister(&network_storage);
882
883         dbus_connection_unref(connection);
884 }