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