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