c36ddcb4e8a4d58c8bc3c08fde89b9b1304c7fa6
[framework/connectivity/connman.git] / src / network.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 "connman.h"
30
31 static unsigned int hidden_counter = 0;
32
33 struct connman_network {
34         struct connman_element element;
35         enum connman_network_type type;
36         connman_bool_t available;
37         connman_bool_t connected;
38         connman_bool_t roaming;
39         connman_bool_t hidden;
40         connman_uint8_t strength;
41         connman_uint16_t frequency;
42         char *identifier;
43         char *name;
44         char *node;
45         char *group;
46
47         struct connman_network_driver *driver;
48         void *driver_data;
49
50         connman_bool_t connecting;
51         connman_bool_t associating;
52
53         struct connman_device *device;
54
55         struct {
56                 void *ssid;
57                 int ssid_len;
58                 char *mode;
59                 unsigned short channel;
60                 char *security;
61                 char *passphrase;
62                 char *eap;
63                 char *identity;
64                 char *ca_cert_path;
65                 char *client_cert_path;
66                 char *private_key_path;
67                 char *private_key_passphrase;
68                 char *phase2_auth;
69                 connman_bool_t wps;
70                 connman_bool_t use_wps;
71                 char *pin_wps;
72         } wifi;
73 };
74
75 static const char *type2string(enum connman_network_type type)
76 {
77         switch (type) {
78         case CONNMAN_NETWORK_TYPE_UNKNOWN:
79         case CONNMAN_NETWORK_TYPE_VENDOR:
80                 break;
81         case CONNMAN_NETWORK_TYPE_ETHERNET:
82                 return "ethernet";
83         case CONNMAN_NETWORK_TYPE_WIFI:
84                 return "wifi";
85         case CONNMAN_NETWORK_TYPE_WIMAX:
86                 return "wimax";
87         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
88         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
89                 return "bluetooth";
90         case CONNMAN_NETWORK_TYPE_CELLULAR:
91                 return "cellular";
92         }
93
94         return NULL;
95 }
96
97 connman_bool_t __connman_network_has_driver(struct connman_network *network)
98 {
99         if (network == NULL || network->driver == NULL)
100                 return FALSE;
101
102         return TRUE;
103 }
104
105 static GSList *driver_list = NULL;
106
107 static gint compare_priority(gconstpointer a, gconstpointer b)
108 {
109         const struct connman_network_driver *driver1 = a;
110         const struct connman_network_driver *driver2 = b;
111
112         return driver2->priority - driver1->priority;
113 }
114
115 /**
116  * connman_network_driver_register:
117  * @driver: network driver definition
118  *
119  * Register a new network driver
120  *
121  * Returns: %0 on success
122  */
123 int connman_network_driver_register(struct connman_network_driver *driver)
124 {
125         GSList *list;
126
127         DBG("driver %p name %s", driver, driver->name);
128
129         for (list = driver_list; list; list = list->next) {
130                 struct connman_network_driver *tmp = list->data;
131
132                 if (tmp->type == driver->type)
133                         return -EALREADY;
134
135         }
136
137         driver_list = g_slist_insert_sorted(driver_list, driver,
138                                                         compare_priority);
139
140         return 0;
141 }
142
143 /**
144  * connman_network_driver_unregister:
145  * @driver: network driver definition
146  *
147  * Remove a previously registered network driver
148  */
149 void connman_network_driver_unregister(struct connman_network_driver *driver)
150 {
151         DBG("driver %p name %s", driver, driver->name);
152
153         driver_list = g_slist_remove(driver_list, driver);
154 }
155
156 static void network_destruct(struct connman_element *element)
157 {
158         struct connman_network *network = element->network;
159
160         DBG("element %p name %s", element, element->name);
161
162         g_free(network->wifi.ssid);
163         g_free(network->wifi.mode);
164         g_free(network->wifi.security);
165         g_free(network->wifi.passphrase);
166         g_free(network->wifi.eap);
167         g_free(network->wifi.identity);
168         g_free(network->wifi.ca_cert_path);
169         g_free(network->wifi.client_cert_path);
170         g_free(network->wifi.private_key_path);
171         g_free(network->wifi.private_key_passphrase);
172         g_free(network->wifi.phase2_auth);
173         g_free(network->wifi.pin_wps);
174
175         g_free(network->group);
176         g_free(network->node);
177         g_free(network->name);
178         g_free(network->identifier);
179
180         network->device = NULL;
181 }
182
183 /**
184  * connman_network_create:
185  * @identifier: network identifier (for example an unqiue name)
186  *
187  * Allocate a new network and assign the #identifier to it.
188  *
189  * Returns: a newly-allocated #connman_network structure
190  */
191 struct connman_network *connman_network_create(const char *identifier,
192                                                 enum connman_network_type type)
193 {
194         struct connman_network *network;
195         connman_uint8_t strength = 0;
196         const char *str;
197         char *temp;
198
199         DBG("identifier %s type %d", identifier, type);
200
201         network = g_try_new0(struct connman_network, 1);
202         if (network == NULL)
203                 return NULL;
204
205         DBG("network %p", network);
206
207         __connman_element_initialize(&network->element);
208
209         if (identifier == NULL) {
210                 temp = g_strdup_printf("hidden_%d", hidden_counter++);
211                 network->hidden = TRUE;
212         } else
213                 temp = g_strdup(identifier);
214
215         if (temp == NULL) {
216                 g_free(network);
217                 return NULL;
218         }
219
220         network->element.name = temp;
221         network->element.type = CONNMAN_ELEMENT_TYPE_NETWORK;
222
223         network->element.network = network;
224         network->element.destruct = network_destruct;
225
226         str = type2string(type);
227         if (str != NULL)
228                 connman_element_set_string(&network->element, "Type", str);
229
230         connman_element_set_uint8(&network->element, "Strength", strength);
231
232         network->type       = type;
233         network->identifier = g_strdup(temp);
234
235         return network;
236 }
237
238 /**
239  * connman_network_ref:
240  * @network: network structure
241  *
242  * Increase reference counter of  network
243  */
244 struct connman_network *connman_network_ref(struct connman_network *network)
245 {
246         if (connman_element_ref(&network->element) == NULL)
247                 return NULL;
248
249         return network;
250 }
251
252 /**
253  * connman_network_unref:
254  * @network: network structure
255  *
256  * Decrease reference counter of network
257  */
258 void connman_network_unref(struct connman_network *network)
259 {
260         connman_element_unref(&network->element);
261 }
262
263 const char *__connman_network_get_type(struct connman_network *network)
264 {
265         return type2string(network->type);
266 }
267
268 /**
269  * connman_network_get_type:
270  * @network: network structure
271  *
272  * Get type of network
273  */
274 enum connman_network_type connman_network_get_type(struct connman_network *network)
275 {
276         return network->type;
277 }
278
279 /**
280  * connman_network_get_identifier:
281  * @network: network structure
282  *
283  * Get identifier of network
284  */
285 const char *connman_network_get_identifier(struct connman_network *network)
286 {
287         return network->identifier;
288 }
289
290 /**
291  * connman_network_set_index:
292  * @network: network structure
293  * @index: index number
294  *
295  * Set index number of network
296  */
297 void connman_network_set_index(struct connman_network *network, int index)
298 {
299         struct connman_service *service;
300         struct connman_ipconfig *ipconfig;
301
302         service = __connman_service_lookup_from_network(network);
303         if (service == NULL)
304                 goto done;
305
306         ipconfig = __connman_service_get_ip4config(service);
307
308         DBG("index %d service %p ip4config %p", network->element.index,
309                 service, ipconfig);
310
311         if (network->element.index < 0 && ipconfig == NULL) {
312
313                 ipconfig = __connman_service_get_ip4config(service);
314                 if (ipconfig == NULL)
315                         /*
316                          * This is needed for plugins that havent set their
317                          * ipconfig layer yet, due to not being able to get
318                          * a network index prior to creating a service.
319                          */
320                         __connman_service_create_ip4config(service, index);
321                 else
322                         __connman_ipconfig_set_index(ipconfig, index);
323
324         } else {
325                 /* If index changed, the index of ipconfig must be reset. */
326                 if (ipconfig == NULL)
327                         goto done;
328
329                 __connman_ipconfig_set_index(ipconfig, index);
330         }
331
332 done:
333         network->element.index = index;
334 }
335
336 /**
337  * connman_network_get_index:
338  * @network: network structure
339  *
340  * Get index number of network
341  */
342 int connman_network_get_index(struct connman_network *network)
343 {
344         return network->element.index;
345 }
346
347 /**
348  * connman_network_get_element:
349  * @network: network structure
350  *
351  * Get connman_element of network
352  */
353 struct connman_element *connman_network_get_element(
354                                 struct connman_network *network)
355 {
356         return &network->element;
357 }
358
359 /**
360  * connman_network_set_group:
361  * @network: network structure
362  * @group: group name
363  *
364  * Set group name for automatic clustering
365  */
366 void connman_network_set_group(struct connman_network *network,
367                                                         const char *group)
368 {
369         switch (network->type) {
370         case CONNMAN_NETWORK_TYPE_UNKNOWN:
371         case CONNMAN_NETWORK_TYPE_VENDOR:
372                 return;
373         case CONNMAN_NETWORK_TYPE_ETHERNET:
374         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
375         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
376         case CONNMAN_NETWORK_TYPE_CELLULAR:
377         case CONNMAN_NETWORK_TYPE_WIFI:
378         case CONNMAN_NETWORK_TYPE_WIMAX:
379                 break;
380         }
381
382         if (g_strcmp0(network->group, group) == 0) {
383                 if (group != NULL)
384                         __connman_profile_update_network(network);
385                 return;
386         }
387
388         if (network->group != NULL) {
389                 __connman_profile_remove_network(network);
390
391                 g_free(network->group);
392         }
393
394         network->group = g_strdup(group);
395
396         if (network->group != NULL)
397                         __connman_profile_add_network(network);
398 }
399
400 /**
401  * connman_network_get_group:
402  * @network: network structure
403  *
404  * Get group name for automatic clustering
405  */
406 const char *connman_network_get_group(struct connman_network *network)
407 {
408         return network->group;
409 }
410
411 const char *__connman_network_get_ident(struct connman_network *network)
412 {
413         if (network->device == NULL)
414                 return NULL;
415
416         return connman_device_get_ident(network->device);
417 }
418
419 connman_bool_t __connman_network_get_weakness(struct connman_network *network)
420 {
421         switch (network->type) {
422         case CONNMAN_NETWORK_TYPE_UNKNOWN:
423         case CONNMAN_NETWORK_TYPE_VENDOR:
424         case CONNMAN_NETWORK_TYPE_ETHERNET:
425         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
426         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
427         case CONNMAN_NETWORK_TYPE_CELLULAR:
428         case CONNMAN_NETWORK_TYPE_WIMAX:
429                 break;
430         case CONNMAN_NETWORK_TYPE_WIFI:
431                 if (g_strcmp0(network->wifi.mode, "adhoc") == 0)
432                         return TRUE;
433                 if (network->strength > 0 && network->strength < 20)
434                         return TRUE;
435                 break;
436         }
437
438         return FALSE;
439 }
440
441 connman_bool_t __connman_network_get_connecting(struct connman_network *network)
442 {
443         return network->connecting;
444 }
445
446 /**
447  * connman_network_set_available:
448  * @network: network structure
449  * @available: availability state
450  *
451  * Change availability state of network (in range)
452  */
453 int connman_network_set_available(struct connman_network *network,
454                                                 connman_bool_t available)
455 {
456         DBG("network %p available %d", network, available);
457
458         if (network->available == available)
459                 return -EALREADY;
460
461         network->available = available;
462
463         return 0;
464 }
465
466 /**
467  * connman_network_get_available:
468  * @network: network structure
469  *
470  * Get network available setting
471  */
472 connman_bool_t connman_network_get_available(struct connman_network *network)
473 {
474         if (network->hidden == TRUE)
475                 return TRUE;
476
477         return network->available;
478 }
479
480 /**
481  * connman_network_set_associating:
482  * @network: network structure
483  * @associating: associating state
484  *
485  * Change associating state of network
486  */
487 int connman_network_set_associating(struct connman_network *network,
488                                                 connman_bool_t associating)
489 {
490         DBG("network %p associating %d", network, associating);
491
492         if (network->associating == associating)
493                 return -EALREADY;
494
495         network->associating = associating;
496
497         if (associating == TRUE) {
498                 struct connman_service *service;
499
500                 service = __connman_service_lookup_from_network(network);
501                 __connman_service_indicate_state(service,
502                                         CONNMAN_SERVICE_STATE_ASSOCIATION,
503                                         CONNMAN_IPCONFIG_TYPE_IPV4);
504         }
505
506         return 0;
507 }
508
509 static void set_associate_error(struct connman_network *network)
510 {
511         struct connman_service *service;
512
513         if (network->associating == FALSE)
514                 return ;
515
516         network->associating = FALSE;
517
518         service = __connman_service_lookup_from_network(network);
519
520         __connman_service_indicate_state(service,
521                                         CONNMAN_SERVICE_STATE_FAILURE,
522                                         CONNMAN_IPCONFIG_TYPE_IPV4);
523 }
524
525 static void set_configure_error(struct connman_network *network)
526 {
527         struct connman_service *service;
528
529         network->connecting = FALSE;
530
531         service = __connman_service_lookup_from_network(network);
532
533         __connman_service_indicate_state(service,
534                                         CONNMAN_SERVICE_STATE_FAILURE,
535                                         CONNMAN_IPCONFIG_TYPE_IPV4);
536 }
537
538 static void set_invalid_key_error(struct connman_network *network)
539 {
540         struct connman_service *service;
541
542         service = __connman_service_lookup_from_network(network);
543
544         __connman_service_indicate_error(service,
545                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
546 }
547
548 void connman_network_set_ipv4_method(struct connman_network *network,
549                                         enum connman_ipconfig_method method)
550 {
551         struct connman_service *service;
552         struct connman_ipconfig *ipconfig;
553
554         network->element.ipv4.method = method;
555
556         service = __connman_service_lookup_from_network(network);
557         if (service == NULL)
558                 return;
559
560         ipconfig = __connman_service_get_ip4config(service);
561         if (ipconfig == NULL)
562                 return;
563
564         connman_ipconfig_set_method(ipconfig, method);
565 }
566
567 void connman_network_set_ipv6_method(struct connman_network *network,
568                                         enum connman_ipconfig_method method)
569 {
570         struct connman_service *service;
571         struct connman_ipconfig *ipconfig;
572
573         network->element.ipv6.method = method;
574
575         service = __connman_service_lookup_from_network(network);
576         if (service == NULL)
577                 return;
578
579         ipconfig = __connman_service_get_ip6config(service);
580         if (ipconfig == NULL)
581                 return;
582
583         connman_ipconfig_set_method(ipconfig, method);
584 }
585
586 void connman_network_set_error(struct connman_network *network,
587                                         enum connman_network_error error)
588 {
589         DBG("nework %p, error %d", network, error);
590
591         network->connecting = FALSE;
592
593         switch (error) {
594         case CONNMAN_NETWORK_ERROR_UNKNOWN:
595                 return;
596         case CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL:
597                 set_associate_error(network);
598                 break;
599         case CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL:
600                 set_configure_error(network);
601                 break;
602         case CONNMAN_NETWORK_ERROR_INVALID_KEY:
603                 set_invalid_key_error(network);
604                 break;
605         }
606 }
607
608 void connman_network_clear_error(struct connman_network *network)
609 {
610         struct connman_service *service;
611
612         DBG("network %p", network);
613
614         if (network == NULL)
615                 return;
616
617         if (network->connecting == TRUE || network->associating == TRUE)
618                 return;
619
620         service = __connman_service_lookup_from_network(network);
621         __connman_service_clear_error(service);
622 }
623
624 static void set_configuration(struct connman_network *network)
625 {
626         struct connman_service *service;
627
628         DBG("network %p", network);
629
630         __connman_device_increase_connections(network->device);
631
632         __connman_device_set_network(network->device, network);
633
634         connman_device_set_disconnected(network->device, FALSE);
635
636         service = __connman_service_lookup_from_network(network);
637         __connman_service_indicate_state(service,
638                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
639                                         CONNMAN_IPCONFIG_TYPE_IPV4);
640 }
641
642 static void dhcp_success(struct connman_network *network)
643 {
644         struct connman_service *service;
645         struct connman_ipconfig *ipconfig_ipv4;
646         int err;
647
648         service = __connman_service_lookup_from_network(network);
649         if (service == NULL)
650                 goto err;
651
652         connman_network_set_associating(network, FALSE);
653
654         network->connecting = FALSE;
655
656         ipconfig_ipv4 = __connman_service_get_ip4config(service);
657         err = __connman_ipconfig_address_add(ipconfig_ipv4);
658         if (err < 0)
659                 goto err;
660
661         err = __connman_ipconfig_gateway_add(ipconfig_ipv4);
662         if (err < 0)
663                 goto err;
664
665         __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
666                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
667
668         return;
669
670 err:
671         connman_network_set_error(network,
672                                 CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
673 }
674
675 static void dhcp_failure(struct connman_network *network)
676 {
677         struct connman_service *service;
678         struct connman_ipconfig *ipconfig_ipv4;
679
680         service = __connman_service_lookup_from_network(network);
681         if (service == NULL)
682                 return;
683
684         ipconfig_ipv4 = __connman_service_get_ip4config(service);
685         __connman_ipconfig_address_remove(ipconfig_ipv4);
686
687         __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_IDLE,
688                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
689 }
690
691 static void dhcp_callback(struct connman_network *network,
692                         connman_bool_t success)
693 {
694         DBG("success %d", success);
695
696         if (success == TRUE)
697                 dhcp_success(network);
698         else
699                 dhcp_failure(network);
700 }
701
702 static int set_connected_fixed(struct connman_network *network)
703 {
704         struct connman_service *service;
705         struct connman_element *parent, *element;
706
707         DBG("");
708
709         service = __connman_service_lookup_from_network(network);
710
711         parent = connman_network_get_element(network);
712
713         set_configuration(network);
714
715         if (parent->ipv4.address == NULL)
716                 return -EINVAL;
717
718         if (parent->ipv4.netmask == NULL)
719                 return -EINVAL;
720
721         element = connman_element_create(NULL);
722         if (element == NULL) {
723                 connman_error("Can not create connman_element");
724                 return -ENOMEM;
725         }
726
727         element->type = CONNMAN_ELEMENT_TYPE_IPV4;
728         element->index = parent->index;
729
730         if (connman_element_register(element, parent) < 0) {
731                 connman_error("Can not register connman_element");
732                 return -EINVAL;
733         }
734
735         network->connecting = FALSE;
736
737         connman_network_set_associating(network, FALSE);
738
739         return 0;
740 }
741
742 static void set_connected_manual(struct connman_network *network)
743 {
744         struct connman_service *service;
745         struct connman_ipconfig *ipconfig;
746         const char *nameserver = NULL;
747         const char *gateway;
748         int err;
749
750         DBG("network %p", network);
751
752         service = __connman_service_lookup_from_network(network);
753
754         ipconfig = __connman_service_get_ip4config(service);
755
756         set_configuration(network);
757
758         err = __connman_ipconfig_address_add(ipconfig);
759         if (err < 0)
760                 goto err;
761
762         connman_element_get_value(&network->element,
763                         CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
764         if (nameserver != NULL)
765                 __connman_service_nameserver_append(service, nameserver);
766
767         connman_element_get_value(&network->element,
768                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
769         if (gateway != NULL) {
770                 __connman_ipconfig_set_gateway(ipconfig, gateway);
771                 err = __connman_ipconfig_gateway_add(ipconfig);
772                 if (err < 0)
773                         goto err;
774         }
775
776         network->connecting = FALSE;
777
778         connman_network_set_associating(network, FALSE);
779
780         __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
781                                         CONNMAN_IPCONFIG_TYPE_IPV4);
782
783 err:
784         connman_network_set_error(network,
785                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
786         return;
787 }
788
789 static int set_connected_dhcp(struct connman_network *network)
790 {
791         int err;
792
793         DBG("network %p", network);
794
795         set_configuration(network);
796
797         err = __connman_dhcp_start(network, dhcp_callback);
798         if (err < 0) {
799                 connman_error("Can not request DHCP lease");
800                 return err;
801         }
802
803         return 0;
804 }
805
806 static int manual_ipv6_set(struct connman_network *network,
807                                 struct connman_ipconfig *ipconfig_ipv6)
808 {
809         struct connman_service *service;
810         int err;
811
812         service = __connman_service_lookup_from_network(network);
813         if (service == NULL)
814                 return -EINVAL;
815
816         err = __connman_ipconfig_address_add(ipconfig_ipv6);
817         if (err < 0) {
818                 connman_network_set_error(network,
819                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
820                 return err;
821         }
822
823         /*
824          * READY state will be indicated by IPV4 setting
825          * gateway will be set by IPV4 setting
826          */
827
828         return 0;
829 }
830
831 static void autoconf_ipv6_set(struct connman_network *network)
832 {
833         struct connman_service *service;
834         struct connman_ipconfig *ipconfig;
835         const char *nameserver = NULL;
836
837         DBG("network %p", network);
838
839         service = __connman_service_lookup_from_network(network);
840
841         ipconfig = __connman_service_get_ip6config(service);
842
843         __connman_device_increase_connections(network->device);
844
845         __connman_device_set_network(network->device, network);
846
847         connman_device_set_disconnected(network->device, FALSE);
848
849         connman_element_get_value(&network->element,
850                         CONNMAN_PROPERTY_ID_IPV6_NAMESERVER, &nameserver);
851         if (nameserver != NULL)
852                 __connman_service_nameserver_append(service, nameserver);
853
854         network->connecting = FALSE;
855
856         __connman_service_indicate_state(service,
857                                         CONNMAN_SERVICE_STATE_READY,
858                                         CONNMAN_IPCONFIG_TYPE_IPV6);
859 }
860
861 static gboolean set_connected(gpointer user_data)
862 {
863         struct connman_network *network = user_data;
864         struct connman_service *service;
865         struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
866         enum connman_ipconfig_method ipv4_method, ipv6_method;
867
868         service = __connman_service_lookup_from_network(network);
869
870         ipconfig_ipv4 = __connman_service_get_ip4config(service);
871         ipconfig_ipv6 = __connman_service_get_ip6config(service);
872
873         DBG("service %p ipv4 %p ipv6 %p", service, ipconfig_ipv4,
874                 ipconfig_ipv6);
875
876         ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4);
877         ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6);
878
879         DBG("method ipv4 %d ipv6 %d", ipv4_method, ipv6_method);
880         DBG("network connected %d", network->connected);
881
882         if (network->connected == TRUE) {
883                 int ret;
884
885                 switch (ipv6_method) {
886                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
887                 case CONNMAN_IPCONFIG_METHOD_OFF:
888                         break;
889                 case CONNMAN_IPCONFIG_METHOD_AUTO:
890                         autoconf_ipv6_set(network);
891                         break;
892                 case CONNMAN_IPCONFIG_METHOD_FIXED:
893                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
894                         ret = manual_ipv6_set(network, ipconfig_ipv6);
895                         if (ret != 0) {
896                                 connman_network_set_error(network,
897                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
898                                 return FALSE;
899                         }
900                         break;
901                 case CONNMAN_IPCONFIG_METHOD_DHCP:
902                         break;
903                 }
904
905                 switch (ipv4_method) {
906                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
907                 case CONNMAN_IPCONFIG_METHOD_OFF:
908                 case CONNMAN_IPCONFIG_METHOD_AUTO:
909                         return FALSE;
910                 case CONNMAN_IPCONFIG_METHOD_FIXED:
911                         if (set_connected_fixed(network) < 0) {
912                                 connman_network_set_error(network,
913                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
914                                 return FALSE;
915                         }
916                         return TRUE;
917                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
918                         set_connected_manual(network);
919                         return TRUE;
920                 case CONNMAN_IPCONFIG_METHOD_DHCP:
921                         if (set_connected_dhcp(network) < 0) {
922                                 connman_network_set_error(network,
923                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
924                                 return FALSE;
925                         }
926                 }
927
928         } else {
929                 struct connman_service *service;
930
931                 connman_element_unregister_children(&network->element);
932
933                 __connman_device_set_network(network->device, NULL);
934                 network->hidden = FALSE;
935
936                 service = __connman_service_lookup_from_network(network);
937
938                 __connman_service_indicate_state(service,
939                                         CONNMAN_SERVICE_STATE_IDLE,
940                                         CONNMAN_IPCONFIG_TYPE_IPV4);
941
942                 /* TODO: eventually the IPv6 disconnect state should be handled
943                  * in connection.c
944                  */
945                 __connman_service_indicate_state(service,
946                                         CONNMAN_SERVICE_STATE_DISCONNECT,
947                                         CONNMAN_IPCONFIG_TYPE_IPV6);
948
949                 __connman_service_indicate_state(service,
950                                         CONNMAN_SERVICE_STATE_IDLE,
951                                         CONNMAN_IPCONFIG_TYPE_IPV6);
952         }
953
954         network->connecting = FALSE;
955
956         connman_network_set_associating(network, FALSE);
957
958         return FALSE;
959 }
960
961 /**
962  * connman_network_set_connected:
963  * @network: network structure
964  * @connected: connected state
965  *
966  * Change connected state of network
967  */
968 int connman_network_set_connected(struct connman_network *network,
969                                                 connman_bool_t connected)
970 {
971         DBG("network %p connected %d", network, connected);
972
973         if ((network->connecting == TRUE || network->associating == TRUE) &&
974                                                         connected == FALSE) {
975                 connman_element_set_error(&network->element,
976                                         CONNMAN_ELEMENT_ERROR_CONNECT_FAILED);
977                 __connman_network_disconnect(network);
978         }
979
980         if (network->connected == connected)
981                 return -EALREADY;
982
983         if (connected == FALSE)
984                 __connman_device_decrease_connections(network->device);
985
986         network->connected = connected;
987
988         set_connected(network);
989
990         return 0;
991 }
992
993 /**
994  * connman_network_get_connected:
995  * @network: network structure
996  *
997  * Get network connection status
998  */
999 connman_bool_t connman_network_get_connected(struct connman_network *network)
1000 {
1001         return network->connected;
1002 }
1003
1004 /**
1005  * connman_network_get_associating:
1006  * @network: network structure
1007  *
1008  * Get network associating status
1009  */
1010 connman_bool_t connman_network_get_associating(struct connman_network *network)
1011 {
1012         return network->associating;
1013 }
1014
1015 /**
1016  * __connman_network_connect:
1017  * @network: network structure
1018  *
1019  * Connect network
1020  */
1021 int __connman_network_connect(struct connman_network *network)
1022 {
1023         struct connman_service *service;
1024         int err;
1025
1026         DBG("network %p", network);
1027
1028         if (network->connected == TRUE)
1029                 return -EISCONN;
1030
1031         if (network->connecting == TRUE || network->associating == TRUE)
1032                 return -EALREADY;
1033
1034         if (network->driver == NULL)
1035                 return -EUNATCH;
1036
1037         if (network->driver->connect == NULL)
1038                 return -ENOSYS;
1039
1040         if (network->device == NULL)
1041                 return -ENODEV;
1042
1043         network->connecting = TRUE;
1044
1045         __connman_device_disconnect(network->device);
1046
1047         service = __connman_service_lookup_from_network(network);
1048
1049         err = network->driver->connect(network);
1050         if (err < 0) {
1051                 if (err == -EINPROGRESS)
1052                         connman_network_set_associating(network, TRUE);
1053                 else {
1054                         network->connecting = FALSE;
1055                         network->hidden = FALSE;
1056                 }
1057
1058                 return err;
1059         }
1060
1061         network->connected = TRUE;
1062         set_connected(network);
1063
1064         return err;
1065 }
1066
1067 /**
1068  * __connman_network_disconnect:
1069  * @network: network structure
1070  *
1071  * Disconnect network
1072  */
1073 int __connman_network_disconnect(struct connman_network *network)
1074 {
1075         int err;
1076
1077         DBG("network %p", network);
1078
1079         if (network->connected == FALSE && network->connecting == FALSE &&
1080                                                 network->associating == FALSE)
1081                 return -ENOTCONN;
1082
1083         if (network->driver == NULL)
1084                 return -EUNATCH;
1085
1086         if (network->driver->disconnect == NULL)
1087                 return -ENOSYS;
1088
1089         network->connecting = FALSE;
1090
1091         err = network->driver->disconnect(network);
1092         if (err == 0) {
1093                 connman_network_set_connected(network, FALSE);
1094                 set_connected(network);
1095         }
1096
1097         return err;
1098 }
1099
1100 static int manual_ipv4_set(struct connman_network *network,
1101                                 struct connman_ipconfig *ipconfig)
1102 {
1103         struct connman_service *service;
1104         const char *gateway;
1105         int err;
1106
1107         service = __connman_service_lookup_from_network(network);
1108         if (service == NULL)
1109                 return -EINVAL;
1110
1111         err = __connman_ipconfig_address_add(ipconfig);
1112         if (err < 0) {
1113                 connman_network_set_error(network,
1114                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
1115                 return err;
1116         }
1117
1118         connman_element_get_value(&network->element,
1119                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
1120         if (gateway != NULL) {
1121                 __connman_ipconfig_set_gateway(ipconfig, gateway);
1122                 __connman_ipconfig_gateway_add(ipconfig);
1123         }
1124
1125         __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
1126                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1127
1128         return 0;
1129 }
1130
1131 int __connman_network_clear_ipconfig(struct connman_network *network,
1132                                         struct connman_ipconfig *ipconfig)
1133 {
1134         struct connman_service *service;
1135         enum connman_ipconfig_method method;
1136         enum connman_ipconfig_type type;
1137
1138         service = __connman_service_lookup_from_network(network);
1139         if (service == NULL)
1140                 return -EINVAL;
1141
1142         method = __connman_ipconfig_get_method(ipconfig);
1143         type = __connman_ipconfig_get_config_type(ipconfig);
1144
1145         switch (method) {
1146         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1147         case CONNMAN_IPCONFIG_METHOD_OFF:
1148         case CONNMAN_IPCONFIG_METHOD_FIXED:
1149         case CONNMAN_IPCONFIG_METHOD_AUTO:
1150                 return -EINVAL;
1151         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1152                 __connman_ipconfig_address_remove(ipconfig);
1153                 break;
1154         case CONNMAN_IPCONFIG_METHOD_DHCP:
1155                 __connman_dhcp_stop(network);
1156                 break;
1157         }
1158
1159         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1160                 __connman_service_indicate_state(service,
1161                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
1162                                         CONNMAN_IPCONFIG_TYPE_IPV6);
1163         else if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1164                 __connman_service_indicate_state(service,
1165                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
1166                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1167
1168         return 0;
1169 }
1170
1171 int __connman_network_set_ipconfig(struct connman_network *network,
1172                                         struct connman_ipconfig *ipconfig_ipv4,
1173                                         struct connman_ipconfig *ipconfig_ipv6)
1174 {
1175         enum connman_ipconfig_method method;
1176         int ret;
1177
1178         if (ipconfig_ipv6) {
1179                 method = __connman_ipconfig_get_method(ipconfig_ipv6);
1180
1181                 switch (method) {
1182                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1183                 case CONNMAN_IPCONFIG_METHOD_OFF:
1184                         break;
1185                 case CONNMAN_IPCONFIG_METHOD_AUTO:
1186                         autoconf_ipv6_set(network);
1187                         break;
1188                 case CONNMAN_IPCONFIG_METHOD_FIXED:
1189                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
1190                         ret = manual_ipv6_set(network, ipconfig_ipv6);
1191                         if (ret != 0) {
1192                                 connman_network_set_error(network,
1193                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
1194                                 return FALSE;
1195                         }
1196                         break;
1197                 case CONNMAN_IPCONFIG_METHOD_DHCP:
1198                         break;
1199                 }
1200         }
1201
1202         if (ipconfig_ipv4) {
1203                 method = __connman_ipconfig_get_method(ipconfig_ipv4);
1204
1205                 switch (method) {
1206                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1207                 case CONNMAN_IPCONFIG_METHOD_OFF:
1208                 case CONNMAN_IPCONFIG_METHOD_FIXED:
1209                 case CONNMAN_IPCONFIG_METHOD_AUTO:
1210                         return -EINVAL;
1211                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
1212                         return manual_ipv4_set(network, ipconfig_ipv4);
1213                 case CONNMAN_IPCONFIG_METHOD_DHCP:
1214                         return __connman_dhcp_start(network, dhcp_callback);
1215                 }
1216         }
1217
1218         return 0;
1219 }
1220
1221 int connman_network_set_ipaddress(struct connman_network *network,
1222                                         struct connman_ipaddress *ipaddress)
1223 {
1224         struct connman_service *service;
1225         struct connman_ipconfig *ipconfig = NULL;
1226
1227         DBG("network %p", network);
1228
1229         service = __connman_service_lookup_from_network(network);
1230         if (service == NULL)
1231                 return -EINVAL;
1232
1233         if (ipaddress->family == CONNMAN_IPCONFIG_TYPE_IPV4)
1234                 ipconfig = __connman_service_get_ip4config(service);
1235         else if (ipaddress->family == CONNMAN_IPCONFIG_TYPE_IPV6)
1236                 ipconfig = __connman_service_get_ip6config(service);
1237
1238         if (ipconfig == NULL)
1239                 return -EINVAL;
1240
1241         __connman_ipconfig_set_local(ipconfig, ipaddress->local);
1242         __connman_ipconfig_set_peer(ipconfig, ipaddress->peer);
1243         __connman_ipconfig_set_broadcast(ipconfig, ipaddress->broadcast);
1244         __connman_ipconfig_set_prefixlen(ipconfig, ipaddress->prefixlen);
1245         __connman_ipconfig_set_gateway(ipconfig, ipaddress->gateway);
1246
1247         return __connman_ipconfig_gateway_add(ipconfig);
1248 }
1249
1250 int connman_network_set_pac(struct connman_network *network,
1251                                 const char *pac)
1252 {
1253         struct connman_service *service;
1254
1255         DBG("network %p pac %s", network, pac);
1256
1257         service = __connman_service_lookup_from_network(network);
1258         if (service == NULL)
1259                 return -EINVAL;
1260
1261         __connman_service_set_pac(service, pac);
1262
1263         return 0;
1264 }
1265
1266 int connman_network_set_nameservers(struct connman_network *network,
1267                                 const char *nameservers)
1268 {
1269         struct connman_service *service;
1270         char **nameservers_array = NULL;
1271         int i;
1272
1273         DBG("network %p nameservers %s", network, nameservers);
1274
1275         service = __connman_service_lookup_from_network(network);
1276         if (service == NULL)
1277                 return -EINVAL;
1278
1279         __connman_service_nameserver_clear(service);
1280
1281         if (nameservers != NULL)
1282                 nameservers_array = g_strsplit(nameservers, " ", 0);
1283
1284         for (i = 0; nameservers_array[i] == NULL; i++) {
1285                 __connman_service_nameserver_append(service,
1286                                                 nameservers_array[i]);
1287         }
1288
1289         return 0;
1290 }
1291
1292 int connman_network_set_domain(struct connman_network *network,
1293                                 const char *domain)
1294 {
1295         struct connman_service *service;
1296
1297         DBG("network %p domain %s", network, domain);
1298
1299         service = __connman_service_lookup_from_network(network);
1300         if (service == NULL)
1301                 return -EINVAL;
1302
1303         __connman_service_set_domainname(service, domain);
1304
1305         return 0;
1306 }
1307
1308 /**
1309  * connman_network_set_name:
1310  * @network: network structure
1311  * @name: name value
1312  *
1313  * Set display name value for network
1314  */
1315 int connman_network_set_name(struct connman_network *network,
1316                                                         const char *name)
1317 {
1318         DBG("network %p name %s", network, name);
1319
1320         g_free(network->name);
1321         network->name = g_strdup(name);
1322
1323         return connman_element_set_string(&network->element, "Name", name);
1324 }
1325
1326 /**
1327  * connman_network_set_strength:
1328  * @network: network structure
1329  * @strength: strength value
1330  *
1331  * Set signal strength value for network
1332  */
1333 int connman_network_set_strength(struct connman_network *network,
1334                                                 connman_uint8_t strength)
1335 {
1336         DBG("network %p strengh %d", network, strength);
1337
1338         network->strength = strength;
1339
1340         return connman_element_set_uint8(&network->element,
1341                                                 "Strength", strength);
1342 }
1343
1344 /**
1345  * connman_network_set_roaming:
1346  * @network: network structure
1347  * @roaming: roaming state
1348  *
1349  * Set roaming state for network
1350  */
1351 int connman_network_set_roaming(struct connman_network *network,
1352                                                 connman_bool_t roaming)
1353 {
1354         DBG("network %p roaming %d", network, roaming);
1355
1356         network->roaming = roaming;
1357
1358         return connman_element_set_bool(&network->element,
1359                                                 "Roaming", roaming);
1360 }
1361
1362 /**
1363  * connman_network_set_string:
1364  * @network: network structure
1365  * @key: unique identifier
1366  * @value: string value
1367  *
1368  * Set string value for specific key
1369  */
1370 int connman_network_set_string(struct connman_network *network,
1371                                         const char *key, const char *value)
1372 {
1373         int err;
1374
1375         DBG("network %p key %s value %s", network, key, value);
1376
1377         if (g_strcmp0(key, "Name") == 0)
1378                 return connman_network_set_name(network, value);
1379
1380         if (g_str_equal(key, "Node") == TRUE) {
1381                 g_free(network->node);
1382                 network->node = g_strdup(value);
1383         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
1384                 g_free(network->wifi.mode);
1385                 network->wifi.mode = g_strdup(value);
1386         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
1387                 g_free(network->wifi.security);
1388                 network->wifi.security = g_strdup(value);
1389         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
1390                 g_free(network->wifi.passphrase);
1391                 network->wifi.passphrase = g_strdup(value);
1392         } else if (g_str_equal(key, "WiFi.EAP") == TRUE) {
1393                 g_free(network->wifi.eap);
1394                 network->wifi.eap = g_strdup(value);
1395         } else if (g_str_equal(key, "WiFi.Identity") == TRUE) {
1396                 g_free(network->wifi.identity);
1397                 network->wifi.identity = g_strdup(value);
1398         } else if (g_str_equal(key, "WiFi.CACertFile") == TRUE) {
1399                 g_free(network->wifi.ca_cert_path);
1400                 network->wifi.ca_cert_path = g_strdup(value);
1401         } else if (g_str_equal(key, "WiFi.ClientCertFile") == TRUE) {
1402                 g_free(network->wifi.client_cert_path);
1403                 network->wifi.client_cert_path = g_strdup(value);
1404         } else if (g_str_equal(key, "WiFi.PrivateKeyFile") == TRUE) {
1405                 g_free(network->wifi.private_key_path);
1406                 network->wifi.private_key_path = g_strdup(value);
1407         } else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase") == TRUE) {
1408                 g_free(network->wifi.private_key_passphrase);
1409                 network->wifi.private_key_passphrase = g_strdup(value);
1410         } else if (g_str_equal(key, "WiFi.Phase2") == TRUE) {
1411                 g_free(network->wifi.phase2_auth);
1412                 network->wifi.phase2_auth = g_strdup(value);
1413         } else if (g_str_equal(key, "WiFi.PinWPS") == TRUE) {
1414                 g_free(network->wifi.pin_wps);
1415                 network->wifi.pin_wps = g_strdup(value);
1416         }
1417
1418         err = connman_element_set_string(&network->element, key, value);
1419         if (err < 0)
1420                 return err;
1421
1422         if (network->driver == NULL)
1423                 return 0;
1424
1425         if (network->driver->setup)
1426                 return network->driver->setup(network, key);
1427
1428         return 0;
1429 }
1430
1431 /**
1432  * connman_network_get_string:
1433  * @network: network structure
1434  * @key: unique identifier
1435  *
1436  * Get string value for specific key
1437  */
1438 const char *connman_network_get_string(struct connman_network *network,
1439                                                         const char *key)
1440 {
1441         DBG("network %p key %s", network, key);
1442
1443         if (g_str_equal(key, "Name") == TRUE)
1444                 return network->name;
1445         else if (g_str_equal(key, "Node") == TRUE)
1446                 return network->node;
1447         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
1448                 return network->wifi.mode;
1449         else if (g_str_equal(key, "WiFi.Security") == TRUE)
1450                 return network->wifi.security;
1451         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
1452                 return network->wifi.passphrase;
1453         else if (g_str_equal(key, "WiFi.EAP") == TRUE)
1454                 return network->wifi.eap;
1455         else if (g_str_equal(key, "WiFi.Identity") == TRUE)
1456                 return network->wifi.identity;
1457         else if (g_str_equal(key, "WiFi.CACertFile") == TRUE)
1458                 return network->wifi.ca_cert_path;
1459         else if (g_str_equal(key, "WiFi.ClientCertFile") == TRUE)
1460                 return network->wifi.client_cert_path;
1461         else if (g_str_equal(key, "WiFi.PrivateKeyFile") == TRUE)
1462                 return network->wifi.private_key_path;
1463         else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase") == TRUE)
1464                 return network->wifi.private_key_passphrase;
1465         else if (g_str_equal(key, "WiFi.Phase2") == TRUE)
1466                 return network->wifi.phase2_auth;
1467         else if (g_str_equal(key, "WiFi.PinWPS") == TRUE)
1468                 return network->wifi.pin_wps;
1469
1470         return connman_element_get_string(&network->element, key);
1471 }
1472
1473 /**
1474  * connman_network_set_bool:
1475  * @network: network structure
1476  * @key: unique identifier
1477  * @value: boolean value
1478  *
1479  * Set boolean value for specific key
1480  */
1481 int connman_network_set_bool(struct connman_network *network,
1482                                         const char *key, connman_bool_t value)
1483 {
1484         DBG("network %p key %s value %d", network, key, value);
1485
1486         if (g_strcmp0(key, "Roaming") == 0)
1487                 return connman_network_set_roaming(network, value);
1488         else if (g_strcmp0(key, "WiFi.WPS") == 0)
1489                 network->wifi.wps = value;
1490         else if (g_strcmp0(key, "WiFi.UseWPS") == 0)
1491                 network->wifi.use_wps = value;
1492
1493         return connman_element_set_bool(&network->element, key, value);
1494 }
1495
1496 /**
1497  * connman_network_get_bool:
1498  * @network: network structure
1499  * @key: unique identifier
1500  *
1501  * Get boolean value for specific key
1502  */
1503 connman_bool_t connman_network_get_bool(struct connman_network *network,
1504                                                         const char *key)
1505 {
1506         DBG("network %p key %s", network, key);
1507
1508         if (g_str_equal(key, "Roaming") == TRUE)
1509                 return network->roaming;
1510         else if (g_str_equal(key, "WiFi.WPS") == TRUE)
1511                 return network->wifi.wps;
1512         else if (g_str_equal(key, "WiFi.UseWPS") == TRUE)
1513                 return network->wifi.use_wps;
1514
1515         return connman_element_get_bool(&network->element, key);
1516 }
1517
1518 /**
1519  * connman_network_set_uint8:
1520  * @network: network structure
1521  * @key: unique identifier
1522  * @value: integer value
1523  *
1524  * Set integer value for specific key
1525  */
1526 int connman_network_set_uint8(struct connman_network *network,
1527                                         const char *key, connman_uint8_t value)
1528 {
1529         DBG("network %p key %s value %d", network, key, value);
1530
1531         if (g_strcmp0(key, "Strength") == 0)
1532                 return connman_network_set_strength(network, value);
1533
1534         return connman_element_set_uint8(&network->element, key, value);
1535 }
1536
1537 /**
1538  * connman_network_get_uint8:
1539  * @network: network structure
1540  * @key: unique identifier
1541  *
1542  * Get integer value for specific key
1543  */
1544 connman_uint8_t connman_network_get_uint8(struct connman_network *network,
1545                                                         const char *key)
1546 {
1547         DBG("network %p key %s", network, key);
1548
1549         if (g_str_equal(key, "Strength") == TRUE)
1550                 return network->strength;
1551
1552         return connman_element_get_uint8(&network->element, key);
1553 }
1554
1555 /**
1556  * connman_network_set_uint16:
1557  * @network: network structure
1558  * @key: unique identifier
1559  * @value: integer value
1560  *
1561  * Set integer value for specific key
1562  */
1563 int connman_network_set_uint16(struct connman_network *network,
1564                                 const char *key, connman_uint16_t value)
1565 {
1566         DBG("network %p key %s value %d", network, key, value);
1567
1568         if (g_str_equal(key, "Frequency") == TRUE)
1569                 network->frequency = value;
1570         else if (g_str_equal(key, "WiFi.Channel") == TRUE)
1571                 network->wifi.channel = value;
1572
1573         return -EINVAL;
1574 }
1575
1576 /**
1577  * connman_network_get_uint16:
1578  * @network: network structure
1579  * @key: unique identifier
1580  *
1581  * Get integer value for specific key
1582  */
1583 connman_uint16_t connman_network_get_uint16(struct connman_network *network,
1584                                                         const char *key)
1585 {
1586         DBG("network %p key %s", network, key);
1587
1588         if (g_str_equal(key, "Frequency") == TRUE)
1589                 return network->frequency;
1590         else if (g_str_equal(key, "WiFi.Channel") == TRUE)
1591                 return network->wifi.channel;
1592
1593         return 0;
1594 }
1595
1596 /**
1597  * connman_network_set_blob:
1598  * @network: network structure
1599  * @key: unique identifier
1600  * @data: blob data
1601  * @size: blob size
1602  *
1603  * Set binary blob value for specific key
1604  */
1605 int connman_network_set_blob(struct connman_network *network,
1606                         const char *key, const void *data, unsigned int size)
1607 {
1608         DBG("network %p key %s size %d", network, key, size);
1609
1610         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
1611                 g_free(network->wifi.ssid);
1612                 network->wifi.ssid = g_try_malloc(size);
1613                 if (network->wifi.ssid != NULL) {
1614                         memcpy(network->wifi.ssid, data, size);
1615                         network->wifi.ssid_len = size;
1616                 } else
1617                         network->wifi.ssid_len = 0;
1618         }
1619
1620         return connman_element_set_blob(&network->element, key, data, size);
1621 }
1622
1623 /**
1624  * connman_network_get_blob:
1625  * @network: network structure
1626  * @key: unique identifier
1627  * @size: pointer to blob size
1628  *
1629  * Get binary blob value for specific key
1630  */
1631 const void *connman_network_get_blob(struct connman_network *network,
1632                                         const char *key, unsigned int *size)
1633 {
1634         DBG("network %p key %s", network, key);
1635
1636         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
1637                 if (size != NULL)
1638                         *size = network->wifi.ssid_len;
1639                 return network->wifi.ssid;
1640         }
1641
1642         return connman_element_get_blob(&network->element, key, size);
1643 }
1644
1645 void __connman_network_set_device(struct connman_network *network,
1646                                         struct connman_device *device)
1647 {
1648         network->device = device;
1649 }
1650
1651 /**
1652  * connman_network_get_device:
1653  * @network: network structure
1654  *
1655  * Get parent device of network
1656  */
1657 struct connman_device *connman_network_get_device(struct connman_network *network)
1658 {
1659         return network->device;
1660 }
1661
1662 /**
1663  * connman_network_get_data:
1664  * @network: network structure
1665  *
1666  * Get private network data pointer
1667  */
1668 void *connman_network_get_data(struct connman_network *network)
1669 {
1670         return network->driver_data;
1671 }
1672
1673 /**
1674  * connman_network_set_data:
1675  * @network: network structure
1676  * @data: data pointer
1677  *
1678  * Set private network data pointer
1679  */
1680 void connman_network_set_data(struct connman_network *network, void *data)
1681 {
1682         network->driver_data = data;
1683 }
1684
1685 void connman_network_update(struct connman_network *network)
1686 {
1687         switch (network->type) {
1688         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1689         case CONNMAN_NETWORK_TYPE_VENDOR:
1690                 return;
1691         case CONNMAN_NETWORK_TYPE_ETHERNET:
1692         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1693         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1694         case CONNMAN_NETWORK_TYPE_CELLULAR:
1695         case CONNMAN_NETWORK_TYPE_WIFI:
1696         case CONNMAN_NETWORK_TYPE_WIMAX:
1697                 break;
1698         }
1699
1700         if (network->group != NULL)
1701                 __connman_service_update_from_network(network);
1702
1703         return;
1704 }
1705
1706 static gboolean match_driver(struct connman_network *network,
1707                                         struct connman_network_driver *driver)
1708 {
1709         if (network->type == driver->type ||
1710                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
1711                 return TRUE;
1712
1713         return FALSE;
1714 }
1715
1716 static int network_probe(struct connman_element *element)
1717 {
1718         struct connman_network *network = element->network;
1719         GSList *list;
1720
1721         DBG("element %p name %s", element, element->name);
1722
1723         if (network == NULL)
1724                 return -ENODEV;
1725
1726         for (list = driver_list; list; list = list->next) {
1727                 struct connman_network_driver *driver = list->data;
1728
1729                 if (match_driver(network, driver) == FALSE)
1730                         continue;
1731
1732                 DBG("driver %p name %s", driver, driver->name);
1733
1734                 if (driver->probe(network) == 0) {
1735                         network->driver = driver;
1736                         break;
1737                 }
1738         }
1739
1740         if (network->driver == NULL)
1741                 return -ENODEV;
1742
1743         switch (network->type) {
1744         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1745         case CONNMAN_NETWORK_TYPE_VENDOR:
1746                 break;
1747         case CONNMAN_NETWORK_TYPE_ETHERNET:
1748         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1749         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1750         case CONNMAN_NETWORK_TYPE_CELLULAR:
1751         case CONNMAN_NETWORK_TYPE_WIFI:
1752         case CONNMAN_NETWORK_TYPE_WIMAX:
1753                 if (network->group != NULL)
1754                         __connman_profile_add_network(network);
1755                 break;
1756         }
1757
1758         return 0;
1759 }
1760
1761 static void network_remove(struct connman_element *element)
1762 {
1763         struct connman_network *network = element->network;
1764
1765         DBG("element %p name %s", element, element->name);
1766
1767         if (network == NULL)
1768                 return;
1769
1770         if (network->driver == NULL)
1771                 return;
1772
1773         switch (network->type) {
1774         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1775         case CONNMAN_NETWORK_TYPE_VENDOR:
1776                 break;
1777         case CONNMAN_NETWORK_TYPE_ETHERNET:
1778         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1779         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1780         case CONNMAN_NETWORK_TYPE_CELLULAR:
1781         case CONNMAN_NETWORK_TYPE_WIFI:
1782         case CONNMAN_NETWORK_TYPE_WIMAX:
1783                 if (network->group != NULL) {
1784                         __connman_profile_remove_network(network);
1785
1786                         g_free(network->group);
1787                         network->group = NULL;
1788                 }
1789                 break;
1790         }
1791
1792         if (network->driver->remove)
1793                 network->driver->remove(network);
1794 }
1795
1796 static void network_change(struct connman_element *element)
1797 {
1798         struct connman_network *network = element->network;
1799
1800         DBG("element %p name %s", element, element->name);
1801
1802         if (element->state != CONNMAN_ELEMENT_STATE_ERROR)
1803                 return;
1804
1805         if (element->error != CONNMAN_ELEMENT_ERROR_DHCP_FAILED)
1806                 return;
1807
1808         if (network->connected == FALSE)
1809                 return;
1810
1811         connman_element_unregister_children(element);
1812
1813         connman_device_set_disconnected(network->device, TRUE);
1814
1815         if (network->driver && network->driver->disconnect) {
1816                 network->driver->disconnect(network);
1817                 return;
1818         }
1819
1820         network->connected = FALSE;
1821 }
1822
1823 static struct connman_driver network_driver = {
1824         .name           = "network",
1825         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
1826         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1827         .probe          = network_probe,
1828         .remove         = network_remove,
1829         .change         = network_change,
1830 };
1831
1832 int __connman_network_init(void)
1833 {
1834         DBG("");
1835
1836         return connman_driver_register(&network_driver);
1837 }
1838
1839 void __connman_network_cleanup(void)
1840 {
1841         DBG("");
1842
1843         connman_driver_unregister(&network_driver);
1844 }