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