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