network: Add IP setters
[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 int set_connected_fixed(struct connman_network *network)
643 {
644         struct connman_service *service;
645         struct connman_element *parent, *element;
646
647         DBG("");
648
649         service = __connman_service_lookup_from_network(network);
650
651         parent = connman_network_get_element(network);
652
653         set_configuration(network);
654
655         if (parent->ipv4.address == NULL)
656                 return -EINVAL;
657
658         if (parent->ipv4.netmask == NULL)
659                 return -EINVAL;
660
661         element = connman_element_create(NULL);
662         if (element == NULL) {
663                 connman_error("Can not create connman_element");
664                 return -ENOMEM;
665         }
666
667         element->type = CONNMAN_ELEMENT_TYPE_IPV4;
668         element->index = parent->index;
669
670         if (connman_element_register(element, parent) < 0) {
671                 connman_error("Can not register connman_element");
672                 return -EINVAL;
673         }
674
675         network->connecting = FALSE;
676
677         connman_network_set_associating(network, FALSE);
678
679         return 0;
680 }
681
682 static void set_connected_manual(struct connman_network *network)
683 {
684         struct connman_service *service;
685         struct connman_ipconfig *ipconfig;
686         const char *nameserver = NULL;
687         const char *gateway;
688         int err;
689
690         DBG("network %p", network);
691
692         service = __connman_service_lookup_from_network(network);
693
694         ipconfig = __connman_service_get_ip4config(service);
695
696         set_configuration(network);
697
698         err = __connman_ipconfig_set_address(ipconfig);
699         if (err < 0) {
700                 connman_network_set_error(network,
701                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
702                 return;
703         }
704
705         connman_element_get_value(&network->element,
706                         CONNMAN_PROPERTY_ID_IPV4_NAMESERVER, &nameserver);
707         if (nameserver != NULL)
708                 __connman_service_nameserver_append(service, nameserver);
709
710         connman_element_get_value(&network->element,
711                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
712         if (gateway != NULL)
713                 __connman_ipconfig_set_gateway(ipconfig, gateway);
714
715         network->connecting = FALSE;
716
717         connman_network_set_associating(network, FALSE);
718
719         __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
720                                         CONNMAN_IPCONFIG_TYPE_IPV4);
721 }
722
723 static int set_connected_dhcp(struct connman_network *network)
724 {
725         struct connman_element *element;
726         int error;
727
728         DBG("network %p", network);
729
730         element = connman_element_create(NULL);
731         if (element == NULL)
732                 return -ENOMEM;
733
734         element->type  = CONNMAN_ELEMENT_TYPE_DHCP;
735         element->index = network->element.index;
736
737         error = connman_element_register(element, &network->element);
738         if (error < 0) {
739                 connman_element_unref(element);
740                 return error;
741         }
742
743         set_configuration(network);
744
745         return 0;
746 }
747
748 static int manual_ipv6_set(struct connman_network *network,
749                                 struct connman_ipconfig *ipconfig_ipv6)
750 {
751         struct connman_service *service;
752         int err;
753
754         service = __connman_service_lookup_from_network(network);
755         if (service == NULL)
756                 return -EINVAL;
757
758         err = __connman_ipconfig_set_address(ipconfig_ipv6);
759         if (err < 0) {
760                 connman_network_set_error(network,
761                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
762                 return err;
763         }
764
765         /*
766          * READY state will be indicated by IPV4 setting
767          * gateway will be set by IPV4 setting
768          */
769
770         return 0;
771 }
772
773 static void autoconf_ipv6_set(struct connman_network *network)
774 {
775         struct connman_service *service;
776         struct connman_ipconfig *ipconfig;
777         const char *nameserver = NULL;
778
779         DBG("network %p", network);
780
781         service = __connman_service_lookup_from_network(network);
782
783         ipconfig = __connman_service_get_ip6config(service);
784
785         __connman_device_increase_connections(network->device);
786
787         __connman_device_set_network(network->device, network);
788
789         connman_device_set_disconnected(network->device, FALSE);
790
791         connman_element_get_value(&network->element,
792                         CONNMAN_PROPERTY_ID_IPV6_NAMESERVER, &nameserver);
793         if (nameserver != NULL)
794                 __connman_service_nameserver_append(service, nameserver);
795
796         network->connecting = FALSE;
797
798         __connman_service_indicate_state(service,
799                                         CONNMAN_SERVICE_STATE_READY,
800                                         CONNMAN_IPCONFIG_TYPE_IPV6);
801 }
802
803 static gboolean set_connected(gpointer user_data)
804 {
805         struct connman_network *network = user_data;
806         struct connman_service *service;
807         struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
808         enum connman_ipconfig_method ipv4_method, ipv6_method;
809
810         service = __connman_service_lookup_from_network(network);
811
812         ipconfig_ipv4 = __connman_service_get_ip4config(service);
813         ipconfig_ipv6 = __connman_service_get_ip6config(service);
814
815         DBG("service %p ipv4 %p ipv6 %p", service, ipconfig_ipv4,
816                 ipconfig_ipv6);
817
818         ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4);
819         ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6);
820
821         DBG("method ipv4 %d ipv6 %d", ipv4_method, ipv6_method);
822         DBG("network connected %d", network->connected);
823
824         if (network->connected == TRUE) {
825                 int ret;
826
827                 switch (ipv6_method) {
828                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
829                 case CONNMAN_IPCONFIG_METHOD_OFF:
830                         break;
831                 case CONNMAN_IPCONFIG_METHOD_AUTO:
832                         autoconf_ipv6_set(network);
833                         break;
834                 case CONNMAN_IPCONFIG_METHOD_FIXED:
835                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
836                         ret = manual_ipv6_set(network, ipconfig_ipv6);
837                         if (ret != 0) {
838                                 connman_network_set_error(network,
839                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
840                                 return FALSE;
841                         }
842                         break;
843                 case CONNMAN_IPCONFIG_METHOD_DHCP:
844                         break;
845                 }
846
847                 switch (ipv4_method) {
848                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
849                 case CONNMAN_IPCONFIG_METHOD_OFF:
850                 case CONNMAN_IPCONFIG_METHOD_AUTO:
851                         return FALSE;
852                 case CONNMAN_IPCONFIG_METHOD_FIXED:
853                         if (set_connected_fixed(network) < 0) {
854                                 connman_network_set_error(network,
855                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
856                                 return FALSE;
857                         }
858                         return TRUE;
859                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
860                         set_connected_manual(network);
861                         return TRUE;
862                 case CONNMAN_IPCONFIG_METHOD_DHCP:
863                         if (set_connected_dhcp(network) < 0) {
864                                 connman_network_set_error(network,
865                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
866                                 return FALSE;
867                         }
868                 }
869
870         } else {
871                 struct connman_service *service;
872
873                 connman_element_unregister_children(&network->element);
874
875                 __connman_device_set_network(network->device, NULL);
876                 network->hidden = FALSE;
877
878                 service = __connman_service_lookup_from_network(network);
879
880                 __connman_service_indicate_state(service,
881                                         CONNMAN_SERVICE_STATE_IDLE,
882                                         CONNMAN_IPCONFIG_TYPE_IPV4);
883
884                 /* TODO: eventually the IPv6 disconnect state should be handled
885                  * in connection.c
886                  */
887                 __connman_service_indicate_state(service,
888                                         CONNMAN_SERVICE_STATE_DISCONNECT,
889                                         CONNMAN_IPCONFIG_TYPE_IPV6);
890
891                 __connman_service_indicate_state(service,
892                                         CONNMAN_SERVICE_STATE_IDLE,
893                                         CONNMAN_IPCONFIG_TYPE_IPV6);
894         }
895
896         network->connecting = FALSE;
897
898         connman_network_set_associating(network, FALSE);
899
900         return FALSE;
901 }
902
903 /**
904  * connman_network_set_connected:
905  * @network: network structure
906  * @connected: connected state
907  *
908  * Change connected state of network
909  */
910 int connman_network_set_connected(struct connman_network *network,
911                                                 connman_bool_t connected)
912 {
913         DBG("network %p connected %d", network, connected);
914
915         if ((network->connecting == TRUE || network->associating == TRUE) &&
916                                                         connected == FALSE) {
917                 connman_element_set_error(&network->element,
918                                         CONNMAN_ELEMENT_ERROR_CONNECT_FAILED);
919                 __connman_network_disconnect(network);
920         }
921
922         if (network->connected == connected)
923                 return -EALREADY;
924
925         if (connected == FALSE)
926                 __connman_device_decrease_connections(network->device);
927
928         network->connected = connected;
929
930         set_connected(network);
931
932         return 0;
933 }
934
935 /**
936  * connman_network_get_connected:
937  * @network: network structure
938  *
939  * Get network connection status
940  */
941 connman_bool_t connman_network_get_connected(struct connman_network *network)
942 {
943         return network->connected;
944 }
945
946 /**
947  * connman_network_get_associating:
948  * @network: network structure
949  *
950  * Get network associating status
951  */
952 connman_bool_t connman_network_get_associating(struct connman_network *network)
953 {
954         return network->associating;
955 }
956
957 /**
958  * __connman_network_connect:
959  * @network: network structure
960  *
961  * Connect network
962  */
963 int __connman_network_connect(struct connman_network *network)
964 {
965         struct connman_service *service;
966         int err;
967
968         DBG("network %p", network);
969
970         if (network->connected == TRUE)
971                 return -EISCONN;
972
973         if (network->connecting == TRUE || network->associating == TRUE)
974                 return -EALREADY;
975
976         if (network->driver == NULL)
977                 return -EUNATCH;
978
979         if (network->driver->connect == NULL)
980                 return -ENOSYS;
981
982         if (network->device == NULL)
983                 return -ENODEV;
984
985         network->connecting = TRUE;
986
987         __connman_device_disconnect(network->device);
988
989         service = __connman_service_lookup_from_network(network);
990
991         err = network->driver->connect(network);
992         if (err < 0) {
993                 if (err == -EINPROGRESS)
994                         connman_network_set_associating(network, TRUE);
995                 else {
996                         network->connecting = FALSE;
997                         network->hidden = FALSE;
998                 }
999
1000                 return err;
1001         }
1002
1003         network->connected = TRUE;
1004         set_connected(network);
1005
1006         return err;
1007 }
1008
1009 /**
1010  * __connman_network_disconnect:
1011  * @network: network structure
1012  *
1013  * Disconnect network
1014  */
1015 int __connman_network_disconnect(struct connman_network *network)
1016 {
1017         int err;
1018
1019         DBG("network %p", network);
1020
1021         if (network->connected == FALSE && network->connecting == FALSE &&
1022                                                 network->associating == FALSE)
1023                 return -ENOTCONN;
1024
1025         if (network->driver == NULL)
1026                 return -EUNATCH;
1027
1028         if (network->driver->disconnect == NULL)
1029                 return -ENOSYS;
1030
1031         network->connecting = FALSE;
1032
1033         err = network->driver->disconnect(network);
1034         if (err == 0) {
1035                 connman_network_set_connected(network, FALSE);
1036                 set_connected(network);
1037         }
1038
1039         return err;
1040 }
1041
1042 static int dhcp_start(struct connman_network *network)
1043 {
1044         struct connman_element *element;
1045         int error;
1046
1047         element = connman_element_create(NULL);
1048         if (element == NULL)
1049                 return -ENOMEM;
1050
1051         element->type  = CONNMAN_ELEMENT_TYPE_DHCP;
1052         element->index = network->element.index;
1053
1054         error = connman_element_register(element, &network->element);
1055         if (error < 0) {
1056                 connman_element_unref(element);
1057                 return error;
1058         }
1059
1060         return 0;
1061 }
1062
1063 static int dhcp_stop(struct connman_network *network)
1064 {
1065         connman_element_unregister_children_type(&network->element,
1066                                                 CONNMAN_ELEMENT_TYPE_IPV4);
1067         connman_element_unregister_children_type(&network->element,
1068                                                 CONNMAN_ELEMENT_TYPE_DHCP);
1069
1070         return 0;
1071 }
1072
1073 static int manual_ipv4_set(struct connman_network *network,
1074                                 struct connman_ipconfig *ipconfig)
1075 {
1076         struct connman_service *service;
1077         const char *gateway;
1078         int err;
1079
1080         service = __connman_service_lookup_from_network(network);
1081         if (service == NULL)
1082                 return -EINVAL;
1083
1084         err = __connman_ipconfig_set_address(ipconfig);
1085         if (err < 0) {
1086                 connman_network_set_error(network,
1087                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
1088                 return err;
1089         }
1090
1091         connman_element_get_value(&network->element,
1092                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
1093         if (gateway != NULL)
1094                 __connman_ipconfig_set_gateway(ipconfig, gateway);
1095
1096         __connman_service_indicate_state(service, CONNMAN_SERVICE_STATE_READY,
1097                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1098
1099         return 0;
1100 }
1101
1102 int __connman_network_clear_ipconfig(struct connman_network *network,
1103                                         struct connman_ipconfig *ipconfig)
1104 {
1105         struct connman_service *service;
1106         enum connman_ipconfig_method method;
1107         enum connman_ipconfig_type type;
1108
1109         service = __connman_service_lookup_from_network(network);
1110         if (service == NULL)
1111                 return -EINVAL;
1112
1113         method = __connman_ipconfig_get_method(ipconfig);
1114         type = __connman_ipconfig_get_config_type(ipconfig);
1115
1116         switch (method) {
1117         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1118         case CONNMAN_IPCONFIG_METHOD_OFF:
1119         case CONNMAN_IPCONFIG_METHOD_FIXED:
1120         case CONNMAN_IPCONFIG_METHOD_AUTO:
1121                 return -EINVAL;
1122         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1123                 __connman_ipconfig_clear_address(ipconfig);
1124                 break;
1125         case CONNMAN_IPCONFIG_METHOD_DHCP:
1126                 dhcp_stop(network);
1127                 break;
1128         }
1129
1130         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1131                 __connman_service_indicate_state(service,
1132                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
1133                                         CONNMAN_IPCONFIG_TYPE_IPV6);
1134         else if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1135                 __connman_service_indicate_state(service,
1136                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
1137                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1138
1139         return 0;
1140 }
1141
1142 int __connman_network_set_ipconfig(struct connman_network *network,
1143                                         struct connman_ipconfig *ipconfig_ipv4,
1144                                         struct connman_ipconfig *ipconfig_ipv6)
1145 {
1146         enum connman_ipconfig_method method;
1147         int ret;
1148
1149         if (ipconfig_ipv6) {
1150                 method = __connman_ipconfig_get_method(ipconfig_ipv6);
1151
1152                 switch (method) {
1153                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1154                 case CONNMAN_IPCONFIG_METHOD_OFF:
1155                         break;
1156                 case CONNMAN_IPCONFIG_METHOD_AUTO:
1157                         autoconf_ipv6_set(network);
1158                         break;
1159                 case CONNMAN_IPCONFIG_METHOD_FIXED:
1160                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
1161                         ret = manual_ipv6_set(network, ipconfig_ipv6);
1162                         if (ret != 0) {
1163                                 connman_network_set_error(network,
1164                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
1165                                 return FALSE;
1166                         }
1167                         break;
1168                 case CONNMAN_IPCONFIG_METHOD_DHCP:
1169                         break;
1170                 }
1171         }
1172
1173         if (ipconfig_ipv4) {
1174                 method = __connman_ipconfig_get_method(ipconfig_ipv4);
1175
1176                 switch (method) {
1177                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1178                 case CONNMAN_IPCONFIG_METHOD_OFF:
1179                 case CONNMAN_IPCONFIG_METHOD_FIXED:
1180                 case CONNMAN_IPCONFIG_METHOD_AUTO:
1181                         return -EINVAL;
1182                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
1183                         return manual_ipv4_set(network, ipconfig_ipv4);
1184                 case CONNMAN_IPCONFIG_METHOD_DHCP:
1185                         return dhcp_start(network);
1186                 }
1187         }
1188
1189         return 0;
1190 }
1191
1192 int connman_network_set_ipaddress(struct connman_network *network,
1193                                         struct connman_ipaddress *ipaddress)
1194 {
1195         struct connman_service *service;
1196         struct connman_ipconfig *ipconfig = NULL;
1197
1198         DBG("network %p", network);
1199
1200         service = __connman_service_lookup_from_network(network);
1201         if (service == NULL)
1202                 return -EINVAL;
1203
1204         if (ipaddress->family == CONNMAN_IPCONFIG_TYPE_IPV4)
1205                 ipconfig = __connman_service_get_ip4config(service);
1206         else if (ipaddress->family == CONNMAN_IPCONFIG_TYPE_IPV6)
1207                 ipconfig = __connman_service_get_ip6config(service);
1208
1209         if (ipconfig == NULL)
1210                 return -EINVAL;
1211
1212         __connman_ipconfig_set_local(ipconfig, ipaddress->local);
1213         __connman_ipconfig_set_peer(ipconfig, ipaddress->peer);
1214         __connman_ipconfig_set_broadcast(ipconfig, ipaddress->broadcast);
1215         __connman_ipconfig_set_gateway(ipconfig, ipaddress->gateway);
1216         __connman_ipconfig_set_prefixlen(ipconfig, ipaddress->prefixlen);
1217
1218         return 0;
1219 }
1220
1221 int connman_network_set_pac(struct connman_network *network,
1222                                 const char *pac)
1223 {
1224         struct connman_service *service;
1225
1226         DBG("network %p pac %s", network, pac);
1227
1228         service = __connman_service_lookup_from_network(network);
1229         if (service == NULL)
1230                 return -EINVAL;
1231
1232         __connman_service_set_pac(service, pac);
1233
1234         return 0;
1235 }
1236
1237 int connman_network_set_nameservers(struct connman_network *network,
1238                                 const char *nameservers)
1239 {
1240         struct connman_service *service;
1241         char **nameservers_array = NULL;
1242         int i;
1243
1244         DBG("network %p nameservers %s", network, nameservers);
1245
1246         service = __connman_service_lookup_from_network(network);
1247         if (service == NULL)
1248                 return -EINVAL;
1249
1250         __connman_service_nameserver_clear(service);
1251
1252         if (nameservers != NULL)
1253                 nameservers_array = g_strsplit(nameservers, " ", 0);
1254
1255         for (i = 0; nameservers_array[i] == NULL; i++) {
1256                 __connman_service_nameserver_append(service,
1257                                                 nameservers_array[i]);
1258         }
1259
1260         return 0;
1261 }
1262
1263 int connman_network_set_domain(struct connman_network *network,
1264                                 const char *domain)
1265 {
1266         struct connman_service *service;
1267
1268         DBG("network %p domain %s", network, domain);
1269
1270         service = __connman_service_lookup_from_network(network);
1271         if (service == NULL)
1272                 return -EINVAL;
1273
1274         __connman_service_set_domainname(service, domain);
1275
1276         return 0;
1277 }
1278
1279 /**
1280  * connman_network_set_name:
1281  * @network: network structure
1282  * @name: name value
1283  *
1284  * Set display name value for network
1285  */
1286 int connman_network_set_name(struct connman_network *network,
1287                                                         const char *name)
1288 {
1289         DBG("network %p name %s", network, name);
1290
1291         g_free(network->name);
1292         network->name = g_strdup(name);
1293
1294         return connman_element_set_string(&network->element, "Name", name);
1295 }
1296
1297 /**
1298  * connman_network_set_strength:
1299  * @network: network structure
1300  * @strength: strength value
1301  *
1302  * Set signal strength value for network
1303  */
1304 int connman_network_set_strength(struct connman_network *network,
1305                                                 connman_uint8_t strength)
1306 {
1307         DBG("network %p strengh %d", network, strength);
1308
1309         network->strength = strength;
1310
1311         return connman_element_set_uint8(&network->element,
1312                                                 "Strength", strength);
1313 }
1314
1315 /**
1316  * connman_network_set_roaming:
1317  * @network: network structure
1318  * @roaming: roaming state
1319  *
1320  * Set roaming state for network
1321  */
1322 int connman_network_set_roaming(struct connman_network *network,
1323                                                 connman_bool_t roaming)
1324 {
1325         DBG("network %p roaming %d", network, roaming);
1326
1327         network->roaming = roaming;
1328
1329         return connman_element_set_bool(&network->element,
1330                                                 "Roaming", roaming);
1331 }
1332
1333 /**
1334  * connman_network_set_string:
1335  * @network: network structure
1336  * @key: unique identifier
1337  * @value: string value
1338  *
1339  * Set string value for specific key
1340  */
1341 int connman_network_set_string(struct connman_network *network,
1342                                         const char *key, const char *value)
1343 {
1344         int err;
1345
1346         DBG("network %p key %s value %s", network, key, value);
1347
1348         if (g_strcmp0(key, "Name") == 0)
1349                 return connman_network_set_name(network, value);
1350
1351         if (g_str_equal(key, "Node") == TRUE) {
1352                 g_free(network->node);
1353                 network->node = g_strdup(value);
1354         } else if (g_str_equal(key, "WiFi.Mode") == TRUE) {
1355                 g_free(network->wifi.mode);
1356                 network->wifi.mode = g_strdup(value);
1357         } else if (g_str_equal(key, "WiFi.Security") == TRUE) {
1358                 g_free(network->wifi.security);
1359                 network->wifi.security = g_strdup(value);
1360         } else if (g_str_equal(key, "WiFi.Passphrase") == TRUE) {
1361                 g_free(network->wifi.passphrase);
1362                 network->wifi.passphrase = g_strdup(value);
1363         } else if (g_str_equal(key, "WiFi.EAP") == TRUE) {
1364                 g_free(network->wifi.eap);
1365                 network->wifi.eap = g_strdup(value);
1366         } else if (g_str_equal(key, "WiFi.Identity") == TRUE) {
1367                 g_free(network->wifi.identity);
1368                 network->wifi.identity = g_strdup(value);
1369         } else if (g_str_equal(key, "WiFi.CACertFile") == TRUE) {
1370                 g_free(network->wifi.ca_cert_path);
1371                 network->wifi.ca_cert_path = g_strdup(value);
1372         } else if (g_str_equal(key, "WiFi.ClientCertFile") == TRUE) {
1373                 g_free(network->wifi.client_cert_path);
1374                 network->wifi.client_cert_path = g_strdup(value);
1375         } else if (g_str_equal(key, "WiFi.PrivateKeyFile") == TRUE) {
1376                 g_free(network->wifi.private_key_path);
1377                 network->wifi.private_key_path = g_strdup(value);
1378         } else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase") == TRUE) {
1379                 g_free(network->wifi.private_key_passphrase);
1380                 network->wifi.private_key_passphrase = g_strdup(value);
1381         } else if (g_str_equal(key, "WiFi.Phase2") == TRUE) {
1382                 g_free(network->wifi.phase2_auth);
1383                 network->wifi.phase2_auth = g_strdup(value);
1384         } else if (g_str_equal(key, "WiFi.PinWPS") == TRUE) {
1385                 g_free(network->wifi.pin_wps);
1386                 network->wifi.pin_wps = g_strdup(value);
1387         }
1388
1389         err = connman_element_set_string(&network->element, key, value);
1390         if (err < 0)
1391                 return err;
1392
1393         if (network->driver == NULL)
1394                 return 0;
1395
1396         if (network->driver->setup)
1397                 return network->driver->setup(network, key);
1398
1399         return 0;
1400 }
1401
1402 /**
1403  * connman_network_get_string:
1404  * @network: network structure
1405  * @key: unique identifier
1406  *
1407  * Get string value for specific key
1408  */
1409 const char *connman_network_get_string(struct connman_network *network,
1410                                                         const char *key)
1411 {
1412         DBG("network %p key %s", network, key);
1413
1414         if (g_str_equal(key, "Name") == TRUE)
1415                 return network->name;
1416         else if (g_str_equal(key, "Node") == TRUE)
1417                 return network->node;
1418         else if (g_str_equal(key, "WiFi.Mode") == TRUE)
1419                 return network->wifi.mode;
1420         else if (g_str_equal(key, "WiFi.Security") == TRUE)
1421                 return network->wifi.security;
1422         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE)
1423                 return network->wifi.passphrase;
1424         else if (g_str_equal(key, "WiFi.EAP") == TRUE)
1425                 return network->wifi.eap;
1426         else if (g_str_equal(key, "WiFi.Identity") == TRUE)
1427                 return network->wifi.identity;
1428         else if (g_str_equal(key, "WiFi.CACertFile") == TRUE)
1429                 return network->wifi.ca_cert_path;
1430         else if (g_str_equal(key, "WiFi.ClientCertFile") == TRUE)
1431                 return network->wifi.client_cert_path;
1432         else if (g_str_equal(key, "WiFi.PrivateKeyFile") == TRUE)
1433                 return network->wifi.private_key_path;
1434         else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase") == TRUE)
1435                 return network->wifi.private_key_passphrase;
1436         else if (g_str_equal(key, "WiFi.Phase2") == TRUE)
1437                 return network->wifi.phase2_auth;
1438         else if (g_str_equal(key, "WiFi.PinWPS") == TRUE)
1439                 return network->wifi.pin_wps;
1440
1441         return connman_element_get_string(&network->element, key);
1442 }
1443
1444 /**
1445  * connman_network_set_bool:
1446  * @network: network structure
1447  * @key: unique identifier
1448  * @value: boolean value
1449  *
1450  * Set boolean value for specific key
1451  */
1452 int connman_network_set_bool(struct connman_network *network,
1453                                         const char *key, connman_bool_t value)
1454 {
1455         DBG("network %p key %s value %d", network, key, value);
1456
1457         if (g_strcmp0(key, "Roaming") == 0)
1458                 return connman_network_set_roaming(network, value);
1459         else if (g_strcmp0(key, "WiFi.WPS") == 0)
1460                 network->wifi.wps = value;
1461         else if (g_strcmp0(key, "WiFi.UseWPS") == 0)
1462                 network->wifi.use_wps = value;
1463
1464         return connman_element_set_bool(&network->element, key, value);
1465 }
1466
1467 /**
1468  * connman_network_get_bool:
1469  * @network: network structure
1470  * @key: unique identifier
1471  *
1472  * Get boolean value for specific key
1473  */
1474 connman_bool_t connman_network_get_bool(struct connman_network *network,
1475                                                         const char *key)
1476 {
1477         DBG("network %p key %s", network, key);
1478
1479         if (g_str_equal(key, "Roaming") == TRUE)
1480                 return network->roaming;
1481         else if (g_str_equal(key, "WiFi.WPS") == TRUE)
1482                 return network->wifi.wps;
1483         else if (g_str_equal(key, "WiFi.UseWPS") == TRUE)
1484                 return network->wifi.use_wps;
1485
1486         return connman_element_get_bool(&network->element, key);
1487 }
1488
1489 /**
1490  * connman_network_set_uint8:
1491  * @network: network structure
1492  * @key: unique identifier
1493  * @value: integer value
1494  *
1495  * Set integer value for specific key
1496  */
1497 int connman_network_set_uint8(struct connman_network *network,
1498                                         const char *key, connman_uint8_t value)
1499 {
1500         DBG("network %p key %s value %d", network, key, value);
1501
1502         if (g_strcmp0(key, "Strength") == 0)
1503                 return connman_network_set_strength(network, value);
1504
1505         return connman_element_set_uint8(&network->element, key, value);
1506 }
1507
1508 /**
1509  * connman_network_get_uint8:
1510  * @network: network structure
1511  * @key: unique identifier
1512  *
1513  * Get integer value for specific key
1514  */
1515 connman_uint8_t connman_network_get_uint8(struct connman_network *network,
1516                                                         const char *key)
1517 {
1518         DBG("network %p key %s", network, key);
1519
1520         if (g_str_equal(key, "Strength") == TRUE)
1521                 return network->strength;
1522
1523         return connman_element_get_uint8(&network->element, key);
1524 }
1525
1526 /**
1527  * connman_network_set_uint16:
1528  * @network: network structure
1529  * @key: unique identifier
1530  * @value: integer value
1531  *
1532  * Set integer value for specific key
1533  */
1534 int connman_network_set_uint16(struct connman_network *network,
1535                                 const char *key, connman_uint16_t value)
1536 {
1537         DBG("network %p key %s value %d", network, key, value);
1538
1539         if (g_str_equal(key, "Frequency") == TRUE)
1540                 network->frequency = value;
1541         else if (g_str_equal(key, "WiFi.Channel") == TRUE)
1542                 network->wifi.channel = value;
1543
1544         return -EINVAL;
1545 }
1546
1547 /**
1548  * connman_network_get_uint16:
1549  * @network: network structure
1550  * @key: unique identifier
1551  *
1552  * Get integer value for specific key
1553  */
1554 connman_uint16_t connman_network_get_uint16(struct connman_network *network,
1555                                                         const char *key)
1556 {
1557         DBG("network %p key %s", network, key);
1558
1559         if (g_str_equal(key, "Frequency") == TRUE)
1560                 return network->frequency;
1561         else if (g_str_equal(key, "WiFi.Channel") == TRUE)
1562                 return network->wifi.channel;
1563
1564         return 0;
1565 }
1566
1567 /**
1568  * connman_network_set_blob:
1569  * @network: network structure
1570  * @key: unique identifier
1571  * @data: blob data
1572  * @size: blob size
1573  *
1574  * Set binary blob value for specific key
1575  */
1576 int connman_network_set_blob(struct connman_network *network,
1577                         const char *key, const void *data, unsigned int size)
1578 {
1579         DBG("network %p key %s size %d", network, key, size);
1580
1581         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
1582                 g_free(network->wifi.ssid);
1583                 network->wifi.ssid = g_try_malloc(size);
1584                 if (network->wifi.ssid != NULL) {
1585                         memcpy(network->wifi.ssid, data, size);
1586                         network->wifi.ssid_len = size;
1587                 } else
1588                         network->wifi.ssid_len = 0;
1589         }
1590
1591         return connman_element_set_blob(&network->element, key, data, size);
1592 }
1593
1594 /**
1595  * connman_network_get_blob:
1596  * @network: network structure
1597  * @key: unique identifier
1598  * @size: pointer to blob size
1599  *
1600  * Get binary blob value for specific key
1601  */
1602 const void *connman_network_get_blob(struct connman_network *network,
1603                                         const char *key, unsigned int *size)
1604 {
1605         DBG("network %p key %s", network, key);
1606
1607         if (g_str_equal(key, "WiFi.SSID") == TRUE) {
1608                 if (size != NULL)
1609                         *size = network->wifi.ssid_len;
1610                 return network->wifi.ssid;
1611         }
1612
1613         return connman_element_get_blob(&network->element, key, size);
1614 }
1615
1616 void __connman_network_set_device(struct connman_network *network,
1617                                         struct connman_device *device)
1618 {
1619         network->device = device;
1620 }
1621
1622 /**
1623  * connman_network_get_device:
1624  * @network: network structure
1625  *
1626  * Get parent device of network
1627  */
1628 struct connman_device *connman_network_get_device(struct connman_network *network)
1629 {
1630         return network->device;
1631 }
1632
1633 /**
1634  * connman_network_get_data:
1635  * @network: network structure
1636  *
1637  * Get private network data pointer
1638  */
1639 void *connman_network_get_data(struct connman_network *network)
1640 {
1641         return network->driver_data;
1642 }
1643
1644 /**
1645  * connman_network_set_data:
1646  * @network: network structure
1647  * @data: data pointer
1648  *
1649  * Set private network data pointer
1650  */
1651 void connman_network_set_data(struct connman_network *network, void *data)
1652 {
1653         network->driver_data = data;
1654 }
1655
1656 void connman_network_update(struct connman_network *network)
1657 {
1658         switch (network->type) {
1659         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1660         case CONNMAN_NETWORK_TYPE_VENDOR:
1661                 return;
1662         case CONNMAN_NETWORK_TYPE_ETHERNET:
1663         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1664         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1665         case CONNMAN_NETWORK_TYPE_CELLULAR:
1666         case CONNMAN_NETWORK_TYPE_WIFI:
1667         case CONNMAN_NETWORK_TYPE_WIMAX:
1668                 break;
1669         }
1670
1671         if (network->group != NULL)
1672                 __connman_service_update_from_network(network);
1673
1674         return;
1675 }
1676
1677 static gboolean match_driver(struct connman_network *network,
1678                                         struct connman_network_driver *driver)
1679 {
1680         if (network->type == driver->type ||
1681                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
1682                 return TRUE;
1683
1684         return FALSE;
1685 }
1686
1687 static int network_probe(struct connman_element *element)
1688 {
1689         struct connman_network *network = element->network;
1690         GSList *list;
1691
1692         DBG("element %p name %s", element, element->name);
1693
1694         if (network == NULL)
1695                 return -ENODEV;
1696
1697         for (list = driver_list; list; list = list->next) {
1698                 struct connman_network_driver *driver = list->data;
1699
1700                 if (match_driver(network, driver) == FALSE)
1701                         continue;
1702
1703                 DBG("driver %p name %s", driver, driver->name);
1704
1705                 if (driver->probe(network) == 0) {
1706                         network->driver = driver;
1707                         break;
1708                 }
1709         }
1710
1711         if (network->driver == NULL)
1712                 return -ENODEV;
1713
1714         switch (network->type) {
1715         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1716         case CONNMAN_NETWORK_TYPE_VENDOR:
1717                 break;
1718         case CONNMAN_NETWORK_TYPE_ETHERNET:
1719         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1720         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1721         case CONNMAN_NETWORK_TYPE_CELLULAR:
1722         case CONNMAN_NETWORK_TYPE_WIFI:
1723         case CONNMAN_NETWORK_TYPE_WIMAX:
1724                 if (network->group != NULL)
1725                         __connman_profile_add_network(network);
1726                 break;
1727         }
1728
1729         return 0;
1730 }
1731
1732 static void network_remove(struct connman_element *element)
1733 {
1734         struct connman_network *network = element->network;
1735
1736         DBG("element %p name %s", element, element->name);
1737
1738         if (network == NULL)
1739                 return;
1740
1741         if (network->driver == NULL)
1742                 return;
1743
1744         switch (network->type) {
1745         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1746         case CONNMAN_NETWORK_TYPE_VENDOR:
1747                 break;
1748         case CONNMAN_NETWORK_TYPE_ETHERNET:
1749         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1750         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1751         case CONNMAN_NETWORK_TYPE_CELLULAR:
1752         case CONNMAN_NETWORK_TYPE_WIFI:
1753         case CONNMAN_NETWORK_TYPE_WIMAX:
1754                 if (network->group != NULL) {
1755                         __connman_profile_remove_network(network);
1756
1757                         g_free(network->group);
1758                         network->group = NULL;
1759                 }
1760                 break;
1761         }
1762
1763         if (network->driver->remove)
1764                 network->driver->remove(network);
1765 }
1766
1767 static void network_change(struct connman_element *element)
1768 {
1769         struct connman_network *network = element->network;
1770
1771         DBG("element %p name %s", element, element->name);
1772
1773         if (element->state != CONNMAN_ELEMENT_STATE_ERROR)
1774                 return;
1775
1776         if (element->error != CONNMAN_ELEMENT_ERROR_DHCP_FAILED)
1777                 return;
1778
1779         if (network->connected == FALSE)
1780                 return;
1781
1782         connman_element_unregister_children(element);
1783
1784         connman_device_set_disconnected(network->device, TRUE);
1785
1786         if (network->driver && network->driver->disconnect) {
1787                 network->driver->disconnect(network);
1788                 return;
1789         }
1790
1791         network->connected = FALSE;
1792 }
1793
1794 static struct connman_driver network_driver = {
1795         .name           = "network",
1796         .type           = CONNMAN_ELEMENT_TYPE_NETWORK,
1797         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
1798         .probe          = network_probe,
1799         .remove         = network_remove,
1800         .change         = network_change,
1801 };
1802
1803 int __connman_network_init(void)
1804 {
1805         DBG("");
1806
1807         return connman_driver_register(&network_driver);
1808 }
1809
1810 void __connman_network_cleanup(void)
1811 {
1812         DBG("");
1813
1814         connman_driver_unregister(&network_driver);
1815 }