Fix wrong device path in connection properties
[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 secondary;
37         connman_bool_t available;
38         connman_bool_t connected;
39         connman_bool_t remember;
40         connman_uint8_t priority;
41         connman_uint8_t strength;
42         char *identifier;
43         char *address;
44         char *name;
45         char *node;
46         char *group;
47
48         struct connman_network_driver *driver;
49         void *driver_data;
50
51         connman_bool_t registered;
52
53         struct connman_device *device;
54
55         struct {
56                 void *ssid;
57                 int ssid_len;
58                 char *mode;
59                 char *security;
60                 char *passphrase;
61         } wifi;
62 };
63
64 static const char *type2string(enum connman_network_type type)
65 {
66         switch (type) {
67         case CONNMAN_NETWORK_TYPE_UNKNOWN:
68         case CONNMAN_NETWORK_TYPE_VENDOR:
69                 break;
70         case CONNMAN_NETWORK_TYPE_WIFI:
71                 return "wifi";
72         case CONNMAN_NETWORK_TYPE_WIMAX:
73                 return "wimax";
74         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
75         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
76                 return "bluetooth";
77         case CONNMAN_NETWORK_TYPE_HSO:
78                 return "cellular";
79         }
80
81         return NULL;
82 }
83
84 static DBusMessage *get_properties(DBusConnection *conn,
85                                         DBusMessage *msg, void *data)
86 {
87         struct connman_network *network = data;
88         DBusMessage *reply;
89         DBusMessageIter array, dict;
90
91         DBG("conn %p", conn);
92
93         if (__connman_security_check_privilege(msg,
94                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
95                 return __connman_error_permission_denied(msg);
96
97         reply = dbus_message_new_method_return(msg);
98         if (reply == NULL)
99                 return NULL;
100
101         dbus_message_iter_init_append(reply, &array);
102
103         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
104                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
105                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
106                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
107
108         if (network->device) {
109                 const char *path = connman_device_get_path(network->device);
110                 if (path != NULL)
111                         connman_dbus_dict_append_variant(&dict, "Device",
112                                                 DBUS_TYPE_OBJECT_PATH, &path);
113         }
114
115         if (network->address != NULL)
116                 connman_dbus_dict_append_variant(&dict, "Address",
117                                         DBUS_TYPE_STRING, &network->address);
118
119         if (network->name != NULL)
120                 connman_dbus_dict_append_variant(&dict, "Name",
121                                         DBUS_TYPE_STRING, &network->name);
122
123         connman_dbus_dict_append_variant(&dict, "Available",
124                                 DBUS_TYPE_BOOLEAN, &network->available);
125
126         connman_dbus_dict_append_variant(&dict, "Connected",
127                                 DBUS_TYPE_BOOLEAN, &network->connected);
128
129         connman_dbus_dict_append_variant(&dict, "Remember",
130                                 DBUS_TYPE_BOOLEAN, &network->remember);
131
132         if (network->priority > 0)
133                 connman_dbus_dict_append_variant(&dict, "Priority",
134                                         DBUS_TYPE_BYTE, &network->priority);
135
136         if (network->strength > 0)
137                 connman_dbus_dict_append_variant(&dict, "Strength",
138                                         DBUS_TYPE_BYTE, &network->strength);
139
140         if (network->wifi.ssid != NULL && network->wifi.ssid_len > 0)
141                 connman_dbus_dict_append_array(&dict, "WiFi.SSID",
142                                 DBUS_TYPE_BYTE, &network->wifi.ssid,
143                                                 network->wifi.ssid_len);
144
145         if (network->wifi.mode != NULL)
146                 connman_dbus_dict_append_variant(&dict, "WiFi.Mode",
147                                 DBUS_TYPE_STRING, &network->wifi.mode);
148
149         if (network->wifi.security != NULL)
150                 connman_dbus_dict_append_variant(&dict, "WiFi.Security",
151                                 DBUS_TYPE_STRING, &network->wifi.security);
152
153         if (network->wifi.passphrase != NULL &&
154                         __connman_security_check_privilege(msg,
155                                 CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
156                 connman_dbus_dict_append_variant(&dict, "WiFi.Passphrase",
157                                 DBUS_TYPE_STRING, &network->wifi.passphrase);
158
159         dbus_message_iter_close_container(&array, &dict);
160
161         return reply;
162 }
163
164 static DBusMessage *set_property(DBusConnection *conn,
165                                         DBusMessage *msg, void *data)
166 {
167         struct connman_network *network = data;
168         DBusMessageIter iter, value;
169         const char *name;
170         int type;
171
172         DBG("conn %p", conn);
173
174         if (dbus_message_iter_init(msg, &iter) == FALSE)
175                 return __connman_error_invalid_arguments(msg);
176
177         dbus_message_iter_get_basic(&iter, &name);
178         dbus_message_iter_next(&iter);
179         dbus_message_iter_recurse(&iter, &value);
180
181         if (__connman_security_check_privilege(msg,
182                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
183                 return __connman_error_permission_denied(msg);
184
185         type = dbus_message_iter_get_arg_type(&value);
186
187         if (g_str_equal(name, "Remember") == TRUE) {
188                 connman_bool_t remember;
189
190                 if (type != DBUS_TYPE_BOOLEAN)
191                         return __connman_error_invalid_arguments(msg);
192
193                 dbus_message_iter_get_basic(&value, &remember);
194
195                 if (network->remember == remember)
196                         return __connman_error_invalid_arguments(msg);
197
198                 network->remember = remember;
199         } else if (g_str_equal(name, "WiFi.Passphrase") == TRUE) {
200                 const char *passphrase;
201
202                 if (type != DBUS_TYPE_STRING)
203                         return __connman_error_invalid_arguments(msg);
204
205                 if (__connman_security_check_privilege(msg,
206                                         CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
207                         return __connman_error_permission_denied(msg);
208
209                 dbus_message_iter_get_basic(&value, &passphrase);
210
211                 g_free(network->wifi.passphrase);
212                 network->wifi.passphrase = g_strdup(passphrase);
213         } else if (g_str_equal(name, "Priority") == TRUE) {
214                 connman_uint8_t priority;
215
216                 if (type != DBUS_TYPE_BYTE)
217                         return __connman_error_invalid_arguments(msg);
218
219                 dbus_message_iter_get_basic(&value, &priority);
220
221                 network->priority = priority;
222         }
223
224         __connman_storage_save_network(network);
225
226         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
227 }
228
229 static DBusMessage *do_connect(DBusConnection *conn,
230                                         DBusMessage *msg, void *data)
231 {
232         struct connman_network *network = data;
233         int err;
234
235         DBG("conn %p", conn);
236
237         if (__connman_security_check_privilege(msg,
238                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
239                 return __connman_error_permission_denied(msg);
240
241         if (network->connected == TRUE)
242                 return __connman_error_failed(msg);
243
244         if (network->driver && network->driver->connect) {
245                 enum connman_device_mode mode;
246
247                 mode = connman_device_get_mode(network->device);
248                 if (mode == CONNMAN_DEVICE_MODE_NETWORK_SINGLE)
249                         __connman_device_disconnect(network->device);
250
251                 err = network->driver->connect(network);
252                 if (err < 0 && err != -EINPROGRESS)
253                         return __connman_error_failed(msg);
254         } else
255                 network->connected = TRUE;
256
257         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
258 }
259
260 static DBusMessage *do_disconnect(DBusConnection *conn,
261                                         DBusMessage *msg, void *data)
262 {
263         struct connman_network *network = data;
264         int err;
265
266         DBG("conn %p", conn);
267
268         if (__connman_security_check_privilege(msg,
269                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
270                 return __connman_error_permission_denied(msg);
271
272         if (network->connected == FALSE)
273                 return __connman_error_failed(msg);
274
275         connman_element_unregister_children(&network->element);
276
277         connman_device_set_disconnected(network->device, TRUE);
278
279         if (network->driver && network->driver->disconnect) {
280                 err = network->driver->disconnect(network);
281                 if (err < 0 && err != -EINPROGRESS)
282                         return __connman_error_failed(msg);
283         } else
284                 network->connected = FALSE;
285
286         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
287 }
288
289 static GDBusMethodTable network_methods[] = {
290         { "GetProperties", "",   "a{sv}", get_properties },
291         { "SetProperty",   "sv", "",      set_property   },
292         { "Connect",       "",   "",      do_connect     },
293         { "Disconnect",    "",   "",      do_disconnect  },
294         { },
295 };
296
297 static GDBusSignalTable network_signals[] = {
298         { "PropertyChanged", "sv" },
299         { },
300 };
301
302 static DBusConnection *connection;
303
304 static void append_networks(struct connman_device *device,
305                                                 DBusMessageIter *entry)
306 {
307         DBusMessageIter value, iter;
308         const char *key = "Networks";
309
310         dbus_message_iter_append_basic(entry, DBUS_TYPE_STRING, &key);
311
312         dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
313                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
314                                                                 &value);
315
316         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
317                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
318         __connman_element_list((struct connman_element *) device,
319                                         CONNMAN_ELEMENT_TYPE_NETWORK, &iter);
320         dbus_message_iter_close_container(&value, &iter);
321
322         dbus_message_iter_close_container(entry, &value);
323 }
324
325 static void emit_networks_signal(struct connman_device *device)
326 {
327         const char *path = connman_device_get_path(device);
328         DBusMessage *signal;
329         DBusMessageIter entry;
330
331         signal = dbus_message_new_signal(path,
332                                 CONNMAN_DEVICE_INTERFACE, "PropertyChanged");
333         if (signal == NULL)
334                 return;
335
336         dbus_message_iter_init_append(signal, &entry);
337
338         append_networks(device, &entry);
339
340         g_dbus_send_message(connection, signal);
341 }
342
343 static int register_interface(struct connman_element *element)
344 {
345         struct connman_network *network = element->network;
346
347         DBG("element %p name %s", element, element->name);
348
349         if (g_dbus_register_interface(connection, element->path,
350                                         CONNMAN_NETWORK_INTERFACE,
351                                         network_methods, network_signals,
352                                         NULL, network, NULL) == FALSE) {
353                 connman_error("Failed to register %s network", element->path);
354                 return -EIO;
355         }
356
357         network->registered = TRUE;
358
359         emit_networks_signal(network->device);
360
361         return 0;
362 }
363
364 static void unregister_interface(struct connman_element *element)
365 {
366         struct connman_network * network = element->network;
367
368         DBG("element %p name %s", element, element->name);
369
370         network->registered = FALSE;
371
372         emit_networks_signal(network->device);
373
374         g_dbus_unregister_interface(connection, element->path,
375                                                 CONNMAN_NETWORK_INTERFACE);
376 }
377
378 connman_bool_t __connman_network_has_driver(struct connman_network *network)
379 {
380         if (network == NULL || network->driver == NULL)
381                 return FALSE;
382
383         return network->registered;
384 }
385
386 static GSList *driver_list = NULL;
387
388 static gint compare_priority(gconstpointer a, gconstpointer b)
389 {
390         const struct connman_network_driver *driver1 = a;
391         const struct connman_network_driver *driver2 = b;
392
393         return driver2->priority - driver1->priority;
394 }
395
396 /**
397  * connman_network_driver_register:
398  * @driver: network driver definition
399  *
400  * Register a new network driver
401  *
402  * Returns: %0 on success
403  */
404 int connman_network_driver_register(struct connman_network_driver *driver)
405 {
406         DBG("driver %p name %s", driver, driver->name);
407
408         driver_list = g_slist_insert_sorted(driver_list, driver,
409                                                         compare_priority);
410
411         return 0;
412 }
413
414 /**
415  * connman_network_driver_unregister:
416  * @driver: network driver definition
417  *
418  * Remove a previously registered network driver
419  */
420 void connman_network_driver_unregister(struct connman_network_driver *driver)
421 {
422         DBG("driver %p name %s", driver, driver->name);
423
424         driver_list = g_slist_remove(driver_list, driver);
425 }
426
427 static void network_destruct(struct connman_element *element)
428 {
429         struct connman_network *network = element->network;
430
431         DBG("element %p name %s", element, element->name);
432
433         g_free(network->wifi.ssid);
434         g_free(network->wifi.mode);
435         g_free(network->wifi.security);
436         g_free(network->wifi.passphrase);
437
438         g_free(network->group);
439         g_free(network->node);
440         g_free(network->name);
441         g_free(network->address);
442         g_free(network->identifier);
443 }
444
445 /**
446  * connman_network_create:
447  * @identifier: network identifier (for example an unqiue name)
448  *
449  * Allocate a new network and assign the #identifier to it.
450  *
451  * Returns: a newly-allocated #connman_network structure
452  */
453 struct connman_network *connman_network_create(const char *identifier,
454                                                 enum connman_network_type type)
455 {
456         struct connman_network *network;
457         connman_uint8_t strength = 0;
458         const char *str;
459         char *temp;
460
461         DBG("identifier %s type %d", identifier, type);
462
463         network = g_try_new0(struct connman_network, 1);
464         if (network == NULL)
465                 return NULL;
466
467         DBG("network %p", network);
468
469         __connman_element_initialize(&network->element);
470
471         //temp = connman_dbus_encode_string(identifier);
472         temp = g_strdup(identifier);
473         if (temp == NULL) {
474                 g_free(network);
475                 return NULL;
476         }
477
478         network->element.name = temp;
479         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
480
481         network->element.network = network;
482         network->element.destruct = network_destruct;
483
484         str = type2string(type);
485         if (str != NULL)
486                 connman_element_set_string(&network->element, "Type", str);
487
488         connman_element_set_uint8(&network->element, "Strength", strength);
489
490         network->type       = type;
491         network->secondary  = FALSE;
492         network->identifier = g_strdup(identifier);
493
494         return network;
495 }
496
497 /**
498  * connman_network_ref:
499  * @network: network structure
500  *
501  * Increase reference counter of  network
502  */
503 struct connman_network *connman_network_ref(struct connman_network *network)
504 {
505         if (connman_element_ref(&network->element) == NULL)
506                 return NULL;
507
508         return network;
509 }
510
511 /**
512  * connman_network_unref:
513  * @network: network structure
514  *
515  * Decrease reference counter of network
516  */
517 void connman_network_unref(struct connman_network *network)
518 {
519         connman_element_unref(&network->element);
520 }
521
522 const char *__connman_network_get_type(struct connman_network *network)
523 {
524         return type2string(network->type);
525 }
526
527 /**
528  * connman_network_get_type:
529  * @network: network structure
530  *
531  * Get type of network
532  */
533 enum connman_network_type connman_network_get_type(struct connman_network *network)
534 {
535         return network->type;
536 }
537
538 /**
539  * connman_network_get_identifier:
540  * @network: network structure
541  *
542  * Get identifier of network
543  */
544 const char *connman_network_get_identifier(struct connman_network *network)
545 {
546         return network->identifier;
547 }
548
549 /**
550  * connman_network_get_path:
551  * @network: network structure
552  *
553  * Get path name of network
554  */
555 const char *connman_network_get_path(struct connman_network *network)
556 {
557         return network->element.path;
558 }
559
560 /**
561  * connman_network_set_index:
562  * @network: network structure
563  * @index: index number
564  *
565  * Set index number of network
566  */
567 void connman_network_set_index(struct connman_network *network, int index)
568 {
569         network->element.index = index;
570 }
571
572 /**
573  * connman_network_get_index:
574  * @network: network structure
575  *
576  * Get index number of network
577  */
578 int connman_network_get_index(struct connman_network *network)
579 {
580         return network->element.index;
581 }
582
583 /**
584  * connman_network_set_protocol:
585  * @network: network structure
586  * @protocol: network protocol
587  *
588  * Change protocol of network
589  */
590 void connman_network_set_protocol(struct connman_network *network,
591                                         enum connman_network_protocol protocol)
592 {
593         network->protocol = protocol;
594 }
595
596 /**
597  * connman_network_set_group:
598  * @network: network structure
599  * @group: group name
600  *
601  * Set group name for automatic clustering
602  */
603 void connman_network_set_group(struct connman_network *network,
604                                                         const char *group)
605 {
606         g_free(network->group);
607         network->group = g_strdup(group);
608 }
609
610 const char *__connman_network_get_group(struct connman_network *network)
611 {
612         return network->group;
613 }
614
615 const char *__connman_network_get_ident(struct connman_network *network)
616 {
617         if (network->device == NULL)
618                 return NULL;
619
620         return __connman_device_get_ident(network->device);
621 }
622
623 /**
624  * connman_network_set_available:
625  * @network: network structure
626  * @available: availability state
627  *
628  * Change availability state of network (in range)
629  */
630 int connman_network_set_available(struct connman_network *network,
631                                                 connman_bool_t available)
632 {
633         DBusMessage *signal;
634         DBusMessageIter entry, value;
635         const char *key = "Available";
636
637         DBG("network %p available %d", network, available);
638
639         if (network->available == available)
640                 return -EALREADY;
641
642         network->available = available;
643
644         if (network->registered == FALSE)
645                 return 0;
646
647         if (network->connected == TRUE)
648                 return 0;
649
650         if (network->remember == FALSE)
651                 return 0;
652
653         signal = dbus_message_new_signal(network->element.path,
654                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
655         if (signal == NULL)
656                 return 0;
657
658         dbus_message_iter_init_append(signal, &entry);
659
660         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
661
662         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
663                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
664         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &available);
665         dbus_message_iter_close_container(&entry, &value);
666
667         g_dbus_send_message(connection, signal);
668
669         return 0;
670 }
671
672 /**
673  * connman_network_get_available:
674  * @network: network structure
675  *
676  * Get network available setting
677  */
678 connman_bool_t connman_network_get_available(struct connman_network *network)
679 {
680         return network->available;
681 }
682
683 static gboolean set_connected(gpointer user_data)
684 {
685         struct connman_network *network = user_data;
686
687         if (network->connected == TRUE) {
688                 struct connman_element *element;
689                 enum connman_element_type type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
690
691                 switch (network->protocol) {
692                 case CONNMAN_NETWORK_PROTOCOL_UNKNOWN:
693                         return 0;
694                 case CONNMAN_NETWORK_PROTOCOL_IP:
695                         type = CONNMAN_ELEMENT_TYPE_DHCP;
696                         break;
697                 case CONNMAN_NETWORK_PROTOCOL_PPP:
698                         type = CONNMAN_ELEMENT_TYPE_PPP;
699                         break;
700                 }
701
702                 __connman_device_increase_connections(network->device);
703
704                 __connman_device_set_network(network->device, network);
705
706                 connman_device_set_disconnected(network->device, FALSE);
707
708                 element = connman_element_create(NULL);
709                 if (element != NULL) {
710                         element->type  = type;
711                         element->index = network->element.index;
712
713                         if (connman_element_register(element,
714                                                 &network->element) < 0)
715                                 connman_element_unref(element);
716                 }
717         } else {
718                 connman_element_unregister_children(&network->element);
719
720                 __connman_device_set_network(network->device, NULL);
721
722                 __connman_device_decrease_connections(network->device);
723         }
724
725         return FALSE;
726 }
727
728 /**
729  * connman_network_set_connected:
730  * @network: network structure
731  * @connected: connected state
732  *
733  * Change connected state of network
734  */
735 int connman_network_set_connected(struct connman_network *network,
736                                                 connman_bool_t connected)
737 {
738         DBusMessage *signal;
739         DBusMessageIter entry, value;
740         const char *key = "Connected";
741
742         DBG("network %p connected %d", network, connected);
743
744         if (network->connected == connected)
745                 return -EALREADY;
746
747         network->connected = connected;
748
749         if (network->registered == FALSE) {
750                 g_idle_add(set_connected, network);
751                 return 0;
752         }
753
754         signal = dbus_message_new_signal(network->element.path,
755                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
756         if (signal == NULL)
757                 return 0;
758
759         dbus_message_iter_init_append(signal, &entry);
760
761         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
762
763         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
764                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
765         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &connected);
766         dbus_message_iter_close_container(&entry, &value);
767
768         g_dbus_send_message(connection, signal);
769
770         set_connected(network);
771
772         return 0;
773 }
774
775 /**
776  * connman_network_get_connected:
777  * @network: network structure
778  *
779  * Get network connection status
780  */
781 connman_bool_t connman_network_get_connected(struct connman_network *network)
782 {
783         return network->connected;
784 }
785
786 /**
787  * connman_network_set_remember:
788  * @network: network structure
789  * @remember: remember state
790  *
791  * Change remember state of network (known networks)
792  */
793 int connman_network_set_remember(struct connman_network *network,
794                                                 connman_bool_t remember)
795 {
796         DBusMessage *signal;
797         DBusMessageIter entry, value;
798         const char *key = "Remember";
799
800         DBG("network %p remember %d", network, remember);
801
802         if (network->remember == remember)
803                 return -EALREADY;
804
805         network->remember = remember;
806
807         if (network->registered == FALSE)
808                 return 0;
809
810         signal = dbus_message_new_signal(network->element.path,
811                                 CONNMAN_NETWORK_INTERFACE, "PropertyChanged");
812         if (signal == NULL)
813                 return 0;
814
815         dbus_message_iter_init_append(signal, &entry);
816
817         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
818
819         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
820                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
821         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &remember);
822         dbus_message_iter_close_container(&entry, &value);
823
824         g_dbus_send_message(connection, signal);
825
826         return 0;
827 }
828
829 /**
830  * connman_network_get_remember:
831  * @network: network structure
832  *
833  * Get network remember setting
834  */
835 connman_bool_t connman_network_get_remember(struct connman_network *network)
836 {
837         return network->remember;
838 }
839
840 /**
841  * connman_network_connect:
842  * @network: network structure
843  *
844  * Connect network
845  */
846 int connman_network_connect(struct connman_network *network)
847 {
848         if (network->connected == TRUE)
849                 return -EALREADY;
850
851         if (network->driver && network->driver->connect)
852                 return network->driver->connect(network);
853
854         network->connected = TRUE;
855
856         return 0;
857 }
858
859 int __connman_network_disconnect(struct connman_network *network)
860 {
861         if (network->connected == FALSE)
862                 return -ENOTCONN;
863
864         connman_element_unregister_children(&network->element);
865
866         if (network->driver && network->driver->disconnect)
867                 return network->driver->disconnect(network);
868
869         network->connected = FALSE;
870
871         return 0;
872 }
873
874 /**
875  * connman_network_set_string:
876  * @network: network structure
877  * @key: unique identifier
878  * @value: string value
879  *
880  * Set string value for specific key
881  */
882 int connman_network_set_string(struct connman_network *network,
883                                         const char *key, const char *value)
884 {
885         DBG("network %p key %s value %s", network, key, value);
886
887         if (g_str_equal(key, "Address") == TRUE) {
888                 g_free(network->address);
889                 network->address = g_strdup(value);
890         } else if (g_str_equal(key, "Name") == TRUE) {
891                 g_free(network->name);
892                 network->name = g_strdup(value);
893         } else if (g_str_equal(key, "Node") == TRUE) {
894                 g_free(network->node);
895                 network->node = g_strdup(value);
896         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
897                 g_free(network->wifi.mode);
898                 network->wifi.mode = g_strdup(value);
899         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
900                 g_free(network->wifi.security);
901                 network->wifi.security = g_strdup(value);
902         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
903                 g_free(network->wifi.passphrase);
904                 network->wifi.passphrase = g_strdup(value);
905         }
906
907         return connman_element_set_string(&network->element, key, value);
908 }
909
910 /**
911  * connman_network_get_string:
912  * @network: network structure
913  * @key: unique identifier
914  *
915  * Get string value for specific key
916  */
917 const char *connman_network_get_string(struct connman_network *network,
918                                                         const char *key)
919 {
920         DBG("network %p key %s", network, key);
921
922         if (g_str_equal(key, "Address") == TRUE)
923                 return network->address;
924         else if (g_str_equal(key, "Name") == TRUE)
925                 return network->name;
926         else if (g_str_equal(key, "Node") == TRUE)
927                 return network->node;
928         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
929                 return network->wifi.mode;
930         else if (g_str_equal(key, "WiFi.Security") == TRUE)
931                 return network->wifi.security;
932         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
933                 return network->wifi.passphrase;
934
935         return connman_element_get_string(&network->element, key);
936 }
937
938 /**
939  * connman_network_set_uint8:
940  * @network: network structure
941  * @key: unique identifier
942  * @value: integer value
943  *
944  * Set integer value for specific key
945  */
946 int connman_network_set_uint8(struct connman_network *network,
947                                         const char *key, connman_uint8_t value)
948 {
949         DBG("network %p key %s value %d", network, key, value);
950
951         if (g_str_equal(key, "Priority") == TRUE)
952                 network->priority = value;
953         else if (g_str_equal(key, "Strength") == TRUE)
954                 network->strength = value;
955
956         return connman_element_set_uint8(&network->element, key, value);
957 }
958
959 /**
960  * connman_network_get_uint8:
961  * @network: network structure
962  * @key: unique identifier
963  *
964  * Get integer value for specific key
965  */
966 connman_uint8_t connman_network_get_uint8(struct connman_network *network,
967                                                         const char *key)
968 {
969         DBG("network %p key %s", network, key);
970
971         if (g_str_equal(key, "Priority") == TRUE)
972                 return network->priority;
973         else if (g_str_equal(key, "Strength") == TRUE)
974                 return network->strength;
975
976         return connman_element_get_uint8(&network->element, key);
977 }
978
979 /**
980  * connman_network_set_blob:
981  * @network: network structure
982  * @key: unique identifier
983  * @data: blob data
984  * @size: blob size
985  *
986  * Set binary blob value for specific key
987  */
988 int connman_network_set_blob(struct connman_network *network,
989                         const char *key, const void *data, unsigned int size)
990 {
991         DBG("network %p key %s size %d", network, key, size);
992
993         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
994                 g_free(network->wifi.ssid);
995                 network->wifi.ssid = g_try_malloc(size);
996                 if (network->wifi.ssid != NULL) {
997                         memcpy(network->wifi.ssid, data, size);
998                         network->wifi.ssid_len = size;
999                 } else
1000                         network->wifi.ssid_len = 0;
1001         }
1002
1003         return connman_element_set_blob(&network->element, key, data, size);
1004 }
1005
1006 /**
1007  * connman_network_get_blob:
1008  * @network: network structure
1009  * @key: unique identifier
1010  * @size: pointer to blob size
1011  *
1012  * Get binary blob value for specific key
1013  */
1014 const void *connman_network_get_blob(struct connman_network *network,
1015                                         const char *key, unsigned int *size)
1016 {
1017         DBG("network %p key %s", network, key);
1018
1019         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
1020                 if (size != NULL)
1021                         *size = network->wifi.ssid_len;
1022                 return network->wifi.ssid;
1023         }
1024
1025         return connman_element_get_blob(&network->element, key, size);
1026 }
1027
1028 void __connman_network_set_device(struct connman_network *network,
1029                                         struct connman_device *device)
1030 {
1031         network->device = device;
1032 }
1033
1034 /**
1035  * connman_network_get_device:
1036  * @network: network structure
1037  *
1038  * Get parent device of network
1039  */
1040 struct connman_device *connman_network_get_device(struct connman_network *network)
1041 {
1042         return network->device;
1043 }
1044
1045 /**
1046  * connman_network_get_data:
1047  * @network: network structure
1048  *
1049  * Get private network data pointer
1050  */
1051 void *connman_network_get_data(struct connman_network *network)
1052 {
1053         return network->driver_data;
1054 }
1055
1056 /**
1057  * connman_network_set_data:
1058  * @network: network structure
1059  * @data: data pointer
1060  *
1061  * Set private network data pointer
1062  */
1063 void connman_network_set_data(struct connman_network *network, void *data)
1064 {
1065         network->driver_data = data;
1066 }
1067
1068 static gboolean match_driver(struct connman_network *network,
1069                                         struct connman_network_driver *driver)
1070 {
1071         if (network->type == driver->type ||
1072                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
1073                 return TRUE;
1074
1075         return FALSE;
1076 }
1077
1078 static int network_probe(struct connman_element *element)
1079 {
1080         struct connman_network *network = element->network;
1081         GSList *list;
1082         int err;
1083
1084         DBG("element %p name %s", element, element->name);
1085
1086         if (network == NULL)
1087                 return -ENODEV;
1088
1089         for (list = driver_list; list; list = list->next) {
1090                 struct connman_network_driver *driver = list->data;
1091
1092                 if (match_driver(network, driver) == FALSE)
1093                         continue;
1094
1095                 DBG("driver %p name %s", driver, driver->name);
1096
1097                 if (driver->probe(network) == 0) {
1098                         network->driver = driver;
1099                         break;
1100                 }
1101         }
1102
1103         if (network->driver == NULL)
1104                 return -ENODEV;
1105
1106         err = register_interface(element);
1107         if (err < 0) {
1108                 if (network->driver->remove)
1109                         network->driver->remove(network);
1110                 return err;
1111         }
1112
1113         network->secondary = connman_device_get_secondary(network->device);
1114
1115         switch (network->type) {
1116         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1117         case CONNMAN_NETWORK_TYPE_VENDOR:
1118         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1119         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1120         case CONNMAN_NETWORK_TYPE_HSO:
1121                 break;
1122         case CONNMAN_NETWORK_TYPE_WIFI:
1123         case CONNMAN_NETWORK_TYPE_WIMAX:
1124                 if (network->secondary == FALSE)
1125                         __connman_profile_add_network(network);
1126                 break;
1127         }
1128
1129         return 0;
1130 }
1131
1132 static void network_remove(struct connman_element *element)
1133 {
1134         struct connman_network *network = element->network;
1135
1136         DBG("element %p name %s", element, element->name);
1137
1138         if (network == NULL)
1139                 return;
1140
1141         if (network->driver == NULL)
1142                 return;
1143
1144         switch (network->type) {
1145         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1146         case CONNMAN_NETWORK_TYPE_VENDOR:
1147         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1148         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1149         case CONNMAN_NETWORK_TYPE_HSO:
1150                 break;
1151         case CONNMAN_NETWORK_TYPE_WIFI:
1152         case CONNMAN_NETWORK_TYPE_WIMAX:
1153                 if (network->secondary == FALSE)
1154                         __connman_profile_remove_network(network);
1155                 break;
1156         }
1157
1158         unregister_interface(element);
1159
1160         if (network->driver->remove)
1161                 network->driver->remove(network);
1162 }
1163
1164 static void network_change(struct connman_element *element)
1165 {
1166         struct connman_network *network = element->network;
1167
1168         DBG("element %p name %s", element, element->name);
1169
1170         if (element->state != CONNMAN_ELEMENT_STATE_ERROR)
1171                 return;
1172
1173         if (element->error != CONNMAN_ELEMENT_ERROR_DHCP_FAILED)
1174                 return;
1175
1176         if (network->connected == FALSE)
1177                 return;
1178
1179         connman_element_unregister_children(element);
1180
1181         connman_device_set_disconnected(network->device, TRUE);
1182
1183         if (network->driver && network->driver->disconnect) {
1184                 network->driver->disconnect(network);
1185                 return;
1186         }
1187
1188         network->connected = FALSE;
1189 }
1190
1191 static struct connman_driver network_driver = {
1192         .name           = "network",
1193         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
1194         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1195         .probe          = network_probe,
1196         .remove         = network_remove,
1197         .change         = network_change,
1198 };
1199
1200 static int network_init(struct connman_device *device)
1201 {
1202         DBG("device %p", device);
1203
1204         return 0;
1205 }
1206
1207 static int network_load(struct connman_network *network)
1208 {
1209         GKeyFile *keyfile;
1210         gchar *pathname, *data = NULL;
1211         gsize length;
1212         const char *name;
1213         char *str;
1214         int val;
1215
1216         DBG("network %p", network);
1217
1218         name = connman_device_get_name(network->device);
1219         if (name == NULL)
1220                 return -EINVAL;
1221
1222         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
1223         if (pathname == NULL)
1224                 return -ENOMEM;
1225
1226         keyfile = g_key_file_new();
1227
1228         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1229                 g_free(pathname);
1230                 return -ENOENT;
1231         }
1232
1233         g_free(pathname);
1234
1235         if (g_key_file_load_from_data(keyfile, data, length,
1236                                                         0, NULL) == FALSE) {
1237                 g_free(data);
1238                 return -EILSEQ;
1239         }
1240
1241         g_free(data);
1242
1243         network->remember = g_key_file_get_boolean(keyfile,
1244                                         network->identifier, "Remember", NULL);
1245
1246         val = g_key_file_get_integer(keyfile, network->identifier,
1247                                                         "Priority", NULL);
1248         if (val > 0)
1249                 network->priority = val;
1250
1251         str = g_key_file_get_string(keyfile,
1252                                 network->identifier, "WiFi.Security", NULL);
1253         if (str != NULL) {
1254                 g_free(network->wifi.security);
1255                 network->wifi.security = str;
1256         }
1257
1258         str = g_key_file_get_string(keyfile,
1259                                 network->identifier, "WiFi.Passphrase", NULL);
1260         if (str != NULL) {
1261                 g_free(network->wifi.passphrase);
1262                 network->wifi.passphrase = str;
1263         }
1264
1265         g_key_file_free(keyfile);
1266
1267         return 0;
1268 }
1269
1270 static int network_save(struct connman_network *network)
1271 {
1272         GKeyFile *keyfile;
1273         gchar *pathname, *data = NULL;
1274         gsize length;
1275         const char *name;
1276
1277         DBG("network %p", network);
1278
1279         name = connman_device_get_name(network->device);
1280         if (name == NULL)
1281                 return -EINVAL;
1282
1283         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, name);
1284         if (pathname == NULL)
1285                 return -ENOMEM;
1286
1287         keyfile = g_key_file_new();
1288
1289         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1290                 goto update;
1291
1292         if (length > 0) {
1293                 if (g_key_file_load_from_data(keyfile, data, length,
1294                                                         0, NULL) == FALSE)
1295                         goto done;
1296         }
1297
1298         g_free(data);
1299
1300 update:
1301         g_key_file_set_boolean(keyfile, network->identifier,
1302                                         "Remember", network->remember);
1303
1304         if (network->priority > 0)
1305                 g_key_file_set_integer(keyfile, network->identifier,
1306                                                 "Priority", network->priority);
1307
1308         if (network->remember == TRUE || network->connected == TRUE) {
1309                 if (network->wifi.security != NULL)
1310                         g_key_file_set_string(keyfile, network->identifier,
1311                                 "WiFi.Security", network->wifi.security);
1312
1313                 if (network->wifi.passphrase != NULL)
1314                         g_key_file_set_string(keyfile, network->identifier,
1315                                 "WiFi.Passphrase", network->wifi.passphrase);
1316         }
1317
1318         data = g_key_file_to_data(keyfile, &length, NULL);
1319
1320         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
1321                 connman_error("Failed to store network information");
1322
1323 done:
1324         g_free(data);
1325
1326         g_key_file_free(keyfile);
1327
1328         g_free(pathname);
1329
1330         return 0;
1331 }
1332
1333 static struct connman_storage network_storage = {
1334         .name           = "network",
1335         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1336         .network_init   = network_init,
1337         .network_load   = network_load,
1338         .network_save   = network_save,
1339 };
1340
1341 int __connman_network_init(void)
1342 {
1343         DBG("");
1344
1345         connection = connman_dbus_get_connection();
1346
1347         if (connman_storage_register(&network_storage) < 0)
1348                 connman_error("Failed to register network storage");
1349
1350         return connman_driver_register(&network_driver);
1351 }
1352
1353 void __connman_network_cleanup(void)
1354 {
1355         DBG("");
1356
1357         connman_driver_unregister(&network_driver);
1358
1359         connman_storage_unregister(&network_storage);
1360
1361         dbus_connection_unref(connection);
1362 }