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