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