Imported Upstream version 1.37
[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 #include <connman/acd.h>
31 #include "src/shared/arp.h"
32
33 /*
34  * How many times to send RS with the purpose of
35  * refreshing RDNSS entries before they actually expire.
36  * With a value of 1, one RS will be sent, with no retries.
37  */
38 #define RS_REFRESH_COUNT        1
39
40 /*
41  * Value in seconds to wait for RA after RS was sent.
42  * After this time elapsed, we can send another RS.
43  */
44 #define RS_REFRESH_TIMEOUT      3
45
46 /*
47  * As per RFC 4861, a host should transmit up to MAX_RTR_SOLICITATIONS(3)
48  * Router Solicitation messages, each separated by at least
49  * RTR_SOLICITATION_INTERVAL(4) seconds to obtain RA for IPv6 auto-configuration.
50  */
51 #define RTR_SOLICITATION_INTERVAL       4
52
53 #define DHCP_RETRY_TIMEOUT     10
54
55 static GSList *network_list = NULL;
56 static GSList *driver_list = NULL;
57
58 struct connman_network {
59         int refcount;
60         enum connman_network_type type;
61         bool available;
62         bool connected;
63         bool roaming;
64         uint8_t strength;
65         uint16_t frequency;
66         char *identifier;
67         char *name;
68         char *node;
69         char *group;
70         char *path;
71         int index;
72         int router_solicit_count;
73         int router_solicit_refresh_count;
74         struct acd_host *acd_host;
75         guint ipv4ll_timeout;
76         guint dhcp_timeout;
77
78         struct connman_network_driver *driver;
79         void *driver_data;
80
81         bool connecting;
82         bool associating;
83
84         struct connman_device *device;
85
86         struct {
87                 void *ssid;
88                 int ssid_len;
89                 char *mode;
90                 unsigned short channel;
91                 char *security;
92                 char *passphrase;
93                 char *eap;
94                 char *identity;
95                 char *anonymous_identity;
96                 char *agent_identity;
97                 char *ca_cert_path;
98                 char *subject_match;
99                 char *altsubject_match;
100                 char *domain_suffix_match;
101                 char *domain_match;
102                 char *client_cert_path;
103                 char *private_key_path;
104                 char *private_key_passphrase;
105                 char *phase2_auth;
106                 bool wps;
107                 bool wps_advertizing;
108                 bool use_wps;
109                 char *pin_wps;
110 #if defined TIZEN_EXT
111                 char encryption_mode[WIFI_ENCYPTION_MODE_LEN_MAX];
112                 unsigned char bssid[WIFI_BSSID_LEN_MAX];
113                 unsigned int maxrate;
114                 int maxspeed;
115                 bool isHS20AP;
116                 unsigned int keymgmt;
117                 char *keymgmt_type;
118                 bool rsn_mode;
119                 int disconnect_reason;
120                 int assoc_status_code;
121                 GSList *vsie_list;
122                 /*
123                 * Only for EAP-FAST
124                 */
125                 char *phase1;
126                 unsigned char country_code[WIFI_COUNTRY_CODE_LEN];
127                 GSList *bssid_list;
128                 ieee80211_modes_e phy_mode;
129                 connection_mode_e connection_mode;
130 #endif
131         } wifi;
132
133 #if defined TIZEN_EXT
134         /* Multiple APN services and a default APN which a user selected */
135         bool default_internet;
136 #endif
137
138 };
139
140 static const char *type2string(enum connman_network_type type)
141 {
142         switch (type) {
143         case CONNMAN_NETWORK_TYPE_UNKNOWN:
144         case CONNMAN_NETWORK_TYPE_VENDOR:
145                 break;
146         case CONNMAN_NETWORK_TYPE_ETHERNET:
147                 return "ethernet";
148         case CONNMAN_NETWORK_TYPE_GADGET:
149                 return "gadget";
150         case CONNMAN_NETWORK_TYPE_WIFI:
151                 return "wifi";
152         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
153         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
154                 return "bluetooth";
155         case CONNMAN_NETWORK_TYPE_CELLULAR:
156                 return "cellular";
157         }
158
159         return NULL;
160 }
161
162 static bool match_driver(struct connman_network *network,
163                                         struct connman_network_driver *driver)
164 {
165         if (network->type == driver->type ||
166                         driver->type == CONNMAN_NETWORK_TYPE_UNKNOWN)
167                 return true;
168
169         return false;
170 }
171
172 static void set_configuration(struct connman_network *network,
173                         enum connman_ipconfig_type type)
174 {
175         struct connman_service *service;
176
177         DBG("network %p", network);
178
179         if (!network->device)
180                 return;
181
182         __connman_device_set_network(network->device, network);
183
184         service = connman_service_lookup_from_network(network);
185         __connman_service_ipconfig_indicate_state(service,
186                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
187                                         type);
188 }
189
190 void connman_network_append_acddbus(DBusMessageIter *dict,
191                 struct connman_network *network)
192 {
193         if (!network->acd_host)
194                 return;
195
196         acd_host_append_dbus_property(network->acd_host, dict);
197 }
198
199 static int start_acd(struct connman_network *network);
200
201 static void remove_ipv4ll_timeout(struct connman_network *network)
202 {
203         if (network->ipv4ll_timeout > 0) {
204                 g_source_remove(network->ipv4ll_timeout);
205                 network->ipv4ll_timeout = 0;
206         }
207 }
208
209 static void acd_host_ipv4_available(struct acd_host *acd, gpointer user_data)
210 {
211         struct connman_network *network = user_data;
212         struct connman_service *service;
213         struct connman_ipconfig *ipconfig_ipv4;
214         int err;
215
216         if (!network)
217                 return;
218
219         service = connman_service_lookup_from_network(network);
220         if (!service)
221                 return;
222
223         ipconfig_ipv4 = __connman_service_get_ip4config(service);
224         if (!ipconfig_ipv4) {
225                 connman_error("Service has no IPv4 configuration");
226                 return;
227         }
228
229         err = __connman_ipconfig_address_add(ipconfig_ipv4);
230         if (err < 0)
231                 goto err;
232
233 #if defined TIZEN_EXT
234         err = __connman_ipconfig_gateway_add(ipconfig_ipv4, service);
235 #else
236         err = __connman_ipconfig_gateway_add(ipconfig_ipv4);
237 #endif
238         if (err < 0)
239                 goto err;
240
241         __connman_service_save(service);
242
243         return;
244
245 err:
246         connman_network_set_error(__connman_service_get_network(service),
247                                 CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
248 }
249
250 static int start_ipv4ll(struct connman_network *network)
251 {
252         struct connman_service *service;
253         struct connman_ipconfig *ipconfig_ipv4;
254         struct in_addr addr;
255         char *address;
256
257         service = connman_service_lookup_from_network(network);
258         if (!service)
259                 return -EINVAL;
260
261         ipconfig_ipv4 = __connman_service_get_ip4config(service);
262         if (!ipconfig_ipv4) {
263                 connman_error("Service has no IPv4 configuration");
264                 return -EINVAL;
265         }
266
267         /* Apply random IPv4 address. */
268         addr.s_addr = htonl(arp_random_ip());
269         address = inet_ntoa(addr);
270         if (!address) {
271                 connman_error("Could not convert IPv4LL random address %u",
272                                 addr.s_addr);
273                 return -EINVAL;
274         }
275         __connman_ipconfig_set_local(ipconfig_ipv4, address);
276
277         connman_info("Probing IPv4LL address %s", address);
278         return start_acd(network);
279 }
280
281 static gboolean start_ipv4ll_ontimeout(gpointer data)
282 {
283         struct connman_network *network = data;
284
285         if (!network)
286                 return FALSE;
287
288         /* Start IPv4LL ACD. */
289         start_ipv4ll(network);
290
291         return FALSE;
292 }
293
294 static void acd_host_ipv4_lost(struct acd_host *acd, gpointer user_data)
295 {
296         struct connman_network *network = user_data;
297         struct connman_service *service;
298         struct connman_ipconfig *ipconfig_ipv4;
299         enum connman_ipconfig_type type;
300         enum connman_ipconfig_method method;
301
302         if (!network)
303                 return;
304
305         service = connman_service_lookup_from_network(network);
306         if (!service)
307                 return;
308
309         ipconfig_ipv4 = __connman_service_get_ip4config(service);
310         if (!ipconfig_ipv4) {
311                 connman_error("Service has no IPv4 configuration");
312                 return;
313         }
314
315         type = __connman_ipconfig_get_config_type(ipconfig_ipv4);
316         if (type != CONNMAN_IPCONFIG_TYPE_IPV4)
317                 return;
318
319         __connman_ipconfig_address_remove(ipconfig_ipv4);
320
321         method = __connman_ipconfig_get_method(ipconfig_ipv4);
322         if (method == CONNMAN_IPCONFIG_METHOD_DHCP) {
323                 /*
324                  * We have one more chance for DHCP. If this fails
325                  * acd_host_ipv4_conflict will be called.
326                  */
327                 network = __connman_service_get_network(service);
328                 if (network)
329                         __connman_network_enable_ipconfig(network, ipconfig_ipv4);
330         } else {
331                 /* Start IPv4LL ACD. */
332                 start_ipv4ll(network);
333         }
334 }
335
336 static void acd_host_ipv4_conflict(struct acd_host *acd, gpointer user_data)
337 {
338         struct connman_network *network = user_data;
339         struct connman_service *service;
340         struct connman_ipconfig *ipconfig_ipv4;
341         enum connman_ipconfig_method method;
342
343         service = connman_service_lookup_from_network(network);
344         if (!service)
345                 return;
346
347         ipconfig_ipv4 = __connman_service_get_ip4config(service);
348         if (!ipconfig_ipv4) {
349                 connman_error("Service has no IPv4 configuration");
350                 return;
351         }
352
353         method = __connman_ipconfig_get_method(ipconfig_ipv4);
354         connman_info("%s conflict counts=%u", __FUNCTION__,
355                         acd_host_get_conflicts_count(acd));
356
357         if (method == CONNMAN_IPCONFIG_METHOD_DHCP &&
358                         acd_host_get_conflicts_count(acd) < 2) {
359                 connman_info("%s Sending DHCP decline", __FUNCTION__);
360                 __connman_dhcp_decline(ipconfig_ipv4);
361
362                 connman_network_set_connected_dhcp_later(network, DHCP_RETRY_TIMEOUT);
363                 __connman_ipconfig_set_local(ipconfig_ipv4, NULL);
364         } else {
365                 if (method == CONNMAN_IPCONFIG_METHOD_DHCP) {
366                         __connman_ipconfig_set_method(ipconfig_ipv4,
367                                         CONNMAN_IPCONFIG_METHOD_AUTO);
368                         __connman_dhcp_decline(ipconfig_ipv4);
369                 }
370                 /* Start IPv4LL ACD. */
371                 start_ipv4ll(network);
372         }
373 }
374
375 static void acd_host_ipv4_maxconflict(struct acd_host *acd, gpointer user_data)
376 {
377         struct connman_network *network = user_data;
378
379         remove_ipv4ll_timeout(network);
380         connman_info("Had maximum number of conflicts. Next IPv4LL address will be "
381                         "tried in %d seconds", RATE_LIMIT_INTERVAL);
382         /* Wait, then start IPv4LL ACD. */
383         network->ipv4ll_timeout =
384                 g_timeout_add_seconds_full(G_PRIORITY_HIGH,
385                                 RATE_LIMIT_INTERVAL,
386                                 start_ipv4ll_ontimeout,
387                                 network,
388                                 NULL);
389 }
390
391 static int start_acd(struct connman_network *network)
392 {
393         struct connman_service *service;
394         struct connman_ipconfig *ipconfig_ipv4;
395         const char* address;
396         struct in_addr addr;
397
398         remove_ipv4ll_timeout(network);
399
400         service = connman_service_lookup_from_network(network);
401         if (!service)
402                 return -EINVAL;
403
404         ipconfig_ipv4 = __connman_service_get_ip4config(service);
405         if (!ipconfig_ipv4) {
406                 connman_error("Service has no IPv4 configuration");
407                 return -EINVAL;
408         }
409
410         if (!network->acd_host) {
411                 int index;
412
413                 index = __connman_ipconfig_get_index(ipconfig_ipv4);
414                 network->acd_host = acd_host_new(index,
415                                 connman_service_get_dbuspath(service));
416                 if (!network->acd_host) {
417                         connman_error("Could not create ACD data structure");
418                         return -EINVAL;
419                 }
420
421                 acd_host_register_event(network->acd_host,
422                                 ACD_HOST_EVENT_IPV4_AVAILABLE,
423                                 acd_host_ipv4_available, network);
424                 acd_host_register_event(network->acd_host,
425                                 ACD_HOST_EVENT_IPV4_LOST,
426                                 acd_host_ipv4_lost, network);
427                 acd_host_register_event(network->acd_host,
428                                 ACD_HOST_EVENT_IPV4_CONFLICT,
429                                 acd_host_ipv4_conflict, network);
430                 acd_host_register_event(network->acd_host,
431                                 ACD_HOST_EVENT_IPV4_MAXCONFLICT,
432                                 acd_host_ipv4_maxconflict, network);
433         }
434
435         address = __connman_ipconfig_get_local(ipconfig_ipv4);
436         if (!address)
437                 return -EINVAL;
438
439         connman_info("Starting ACD for address %s", address);
440         if (inet_pton(AF_INET, address, &addr) != 1)
441                 connman_error("Could not convert address %s", address);
442
443         acd_host_start(network->acd_host, htonl(addr.s_addr));
444
445         return 0;
446 }
447
448 static void dhcp_success(struct connman_network *network)
449 {
450         struct connman_service *service;
451         struct connman_ipconfig *ipconfig_ipv4;
452         int err;
453
454         service = connman_service_lookup_from_network(network);
455         if (!service)
456                 goto err;
457
458         ipconfig_ipv4 = __connman_service_get_ip4config(service);
459
460         DBG("lease acquired for ipconfig %p", ipconfig_ipv4);
461
462         if (!ipconfig_ipv4)
463                 return;
464
465         if (connman_setting_get_bool("AddressConflictDetection")) {
466                 err = start_acd(network);
467                 if (!err)
468                         return;
469
470                 /* On error proceed without ACD. */
471         }
472
473         err = __connman_ipconfig_address_add(ipconfig_ipv4);
474         if (err < 0)
475                 goto err;
476
477 #if defined TIZEN_EXT
478         err = __connman_ipconfig_gateway_add(ipconfig_ipv4, service);
479 #else
480         err = __connman_ipconfig_gateway_add(ipconfig_ipv4);
481 #endif
482         if (err < 0)
483                 goto err;
484
485         __connman_service_save(service);
486
487         return;
488
489 err:
490         connman_network_set_error(network,
491                                 CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
492 }
493
494 static void dhcp_failure(struct connman_network *network)
495 {
496         struct connman_service *service;
497         struct connman_ipconfig *ipconfig_ipv4;
498
499         service = connman_service_lookup_from_network(network);
500         if (!service)
501                 return;
502
503         ipconfig_ipv4 = __connman_service_get_ip4config(service);
504
505         DBG("lease lost for ipconfig %p", ipconfig_ipv4);
506
507         if (!ipconfig_ipv4)
508                 return;
509
510         __connman_ipconfig_address_remove(ipconfig_ipv4);
511         __connman_ipconfig_gateway_remove(ipconfig_ipv4);
512 }
513
514 static void dhcp_callback(struct connman_ipconfig *ipconfig,
515                         struct connman_network *network,
516                         bool success, gpointer data)
517 {
518         network->connecting = false;
519
520         if (success)
521                 dhcp_success(network);
522         else
523                 dhcp_failure(network);
524 }
525
526 static int set_connected_manual(struct connman_network *network)
527 {
528         int err = 0;
529         struct connman_service *service;
530         struct connman_ipconfig *ipconfig;
531
532         DBG("network %p", network);
533
534         network->connecting = false;
535
536         service = connman_service_lookup_from_network(network);
537         ipconfig = __connman_service_get_ip4config(service);
538         __connman_ipconfig_enable(ipconfig);
539
540         if (!__connman_ipconfig_get_local(ipconfig))
541                 __connman_service_read_ip4config(service);
542
543         if (connman_setting_get_bool("AddressConflictDetection")) {
544                 err = start_acd(network);
545                 if (!err)
546                         return 0;
547
548                 /* On error proceed without ACD. */
549         }
550
551         err = __connman_ipconfig_address_add(ipconfig);
552         if (err < 0)
553                 goto err;
554
555 #if defined TIZEN_EXT
556         err = __connman_ipconfig_gateway_add(ipconfig, service);
557 #else
558         err = __connman_ipconfig_gateway_add(ipconfig);
559 #endif
560         if (err < 0)
561                 goto err;
562
563 err:
564         return err;
565 }
566
567 static void remove_dhcp_timeout(struct connman_network *network)
568 {
569         if (network->dhcp_timeout > 0) {
570                 g_source_remove(network->dhcp_timeout);
571                 network->dhcp_timeout = 0;
572         }
573 }
574
575 static int set_connected_dhcp(struct connman_network *network)
576 {
577         struct connman_service *service;
578         struct connman_ipconfig *ipconfig_ipv4;
579         int err;
580
581         DBG("network %p", network);
582         remove_dhcp_timeout(network);
583
584         service = connman_service_lookup_from_network(network);
585         ipconfig_ipv4 = __connman_service_get_ip4config(service);
586         __connman_ipconfig_enable(ipconfig_ipv4);
587
588         err = __connman_dhcp_start(ipconfig_ipv4, network,
589                                                         dhcp_callback, NULL);
590         if (err < 0) {
591                 connman_error("Can not request DHCP lease");
592                 return err;
593         }
594
595         return 0;
596 }
597
598 static gboolean set_connected_dhcp_timout(gpointer data)
599 {
600         struct connman_network *network = data;
601         struct connman_service *service;
602         struct connman_ipconfig *ipconfig;
603         enum connman_ipconfig_method method;
604
605         network->dhcp_timeout = 0;
606
607         service = connman_service_lookup_from_network(network);
608         if (!service)
609                 return FALSE;
610
611         ipconfig = __connman_service_get_ip4config(service);
612         if (!ipconfig)
613                 return FALSE;
614
615         /* Method is still DHCP? */
616         method = __connman_ipconfig_get_method(ipconfig);
617         if (method == CONNMAN_IPCONFIG_METHOD_DHCP)
618                 set_connected_dhcp(network);
619
620         return FALSE;
621 }
622
623 void connman_network_set_connected_dhcp_later(struct connman_network *network,
624                 uint32_t sec)
625 {
626         remove_dhcp_timeout(network);
627
628         network->dhcp_timeout =
629                 g_timeout_add_seconds_full(G_PRIORITY_HIGH,
630                                 sec,
631                                 set_connected_dhcp_timout,
632                                 network,
633                                 NULL);
634 }
635
636 static int manual_ipv6_set(struct connman_network *network,
637                                 struct connman_ipconfig *ipconfig_ipv6)
638 {
639         struct connman_service *service;
640         int err;
641
642         DBG("network %p ipv6 %p", network, ipconfig_ipv6);
643
644         service = connman_service_lookup_from_network(network);
645         if (!service)
646                 return -EINVAL;
647
648         if (!__connman_ipconfig_get_local(ipconfig_ipv6))
649                 __connman_service_read_ip6config(service);
650
651         __connman_ipconfig_enable_ipv6(ipconfig_ipv6);
652
653         err = __connman_ipconfig_address_add(ipconfig_ipv6);
654         if (err < 0) {
655                 connman_network_set_error(network,
656                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
657                 return err;
658         }
659
660 #if defined TIZEN_EXT
661         err = __connman_ipconfig_gateway_add(ipconfig_ipv6, service);
662 #else
663         err = __connman_ipconfig_gateway_add(ipconfig_ipv6);
664 #endif
665         if (err < 0)
666                 return err;
667
668         __connman_device_set_network(network->device, network);
669
670         connman_network_set_associating(network, false);
671
672         network->connecting = false;
673
674         return 0;
675 }
676
677 static void stop_dhcpv6(struct connman_network *network)
678 {
679         network->connecting = false;
680
681         __connman_dhcpv6_stop(network);
682 }
683
684 static void dhcpv6_release_callback(struct connman_network *network,
685                                 enum __connman_dhcpv6_status status,
686                                 gpointer data)
687 {
688         DBG("status %d", status);
689
690         stop_dhcpv6(network);
691 }
692
693 static void release_dhcpv6(struct connman_network *network)
694 {
695         __connman_dhcpv6_start_release(network, dhcpv6_release_callback);
696         stop_dhcpv6(network);
697 }
698
699 static void dhcpv6_info_callback(struct connman_network *network,
700                                 enum __connman_dhcpv6_status status,
701                                 gpointer data)
702 {
703         DBG("status %d", status);
704
705         stop_dhcpv6(network);
706 }
707
708 static int dhcpv6_set_addresses(struct connman_network *network)
709 {
710         struct connman_service *service;
711         struct connman_ipconfig *ipconfig_ipv6;
712         int err = -EINVAL;
713
714         service = connman_service_lookup_from_network(network);
715         if (!service)
716                 goto err;
717
718         network->connecting = false;
719
720         ipconfig_ipv6 = __connman_service_get_ip6config(service);
721         err = __connman_ipconfig_address_add(ipconfig_ipv6);
722         if (err < 0)
723                 goto err;
724
725         return 0;
726
727 err:
728         connman_network_set_error(network,
729                                 CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
730         return err;
731 }
732
733 static void autoconf_ipv6_set(struct connman_network *network);
734 static void dhcpv6_callback(struct connman_network *network,
735                         enum __connman_dhcpv6_status status, gpointer data);
736
737 /*
738  * Have a separate callback for renew so that we do not do autoconf
739  * in wrong phase as the dhcpv6_callback() is also called when doing
740  * DHCPv6 solicitation.
741  */
742 static void dhcpv6_renew_callback(struct connman_network *network,
743                                 enum __connman_dhcpv6_status status,
744                                 gpointer data)
745 {
746         switch (status) {
747         case CONNMAN_DHCPV6_STATUS_SUCCEED:
748                 dhcpv6_callback(network, status, data);
749                 break;
750         case CONNMAN_DHCPV6_STATUS_FAIL:
751         case CONNMAN_DHCPV6_STATUS_RESTART:
752                 stop_dhcpv6(network);
753
754                 /* restart and do solicit again. */
755                 autoconf_ipv6_set(network);
756                 break;
757         }
758 }
759
760 static void dhcpv6_callback(struct connman_network *network,
761                         enum __connman_dhcpv6_status status, gpointer data)
762 {
763         DBG("status %d", status);
764
765         /* Start the renew process if necessary */
766         if (status == CONNMAN_DHCPV6_STATUS_SUCCEED) {
767
768                 if (dhcpv6_set_addresses(network) < 0) {
769                         stop_dhcpv6(network);
770                         return;
771                 }
772
773                 if (__connman_dhcpv6_start_renew(network,
774                                         dhcpv6_renew_callback) == -ETIMEDOUT)
775                         dhcpv6_renew_callback(network,
776                                                 CONNMAN_DHCPV6_STATUS_FAIL,
777                                                 data);
778
779         } else if (status == CONNMAN_DHCPV6_STATUS_RESTART) {
780                 stop_dhcpv6(network);
781                 autoconf_ipv6_set(network);
782         } else
783                 stop_dhcpv6(network);
784 }
785
786 static void check_dhcpv6(struct nd_router_advert *reply,
787                         unsigned int length, void *user_data)
788 {
789         struct connman_network *network = user_data;
790         struct connman_service *service;
791         GSList *prefixes;
792
793         DBG("reply %p", reply);
794
795         if (!reply) {
796                 /*
797                  * Router solicitation message seem to get lost easily so
798                  * try to send it again.
799                  */
800                 if (network->router_solicit_count > 0) {
801                         DBG("re-send router solicitation %d",
802                                                 network->router_solicit_count);
803                         network->router_solicit_count--;
804                         __connman_inet_ipv6_send_rs(network->index, RTR_SOLICITATION_INTERVAL,
805                                                 check_dhcpv6, network);
806                         return;
807                 }
808 #if defined TIZEN_EXT
809                 DBG("RA message is not received from server in reply of RS.");
810 #endif
811                 connman_network_unref(network);
812                 return;
813         }
814
815         network->router_solicit_count = 0;
816
817         /*
818          * If we were disconnected while waiting router advertisement,
819          * we just quit and do not start DHCPv6
820          */
821         if (!network->connected) {
822                 connman_network_unref(network);
823 #if defined TIZEN_EXT
824                 DBG("Network is not connected");
825 #endif
826                 return;
827         }
828
829         prefixes = __connman_inet_ipv6_get_prefixes(reply, length);
830
831         /*
832          * If IPv6 config is missing from service, then create it.
833          * The ipconfig might be missing if we got a rtnl message
834          * that disabled IPv6 config and thus removed it. This
835          * can happen if we are switching from one service to
836          * another in the same interface. The only way to get IPv6
837          * config back is to re-create it here.
838          */
839         service = connman_service_lookup_from_network(network);
840         if (service) {
841                 connman_service_create_ip6config(service, network->index);
842
843                 connman_network_set_associating(network, false);
844
845                 __connman_service_ipconfig_indicate_state(service,
846                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
847                                         CONNMAN_IPCONFIG_TYPE_IPV6);
848         }
849
850         /*
851          * We do stateful/stateless DHCPv6 if router advertisement says so.
852          */
853         if (reply->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) {
854 #if defined TIZEN_EXT
855                 DBG("IPv6 ND_RA_FLAG_MANAGED");
856 #endif
857                 __connman_dhcpv6_start(network, prefixes, dhcpv6_callback);
858         } else {
859                 if (reply->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
860 #if defined TIZEN_EXT
861                 {
862                         DBG("IPv6 ND_RA_FLAG_OTHER");
863 #endif
864                         __connman_dhcpv6_start_info(network,
865                                                         dhcpv6_info_callback);
866 #if defined TIZEN_EXT
867                 }
868 #endif
869
870                 g_slist_free_full(prefixes, g_free);
871                 network->connecting = false;
872         }
873
874         connman_network_unref(network);
875 }
876
877 static void receive_refresh_rs_reply(struct nd_router_advert *reply,
878                 unsigned int length, void *user_data)
879 {
880         struct connman_network *network = user_data;
881
882         DBG("reply %p", reply);
883
884         if (!reply) {
885                 /*
886                  * Router solicitation message seem to get lost easily so
887                  * try to send it again.
888                  */
889                 if (network->router_solicit_refresh_count > 1) {
890                         network->router_solicit_refresh_count--;
891                         DBG("re-send router solicitation %d",
892                                         network->router_solicit_refresh_count);
893                         __connman_inet_ipv6_send_rs(network->index,
894                                         RS_REFRESH_TIMEOUT,
895                                         receive_refresh_rs_reply,
896                                         network);
897                         return;
898                 }
899         }
900
901         /* RS refresh not in progress anymore */
902         network->router_solicit_refresh_count = 0;
903
904         connman_network_unref(network);
905 }
906
907 int __connman_network_refresh_rs_ipv6(struct connman_network *network,
908                                         int index)
909 {
910         int ret = 0;
911
912         DBG("network %p index %d", network, index);
913
914         /* Send only one RS for all RDNSS entries which are about to expire */
915         if (network->router_solicit_refresh_count > 0) {
916                 DBG("RS refresh already started");
917                 return 0;
918         }
919
920         network->router_solicit_refresh_count = RS_REFRESH_COUNT;
921
922         connman_network_ref(network);
923
924         ret = __connman_inet_ipv6_send_rs(index, RS_REFRESH_TIMEOUT,
925                         receive_refresh_rs_reply, network);
926         return ret;
927 }
928
929 static void autoconf_ipv6_set(struct connman_network *network)
930 {
931         struct connman_service *service;
932         struct connman_ipconfig *ipconfig;
933         int index;
934
935         DBG("network %p", network);
936
937         if (network->router_solicit_count > 0) {
938                 /*
939                  * The autoconfiguration is already pending and we have sent
940                  * router solicitation messages and are now waiting answers.
941                  * There is no need to continue any further.
942                  */
943                 DBG("autoconfiguration already started");
944                 return;
945         }
946
947         __connman_device_set_network(network->device, network);
948
949 #if defined TIZEN_EXT
950         if(network->type == CONNMAN_NETWORK_TYPE_CELLULAR)
951                 return;
952 #endif
953
954         service = connman_service_lookup_from_network(network);
955         if (!service)
956                 return;
957
958         ipconfig = __connman_service_get_ip6config(service);
959         if (!ipconfig)
960                 return;
961
962         __connman_ipconfig_enable(ipconfig);
963
964         __connman_ipconfig_enable_ipv6(ipconfig);
965
966         __connman_ipconfig_address_remove(ipconfig);
967
968         index = __connman_ipconfig_get_index(ipconfig);
969
970         connman_network_ref(network);
971
972         /* Try to get stateless DHCPv6 information, RFC 3736 */
973         network->router_solicit_count = 3;
974         __connman_inet_ipv6_send_rs(index, RTR_SOLICITATION_INTERVAL,
975                         check_dhcpv6, network);
976 }
977
978 static void set_connected(struct connman_network *network)
979 {
980         struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
981         struct connman_service *service;
982
983         if (network->connected)
984                 return;
985
986         connman_network_set_associating(network, false);
987
988         network->connected = true;
989
990         service = connman_service_lookup_from_network(network);
991
992         ipconfig_ipv4 = __connman_service_get_ip4config(service);
993         ipconfig_ipv6 = __connman_service_get_ip6config(service);
994
995         DBG("service %p ipv4 %p ipv6 %p", service, ipconfig_ipv4,
996                 ipconfig_ipv6);
997
998         __connman_network_enable_ipconfig(network, ipconfig_ipv4);
999         __connman_network_enable_ipconfig(network, ipconfig_ipv6);
1000 }
1001
1002 static void set_disconnected(struct connman_network *network)
1003 {
1004         struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
1005         enum connman_ipconfig_method ipv4_method, ipv6_method;
1006         enum connman_service_state state;
1007         struct connman_service *service;
1008
1009         service = connman_service_lookup_from_network(network);
1010
1011         ipconfig_ipv4 = __connman_service_get_ip4config(service);
1012         ipconfig_ipv6 = __connman_service_get_ip6config(service);
1013
1014         DBG("service %p ipv4 %p ipv6 %p", service, ipconfig_ipv4,
1015                 ipconfig_ipv6);
1016
1017         ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4);
1018         ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6);
1019
1020         DBG("method ipv4 %d ipv6 %d", ipv4_method, ipv6_method);
1021
1022         /*
1023          * Resetting solicit count here will prevent the RS resend loop
1024          * from sending packets in check_dhcpv6()
1025          */
1026         network->router_solicit_count = 0;
1027
1028         __connman_device_set_network(network->device, NULL);
1029
1030         if (network->connected) {
1031                 switch (ipv6_method) {
1032                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1033                 case CONNMAN_IPCONFIG_METHOD_OFF:
1034                 case CONNMAN_IPCONFIG_METHOD_FIXED:
1035                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
1036                         break;
1037                 case CONNMAN_IPCONFIG_METHOD_DHCP:
1038                 case CONNMAN_IPCONFIG_METHOD_AUTO:
1039                         release_dhcpv6(network);
1040                         break;
1041                 }
1042
1043                 switch (ipv4_method) {
1044                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
1045                 case CONNMAN_IPCONFIG_METHOD_OFF:
1046                 case CONNMAN_IPCONFIG_METHOD_FIXED:
1047                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
1048                         break;
1049                 case CONNMAN_IPCONFIG_METHOD_AUTO:
1050                         /*
1051                          * If the current method is AUTO then next time we
1052                          * try first DHCP. DHCP also needs to be stopped
1053                          * in this case because if we fell in AUTO means
1054                          * that DHCP  was launched for IPv4 but it failed.
1055                          */
1056                         __connman_ipconfig_set_method(ipconfig_ipv4,
1057                                                 CONNMAN_IPCONFIG_METHOD_DHCP);
1058                         __connman_service_notify_ipv4_configuration(service);
1059                         /* fall through */
1060                 case CONNMAN_IPCONFIG_METHOD_DHCP:
1061                         remove_dhcp_timeout(network);
1062                         __connman_dhcp_stop(ipconfig_ipv4);
1063                         break;
1064                 }
1065         }
1066
1067         /*
1068          * We only set the disconnect state if we were not in idle
1069          * or in failure. It does not make sense to go to disconnect
1070          * state if we were not connected.
1071          */
1072         state = __connman_service_ipconfig_get_state(service,
1073                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
1074         if (state != CONNMAN_SERVICE_STATE_IDLE &&
1075                         state != CONNMAN_SERVICE_STATE_FAILURE)
1076                 __connman_service_ipconfig_indicate_state(service,
1077                                         CONNMAN_SERVICE_STATE_DISCONNECT,
1078                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1079
1080         state = __connman_service_ipconfig_get_state(service,
1081                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
1082         if (state != CONNMAN_SERVICE_STATE_IDLE &&
1083                                 state != CONNMAN_SERVICE_STATE_FAILURE)
1084                 __connman_service_ipconfig_indicate_state(service,
1085                                         CONNMAN_SERVICE_STATE_DISCONNECT,
1086                                         CONNMAN_IPCONFIG_TYPE_IPV6);
1087
1088         if (network->connected) {
1089 #if defined TIZEN_EXT
1090                 /**
1091                  * Do not remove gateway and its address,
1092                  * if there are connected profiles that use same interface (multiple PDN)
1093                  */
1094                 if (connman_service_get_type(service) != CONNMAN_SERVICE_TYPE_CELLULAR ||
1095                                 __connman_service_get_connected_count_of_iface(service) <= 0) {
1096 #endif
1097                 __connman_connection_gateway_remove(service,
1098                                                 CONNMAN_IPCONFIG_TYPE_ALL);
1099
1100                 __connman_ipconfig_address_unset(ipconfig_ipv4);
1101                 __connman_ipconfig_address_unset(ipconfig_ipv6);
1102
1103 #if defined TIZEN_EXT
1104                 }
1105 #endif
1106                 /*
1107                  * Special handling for IPv6 autoconfigured address.
1108                  * The simplest way to remove autoconfigured routes is to
1109                  * disable IPv6 temporarily so that kernel will do the cleanup
1110                  * automagically.
1111                  */
1112                 if (ipv6_method == CONNMAN_IPCONFIG_METHOD_AUTO) {
1113                         __connman_ipconfig_disable_ipv6(ipconfig_ipv6);
1114                         __connman_ipconfig_enable_ipv6(ipconfig_ipv6);
1115                 }
1116         }
1117
1118         __connman_service_ipconfig_indicate_state(service,
1119                                                 CONNMAN_SERVICE_STATE_IDLE,
1120                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
1121
1122         __connman_service_ipconfig_indicate_state(service,
1123                                                 CONNMAN_SERVICE_STATE_IDLE,
1124                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
1125
1126         network->connecting = false;
1127         network->connected = false;
1128
1129         connman_network_set_associating(network, false);
1130 }
1131
1132
1133
1134 static int network_probe(struct connman_network *network)
1135 {
1136         GSList *list;
1137         struct connman_network_driver *driver = NULL;
1138
1139         DBG("network %p name %s", network, network->name);
1140
1141         if (network->driver)
1142                 return -EALREADY;
1143
1144         for (list = driver_list; list; list = list->next) {
1145                 driver = list->data;
1146
1147                 if (!match_driver(network, driver)) {
1148                         driver = NULL;
1149                         continue;
1150                 }
1151
1152                 DBG("driver %p name %s", driver, driver->name);
1153
1154                 if (driver->probe(network) == 0)
1155                         break;
1156
1157                 driver = NULL;
1158         }
1159
1160         if (!driver)
1161                 return -ENODEV;
1162
1163         if (!network->group)
1164                 return -EINVAL;
1165
1166         switch (network->type) {
1167         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1168         case CONNMAN_NETWORK_TYPE_VENDOR:
1169                 return 0;
1170         case CONNMAN_NETWORK_TYPE_ETHERNET:
1171         case CONNMAN_NETWORK_TYPE_GADGET:
1172         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1173         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1174         case CONNMAN_NETWORK_TYPE_CELLULAR:
1175         case CONNMAN_NETWORK_TYPE_WIFI:
1176                 network->driver = driver;
1177                 if (!__connman_service_create_from_network(network)) {
1178                         network->driver = NULL;
1179                         return -EINVAL;
1180                 }
1181         }
1182
1183         return 0;
1184 }
1185
1186 static void network_remove(struct connman_network *network)
1187 {
1188         DBG("network %p name %s", network, network->name);
1189
1190         if (!network->driver)
1191                 return;
1192
1193         if (network->connected)
1194                 set_disconnected(network);
1195
1196         switch (network->type) {
1197         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1198         case CONNMAN_NETWORK_TYPE_VENDOR:
1199                 break;
1200         case CONNMAN_NETWORK_TYPE_ETHERNET:
1201         case CONNMAN_NETWORK_TYPE_GADGET:
1202         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1203         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1204         case CONNMAN_NETWORK_TYPE_CELLULAR:
1205         case CONNMAN_NETWORK_TYPE_WIFI:
1206                 if (network->group) {
1207                         __connman_service_remove_from_network(network);
1208
1209                         g_free(network->group);
1210                         network->group = NULL;
1211                 }
1212                 break;
1213         }
1214
1215         if (network->driver->remove)
1216                 network->driver->remove(network);
1217
1218         network->driver = NULL;
1219 }
1220
1221 static void probe_driver(struct connman_network_driver *driver)
1222 {
1223         GSList *list;
1224
1225         DBG("driver %p name %s", driver, driver->name);
1226
1227         for (list = network_list; list; list = list->next) {
1228                 struct connman_network *network = list->data;
1229
1230                 if (network->driver)
1231                         continue;
1232
1233                 if (driver->type != network->type)
1234                         continue;
1235
1236                 if (driver->probe(network) < 0)
1237                         continue;
1238
1239                 network->driver = driver;
1240         }
1241 }
1242
1243 static gint compare_priority(gconstpointer a, gconstpointer b)
1244 {
1245         const struct connman_network_driver *driver1 = a;
1246         const struct connman_network_driver *driver2 = b;
1247
1248         return driver2->priority - driver1->priority;
1249 }
1250
1251 /**
1252  * connman_network_driver_register:
1253  * @driver: network driver definition
1254  *
1255  * Register a new network driver
1256  *
1257  * Returns: %0 on success
1258  */
1259 int connman_network_driver_register(struct connman_network_driver *driver)
1260 {
1261         DBG("driver %p name %s", driver, driver->name);
1262
1263         driver_list = g_slist_insert_sorted(driver_list, driver,
1264                                                         compare_priority);
1265
1266         probe_driver(driver);
1267
1268         return 0;
1269 }
1270
1271 /**
1272  * connman_network_driver_unregister:
1273  * @driver: network driver definition
1274  *
1275  * Remove a previously registered network driver
1276  */
1277 void connman_network_driver_unregister(struct connman_network_driver *driver)
1278 {
1279         GSList *list;
1280
1281         DBG("driver %p name %s", driver, driver->name);
1282
1283         driver_list = g_slist_remove(driver_list, driver);
1284
1285         for (list = network_list; list; list = list->next) {
1286                 struct connman_network *network = list->data;
1287
1288                 if (network->driver == driver)
1289                         network_remove(network);
1290         }
1291 }
1292
1293 static void network_destruct(struct connman_network *network)
1294 {
1295         DBG("network %p name %s", network, network->name);
1296
1297         g_free(network->wifi.ssid);
1298         g_free(network->wifi.mode);
1299         g_free(network->wifi.security);
1300         g_free(network->wifi.passphrase);
1301         g_free(network->wifi.eap);
1302         g_free(network->wifi.identity);
1303         g_free(network->wifi.anonymous_identity);
1304         g_free(network->wifi.agent_identity);
1305         g_free(network->wifi.ca_cert_path);
1306         g_free(network->wifi.subject_match);
1307         g_free(network->wifi.altsubject_match);
1308         g_free(network->wifi.domain_suffix_match);
1309         g_free(network->wifi.domain_match);
1310         g_free(network->wifi.client_cert_path);
1311         g_free(network->wifi.private_key_path);
1312         g_free(network->wifi.private_key_passphrase);
1313         g_free(network->wifi.phase2_auth);
1314         g_free(network->wifi.pin_wps);
1315
1316 #if defined TIZEN_EXT
1317         g_slist_free_full(network->wifi.vsie_list, g_free);
1318         g_slist_free_full(network->wifi.bssid_list, g_free);
1319 #endif
1320         g_free(network->path);
1321         g_free(network->group);
1322         g_free(network->node);
1323         g_free(network->name);
1324         g_free(network->identifier);
1325         acd_host_free(network->acd_host);
1326
1327         network->device = NULL;
1328
1329         g_free(network);
1330 }
1331
1332 /**
1333  * connman_network_create:
1334  * @identifier: network identifier (for example an unqiue name)
1335  *
1336  * Allocate a new network and assign the #identifier to it.
1337  *
1338  * Returns: a newly-allocated #connman_network structure
1339  */
1340 struct connman_network *connman_network_create(const char *identifier,
1341                                                 enum connman_network_type type)
1342 {
1343         struct connman_network *network;
1344         char *ident;
1345
1346         network = g_try_new0(struct connman_network, 1);
1347         if (!network)
1348                 return NULL;
1349
1350         network->refcount = 1;
1351
1352         ident = g_strdup(identifier);
1353
1354         if (!ident) {
1355                 g_free(network);
1356                 return NULL;
1357         }
1358
1359         network->type       = type;
1360         network->identifier = ident;
1361         network->acd_host = NULL;
1362         network->ipv4ll_timeout = 0;
1363
1364         network_list = g_slist_prepend(network_list, network);
1365
1366         network->dhcp_timeout = 0;
1367
1368         DBG("network %p identifier %s type %s", network, identifier,
1369                 type2string(type));
1370         return network;
1371 }
1372
1373 /**
1374  * connman_network_ref:
1375  * @network: network structure
1376  *
1377  * Increase reference counter of  network
1378  */
1379 struct connman_network *
1380 connman_network_ref_debug(struct connman_network *network,
1381                         const char *file, int line, const char *caller)
1382 {
1383         DBG("%p name %s ref %d by %s:%d:%s()", network, network->name,
1384                 network->refcount + 1, file, line, caller);
1385
1386         __sync_fetch_and_add(&network->refcount, 1);
1387
1388         return network;
1389 }
1390
1391 /**
1392  * connman_network_unref:
1393  * @network: network structure
1394  *
1395  * Decrease reference counter of network
1396  */
1397 void connman_network_unref_debug(struct connman_network *network,
1398                                 const char *file, int line, const char *caller)
1399 {
1400         DBG("%p name %s ref %d by %s:%d:%s()", network, network->name,
1401                 network->refcount - 1, file, line, caller);
1402
1403         if (__sync_fetch_and_sub(&network->refcount, 1) != 1)
1404                 return;
1405
1406         network_list = g_slist_remove(network_list, network);
1407
1408         network_destruct(network);
1409 }
1410
1411 const char *__connman_network_get_type(struct connman_network *network)
1412 {
1413         return type2string(network->type);
1414 }
1415
1416 /**
1417  * connman_network_get_type:
1418  * @network: network structure
1419  *
1420  * Get type of network
1421  */
1422 enum connman_network_type connman_network_get_type(
1423                                 struct connman_network *network)
1424 {
1425         return network->type;
1426 }
1427
1428 /**
1429  * connman_network_get_identifier:
1430  * @network: network structure
1431  *
1432  * Get identifier of network
1433  */
1434 const char *connman_network_get_identifier(struct connman_network *network)
1435 {
1436         return network->identifier;
1437 }
1438
1439 /**
1440  * connman_network_set_index:
1441  * @network: network structure
1442  * @index: index number
1443  *
1444  * Set index number of network
1445  */
1446 void connman_network_set_index(struct connman_network *network, int index)
1447 {
1448         struct connman_service *service;
1449         struct connman_ipconfig *ipconfig;
1450
1451         service = connman_service_lookup_from_network(network);
1452         if (!service)
1453                 goto done;
1454
1455         ipconfig = __connman_service_get_ip4config(service);
1456         if (ipconfig) {
1457                 __connman_ipconfig_set_index(ipconfig, index);
1458
1459                 DBG("index %d service %p ip4config %p", network->index,
1460                         service, ipconfig);
1461         }
1462
1463         ipconfig = __connman_service_get_ip6config(service);
1464         if (ipconfig) {
1465                 __connman_ipconfig_set_index(ipconfig, index);
1466
1467                 DBG("index %d service %p ip6config %p", network->index,
1468                         service, ipconfig);
1469         }
1470
1471 done:
1472         network->index = index;
1473 }
1474
1475 /**
1476  * connman_network_get_index:
1477  * @network: network structure
1478  *
1479  * Get index number of network
1480  */
1481 int connman_network_get_index(struct connman_network *network)
1482 {
1483         return network->index;
1484 }
1485
1486 /**
1487  * connman_network_set_group:
1488  * @network: network structure
1489  * @group: group name
1490  *
1491  * Set group name for automatic clustering
1492  */
1493 void connman_network_set_group(struct connman_network *network,
1494                                                         const char *group)
1495 {
1496         switch (network->type) {
1497         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1498         case CONNMAN_NETWORK_TYPE_VENDOR:
1499                 return;
1500         case CONNMAN_NETWORK_TYPE_ETHERNET:
1501         case CONNMAN_NETWORK_TYPE_GADGET:
1502         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1503         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1504         case CONNMAN_NETWORK_TYPE_CELLULAR:
1505         case CONNMAN_NETWORK_TYPE_WIFI:
1506                 break;
1507         }
1508
1509         if (g_strcmp0(network->group, group) == 0) {
1510                 if (group)
1511                         __connman_service_update_from_network(network);
1512                 return;
1513         }
1514
1515         if (network->group) {
1516                 __connman_service_remove_from_network(network);
1517
1518                 g_free(network->group);
1519         }
1520
1521         network->group = g_strdup(group);
1522
1523         if (network->group)
1524                 network_probe(network);
1525 }
1526
1527 /**
1528  * connman_network_get_group:
1529  * @network: network structure
1530  *
1531  * Get group name for automatic clustering
1532  */
1533 const char *connman_network_get_group(struct connman_network *network)
1534 {
1535         return network->group;
1536 }
1537
1538 const char *__connman_network_get_ident(struct connman_network *network)
1539 {
1540         if (!network->device)
1541                 return NULL;
1542
1543         return connman_device_get_ident(network->device);
1544 }
1545
1546 bool __connman_network_get_weakness(struct connman_network *network)
1547 {
1548         switch (network->type) {
1549         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1550         case CONNMAN_NETWORK_TYPE_VENDOR:
1551         case CONNMAN_NETWORK_TYPE_ETHERNET:
1552         case CONNMAN_NETWORK_TYPE_GADGET:
1553         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1554         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1555         case CONNMAN_NETWORK_TYPE_CELLULAR:
1556                 break;
1557         case CONNMAN_NETWORK_TYPE_WIFI:
1558                 if (network->strength > 0 && network->strength < 20)
1559                         return true;
1560                 break;
1561         }
1562
1563         return false;
1564 }
1565
1566 #if defined TIZEN_EXT
1567 void connman_network_set_connecting(struct connman_network *network)
1568 {
1569         DBG("set network connecting true");
1570         network->connecting = TRUE;
1571         return;
1572 }
1573 #endif
1574
1575 bool connman_network_get_connecting(struct connman_network *network)
1576 {
1577         return network->connecting;
1578 }
1579
1580 /**
1581  * connman_network_set_available:
1582  * @network: network structure
1583  * @available: availability state
1584  *
1585  * Change availability state of network (in range)
1586  */
1587 int connman_network_set_available(struct connman_network *network,
1588                                                 bool available)
1589 {
1590 #if !defined TIZEN_EXT
1591         DBG("network %p available %d", network, available);
1592 #endif
1593
1594         if (network->available == available)
1595                 return -EALREADY;
1596
1597         network->available = available;
1598
1599         return 0;
1600 }
1601
1602 /**
1603  * connman_network_get_available:
1604  * @network: network structure
1605  *
1606  * Get network available setting
1607  */
1608 bool connman_network_get_available(struct connman_network *network)
1609 {
1610         return network->available;
1611 }
1612
1613 #if defined TIZEN_EXT
1614 void connman_network_clear_associating(struct connman_network *network)
1615 {
1616         struct connman_service *service;
1617         enum connman_service_state state;
1618
1619         DBG("network %p", network);
1620
1621         network->connecting = FALSE;
1622         network->associating = FALSE;
1623
1624         service = connman_service_lookup_from_network(network);
1625         if (!service)
1626                 return;
1627
1628         state = __connman_service_ipconfig_get_state(service,
1629                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
1630         if (state != CONNMAN_SERVICE_STATE_IDLE &&
1631                         state != CONNMAN_SERVICE_STATE_FAILURE)
1632                 __connman_service_ipconfig_indicate_state(service,
1633                                         CONNMAN_SERVICE_STATE_DISCONNECT,
1634                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1635
1636         state = __connman_service_ipconfig_get_state(service,
1637                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
1638         if (state != CONNMAN_SERVICE_STATE_IDLE &&
1639                                 state != CONNMAN_SERVICE_STATE_FAILURE)
1640                 __connman_service_ipconfig_indicate_state(service,
1641                                         CONNMAN_SERVICE_STATE_DISCONNECT,
1642                                         CONNMAN_IPCONFIG_TYPE_IPV6);
1643
1644         __connman_service_ipconfig_indicate_state(service,
1645                                                 CONNMAN_SERVICE_STATE_IDLE,
1646                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
1647
1648         __connman_service_ipconfig_indicate_state(service,
1649                                                 CONNMAN_SERVICE_STATE_IDLE,
1650                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
1651 }
1652
1653 static gboolean __connman_network_clear_associating_delayed(gpointer user_data)
1654 {
1655         GSList *list;
1656         gboolean found = FALSE;
1657         enum connman_service_state state_ipv4;
1658         enum connman_service_state state_ipv6;
1659         struct connman_service *service;
1660         struct connman_network *network = (struct connman_network *)user_data;
1661
1662         for (list = network_list; list != NULL; list = list->next) {
1663                 struct connman_network *item = list->data;
1664
1665                 if (item == network) {
1666                         found = TRUE;
1667                         break;
1668                 }
1669         }
1670
1671         if (found != TRUE)
1672                 return FALSE;
1673
1674         DBG("network %p name %s", network, network->name);
1675         service = connman_service_lookup_from_network(network);
1676
1677         state_ipv4 = __connman_service_ipconfig_get_state(service,
1678                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
1679         state_ipv6 = __connman_service_ipconfig_get_state(service,
1680                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
1681
1682         DBG("service %p state %d/%d", service, state_ipv4, state_ipv6);
1683
1684         if (network->associating == FALSE &&
1685                         state_ipv4 == CONNMAN_SERVICE_STATE_ASSOCIATION &&
1686                         state_ipv6 == CONNMAN_SERVICE_STATE_ASSOCIATION) {
1687                 __connman_service_ipconfig_indicate_state(service,
1688                                 CONNMAN_SERVICE_STATE_IDLE,
1689                                 CONNMAN_IPCONFIG_TYPE_IPV4);
1690                 __connman_service_ipconfig_indicate_state(service,
1691                                 CONNMAN_SERVICE_STATE_IDLE,
1692                                 CONNMAN_IPCONFIG_TYPE_IPV6);
1693         } else {
1694                 if (network->associating == FALSE) {
1695                         struct connman_ipconfig *ipconfig_ipv4, *ipconfig_ipv6;
1696                         enum connman_ipconfig_method ipv4_method, ipv6_method;
1697
1698                         ipconfig_ipv4 = __connman_service_get_ip4config(service);
1699                         ipv4_method = __connman_ipconfig_get_method(ipconfig_ipv4);
1700                         ipconfig_ipv6 = __connman_service_get_ip4config(service);
1701                         ipv6_method = __connman_ipconfig_get_method(ipconfig_ipv6);
1702
1703                         if((ipv4_method == CONNMAN_IPCONFIG_METHOD_UNKNOWN || ipv4_method == CONNMAN_IPCONFIG_METHOD_OFF) &&
1704                                         (state_ipv6 == CONNMAN_SERVICE_STATE_ASSOCIATION))
1705                                 __connman_service_ipconfig_indicate_state(service,
1706                                                 CONNMAN_SERVICE_STATE_IDLE,
1707                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
1708                         if((ipv6_method == CONNMAN_IPCONFIG_METHOD_UNKNOWN || ipv6_method == CONNMAN_IPCONFIG_METHOD_OFF) &&
1709                                         (state_ipv4 == CONNMAN_SERVICE_STATE_ASSOCIATION))
1710                                 __connman_service_ipconfig_indicate_state(service,
1711                                                 CONNMAN_SERVICE_STATE_IDLE,
1712                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
1713                 }
1714         }
1715
1716         return FALSE;
1717 }
1718 #endif
1719
1720 /**
1721  * connman_network_set_associating:
1722  * @network: network structure
1723  * @associating: associating state
1724  *
1725  * Change associating state of network
1726  */
1727 int connman_network_set_associating(struct connman_network *network,
1728                                                 bool associating)
1729 {
1730         DBG("network %p associating %d", network, associating);
1731
1732         if (network->associating == associating)
1733                 return -EALREADY;
1734
1735         network->associating = associating;
1736
1737         if (associating) {
1738                 struct connman_service *service;
1739
1740                 service = connman_service_lookup_from_network(network);
1741                 __connman_service_ipconfig_indicate_state(service,
1742                                         CONNMAN_SERVICE_STATE_ASSOCIATION,
1743                                         CONNMAN_IPCONFIG_TYPE_IPV4);
1744                 __connman_service_ipconfig_indicate_state(service,
1745                                         CONNMAN_SERVICE_STATE_ASSOCIATION,
1746                                         CONNMAN_IPCONFIG_TYPE_IPV6);
1747         }
1748
1749 #if defined TIZEN_EXT
1750         if (associating == FALSE &&
1751                         connman_network_get_bool(network, "WiFi.UseWPS") == FALSE)
1752                 g_timeout_add_seconds(1,
1753                                 __connman_network_clear_associating_delayed,
1754                                 network);
1755 #endif
1756
1757         return 0;
1758 }
1759
1760 static void set_associate_error(struct connman_network *network)
1761 {
1762         struct connman_service *service;
1763
1764         service = connman_service_lookup_from_network(network);
1765
1766 #if defined TIZEN_EXT
1767         __connman_service_indicate_error(service,
1768                                         CONNMAN_SERVICE_ERROR_AUTH_FAILED);
1769 #else
1770         __connman_service_indicate_error(service,
1771                                         CONNMAN_SERVICE_ERROR_CONNECT_FAILED);
1772 #endif
1773 }
1774
1775 static void set_configure_error(struct connman_network *network)
1776 {
1777         struct connman_service *service;
1778
1779         service = connman_service_lookup_from_network(network);
1780
1781         __connman_service_indicate_error(service,
1782                                         CONNMAN_SERVICE_ERROR_CONNECT_FAILED);
1783 }
1784
1785 static void set_invalid_key_error(struct connman_network *network)
1786 {
1787         struct connman_service *service;
1788
1789         service = connman_service_lookup_from_network(network);
1790
1791 #if defined TIZEN_EXT
1792         if (service)
1793                 __connman_service_set_favorite(service, false);
1794 #endif
1795         __connman_service_indicate_error(service,
1796                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
1797 }
1798
1799 static void set_connect_error(struct connman_network *network)
1800 {
1801         struct connman_service *service;
1802
1803         service = connman_service_lookup_from_network(network);
1804
1805         __connman_service_indicate_error(service,
1806                                         CONNMAN_SERVICE_ERROR_CONNECT_FAILED);
1807 }
1808
1809 static void set_blocked_error(struct connman_network *network)
1810 {
1811         struct connman_service *service;
1812
1813         service = connman_service_lookup_from_network(network);
1814
1815         __connman_service_indicate_error(service,
1816                                         CONNMAN_SERVICE_ERROR_BLOCKED);
1817 }
1818
1819
1820 #if defined TIZEN_EXT
1821 static void set_dhcp_error(struct connman_network *network)
1822 {
1823         struct connman_service *service;
1824
1825         if (network->associating != FALSE)
1826                 network->associating = FALSE;
1827
1828         service = connman_service_lookup_from_network(network);
1829
1830         __connman_service_indicate_error(service,
1831                                         CONNMAN_SERVICE_ERROR_DHCP_FAILED);
1832 }
1833 #endif
1834
1835 void connman_network_set_ipv4_method(struct connman_network *network,
1836                                         enum connman_ipconfig_method method)
1837 {
1838         struct connman_service *service;
1839         struct connman_ipconfig *ipconfig;
1840
1841         service = connman_service_lookup_from_network(network);
1842         if (!service)
1843                 return;
1844
1845         ipconfig = __connman_service_get_ip4config(service);
1846         if (!ipconfig)
1847                 return;
1848
1849         __connman_ipconfig_set_method(ipconfig, method);
1850 }
1851
1852 void connman_network_set_ipv6_method(struct connman_network *network,
1853                                         enum connman_ipconfig_method method)
1854 {
1855         struct connman_service *service;
1856         struct connman_ipconfig *ipconfig;
1857
1858         service = connman_service_lookup_from_network(network);
1859         if (!service)
1860                 return;
1861
1862         ipconfig = __connman_service_get_ip6config(service);
1863         if (!ipconfig)
1864                 return;
1865
1866         __connman_ipconfig_set_method(ipconfig, method);
1867 }
1868
1869 void connman_network_set_error(struct connman_network *network,
1870                                         enum connman_network_error error)
1871 {
1872         DBG("network %p error %d", network, error);
1873
1874         switch (error) {
1875         case CONNMAN_NETWORK_ERROR_UNKNOWN:
1876                 return;
1877         case CONNMAN_NETWORK_ERROR_ASSOCIATE_FAIL:
1878                 set_associate_error(network);
1879                 break;
1880         case CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL:
1881                 set_configure_error(network);
1882                 break;
1883         case CONNMAN_NETWORK_ERROR_INVALID_KEY:
1884                 set_invalid_key_error(network);
1885                 break;
1886         case CONNMAN_NETWORK_ERROR_CONNECT_FAIL:
1887                 set_connect_error(network);
1888                 break;
1889 #if defined TIZEN_EXT
1890         case CONNMAN_NETWORK_ERROR_DHCP_FAIL:
1891                 set_dhcp_error(network);
1892                 break;
1893 #endif
1894
1895         case CONNMAN_NETWORK_ERROR_BLOCKED:
1896                 set_blocked_error(network);
1897                 break;
1898         }
1899
1900         __connman_network_disconnect(network);
1901 }
1902
1903 /**
1904  * connman_network_set_connected:
1905  * @network: network structure
1906  * @connected: connected state
1907  *
1908  * Change connected state of network
1909  */
1910 int connman_network_set_connected(struct connman_network *network,
1911                                                 bool connected)
1912 {
1913         DBG("network %p connected %d/%d connecting %d associating %d",
1914                 network, network->connected, connected, network->connecting,
1915                 network->associating);
1916
1917         if ((network->connecting || network->associating) &&
1918                                                         !connected) {
1919                 connman_network_set_error(network,
1920                                         CONNMAN_NETWORK_ERROR_CONNECT_FAIL);
1921                 return 0;
1922         }
1923
1924         if (network->connected == connected)
1925                 return -EALREADY;
1926
1927         if (!connected)
1928                 set_disconnected(network);
1929         else
1930                 set_connected(network);
1931
1932         return 0;
1933 }
1934
1935 /**
1936  * connman_network_get_connected:
1937  * @network: network structure
1938  *
1939  * Get network connection status
1940  */
1941 bool connman_network_get_connected(struct connman_network *network)
1942 {
1943         return network->connected;
1944 }
1945
1946 /**
1947  * connman_network_get_associating:
1948  * @network: network structure
1949  *
1950  * Get network associating status
1951  */
1952 bool connman_network_get_associating(struct connman_network *network)
1953 {
1954         return network->associating;
1955 }
1956
1957 void connman_network_clear_hidden(void *user_data)
1958 {
1959         if (!user_data)
1960                 return;
1961
1962         DBG("user_data %p", user_data);
1963
1964         /*
1965          * Hidden service does not have a connect timeout so
1966          * we do not need to remove it. We can just return
1967          * error to the caller telling that we could not find
1968          * any network that we could connect to.
1969          */
1970         connman_dbus_reply_pending(user_data, EIO, NULL);
1971 }
1972
1973 int connman_network_connect_hidden(struct connman_network *network,
1974                         char *identity, char *passphrase, void *user_data)
1975 {
1976         int err = 0;
1977         struct connman_service *service;
1978
1979         service = connman_service_lookup_from_network(network);
1980
1981         DBG("network %p service %p user_data %p", network, service, user_data);
1982
1983         if (!service)
1984                 return -EINVAL;
1985
1986         if (identity)
1987                 __connman_service_set_agent_identity(service, identity);
1988
1989         if (passphrase)
1990                 err = __connman_service_set_passphrase(service, passphrase);
1991
1992         if (err == -ENOKEY) {
1993                 __connman_service_indicate_error(service,
1994                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
1995                 goto out;
1996         } else {
1997                 __connman_service_set_hidden(service);
1998                 __connman_service_set_hidden_data(service, user_data);
1999                 return __connman_service_connect(service,
2000                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
2001         }
2002
2003 out:
2004         __connman_service_return_error(service, -err, user_data);
2005         return err;
2006 }
2007
2008 /**
2009  * __connman_network_connect:
2010  * @network: network structure
2011  *
2012  * Connect network
2013  */
2014 int __connman_network_connect(struct connman_network *network)
2015 {
2016         int err;
2017
2018         DBG("network %p", network);
2019
2020         if (network->connected)
2021                 return -EISCONN;
2022
2023         if (network->connecting || network->associating)
2024                 return -EALREADY;
2025
2026         if (!network->driver)
2027                 return -EUNATCH;
2028
2029         if (!network->driver->connect)
2030                 return -ENOSYS;
2031
2032         if (!network->device)
2033                 return -ENODEV;
2034
2035 #if defined TIZEN_EXT
2036         if (network->type != CONNMAN_NETWORK_TYPE_CELLULAR)
2037 #endif
2038         __connman_device_disconnect(network->device);
2039
2040         network->connecting = true;
2041
2042 #if defined TIZEN_EXT
2043         DBG("ConnMan, Connect Request [%s]", network->name);
2044 #endif
2045
2046         err = network->driver->connect(network);
2047         if (err < 0) {
2048                 if (err == -EINPROGRESS) {
2049 #if defined TIZEN_EXT
2050                         if (network->type != CONNMAN_NETWORK_TYPE_CELLULAR)
2051 #endif
2052                         connman_network_set_associating(network, true);
2053                 } else
2054                         network->connecting = false;
2055
2056                 return err;
2057         }
2058
2059         set_connected(network);
2060
2061         return err;
2062 }
2063
2064 /**
2065  * __connman_network_disconnect:
2066  * @network: network structure
2067  *
2068  * Disconnect network
2069  */
2070 int __connman_network_disconnect(struct connman_network *network)
2071 {
2072         int err = 0;
2073
2074         DBG("network %p", network);
2075
2076         remove_ipv4ll_timeout(network);
2077         if (network->acd_host)
2078                 acd_host_stop(network->acd_host);
2079
2080         if (!network->connected && !network->connecting &&
2081                                                 !network->associating)
2082                 return -ENOTCONN;
2083
2084         if (!network->driver)
2085                 return -EUNATCH;
2086
2087         network->connecting = false;
2088
2089 #if defined TIZEN_EXT
2090         DBG("ConnMan, Disconnect request");
2091         struct connman_service *service = connman_service_lookup_from_network(network);
2092         connman_service_set_disconnection_requested(service, true);
2093 #endif
2094         if (network->driver->disconnect)
2095                 err = network->driver->disconnect(network);
2096
2097         if (err != -EINPROGRESS)
2098                 set_disconnected(network);
2099
2100         return err;
2101 }
2102
2103 int __connman_network_clear_ipconfig(struct connman_network *network,
2104                                         struct connman_ipconfig *ipconfig)
2105 {
2106         struct connman_service *service;
2107         struct connman_ipconfig *ipconfig_ipv4;
2108         enum connman_ipconfig_method method;
2109         enum connman_ipconfig_type type;
2110
2111         service = connman_service_lookup_from_network(network);
2112         if (!service)
2113                 return -EINVAL;
2114
2115         ipconfig_ipv4 = __connman_service_get_ip4config(service);
2116         method = __connman_ipconfig_get_method(ipconfig);
2117         type = __connman_ipconfig_get_config_type(ipconfig);
2118
2119         switch (method) {
2120         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2121         case CONNMAN_IPCONFIG_METHOD_OFF:
2122         case CONNMAN_IPCONFIG_METHOD_FIXED:
2123                 return -EINVAL;
2124         case CONNMAN_IPCONFIG_METHOD_MANUAL:
2125                 __connman_ipconfig_address_remove(ipconfig);
2126                 break;
2127         case CONNMAN_IPCONFIG_METHOD_AUTO:
2128                 release_dhcpv6(network);
2129                 if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
2130                         break;
2131                 /* fall through */
2132         case CONNMAN_IPCONFIG_METHOD_DHCP:
2133                 remove_dhcp_timeout(network);
2134                 __connman_dhcp_stop(ipconfig_ipv4);
2135                 break;
2136         }
2137
2138         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
2139                 __connman_service_ipconfig_indicate_state(service,
2140                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
2141                                         CONNMAN_IPCONFIG_TYPE_IPV6);
2142         else if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
2143                 __connman_service_ipconfig_indicate_state(service,
2144                                         CONNMAN_SERVICE_STATE_CONFIGURATION,
2145                                         CONNMAN_IPCONFIG_TYPE_IPV4);
2146
2147         return 0;
2148 }
2149
2150 #if defined TIZEN_EXT
2151 void __connman_network_set_auto_ipv6_gateway(char *gateway, void *user_data)
2152 {
2153         DBG("");
2154
2155         struct connman_network *network = user_data;
2156         struct connman_service *service;
2157         struct connman_ipconfig *ipconfig = NULL;
2158
2159         service = connman_service_lookup_from_network(network);
2160         if (service == NULL)
2161                 return;
2162
2163         ipconfig = __connman_service_get_ipconfig(service, AF_INET6);
2164         if (ipconfig == NULL)
2165                 return;
2166
2167         __connman_ipconfig_set_gateway(ipconfig, gateway);
2168
2169         return;
2170 }
2171 #endif
2172
2173 int __connman_network_enable_ipconfig(struct connman_network *network,
2174                                 struct connman_ipconfig *ipconfig)
2175 {
2176         int r = 0;
2177         enum connman_ipconfig_type type;
2178         enum connman_ipconfig_method method;
2179 #if defined TIZEN_EXT
2180         struct connman_service *service;
2181 #endif
2182
2183         if (!network || !ipconfig)
2184                 return -EINVAL;
2185
2186         type = __connman_ipconfig_get_config_type(ipconfig);
2187
2188         switch (type) {
2189         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
2190         case CONNMAN_IPCONFIG_TYPE_ALL:
2191                 return -ENOSYS;
2192
2193         case CONNMAN_IPCONFIG_TYPE_IPV6:
2194                 set_configuration(network, type);
2195
2196                 method = __connman_ipconfig_get_method(ipconfig);
2197
2198                 DBG("ipv6 ipconfig method %d", method);
2199
2200                 switch (method) {
2201                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2202                         break;
2203
2204                 case CONNMAN_IPCONFIG_METHOD_OFF:
2205                         __connman_ipconfig_disable_ipv6(ipconfig);
2206                         break;
2207
2208                 case CONNMAN_IPCONFIG_METHOD_AUTO:
2209 #if defined TIZEN_EXT
2210                 service = connman_service_lookup_from_network(network);
2211
2212                 if(network->type == CONNMAN_NETWORK_TYPE_CELLULAR)
2213                         __connman_service_ipconfig_indicate_state(service,
2214                                 CONNMAN_SERVICE_STATE_CONFIGURATION,
2215                                         CONNMAN_IPCONFIG_TYPE_IPV6);
2216 #endif
2217                         autoconf_ipv6_set(network);
2218                         break;
2219
2220                 case CONNMAN_IPCONFIG_METHOD_FIXED:
2221                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
2222                         r = manual_ipv6_set(network, ipconfig);
2223                         break;
2224
2225                 case CONNMAN_IPCONFIG_METHOD_DHCP:
2226                         r = -ENOSYS;
2227                         break;
2228                 }
2229
2230                 break;
2231
2232         case CONNMAN_IPCONFIG_TYPE_IPV4:
2233                 set_configuration(network, type);
2234
2235                 method = __connman_ipconfig_get_method(ipconfig);
2236
2237                 DBG("ipv4 ipconfig method %d", method);
2238
2239                 switch (method) {
2240                 case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
2241                 case CONNMAN_IPCONFIG_METHOD_OFF:
2242                         break;
2243
2244                 case CONNMAN_IPCONFIG_METHOD_AUTO:
2245                         r = -ENOSYS;
2246                         break;
2247
2248                 case CONNMAN_IPCONFIG_METHOD_FIXED:
2249                 case CONNMAN_IPCONFIG_METHOD_MANUAL:
2250                         r = set_connected_manual(network);
2251                         break;
2252
2253                 case CONNMAN_IPCONFIG_METHOD_DHCP:
2254                         r = set_connected_dhcp(network);
2255                         break;
2256                 }
2257
2258                 break;
2259         }
2260
2261         if (r < 0)
2262                 connman_network_set_error(network,
2263                                         CONNMAN_NETWORK_ERROR_CONFIGURE_FAIL);
2264
2265         return r;
2266 }
2267
2268 int connman_network_set_ipaddress(struct connman_network *network,
2269                                         struct connman_ipaddress *ipaddress)
2270 {
2271         struct connman_service *service;
2272         struct connman_ipconfig *ipconfig = NULL;
2273
2274         DBG("network %p", network);
2275
2276         service = connman_service_lookup_from_network(network);
2277         if (!service)
2278                 return -EINVAL;
2279
2280         ipconfig = __connman_service_get_ipconfig(service, ipaddress->family);
2281         if (!ipconfig)
2282                 return -EINVAL;
2283
2284         __connman_ipconfig_set_local(ipconfig, ipaddress->local);
2285         __connman_ipconfig_set_peer(ipconfig, ipaddress->peer);
2286         __connman_ipconfig_set_broadcast(ipconfig, ipaddress->broadcast);
2287         __connman_ipconfig_set_prefixlen(ipconfig, ipaddress->prefixlen);
2288         __connman_ipconfig_set_gateway(ipconfig, ipaddress->gateway);
2289
2290         return 0;
2291 }
2292
2293 #if defined TIZEN_EXT
2294 /*
2295  * Description: Network client requires additional wifi specific info
2296  */
2297 int connman_network_set_bssid(struct connman_network *network,
2298                                 const unsigned char *bssid)
2299 {
2300         int i = 0;
2301
2302         if (bssid == NULL)
2303                 return -EINVAL;
2304
2305         DBG("network %p bssid %02x:%02x:%02x:%02x:%02x:%02x", network,
2306                         bssid[0], bssid[1], bssid[2],
2307                         bssid[3], bssid[4], bssid[5]);
2308
2309         for (;i < WIFI_BSSID_LEN_MAX;i++)
2310                 network->wifi.bssid[i] = bssid[i];
2311
2312         return 0;
2313 }
2314
2315 unsigned char *connman_network_get_bssid(struct connman_network *network)
2316 {
2317         return (unsigned char *)network->wifi.bssid;
2318 }
2319
2320 int connman_network_set_maxspeed(struct connman_network *network,
2321                                 int maxspeed)
2322 {
2323         network->wifi.maxspeed = maxspeed;
2324         return 0;
2325 }
2326
2327 int connman_network_get_maxspeed(struct connman_network *network)
2328 {
2329         if (!network->driver)
2330                 return 0;
2331
2332         if (network->connected)
2333                 return network->wifi.maxspeed;
2334
2335         return 0;
2336 }
2337
2338 int connman_network_set_maxrate(struct connman_network *network,
2339                                 unsigned int maxrate)
2340 {
2341 #if !defined TIZEN_EXT
2342         DBG("network %p maxrate %d", network, maxrate);
2343 #endif
2344
2345         network->wifi.maxrate = maxrate;
2346
2347         return 0;
2348 }
2349
2350 unsigned int connman_network_get_maxrate(struct connman_network *network)
2351 {
2352         return network->wifi.maxrate;
2353 }
2354
2355 int connman_network_set_enc_mode(struct connman_network *network,
2356                                 const char *encryption_mode)
2357 {
2358         if (encryption_mode == NULL)
2359                 return -EINVAL;
2360
2361         DBG("network %p encryption mode %s", network, encryption_mode);
2362
2363         g_strlcpy(network->wifi.encryption_mode, encryption_mode,
2364                                         WIFI_ENCYPTION_MODE_LEN_MAX);
2365
2366         return 0;
2367 }
2368
2369 const char *connman_network_get_enc_mode(struct connman_network *network)
2370 {
2371         return (const char *)network->wifi.encryption_mode;
2372 }
2373
2374 int connman_network_set_rsn_mode(struct connman_network *network,
2375                                 bool rsn_mode)
2376 {
2377         network->wifi.rsn_mode = rsn_mode;
2378
2379         return 0;
2380 }
2381
2382 int connman_network_set_proxy(struct connman_network *network,
2383                                 const char *proxies)
2384 {
2385         struct connman_service *service;
2386
2387         DBG("network %p proxies %s", network, proxies);
2388
2389         service = connman_service_lookup_from_network(network);
2390         if (service == NULL)
2391                 return -EINVAL;
2392
2393         __connman_service_set_proxy(service, proxies);
2394
2395         connman_service_set_proxy_method(service,
2396                                 CONNMAN_SERVICE_PROXY_METHOD_MANUAL);
2397
2398         return 0;
2399 }
2400
2401 int connman_network_set_keymgmt(struct connman_network *network,
2402                                 unsigned int keymgmt)
2403 {
2404         if (network == NULL)
2405                 return 0;
2406
2407         network->wifi.keymgmt = keymgmt;
2408
2409         return 0;
2410 }
2411
2412 unsigned int connman_network_get_keymgmt(struct connman_network *network)
2413 {
2414         if (network == NULL)
2415                 return 0;
2416
2417         return network->wifi.keymgmt;
2418 }
2419
2420 int connman_network_set_disconnect_reason(struct connman_network *network,
2421                                 int reason_code)
2422 {
2423         if (network == NULL)
2424                 return 0;
2425
2426         network->wifi.disconnect_reason = reason_code;
2427
2428         return 0;
2429 }
2430
2431 int connman_network_get_disconnect_reason(struct connman_network *network)
2432 {
2433         if (network == NULL)
2434                 return 0;
2435
2436         return network->wifi.disconnect_reason;
2437 }
2438 int connman_network_get_assoc_status_code(struct connman_network *network)
2439 {
2440         if (network == NULL)
2441                 return 0;
2442
2443         return network->wifi.assoc_status_code;
2444 }
2445
2446 int connman_network_set_countrycode(struct connman_network *network,
2447                                     const unsigned char *country_code)
2448 {
2449         int i = 0;
2450
2451         if (country_code == NULL)
2452                 return -EINVAL;
2453
2454         DBG("network %p Country Code %02x:%02x",network,
2455             country_code[0],country_code[1]);
2456
2457         for (; i < WIFI_COUNTRY_CODE_LEN; i++)
2458                 network->wifi.country_code[i] = country_code[i];
2459
2460         return 0;
2461 }
2462
2463 unsigned char *connman_network_get_countrycode(struct connman_network *network)
2464 {
2465         return (unsigned char *)network->wifi.country_code;
2466 }
2467
2468 int connman_network_set_bssid_list(struct connman_network *network,
2469                                         GSList *bssids)
2470 {
2471         g_slist_free_full(network->wifi.bssid_list, g_free);
2472         network->wifi.bssid_list = bssids;
2473
2474         return 0;
2475 }
2476
2477 int connman_network_set_phy_mode(struct connman_network *network,
2478                                     ieee80211_modes_e mode)
2479 {
2480         DBG("network %p phy mode %d", network, mode);
2481         network->wifi.phy_mode = mode;
2482
2483         return 0;
2484 }
2485
2486 ieee80211_modes_e connman_network_get_phy_mode(struct connman_network *network)
2487 {
2488         return network->wifi.phy_mode;
2489 }
2490
2491 int connman_network_set_connection_mode(struct connman_network *network,
2492                                     connection_mode_e mode)
2493 {
2494         DBG("network %p connection mode %d", network, mode);
2495         network->wifi.connection_mode = mode;
2496
2497         return 0;
2498 }
2499
2500 connection_mode_e connman_network_get_connection_mode(struct connman_network *network)
2501 {
2502         return network->wifi.connection_mode;
2503 }
2504
2505 void *connman_network_get_bssid_list(struct connman_network *network)
2506 {
2507         return network->wifi.bssid_list;
2508 }
2509 #endif
2510
2511 int connman_network_set_nameservers(struct connman_network *network,
2512                                 const char *nameservers)
2513 {
2514         struct connman_service *service;
2515         char **nameservers_array;
2516         int i;
2517
2518         DBG("network %p nameservers %s", network, nameservers);
2519
2520         service = connman_service_lookup_from_network(network);
2521         if (!service)
2522                 return -EINVAL;
2523
2524         __connman_service_nameserver_clear(service);
2525
2526         if (!nameservers)
2527                 return 0;
2528
2529         nameservers_array = g_strsplit(nameservers, " ", 0);
2530
2531         for (i = 0; nameservers_array[i]; i++) {
2532 #if defined TIZEN_EXT
2533                 __connman_service_nameserver_append(service,
2534                                                 nameservers_array[i], false,
2535                                                 CONNMAN_IPCONFIG_TYPE_ALL);
2536 #else
2537                 __connman_service_nameserver_append(service,
2538                                                 nameservers_array[i], false);
2539 #endif
2540         }
2541
2542         g_strfreev(nameservers_array);
2543
2544         return 0;
2545 }
2546
2547 int connman_network_set_domain(struct connman_network *network,
2548                                 const char *domain)
2549 {
2550         struct connman_service *service;
2551
2552         DBG("network %p domain %s", network, domain);
2553
2554         service = connman_service_lookup_from_network(network);
2555         if (!service)
2556                 return -EINVAL;
2557
2558         __connman_service_set_domainname(service, domain);
2559
2560         return 0;
2561 }
2562
2563 /**
2564  * connman_network_set_name:
2565  * @network: network structure
2566  * @name: name value
2567  *
2568  * Set display name value for network
2569  */
2570 int connman_network_set_name(struct connman_network *network,
2571                                                         const char *name)
2572 {
2573         DBG("network %p name %s", network, name);
2574
2575         g_free(network->name);
2576         network->name = g_strdup(name);
2577
2578         return 0;
2579 }
2580
2581 /**
2582  * connman_network_set_strength:
2583  * @network: network structure
2584  * @strength: strength value
2585  *
2586  * Set signal strength value for network
2587  */
2588
2589 int connman_network_set_strength(struct connman_network *network,
2590                                                 uint8_t strength)
2591 {
2592         network->strength = strength;
2593 #if defined TIZEN_EXT
2594         __connman_service_notify_strength_changed(network);
2595 #endif
2596
2597         return 0;
2598 }
2599
2600 uint8_t connman_network_get_strength(struct connman_network *network)
2601 {
2602         return network->strength;
2603 }
2604
2605 int connman_network_set_frequency(struct connman_network *network,
2606                                                 uint16_t frequency)
2607 {
2608         network->frequency = frequency;
2609
2610         return 0;
2611 }
2612
2613 uint16_t connman_network_get_frequency(struct connman_network *network)
2614 {
2615         return network->frequency;
2616 }
2617
2618 int connman_network_set_wifi_channel(struct connman_network *network,
2619                                                 uint16_t channel)
2620 {
2621         network->wifi.channel = channel;
2622
2623         return 0;
2624 }
2625
2626 uint16_t connman_network_get_wifi_channel(struct connman_network *network)
2627 {
2628         return network->wifi.channel;
2629 }
2630
2631 /**
2632  * connman_network_set_string:
2633  * @network: network structure
2634  * @key: unique identifier
2635  * @value: string value
2636  *
2637  * Set string value for specific key
2638  */
2639 int connman_network_set_string(struct connman_network *network,
2640                                         const char *key, const char *value)
2641 {
2642         if (g_strcmp0(key, "Name") == 0)
2643                 return connman_network_set_name(network, value);
2644
2645         if (g_str_equal(key, "Path")) {
2646                 g_free(network->path);
2647                 network->path = g_strdup(value);
2648         } else if (g_str_equal(key, "Node")) {
2649                 g_free(network->node);
2650                 network->node = g_strdup(value);
2651         } else if (g_str_equal(key, "WiFi.Mode")) {
2652                 g_free(network->wifi.mode);
2653                 network->wifi.mode = g_strdup(value);
2654         } else if (g_str_equal(key, "WiFi.Security")) {
2655                 g_free(network->wifi.security);
2656                 network->wifi.security = g_strdup(value);
2657         } else if (g_str_equal(key, "WiFi.Passphrase")) {
2658 #if defined TIZEN_EXT
2659                 DBG("ConnMan, %p key %s", network, key);
2660 #endif
2661                 g_free(network->wifi.passphrase);
2662                 network->wifi.passphrase = g_strdup(value);
2663         } else if (g_str_equal(key, "WiFi.EAP")) {
2664                 g_free(network->wifi.eap);
2665                 network->wifi.eap = g_strdup(value);
2666         } else if (g_str_equal(key, "WiFi.Identity")) {
2667                 g_free(network->wifi.identity);
2668                 network->wifi.identity = g_strdup(value);
2669         } else if (g_str_equal(key, "WiFi.AnonymousIdentity")) {
2670                 g_free(network->wifi.anonymous_identity);
2671                 network->wifi.anonymous_identity = g_strdup(value);
2672         } else if (g_str_equal(key, "WiFi.AgentIdentity")) {
2673                 g_free(network->wifi.agent_identity);
2674                 network->wifi.agent_identity = g_strdup(value);
2675         } else if (g_str_equal(key, "WiFi.CACertFile")) {
2676                 g_free(network->wifi.ca_cert_path);
2677                 network->wifi.ca_cert_path = g_strdup(value);
2678         } else if (g_str_equal(key, "WiFi.SubjectMatch")) {
2679                 g_free(network->wifi.subject_match);
2680                 network->wifi.subject_match = g_strdup(value);
2681         } else if (g_str_equal(key, "WiFi.AltSubjectMatch")) {
2682                 g_free(network->wifi.altsubject_match);
2683                 network->wifi.altsubject_match = g_strdup(value);
2684         } else if (g_str_equal(key, "WiFi.DomainSuffixMatch")) {
2685                 g_free(network->wifi.domain_suffix_match);
2686                 network->wifi.domain_suffix_match = g_strdup(value);
2687         } else if (g_str_equal(key, "WiFi.DomainMatch")) {
2688                 g_free(network->wifi.domain_match);
2689                 network->wifi.domain_match = g_strdup(value);
2690         } else if (g_str_equal(key, "WiFi.ClientCertFile")) {
2691                 g_free(network->wifi.client_cert_path);
2692                 network->wifi.client_cert_path = g_strdup(value);
2693         } else if (g_str_equal(key, "WiFi.PrivateKeyFile")) {
2694                 g_free(network->wifi.private_key_path);
2695                 network->wifi.private_key_path = g_strdup(value);
2696         } else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase")) {
2697                 g_free(network->wifi.private_key_passphrase);
2698                 network->wifi.private_key_passphrase = g_strdup(value);
2699         } else if (g_str_equal(key, "WiFi.Phase2")) {
2700                 g_free(network->wifi.phase2_auth);
2701                 network->wifi.phase2_auth = g_strdup(value);
2702         } else if (g_str_equal(key, "WiFi.PinWPS")) {
2703                 g_free(network->wifi.pin_wps);
2704                 network->wifi.pin_wps = g_strdup(value);
2705         } else {
2706                 return -EINVAL;
2707         }
2708
2709         return 0;
2710 }
2711
2712 /**
2713  * connman_network_get_string:
2714  * @network: network structure
2715  * @key: unique identifier
2716  *
2717  * Get string value for specific key
2718  */
2719 const char *connman_network_get_string(struct connman_network *network,
2720                                                         const char *key)
2721 {
2722         if (g_str_equal(key, "Path"))
2723                 return network->path;
2724         else if (g_str_equal(key, "Name"))
2725                 return network->name;
2726         else if (g_str_equal(key, "Node"))
2727                 return network->node;
2728         else if (g_str_equal(key, "WiFi.Mode"))
2729                 return network->wifi.mode;
2730         else if (g_str_equal(key, "WiFi.Security"))
2731 #if defined TIZEN_EXT
2732                 if (network->wifi.rsn_mode != true ||
2733                     g_str_equal(network->wifi.security, "ieee8021x"))
2734                         return network->wifi.security;
2735                 else
2736                         return "rsn";
2737 #else
2738                 return network->wifi.security;
2739 #endif
2740         else if (g_str_equal(key, "WiFi.Passphrase"))
2741                 return network->wifi.passphrase;
2742         else if (g_str_equal(key, "WiFi.EAP"))
2743                 return network->wifi.eap;
2744         else if (g_str_equal(key, "WiFi.Identity"))
2745                 return network->wifi.identity;
2746         else if (g_str_equal(key, "WiFi.AnonymousIdentity"))
2747                 return network->wifi.anonymous_identity;
2748         else if (g_str_equal(key, "WiFi.AgentIdentity"))
2749                 return network->wifi.agent_identity;
2750         else if (g_str_equal(key, "WiFi.CACertFile"))
2751                 return network->wifi.ca_cert_path;
2752         else if (g_str_equal(key, "WiFi.SubjectMatch"))
2753                 return network->wifi.subject_match;
2754         else if (g_str_equal(key, "WiFi.AltSubjectMatch"))
2755                 return network->wifi.altsubject_match;
2756         else if (g_str_equal(key, "WiFi.DomainSuffixMatch"))
2757                 return network->wifi.domain_suffix_match;
2758         else if (g_str_equal(key, "WiFi.DomainMatch"))
2759                 return network->wifi.domain_match;
2760         else if (g_str_equal(key, "WiFi.ClientCertFile"))
2761                 return network->wifi.client_cert_path;
2762         else if (g_str_equal(key, "WiFi.PrivateKeyFile"))
2763                 return network->wifi.private_key_path;
2764         else if (g_str_equal(key, "WiFi.PrivateKeyPassphrase"))
2765                 return network->wifi.private_key_passphrase;
2766         else if (g_str_equal(key, "WiFi.Phase2"))
2767                 return network->wifi.phase2_auth;
2768         else if (g_str_equal(key, "WiFi.PinWPS"))
2769                 return network->wifi.pin_wps;
2770
2771         return NULL;
2772 }
2773
2774 /**
2775  * connman_network_set_bool:
2776  * @network: network structure
2777  * @key: unique identifier
2778  * @value: boolean value
2779  *
2780  * Set boolean value for specific key
2781  */
2782 int connman_network_set_bool(struct connman_network *network,
2783                                         const char *key, bool value)
2784 {
2785         if (g_strcmp0(key, "Roaming") == 0)
2786                 network->roaming = value;
2787         else if (g_strcmp0(key, "WiFi.WPS") == 0)
2788                 network->wifi.wps = value;
2789         else if (g_strcmp0(key, "WiFi.WPSAdvertising") == 0)
2790                 network->wifi.wps_advertizing = value;
2791         else if (g_strcmp0(key, "WiFi.UseWPS") == 0)
2792                 network->wifi.use_wps = value;
2793 #if defined TIZEN_EXT
2794         else if (g_strcmp0(key, "DefaultInternet") == 0)
2795                 network->default_internet = value;
2796         else if (g_strcmp0(key, "WiFi.HS20AP") == 0)
2797                 network->wifi.isHS20AP = value;
2798 #endif
2799
2800         return -EINVAL;
2801 }
2802
2803 /**
2804  * connman_network_get_bool:
2805  * @network: network structure
2806  * @key: unique identifier
2807  *
2808  * Get boolean value for specific key
2809  */
2810 bool connman_network_get_bool(struct connman_network *network,
2811                                                         const char *key)
2812 {
2813         if (g_str_equal(key, "Roaming"))
2814                 return network->roaming;
2815         else if (g_str_equal(key, "WiFi.WPS"))
2816                 return network->wifi.wps;
2817         else if (g_str_equal(key, "WiFi.WPSAdvertising"))
2818                 return network->wifi.wps_advertizing;
2819         else if (g_str_equal(key, "WiFi.UseWPS"))
2820                 return network->wifi.use_wps;
2821 #if defined TIZEN_EXT
2822         else if (g_str_equal(key, "DefaultInternet"))
2823                 return network->default_internet;
2824         else if (g_str_equal(key, "WiFi.HS20AP"))
2825                 return network->wifi.isHS20AP;
2826 #endif
2827
2828         return false;
2829 }
2830
2831 #if defined TIZEN_EXT
2832 /**
2833  * connman_network_set_vsie_list:
2834  * @network: network structure
2835  * @vsie_list: GSList pointer
2836  *
2837  * Set vendor specific list pointer
2838  */
2839 void connman_network_set_vsie_list(struct connman_network *network, GSList *vsie_list)
2840 {
2841         g_slist_free_full(network->wifi.vsie_list, g_free);
2842         network->wifi.vsie_list = vsie_list;
2843 }
2844
2845 /**
2846  * connman_network_get_vsie_list:
2847  * @network: network structure
2848  *
2849  * Get vendor specific list pointer
2850  */
2851 void *connman_network_get_vsie_list(struct connman_network *network)
2852 {
2853         return network->wifi.vsie_list;
2854 }
2855 #endif
2856
2857 /**
2858  * connman_network_set_blob:
2859  * @network: network structure
2860  * @key: unique identifier
2861  * @data: blob data
2862  * @size: blob size
2863  *
2864  * Set binary blob value for specific key
2865  */
2866 int connman_network_set_blob(struct connman_network *network,
2867                         const char *key, const void *data, unsigned int size)
2868 {
2869         if (g_str_equal(key, "WiFi.SSID")) {
2870                 g_free(network->wifi.ssid);
2871                 network->wifi.ssid = g_try_malloc(size);
2872                 if (network->wifi.ssid) {
2873                         memcpy(network->wifi.ssid, data, size);
2874                         network->wifi.ssid_len = size;
2875                 } else
2876                         network->wifi.ssid_len = 0;
2877         } else {
2878                 return -EINVAL;
2879         }
2880
2881         return 0;
2882 }
2883
2884 /**
2885  * connman_network_get_blob:
2886  * @network: network structure
2887  * @key: unique identifier
2888  * @size: pointer to blob size
2889  *
2890  * Get binary blob value for specific key
2891  */
2892 const void *connman_network_get_blob(struct connman_network *network,
2893                                         const char *key, unsigned int *size)
2894 {
2895         if (g_str_equal(key, "WiFi.SSID")) {
2896                 if (size)
2897                         *size = network->wifi.ssid_len;
2898                 return network->wifi.ssid;
2899         }
2900
2901         return NULL;
2902 }
2903
2904 void __connman_network_set_device(struct connman_network *network,
2905                                         struct connman_device *device)
2906 {
2907         if (network->device == device)
2908                 return;
2909
2910         if (network->device)
2911                 network_remove(network);
2912
2913         network->device = device;
2914
2915         if (network->device)
2916                 network_probe(network);
2917 }
2918
2919 /**
2920  * connman_network_get_device:
2921  * @network: network structure
2922  *
2923  * Get parent device of network
2924  */
2925 struct connman_device *connman_network_get_device(struct connman_network *network)
2926 {
2927         return network->device;
2928 }
2929
2930 /**
2931  * connman_network_get_data:
2932  * @network: network structure
2933  *
2934  * Get private network data pointer
2935  */
2936 void *connman_network_get_data(struct connman_network *network)
2937 {
2938         return network->driver_data;
2939 }
2940
2941 /**
2942  * connman_network_set_data:
2943  * @network: network structure
2944  * @data: data pointer
2945  *
2946  * Set private network data pointer
2947  */
2948 void connman_network_set_data(struct connman_network *network, void *data)
2949 {
2950         network->driver_data = data;
2951 }
2952
2953 void connman_network_update(struct connman_network *network)
2954 {
2955         switch (network->type) {
2956         case CONNMAN_NETWORK_TYPE_UNKNOWN:
2957         case CONNMAN_NETWORK_TYPE_VENDOR:
2958                 return;
2959         case CONNMAN_NETWORK_TYPE_ETHERNET:
2960         case CONNMAN_NETWORK_TYPE_GADGET:
2961         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
2962         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
2963         case CONNMAN_NETWORK_TYPE_CELLULAR:
2964         case CONNMAN_NETWORK_TYPE_WIFI:
2965                 break;
2966         }
2967
2968         if (network->group)
2969                 __connman_service_update_from_network(network);
2970 }
2971
2972 int __connman_network_init(void)
2973 {
2974         DBG("");
2975
2976         return 0;
2977 }
2978
2979 void __connman_network_cleanup(void)
2980 {
2981         DBG("");
2982 }