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