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