b388995ff42a43851c478eeaf314604d1593276a
[platform/upstream/connman.git] / src / network.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2014  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 /*
32  * How many times to send RS with the purpose of
33  * refreshing RDNSS entries before they actually expire.
34  * With a value of 1, one RS will be sent, with no retries.
35  */
36 #define RS_REFRESH_COUNT        1
37
38 /*
39  * Value in seconds to wait for RA after RS was sent.
40  * After this time elapsed, we can send another RS.
41  */
42 #define RS_REFRESH_TIMEOUT      3
43
44 static GSList *network_list = NULL;
45 static GSList *driver_list = NULL;
46
47 struct connman_network {
48         int refcount;
49         enum connman_network_type type;
50         bool available;
51         bool connected;
52         bool roaming;
53         uint8_t strength;
54         uint16_t frequency;
55         char *identifier;
56         char *name;
57         char *node;
58         char *group;
59         char *path;
60         int index;
61         int router_solicit_count;
62         int router_solicit_refresh_count;
63
64         struct connman_network_driver *driver;
65         void *driver_data;
66
67         bool connecting;
68         bool associating;
69
70         struct connman_device *device;
71
72         struct {
73                 void *ssid;
74                 int ssid_len;
75                 char *mode;
76                 unsigned short channel;
77                 char *security;
78                 char *passphrase;
79                 char *eap;
80                 char *identity;
81                 char *agent_identity;
82                 char *ca_cert_path;
83                 char *client_cert_path;
84                 char *private_key_path;
85                 char *private_key_passphrase;
86                 char *phase2_auth;
87                 bool wps;
88                 bool use_wps;
89                 char *pin_wps;
90         } wifi;
91
92 };
93
94 static const char *type2string(enum connman_network_type type)
95 {
96         switch (type) {
97         case CONNMAN_NETWORK_TYPE_UNKNOWN:
98         case CONNMAN_NETWORK_TYPE_VENDOR:
99                 break;
100         case CONNMAN_NETWORK_TYPE_ETHERNET:
101                 return "ethernet";
102         case CONNMAN_NETWORK_TYPE_GADGET:
103                 return "gadget";
104         case CONNMAN_NETWORK_TYPE_WIFI:
105                 return "wifi";
106         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
107         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
108                 return "bluetooth";
109         case CONNMAN_NETWORK_TYPE_CELLULAR:
110                 return "cellular";
111         }
112
113         return NULL;
114 }
115
116 static bool match_driver(struct connman_network *network,
117                                         struct connman_network_driver *driver)
118 {
119         if (network->type == driver->type ||
120                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
121                 return true;
122
123         return false;
124 }
125
126 static void set_configuration(struct connman_network *network,
127                         enum connman_ipconfig_type type)
128 {
129         struct connman_service *service;
130
131         DBG("network %p", network);
132
133         if (!network->device)
134                 return;
135
136         __connman_device_set_network(network->device, network);
137
138         connman_device_set_disconnected(network->device, false);
139
140         service = connman_service_lookup_from_network(network);
141         __connman_service_ipconfig_indicate_state(service,
142                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
143                                         type);
144 }
145
146 static void dhcp_success(struct connman_network *network)
147 {
148         struct connman_service *service;
149         struct connman_ipconfig *ipconfig_ipv4;
150         int err;
151
152         service = connman_service_lookup_from_network(network);
153         if (!service)
154                 goto err;
155
156         connman_network_set_associating(network, false);
157
158         network->connecting = false;
159
160         ipconfig_ipv4 = __connman_service_get_ip4config(service);
161
162         DBG("lease acquired for ipconfig %p", ipconfig_ipv4);
163
164         if (!ipconfig_ipv4)
165                 return;
166
167         err = __connman_ipconfig_address_add(ipconfig_ipv4);
168         if (err < 0)
169                 goto err;
170
171         err = __connman_ipconfig_gateway_add(ipconfig_ipv4);
172         if (err < 0)
173                 goto err;
174
175         return;
176
177 err:
178         connman_network_set_error(network,
179                                 CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
180 }
181
182 static void dhcp_failure(struct connman_network *network)
183 {
184         struct connman_service *service;
185         struct connman_ipconfig *ipconfig_ipv4;
186
187         service = connman_service_lookup_from_network(network);
188         if (!service)
189                 return;
190
191         connman_network_set_associating(network, false);
192         network->connecting = false;
193
194         ipconfig_ipv4 = __connman_service_get_ip4config(service);
195
196         DBG("lease lost for ipconfig %p", ipconfig_ipv4);
197
198         if (!ipconfig_ipv4)
199                 return;
200
201         __connman_ipconfig_address_remove(ipconfig_ipv4);
202         __connman_ipconfig_gateway_remove(ipconfig_ipv4);
203 }
204
205 static void dhcp_callback(struct connman_ipconfig *ipconfig,
206                         struct connman_network *network,
207                         bool success, gpointer data)
208 {
209         if (success)
210                 dhcp_success(network);
211         else
212                 dhcp_failure(network);
213 }
214
215 static int set_connected_fixed(struct connman_network *network)
216 {
217         struct connman_service *service;
218         struct connman_ipconfig *ipconfig_ipv4;
219         int err;
220
221         DBG("");
222
223         service = connman_service_lookup_from_network(network);
224
225         ipconfig_ipv4 = __connman_service_get_ip4config(service);
226
227         set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4);
228
229         network->connecting = false;
230
231         connman_network_set_associating(network, false);
232
233         err = __connman_ipconfig_address_add(ipconfig_ipv4);
234         if (err < 0)
235                 goto err;
236
237         err = __connman_ipconfig_gateway_add(ipconfig_ipv4);
238         if (err < 0)
239                 goto err;
240
241         return 0;
242
243 err:
244         connman_network_set_error(network,
245                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
246
247         return err;
248 }
249
250 static void set_connected_manual(struct connman_network *network)
251 {
252         struct connman_service *service;
253         struct connman_ipconfig *ipconfig;
254         int err;
255
256         DBG("network %p", network);
257
258         service = connman_service_lookup_from_network(network);
259
260         ipconfig = __connman_service_get_ip4config(service);
261
262         if (!__connman_ipconfig_get_local(ipconfig))
263                 __connman_service_read_ip4config(service);
264
265         set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4);
266
267         err = __connman_ipconfig_address_add(ipconfig);
268         if (err < 0)
269                 goto err;
270
271         err = __connman_ipconfig_gateway_add(ipconfig);
272         if (err < 0)
273                 goto err;
274
275         network->connecting = false;
276
277         connman_network_set_associating(network, false);
278
279         return;
280
281 err:
282         connman_network_set_error(network,
283                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
284         return;
285 }
286
287 static int set_connected_dhcp(struct connman_network *network)
288 {
289         struct connman_service *service;
290         struct connman_ipconfig *ipconfig_ipv4;
291         int err;
292
293         DBG("network %p", network);
294
295         set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4);
296
297         service = connman_service_lookup_from_network(network);
298         ipconfig_ipv4 = __connman_service_get_ip4config(service);
299
300         err = __connman_dhcp_start(ipconfig_ipv4, network,
301                                                         dhcp_callback, NULL);
302         if (err < 0) {
303                 connman_error("Can not request DHCP lease");
304                 return err;
305         }
306
307         return 0;
308 }
309
310 static int manual_ipv6_set(struct connman_network *network,
311                                 struct connman_ipconfig *ipconfig_ipv6)
312 {
313         struct connman_service *service;
314         int err;
315
316         DBG("network %p ipv6 %p", network, ipconfig_ipv6);
317
318         service = connman_service_lookup_from_network(network);
319         if (!service)
320                 return -EINVAL;
321
322         if (!__connman_ipconfig_get_local(ipconfig_ipv6))
323                 __connman_service_read_ip6config(service);
324
325         __connman_ipconfig_enable_ipv6(ipconfig_ipv6);
326
327         err = __connman_ipconfig_address_add(ipconfig_ipv6);
328         if (err < 0) {
329                 connman_network_set_error(network,
330                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
331                 return err;
332         }
333
334         err = __connman_ipconfig_gateway_add(ipconfig_ipv6);
335         if (err < 0)
336                 return err;
337
338         __connman_connection_gateway_activate(service,
339                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
340
341         __connman_device_set_network(network->device, network);
342
343         connman_device_set_disconnected(network->device, false);
344
345         network->connecting = false;
346
347         return 0;
348 }
349
350 static void stop_dhcpv6(struct connman_network *network)
351 {
352         __connman_dhcpv6_stop(network);
353 }
354
355 static void dhcpv6_release_callback(struct connman_network *network,
356                                 enum __connman_dhcpv6_status status,
357                                 gpointer data)
358 {
359         DBG("status %d", status);
360
361         stop_dhcpv6(network);
362 }
363
364 static void release_dhcpv6(struct connman_network *network)
365 {
366         __connman_dhcpv6_start_release(network, dhcpv6_release_callback);
367         stop_dhcpv6(network);
368 }
369
370 static void dhcpv6_info_callback(struct connman_network *network,
371                                 enum __connman_dhcpv6_status status,
372                                 gpointer data)
373 {
374         DBG("status %d", status);
375
376         stop_dhcpv6(network);
377 }
378
379 static int dhcpv6_set_addresses(struct connman_network *network)
380 {
381         struct connman_service *service;
382         struct connman_ipconfig *ipconfig_ipv6;
383         int err = -EINVAL;
384
385         service = connman_service_lookup_from_network(network);
386         if (!service)
387                 goto err;
388
389         connman_network_set_associating(network, false);
390
391         network->connecting = false;
392
393         ipconfig_ipv6 = __connman_service_get_ip6config(service);
394         err = __connman_ipconfig_address_add(ipconfig_ipv6);
395         if (err < 0)
396                 goto err;
397
398         err = __connman_ipconfig_gateway_add(ipconfig_ipv6);
399         if (err < 0)
400                 goto err;
401
402         return 0;
403
404 err:
405         connman_network_set_error(network,
406                                 CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
407         return err;
408 }
409
410 static void autoconf_ipv6_set(struct connman_network *network);
411 static void dhcpv6_callback(struct connman_network *network,
412                         enum __connman_dhcpv6_status status, gpointer data);
413
414 /*
415  * Have a separate callback for renew so that we do not do autoconf
416  * in wrong phase as the dhcpv6_callback() is also called when doing
417  * DHCPv6 solicitation.
418  */
419 static void dhcpv6_renew_callback(struct connman_network *network,
420                                 enum __connman_dhcpv6_status status,
421                                 gpointer data)
422 {
423         switch (status) {
424         case CONNMAN_DHCPV6_STATUS_SUCCEED:
425                 dhcpv6_callback(network, status, data);
426                 break;
427         case CONNMAN_DHCPV6_STATUS_FAIL:
428         case CONNMAN_DHCPV6_STATUS_RESTART:
429                 stop_dhcpv6(network);
430
431                 /* restart and do solicit again. */
432                 autoconf_ipv6_set(network);
433                 break;
434         }
435 }
436
437 static void dhcpv6_callback(struct connman_network *network,
438                         enum __connman_dhcpv6_status status, gpointer data)
439 {
440         DBG("status %d", status);
441
442         /* Start the renew process if necessary */
443         if (status == CONNMAN_DHCPV6_STATUS_SUCCEED) {
444
445                 if (dhcpv6_set_addresses(network) < 0) {
446                         stop_dhcpv6(network);
447                         return;
448                 }
449
450                 if (__connman_dhcpv6_start_renew(network,
451                                         dhcpv6_renew_callback) == -ETIMEDOUT)
452                         dhcpv6_renew_callback(network,
453                                                 CONNMAN_DHCPV6_STATUS_FAIL,
454                                                 data);
455
456         } else if (status == CONNMAN_DHCPV6_STATUS_RESTART) {
457                 stop_dhcpv6(network);
458                 autoconf_ipv6_set(network);
459         } else
460                 stop_dhcpv6(network);
461 }
462
463 static void check_dhcpv6(struct nd_router_advert *reply,
464                         unsigned int length, void *user_data)
465 {
466         struct connman_network *network = user_data;
467         struct connman_service *service;
468         GSList *prefixes;
469
470         DBG("reply %p", reply);
471
472         if (!reply) {
473                 /*
474                  * Router solicitation message seem to get lost easily so
475                  * try to send it again.
476                  */
477                 if (network->router_solicit_count > 0) {
478                         DBG("re-send router solicitation %d",
479                                                 network->router_solicit_count);
480                         network->router_solicit_count--;
481                         __connman_inet_ipv6_send_rs(network->index, 1,
482                                                 check_dhcpv6, network);
483                         return;
484                 }
485                 connman_network_unref(network);
486                 return;
487         }
488
489         network->router_solicit_count = 0;
490
491         /*
492          * If we were disconnected while waiting router advertisement,
493          * we just quit and do not start DHCPv6
494          */
495         if (!network->connected) {
496                 connman_network_unref(network);
497                 return;
498         }
499
500         prefixes = __connman_inet_ipv6_get_prefixes(reply, length);
501
502         /*
503          * If IPv6 config is missing from service, then create it.
504          * The ipconfig might be missing if we got a rtnl message
505          * that disabled IPv6 config and thus removed it. This
506          * can happen if we are switching from one service to
507          * another in the same interface. The only way to get IPv6
508          * config back is to re-create it here.
509          */
510         service = connman_service_lookup_from_network(network);
511         if (service) {
512                 connman_service_create_ip6config(service, network->index);
513
514                 __connman_service_ipconfig_indicate_state(service,
515                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
516                                         CONNMAN_IPCONFIG_TYPE_IPV6);
517         }
518
519         /*
520          * We do stateful/stateless DHCPv6 if router advertisement says so.
521          */
522         if (reply->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
523                 __connman_dhcpv6_start(network, prefixes, dhcpv6_callback);
524         else if (reply->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
525                 __connman_dhcpv6_start_info(network, dhcpv6_info_callback);
526
527         connman_network_unref(network);
528 }
529
530 static void receive_refresh_rs_reply(struct nd_router_advert *reply,
531                 unsigned int length, void *user_data)
532 {
533         struct connman_network *network = user_data;
534
535         DBG("reply %p", reply);
536
537         if (!reply) {
538                 /*
539                  * Router solicitation message seem to get lost easily so
540                  * try to send it again.
541                  */
542                 if (network->router_solicit_refresh_count > 1) {
543                         network->router_solicit_refresh_count--;
544                         DBG("re-send router solicitation %d",
545                                         network->router_solicit_refresh_count);
546                         __connman_inet_ipv6_send_rs(network->index,
547                                         RS_REFRESH_TIMEOUT,
548                                         receive_refresh_rs_reply,
549                                         network);
550                         return;
551                 }
552         }
553
554         /* RS refresh not in progress anymore */
555         network->router_solicit_refresh_count = 0;
556
557         connman_network_unref(network);
558         return;
559 }
560
561 int __connman_network_refresh_rs_ipv6(struct connman_network *network,
562                                         int index)
563 {
564         int ret = 0;
565
566         DBG("network %p index %d", network, index);
567
568         /* Send only one RS for all RDNSS entries which are about to expire */
569         if (network->router_solicit_refresh_count > 0) {
570                 DBG("RS refresh already started");
571                 return 0;
572         }
573
574         network->router_solicit_refresh_count = RS_REFRESH_COUNT;
575
576         connman_network_ref(network);
577
578         ret = __connman_inet_ipv6_send_rs(index, RS_REFRESH_TIMEOUT,
579                         receive_refresh_rs_reply, network);
580         return ret;
581 }
582
583 static void autoconf_ipv6_set(struct connman_network *network)
584 {
585         struct connman_service *service;
586         struct connman_ipconfig *ipconfig;
587         int index;
588
589         DBG("network %p", network);
590
591         if (network->router_solicit_count > 0) {
592                 /*
593                  * The autoconfiguration is already pending and we have sent
594                  * router solicitation messages and are now waiting answers.
595                  * There is no need to continue any further.
596                  */
597                 DBG("autoconfiguration already started");
598                 return;
599         }
600
601         __connman_device_set_network(network->device, network);
602
603         connman_device_set_disconnected(network->device, false);
604
605         network->connecting = false;
606
607         service = connman_service_lookup_from_network(network);
608         if (!service)
609                 return;
610
611         ipconfig = __connman_service_get_ip6config(service);
612         if (!ipconfig)
613                 return;
614
615         __connman_ipconfig_address_remove(ipconfig);
616
617         index = __connman_ipconfig_get_index(ipconfig);
618
619         connman_network_ref(network);
620
621         /* Try to get stateless DHCPv6 information, RFC 3736 */
622         network->router_solicit_count = 3;
623         __connman_inet_ipv6_send_rs(index, 1, check_dhcpv6, network);
624 }
625
626 static void set_connected(struct connman_network *network)
627 {
628         struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
629         enum connman_ipconfig_method ipv4_method, ipv6_method;
630         struct connman_service *service;
631         int ret;
632
633         if (network->connected)
634                 return;
635
636         network->connected = true;
637
638         service = connman_service_lookup_from_network(network);
639
640         ipconfig_ipv4 = __connman_service_get_ip4config(service);
641         ipconfig_ipv6 = __connman_service_get_ip6config(service);
642
643         DBG("service %p ipv4 %p ipv6 %p", service, ipconfig_ipv4,
644                 ipconfig_ipv6);
645
646         ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4);
647         ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6);
648
649         DBG("method ipv4 %d ipv6 %d", ipv4_method, ipv6_method);
650
651         switch (ipv6_method) {
652         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
653         case CONNMAN_IPCONFIG_METHOD_OFF:
654                 break;
655         case CONNMAN_IPCONFIG_METHOD_DHCP:
656         case CONNMAN_IPCONFIG_METHOD_AUTO:
657                 autoconf_ipv6_set(network);
658                 break;
659         case CONNMAN_IPCONFIG_METHOD_FIXED:
660         case CONNMAN_IPCONFIG_METHOD_MANUAL:
661                 ret = manual_ipv6_set(network, ipconfig_ipv6);
662                 if (ret != 0) {
663                         connman_network_set_error(network,
664                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
665                         return;
666                 }
667                 break;
668         }
669
670         switch (ipv4_method) {
671         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
672         case CONNMAN_IPCONFIG_METHOD_OFF:
673         case CONNMAN_IPCONFIG_METHOD_AUTO:
674                 return;
675         case CONNMAN_IPCONFIG_METHOD_FIXED:
676                 if (set_connected_fixed(network) < 0) {
677                         connman_network_set_error(network,
678                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
679                         return;
680                 }
681                 return;
682         case CONNMAN_IPCONFIG_METHOD_MANUAL:
683                 set_connected_manual(network);
684                 return;
685         case CONNMAN_IPCONFIG_METHOD_DHCP:
686                 if (set_connected_dhcp(network) < 0) {
687                         connman_network_set_error(network,
688                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
689                         return;
690                 }
691         }
692
693         network->connecting = false;
694
695         connman_network_set_associating(network, false);
696 }
697
698 static void set_disconnected(struct connman_network *network)
699 {
700         struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
701         enum connman_ipconfig_method ipv4_method, ipv6_method;
702         enum connman_service_state state;
703         struct connman_service *service;
704
705         service = connman_service_lookup_from_network(network);
706
707         ipconfig_ipv4 = __connman_service_get_ip4config(service);
708         ipconfig_ipv6 = __connman_service_get_ip6config(service);
709
710         DBG("service %p ipv4 %p ipv6 %p", service, ipconfig_ipv4,
711                 ipconfig_ipv6);
712
713         ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4);
714         ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6);
715
716         DBG("method ipv4 %d ipv6 %d", ipv4_method, ipv6_method);
717
718         /*
719          * Resetting solicit count here will prevent the RS resend loop
720          * from sending packets in check_dhcpv6()
721          */
722         network->router_solicit_count = 0;
723
724         __connman_device_set_network(network->device, NULL);
725
726         if (network->connected) {
727                 switch (ipv6_method) {
728                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
729                 case CONNMAN_IPCONFIG_METHOD_OFF:
730                 case CONNMAN_IPCONFIG_METHOD_FIXED:
731                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
732                         break;
733                 case CONNMAN_IPCONFIG_METHOD_DHCP:
734                 case CONNMAN_IPCONFIG_METHOD_AUTO:
735                         release_dhcpv6(network);
736                         break;
737                 }
738
739                 switch (ipv4_method) {
740                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
741                 case CONNMAN_IPCONFIG_METHOD_OFF:
742                 case CONNMAN_IPCONFIG_METHOD_AUTO:
743                 case CONNMAN_IPCONFIG_METHOD_FIXED:
744                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
745                         break;
746                 case CONNMAN_IPCONFIG_METHOD_DHCP:
747                         __connman_dhcp_stop(ipconfig_ipv4);
748                         break;
749                 }
750         }
751
752         /*
753          * We only set the disconnect state if we were not in idle
754          * or in failure. It does not make sense to go to disconnect
755          * state if we were not connected.
756          */
757         state = __connman_service_ipconfig_get_state(service,
758                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
759         if (state != CONNMAN_SERVICE_STATE_IDLE &&
760                         state != CONNMAN_SERVICE_STATE_FAILURE)
761                 __connman_service_ipconfig_indicate_state(service,
762                                         CONNMAN_SERVICE_STATE_DISCONNECT,
763                                         CONNMAN_IPCONFIG_TYPE_IPV4);
764
765         state = __connman_service_ipconfig_get_state(service,
766                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
767         if (state != CONNMAN_SERVICE_STATE_IDLE &&
768                                 state != CONNMAN_SERVICE_STATE_FAILURE)
769                 __connman_service_ipconfig_indicate_state(service,
770                                         CONNMAN_SERVICE_STATE_DISCONNECT,
771                                         CONNMAN_IPCONFIG_TYPE_IPV6);
772
773         if (network->connected) {
774                 __connman_connection_gateway_remove(service,
775                                                 CONNMAN_IPCONFIG_TYPE_ALL);
776
777                 __connman_ipconfig_address_unset(ipconfig_ipv4);
778                 __connman_ipconfig_address_unset(ipconfig_ipv6);
779
780                 /*
781                  * Special handling for IPv6 autoconfigured address.
782                  * The simplest way to remove autoconfigured routes is to
783                  * disable IPv6 temporarily so that kernel will do the cleanup
784                  * automagically.
785                  */
786                 if (ipv6_method == CONNMAN_IPCONFIG_METHOD_AUTO) {
787                         __connman_ipconfig_disable_ipv6(ipconfig_ipv6);
788                         __connman_ipconfig_enable_ipv6(ipconfig_ipv6);
789                 }
790         }
791
792         __connman_service_ipconfig_indicate_state(service,
793                                                 CONNMAN_SERVICE_STATE_IDLE,
794                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
795
796         __connman_service_ipconfig_indicate_state(service,
797                                                 CONNMAN_SERVICE_STATE_IDLE,
798                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
799
800         network->connecting = false;
801         network->connected = false;
802
803         connman_network_set_associating(network, false);
804 }
805
806
807
808 static int network_probe(struct connman_network *network)
809 {
810         GSList *list;
811         struct connman_network_driver *driver = NULL;
812
813         DBG("network %p name %s", network, network->name);
814
815         if (network->driver)
816                 return -EALREADY;
817
818         for (list = driver_list; list; list = list->next) {
819                 driver = list->data;
820
821                 if (!match_driver(network, driver)) {
822                         driver = NULL;
823                         continue;
824                 }
825
826                 DBG("driver %p name %s", driver, driver->name);
827
828                 if (driver->probe(network) == 0)
829                         break;
830
831                 driver = NULL;
832         }
833
834         if (!driver)
835                 return -ENODEV;
836
837         if (!network->group)
838                 return -EINVAL;
839
840         switch (network->type) {
841         case CONNMAN_NETWORK_TYPE_UNKNOWN:
842         case CONNMAN_NETWORK_TYPE_VENDOR:
843                 return 0;
844         case CONNMAN_NETWORK_TYPE_ETHERNET:
845         case CONNMAN_NETWORK_TYPE_GADGET:
846         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
847         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
848         case CONNMAN_NETWORK_TYPE_CELLULAR:
849         case CONNMAN_NETWORK_TYPE_WIFI:
850                 network->driver = driver;
851                 if (!__connman_service_create_from_network(network)) {
852                         network->driver = NULL;
853                         return -EINVAL;
854                 }
855         }
856
857         return 0;
858 }
859
860 static void network_remove(struct connman_network *network)
861 {
862         DBG("network %p name %s", network, network->name);
863
864         if (!network->driver)
865                 return;
866
867         if (network->connected)
868                 set_disconnected(network);
869
870         switch (network->type) {
871         case CONNMAN_NETWORK_TYPE_UNKNOWN:
872         case CONNMAN_NETWORK_TYPE_VENDOR:
873                 break;
874         case CONNMAN_NETWORK_TYPE_ETHERNET:
875         case CONNMAN_NETWORK_TYPE_GADGET:
876         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
877         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
878         case CONNMAN_NETWORK_TYPE_CELLULAR:
879         case CONNMAN_NETWORK_TYPE_WIFI:
880                 if (network->group) {
881                         __connman_service_remove_from_network(network);
882
883                         g_free(network->group);
884                         network->group = NULL;
885                 }
886                 break;
887         }
888
889         if (network->driver->remove)
890                 network->driver->remove(network);
891
892         network->driver = NULL;
893 }
894
895 static void network_change(struct connman_network *network)
896 {
897         DBG("network %p name %s", network, network->name);
898
899         if (!network->connected)
900                 return;
901
902         connman_device_set_disconnected(network->device, true);
903
904         if (network->driver && network->driver->disconnect) {
905                 network->driver->disconnect(network);
906                 return;
907         }
908
909         network->connected = false;
910 }
911
912 static void probe_driver(struct connman_network_driver *driver)
913 {
914         GSList *list;
915
916         DBG("driver %p name %s", driver, driver->name);
917
918         for (list = network_list; list; list = list->next) {
919                 struct connman_network *network = list->data;
920
921                 if (network->driver)
922                         continue;
923
924                 if (driver->type != network->type)
925                         continue;
926
927                 if (driver->probe(network) < 0)
928                         continue;
929
930                 network->driver = driver;
931         }
932 }
933
934 static void remove_driver(struct connman_network_driver *driver)
935 {
936         GSList *list;
937
938         DBG("driver %p name %s", driver, driver->name);
939
940         for (list = network_list; list; list = list->next) {
941                 struct connman_network *network = list->data;
942
943                 if (network->driver == driver)
944                         network_remove(network);
945         }
946 }
947
948 static gint compare_priority(gconstpointer a, gconstpointer b)
949 {
950         const struct connman_network_driver *driver1 = a;
951         const struct connman_network_driver *driver2 = b;
952
953         return driver2->priority - driver1->priority;
954 }
955
956 /**
957  * connman_network_driver_register:
958  * @driver: network driver definition
959  *
960  * Register a new network driver
961  *
962  * Returns: %0 on success
963  */
964 int connman_network_driver_register(struct connman_network_driver *driver)
965 {
966         DBG("driver %p name %s", driver, driver->name);
967
968         driver_list = g_slist_insert_sorted(driver_list, driver,
969                                                         compare_priority);
970
971         probe_driver(driver);
972
973         return 0;
974 }
975
976 /**
977  * connman_network_driver_unregister:
978  * @driver: network driver definition
979  *
980  * Remove a previously registered network driver
981  */
982 void connman_network_driver_unregister(struct connman_network_driver *driver)
983 {
984         DBG("driver %p name %s", driver, driver->name);
985
986         driver_list = g_slist_remove(driver_list, driver);
987
988         remove_driver(driver);
989 }
990
991 static void network_destruct(struct connman_network *network)
992 {
993         DBG("network %p name %s", network, network->name);
994
995         g_free(network->wifi.ssid);
996         g_free(network->wifi.mode);
997         g_free(network->wifi.security);
998         g_free(network->wifi.passphrase);
999         g_free(network->wifi.eap);
1000         g_free(network->wifi.identity);
1001         g_free(network->wifi.agent_identity);
1002         g_free(network->wifi.ca_cert_path);
1003         g_free(network->wifi.client_cert_path);
1004         g_free(network->wifi.private_key_path);
1005         g_free(network->wifi.private_key_passphrase);
1006         g_free(network->wifi.phase2_auth);
1007         g_free(network->wifi.pin_wps);
1008
1009         g_free(network->path);
1010         g_free(network->group);
1011         g_free(network->node);
1012         g_free(network->name);
1013         g_free(network->identifier);
1014
1015         network->device = NULL;
1016
1017         g_free(network);
1018 }
1019
1020 /**
1021  * connman_network_create:
1022  * @identifier: network identifier (for example an unqiue name)
1023  *
1024  * Allocate a new network and assign the #identifier to it.
1025  *
1026  * Returns: a newly-allocated #connman_network structure
1027  */
1028 struct connman_network *connman_network_create(const char *identifier,
1029                                                 enum connman_network_type type)
1030 {
1031         struct connman_network *network;
1032         char *ident;
1033
1034         DBG("identifier %s type %d", identifier, type);
1035
1036         network = g_try_new0(struct connman_network, 1);
1037         if (!network)
1038                 return NULL;
1039
1040         DBG("network %p", network);
1041
1042         network->refcount = 1;
1043
1044         ident = g_strdup(identifier);
1045
1046         if (!ident) {
1047                 g_free(network);
1048                 return NULL;
1049         }
1050
1051         network->type       = type;
1052         network->identifier = ident;
1053
1054         network_list = g_slist_prepend(network_list, network);
1055
1056         return network;
1057 }
1058
1059 /**
1060  * connman_network_ref:
1061  * @network: network structure
1062  *
1063  * Increase reference counter of  network
1064  */
1065 struct connman_network *
1066 connman_network_ref_debug(struct connman_network *network,
1067                         const char *file, int line, const char *caller)
1068 {
1069         DBG("%p name %s ref %d by %s:%d:%s()", network, network->name,
1070                 network->refcount + 1, file, line, caller);
1071
1072         __sync_fetch_and_add(&network->refcount, 1);
1073
1074         return network;
1075 }
1076
1077 /**
1078  * connman_network_unref:
1079  * @network: network structure
1080  *
1081  * Decrease reference counter of network
1082  */
1083 void connman_network_unref_debug(struct connman_network *network,
1084                                 const char *file, int line, const char *caller)
1085 {
1086         DBG("%p name %s ref %d by %s:%d:%s()", network, network->name,
1087                 network->refcount - 1, file, line, caller);
1088
1089         if (__sync_fetch_and_sub(&network->refcount, 1) != 1)
1090                 return;
1091
1092         network_list = g_slist_remove(network_list, network);
1093
1094         network_destruct(network);
1095 }
1096
1097 const char *__connman_network_get_type(struct connman_network *network)
1098 {
1099         return type2string(network->type);
1100 }
1101
1102 /**
1103  * connman_network_get_type:
1104  * @network: network structure
1105  *
1106  * Get type of network
1107  */
1108 enum connman_network_type connman_network_get_type(
1109                                 struct connman_network *network)
1110 {
1111         return network->type;
1112 }
1113
1114 /**
1115  * connman_network_get_identifier:
1116  * @network: network structure
1117  *
1118  * Get identifier of network
1119  */
1120 const char *connman_network_get_identifier(struct connman_network *network)
1121 {
1122         return network->identifier;
1123 }
1124
1125 /**
1126  * connman_network_set_index:
1127  * @network: network structure
1128  * @index: index number
1129  *
1130  * Set index number of network
1131  */
1132 void connman_network_set_index(struct connman_network *network, int index)
1133 {
1134         struct connman_service *service;
1135         struct connman_ipconfig *ipconfig;
1136
1137         service = connman_service_lookup_from_network(network);
1138         if (!service)
1139                 goto done;
1140
1141         ipconfig = __connman_service_get_ip4config(service);
1142         if (!ipconfig)
1143                 goto done;
1144
1145         /* If index changed, the index of ipconfig must be reset. */
1146         __connman_ipconfig_set_index(ipconfig, index);
1147
1148         DBG("index %d service %p ip4config %p", network->index,
1149                 service, ipconfig);
1150 done:
1151         network->index = index;
1152 }
1153
1154 /**
1155  * connman_network_get_index:
1156  * @network: network structure
1157  *
1158  * Get index number of network
1159  */
1160 int connman_network_get_index(struct connman_network *network)
1161 {
1162         return network->index;
1163 }
1164
1165 /**
1166  * connman_network_set_group:
1167  * @network: network structure
1168  * @group: group name
1169  *
1170  * Set group name for automatic clustering
1171  */
1172 void connman_network_set_group(struct connman_network *network,
1173                                                         const char *group)
1174 {
1175         switch (network->type) {
1176         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1177         case CONNMAN_NETWORK_TYPE_VENDOR:
1178                 return;
1179         case CONNMAN_NETWORK_TYPE_ETHERNET:
1180         case CONNMAN_NETWORK_TYPE_GADGET:
1181         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1182         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1183         case CONNMAN_NETWORK_TYPE_CELLULAR:
1184         case CONNMAN_NETWORK_TYPE_WIFI:
1185                 break;
1186         }
1187
1188         if (g_strcmp0(network->group, group) == 0) {
1189                 if (group)
1190                         __connman_service_update_from_network(network);
1191                 return;
1192         }
1193
1194         if (network->group) {
1195                 __connman_service_remove_from_network(network);
1196
1197                 g_free(network->group);
1198         }
1199
1200         network->group = g_strdup(group);
1201
1202         if (network->group)
1203                 network_probe(network);
1204 }
1205
1206 /**
1207  * connman_network_get_group:
1208  * @network: network structure
1209  *
1210  * Get group name for automatic clustering
1211  */
1212 const char *connman_network_get_group(struct connman_network *network)
1213 {
1214         return network->group;
1215 }
1216
1217 const char *__connman_network_get_ident(struct connman_network *network)
1218 {
1219         if (!network->device)
1220                 return NULL;
1221
1222         return connman_device_get_ident(network->device);
1223 }
1224
1225 bool __connman_network_get_weakness(struct connman_network *network)
1226 {
1227         switch (network->type) {
1228         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1229         case CONNMAN_NETWORK_TYPE_VENDOR:
1230         case CONNMAN_NETWORK_TYPE_ETHERNET:
1231         case CONNMAN_NETWORK_TYPE_GADGET:
1232         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1233         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1234         case CONNMAN_NETWORK_TYPE_CELLULAR:
1235                 break;
1236         case CONNMAN_NETWORK_TYPE_WIFI:
1237                 if (network->strength > 0 && network->strength < 20)
1238                         return true;
1239                 break;
1240         }
1241
1242         return false;
1243 }
1244
1245 bool connman_network_get_connecting(struct connman_network *network)
1246 {
1247         return network->connecting;
1248 }
1249
1250 /**
1251  * connman_network_set_available:
1252  * @network: network structure
1253  * @available: availability state
1254  *
1255  * Change availability state of network (in range)
1256  */
1257 int connman_network_set_available(struct connman_network *network,
1258                                                 bool available)
1259 {
1260         DBG("network %p available %d", network, available);
1261
1262         if (network->available == available)
1263                 return -EALREADY;
1264
1265         network->available = available;
1266
1267         return 0;
1268 }
1269
1270 /**
1271  * connman_network_get_available:
1272  * @network: network structure
1273  *
1274  * Get network available setting
1275  */
1276 bool connman_network_get_available(struct connman_network *network)
1277 {
1278         return network->available;
1279 }
1280
1281 /**
1282  * connman_network_set_associating:
1283  * @network: network structure
1284  * @associating: associating state
1285  *
1286  * Change associating state of network
1287  */
1288 int connman_network_set_associating(struct connman_network *network,
1289                                                 bool associating)
1290 {
1291         DBG("network %p associating %d", network, associating);
1292
1293         if (network->associating == associating)
1294                 return -EALREADY;
1295
1296         network->associating = associating;
1297
1298         if (associating) {
1299                 struct connman_service *service;
1300
1301                 service = connman_service_lookup_from_network(network);
1302                 __connman_service_ipconfig_indicate_state(service,
1303                                         CONNMAN_SERVICE_STATE_ASSOCIATION,
1304                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1305                 __connman_service_ipconfig_indicate_state(service,
1306                                         CONNMAN_SERVICE_STATE_ASSOCIATION,
1307                                         CONNMAN_IPCONFIG_TYPE_IPV6);
1308         }
1309
1310         return 0;
1311 }
1312
1313 static void set_associate_error(struct connman_network *network)
1314 {
1315         struct connman_service *service;
1316
1317         service = connman_service_lookup_from_network(network);
1318
1319         __connman_service_indicate_error(service,
1320                                         CONNMAN_SERVICE_ERROR_CONNECT_FAILED);
1321 }
1322
1323 static void set_configure_error(struct connman_network *network)
1324 {
1325         struct connman_service *service;
1326
1327         service = connman_service_lookup_from_network(network);
1328
1329         __connman_service_indicate_error(service,
1330                                         CONNMAN_SERVICE_ERROR_CONNECT_FAILED);
1331 }
1332
1333 static void set_invalid_key_error(struct connman_network *network)
1334 {
1335         struct connman_service *service;
1336
1337         service = connman_service_lookup_from_network(network);
1338
1339         __connman_service_indicate_error(service,
1340                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
1341 }
1342
1343 static void set_connect_error(struct connman_network *network)
1344 {
1345         struct connman_service *service;
1346
1347         service = connman_service_lookup_from_network(network);
1348
1349         __connman_service_indicate_error(service,
1350                                         CONNMAN_SERVICE_ERROR_CONNECT_FAILED);
1351 }
1352
1353 void connman_network_set_ipv4_method(struct connman_network *network,
1354                                         enum connman_ipconfig_method method)
1355 {
1356         struct connman_service *service;
1357         struct connman_ipconfig *ipconfig;
1358
1359         service = connman_service_lookup_from_network(network);
1360         if (!service)
1361                 return;
1362
1363         ipconfig = __connman_service_get_ip4config(service);
1364         if (!ipconfig)
1365                 return;
1366
1367         __connman_ipconfig_set_method(ipconfig, method);
1368 }
1369
1370 void connman_network_set_ipv6_method(struct connman_network *network,
1371                                         enum connman_ipconfig_method method)
1372 {
1373         struct connman_service *service;
1374         struct connman_ipconfig *ipconfig;
1375
1376         service = connman_service_lookup_from_network(network);
1377         if (!service)
1378                 return;
1379
1380         ipconfig = __connman_service_get_ip6config(service);
1381         if (!ipconfig)
1382                 return;
1383
1384         __connman_ipconfig_set_method(ipconfig, method);
1385 }
1386
1387 void connman_network_set_error(struct connman_network *network,
1388                                         enum connman_network_error error)
1389 {
1390         DBG("network %p error %d", network, error);
1391
1392         network->connecting = false;
1393         network->associating = false;
1394
1395         switch (error) {
1396         case CONNMAN_NETWORK_ERROR_UNKNOWN:
1397                 return;
1398         case CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL:
1399                 set_associate_error(network);
1400                 break;
1401         case CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL:
1402                 set_configure_error(network);
1403                 break;
1404         case CONNMAN_NETWORK_ERROR_INVALID_KEY:
1405                 set_invalid_key_error(network);
1406                 break;
1407         case CONNMAN_NETWORK_ERROR_CONNECT_FAIL:
1408                 set_connect_error(network);
1409                 break;
1410         }
1411
1412         network_change(network);
1413 }
1414
1415 /**
1416  * connman_network_set_connected:
1417  * @network: network structure
1418  * @connected: connected state
1419  *
1420  * Change connected state of network
1421  */
1422 int connman_network_set_connected(struct connman_network *network,
1423                                                 bool connected)
1424 {
1425         DBG("network %p connected %d/%d connecting %d associating %d",
1426                 network, network->connected, connected, network->connecting,
1427                 network->associating);
1428
1429         if ((network->connecting || network->associating) &&
1430                                                         !connected) {
1431                 connman_network_set_error(network,
1432                                         CONNMAN_NETWORK_ERROR_CONNECT_FAIL);
1433                 if (__connman_network_disconnect(network) == 0)
1434                         return 0;
1435         }
1436
1437         if (network->connected == connected)
1438                 return -EALREADY;
1439
1440         if (!connected)
1441                 set_disconnected(network);
1442         else
1443                 set_connected(network);
1444
1445         return 0;
1446 }
1447
1448 /**
1449  * connman_network_get_connected:
1450  * @network: network structure
1451  *
1452  * Get network connection status
1453  */
1454 bool connman_network_get_connected(struct connman_network *network)
1455 {
1456         return network->connected;
1457 }
1458
1459 /**
1460  * connman_network_get_associating:
1461  * @network: network structure
1462  *
1463  * Get network associating status
1464  */
1465 bool connman_network_get_associating(struct connman_network *network)
1466 {
1467         return network->associating;
1468 }
1469
1470 void connman_network_clear_hidden(void *user_data)
1471 {
1472         if (!user_data)
1473                 return;
1474
1475         DBG("user_data %p", user_data);
1476
1477         /*
1478          * Hidden service does not have a connect timeout so
1479          * we do not need to remove it. We can just return
1480          * error to the caller telling that we could not find
1481          * any network that we could connect to.
1482          */
1483         connman_dbus_reply_pending(user_data, EIO, NULL);
1484 }
1485
1486 int connman_network_connect_hidden(struct connman_network *network,
1487                         char *identity, char *passphrase, void *user_data)
1488 {
1489         int err = 0;
1490         struct connman_service *service;
1491
1492         service = connman_service_lookup_from_network(network);
1493
1494         DBG("network %p service %p user_data %p", network, service, user_data);
1495
1496         if (!service)
1497                 return -EINVAL;
1498
1499         if (identity)
1500                 __connman_service_set_agent_identity(service, identity);
1501
1502         if (passphrase)
1503                 err = __connman_service_set_passphrase(service, passphrase);
1504
1505         if (err == -ENOKEY) {
1506                 __connman_service_indicate_error(service,
1507                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
1508                 goto out;
1509         } else {
1510                 __connman_service_set_hidden(service);
1511                 __connman_service_set_hidden_data(service, user_data);
1512                 return __connman_service_connect(service,
1513                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
1514         }
1515
1516 out:
1517         __connman_service_return_error(service, -err, user_data);
1518         return err;
1519 }
1520
1521 /**
1522  * __connman_network_connect:
1523  * @network: network structure
1524  *
1525  * Connect network
1526  */
1527 int __connman_network_connect(struct connman_network *network)
1528 {
1529         int err;
1530
1531         DBG("network %p", network);
1532
1533         if (network->connected)
1534                 return -EISCONN;
1535
1536         if (network->connecting || network->associating)
1537                 return -EALREADY;
1538
1539         if (!network->driver)
1540                 return -EUNATCH;
1541
1542         if (!network->driver->connect)
1543                 return -ENOSYS;
1544
1545         if (!network->device)
1546                 return -ENODEV;
1547
1548         network->connecting = true;
1549
1550         __connman_device_disconnect(network->device);
1551
1552         err = network->driver->connect(network);
1553         if (err < 0) {
1554                 if (err == -EINPROGRESS)
1555                         connman_network_set_associating(network, true);
1556                 else
1557                         network->connecting = false;
1558
1559                 return err;
1560         }
1561
1562         set_connected(network);
1563
1564         return err;
1565 }
1566
1567 /**
1568  * __connman_network_disconnect:
1569  * @network: network structure
1570  *
1571  * Disconnect network
1572  */
1573 int __connman_network_disconnect(struct connman_network *network)
1574 {
1575         int err = 0;
1576
1577         DBG("network %p", network);
1578
1579         if (!network->connected && !network->connecting &&
1580                                                 !network->associating)
1581                 return -ENOTCONN;
1582
1583         if (!network->driver)
1584                 return -EUNATCH;
1585
1586         network->connecting = false;
1587
1588         if (network->driver->disconnect)
1589                 err = network->driver->disconnect(network);
1590
1591         if (err != -EINPROGRESS)
1592                 set_disconnected(network);
1593
1594         return err;
1595 }
1596
1597 static int manual_ipv4_set(struct connman_network *network,
1598                                 struct connman_ipconfig *ipconfig)
1599 {
1600         struct connman_service *service;
1601         int err;
1602
1603         service = connman_service_lookup_from_network(network);
1604         if (!service)
1605                 return -EINVAL;
1606
1607         err = __connman_ipconfig_address_add(ipconfig);
1608         if (err < 0) {
1609                 connman_network_set_error(network,
1610                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
1611                 return err;
1612         }
1613
1614         return __connman_ipconfig_gateway_add(ipconfig);
1615 }
1616
1617 int __connman_network_clear_ipconfig(struct connman_network *network,
1618                                         struct connman_ipconfig *ipconfig)
1619 {
1620         struct connman_service *service;
1621         struct connman_ipconfig *ipconfig_ipv4;
1622         enum connman_ipconfig_method method;
1623         enum connman_ipconfig_type type;
1624
1625         service = connman_service_lookup_from_network(network);
1626         if (!service)
1627                 return -EINVAL;
1628
1629         ipconfig_ipv4 = __connman_service_get_ip4config(service);
1630         method = __connman_ipconfig_get_method(ipconfig);
1631         type = __connman_ipconfig_get_config_type(ipconfig);
1632
1633         switch (method) {
1634         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1635         case CONNMAN_IPCONFIG_METHOD_OFF:
1636         case CONNMAN_IPCONFIG_METHOD_FIXED:
1637                 return -EINVAL;
1638         case CONNMAN_IPCONFIG_METHOD_AUTO:
1639                 release_dhcpv6(network);
1640                 break;
1641         case CONNMAN_IPCONFIG_METHOD_MANUAL:
1642                 __connman_ipconfig_address_remove(ipconfig);
1643                 break;
1644         case CONNMAN_IPCONFIG_METHOD_DHCP:
1645                 __connman_dhcp_stop(ipconfig_ipv4);
1646                 break;
1647         }
1648
1649         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1650                 __connman_service_ipconfig_indicate_state(service,
1651                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
1652                                         CONNMAN_IPCONFIG_TYPE_IPV6);
1653         else if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1654                 __connman_service_ipconfig_indicate_state(service,
1655                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
1656                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1657
1658         return 0;
1659 }
1660
1661 int __connman_network_set_ipconfig(struct connman_network *network,
1662                                         struct connman_ipconfig *ipconfig_ipv4,
1663                                         struct connman_ipconfig *ipconfig_ipv6)
1664 {
1665         enum connman_ipconfig_method method;
1666         int ret;
1667
1668         if (!network)
1669                 return -EINVAL;
1670
1671         if (ipconfig_ipv6) {
1672                 method = __connman_ipconfig_get_method(ipconfig_ipv6);
1673
1674                 switch (method) {
1675                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1676                 case CONNMAN_IPCONFIG_METHOD_OFF:
1677                         break;
1678                 case CONNMAN_IPCONFIG_METHOD_AUTO:
1679                         autoconf_ipv6_set(network);
1680                         break;
1681                 case CONNMAN_IPCONFIG_METHOD_FIXED:
1682                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
1683                         ret = manual_ipv6_set(network, ipconfig_ipv6);
1684                         if (ret != 0) {
1685                                 connman_network_set_error(network,
1686                                         CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL);
1687                                 return ret;
1688                         }
1689                         break;
1690                 case CONNMAN_IPCONFIG_METHOD_DHCP:
1691                         break;
1692                 }
1693         }
1694
1695         if (ipconfig_ipv4) {
1696                 method = __connman_ipconfig_get_method(ipconfig_ipv4);
1697
1698                 switch (method) {
1699                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1700                 case CONNMAN_IPCONFIG_METHOD_OFF:
1701                 case CONNMAN_IPCONFIG_METHOD_FIXED:
1702                 case CONNMAN_IPCONFIG_METHOD_AUTO:
1703                         return -EINVAL;
1704                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
1705                         return manual_ipv4_set(network, ipconfig_ipv4);
1706                 case CONNMAN_IPCONFIG_METHOD_DHCP:
1707                         return __connman_dhcp_start(ipconfig_ipv4,
1708                                                 network, dhcp_callback, NULL);
1709                 }
1710         }
1711
1712         return 0;
1713 }
1714
1715 int connman_network_set_ipaddress(struct connman_network *network,
1716                                         struct connman_ipaddress *ipaddress)
1717 {
1718         struct connman_service *service;
1719         struct connman_ipconfig *ipconfig = NULL;
1720
1721         DBG("network %p", network);
1722
1723         service = connman_service_lookup_from_network(network);
1724         if (!service)
1725                 return -EINVAL;
1726
1727         ipconfig = __connman_service_get_ipconfig(service, ipaddress->family);
1728         if (!ipconfig)
1729                 return -EINVAL;
1730
1731         __connman_ipconfig_set_local(ipconfig, ipaddress->local);
1732         __connman_ipconfig_set_peer(ipconfig, ipaddress->peer);
1733         __connman_ipconfig_set_broadcast(ipconfig, ipaddress->broadcast);
1734         __connman_ipconfig_set_prefixlen(ipconfig, ipaddress->prefixlen);
1735         __connman_ipconfig_set_gateway(ipconfig, ipaddress->gateway);
1736
1737         return 0;
1738 }
1739
1740 int connman_network_set_nameservers(struct connman_network *network,
1741                                 const char *nameservers)
1742 {
1743         struct connman_service *service;
1744         char **nameservers_array;
1745         int i;
1746
1747         DBG("network %p nameservers %s", network, nameservers);
1748
1749         service = connman_service_lookup_from_network(network);
1750         if (!service)
1751                 return -EINVAL;
1752
1753         __connman_service_nameserver_clear(service);
1754
1755         if (!nameservers)
1756                 return 0;
1757
1758         nameservers_array = g_strsplit(nameservers, " ", 0);
1759
1760         for (i = 0; nameservers_array[i]; i++) {
1761                 __connman_service_nameserver_append(service,
1762                                                 nameservers_array[i], false);
1763         }
1764
1765         g_strfreev(nameservers_array);
1766
1767         return 0;
1768 }
1769
1770 int connman_network_set_domain(struct connman_network *network,
1771                                 const char *domain)
1772 {
1773         struct connman_service *service;
1774
1775         DBG("network %p domain %s", network, domain);
1776
1777         service = connman_service_lookup_from_network(network);
1778         if (!service)
1779                 return -EINVAL;
1780
1781         __connman_service_set_domainname(service, domain);
1782
1783         return 0;
1784 }
1785
1786 /**
1787  * connman_network_set_name:
1788  * @network: network structure
1789  * @name: name value
1790  *
1791  * Set display name value for network
1792  */
1793 int connman_network_set_name(struct connman_network *network,
1794                                                         const char *name)
1795 {
1796         DBG("network %p name %s", network, name);
1797
1798         g_free(network->name);
1799         network->name = g_strdup(name);
1800
1801         return 0;
1802 }
1803
1804 /**
1805  * connman_network_set_strength:
1806  * @network: network structure
1807  * @strength: strength value
1808  *
1809  * Set signal strength value for network
1810  */
1811
1812 int connman_network_set_strength(struct connman_network *network,
1813                                                 uint8_t strength)
1814 {
1815         DBG("network %p strengh %d", network, strength);
1816
1817         network->strength = strength;
1818
1819         return 0;
1820 }
1821
1822 uint8_t connman_network_get_strength(struct connman_network *network)
1823 {
1824         return network->strength;
1825 }
1826
1827 int connman_network_set_frequency(struct connman_network *network,
1828                                                 uint16_t frequency)
1829 {
1830         DBG("network %p frequency %d", network, frequency);
1831
1832         network->frequency = frequency;
1833
1834         return 0;
1835 }
1836
1837 uint16_t connman_network_get_frequency(struct connman_network *network)
1838 {
1839         return network->frequency;
1840 }
1841
1842 int connman_network_set_wifi_channel(struct connman_network *network,
1843                                                 uint16_t channel)
1844 {
1845         DBG("network %p wifi channel %d", network, channel);
1846
1847         network->wifi.channel = channel;
1848
1849         return 0;
1850 }
1851
1852 uint16_t connman_network_get_wifi_channel(struct connman_network *network)
1853 {
1854         return network->wifi.channel;
1855 }
1856
1857 /**
1858  * connman_network_set_string:
1859  * @network: network structure
1860  * @key: unique identifier
1861  * @value: string value
1862  *
1863  * Set string value for specific key
1864  */
1865 int connman_network_set_string(struct connman_network *network,
1866                                         const char *key, const char *value)
1867 {
1868         DBG("network %p key %s value %s", network, key, value);
1869
1870         if (g_strcmp0(key, "Name") == 0)
1871                 return connman_network_set_name(network, value);
1872
1873         if (g_str_equal(key, "Path")) {
1874                 g_free(network->path);
1875                 network->path = g_strdup(value);
1876         } else if (g_str_equal(key, "Node")) {
1877                 g_free(network->node);
1878                 network->node = g_strdup(value);
1879         } else if (g_str_equal(key, "WiFi.Mode")) {
1880                 g_free(network->wifi.mode);
1881                 network->wifi.mode = g_strdup(value);
1882         } else if (g_str_equal(key, "WiFi.Security")) {
1883                 g_free(network->wifi.security);
1884                 network->wifi.security = g_strdup(value);
1885         } else if (g_str_equal(key, "WiFi.Passphrase")) {
1886                 g_free(network->wifi.passphrase);
1887                 network->wifi.passphrase = g_strdup(value);
1888         } else if (g_str_equal(key, "WiFi.EAP")) {
1889                 g_free(network->wifi.eap);
1890                 network->wifi.eap = g_strdup(value);
1891         } else if (g_str_equal(key, "WiFi.Identity")) {
1892                 g_free(network->wifi.identity);
1893                 network->wifi.identity = g_strdup(value);
1894         } else if (g_str_equal(key, "WiFi.AgentIdentity")) {
1895                 g_free(network->wifi.agent_identity);
1896                 network->wifi.agent_identity = g_strdup(value);
1897         } else if (g_str_equal(key, "WiFi.CACertFile")) {
1898                 g_free(network->wifi.ca_cert_path);
1899                 network->wifi.ca_cert_path = g_strdup(value);
1900         } else if (g_str_equal(key, "WiFi.ClientCertFile")) {
1901                 g_free(network->wifi.client_cert_path);
1902                 network->wifi.client_cert_path = g_strdup(value);
1903         } else if (g_str_equal(key, "WiFi.PrivateKeyFile")) {
1904                 g_free(network->wifi.private_key_path);
1905                 network->wifi.private_key_path = g_strdup(value);
1906         } else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase")) {
1907                 g_free(network->wifi.private_key_passphrase);
1908                 network->wifi.private_key_passphrase = g_strdup(value);
1909         } else if (g_str_equal(key, "WiFi.Phase2")) {
1910                 g_free(network->wifi.phase2_auth);
1911                 network->wifi.phase2_auth = g_strdup(value);
1912         } else if (g_str_equal(key, "WiFi.PinWPS")) {
1913                 g_free(network->wifi.pin_wps);
1914                 network->wifi.pin_wps = g_strdup(value);
1915         } else {
1916                 return -EINVAL;
1917         }
1918
1919         return 0;
1920 }
1921
1922 /**
1923  * connman_network_get_string:
1924  * @network: network structure
1925  * @key: unique identifier
1926  *
1927  * Get string value for specific key
1928  */
1929 const char *connman_network_get_string(struct connman_network *network,
1930                                                         const char *key)
1931 {
1932         DBG("network %p key %s", network, key);
1933
1934         if (g_str_equal(key, "Path"))
1935                 return network->path;
1936         else if (g_str_equal(key, "Name"))
1937                 return network->name;
1938         else if (g_str_equal(key, "Node"))
1939                 return network->node;
1940         else if (g_str_equal(key, "WiFi.Mode"))
1941                 return network->wifi.mode;
1942         else if (g_str_equal(key, "WiFi.Security"))
1943                 return network->wifi.security;
1944         else if (g_str_equal(key, "WiFi.Passphrase"))
1945                 return network->wifi.passphrase;
1946         else if (g_str_equal(key, "WiFi.EAP"))
1947                 return network->wifi.eap;
1948         else if (g_str_equal(key, "WiFi.Identity"))
1949                 return network->wifi.identity;
1950         else if (g_str_equal(key, "WiFi.AgentIdentity"))
1951                 return network->wifi.agent_identity;
1952         else if (g_str_equal(key, "WiFi.CACertFile"))
1953                 return network->wifi.ca_cert_path;
1954         else if (g_str_equal(key, "WiFi.ClientCertFile"))
1955                 return network->wifi.client_cert_path;
1956         else if (g_str_equal(key, "WiFi.PrivateKeyFile"))
1957                 return network->wifi.private_key_path;
1958         else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase"))
1959                 return network->wifi.private_key_passphrase;
1960         else if (g_str_equal(key, "WiFi.Phase2"))
1961                 return network->wifi.phase2_auth;
1962         else if (g_str_equal(key, "WiFi.PinWPS"))
1963                 return network->wifi.pin_wps;
1964
1965         return NULL;
1966 }
1967
1968 /**
1969  * connman_network_set_bool:
1970  * @network: network structure
1971  * @key: unique identifier
1972  * @value: boolean value
1973  *
1974  * Set boolean value for specific key
1975  */
1976 int connman_network_set_bool(struct connman_network *network,
1977                                         const char *key, bool value)
1978 {
1979         DBG("network %p key %s value %d", network, key, value);
1980
1981         if (g_strcmp0(key, "Roaming") == 0)
1982                 network->roaming = value;
1983         else if (g_strcmp0(key, "WiFi.WPS") == 0)
1984                 network->wifi.wps = value;
1985         else if (g_strcmp0(key, "WiFi.UseWPS") == 0)
1986                 network->wifi.use_wps = value;
1987
1988         return -EINVAL;
1989 }
1990
1991 /**
1992  * connman_network_get_bool:
1993  * @network: network structure
1994  * @key: unique identifier
1995  *
1996  * Get boolean value for specific key
1997  */
1998 bool connman_network_get_bool(struct connman_network *network,
1999                                                         const char *key)
2000 {
2001         DBG("network %p key %s", network, key);
2002
2003         if (g_str_equal(key, "Roaming"))
2004                 return network->roaming;
2005         else if (g_str_equal(key, "WiFi.WPS"))
2006                 return network->wifi.wps;
2007         else if (g_str_equal(key, "WiFi.UseWPS"))
2008                 return network->wifi.use_wps;
2009
2010         return false;
2011 }
2012
2013 /**
2014  * connman_network_set_blob:
2015  * @network: network structure
2016  * @key: unique identifier
2017  * @data: blob data
2018  * @size: blob size
2019  *
2020  * Set binary blob value for specific key
2021  */
2022 int connman_network_set_blob(struct connman_network *network,
2023                         const char *key, const void *data, unsigned int size)
2024 {
2025         DBG("network %p key %s size %d", network, key, size);
2026
2027         if (g_str_equal(key, "WiFi.SSID")) {
2028                 g_free(network->wifi.ssid);
2029                 network->wifi.ssid = g_try_malloc(size);
2030                 if (network->wifi.ssid) {
2031                         memcpy(network->wifi.ssid, data, size);
2032                         network->wifi.ssid_len = size;
2033                 } else
2034                         network->wifi.ssid_len = 0;
2035         } else {
2036                 return -EINVAL;
2037         }
2038
2039         return 0;
2040 }
2041
2042 /**
2043  * connman_network_get_blob:
2044  * @network: network structure
2045  * @key: unique identifier
2046  * @size: pointer to blob size
2047  *
2048  * Get binary blob value for specific key
2049  */
2050 const void *connman_network_get_blob(struct connman_network *network,
2051                                         const char *key, unsigned int *size)
2052 {
2053         DBG("network %p key %s", network, key);
2054
2055         if (g_str_equal(key, "WiFi.SSID")) {
2056                 if (size)
2057                         *size = network->wifi.ssid_len;
2058                 return network->wifi.ssid;
2059         }
2060
2061         return NULL;
2062 }
2063
2064 void __connman_network_set_device(struct connman_network *network,
2065                                         struct connman_device *device)
2066 {
2067         if (network->device == device)
2068                 return;
2069
2070         if (network->device)
2071                 network_remove(network);
2072
2073         network->device = device;
2074
2075         if (network->device)
2076                 network_probe(network);
2077 }
2078
2079 /**
2080  * connman_network_get_device:
2081  * @network: network structure
2082  *
2083  * Get parent device of network
2084  */
2085 struct connman_device *connman_network_get_device(struct connman_network *network)
2086 {
2087         return network->device;
2088 }
2089
2090 /**
2091  * connman_network_get_data:
2092  * @network: network structure
2093  *
2094  * Get private network data pointer
2095  */
2096 void *connman_network_get_data(struct connman_network *network)
2097 {
2098         return network->driver_data;
2099 }
2100
2101 /**
2102  * connman_network_set_data:
2103  * @network: network structure
2104  * @data: data pointer
2105  *
2106  * Set private network data pointer
2107  */
2108 void connman_network_set_data(struct connman_network *network, void *data)
2109 {
2110         network->driver_data = data;
2111 }
2112
2113 void connman_network_update(struct connman_network *network)
2114 {
2115         switch (network->type) {
2116         case CONNMAN_NETWORK_TYPE_UNKNOWN:
2117         case CONNMAN_NETWORK_TYPE_VENDOR:
2118                 return;
2119         case CONNMAN_NETWORK_TYPE_ETHERNET:
2120         case CONNMAN_NETWORK_TYPE_GADGET:
2121         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
2122         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
2123         case CONNMAN_NETWORK_TYPE_CELLULAR:
2124         case CONNMAN_NETWORK_TYPE_WIFI:
2125                 break;
2126         }
2127
2128         if (network->group)
2129                 __connman_service_update_from_network(network);
2130 }
2131
2132 int __connman_network_init(void)
2133 {
2134         DBG("");
2135
2136         return 0;
2137 }
2138
2139 void __connman_network_cleanup(void)
2140 {
2141         DBG("");
2142 }