Remove element subtype details
[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         network->element.network = network;
353         network->element.destruct = network_destruct;
354
355         network->type = type;
356         network->identifier = g_strdup(identifier);
357
358         return network;
359 }
360
361 /**
362  * connman_network_ref:
363  * @network: network structure
364  *
365  * Increase reference counter of  network
366  */
367 struct connman_network *connman_network_ref(struct connman_network *network)
368 {
369         if (connman_element_ref(&network->element) == NULL)
370                 return NULL;
371
372         return network;
373 }
374
375 /**
376  * connman_network_unref:
377  * @network: network structure
378  *
379  * Decrease reference counter of network
380  */
381 void connman_network_unref(struct connman_network *network)
382 {
383         connman_element_unref(&network->element);
384 }
385
386 /**
387  * connman_network_get_identifier:
388  * @network: network structure
389  *
390  * Get identifier of network
391  */
392 const char *connman_network_get_identifier(struct connman_network *network)
393 {
394         return network->identifier;
395 }
396
397 /**
398  * connman_network_get_path:
399  * @network: network structure
400  *
401  * Get path name of network
402  */
403 const char *connman_network_get_path(struct connman_network *network)
404 {
405         return network->element.path;
406 }
407
408 /**
409  * connman_network_set_index:
410  * @network: network structure
411  * @index: index number
412  *
413  * Set index number of network
414  */
415 void connman_network_set_index(struct connman_network *network, int index)
416 {
417         network->element.index = index;
418 }
419
420 /**
421  * connman_network_get_index:
422  * @network: network structure
423  *
424  * Get index number of network
425  */
426 int connman_network_get_index(struct connman_network *network)
427 {
428         return network->element.index;
429 }
430
431 /**
432  * connman_network_set_protocol:
433  * @network: network structure
434  * @protocol: network protocol
435  *
436  * Change protocol of network
437  */
438 void connman_network_set_protocol(struct connman_network *network,
439                                         enum connman_network_protocol protocol)
440 {
441         network->protocol = protocol;
442 }
443
444 /**
445  * connman_network_set_connected:
446  * @network: network structure
447  * @connected: connected state
448  *
449  * Change connected state of network
450  */
451 int connman_network_set_connected(struct connman_network *network,
452                                                 connman_bool_t connected)
453 {
454         DBG("network %p connected %d", network, connected);
455
456         if (network->connected == connected)
457                 return -EALREADY;
458
459         network->connected = connected;
460
461         if (connected == TRUE) {
462                 struct connman_element *element;
463                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
464
465                 switch (network->protocol) {
466                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
467                         return 0;
468                 case CONNMAN_NETWORK_PROTOCOL_IP:
469                         type = CONNMAN_ELEMENT_TYPE_DHCP;
470                         break;
471                 case CONNMAN_NETWORK_PROTOCOL_PPP:
472                         type = CONNMAN_ELEMENT_TYPE_PPP;
473                         break;
474                 }
475
476                 __connman_device_increase_connections(network->device);
477
478                 element = connman_element_create(NULL);
479                 if (element != NULL) {
480                         element->type  = type;
481                         element->index = network->element.index;
482
483                         if (connman_element_register(element,
484                                                 &network->element) < 0)
485                                 connman_element_unref(element);
486                 }
487         } else {
488                 connman_element_unregister_children(&network->element);
489
490                 __connman_device_decrease_connections(network->device);
491         }
492
493         return 0;
494 }
495
496 /**
497  * connman_network_get_remember:
498  * @network: network structure
499  *
500  * Get network remember setting
501  */
502 connman_bool_t connman_network_get_remember(struct connman_network *network)
503 {
504         return network->remember;
505 }
506
507 /**
508  * connman_network_connect:
509  * @network: network structure
510  *
511  * Connect network
512  */
513 int connman_network_connect(struct connman_network *network)
514 {
515         if (network->connected == TRUE)
516                 return -EALREADY;
517
518         if (network->driver && network->driver->connect)
519                 return network->driver->connect(network);
520
521         network->connected = TRUE;
522
523         return 0;
524 }
525
526 /**
527  * connman_network_set_string:
528  * @network: network structure
529  * @key: unique identifier
530  * @value: string value
531  *
532  * Set string value for specific key
533  */
534 int connman_network_set_string(struct connman_network *network,
535                                         const char *key, const char *value)
536 {
537         DBG("network %p key %s value %s", network, key, value);
538
539         if (g_str_equal(key, "Name") == TRUE) {
540                 g_free(network->name);
541                 network->name = g_strdup(value);
542         } else if (g_str_equal(key, "Node") == TRUE) {
543                 g_free(network->node);
544                 network->node = g_strdup(value);
545         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
546                 g_free(network->wifi.mode);
547                 network->wifi.mode = g_strdup(value);
548         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
549                 g_free(network->wifi.security);
550                 network->wifi.security = g_strdup(value);
551         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
552                 g_free(network->wifi.passphrase);
553                 network->wifi.passphrase = g_strdup(value);
554         }
555
556         return 0;
557 }
558
559 /**
560  * connman_network_get_string:
561  * @network: network structure
562  * @key: unique identifier
563  *
564  * Get string value for specific key
565  */
566 const char *connman_network_get_string(struct connman_network *network,
567                                                         const char *key)
568 {
569         DBG("network %p key %s", network, key);
570
571         if (g_str_equal(key, "Name") == TRUE)
572                 return network->name;
573         else if (g_str_equal(key, "Node") == TRUE)
574                 return network->node;
575         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
576                 return network->wifi.mode;
577         else if (g_str_equal(key, "WiFi.Security") == TRUE)
578                 return network->wifi.security;
579         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
580                 return network->wifi.passphrase;
581
582         return NULL;
583 }
584
585 /**
586  * connman_network_set_uint8:
587  * @network: network structure
588  * @key: unique identifier
589  * @value: integer value
590  *
591  * Set integer value for specific key
592  */
593 int connman_network_set_uint8(struct connman_network *network,
594                                         const char *key, connman_uint8_t value)
595 {
596         DBG("network %p key %s value %d", network, key, value);
597
598         if (g_str_equal(key, "Strength") == TRUE)
599                 network->strength = value;
600
601         return 0;
602 }
603
604 /**
605  * connman_network_set_blob:
606  * @network: network structure
607  * @key: unique identifier
608  * @data: blob data
609  * @size: blob size
610  *
611  * Set binary blob value for specific key
612  */
613 int connman_network_set_blob(struct connman_network *network,
614                         const char *key, const void *data, unsigned int size)
615 {
616         DBG("network %p key %s size %d", network, key, size);
617
618         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
619                 g_free(network->wifi.ssid);
620                 network->wifi.ssid = g_try_malloc(size);
621                 if (network->wifi.ssid != NULL) {
622                         memcpy(network->wifi.ssid, data, size);
623                         network->wifi.ssid_len = size;
624                 } else
625                         network->wifi.ssid_len = 0;
626         }
627
628         return 0;
629 }
630
631 /**
632  * connman_network_get_blob:
633  * @network: network structure
634  * @key: unique identifier
635  * @size: pointer to blob size
636  *
637  * Get binary blob value for specific key
638  */
639 const void *connman_network_get_blob(struct connman_network *network,
640                                         const char *key, unsigned int *size)
641 {
642         DBG("network %p key %s", network, key);
643
644         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
645                 if (size != NULL)
646                         *size = network->wifi.ssid_len;
647                 return network->wifi.ssid;
648         }
649
650         return NULL;
651 }
652
653 void __connman_network_set_device(struct connman_network *network,
654                                         struct connman_device *device)
655 {
656         network->device = device;
657 }
658
659 /**
660  * connman_network_get_device:
661  * @network: network structure
662  *
663  * Get parent device of network
664  */
665 struct connman_device *connman_network_get_device(struct connman_network *network)
666 {
667         return network->device;
668 }
669
670 /**
671  * connman_network_get_data:
672  * @network: network structure
673  *
674  * Get private network data pointer
675  */
676 void *connman_network_get_data(struct connman_network *network)
677 {
678         return network->driver_data;
679 }
680
681 /**
682  * connman_network_set_data:
683  * @network: network structure
684  * @data: data pointer
685  *
686  * Set private network data pointer
687  */
688 void connman_network_set_data(struct connman_network *network, void *data)
689 {
690         network->driver_data = data;
691 }
692
693 static gboolean match_driver(struct connman_network *network,
694                                         struct connman_network_driver *driver)
695 {
696         if (network->type == driver->type ||
697                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
698                 return TRUE;
699
700         return FALSE;
701 }
702
703 static int network_probe(struct connman_element *element)
704 {
705         struct connman_network *network = element->network;
706         GSList *list;
707         int err;
708
709         DBG("element %p name %s", element, element->name);
710
711         if (network == NULL)
712                 return -ENODEV;
713
714         for (list = driver_list; list; list = list->next) {
715                 struct connman_network_driver *driver = list->data;
716
717                 if (match_driver(network, driver) == FALSE)
718                         continue;
719
720                 DBG("driver %p name %s", driver, driver->name);
721
722                 if (driver->probe(network) == 0) {
723                         network->driver = driver;
724                         break;
725                 }
726         }
727
728         if (network->driver == NULL)
729                 return -ENODEV;
730
731         err = register_interface(element);
732         if (err < 0) {
733                 if (network->driver->remove)
734                         network->driver->remove(network);
735                 return err;
736         }
737
738         return 0;
739 }
740
741 static void network_remove(struct connman_element *element)
742 {
743         struct connman_network *network = element->network;
744
745         DBG("element %p name %s", element, element->name);
746
747         if (network == NULL)
748                 return;
749
750         if (network->driver == NULL)
751                 return;
752
753         unregister_interface(element);
754
755         if (network->driver->remove)
756                 network->driver->remove(network);
757 }
758
759 static struct connman_driver network_driver = {
760         .name           = "network",
761         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
762         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
763         .probe          = network_probe,
764         .remove         = network_remove,
765 };
766
767 static int network_load(struct connman_network *network)
768 {
769         GKeyFile *keyfile;
770         gchar *pathname, *data = NULL;
771         gsize length;
772         const char *name;
773
774         DBG("network %p", network);
775
776         name = connman_device_get_name(network->device);
777         if (name == NULL)
778                 return -EINVAL;
779
780         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
781         if (pathname == NULL)
782                 return -ENOMEM;
783
784         keyfile = g_key_file_new();
785
786         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
787                 g_free(pathname);
788                 return -ENOENT;
789         }
790
791         g_free(pathname);
792
793         if (g_key_file_load_from_data(keyfile, data, length,
794                                                         0, NULL) == FALSE) {
795                 g_free(data);
796                 return -EILSEQ;
797         }
798
799         g_free(data);
800
801         network->remember = g_key_file_get_boolean(keyfile,
802                                         network->identifier, "Remember", NULL);
803
804         g_free(network->wifi.security);
805         network->wifi.security = g_key_file_get_string(keyfile,
806                                 network->identifier, "WiFi.Security", NULL);
807
808         g_free(network->wifi.passphrase);
809         network->wifi.passphrase = g_key_file_get_string(keyfile,
810                                 network->identifier, "WiFi.Passphrase", NULL);
811
812         g_key_file_free(keyfile);
813
814         return 0;
815 }
816
817 static int network_save(struct connman_network *network)
818 {
819         GKeyFile *keyfile;
820         gchar *pathname, *data = NULL;
821         gsize length;
822         const char *name;
823
824         DBG("network %p", network);
825
826         name = connman_device_get_name(network->device);
827         if (name == NULL)
828                 return -EINVAL;
829
830         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
831         if (pathname == NULL)
832                 return -ENOMEM;
833
834         keyfile = g_key_file_new();
835
836         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
837                 goto update;
838
839         if (length > 0) {
840                 if (g_key_file_load_from_data(keyfile, data, length,
841                                                         0, NULL) == FALSE)
842                         goto done;
843         }
844
845         g_free(data);
846
847 update:
848         g_key_file_set_boolean(keyfile, network->identifier,
849                                         "Remember", network->remember);
850
851         if (network->wifi.security != NULL)
852                 g_key_file_set_string(keyfile, network->identifier,
853                                 "WiFi.Security", network->wifi.security);
854
855         if (network->wifi.passphrase != NULL)
856                 g_key_file_set_string(keyfile, network->identifier,
857                                 "WiFi.Passphrase", network->wifi.passphrase);
858
859         data = g_key_file_to_data(keyfile, &length, NULL);
860
861         g_file_set_contents(pathname, data, length, NULL);
862
863 done:
864         g_free(data);
865
866         g_key_file_free(keyfile);
867
868         g_free(pathname);
869
870         return 0;
871 }
872
873 static struct connman_storage network_storage = {
874         .name           = "network",
875         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
876         .network_load   = network_load,
877         .network_save   = network_save,
878 };
879
880 int __connman_network_init(void)
881 {
882         DBG("");
883
884         connection = connman_dbus_get_connection();
885
886         if (connman_storage_register(&network_storage) < 0)
887                 connman_error("Failed to register network storage");
888
889         return connman_driver_register(&network_driver);
890 }
891
892 void __connman_network_cleanup(void)
893 {
894         DBG("");
895
896         connman_driver_unregister(&network_driver);
897
898         connman_storage_unregister(&network_storage);
899
900         dbus_connection_unref(connection);
901 }