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