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