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