Add support for automatic connection policy
[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                 __connman_device_increase_connections(network->device);
494
495                 element = connman_element_create(NULL);
496                 if (element != NULL) {
497                         element->type    = type;
498                         element->subtype = network->element.subtype;
499                         element->index   = network->element.index;
500
501                         if (connman_element_register(element,
502                                                 &network->element) < 0)
503                                 connman_element_unref(element);
504                 }
505         } else {
506                 connman_element_unregister_children(&network->element);
507
508                 __connman_device_decrease_connections(network->device);
509         }
510
511         return 0;
512 }
513
514 /**
515  * connman_network_set_string:
516  * @network: network structure
517  * @key: unique identifier
518  * @value: string value
519  *
520  * Set string value for specific key
521  */
522 int connman_network_set_string(struct connman_network *network,
523                                         const char *key, const char *value)
524 {
525         DBG("network %p key %s value %s", network, key, value);
526
527         if (g_str_equal(key, "Name") == TRUE) {
528                 g_free(network->name);
529                 network->name = g_strdup(value);
530         } else if (g_str_equal(key, "Node") == TRUE) {
531                 g_free(network->node);
532                 network->node = g_strdup(value);
533         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
534                 g_free(network->wifi.mode);
535                 network->wifi.mode = g_strdup(value);
536         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
537                 g_free(network->wifi.security);
538                 network->wifi.security = g_strdup(value);
539         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
540                 g_free(network->wifi.passphrase);
541                 network->wifi.passphrase = g_strdup(value);
542         }
543
544         return 0;
545 }
546
547 /**
548  * connman_network_get_string:
549  * @network: network structure
550  * @key: unique identifier
551  *
552  * Get string value for specific key
553  */
554 const char *connman_network_get_string(struct connman_network *network,
555                                                         const char *key)
556 {
557         DBG("network %p key %s", network, key);
558
559         if (g_str_equal(key, "Name") == TRUE)
560                 return network->name;
561         else if (g_str_equal(key, "Node") == TRUE)
562                 return network->node;
563         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
564                 return network->wifi.mode;
565         else if (g_str_equal(key, "WiFi.Security") == TRUE)
566                 return network->wifi.security;
567         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
568                 return network->wifi.passphrase;
569
570         return NULL;
571 }
572
573 /**
574  * connman_network_set_uint8:
575  * @network: network structure
576  * @key: unique identifier
577  * @value: integer value
578  *
579  * Set integer value for specific key
580  */
581 int connman_network_set_uint8(struct connman_network *network,
582                                         const char *key, connman_uint8_t value)
583 {
584         DBG("network %p key %s value %d", network, key, value);
585
586         if (g_str_equal(key, "Strength") == TRUE)
587                 network->strength = value;
588
589         return 0;
590 }
591
592 /**
593  * connman_network_set_blob:
594  * @network: network structure
595  * @key: unique identifier
596  * @data: blob data
597  * @size: blob size
598  *
599  * Set binary blob value for specific key
600  */
601 int connman_network_set_blob(struct connman_network *network,
602                         const char *key, const void *data, unsigned int size)
603 {
604         DBG("network %p key %s size %d", network, key, size);
605
606         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
607                 g_free(network->wifi.ssid);
608                 network->wifi.ssid = g_try_malloc(size);
609                 if (network->wifi.ssid != NULL) {
610                         memcpy(network->wifi.ssid, data, size);
611                         network->wifi.ssid_len = size;
612                 } else
613                         network->wifi.ssid_len = 0;
614         }
615
616         return 0;
617 }
618
619 /**
620  * connman_network_get_blob:
621  * @network: network structure
622  * @key: unique identifier
623  * @size: pointer to blob size
624  *
625  * Get binary blob value for specific key
626  */
627 const void *connman_network_get_blob(struct connman_network *network,
628                                         const char *key, unsigned int *size)
629 {
630         DBG("network %p key %s", network, key);
631
632         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
633                 if (size != NULL)
634                         *size = network->wifi.ssid_len;
635                 return network->wifi.ssid;
636         }
637
638         return NULL;
639 }
640
641 void __connman_network_set_device(struct connman_network *network,
642                                         struct connman_device *device)
643 {
644         network->device = device;
645 }
646
647 /**
648  * connman_network_get_device:
649  * @network: network structure
650  *
651  * Get parent device of network
652  */
653 struct connman_device *connman_network_get_device(struct connman_network *network)
654 {
655         return network->device;
656 }
657
658 /**
659  * connman_network_get_data:
660  * @network: network structure
661  *
662  * Get private network data pointer
663  */
664 void *connman_network_get_data(struct connman_network *network)
665 {
666         return network->driver_data;
667 }
668
669 /**
670  * connman_network_set_data:
671  * @network: network structure
672  * @data: data pointer
673  *
674  * Set private network data pointer
675  */
676 void connman_network_set_data(struct connman_network *network, void *data)
677 {
678         network->driver_data = data;
679 }
680
681 static gboolean match_driver(struct connman_network *network,
682                                         struct connman_network_driver *driver)
683 {
684         if (network->type == driver->type ||
685                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
686                 return TRUE;
687
688         return FALSE;
689 }
690
691 static int network_probe(struct connman_element *element)
692 {
693         struct connman_network *network = element->network;
694         GSList *list;
695         int err;
696
697         DBG("element %p name %s", element, element->name);
698
699         if (network == NULL)
700                 return -ENODEV;
701
702         for (list = driver_list; list; list = list->next) {
703                 struct connman_network_driver *driver = list->data;
704
705                 if (match_driver(network, driver) == FALSE)
706                         continue;
707
708                 DBG("driver %p name %s", driver, driver->name);
709
710                 if (driver->probe(network) == 0) {
711                         network->driver = driver;
712                         break;
713                 }
714         }
715
716         if (network->driver == NULL)
717                 return -ENODEV;
718
719         err = register_interface(element);
720         if (err < 0) {
721                 if (network->driver->remove)
722                         network->driver->remove(network);
723                 return err;
724         }
725
726         return 0;
727 }
728
729 static void network_remove(struct connman_element *element)
730 {
731         struct connman_network *network = element->network;
732
733         DBG("element %p name %s", element, element->name);
734
735         if (network == NULL)
736                 return;
737
738         if (network->driver == NULL)
739                 return;
740
741         unregister_interface(element);
742
743         if (network->driver->remove)
744                 network->driver->remove(network);
745 }
746
747 static struct connman_driver network_driver = {
748         .name           = "network",
749         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
750         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
751         .probe          = network_probe,
752         .remove         = network_remove,
753 };
754
755 static int network_load(struct connman_network *network)
756 {
757         GKeyFile *keyfile;
758         gchar *pathname, *data = NULL;
759         gsize length;
760         const char *name;
761
762         DBG("network %p", network);
763
764         name = connman_device_get_name(network->device);
765         if (name == NULL)
766                 return -EINVAL;
767
768         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
769         if (pathname == NULL)
770                 return -ENOMEM;
771
772         keyfile = g_key_file_new();
773
774         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
775                 g_free(pathname);
776                 return -ENOENT;
777         }
778
779         g_free(pathname);
780
781         if (g_key_file_load_from_data(keyfile, data, length,
782                                                         0, NULL) == FALSE) {
783                 g_free(data);
784                 return -EILSEQ;
785         }
786
787         g_free(data);
788
789         network->remember = g_key_file_get_boolean(keyfile,
790                                         network->identifier, "Remember", NULL);
791
792         g_free(network->wifi.security);
793         network->wifi.security = g_key_file_get_string(keyfile,
794                                 network->identifier, "WiFi.Security", NULL);
795
796         g_free(network->wifi.passphrase);
797         network->wifi.passphrase = g_key_file_get_string(keyfile,
798                                 network->identifier, "WiFi.Passphrase", NULL);
799
800         g_key_file_free(keyfile);
801
802         return 0;
803 }
804
805 static int network_save(struct connman_network *network)
806 {
807         GKeyFile *keyfile;
808         gchar *pathname, *data = NULL;
809         gsize length;
810         const char *name;
811
812         DBG("network %p", network);
813
814         name = connman_device_get_name(network->device);
815         if (name == NULL)
816                 return -EINVAL;
817
818         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
819         if (pathname == NULL)
820                 return -ENOMEM;
821
822         keyfile = g_key_file_new();
823
824         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
825                 goto update;
826
827         if (length > 0) {
828                 if (g_key_file_load_from_data(keyfile, data, length,
829                                                         0, NULL) == FALSE)
830                         goto done;
831         }
832
833         g_free(data);
834
835 update:
836         g_key_file_set_boolean(keyfile, network->identifier,
837                                         "Remember", network->remember);
838
839         if (network->wifi.security != NULL)
840                 g_key_file_set_string(keyfile, network->identifier,
841                                 "WiFi.Security", network->wifi.security);
842
843         if (network->wifi.passphrase != NULL)
844                 g_key_file_set_string(keyfile, network->identifier,
845                                 "WiFi.Passphrase", network->wifi.passphrase);
846
847         data = g_key_file_to_data(keyfile, &length, NULL);
848
849         g_file_set_contents(pathname, data, length, NULL);
850
851 done:
852         g_free(data);
853
854         g_key_file_free(keyfile);
855
856         g_free(pathname);
857
858         return 0;
859 }
860
861 static struct connman_storage network_storage = {
862         .name           = "network",
863         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
864         .network_load   = network_load,
865         .network_save   = network_save,
866 };
867
868 int __connman_network_init(void)
869 {
870         DBG("");
871
872         connection = connman_dbus_get_connection();
873
874         if (connman_storage_register(&network_storage) < 0)
875                 connman_error("Failed to register network storage");
876
877         return connman_driver_register(&network_driver);
878 }
879
880 void __connman_network_cleanup(void)
881 {
882         DBG("");
883
884         connman_driver_unregister(&network_driver);
885
886         connman_storage_unregister(&network_storage);
887
888         dbus_connection_unref(connection);
889 }