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