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