Merge "[Fix] Dereference after free in sta_remove_callback()" into tizen
[platform/upstream/connman.git] / src / service.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 <stdio.h>
28 #include <string.h>
29 #include <netdb.h>
30 #include <gdbus.h>
31 #include <ctype.h>
32 #include <stdint.h>
33
34 #include <connman/storage.h>
35 #include <connman/setting.h>
36 #include <connman/agent.h>
37
38 #include "connman.h"
39
40 #define CONNECT_TIMEOUT         120
41
42 #if defined TIZEN_EXT
43 #define WIFI_BSSID_STR_LEN      18
44 #endif
45
46 static DBusConnection *connection = NULL;
47
48 static GList *service_list = NULL;
49 static GHashTable *service_hash = NULL;
50 static GSList *counter_list = NULL;
51 static unsigned int autoconnect_id = 0;
52 static unsigned int vpn_autoconnect_id = 0;
53 static struct connman_service *current_default = NULL;
54 static bool services_dirty = false;
55
56 #if defined TIZEN_EXT
57 static bool auto_connect_mode = TRUE;
58 #endif
59
60 struct connman_stats {
61         bool valid;
62         bool enabled;
63         struct connman_stats_data data_last;
64         struct connman_stats_data data;
65         GTimer *timer;
66 };
67
68 struct connman_stats_counter {
69         bool append_all;
70         struct connman_stats stats;
71         struct connman_stats stats_roaming;
72 };
73
74 struct connman_service {
75         int refcount;
76         char *identifier;
77         char *path;
78         enum connman_service_type type;
79         enum connman_service_security security;
80         enum connman_service_state state;
81         enum connman_service_state state_ipv4;
82         enum connman_service_state state_ipv6;
83         enum connman_service_error error;
84         enum connman_service_connect_reason connect_reason;
85         uint8_t strength;
86         bool favorite;
87         bool immutable;
88         bool hidden;
89         bool ignore;
90         bool autoconnect;
91         GTimeVal modified;
92         unsigned int order;
93         char *name;
94         char *passphrase;
95         bool roaming;
96         struct connman_ipconfig *ipconfig_ipv4;
97         struct connman_ipconfig *ipconfig_ipv6;
98         struct connman_network *network;
99         struct connman_provider *provider;
100         char **nameservers;
101         char **nameservers_config;
102         char **nameservers_auto;
103         int nameservers_timeout;
104         char **domains;
105         bool mdns;
106         bool mdns_config;
107         char *hostname;
108         char *domainname;
109         char **timeservers;
110         char **timeservers_config;
111         /* 802.1x settings from the config files */
112         char *eap;
113         char *identity;
114         char *anonymous_identity;
115         char *agent_identity;
116         char *ca_cert_file;
117         char *subject_match;
118         char *altsubject_match;
119         char *domain_suffix_match;
120         char *domain_match;
121         char *client_cert_file;
122         char *private_key_file;
123         char *private_key_passphrase;
124         char *phase2;
125         DBusMessage *pending;
126         DBusMessage *provider_pending;
127         guint timeout;
128         struct connman_stats stats;
129         struct connman_stats stats_roaming;
130         GHashTable *counter_table;
131         enum connman_service_proxy_method proxy;
132         enum connman_service_proxy_method proxy_config;
133         char **proxies;
134         char **excludes;
135         char *pac;
136         bool wps;
137         bool wps_advertizing;
138         guint online_timeout;
139         int online_check_interval_ipv4;
140         int online_check_interval_ipv6;
141         bool do_split_routing;
142         bool new_service;
143         bool hidden_service;
144         char *config_file;
145         char *config_entry;
146 #if defined TIZEN_EXT
147         /*
148          * Description: TIZEN implements system global connection management.
149          *              It's only for PDP (cellular) bearer. Wi-Fi is managed
150          *              by ConnMan automatically. Reference count can help to
151          *              manage open/close connection requests by each application.
152          */
153         int user_pdn_connection_refcount;
154         bool storage_reload;
155         /*
156          * Description: In case of EAP security type,
157          *                                user can select the keymgmt type for roaming(802.11r).
158          *                                - FT, CCKM, OKC, ...
159          */
160         char *keymgmt_type;
161         int disconnect_reason;
162         int assoc_status_code;
163         /*
164          * Only for EAP-FAST
165          */
166         char *phase1;
167         /*
168          * Description: To indicate that disconnection triggered by user.
169          */
170         bool disconnection_requested;
171
172         enum connman_dnsconfig_method dns_config_method_ipv4;
173         enum connman_dnsconfig_method dns_config_method_ipv6;
174 #endif
175 #if defined TIZEN_EXT
176         char *connector;
177         char *c_sign_key;
178         char *net_access_key;
179 #endif
180 };
181
182 static bool allow_property_changed(struct connman_service *service);
183
184 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
185                 int index, enum connman_ipconfig_method method);
186 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
187                 int index);
188 static void dns_changed(struct connman_service *service);
189
190 struct find_data {
191         const char *path;
192         struct connman_service *service;
193 };
194
195 #if defined TIZEN_EXT
196 /*
197  * Public APIs to use user_pdn_connection_refcount
198  */
199 void connman_service_user_pdn_connection_ref(struct connman_service *service)
200 {
201         __sync_fetch_and_add(&service->user_pdn_connection_refcount, 1);
202
203         DBG("User made PDN connection referenced: %d",
204                                 service->user_pdn_connection_refcount);
205 }
206
207 gboolean connman_service_user_pdn_connection_unref_and_test(
208                                         struct connman_service *service)
209 {
210         __sync_synchronize();
211
212         DBG("User made PDN connection referenced: %d, which will be decreased",
213                                 service->user_pdn_connection_refcount);
214
215         if (service->user_pdn_connection_refcount < 1)
216                 return TRUE;
217
218         if (__sync_sub_and_fetch(&service->user_pdn_connection_refcount, 1) == 0)
219                 return TRUE;
220
221         return FALSE;
222 }
223
224 gboolean connman_service_is_no_ref_user_pdn_connection(
225                                         struct connman_service *cellular)
226 {
227         if (cellular == NULL)
228                 return TRUE;
229
230         __sync_synchronize();
231         if (cellular->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
232                         cellular->user_pdn_connection_refcount == 0)
233                 return TRUE;
234
235         return FALSE;
236 }
237 #endif
238
239 static void compare_path(gpointer value, gpointer user_data)
240 {
241         struct connman_service *service = value;
242         struct find_data *data = user_data;
243
244         if (data->service)
245                 return;
246
247         if (g_strcmp0(service->path, data->path) == 0)
248                 data->service = service;
249 }
250
251 static struct connman_service *find_service(const char *path)
252 {
253         struct find_data data = { .path = path, .service = NULL };
254
255         DBG("path %s", path);
256
257         g_list_foreach(service_list, compare_path, &data);
258
259         return data.service;
260 }
261
262 static const char *reason2string(enum connman_service_connect_reason reason)
263 {
264
265         switch (reason) {
266         case CONNMAN_SERVICE_CONNECT_REASON_NONE:
267                 return "none";
268         case CONNMAN_SERVICE_CONNECT_REASON_USER:
269                 return "user";
270         case CONNMAN_SERVICE_CONNECT_REASON_AUTO:
271                 return "auto";
272         case CONNMAN_SERVICE_CONNECT_REASON_SESSION:
273                 return "session";
274         }
275
276         return "unknown";
277 }
278
279 const char *__connman_service_type2string(enum connman_service_type type)
280 {
281         switch (type) {
282         case CONNMAN_SERVICE_TYPE_UNKNOWN:
283                 break;
284         case CONNMAN_SERVICE_TYPE_SYSTEM:
285                 return "system";
286         case CONNMAN_SERVICE_TYPE_ETHERNET:
287                 return "ethernet";
288         case CONNMAN_SERVICE_TYPE_WIFI:
289                 return "wifi";
290         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
291                 return "bluetooth";
292         case CONNMAN_SERVICE_TYPE_CELLULAR:
293                 return "cellular";
294         case CONNMAN_SERVICE_TYPE_GPS:
295                 return "gps";
296         case CONNMAN_SERVICE_TYPE_VPN:
297                 return "vpn";
298         case CONNMAN_SERVICE_TYPE_GADGET:
299                 return "gadget";
300         case CONNMAN_SERVICE_TYPE_P2P:
301                 return "p2p";
302 #if defined TIZEN_EXT_WIFI_MESH
303         case CONNMAN_SERVICE_TYPE_MESH:
304                 return "mesh";
305 #endif
306         }
307
308         return NULL;
309 }
310
311 enum connman_service_type __connman_service_string2type(const char *str)
312 {
313         if (!str)
314                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
315
316         if (strcmp(str, "ethernet") == 0)
317                 return CONNMAN_SERVICE_TYPE_ETHERNET;
318         if (strcmp(str, "gadget") == 0)
319                 return CONNMAN_SERVICE_TYPE_GADGET;
320         if (strcmp(str, "wifi") == 0)
321                 return CONNMAN_SERVICE_TYPE_WIFI;
322         if (strcmp(str, "cellular") == 0)
323                 return CONNMAN_SERVICE_TYPE_CELLULAR;
324         if (strcmp(str, "bluetooth") == 0)
325                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
326         if (strcmp(str, "vpn") == 0)
327                 return CONNMAN_SERVICE_TYPE_VPN;
328         if (strcmp(str, "gps") == 0)
329                 return CONNMAN_SERVICE_TYPE_GPS;
330         if (strcmp(str, "system") == 0)
331                 return CONNMAN_SERVICE_TYPE_SYSTEM;
332         if (strcmp(str, "p2p") == 0)
333                 return CONNMAN_SERVICE_TYPE_P2P;
334
335         return CONNMAN_SERVICE_TYPE_UNKNOWN;
336 }
337
338 enum connman_service_security __connman_service_string2security(const char *str)
339 {
340         if (!str)
341                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
342
343         if (!strcmp(str, "psk"))
344                 return CONNMAN_SERVICE_SECURITY_PSK;
345         if (!strcmp(str, "ieee8021x") || !strcmp(str, "8021x"))
346                 return CONNMAN_SERVICE_SECURITY_8021X;
347         if (!strcmp(str, "none") || !strcmp(str, "open"))
348                 return CONNMAN_SERVICE_SECURITY_NONE;
349         if (!strcmp(str, "wep"))
350                 return CONNMAN_SERVICE_SECURITY_WEP;
351 #if defined TIZEN_EXT
352         if (!strcmp(str, "rsn"))
353                 return CONNMAN_SERVICE_SECURITY_RSN;
354         if (!strcmp(str, "sae"))
355                 return CONNMAN_SERVICE_SECURITY_SAE;
356         if (!strcmp(str, "owe"))
357                 return CONNMAN_SERVICE_SECURITY_OWE;
358         if (!strcmp(str, "dpp"))
359                 return CONNMAN_SERVICE_SECURITY_DPP;
360 #endif
361
362         return CONNMAN_SERVICE_SECURITY_UNKNOWN;
363 }
364
365 static const char *security2string(enum connman_service_security security)
366 {
367         switch (security) {
368         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
369                 break;
370         case CONNMAN_SERVICE_SECURITY_NONE:
371                 return "none";
372         case CONNMAN_SERVICE_SECURITY_WEP:
373                 return "wep";
374         case CONNMAN_SERVICE_SECURITY_PSK:
375         case CONNMAN_SERVICE_SECURITY_WPA:
376 #if defined TIZEN_EXT
377                 return "psk";
378         case CONNMAN_SERVICE_SECURITY_RSN:
379                 return "rsn";
380         case CONNMAN_SERVICE_SECURITY_SAE:
381                 return "sae";
382         case CONNMAN_SERVICE_SECURITY_OWE:
383                 return "owe";
384         case CONNMAN_SERVICE_SECURITY_DPP:
385                 return "dpp";
386 #else
387         case CONNMAN_SERVICE_SECURITY_RSN:
388                 return "psk";
389 #endif
390         case CONNMAN_SERVICE_SECURITY_8021X:
391                 return "ieee8021x";
392         }
393
394         return NULL;
395 }
396
397 static const char *state2string(enum connman_service_state state)
398 {
399         switch (state) {
400         case CONNMAN_SERVICE_STATE_UNKNOWN:
401                 break;
402         case CONNMAN_SERVICE_STATE_IDLE:
403                 return "idle";
404         case CONNMAN_SERVICE_STATE_ASSOCIATION:
405                 return "association";
406         case CONNMAN_SERVICE_STATE_CONFIGURATION:
407                 return "configuration";
408         case CONNMAN_SERVICE_STATE_READY:
409                 return "ready";
410         case CONNMAN_SERVICE_STATE_ONLINE:
411                 return "online";
412         case CONNMAN_SERVICE_STATE_DISCONNECT:
413                 return "disconnect";
414         case CONNMAN_SERVICE_STATE_FAILURE:
415                 return "failure";
416         }
417
418         return NULL;
419 }
420
421 static const char *error2string(enum connman_service_error error)
422 {
423         switch (error) {
424         case CONNMAN_SERVICE_ERROR_UNKNOWN:
425                 break;
426         case CONNMAN_SERVICE_ERROR_OUT_OF_RANGE:
427                 return "out-of-range";
428         case CONNMAN_SERVICE_ERROR_PIN_MISSING:
429                 return "pin-missing";
430         case CONNMAN_SERVICE_ERROR_DHCP_FAILED:
431                 return "dhcp-failed";
432         case CONNMAN_SERVICE_ERROR_CONNECT_FAILED:
433                 return "connect-failed";
434         case CONNMAN_SERVICE_ERROR_LOGIN_FAILED:
435                 return "login-failed";
436         case CONNMAN_SERVICE_ERROR_AUTH_FAILED:
437                 return "auth-failed";
438         case CONNMAN_SERVICE_ERROR_INVALID_KEY:
439                 return "invalid-key";
440         case CONNMAN_SERVICE_ERROR_BLOCKED:
441                 return "blocked";
442         }
443
444         return NULL;
445 }
446
447 static const char *proxymethod2string(enum connman_service_proxy_method method)
448 {
449         switch (method) {
450         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
451                 return "direct";
452         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
453                 return "manual";
454         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
455                 return "auto";
456         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
457                 break;
458         }
459
460         return NULL;
461 }
462
463 static enum connman_service_proxy_method string2proxymethod(const char *method)
464 {
465         if (g_strcmp0(method, "direct") == 0)
466                 return CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
467         else if (g_strcmp0(method, "auto") == 0)
468                 return CONNMAN_SERVICE_PROXY_METHOD_AUTO;
469         else if (g_strcmp0(method, "manual") == 0)
470                 return CONNMAN_SERVICE_PROXY_METHOD_MANUAL;
471         else
472                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
473 }
474
475 #ifdef TIZEN_EXT
476 static const char *__connman_dnsconfig_method2string(enum connman_dnsconfig_method method)
477 {
478         switch (method) {
479         case CONNMAN_DNSCONFIG_METHOD_UNKNOWN:
480                 return "unknown";
481         case CONNMAN_DNSCONFIG_METHOD_MANUAL:
482                 return "manual";
483         case CONNMAN_DNSCONFIG_METHOD_DHCP:
484                 return "dhcp";
485         }
486
487         return NULL;
488 }
489
490 static enum connman_dnsconfig_method __connman_dnsconfig_string2method(
491                 const char *method)
492 {
493         if (g_strcmp0(method, "manual") == 0)
494                 return CONNMAN_DNSCONFIG_METHOD_MANUAL;
495         else if (g_strcmp0(method, "dhcp") == 0)
496                 return CONNMAN_DNSCONFIG_METHOD_DHCP;
497         else
498                 return CONNMAN_DNSCONFIG_METHOD_UNKNOWN;
499 }
500 #endif
501
502 static void set_split_routing(struct connman_service *service, bool value)
503 {
504         if (service->type != CONNMAN_SERVICE_TYPE_VPN)
505                 return;
506
507         service->do_split_routing = value;
508
509         if (service->do_split_routing)
510                 service->order = 0;
511         else
512                 service->order = 10;
513 }
514
515 int __connman_service_load_modifiable(struct connman_service *service)
516 {
517         GKeyFile *keyfile;
518         GError *error = NULL;
519         gchar *str;
520         bool autoconnect;
521
522         DBG("service %p", service);
523
524         keyfile = connman_storage_load_service(service->identifier);
525         if (!keyfile)
526                 return -EIO;
527
528         switch (service->type) {
529         case CONNMAN_SERVICE_TYPE_UNKNOWN:
530         case CONNMAN_SERVICE_TYPE_SYSTEM:
531         case CONNMAN_SERVICE_TYPE_GPS:
532         case CONNMAN_SERVICE_TYPE_P2P:
533 #if defined TIZEN_EXT_WIFI_MESH
534         case CONNMAN_SERVICE_TYPE_MESH:
535 #endif
536                 break;
537         case CONNMAN_SERVICE_TYPE_VPN:
538                 set_split_routing(service, g_key_file_get_boolean(keyfile,
539                                                         service->identifier,
540                                                         "SplitRouting", NULL));
541
542                 /* fall through */
543         case CONNMAN_SERVICE_TYPE_WIFI:
544         case CONNMAN_SERVICE_TYPE_GADGET:
545         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
546         case CONNMAN_SERVICE_TYPE_CELLULAR:
547         case CONNMAN_SERVICE_TYPE_ETHERNET:
548                 autoconnect = g_key_file_get_boolean(keyfile,
549                                 service->identifier, "AutoConnect", &error);
550                 if (!error)
551                         service->autoconnect = autoconnect;
552                 g_clear_error(&error);
553                 break;
554         }
555
556         str = g_key_file_get_string(keyfile,
557                                 service->identifier, "Modified", NULL);
558         if (str) {
559                 g_time_val_from_iso8601(str, &service->modified);
560                 g_free(str);
561         }
562
563         g_key_file_free(keyfile);
564
565         return 0;
566 }
567
568 static int service_load(struct connman_service *service)
569 {
570         GKeyFile *keyfile;
571         GError *error = NULL;
572         gsize length;
573         gchar *str;
574         bool autoconnect;
575         unsigned int ssid_len;
576         int err = 0;
577
578         DBG("service %p", service);
579
580         keyfile = connman_storage_load_service(service->identifier);
581         if (!keyfile) {
582                 service->new_service = true;
583                 return -EIO;
584         } else
585                 service->new_service = false;
586
587         switch (service->type) {
588         case CONNMAN_SERVICE_TYPE_UNKNOWN:
589         case CONNMAN_SERVICE_TYPE_SYSTEM:
590         case CONNMAN_SERVICE_TYPE_GPS:
591         case CONNMAN_SERVICE_TYPE_P2P:
592 #if defined TIZEN_EXT_WIFI_MESH
593         case CONNMAN_SERVICE_TYPE_MESH:
594 #endif
595                 break;
596         case CONNMAN_SERVICE_TYPE_VPN:
597                 set_split_routing(service, g_key_file_get_boolean(keyfile,
598                                                         service->identifier,
599                                                         "SplitRouting", NULL));
600
601                 autoconnect = g_key_file_get_boolean(keyfile,
602                                 service->identifier, "AutoConnect", &error);
603                 if (!error)
604                         service->autoconnect = autoconnect;
605                 g_clear_error(&error);
606                 break;
607         case CONNMAN_SERVICE_TYPE_WIFI:
608                 if (!service->name) {
609                         gchar *name;
610
611                         name = g_key_file_get_string(keyfile,
612                                         service->identifier, "Name", NULL);
613                         if (name) {
614                                 g_free(service->name);
615                                 service->name = name;
616                         }
617
618                         if (service->network)
619                                 connman_network_set_name(service->network,
620                                                                         name);
621                 }
622
623                 if (service->network &&
624                                 !connman_network_get_blob(service->network,
625                                                 "WiFi.SSID", &ssid_len)) {
626                         gchar *hex_ssid;
627
628                         hex_ssid = g_key_file_get_string(keyfile,
629                                                         service->identifier,
630                                                                 "SSID", NULL);
631
632                         if (hex_ssid) {
633                                 gchar *ssid;
634                                 unsigned int i, j = 0, hex;
635                                 size_t hex_ssid_len = strlen(hex_ssid);
636
637                                 ssid = g_try_malloc0(hex_ssid_len / 2);
638                                 if (!ssid) {
639                                         g_free(hex_ssid);
640                                         err = -ENOMEM;
641                                         goto done;
642                                 }
643
644                                 for (i = 0; i < hex_ssid_len; i += 2) {
645                                         sscanf(hex_ssid + i, "%02x", &hex);
646                                         ssid[j++] = hex;
647                                 }
648
649                                 connman_network_set_blob(service->network,
650                                         "WiFi.SSID", ssid, hex_ssid_len / 2);
651
652                                 g_free(ssid);
653                         }
654
655                         g_free(hex_ssid);
656                 }
657                 /* fall through */
658
659         case CONNMAN_SERVICE_TYPE_GADGET:
660         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
661         case CONNMAN_SERVICE_TYPE_CELLULAR:
662                 service->favorite = g_key_file_get_boolean(keyfile,
663                                 service->identifier, "Favorite", NULL);
664
665                 /* fall through */
666
667         case CONNMAN_SERVICE_TYPE_ETHERNET:
668                 autoconnect = g_key_file_get_boolean(keyfile,
669                                 service->identifier, "AutoConnect", &error);
670                 if (!error)
671                         service->autoconnect = autoconnect;
672                 g_clear_error(&error);
673                 break;
674         }
675
676         str = g_key_file_get_string(keyfile,
677                                 service->identifier, "Modified", NULL);
678         if (str) {
679                 g_time_val_from_iso8601(str, &service->modified);
680                 g_free(str);
681         }
682
683         str = g_key_file_get_string(keyfile,
684                                 service->identifier, "Passphrase", NULL);
685         if (str) {
686                 g_free(service->passphrase);
687                 service->passphrase = str;
688         }
689
690         if (service->ipconfig_ipv4)
691                 __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
692                                         service->identifier, "IPv4.");
693
694         if (service->ipconfig_ipv6)
695                 __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
696                                         service->identifier, "IPv6.");
697
698         service->nameservers_config = g_key_file_get_string_list(keyfile,
699                         service->identifier, "Nameservers", &length, NULL);
700         if (service->nameservers_config && length == 0) {
701                 g_strfreev(service->nameservers_config);
702                 service->nameservers_config = NULL;
703         }
704
705 #ifdef TIZEN_EXT
706         char *dns_method;
707
708         dns_method = g_key_file_get_string(keyfile, service->identifier,
709                         "Nameservers.IPv4method", NULL);
710         if (dns_method) {
711                 service->dns_config_method_ipv4 = __connman_dnsconfig_string2method(dns_method);
712                 g_free(dns_method);
713         }
714
715         dns_method = g_key_file_get_string(keyfile, service->identifier,
716                         "Nameservers.IPv6method", NULL);
717         if (dns_method) {
718                 service->dns_config_method_ipv6 = __connman_dnsconfig_string2method(dns_method);
719                 g_free(dns_method);
720         }
721 #endif
722
723         service->timeservers_config = g_key_file_get_string_list(keyfile,
724                         service->identifier, "Timeservers", &length, NULL);
725         if (service->timeservers_config && length == 0) {
726                 g_strfreev(service->timeservers_config);
727                 service->timeservers_config = NULL;
728         }
729
730         service->domains = g_key_file_get_string_list(keyfile,
731                         service->identifier, "Domains", &length, NULL);
732         if (service->domains && length == 0) {
733                 g_strfreev(service->domains);
734                 service->domains = NULL;
735         }
736
737         str = g_key_file_get_string(keyfile,
738                                 service->identifier, "Proxy.Method", NULL);
739         if (str)
740                 service->proxy_config = string2proxymethod(str);
741
742         g_free(str);
743
744         service->proxies = g_key_file_get_string_list(keyfile,
745                         service->identifier, "Proxy.Servers", &length, NULL);
746         if (service->proxies && length == 0) {
747                 g_strfreev(service->proxies);
748                 service->proxies = NULL;
749         }
750
751         service->excludes = g_key_file_get_string_list(keyfile,
752                         service->identifier, "Proxy.Excludes", &length, NULL);
753         if (service->excludes && length == 0) {
754                 g_strfreev(service->excludes);
755                 service->excludes = NULL;
756         }
757
758         str = g_key_file_get_string(keyfile,
759                                 service->identifier, "Proxy.URL", NULL);
760         if (str) {
761                 g_free(service->pac);
762                 service->pac = str;
763         }
764
765         service->mdns_config = g_key_file_get_boolean(keyfile,
766                                 service->identifier, "mDNS", NULL);
767
768         service->hidden_service = g_key_file_get_boolean(keyfile,
769                                         service->identifier, "Hidden", NULL);
770
771 #if defined TIZEN_EXT
772         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
773                         service->security == CONNMAN_SERVICE_SECURITY_8021X) {
774                 str = g_key_file_get_string(keyfile,
775                                 service->identifier, "EAP", NULL);
776                 if (str != NULL) {
777                         g_free(service->eap);
778                         service->eap = str;
779                 }
780
781                 str = g_key_file_get_string(keyfile,
782                                 service->identifier, "Phase2", NULL);
783                 if (str != NULL) {
784                         g_free(service->phase2);
785                         service->phase2 = str;
786                 }
787
788                 str = g_key_file_get_string(keyfile,
789                                 service->identifier, "Identity", NULL);
790                 if (str != NULL) {
791                         g_free(service->identity);
792                         service->identity = str;
793                 }
794
795                 str = g_key_file_get_string(keyfile,
796                                 service->identifier, "CACertFile", NULL);
797                 if (str != NULL) {
798                         g_free(service->ca_cert_file);
799                         service->ca_cert_file = str;
800                 }
801
802                 str = g_key_file_get_string(keyfile,
803                                 service->identifier, "ClientCertFile", NULL);
804                 if (str != NULL) {
805                         g_free(service->client_cert_file);
806                         service->client_cert_file = str;
807                 }
808
809                 str = g_key_file_get_string(keyfile,
810                                 service->identifier, "PrivateKeyFile", NULL);
811                 if (str != NULL) {
812                         g_free(service->private_key_file);
813                         service->private_key_file = str;
814                 }
815
816                 str = g_key_file_get_string(keyfile,
817                                 service->identifier, "PrivateKeyPassphrase", NULL);
818                 if (str != NULL) {
819                         g_free(service->private_key_passphrase);
820                         service->private_key_passphrase = str;
821                 }
822         }
823 #endif
824 #if defined TIZEN_EXT
825         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
826                         service->security == CONNMAN_SERVICE_SECURITY_DPP) {
827                 str = g_key_file_get_string(keyfile,
828                                 service->identifier, "Connector", NULL);
829                 if (str != NULL) {
830                         g_free(service->connector);
831                         service->connector = str;
832                 }
833                 str = g_key_file_get_string(keyfile,
834                                 service->identifier, "CSignKey", NULL);
835                 if (str != NULL) {
836                         g_free(service->c_sign_key);
837                         service->c_sign_key = str;
838                 }
839                 str = g_key_file_get_string(keyfile,
840                                 service->identifier, "NetAccessKey", NULL);
841                 if (str != NULL) {
842                         g_free(service->net_access_key);
843                         service->net_access_key = str;
844                 }
845         }
846 #endif
847
848 done:
849         g_key_file_free(keyfile);
850
851         return err;
852 }
853
854 static int service_save(struct connman_service *service)
855 {
856         GKeyFile *keyfile;
857         gchar *str;
858         guint freq;
859         const char *cst_str = NULL;
860         int err = 0;
861
862         DBG("service %p new %d", service, service->new_service);
863
864         if (service->new_service)
865                 return -ESRCH;
866
867         keyfile = __connman_storage_open_service(service->identifier);
868         if (!keyfile)
869                 return -EIO;
870
871         if (service->name)
872                 g_key_file_set_string(keyfile, service->identifier,
873                                                 "Name", service->name);
874
875         switch (service->type) {
876         case CONNMAN_SERVICE_TYPE_UNKNOWN:
877         case CONNMAN_SERVICE_TYPE_SYSTEM:
878         case CONNMAN_SERVICE_TYPE_GPS:
879         case CONNMAN_SERVICE_TYPE_P2P:
880 #if defined TIZEN_EXT_WIFI_MESH
881         case CONNMAN_SERVICE_TYPE_MESH:
882 #endif
883                 break;
884         case CONNMAN_SERVICE_TYPE_VPN:
885                 g_key_file_set_boolean(keyfile, service->identifier,
886                                 "SplitRouting", service->do_split_routing);
887                 if (service->favorite)
888                         g_key_file_set_boolean(keyfile, service->identifier,
889                                         "AutoConnect", service->autoconnect);
890                 break;
891         case CONNMAN_SERVICE_TYPE_WIFI:
892                 if (service->network) {
893                         const unsigned char *ssid;
894                         unsigned int ssid_len = 0;
895
896                         ssid = connman_network_get_blob(service->network,
897                                                         "WiFi.SSID", &ssid_len);
898
899                         if (ssid && ssid_len > 0 && ssid[0] != '\0') {
900                                 char *identifier = service->identifier;
901                                 GString *ssid_str;
902                                 unsigned int i;
903
904                                 ssid_str = g_string_sized_new(ssid_len * 2);
905                                 if (!ssid_str) {
906                                         err = -ENOMEM;
907                                         goto done;
908                                 }
909
910                                 for (i = 0; i < ssid_len; i++)
911                                         g_string_append_printf(ssid_str,
912                                                         "%02x", ssid[i]);
913
914                                 g_key_file_set_string(keyfile, identifier,
915                                                         "SSID", ssid_str->str);
916
917                                 g_string_free(ssid_str, TRUE);
918                         }
919
920                         freq = connman_network_get_frequency(service->network);
921                         g_key_file_set_integer(keyfile, service->identifier,
922                                                 "Frequency", freq);
923                 }
924                 /* fall through */
925
926         case CONNMAN_SERVICE_TYPE_GADGET:
927         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
928         case CONNMAN_SERVICE_TYPE_CELLULAR:
929                 g_key_file_set_boolean(keyfile, service->identifier,
930                                         "Favorite", service->favorite);
931
932                 g_key_file_remove_key(keyfile, service->identifier,
933                                 "Failure", NULL);
934
935                 /* fall through */
936
937         case CONNMAN_SERVICE_TYPE_ETHERNET:
938                 if (service->favorite)
939                         g_key_file_set_boolean(keyfile, service->identifier,
940                                         "AutoConnect", service->autoconnect);
941                 break;
942         }
943
944         str = g_time_val_to_iso8601(&service->modified);
945         if (str) {
946                 g_key_file_set_string(keyfile, service->identifier,
947                                                         "Modified", str);
948                 g_free(str);
949         }
950
951         if (service->passphrase && strlen(service->passphrase) > 0)
952                 g_key_file_set_string(keyfile, service->identifier,
953                                         "Passphrase", service->passphrase);
954         else
955                 g_key_file_remove_key(keyfile, service->identifier,
956                                                         "Passphrase", NULL);
957
958         if (service->ipconfig_ipv4)
959                 __connman_ipconfig_save(service->ipconfig_ipv4, keyfile,
960                                         service->identifier, "IPv4.");
961
962         if (service->ipconfig_ipv6)
963                 __connman_ipconfig_save(service->ipconfig_ipv6, keyfile,
964                                                 service->identifier, "IPv6.");
965
966         if (service->nameservers_config) {
967                 guint len = g_strv_length(service->nameservers_config);
968
969                 g_key_file_set_string_list(keyfile, service->identifier,
970                                                                 "Nameservers",
971                                 (const gchar **) service->nameservers_config, len);
972         } else
973         g_key_file_remove_key(keyfile, service->identifier,
974                                                         "Nameservers", NULL);
975
976 #if defined TIZEN_EXT
977         if(service->dns_config_method_ipv4 != 0) {
978                 const char *method;
979                 method = __connman_dnsconfig_method2string(
980                                 service->dns_config_method_ipv4);
981                 g_key_file_set_string(keyfile, service->identifier,
982                                 "Nameservers.IPv4method", method);
983         } else
984         g_key_file_remove_key(keyfile, service->identifier,
985                                                 "Nameservers.IPv4method", NULL);
986
987         if(service->dns_config_method_ipv6 != 0) {
988                 const char *method;
989                 method = __connman_dnsconfig_method2string(
990                                 service->dns_config_method_ipv6);
991                 g_key_file_set_string(keyfile, service->identifier,
992                                 "Nameservers.IPv6method", method);
993         } else
994         g_key_file_remove_key(keyfile, service->identifier,
995                                                         "Nameservers.IPv6method", NULL);
996 #endif
997
998         if (service->timeservers_config) {
999                 guint len = g_strv_length(service->timeservers_config);
1000
1001                 g_key_file_set_string_list(keyfile, service->identifier,
1002                                                                 "Timeservers",
1003                                 (const gchar **) service->timeservers_config, len);
1004         } else
1005                 g_key_file_remove_key(keyfile, service->identifier,
1006                                                         "Timeservers", NULL);
1007
1008         if (service->domains) {
1009                 guint len = g_strv_length(service->domains);
1010
1011                 g_key_file_set_string_list(keyfile, service->identifier,
1012                                                                 "Domains",
1013                                 (const gchar **) service->domains, len);
1014         } else
1015                 g_key_file_remove_key(keyfile, service->identifier,
1016                                                         "Domains", NULL);
1017
1018         cst_str = proxymethod2string(service->proxy_config);
1019         if (cst_str)
1020                 g_key_file_set_string(keyfile, service->identifier,
1021                                 "Proxy.Method", cst_str);
1022
1023         if (service->proxies) {
1024                 guint len = g_strv_length(service->proxies);
1025
1026                 g_key_file_set_string_list(keyfile, service->identifier,
1027                                 "Proxy.Servers",
1028                                 (const gchar **) service->proxies, len);
1029         } else
1030                 g_key_file_remove_key(keyfile, service->identifier,
1031                                                 "Proxy.Servers", NULL);
1032
1033         if (service->excludes) {
1034                 guint len = g_strv_length(service->excludes);
1035
1036                 g_key_file_set_string_list(keyfile, service->identifier,
1037                                 "Proxy.Excludes",
1038                                 (const gchar **) service->excludes, len);
1039         } else
1040                 g_key_file_remove_key(keyfile, service->identifier,
1041                                                 "Proxy.Excludes", NULL);
1042
1043         if (service->pac && strlen(service->pac) > 0)
1044                 g_key_file_set_string(keyfile, service->identifier,
1045                                         "Proxy.URL", service->pac);
1046         else
1047                 g_key_file_remove_key(keyfile, service->identifier,
1048                                                         "Proxy.URL", NULL);
1049
1050         if (service->mdns_config)
1051                 g_key_file_set_boolean(keyfile, service->identifier,
1052                                                                 "mDNS", TRUE);
1053         else
1054                 g_key_file_remove_key(keyfile, service->identifier,
1055                                                                 "mDNS", NULL);
1056
1057         if (service->hidden_service)
1058                 g_key_file_set_boolean(keyfile, service->identifier, "Hidden",
1059                                                                         TRUE);
1060
1061         if (service->config_file && strlen(service->config_file) > 0)
1062                 g_key_file_set_string(keyfile, service->identifier,
1063                                 "Config.file", service->config_file);
1064
1065         if (service->config_entry &&
1066                                         strlen(service->config_entry) > 0)
1067                 g_key_file_set_string(keyfile, service->identifier,
1068                                 "Config.ident", service->config_entry);
1069
1070 #if defined TIZEN_EXT
1071         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
1072                         service->security == CONNMAN_SERVICE_SECURITY_8021X) {
1073                 if (service->eap != NULL && strlen(service->eap) > 0)
1074                         g_key_file_set_string(keyfile, service->identifier,
1075                                         "EAP", service->eap);
1076                 else
1077                         g_key_file_remove_key(keyfile, service->identifier,
1078                                         "EAP", NULL);
1079
1080                 if (service->phase2 != NULL && strlen(service->phase2) > 0)
1081                         g_key_file_set_string(keyfile, service->identifier,
1082                                         "Phase2", service->phase2);
1083                 else
1084                         g_key_file_remove_key(keyfile, service->identifier,
1085                                         "Phase2", NULL);
1086
1087                 if (service->identity != NULL && strlen(service->identity) > 0)
1088                         g_key_file_set_string(keyfile, service->identifier,
1089                                         "Identity", service->identity);
1090                 else
1091                         g_key_file_remove_key(keyfile, service->identifier,
1092                                         "Identity", NULL);
1093
1094                 if (service->ca_cert_file != NULL && strlen(service->ca_cert_file) > 0)
1095                         g_key_file_set_string(keyfile, service->identifier,
1096                                         "CACertFile", service->ca_cert_file);
1097                 else
1098                         g_key_file_remove_key(keyfile, service->identifier,
1099                                         "CACertFile", NULL);
1100
1101                 if (service->client_cert_file != NULL && strlen(service->client_cert_file) > 0)
1102                         g_key_file_set_string(keyfile, service->identifier,
1103                                         "ClientCertFile", service->client_cert_file);
1104                 else
1105                         g_key_file_remove_key(keyfile, service->identifier,
1106                                         "ClientCertFile", NULL);
1107
1108                 if (service->private_key_file != NULL && strlen(service->private_key_file) > 0)
1109                         g_key_file_set_string(keyfile, service->identifier,
1110                                         "PrivateKeyFile", service->private_key_file);
1111                 else
1112                         g_key_file_remove_key(keyfile, service->identifier,
1113                                         "PrivateKeyFile", NULL);
1114
1115                 if (service->private_key_passphrase != NULL && strlen(service->private_key_passphrase) > 0)
1116                         g_key_file_set_string(keyfile, service->identifier,
1117                                         "PrivateKeyPassphrase", service->private_key_passphrase);
1118                 else
1119                         g_key_file_remove_key(keyfile, service->identifier,
1120                                         "PrivateKeyPassphrase", NULL);
1121         }
1122         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
1123                         service->security == CONNMAN_SERVICE_SECURITY_DPP) {
1124                 if (service->connector != NULL && strlen(service->connector) > 0)
1125                         g_key_file_set_string(keyfile, service->identifier,
1126                                         "Connector", service->connector);
1127                 else
1128                         g_key_file_remove_key(keyfile, service->identifier,
1129                                         "Connector", NULL);
1130
1131                 if (service->c_sign_key != NULL && strlen(service->c_sign_key) > 0)
1132                         g_key_file_set_string(keyfile, service->identifier,
1133                                         "CSignKey", service->c_sign_key);
1134                 else
1135                         g_key_file_remove_key(keyfile, service->identifier,
1136                                         "CSignKey", NULL);
1137
1138                 if (service->net_access_key != NULL && strlen(service->net_access_key) > 0)
1139                         g_key_file_set_string(keyfile, service->identifier,
1140                                         "NetAccessKey", service->net_access_key);
1141                 else
1142                         g_key_file_remove_key(keyfile, service->identifier,
1143                                         "NetAccessKey", NULL);
1144         }
1145 #endif
1146
1147 done:
1148         __connman_storage_save_service(keyfile, service->identifier);
1149
1150         g_key_file_free(keyfile);
1151
1152         return err;
1153 }
1154
1155 void __connman_service_save(struct connman_service *service)
1156 {
1157         if (!service)
1158                 return;
1159
1160         service_save(service);
1161 }
1162
1163 static enum connman_service_state combine_state(
1164                                         enum connman_service_state state_a,
1165                                         enum connman_service_state state_b)
1166 {
1167         enum connman_service_state result;
1168
1169         if (state_a == state_b) {
1170                 result = state_a;
1171                 goto done;
1172         }
1173
1174         if (state_a == CONNMAN_SERVICE_STATE_UNKNOWN) {
1175                 result = state_b;
1176                 goto done;
1177         }
1178
1179         if (state_b == CONNMAN_SERVICE_STATE_UNKNOWN) {
1180                 result = state_a;
1181                 goto done;
1182         }
1183
1184         if (state_a == CONNMAN_SERVICE_STATE_IDLE) {
1185                 result = state_b;
1186                 goto done;
1187         }
1188
1189         if (state_b == CONNMAN_SERVICE_STATE_IDLE) {
1190                 result = state_a;
1191                 goto done;
1192         }
1193
1194         if (state_a == CONNMAN_SERVICE_STATE_ONLINE) {
1195                 result = state_a;
1196                 goto done;
1197         }
1198
1199         if (state_b == CONNMAN_SERVICE_STATE_ONLINE) {
1200                 result = state_b;
1201                 goto done;
1202         }
1203
1204         if (state_a == CONNMAN_SERVICE_STATE_READY) {
1205                 result = state_a;
1206                 goto done;
1207         }
1208
1209         if (state_b == CONNMAN_SERVICE_STATE_READY) {
1210                 result = state_b;
1211                 goto done;
1212         }
1213
1214         if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION) {
1215                 result = state_a;
1216                 goto done;
1217         }
1218
1219         if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION) {
1220                 result = state_b;
1221                 goto done;
1222         }
1223
1224         if (state_a == CONNMAN_SERVICE_STATE_ASSOCIATION) {
1225                 result = state_a;
1226                 goto done;
1227         }
1228
1229         if (state_b == CONNMAN_SERVICE_STATE_ASSOCIATION) {
1230                 result = state_b;
1231                 goto done;
1232         }
1233
1234         if (state_a == CONNMAN_SERVICE_STATE_DISCONNECT) {
1235                 result = state_a;
1236                 goto done;
1237         }
1238
1239         if (state_b == CONNMAN_SERVICE_STATE_DISCONNECT) {
1240                 result = state_b;
1241                 goto done;
1242         }
1243
1244         result = CONNMAN_SERVICE_STATE_FAILURE;
1245
1246 done:
1247         return result;
1248 }
1249
1250 static bool is_connecting(enum connman_service_state state)
1251 {
1252         switch (state) {
1253         case CONNMAN_SERVICE_STATE_UNKNOWN:
1254         case CONNMAN_SERVICE_STATE_IDLE:
1255         case CONNMAN_SERVICE_STATE_FAILURE:
1256         case CONNMAN_SERVICE_STATE_DISCONNECT:
1257         case CONNMAN_SERVICE_STATE_READY:
1258         case CONNMAN_SERVICE_STATE_ONLINE:
1259                 break;
1260         case CONNMAN_SERVICE_STATE_ASSOCIATION:
1261         case CONNMAN_SERVICE_STATE_CONFIGURATION:
1262                 return true;
1263         }
1264
1265         return false;
1266 }
1267
1268 static bool is_connected(enum connman_service_state state)
1269 {
1270         switch (state) {
1271         case CONNMAN_SERVICE_STATE_UNKNOWN:
1272         case CONNMAN_SERVICE_STATE_IDLE:
1273         case CONNMAN_SERVICE_STATE_ASSOCIATION:
1274         case CONNMAN_SERVICE_STATE_CONFIGURATION:
1275         case CONNMAN_SERVICE_STATE_DISCONNECT:
1276         case CONNMAN_SERVICE_STATE_FAILURE:
1277                 break;
1278         case CONNMAN_SERVICE_STATE_READY:
1279         case CONNMAN_SERVICE_STATE_ONLINE:
1280                 return true;
1281         }
1282
1283         return false;
1284 }
1285
1286 static bool is_idle(enum connman_service_state state)
1287 {
1288         switch (state) {
1289         case CONNMAN_SERVICE_STATE_IDLE:
1290         case CONNMAN_SERVICE_STATE_DISCONNECT:
1291         case CONNMAN_SERVICE_STATE_FAILURE:
1292                 return true;
1293         case CONNMAN_SERVICE_STATE_UNKNOWN:
1294         case CONNMAN_SERVICE_STATE_ASSOCIATION:
1295         case CONNMAN_SERVICE_STATE_CONFIGURATION:
1296         case CONNMAN_SERVICE_STATE_READY:
1297         case CONNMAN_SERVICE_STATE_ONLINE:
1298                 break;
1299         }
1300
1301         return false;
1302 }
1303
1304 static int nameservers_changed_cb(void *user_data)
1305 {
1306         struct connman_service *service = user_data;
1307
1308         DBG("service %p", service);
1309
1310         service->nameservers_timeout = 0;
1311         if ((is_idle(service->state) && !service->nameservers) ||
1312                         is_connected(service->state))
1313                 dns_changed(service);
1314
1315         return FALSE;
1316 }
1317
1318 static void nameservers_changed(struct connman_service *service)
1319 {
1320         if (!service->nameservers_timeout)
1321                 service->nameservers_timeout = g_idle_add(nameservers_changed_cb,
1322                                                         service);
1323 }
1324
1325 static bool nameserver_available(struct connman_service *service,
1326                                 enum connman_ipconfig_type type,
1327                                 const char *ns)
1328 {
1329         int family;
1330
1331         family = connman_inet_check_ipaddress(ns);
1332
1333         if (family == AF_INET) {
1334                 if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
1335                         return false;
1336
1337                 return is_connected(service->state_ipv4);
1338         }
1339
1340         if (family == AF_INET6) {
1341                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
1342                         return false;
1343
1344                 return is_connected(service->state_ipv6);
1345         }
1346
1347         return false;
1348 }
1349
1350 static int searchdomain_add_all(struct connman_service *service)
1351 {
1352         int index, i = 0;
1353
1354         if (!is_connected(service->state))
1355                 return -ENOTCONN;
1356
1357         index = __connman_service_get_index(service);
1358         if (index < 0)
1359                 return -ENXIO;
1360
1361         if (service->domains) {
1362                 while (service->domains[i]) {
1363                         connman_resolver_append(index, service->domains[i],
1364                                                 NULL);
1365                         i++;
1366                 }
1367
1368                 return 0;
1369         }
1370
1371         if (service->domainname)
1372                 connman_resolver_append(index, service->domainname, NULL);
1373
1374         return 0;
1375
1376 }
1377
1378 static int searchdomain_remove_all(struct connman_service *service)
1379 {
1380         int index, i = 0;
1381
1382         if (!is_connected(service->state))
1383                 return -ENOTCONN;
1384
1385         index = __connman_service_get_index(service);
1386         if (index < 0)
1387                 return -ENXIO;
1388
1389         while (service->domains && service->domains[i]) {
1390                 connman_resolver_remove(index, service->domains[i], NULL);
1391                 i++;
1392         }
1393
1394         if (service->domainname)
1395                 connman_resolver_remove(index, service->domainname, NULL);
1396
1397         return 0;
1398 }
1399
1400 static int nameserver_add(struct connman_service *service,
1401                         enum connman_ipconfig_type type,
1402                         const char *nameserver)
1403 {
1404         int index, ret;
1405
1406         if (!nameserver_available(service, type, nameserver))
1407                 return 0;
1408
1409         index = __connman_service_get_index(service);
1410         if (index < 0)
1411                 return -ENXIO;
1412
1413 #if defined TIZEN_EXT
1414         DBG("Resolver append nameserver: %s", nameserver);
1415 #endif
1416         ret = connman_resolver_append(index, NULL, nameserver);
1417         if (ret >= 0)
1418                 nameservers_changed(service);
1419
1420         return ret;
1421 }
1422
1423 static int nameserver_add_all(struct connman_service *service,
1424                         enum connman_ipconfig_type type)
1425 {
1426         int i = 0;
1427
1428         if (service->nameservers_config) {
1429                 while (service->nameservers_config[i]) {
1430 #if defined TIZEN_EXT
1431                         DBG("type %d add service->nameservers_config[%d]:%s",type,
1432                             i, service->nameservers_config[i]);
1433                         if(strncmp(service->nameservers_config[i], "::", 2) == 0) {
1434                                 DBG("Invalid nameserver");
1435                                 i++;
1436                                 continue;
1437                         }
1438
1439                         switch(type) {
1440                         case CONNMAN_IPCONFIG_TYPE_IPV4:
1441                                 if (connman_inet_check_ipaddress(
1442                                         service->nameservers_config[i]) == AF_INET &&
1443                                     service->dns_config_method_ipv4 ==
1444                                     CONNMAN_DNSCONFIG_METHOD_MANUAL) {
1445                                         nameserver_add(service, type,
1446                                                        service->nameservers_config[i]);
1447                                 }
1448                                 break;
1449                         case CONNMAN_IPCONFIG_TYPE_IPV6:
1450                                 if (connman_inet_check_ipaddress(
1451                                         service->nameservers_config[i]) == AF_INET6 &&
1452                                     service->dns_config_method_ipv6 ==
1453                                         CONNMAN_DNSCONFIG_METHOD_MANUAL) {
1454                                         nameserver_add(service, type,
1455                                                        service->nameservers_config[i]);
1456                                 }
1457                                 break;
1458                         case CONNMAN_IPCONFIG_TYPE_ALL:
1459                                 if (connman_inet_check_ipaddress(
1460                                         service->nameservers_config[i]) == AF_INET &&
1461                                     service->dns_config_method_ipv4 ==
1462                                         CONNMAN_DNSCONFIG_METHOD_MANUAL) {
1463                                         nameserver_add(service, type,
1464                                                        service->nameservers_config[i]);
1465                                 }
1466                                 if (connman_inet_check_ipaddress(
1467                                         service->nameservers_config[i]) == AF_INET6 &&
1468                                     service->dns_config_method_ipv6 ==
1469                                         CONNMAN_DNSCONFIG_METHOD_MANUAL) {
1470                                         nameserver_add(service, type,
1471                                                        service->nameservers_config[i]);
1472                                 }
1473                                 break;
1474                         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
1475                                 DBG("CONNMAN_IPCONFIG_TYPE_UNKNOWN do nothing");
1476                                 break;
1477                         default:
1478                                 DBG("default case do nothing");
1479                                 break;
1480                         }
1481 #else
1482                         nameserver_add(service, type,
1483                                 service->nameservers_config[i]);
1484 #endif
1485                         i++;
1486                 }
1487         } else if (service->nameservers) {
1488                 while (service->nameservers[i]) {
1489 #if defined TIZEN_EXT
1490                         DBG("type %d service->nameservers[%d]: %s",type,
1491                             i, service->nameservers[i]);
1492
1493                         switch(type) {
1494                         case CONNMAN_IPCONFIG_TYPE_IPV4:
1495                                 if (connman_inet_check_ipaddress(
1496                                         service->nameservers[i]) == AF_INET &&
1497                                         service->dns_config_method_ipv4 ==
1498                                                 CONNMAN_DNSCONFIG_METHOD_DHCP) {
1499                                         nameserver_add(service, type,
1500                                                        service->nameservers[i]);
1501                                 }
1502                                 break;
1503                         case CONNMAN_IPCONFIG_TYPE_IPV6:
1504                                 if (connman_inet_check_ipaddress(
1505                                         service->nameservers[i]) == AF_INET6 &&
1506                                         service->dns_config_method_ipv6 ==
1507                                                 CONNMAN_DNSCONFIG_METHOD_DHCP) {
1508                                         nameserver_add(service, type,
1509                                                        service->nameservers[i]);
1510                                 }
1511                                 break;
1512                         case CONNMAN_IPCONFIG_TYPE_ALL:
1513                                 if (connman_inet_check_ipaddress(
1514                                         service->nameservers[i]) == AF_INET &&
1515                                         service->dns_config_method_ipv4 ==
1516                                                 CONNMAN_DNSCONFIG_METHOD_DHCP) {
1517                                         nameserver_add(service, type,
1518                                                        service->nameservers[i]);
1519                                 }
1520                                 if (connman_inet_check_ipaddress(
1521                                         service->nameservers[i]) == AF_INET6 &&
1522                                         service->dns_config_method_ipv6 ==
1523                                                 CONNMAN_DNSCONFIG_METHOD_DHCP) {
1524                                         nameserver_add(service, type,
1525                                                        service->nameservers[i]);
1526                                 }
1527                                 break;
1528                         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
1529                                 DBG("CONNMAN_IPCONFIG_TYPE_UNKNOWN do nothing");
1530                                 break;
1531                         default:
1532                                 DBG("default case do nothing");
1533                                 break;
1534                         }
1535 #else
1536                         nameserver_add(service, type,
1537                                 service->nameservers[i]);
1538 #endif
1539                         i++;
1540                 }
1541         }
1542
1543         if (!i)
1544                 __connman_resolver_append_fallback_nameservers();
1545
1546 #if defined TIZEN_EXT
1547         const char *global_dns = connman_option_get_string("GlobalNameserver");
1548         if (global_dns)
1549                 nameserver_add(service, type, global_dns);
1550 #endif
1551
1552         searchdomain_add_all(service);
1553
1554         return 0;
1555 }
1556
1557 static int nameserver_remove(struct connman_service *service,
1558                         enum connman_ipconfig_type type,
1559                         const char *nameserver)
1560 {
1561         int index, ret;
1562
1563         if (!nameserver_available(service, type, nameserver))
1564                 return 0;
1565
1566         index = __connman_service_get_index(service);
1567         if (index < 0)
1568                 return -ENXIO;
1569
1570 #if defined TIZEN_EXT
1571         DBG("Resolver remove nameserver: %s", nameserver);
1572 #endif
1573         ret = connman_resolver_remove(index, NULL, nameserver);
1574         if (ret >= 0)
1575                 nameservers_changed(service);
1576
1577         return ret;
1578 }
1579
1580 static int nameserver_remove_all(struct connman_service *service,
1581                                 enum connman_ipconfig_type type)
1582 {
1583 #if defined TIZEN_EXT
1584         /**
1585           * Skip this function if there is any connected profiles
1586           * that use same interface
1587           */
1588         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
1589                         __connman_service_get_connected_count_of_iface(service) > 0)
1590                 return 0;
1591 #endif
1592         int index, i = 0;
1593
1594         index = __connman_service_get_index(service);
1595         if (index < 0)
1596                 return -ENXIO;
1597
1598         while (service->nameservers_config && service->nameservers_config[i]) {
1599
1600 #if defined TIZEN_EXT
1601                 DBG("type %d Remove service->nameservers_config[%d]: %s",
1602                       type, i, service->nameservers_config[i]);
1603                 switch(type) {
1604                 case CONNMAN_IPCONFIG_TYPE_IPV4:
1605                         if (connman_inet_check_ipaddress(
1606                                 service->nameservers_config[i]) == AF_INET &&
1607                                 (service->dns_config_method_ipv4 ==
1608                                         CONNMAN_DNSCONFIG_METHOD_DHCP ||
1609                                 service->dns_config_method_ipv4 ==
1610                                         CONNMAN_DNSCONFIG_METHOD_MANUAL)) {
1611                                 nameserver_remove(service, type,
1612                                                   service->nameservers_config[i]);
1613                         }
1614                         break;
1615                 case CONNMAN_IPCONFIG_TYPE_IPV6:
1616                         if (connman_inet_check_ipaddress(
1617                                 service->nameservers_config[i]) == AF_INET6 &&
1618                                 (service->dns_config_method_ipv6 ==
1619                                         CONNMAN_DNSCONFIG_METHOD_DHCP ||
1620                                 service->dns_config_method_ipv6 ==
1621                                         CONNMAN_DNSCONFIG_METHOD_MANUAL)) {
1622                                 nameserver_remove(service, type,
1623                                                   service->nameservers_config[i]);
1624                         }
1625                         break;
1626                 case CONNMAN_IPCONFIG_TYPE_ALL:
1627                         if (connman_inet_check_ipaddress(
1628                                 service->nameservers_config[i]) == AF_INET &&
1629                                 (service->dns_config_method_ipv4 ==
1630                                         CONNMAN_DNSCONFIG_METHOD_DHCP ||
1631                                 service->dns_config_method_ipv4 ==
1632                                         CONNMAN_DNSCONFIG_METHOD_MANUAL)) {
1633                                 nameserver_remove(service, type,
1634                                                   service->nameservers_config[i]);
1635                         }
1636                         if (connman_inet_check_ipaddress(
1637                                 service->nameservers_config[i]) == AF_INET6 &&
1638                                 (service->dns_config_method_ipv6 ==
1639                                         CONNMAN_DNSCONFIG_METHOD_DHCP ||
1640                                 service->dns_config_method_ipv6 ==
1641                                         CONNMAN_DNSCONFIG_METHOD_MANUAL)) {
1642                                 nameserver_remove(service, type,
1643                                                   service->nameservers_config[i]);
1644                         }
1645                         break;
1646                 case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
1647                         DBG("CONNMAN_IPCONFIG_TYPE_UNKNOWN do nothing");
1648                         break;
1649                 default:
1650                         DBG("default case do nothing");
1651                         break;
1652                 }
1653 #else
1654                 nameserver_remove(service, type,
1655                                 service->nameservers_config[i]);
1656 #endif
1657                 i++;
1658         }
1659
1660         i = 0;
1661         while (service->nameservers && service->nameservers[i]) {
1662 #if defined TIZEN_EXT
1663                 DBG("type %d Remove service->nameservers[%d]: %s",type, i,
1664                       service->nameservers[i]);
1665                 switch(type) {
1666                         case CONNMAN_IPCONFIG_TYPE_IPV4:
1667                                 if (connman_inet_check_ipaddress(
1668                                         service->nameservers[i]) == AF_INET &&
1669                                         (service->dns_config_method_ipv4 ==
1670                                                 CONNMAN_DNSCONFIG_METHOD_MANUAL ||
1671                                         service->dns_config_method_ipv4 ==
1672                                                 CONNMAN_DNSCONFIG_METHOD_DHCP)) {
1673                                         nameserver_remove(service, type,
1674                                                           service->nameservers[i]);
1675                                 }
1676                                 break;
1677                         case CONNMAN_IPCONFIG_TYPE_IPV6:
1678                                 if (connman_inet_check_ipaddress(
1679                                         service->nameservers[i]) == AF_INET6 &&
1680                                         (service->dns_config_method_ipv6 ==
1681                                                 CONNMAN_DNSCONFIG_METHOD_MANUAL ||
1682                                         service->dns_config_method_ipv6 ==
1683                                                 CONNMAN_DNSCONFIG_METHOD_DHCP)) {
1684                                         nameserver_remove(service, type,
1685                                                           service->nameservers[i]);
1686                                 }
1687                                 break;
1688                         case CONNMAN_IPCONFIG_TYPE_ALL:
1689                                 if (connman_inet_check_ipaddress(
1690                                         service->nameservers[i]) == AF_INET &&
1691                                         (service->dns_config_method_ipv4 ==
1692                                                 CONNMAN_DNSCONFIG_METHOD_MANUAL ||
1693                                         service->dns_config_method_ipv4 ==
1694                                                 CONNMAN_DNSCONFIG_METHOD_DHCP)) {
1695                                         nameserver_remove(service, type,
1696                                                           service->nameservers[i]);
1697                                 }
1698                                 if (connman_inet_check_ipaddress(
1699                                         service->nameservers[i]) == AF_INET6 &&
1700                                         (service->dns_config_method_ipv6 ==
1701                                                 CONNMAN_DNSCONFIG_METHOD_MANUAL ||
1702                                         service->dns_config_method_ipv6 ==
1703                                                 CONNMAN_DNSCONFIG_METHOD_DHCP)) {
1704                                         nameserver_remove(service, type,
1705                                                           service->nameservers[i]);
1706                                 }
1707                                 break;
1708                         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
1709                                 DBG("CONNMAN_IPCONFIG_TYPE_UNKNOWN do nothing");
1710                                 break;
1711                         default:
1712                                 DBG("default case do nothing");
1713                                 break;
1714                 }
1715 #else
1716                 nameserver_remove(service, type, service->nameservers[i]);
1717 #endif
1718                 i++;
1719         }
1720
1721 #if defined TIZEN_EXT
1722         const char *global_dns = connman_option_get_string("GlobalNameserver");
1723         if (global_dns)
1724                 nameserver_remove(service, type, global_dns);
1725 #endif
1726         searchdomain_remove_all(service);
1727
1728         return 0;
1729 }
1730
1731 /*
1732  * The is_auto variable is set to true when IPv6 autoconf nameservers are
1733  * inserted to resolver via netlink message (see rtnl.c:rtnl_newnduseropt()
1734  * for details) and not through service.c
1735  */
1736 #if defined TIZEN_EXT
1737 int __connman_service_nameserver_append(struct connman_service *service,
1738                                 const char *nameserver, bool is_auto,
1739                                 enum connman_ipconfig_type type)
1740 #else
1741 int __connman_service_nameserver_append(struct connman_service *service,
1742                                 const char *nameserver, bool is_auto)
1743 #endif
1744 {
1745         char **nameservers;
1746         int len, i;
1747
1748         DBG("service %p nameserver %s auto %d", service, nameserver, is_auto);
1749
1750         if (!nameserver)
1751                 return -EINVAL;
1752
1753         if (is_auto)
1754                 nameservers = service->nameservers_auto;
1755         else
1756                 nameservers = service->nameservers;
1757
1758         for (i = 0; nameservers && nameservers[i]; i++)
1759 #if defined TIZEN_EXT
1760         {
1761                 DBG("nameservers[%d] %s, nameserver %s", i, nameservers[i], nameserver);
1762 #endif
1763                 if (g_strcmp0(nameservers[i], nameserver) == 0)
1764                         return -EEXIST;
1765 #if defined TIZEN_EXT
1766         }
1767 #endif
1768
1769         if (nameservers) {
1770                 len = g_strv_length(nameservers);
1771                 nameservers = g_try_renew(char *, nameservers, len + 2);
1772         } else {
1773                 len = 0;
1774                 nameservers = g_try_new0(char *, len + 2);
1775         }
1776
1777         if (!nameservers)
1778                 return -ENOMEM;
1779
1780         nameservers[len] = g_strdup(nameserver);
1781         nameservers[len + 1] = NULL;
1782
1783 #ifdef TIZEN_EXT
1784         if(type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
1785            service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_UNKNOWN)
1786                 service->dns_config_method_ipv4 = CONNMAN_DNSCONFIG_METHOD_DHCP;
1787
1788         if(type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
1789            service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_UNKNOWN)
1790                 service->dns_config_method_ipv6 = CONNMAN_DNSCONFIG_METHOD_DHCP;
1791 #endif
1792
1793         if (is_auto) {
1794                 service->nameservers_auto = nameservers;
1795         } else {
1796                 service->nameservers = nameservers;
1797                 nameserver_add(service, CONNMAN_IPCONFIG_TYPE_ALL, nameserver);
1798         }
1799
1800         nameservers_changed(service);
1801
1802         searchdomain_add_all(service);
1803
1804         return 0;
1805 }
1806
1807 #if defined TIZEN_EXT
1808 int __connman_service_nameserver_remove(struct connman_service *service,
1809                                 const char *nameserver, bool is_auto,
1810                                 enum connman_ipconfig_type type)
1811 #else
1812 int __connman_service_nameserver_remove(struct connman_service *service,
1813                                 const char *nameserver, bool is_auto)
1814 #endif
1815 {
1816         char **servers, **nameservers;
1817         bool found = false;
1818         int len, i, j;
1819
1820         DBG("service %p nameserver %s auto %d", service, nameserver, is_auto);
1821
1822         if (!nameserver)
1823                 return -EINVAL;
1824
1825         if (is_auto)
1826                 nameservers = service->nameservers_auto;
1827         else
1828                 nameservers = service->nameservers;
1829
1830         if (!nameservers)
1831                 return 0;
1832
1833         for (i = 0; nameservers[i]; i++)
1834                 if (g_strcmp0(nameservers[i], nameserver) == 0) {
1835                         found = true;
1836                         break;
1837                 }
1838
1839         if (!found)
1840                 return 0;
1841
1842         len = g_strv_length(nameservers);
1843
1844         if (len == 1) {
1845                 servers = NULL;
1846                 goto set_servers;
1847         }
1848
1849         servers = g_try_new0(char *, len);
1850         if (!servers)
1851                 return -ENOMEM;
1852
1853         for (i = 0, j = 0; i < len; i++) {
1854                 if (g_strcmp0(nameservers[i], nameserver)) {
1855                         servers[j] = nameservers[i];
1856                         j++;
1857                 } else
1858                         g_free(nameservers[i]);
1859
1860                 nameservers[i] = NULL;
1861         }
1862         servers[len - 1] = NULL;
1863
1864 set_servers:
1865         g_strfreev(nameservers);
1866         nameservers = servers;
1867
1868         if (is_auto) {
1869                 service->nameservers_auto = nameservers;
1870         } else {
1871                 service->nameservers = nameservers;
1872 #if defined TIZEN_EXT
1873                 DBG("nameserver remove ip_type: %d", type);
1874                 nameserver_remove(service, type,
1875                                 nameserver);
1876 #else
1877                 nameserver_remove(service, CONNMAN_IPCONFIG_TYPE_ALL,
1878                                 nameserver);
1879 #endif
1880         }
1881
1882         return 0;
1883 }
1884
1885 void __connman_service_nameserver_clear(struct connman_service *service)
1886 {
1887         nameserver_remove_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
1888
1889         g_strfreev(service->nameservers);
1890         service->nameservers = NULL;
1891
1892         nameserver_add_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
1893 }
1894
1895 static void add_nameserver_route(int family, int index, char *nameserver,
1896                                 const char *gw)
1897 {
1898         switch (family) {
1899         case AF_INET:
1900                 if (connman_inet_compare_subnet(index, nameserver))
1901                         break;
1902
1903                 if (connman_inet_add_host_route(index, nameserver, gw) < 0)
1904                         /* For P-t-P link the above route add will fail */
1905                         connman_inet_add_host_route(index, nameserver, NULL);
1906                 break;
1907
1908         case AF_INET6:
1909                 if (connman_inet_add_ipv6_host_route(index, nameserver,
1910                                                                 gw) < 0)
1911                         connman_inet_add_ipv6_host_route(index, nameserver,
1912                                                         NULL);
1913                 break;
1914         }
1915 }
1916
1917 static void nameserver_add_routes(int index, char **nameservers,
1918                                         const char *gw)
1919 {
1920         int i, ns_family, gw_family;
1921
1922         gw_family = connman_inet_check_ipaddress(gw);
1923         if (gw_family < 0)
1924                 return;
1925
1926         for (i = 0; nameservers[i]; i++) {
1927                 ns_family = connman_inet_check_ipaddress(nameservers[i]);
1928                 if (ns_family < 0 || ns_family != gw_family)
1929                         continue;
1930
1931                 add_nameserver_route(ns_family, index, nameservers[i], gw);
1932         }
1933 }
1934
1935 static void nameserver_del_routes(int index, char **nameservers,
1936                                 enum connman_ipconfig_type type)
1937 {
1938         int i, family;
1939
1940         for (i = 0; nameservers[i]; i++) {
1941                 family = connman_inet_check_ipaddress(nameservers[i]);
1942                 if (family < 0)
1943                         continue;
1944
1945                 switch (family) {
1946                 case AF_INET:
1947                         if (type != CONNMAN_IPCONFIG_TYPE_IPV6)
1948                                 connman_inet_del_host_route(index,
1949                                                         nameservers[i]);
1950                         break;
1951                 case AF_INET6:
1952                         if (type != CONNMAN_IPCONFIG_TYPE_IPV4)
1953                                 connman_inet_del_ipv6_host_route(index,
1954                                                         nameservers[i]);
1955                         break;
1956                 }
1957         }
1958 }
1959
1960 void __connman_service_nameserver_add_routes(struct connman_service *service,
1961                                                 const char *gw)
1962 {
1963         int index;
1964
1965         if (!service)
1966                 return;
1967
1968         index = __connman_service_get_index(service);
1969
1970         if (service->nameservers_config) {
1971                 /*
1972                  * Configured nameserver takes preference over the
1973                  * discoverd nameserver gathered from DHCP, VPN, etc.
1974                  */
1975                 nameserver_add_routes(index, service->nameservers_config, gw);
1976         } else if (service->nameservers) {
1977                 /*
1978                  * We add nameservers host routes for nameservers that
1979                  * are not on our subnet. For those who are, the subnet
1980                  * route will be installed by the time the dns proxy code
1981                  * tries to reach them. The subnet route is installed
1982                  * when setting the interface IP address.
1983                  */
1984                 nameserver_add_routes(index, service->nameservers, gw);
1985         }
1986 }
1987
1988 void __connman_service_nameserver_del_routes(struct connman_service *service,
1989                                         enum connman_ipconfig_type type)
1990 {
1991         int index;
1992
1993         if (!service)
1994                 return;
1995
1996         index = __connman_service_get_index(service);
1997
1998         if (service->nameservers_config)
1999                 nameserver_del_routes(index, service->nameservers_config,
2000                                         type);
2001         else if (service->nameservers)
2002                 nameserver_del_routes(index, service->nameservers, type);
2003 }
2004
2005 static void address_updated(struct connman_service *service,
2006                         enum connman_ipconfig_type type)
2007 {
2008         if (is_connected(service->state) &&
2009                         service == connman_service_get_default()) {
2010                 nameserver_remove_all(service, type);
2011                 nameserver_add_all(service, type);
2012
2013                 __connman_timeserver_sync(service);
2014         }
2015 }
2016
2017 static struct connman_stats *stats_get(struct connman_service *service)
2018 {
2019         if (service->roaming)
2020                 return &service->stats_roaming;
2021         else
2022                 return &service->stats;
2023 }
2024
2025 static bool stats_enabled(struct connman_service *service)
2026 {
2027         struct connman_stats *stats = stats_get(service);
2028
2029         return stats->enabled;
2030 }
2031
2032 static void stats_start(struct connman_service *service)
2033 {
2034         struct connman_stats *stats = stats_get(service);
2035
2036         DBG("service %p", service);
2037
2038         if (!stats->timer)
2039                 return;
2040
2041         stats->enabled = true;
2042         stats->data_last.time = stats->data.time;
2043
2044         g_timer_start(stats->timer);
2045 }
2046
2047 static void stats_stop(struct connman_service *service)
2048 {
2049         struct connman_stats *stats = stats_get(service);
2050         unsigned int seconds;
2051
2052         DBG("service %p", service);
2053
2054         if (!stats->timer)
2055                 return;
2056
2057         if (!stats->enabled)
2058                 return;
2059
2060         g_timer_stop(stats->timer);
2061
2062         seconds = g_timer_elapsed(stats->timer, NULL);
2063         stats->data.time = stats->data_last.time + seconds;
2064
2065         stats->enabled = false;
2066 }
2067
2068 static void reset_stats(struct connman_service *service)
2069 {
2070         DBG("service %p", service);
2071
2072         /* home */
2073         service->stats.valid = false;
2074
2075         service->stats.data.rx_packets = 0;
2076         service->stats.data.tx_packets = 0;
2077         service->stats.data.rx_bytes = 0;
2078         service->stats.data.tx_bytes = 0;
2079         service->stats.data.rx_errors = 0;
2080         service->stats.data.tx_errors = 0;
2081         service->stats.data.rx_dropped = 0;
2082         service->stats.data.tx_dropped = 0;
2083         service->stats.data.time = 0;
2084         service->stats.data_last.time = 0;
2085
2086         g_timer_reset(service->stats.timer);
2087
2088         /* roaming */
2089         service->stats_roaming.valid = false;
2090
2091         service->stats_roaming.data.rx_packets = 0;
2092         service->stats_roaming.data.tx_packets = 0;
2093         service->stats_roaming.data.rx_bytes = 0;
2094         service->stats_roaming.data.tx_bytes = 0;
2095         service->stats_roaming.data.rx_errors = 0;
2096         service->stats_roaming.data.tx_errors = 0;
2097         service->stats_roaming.data.rx_dropped = 0;
2098         service->stats_roaming.data.tx_dropped = 0;
2099         service->stats_roaming.data.time = 0;
2100         service->stats_roaming.data_last.time = 0;
2101
2102         g_timer_reset(service->stats_roaming.timer);
2103 }
2104
2105 #if defined TIZEN_EXT
2106 static gboolean __connman_service_is_internet_profile(
2107                 struct connman_service *cellular)
2108 {
2109         const char internet_suffix[] = "_1";
2110
2111         DBG("Service path: %s", cellular->path);
2112
2113         if (g_str_has_suffix(cellular->path, internet_suffix) == TRUE)
2114                 return TRUE;
2115
2116         return FALSE;
2117 }
2118
2119 struct connman_service *connman_service_get_default_connection(void)
2120 {
2121         GList *list;
2122         struct connman_service *service;
2123         struct connman_service *default_service = NULL;
2124
2125         for (list = service_list; list; list = list->next) {
2126                 service = list->data;
2127
2128                 DBG("service: %p %s %s %s", service, service->name,
2129                                 state2string(service->state),
2130                                 __connman_service_type2string(service->type));
2131
2132 #if defined TIZEN_MAINTAIN_ONLINE
2133                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
2134                                 service->state == CONNMAN_SERVICE_STATE_ONLINE) {
2135 #else
2136                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
2137                                 is_connected(service->state) == TRUE) {
2138 #endif
2139                         return service;
2140                 } else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
2141                                 __connman_service_is_internet_profile(service) == TRUE) {
2142                         if (default_service == NULL)
2143                                 default_service = service;
2144                         else if (is_connected(service->state) == TRUE &&
2145                                         is_connected(default_service->state) == FALSE)
2146                                 default_service = service;
2147                 } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET &&
2148                                 is_connected(service->state) == TRUE) {
2149                         if (default_service == NULL)
2150                                 default_service = service;
2151                 } else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH &&
2152                                 is_connected(service->state) == TRUE) {
2153                         if (default_service == NULL)
2154                                 default_service = service;
2155                 }
2156         }
2157
2158         return default_service;
2159 }
2160 #endif
2161
2162 struct connman_service *connman_service_get_default(void)
2163 {
2164 #if defined TIZEN_MAINTAIN_ONLINE
2165         return connman_service_get_default_connection();
2166 #else
2167         struct connman_service *service;
2168
2169         if (!service_list)
2170                 return NULL;
2171
2172         service = service_list->data;
2173
2174         if (!is_connected(service->state))
2175                 return NULL;
2176
2177         return service;
2178 #endif
2179 }
2180
2181 bool __connman_service_index_is_default(int index)
2182 {
2183         struct connman_service *service;
2184
2185         if (index < 0)
2186                 return false;
2187
2188         service = connman_service_get_default();
2189
2190         return __connman_service_get_index(service) == index;
2191 }
2192
2193 static void default_changed(void)
2194 {
2195         struct connman_service *service = connman_service_get_default();
2196
2197         if (service == current_default)
2198                 return;
2199
2200         DBG("current default %p %s", current_default,
2201                 current_default ? current_default->identifier : "");
2202         DBG("new default %p %s", service, service ? service->identifier : "");
2203
2204 #if defined TIZEN_EXT
2205         current_default = service;
2206
2207         __connman_service_timeserver_changed(service, NULL);
2208 #else
2209         __connman_service_timeserver_changed(current_default, NULL);
2210
2211         current_default = service;
2212 #endif
2213
2214         if (service) {
2215                 if (service->hostname &&
2216                                 connman_setting_get_bool("AllowHostnameUpdates"))
2217                         __connman_utsname_set_hostname(service->hostname);
2218
2219                 if (service->domainname &&
2220                                 connman_setting_get_bool("AllowDomainnameUpdates"))
2221                         __connman_utsname_set_domainname(service->domainname);
2222         }
2223
2224         __connman_notifier_default_changed(service);
2225 }
2226
2227 static void state_changed(struct connman_service *service)
2228 {
2229         const char *str;
2230
2231         __connman_notifier_service_state_changed(service, service->state);
2232
2233         str = state2string(service->state);
2234         if (!str)
2235                 return;
2236
2237 #if !defined TIZEN_EXT
2238         if (!allow_property_changed(service))
2239                 return;
2240
2241 #endif
2242 #if defined TIZEN_EXT
2243         DBG(" %s, %s", str, service->path);
2244 #endif
2245         connman_dbus_property_changed_basic(service->path,
2246                                 CONNMAN_SERVICE_INTERFACE, "State",
2247                                                 DBUS_TYPE_STRING, &str);
2248 }
2249
2250 #if defined TIZEN_EXT
2251 static void connect_reason_changed(struct connman_service *service)
2252 {
2253         if (!service->path)
2254                 return;
2255
2256         if (!allow_property_changed(service))
2257                 return;
2258
2259         connman_dbus_property_changed_basic(service->path,
2260                                             CONNMAN_SERVICE_INTERFACE,
2261                                             "ConnectReason",
2262                                             DBUS_TYPE_INT32,
2263                                             &service->connect_reason);
2264 }
2265
2266 static void disconnection_requested_changed(struct connman_service *service)
2267 {
2268         dbus_bool_t disconnection_requested;
2269
2270         if (!service->path)
2271                 return;
2272
2273         if (!allow_property_changed(service))
2274                 return;
2275
2276         disconnection_requested = service->disconnection_requested;
2277         connman_dbus_property_changed_basic(service->path,
2278                                             CONNMAN_SERVICE_INTERFACE,
2279                                             "DisconnectionRequested",
2280                                             DBUS_TYPE_BOOLEAN,
2281                                             &disconnection_requested);
2282 }
2283
2284 void connman_service_set_disconnection_requested(struct connman_service *service,
2285                                                  bool disconnection_requested)
2286 {
2287         if (service == NULL)
2288                 return;
2289
2290         service->disconnection_requested = disconnection_requested;
2291         disconnection_requested_changed(service);
2292 }
2293 #endif
2294
2295 static void strength_changed(struct connman_service *service)
2296 {
2297         if (service->strength == 0)
2298                 return;
2299
2300         if (!allow_property_changed(service))
2301                 return;
2302
2303         connman_dbus_property_changed_basic(service->path,
2304                                 CONNMAN_SERVICE_INTERFACE, "Strength",
2305                                         DBUS_TYPE_BYTE, &service->strength);
2306 }
2307
2308 static void favorite_changed(struct connman_service *service)
2309 {
2310         dbus_bool_t favorite;
2311
2312         if (!service->path)
2313                 return;
2314
2315         if (!allow_property_changed(service))
2316                 return;
2317
2318         favorite = service->favorite;
2319         connman_dbus_property_changed_basic(service->path,
2320                                 CONNMAN_SERVICE_INTERFACE, "Favorite",
2321                                         DBUS_TYPE_BOOLEAN, &favorite);
2322 }
2323
2324 static void immutable_changed(struct connman_service *service)
2325 {
2326         dbus_bool_t immutable;
2327
2328         if (!service->path)
2329                 return;
2330
2331         if (!allow_property_changed(service))
2332                 return;
2333
2334         immutable = service->immutable;
2335         connman_dbus_property_changed_basic(service->path,
2336                                 CONNMAN_SERVICE_INTERFACE, "Immutable",
2337                                         DBUS_TYPE_BOOLEAN, &immutable);
2338 }
2339
2340 static void roaming_changed(struct connman_service *service)
2341 {
2342         dbus_bool_t roaming;
2343
2344         if (!service->path)
2345                 return;
2346
2347         if (!allow_property_changed(service))
2348                 return;
2349
2350         roaming = service->roaming;
2351         connman_dbus_property_changed_basic(service->path,
2352                                 CONNMAN_SERVICE_INTERFACE, "Roaming",
2353                                         DBUS_TYPE_BOOLEAN, &roaming);
2354 }
2355
2356 static void autoconnect_changed(struct connman_service *service)
2357 {
2358         dbus_bool_t autoconnect;
2359
2360         if (!service->path)
2361                 return;
2362
2363         if (!allow_property_changed(service))
2364                 return;
2365
2366         autoconnect = service->autoconnect;
2367         connman_dbus_property_changed_basic(service->path,
2368                                 CONNMAN_SERVICE_INTERFACE, "AutoConnect",
2369                                 DBUS_TYPE_BOOLEAN, &autoconnect);
2370 }
2371
2372 static void append_security(DBusMessageIter *iter, void *user_data)
2373 {
2374         struct connman_service *service = user_data;
2375         const char *str;
2376
2377         str = security2string(service->security);
2378         if (str)
2379                 dbus_message_iter_append_basic(iter,
2380                                 DBUS_TYPE_STRING, &str);
2381
2382         /*
2383          * Some access points incorrectly advertise WPS even when they
2384          * are configured as open or no security, so filter
2385          * appropriately.
2386          */
2387         if (service->wps) {
2388                 switch (service->security) {
2389                 case CONNMAN_SERVICE_SECURITY_PSK:
2390                 case CONNMAN_SERVICE_SECURITY_WPA:
2391                 case CONNMAN_SERVICE_SECURITY_RSN:
2392 #if defined TIZEN_EXT
2393                 case CONNMAN_SERVICE_SECURITY_SAE:
2394 #endif
2395                         str = "wps";
2396                         dbus_message_iter_append_basic(iter,
2397                                                 DBUS_TYPE_STRING, &str);
2398                         break;
2399 #if defined TIZEN_EXT
2400                 case CONNMAN_SERVICE_SECURITY_OWE:
2401 #endif
2402                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
2403                 case CONNMAN_SERVICE_SECURITY_NONE:
2404                 case CONNMAN_SERVICE_SECURITY_WEP:
2405                 case CONNMAN_SERVICE_SECURITY_8021X:
2406                         break;
2407                 }
2408
2409                 if (service->wps_advertizing) {
2410                         str = "wps_advertising";
2411                         dbus_message_iter_append_basic(iter,
2412                                                 DBUS_TYPE_STRING, &str);
2413                 }
2414         }
2415 }
2416
2417 static void security_changed(struct connman_service *service)
2418 {
2419         if (!service->path)
2420                 return;
2421
2422         if (!allow_property_changed(service))
2423                 return;
2424
2425         connman_dbus_property_changed_array(service->path,
2426                                 CONNMAN_SERVICE_INTERFACE, "Security",
2427                                 DBUS_TYPE_STRING, append_security, service);
2428 }
2429
2430 static void append_ethernet(DBusMessageIter *iter, void *user_data)
2431 {
2432         struct connman_service *service = user_data;
2433
2434         if (service->ipconfig_ipv4)
2435                 __connman_ipconfig_append_ethernet(service->ipconfig_ipv4,
2436                                                                         iter);
2437         else if (service->ipconfig_ipv6)
2438                 __connman_ipconfig_append_ethernet(service->ipconfig_ipv6,
2439                                                                         iter);
2440 }
2441
2442 static void append_ipv4(DBusMessageIter *iter, void *user_data)
2443 {
2444         struct connman_service *service = user_data;
2445
2446         if (!is_connected(service->state_ipv4))
2447                 return;
2448
2449         if (service->ipconfig_ipv4)
2450                 __connman_ipconfig_append_ipv4(service->ipconfig_ipv4, iter);
2451 }
2452
2453 static void append_ipv6(DBusMessageIter *iter, void *user_data)
2454 {
2455         struct connman_service *service = user_data;
2456
2457         if (!is_connected(service->state_ipv6))
2458                 return;
2459
2460         if (service->ipconfig_ipv6)
2461                 __connman_ipconfig_append_ipv6(service->ipconfig_ipv6, iter,
2462                                                 service->ipconfig_ipv4);
2463 }
2464
2465 static void append_ipv4config(DBusMessageIter *iter, void *user_data)
2466 {
2467         struct connman_service *service = user_data;
2468
2469         if (service->ipconfig_ipv4)
2470                 __connman_ipconfig_append_ipv4config(service->ipconfig_ipv4,
2471                                                         iter);
2472 }
2473
2474 static void append_ipv6config(DBusMessageIter *iter, void *user_data)
2475 {
2476         struct connman_service *service = user_data;
2477
2478         if (service->ipconfig_ipv6)
2479                 __connman_ipconfig_append_ipv6config(service->ipconfig_ipv6,
2480                                                         iter);
2481 }
2482
2483 static void append_nameservers(DBusMessageIter *iter,
2484                 struct connman_service *service, char **servers)
2485 {
2486         int i;
2487         bool available = true;
2488
2489         for (i = 0; servers[i]; i++) {
2490                 if (service)
2491                         available = nameserver_available(service,
2492                                                 CONNMAN_IPCONFIG_TYPE_ALL,
2493                                                 servers[i]);
2494
2495                 if (available)
2496                         dbus_message_iter_append_basic(iter,
2497                                         DBUS_TYPE_STRING, &servers[i]);
2498         }
2499 }
2500
2501 #if defined TIZEN_EXT
2502 static void append_nameserver_manual(DBusMessageIter *iter,
2503                 struct connman_service *service, const char *server)
2504 {
2505         bool available = true;
2506
2507         if (service)
2508                 available = nameserver_available(service,
2509                                 CONNMAN_IPCONFIG_TYPE_ALL, server);
2510
2511         if (available)
2512                 dbus_message_iter_append_basic(iter,
2513                                 DBUS_TYPE_STRING, &server);
2514 }
2515
2516 static void append_nameserver_dhcp(DBusMessageIter *iter,
2517                 struct connman_service *service, const char *server)
2518 {
2519         bool available = true;
2520
2521         if (service)
2522                 available = nameserver_available(service,
2523                                 CONNMAN_IPCONFIG_TYPE_ALL, server);
2524
2525         if (available)
2526                 dbus_message_iter_append_basic(iter,
2527                                 DBUS_TYPE_STRING, &server);
2528 }
2529 #endif
2530
2531 static void append_dns(DBusMessageIter *iter, void *user_data)
2532 {
2533         struct connman_service *service = user_data;
2534 #if defined TIZEN_EXT
2535         int i;
2536 #endif
2537
2538         if (!is_connected(service->state))
2539                 return;
2540
2541 #ifdef TIZEN_EXT
2542         const char *str;
2543
2544         str = __connman_dnsconfig_method2string(service->dns_config_method_ipv4);
2545         if(str != NULL) {
2546                 char *str1 = g_strdup_printf("ipv4.%s", str);
2547                 dbus_message_iter_append_basic(iter,
2548                         DBUS_TYPE_STRING, &str1);
2549                 g_free(str1);
2550         }
2551
2552         str = __connman_dnsconfig_method2string(service->dns_config_method_ipv6);
2553         if(str != NULL) {
2554                 char *str1 = g_strdup_printf("ipv6.%s", str);
2555                 dbus_message_iter_append_basic(iter,
2556                         DBUS_TYPE_STRING, &str1);
2557                 g_free(str1);
2558         }
2559 #endif
2560
2561         if (service->nameservers_config) {
2562 #if defined TIZEN_EXT
2563                 i = 0;
2564                 while (service->nameservers_config[i]) {
2565                         if (connman_inet_check_ipaddress(
2566                                 service->nameservers_config[i]) == AF_INET &&
2567                                 service->dns_config_method_ipv4 ==
2568                                         CONNMAN_DNSCONFIG_METHOD_MANUAL) {
2569                                 append_nameserver_manual(iter, service,
2570                                                 service->nameservers_config[i]);
2571                         }
2572
2573                         if (connman_inet_check_ipaddress(
2574                                 service->nameservers_config[i]) == AF_INET6 &&
2575                                 service->dns_config_method_ipv6 ==
2576                                         CONNMAN_DNSCONFIG_METHOD_MANUAL) {
2577                                 append_nameserver_manual(iter, service,
2578                                                 service->nameservers_config[i]);
2579                         }
2580                         i++;
2581                 }
2582                 /* In case of mixed DNS Config Type one of IPv4/IPv6 can be
2583                  * dynamic while other is static so try to append the DNS
2584                  * Address which is dynamic also */
2585                 if (service->nameservers != NULL) {
2586                         i = 0;
2587                         while (service->nameservers[i]) {
2588                                 if (connman_inet_check_ipaddress(
2589                                         service->nameservers[i]) == AF_INET &&
2590                                         service->dns_config_method_ipv4 ==
2591                                                 CONNMAN_DNSCONFIG_METHOD_DHCP) {
2592                                         append_nameserver_dhcp(iter, service,
2593                                                         service->nameservers[i]);
2594                                 }
2595
2596                                 if (connman_inet_check_ipaddress(
2597                                         service->nameservers[i]) == AF_INET6 &&
2598                                         service->dns_config_method_ipv6 ==
2599                                                 CONNMAN_DNSCONFIG_METHOD_DHCP) {
2600                                         append_nameserver_dhcp(iter, service,
2601                                                         service->nameservers[i]);
2602                                 }
2603                                 i++;
2604                         }
2605                 }
2606 #else
2607                 append_nameservers(iter, service, service->nameservers_config);
2608 #endif
2609                 return;
2610         } else {
2611                 if (service->nameservers)
2612 #if defined TIZEN_EXT
2613                 {
2614                         i = 0;
2615                         while (service->nameservers[i]) {
2616                                 if (connman_inet_check_ipaddress(
2617                                         service->nameservers[i]) == AF_INET &&
2618                                         service->dns_config_method_ipv4 ==
2619                                                 CONNMAN_DNSCONFIG_METHOD_DHCP) {
2620                                         append_nameserver_dhcp(iter, service,
2621                                                         service->nameservers[i]);
2622                                 }
2623
2624                                 if (connman_inet_check_ipaddress(
2625                                         service->nameservers[i]) == AF_INET6 &&
2626                                         service->dns_config_method_ipv6 ==
2627                                                 CONNMAN_DNSCONFIG_METHOD_DHCP) {
2628                                         append_nameserver_dhcp(iter, service,
2629                                                         service->nameservers[i]);
2630                                 }
2631                                 i++;
2632                         }
2633                 }
2634 #else
2635                         append_nameservers(iter, service,
2636                                         service->nameservers);
2637 #endif
2638
2639                 if (service->nameservers_auto)
2640                         append_nameservers(iter, service,
2641                                         service->nameservers_auto);
2642
2643                 if (!service->nameservers && !service->nameservers_auto) {
2644                         char **ns;
2645
2646                         DBG("append fallback nameservers");
2647
2648                         ns = connman_setting_get_string_list("FallbackNameservers");
2649                         if (ns)
2650                                 append_nameservers(iter, service, ns);
2651                 }
2652         }
2653 }
2654
2655 static void append_dnsconfig(DBusMessageIter *iter, void *user_data)
2656 {
2657         struct connman_service *service = user_data;
2658
2659 #ifdef TIZEN_EXT
2660         /* Append DNS Config Type */
2661         const char *str;
2662         str = __connman_dnsconfig_method2string(service->dns_config_method_ipv4);
2663         if(str != NULL) {
2664                 char *str1 = g_strdup_printf("ipv4.%s", str);
2665                 dbus_message_iter_append_basic(iter,
2666                         DBUS_TYPE_STRING, &str1);
2667                 g_free(str1);
2668         }
2669
2670         str = __connman_dnsconfig_method2string(service->dns_config_method_ipv6);
2671         if(str != NULL) {
2672                 char *str1 = g_strdup_printf("ipv6.%s", str);
2673                 dbus_message_iter_append_basic(iter,
2674                         DBUS_TYPE_STRING, &str1);
2675                 g_free(str1);
2676         }
2677 #endif
2678
2679         if (!service->nameservers_config)
2680                 return;
2681
2682 #if defined TIZEN_EXT
2683         int i = 0;
2684         while (service->nameservers_config[i]) {
2685                 if (connman_inet_check_ipaddress(service->nameservers_config[i]) == AF_INET &&
2686                                 service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_MANUAL) {
2687                         append_nameserver_manual(iter, NULL, service->nameservers_config[i]);
2688                 }
2689
2690                 if (connman_inet_check_ipaddress(service->nameservers_config[i]) == AF_INET6 &&
2691                                 service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_MANUAL) {
2692                         append_nameserver_manual(iter, NULL, service->nameservers_config[i]);
2693                 }
2694                 i++;
2695         }
2696 #else
2697         append_nameservers(iter, NULL, service->nameservers_config);
2698 #endif
2699 }
2700
2701 static void append_ts(DBusMessageIter *iter, void *user_data)
2702 {
2703         GSList *list = user_data;
2704
2705         while (list) {
2706                 char *timeserver = list->data;
2707
2708                 if (timeserver)
2709                         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
2710                                         &timeserver);
2711
2712                 list = g_slist_next(list);
2713         }
2714 }
2715
2716 static void append_tsconfig(DBusMessageIter *iter, void *user_data)
2717 {
2718         struct connman_service *service = user_data;
2719         int i;
2720
2721         if (!service->timeservers_config)
2722                 return;
2723
2724         for (i = 0; service->timeservers_config[i]; i++) {
2725                 dbus_message_iter_append_basic(iter,
2726                                 DBUS_TYPE_STRING,
2727                                 &service->timeservers_config[i]);
2728         }
2729 }
2730
2731 static void append_domainconfig(DBusMessageIter *iter, void *user_data)
2732 {
2733         struct connman_service *service = user_data;
2734         int i;
2735
2736         if (!service->domains)
2737                 return;
2738
2739         for (i = 0; service->domains[i]; i++)
2740                 dbus_message_iter_append_basic(iter,
2741                                 DBUS_TYPE_STRING, &service->domains[i]);
2742 }
2743
2744 static void append_domain(DBusMessageIter *iter, void *user_data)
2745 {
2746         struct connman_service *service = user_data;
2747
2748         if (!is_connected(service->state) &&
2749                                 !is_connecting(service->state))
2750                 return;
2751
2752         if (service->domains)
2753                 append_domainconfig(iter, user_data);
2754         else if (service->domainname)
2755                 dbus_message_iter_append_basic(iter,
2756                                 DBUS_TYPE_STRING, &service->domainname);
2757 }
2758
2759 static void append_proxies(DBusMessageIter *iter, void *user_data)
2760 {
2761         struct connman_service *service = user_data;
2762         int i;
2763
2764         if (!service->proxies)
2765                 return;
2766
2767         for (i = 0; service->proxies[i]; i++)
2768                 dbus_message_iter_append_basic(iter,
2769                                 DBUS_TYPE_STRING, &service->proxies[i]);
2770 }
2771
2772 static void append_excludes(DBusMessageIter *iter, void *user_data)
2773 {
2774         struct connman_service *service = user_data;
2775         int i;
2776
2777         if (!service->excludes)
2778                 return;
2779
2780         for (i = 0; service->excludes[i]; i++)
2781                 dbus_message_iter_append_basic(iter,
2782                                 DBUS_TYPE_STRING, &service->excludes[i]);
2783 }
2784
2785 static void append_proxy(DBusMessageIter *iter, void *user_data)
2786 {
2787         struct connman_service *service = user_data;
2788         enum connman_service_proxy_method proxy;
2789         const char *pac = NULL;
2790         const char *method = proxymethod2string(
2791                 CONNMAN_SERVICE_PROXY_METHOD_DIRECT);
2792
2793         if (!is_connected(service->state))
2794                 return;
2795
2796         proxy = connman_service_get_proxy_method(service);
2797
2798         switch (proxy) {
2799         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
2800                 return;
2801         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
2802                 goto done;
2803         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
2804                 connman_dbus_dict_append_array(iter, "Servers",
2805                                         DBUS_TYPE_STRING, append_proxies,
2806                                         service);
2807
2808                 connman_dbus_dict_append_array(iter, "Excludes",
2809                                         DBUS_TYPE_STRING, append_excludes,
2810                                         service);
2811                 break;
2812         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
2813                 /* Maybe DHCP, or WPAD,  has provided an url for a pac file */
2814                 if (service->ipconfig_ipv4)
2815                         pac = __connman_ipconfig_get_proxy_autoconfig(
2816                                 service->ipconfig_ipv4);
2817                 else if (service->ipconfig_ipv6)
2818                         pac = __connman_ipconfig_get_proxy_autoconfig(
2819                                 service->ipconfig_ipv6);
2820
2821                 if (!service->pac && !pac)
2822                         goto done;
2823
2824                 if (service->pac)
2825                         pac = service->pac;
2826
2827                 connman_dbus_dict_append_basic(iter, "URL",
2828                                         DBUS_TYPE_STRING, &pac);
2829                 break;
2830         }
2831
2832         method = proxymethod2string(proxy);
2833
2834 done:
2835         connman_dbus_dict_append_basic(iter, "Method",
2836                                         DBUS_TYPE_STRING, &method);
2837 }
2838
2839 static void append_proxyconfig(DBusMessageIter *iter, void *user_data)
2840 {
2841         struct connman_service *service = user_data;
2842         const char *method;
2843
2844         if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
2845                 return;
2846
2847         switch (service->proxy_config) {
2848         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
2849                 return;
2850         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
2851                 break;
2852         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
2853                 if (service->proxies)
2854                         connman_dbus_dict_append_array(iter, "Servers",
2855                                                 DBUS_TYPE_STRING,
2856                                                 append_proxies, service);
2857
2858                 if (service->excludes)
2859                         connman_dbus_dict_append_array(iter, "Excludes",
2860                                                 DBUS_TYPE_STRING,
2861                                                 append_excludes, service);
2862                 break;
2863         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
2864                 if (service->pac)
2865                         connman_dbus_dict_append_basic(iter, "URL",
2866                                         DBUS_TYPE_STRING, &service->pac);
2867                 break;
2868         }
2869
2870         method = proxymethod2string(service->proxy_config);
2871
2872         connman_dbus_dict_append_basic(iter, "Method",
2873                                 DBUS_TYPE_STRING, &method);
2874 }
2875
2876 static void append_provider(DBusMessageIter *iter, void *user_data)
2877 {
2878         struct connman_service *service = user_data;
2879
2880         if (!is_connected(service->state))
2881                 return;
2882
2883         if (service->provider)
2884                 __connman_provider_append_properties(service->provider, iter);
2885 }
2886
2887
2888 static void settings_changed(struct connman_service *service,
2889                                 struct connman_ipconfig *ipconfig)
2890 {
2891         enum connman_ipconfig_type type;
2892
2893         type = __connman_ipconfig_get_config_type(ipconfig);
2894
2895         __connman_notifier_ipconfig_changed(service, ipconfig);
2896
2897         if (!allow_property_changed(service))
2898                 return;
2899
2900         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
2901                 connman_dbus_property_changed_dict(service->path,
2902                                         CONNMAN_SERVICE_INTERFACE, "IPv4",
2903                                         append_ipv4, service);
2904         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
2905                 connman_dbus_property_changed_dict(service->path,
2906                                         CONNMAN_SERVICE_INTERFACE, "IPv6",
2907                                         append_ipv6, service);
2908 }
2909
2910 static void ipv4_configuration_changed(struct connman_service *service)
2911 {
2912         if (!allow_property_changed(service))
2913                 return;
2914
2915         connman_dbus_property_changed_dict(service->path,
2916                                         CONNMAN_SERVICE_INTERFACE,
2917                                                         "IPv4.Configuration",
2918                                                         append_ipv4config,
2919                                                         service);
2920 }
2921
2922 void __connman_service_notify_ipv4_configuration(
2923                                         struct connman_service *service)
2924 {
2925         if (!service)
2926                 return;
2927
2928         ipv4_configuration_changed(service);
2929 }
2930
2931 static void ipv6_configuration_changed(struct connman_service *service)
2932 {
2933         if (!allow_property_changed(service))
2934                 return;
2935
2936         connman_dbus_property_changed_dict(service->path,
2937                                         CONNMAN_SERVICE_INTERFACE,
2938                                                         "IPv6.Configuration",
2939                                                         append_ipv6config,
2940                                                         service);
2941 }
2942
2943 static void dns_changed(struct connman_service *service)
2944 {
2945         if (!allow_property_changed(service))
2946                 return;
2947
2948         connman_dbus_property_changed_array(service->path,
2949                                 CONNMAN_SERVICE_INTERFACE, "Nameservers",
2950                                         DBUS_TYPE_STRING, append_dns, service);
2951 }
2952
2953 static void dns_configuration_changed(struct connman_service *service)
2954 {
2955         if (!allow_property_changed(service))
2956                 return;
2957
2958         connman_dbus_property_changed_array(service->path,
2959                                 CONNMAN_SERVICE_INTERFACE,
2960                                 "Nameservers.Configuration",
2961                                 DBUS_TYPE_STRING, append_dnsconfig, service);
2962
2963         dns_changed(service);
2964 }
2965
2966 static void domain_changed(struct connman_service *service)
2967 {
2968         if (!allow_property_changed(service))
2969                 return;
2970
2971         connman_dbus_property_changed_array(service->path,
2972                                 CONNMAN_SERVICE_INTERFACE, "Domains",
2973                                 DBUS_TYPE_STRING, append_domain, service);
2974 }
2975
2976 static void domain_configuration_changed(struct connman_service *service)
2977 {
2978         if (!allow_property_changed(service))
2979                 return;
2980
2981         connman_dbus_property_changed_array(service->path,
2982                                 CONNMAN_SERVICE_INTERFACE,
2983                                 "Domains.Configuration",
2984                                 DBUS_TYPE_STRING, append_domainconfig, service);
2985 }
2986
2987 static void proxy_changed(struct connman_service *service)
2988 {
2989         if (!allow_property_changed(service))
2990                 return;
2991
2992         connman_dbus_property_changed_dict(service->path,
2993                                         CONNMAN_SERVICE_INTERFACE, "Proxy",
2994                                                         append_proxy, service);
2995 }
2996
2997 static void proxy_configuration_changed(struct connman_service *service)
2998 {
2999         if (!allow_property_changed(service))
3000                 return;
3001
3002         connman_dbus_property_changed_dict(service->path,
3003                         CONNMAN_SERVICE_INTERFACE, "Proxy.Configuration",
3004                                                 append_proxyconfig, service);
3005
3006         proxy_changed(service);
3007 }
3008
3009 static void mdns_changed(struct connman_service *service)
3010 {
3011         dbus_bool_t mdns = service->mdns;
3012
3013         if (!allow_property_changed(service))
3014                 return;
3015
3016         connman_dbus_property_changed_basic(service->path,
3017                         CONNMAN_SERVICE_INTERFACE, "mDNS", DBUS_TYPE_BOOLEAN,
3018                         &mdns);
3019 }
3020
3021 static void mdns_configuration_changed(struct connman_service *service)
3022 {
3023         dbus_bool_t mdns_config = service->mdns_config;
3024
3025         if (!allow_property_changed(service))
3026                 return;
3027
3028         connman_dbus_property_changed_basic(service->path,
3029                         CONNMAN_SERVICE_INTERFACE, "mDNS.Configuration",
3030                         DBUS_TYPE_BOOLEAN, &mdns_config);
3031 }
3032
3033 static int set_mdns(struct connman_service *service,
3034                         bool enabled)
3035 {
3036         int result;
3037
3038         result = __connman_resolver_set_mdns(
3039                         __connman_service_get_index(service), enabled);
3040
3041         if (result == 0) {
3042                 if (service->mdns != enabled) {
3043                         service->mdns = enabled;
3044                         mdns_changed(service);
3045                 }
3046         }
3047
3048         return result;
3049 }
3050
3051 static void timeservers_configuration_changed(struct connman_service *service)
3052 {
3053         if (!allow_property_changed(service))
3054                 return;
3055
3056         connman_dbus_property_changed_array(service->path,
3057                         CONNMAN_SERVICE_INTERFACE,
3058                         "Timeservers.Configuration",
3059                         DBUS_TYPE_STRING,
3060                         append_tsconfig, service);
3061 }
3062
3063 static void link_changed(struct connman_service *service)
3064 {
3065         if (!allow_property_changed(service))
3066                 return;
3067
3068         connman_dbus_property_changed_dict(service->path,
3069                                         CONNMAN_SERVICE_INTERFACE, "Ethernet",
3070                                                 append_ethernet, service);
3071 }
3072
3073 static void stats_append_counters(DBusMessageIter *dict,
3074                         struct connman_stats_data *stats,
3075                         struct connman_stats_data *counters,
3076                         bool append_all)
3077 {
3078         if (counters->rx_packets != stats->rx_packets || append_all) {
3079                 counters->rx_packets = stats->rx_packets;
3080                 connman_dbus_dict_append_basic(dict, "RX.Packets",
3081                                         DBUS_TYPE_UINT32, &stats->rx_packets);
3082         }
3083
3084         if (counters->tx_packets != stats->tx_packets || append_all) {
3085                 counters->tx_packets = stats->tx_packets;
3086                 connman_dbus_dict_append_basic(dict, "TX.Packets",
3087                                         DBUS_TYPE_UINT32, &stats->tx_packets);
3088         }
3089
3090         if (counters->rx_bytes != stats->rx_bytes || append_all) {
3091                 counters->rx_bytes = stats->rx_bytes;
3092                 connman_dbus_dict_append_basic(dict, "RX.Bytes",
3093                                         DBUS_TYPE_UINT32, &stats->rx_bytes);
3094         }
3095
3096         if (counters->tx_bytes != stats->tx_bytes || append_all) {
3097                 counters->tx_bytes = stats->tx_bytes;
3098                 connman_dbus_dict_append_basic(dict, "TX.Bytes",
3099                                         DBUS_TYPE_UINT32, &stats->tx_bytes);
3100         }
3101
3102         if (counters->rx_errors != stats->rx_errors || append_all) {
3103                 counters->rx_errors = stats->rx_errors;
3104                 connman_dbus_dict_append_basic(dict, "RX.Errors",
3105                                         DBUS_TYPE_UINT32, &stats->rx_errors);
3106         }
3107
3108         if (counters->tx_errors != stats->tx_errors || append_all) {
3109                 counters->tx_errors = stats->tx_errors;
3110                 connman_dbus_dict_append_basic(dict, "TX.Errors",
3111                                         DBUS_TYPE_UINT32, &stats->tx_errors);
3112         }
3113
3114         if (counters->rx_dropped != stats->rx_dropped || append_all) {
3115                 counters->rx_dropped = stats->rx_dropped;
3116                 connman_dbus_dict_append_basic(dict, "RX.Dropped",
3117                                         DBUS_TYPE_UINT32, &stats->rx_dropped);
3118         }
3119
3120         if (counters->tx_dropped != stats->tx_dropped || append_all) {
3121                 counters->tx_dropped = stats->tx_dropped;
3122                 connman_dbus_dict_append_basic(dict, "TX.Dropped",
3123                                         DBUS_TYPE_UINT32, &stats->tx_dropped);
3124         }
3125
3126         if (counters->time != stats->time || append_all) {
3127                 counters->time = stats->time;
3128                 connman_dbus_dict_append_basic(dict, "Time",
3129                                         DBUS_TYPE_UINT32, &stats->time);
3130         }
3131 }
3132
3133 static void stats_append(struct connman_service *service,
3134                                 const char *counter,
3135                                 struct connman_stats_counter *counters,
3136                                 bool append_all)
3137 {
3138         DBusMessageIter array, dict;
3139         DBusMessage *msg;
3140
3141         DBG("service %p counter %s", service, counter);
3142
3143         msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
3144         if (!msg)
3145                 return;
3146
3147         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH,
3148                                 &service->path, DBUS_TYPE_INVALID);
3149
3150         dbus_message_iter_init_append(msg, &array);
3151
3152         /* home counter */
3153         connman_dbus_dict_open(&array, &dict);
3154
3155         stats_append_counters(&dict, &service->stats.data,
3156                                 &counters->stats.data, append_all);
3157
3158         connman_dbus_dict_close(&array, &dict);
3159
3160         /* roaming counter */
3161         connman_dbus_dict_open(&array, &dict);
3162
3163         stats_append_counters(&dict, &service->stats_roaming.data,
3164                                 &counters->stats_roaming.data, append_all);
3165
3166         connman_dbus_dict_close(&array, &dict);
3167
3168         __connman_counter_send_usage(counter, msg);
3169 }
3170
3171 static void stats_update(struct connman_service *service,
3172                                 unsigned int rx_packets, unsigned int tx_packets,
3173                                 unsigned int rx_bytes, unsigned int tx_bytes,
3174                                 unsigned int rx_errors, unsigned int tx_errors,
3175                                 unsigned int rx_dropped, unsigned int tx_dropped)
3176 {
3177         struct connman_stats *stats = stats_get(service);
3178         struct connman_stats_data *data_last = &stats->data_last;
3179         struct connman_stats_data *data = &stats->data;
3180         unsigned int seconds;
3181
3182         DBG("service %p", service);
3183
3184         if (stats->valid) {
3185                 data->rx_packets +=
3186                         rx_packets - data_last->rx_packets;
3187                 data->tx_packets +=
3188                         tx_packets - data_last->tx_packets;
3189                 data->rx_bytes +=
3190                         rx_bytes - data_last->rx_bytes;
3191                 data->tx_bytes +=
3192                         tx_bytes - data_last->tx_bytes;
3193                 data->rx_errors +=
3194                         rx_errors - data_last->rx_errors;
3195                 data->tx_errors +=
3196                         tx_errors - data_last->tx_errors;
3197                 data->rx_dropped +=
3198                         rx_dropped - data_last->rx_dropped;
3199                 data->tx_dropped +=
3200                         tx_dropped - data_last->tx_dropped;
3201         } else {
3202                 stats->valid = true;
3203         }
3204
3205         data_last->rx_packets = rx_packets;
3206         data_last->tx_packets = tx_packets;
3207         data_last->rx_bytes = rx_bytes;
3208         data_last->tx_bytes = tx_bytes;
3209         data_last->rx_errors = rx_errors;
3210         data_last->tx_errors = tx_errors;
3211         data_last->rx_dropped = rx_dropped;
3212         data_last->tx_dropped = tx_dropped;
3213
3214         seconds = g_timer_elapsed(stats->timer, NULL);
3215         stats->data.time = stats->data_last.time + seconds;
3216 }
3217
3218 void __connman_service_notify(struct connman_service *service,
3219                         unsigned int rx_packets, unsigned int tx_packets,
3220                         unsigned int rx_bytes, unsigned int tx_bytes,
3221                         unsigned int rx_errors, unsigned int tx_errors,
3222                         unsigned int rx_dropped, unsigned int tx_dropped)
3223 {
3224         GHashTableIter iter;
3225         gpointer key, value;
3226         const char *counter;
3227         struct connman_stats_counter *counters;
3228         struct connman_stats_data *data;
3229         int err;
3230
3231         if (!service)
3232                 return;
3233
3234         if (!is_connected(service->state))
3235                 return;
3236
3237         stats_update(service,
3238                 rx_packets, tx_packets,
3239                 rx_bytes, tx_bytes,
3240                 rx_errors, tx_errors,
3241                 rx_dropped, tx_dropped);
3242
3243         data = &stats_get(service)->data;
3244         err = __connman_stats_update(service, service->roaming, data);
3245         if (err < 0)
3246                 connman_error("Failed to store statistics for %s",
3247                                 service->identifier);
3248
3249         g_hash_table_iter_init(&iter, service->counter_table);
3250         while (g_hash_table_iter_next(&iter, &key, &value)) {
3251                 counter = key;
3252                 counters = value;
3253
3254                 stats_append(service, counter, counters, counters->append_all);
3255                 counters->append_all = false;
3256         }
3257 }
3258
3259 int __connman_service_counter_register(const char *counter)
3260 {
3261         struct connman_service *service;
3262         GList *list;
3263         struct connman_stats_counter *counters;
3264
3265         DBG("counter %s", counter);
3266
3267         counter_list = g_slist_prepend(counter_list, (gpointer)counter);
3268
3269         for (list = service_list; list; list = list->next) {
3270                 service = list->data;
3271
3272                 counters = g_try_new0(struct connman_stats_counter, 1);
3273                 if (!counters)
3274                         return -ENOMEM;
3275
3276                 counters->append_all = true;
3277
3278                 g_hash_table_replace(service->counter_table, (gpointer)counter,
3279                                         counters);
3280         }
3281
3282         return 0;
3283 }
3284
3285 void __connman_service_counter_unregister(const char *counter)
3286 {
3287         struct connman_service *service;
3288         GList *list;
3289
3290         DBG("counter %s", counter);
3291
3292         for (list = service_list; list; list = list->next) {
3293                 service = list->data;
3294
3295                 g_hash_table_remove(service->counter_table, counter);
3296         }
3297
3298         counter_list = g_slist_remove(counter_list, counter);
3299 }
3300
3301 int connman_service_iterate_services(connman_service_iterate_cb cb,
3302                                                         void *user_data)
3303 {
3304         GList *list;
3305         int ret = 0;
3306
3307         for (list = service_list; list && ret == 0; list = list->next)
3308                 ret = cb((struct connman_service *)list->data, user_data);
3309
3310         return ret;
3311 }
3312
3313 #if defined TIZEN_EXT
3314 static void append_wifi_ext_info(DBusMessageIter *dict,
3315                                         struct connman_network *network)
3316 {
3317         char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
3318         char *bssid_str = bssid_buff;
3319         const void *ssid;
3320         unsigned int ssid_len;
3321         unsigned char *bssid;
3322         unsigned int maxrate;
3323         int maxspeed;
3324         unsigned int keymgmt;
3325         uint16_t frequency;
3326         const char *enc_mode;
3327         const char *str;
3328         gboolean passpoint;
3329         char country_code_buff[WIFI_COUNTRY_CODE_LEN + 1] = {0,};
3330         char *country_code_str = country_code_buff;
3331         unsigned char *country_code;
3332         uint16_t connection_mode;
3333
3334         ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len);
3335         bssid = connman_network_get_bssid(network);
3336         maxrate = connman_network_get_maxrate(network);
3337         maxspeed = connman_network_get_maxspeed(network);
3338         frequency = connman_network_get_frequency(network);
3339         enc_mode = connman_network_get_enc_mode(network);
3340         passpoint = connman_network_get_bool(network, "WiFi.HS20AP");
3341         keymgmt = connman_network_get_keymgmt(network);
3342         country_code = connman_network_get_countrycode(network);
3343         connection_mode = connman_network_get_connection_mode(network);
3344
3345         snprintf(bssid_str, WIFI_BSSID_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
3346                                 bssid[0], bssid[1], bssid[2],
3347                                 bssid[3], bssid[4], bssid[5]);
3348
3349         snprintf(country_code_str, (WIFI_COUNTRY_CODE_LEN + 1), "%c%c",
3350                  country_code[0], country_code[1]);
3351
3352
3353         connman_dbus_dict_append_fixed_array(dict, "SSID",
3354                                         DBUS_TYPE_BYTE, &ssid, ssid_len);
3355         connman_dbus_dict_append_basic(dict, "BSSID",
3356                                         DBUS_TYPE_STRING, &bssid_str);
3357         connman_dbus_dict_append_basic(dict, "MaxRate",
3358                                         DBUS_TYPE_UINT32, &maxrate);
3359         connman_dbus_dict_append_basic(dict, "MaxSpeed",
3360                                         DBUS_TYPE_INT32, &maxspeed);
3361         connman_dbus_dict_append_basic(dict, "Frequency",
3362                                         DBUS_TYPE_UINT16, &frequency);
3363         connman_dbus_dict_append_basic(dict, "EncryptionMode",
3364                                         DBUS_TYPE_STRING, &enc_mode);
3365         connman_dbus_dict_append_basic(dict, "Passpoint",
3366                                         DBUS_TYPE_BOOLEAN, &passpoint);
3367         connman_dbus_dict_append_basic(dict, "Keymgmt",
3368                                         DBUS_TYPE_UINT32, &keymgmt);
3369         connman_dbus_dict_append_basic(dict, "Country", DBUS_TYPE_STRING,
3370                                        &country_code_str);
3371         connman_dbus_dict_append_basic(dict, "ConnMode",
3372                                         DBUS_TYPE_UINT16, &connection_mode);
3373
3374         str = connman_network_get_string(network, "WiFi.Security");
3375         if (str != NULL && g_str_equal(str, "ieee8021x") == TRUE) {
3376                 str = connman_network_get_string(network, "WiFi.EAP");
3377                 if (str != NULL)
3378                         connman_dbus_dict_append_basic(dict, "EAP",
3379                                         DBUS_TYPE_STRING, &str);
3380
3381                 str = connman_network_get_string(network, "WiFi.Phase2");
3382                 if (str != NULL)
3383                         connman_dbus_dict_append_basic(dict, "Phase2",
3384                                         DBUS_TYPE_STRING, &str);
3385
3386                 str = connman_network_get_string(network, "WiFi.Identity");
3387                 if (str != NULL)
3388                         connman_dbus_dict_append_basic(dict, "Identity",
3389                                         DBUS_TYPE_STRING, &str);
3390
3391                 str = connman_network_get_string(network, "WiFi.CACertFile");
3392                 if (str != NULL)
3393                         connman_dbus_dict_append_basic(dict, "CACertFile",
3394                                         DBUS_TYPE_STRING, &str);
3395
3396                 str = connman_network_get_string(network,
3397                                 "WiFi.ClientCertFile");
3398                 if (str != NULL)
3399                         connman_dbus_dict_append_basic(dict, "ClientCertFile",
3400                                         DBUS_TYPE_STRING, &str);
3401
3402                 str = connman_network_get_string(network,
3403                                 "WiFi.PrivateKeyFile");
3404                 if (str != NULL)
3405                         connman_dbus_dict_append_basic(dict, "PrivateKeyFile",
3406                                         DBUS_TYPE_STRING, &str);
3407         }
3408 }
3409
3410 static void append_bssid_info(DBusMessageIter *iter, void *user_data)
3411 {
3412         GSList *bssid_list = NULL;
3413         struct connman_network *network = user_data;
3414         struct connman_bssids *bssids;
3415         char bssid_buf[MAC_ADDRESS_LENGTH] = {0,};
3416         char *bssid_str = bssid_buf;
3417
3418         bssid_list = (GSList *)connman_network_get_bssid_list(network);
3419         if(bssid_list) {
3420                 GSList *list;
3421                 for (list = bssid_list; list; list = list->next) {
3422                         bssids = (struct connman_bssids *)list->data;
3423                         g_snprintf(bssid_buf, MAC_ADDRESS_LENGTH, "%02x:%02x:%02x:%02x:%02x:%02x",
3424                                         bssids->bssid[0], bssids->bssid[1], bssids->bssid[2],
3425                                         bssids->bssid[3], bssids->bssid[4], bssids->bssid[5]);
3426
3427                         connman_dbus_dict_append_basic(iter, "BSSID",
3428                                         DBUS_TYPE_STRING, &bssid_str);
3429
3430                         connman_dbus_dict_append_basic(iter, "Strength",
3431                                         DBUS_TYPE_UINT16, &bssids->strength);
3432
3433                         connman_dbus_dict_append_basic(iter, "Frequency",
3434                                         DBUS_TYPE_UINT16, &bssids->frequency);
3435                 }
3436         }
3437 }
3438 #endif
3439
3440 static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
3441                                         struct connman_service *service)
3442 {
3443         dbus_bool_t val;
3444         const char *str;
3445         GSList *list;
3446
3447 #if defined TIZEN_EXT
3448         unsigned int frequency = 0U;
3449         if (service && service->network) {
3450                 frequency = connman_network_get_frequency(service->network);
3451                 connman_dbus_dict_append_basic(dict, "Frequency",
3452                                 DBUS_TYPE_UINT16, &frequency);
3453         }
3454
3455         unsigned char *wifi_vsie;
3456         unsigned int wifi_vsie_len;
3457         GSList *vsie_list = NULL;
3458
3459         if (service->network)
3460                 vsie_list = (GSList *)connman_network_get_vsie_list(service->network);
3461
3462         if (vsie_list) {
3463                 GSList *list;
3464                 for (list = vsie_list; list; list = list->next) {
3465                         wifi_vsie = (unsigned char *)list->data;
3466                         wifi_vsie_len = wifi_vsie[1] + 2;
3467
3468                         connman_dbus_dict_append_fixed_array(dict, "Vsie", DBUS_TYPE_BYTE,
3469                                         &wifi_vsie, wifi_vsie_len);
3470                 }
3471         }
3472 #endif
3473
3474         str = __connman_service_type2string(service->type);
3475         if (str)
3476                 connman_dbus_dict_append_basic(dict, "Type",
3477                                                 DBUS_TYPE_STRING, &str);
3478
3479         connman_dbus_dict_append_array(dict, "Security",
3480                                 DBUS_TYPE_STRING, append_security, service);
3481
3482         str = state2string(service->state);
3483         if (str)
3484                 connman_dbus_dict_append_basic(dict, "State",
3485                                                 DBUS_TYPE_STRING, &str);
3486
3487 #ifdef TIZEN_EXT
3488         str = state2string(service->state_ipv6);
3489         if (str != NULL)
3490                 connman_dbus_dict_append_basic(dict, "StateIPv6",
3491                                 DBUS_TYPE_STRING, &str);
3492 #endif
3493
3494         str = error2string(service->error);
3495         if (str)
3496                 connman_dbus_dict_append_basic(dict, "Error",
3497                                                 DBUS_TYPE_STRING, &str);
3498
3499         if (service->strength > 0)
3500                 connman_dbus_dict_append_basic(dict, "Strength",
3501                                         DBUS_TYPE_BYTE, &service->strength);
3502
3503         val = service->favorite;
3504         connman_dbus_dict_append_basic(dict, "Favorite",
3505                                         DBUS_TYPE_BOOLEAN, &val);
3506
3507         val = service->immutable;
3508         connman_dbus_dict_append_basic(dict, "Immutable",
3509                                         DBUS_TYPE_BOOLEAN, &val);
3510
3511         if (service->favorite)
3512                 val = service->autoconnect;
3513         else
3514                 val = service->favorite;
3515
3516         connman_dbus_dict_append_basic(dict, "AutoConnect",
3517                                 DBUS_TYPE_BOOLEAN, &val);
3518
3519         if (service->name)
3520                 connman_dbus_dict_append_basic(dict, "Name",
3521                                         DBUS_TYPE_STRING, &service->name);
3522
3523         switch (service->type) {
3524         case CONNMAN_SERVICE_TYPE_UNKNOWN:
3525         case CONNMAN_SERVICE_TYPE_SYSTEM:
3526         case CONNMAN_SERVICE_TYPE_GPS:
3527         case CONNMAN_SERVICE_TYPE_VPN:
3528         case CONNMAN_SERVICE_TYPE_P2P:
3529 #if defined TIZEN_EXT_WIFI_MESH
3530         case CONNMAN_SERVICE_TYPE_MESH:
3531 #endif
3532                 break;
3533         case CONNMAN_SERVICE_TYPE_CELLULAR:
3534                 val = service->roaming;
3535                 connman_dbus_dict_append_basic(dict, "Roaming",
3536                                         DBUS_TYPE_BOOLEAN, &val);
3537
3538                 connman_dbus_dict_append_dict(dict, "Ethernet",
3539                                                 append_ethernet, service);
3540                 break;
3541         case CONNMAN_SERVICE_TYPE_WIFI:
3542 #if defined TIZEN_EXT
3543                 if (service->network != NULL) {
3544                         append_wifi_ext_info(dict, service->network);
3545                         connman_dbus_dict_append_dict(dict, "BSSID.List",
3546                                         append_bssid_info, service->network);
3547                 }
3548
3549                 connman_dbus_dict_append_dict(dict, "Ethernet",
3550                                                 append_ethernet, service);
3551
3552                 service->disconnect_reason = connman_network_get_disconnect_reason(service->network);
3553                 connman_dbus_dict_append_basic(dict, "DisconnectReason",
3554                                 DBUS_TYPE_INT32, &service->disconnect_reason);
3555
3556                 connman_dbus_dict_append_basic(dict, "AssocStatusCode",
3557                                 DBUS_TYPE_INT32, &service->assoc_status_code);
3558
3559                 connman_dbus_dict_append_basic(dict, "Hidden",
3560                                 DBUS_TYPE_BOOLEAN, &service->hidden_service);
3561
3562                 break;
3563 #endif
3564         case CONNMAN_SERVICE_TYPE_ETHERNET:
3565         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
3566         case CONNMAN_SERVICE_TYPE_GADGET:
3567                 connman_dbus_dict_append_dict(dict, "Ethernet",
3568                                                 append_ethernet, service);
3569                 break;
3570         }
3571
3572         connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service);
3573
3574         connman_dbus_dict_append_dict(dict, "IPv4.Configuration",
3575                                                 append_ipv4config, service);
3576
3577         connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service);
3578
3579         connman_dbus_dict_append_dict(dict, "IPv6.Configuration",
3580                                                 append_ipv6config, service);
3581
3582         connman_dbus_dict_append_array(dict, "Nameservers",
3583                                 DBUS_TYPE_STRING, append_dns, service);
3584
3585         connman_dbus_dict_append_array(dict, "Nameservers.Configuration",
3586                                 DBUS_TYPE_STRING, append_dnsconfig, service);
3587
3588         if (service->state == CONNMAN_SERVICE_STATE_READY ||
3589                         service->state == CONNMAN_SERVICE_STATE_ONLINE)
3590                 list = __connman_timeserver_get_all(service);
3591         else
3592                 list = NULL;
3593
3594         connman_dbus_dict_append_array(dict, "Timeservers",
3595                                 DBUS_TYPE_STRING, append_ts, list);
3596
3597         g_slist_free_full(list, g_free);
3598
3599         connman_dbus_dict_append_array(dict, "Timeservers.Configuration",
3600                                 DBUS_TYPE_STRING, append_tsconfig, service);
3601
3602         connman_dbus_dict_append_array(dict, "Domains",
3603                                 DBUS_TYPE_STRING, append_domain, service);
3604
3605         connman_dbus_dict_append_array(dict, "Domains.Configuration",
3606                                 DBUS_TYPE_STRING, append_domainconfig, service);
3607
3608         connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service);
3609
3610         connman_dbus_dict_append_dict(dict, "Proxy.Configuration",
3611                                                 append_proxyconfig, service);
3612
3613         val = service->mdns;
3614         connman_dbus_dict_append_basic(dict, "mDNS", DBUS_TYPE_BOOLEAN,
3615                                 &val);
3616
3617         val = service->mdns_config;
3618         connman_dbus_dict_append_basic(dict, "mDNS.Configuration",
3619                                 DBUS_TYPE_BOOLEAN, &val);
3620
3621         connman_dbus_dict_append_dict(dict, "Provider",
3622                                                 append_provider, service);
3623
3624         if (service->network)
3625                 connman_network_append_acddbus(dict, service->network);
3626 }
3627
3628 static void append_struct_service(DBusMessageIter *iter,
3629                 connman_dbus_append_cb_t function,
3630                 struct connman_service *service)
3631 {
3632         DBusMessageIter entry, dict;
3633
3634         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
3635
3636         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
3637                                                         &service->path);
3638
3639         connman_dbus_dict_open(&entry, &dict);
3640         if (function)
3641                 function(&dict, service);
3642         connman_dbus_dict_close(&entry, &dict);
3643
3644         dbus_message_iter_close_container(iter, &entry);
3645 }
3646
3647 static void append_dict_properties(DBusMessageIter *dict, void *user_data)
3648 {
3649         struct connman_service *service = user_data;
3650
3651         append_properties(dict, TRUE, service);
3652 }
3653
3654 static void append_struct(gpointer value, gpointer user_data)
3655 {
3656         struct connman_service *service = value;
3657         DBusMessageIter *iter = user_data;
3658
3659         if (!service->path)
3660                 return;
3661
3662         append_struct_service(iter, append_dict_properties, service);
3663 }
3664
3665 void __connman_service_list_struct(DBusMessageIter *iter)
3666 {
3667         g_list_foreach(service_list, append_struct, iter);
3668 }
3669
3670 bool __connman_service_is_hidden(struct connman_service *service)
3671 {
3672         return service->hidden;
3673 }
3674
3675 bool
3676 __connman_service_is_split_routing(struct connman_service *service)
3677 {
3678         return service->do_split_routing;
3679 }
3680
3681 bool __connman_service_index_is_split_routing(int index)
3682 {
3683         struct connman_service *service;
3684
3685         if (index < 0)
3686                 return false;
3687
3688         service = __connman_service_lookup_from_index(index);
3689         if (!service)
3690                 return false;
3691
3692         return __connman_service_is_split_routing(service);
3693 }
3694
3695 int __connman_service_get_index(struct connman_service *service)
3696 {
3697         if (!service)
3698                 return -1;
3699
3700         if (service->network)
3701                 return connman_network_get_index(service->network);
3702         else if (service->provider)
3703                 return connman_provider_get_index(service->provider);
3704
3705         return -1;
3706 }
3707
3708 void __connman_service_set_hidden(struct connman_service *service)
3709 {
3710         if (!service || service->hidden)
3711                 return;
3712
3713         service->hidden_service = true;
3714 }
3715
3716 void __connman_service_set_hostname(struct connman_service *service,
3717                                                 const char *hostname)
3718 {
3719         if (!service || service->hidden)
3720                 return;
3721
3722         g_free(service->hostname);
3723         service->hostname = NULL;
3724
3725         if (hostname && g_str_is_ascii(hostname))
3726                 service->hostname = g_strdup(hostname);
3727 }
3728
3729 const char *__connman_service_get_hostname(struct connman_service *service)
3730 {
3731         if (!service)
3732                 return NULL;
3733
3734         return service->hostname;
3735 }
3736
3737 void __connman_service_set_domainname(struct connman_service *service,
3738                                                 const char *domainname)
3739 {
3740         if (!service || service->hidden)
3741                 return;
3742
3743         g_free(service->domainname);
3744         service->domainname = NULL;
3745
3746         if (domainname && g_str_is_ascii(domainname))
3747                 service->domainname = g_strdup(domainname);
3748
3749         domain_changed(service);
3750 }
3751
3752 const char *connman_service_get_domainname(struct connman_service *service)
3753 {
3754         if (!service)
3755                 return NULL;
3756
3757         if (service->domains)
3758                 return service->domains[0];
3759         else
3760                 return service->domainname;
3761 }
3762
3763 const char *connman_service_get_dbuspath(struct connman_service *service)
3764 {
3765         if (!service)
3766                 return NULL;
3767
3768         return service->path;
3769 }
3770
3771 char **connman_service_get_nameservers(struct connman_service *service)
3772 {
3773         if (!service)
3774                 return NULL;
3775
3776         if (service->nameservers_config)
3777                 return g_strdupv(service->nameservers_config);
3778         else if (service->nameservers ||
3779                                         service->nameservers_auto) {
3780                 int len = 0, len_auto = 0, i;
3781                 char **nameservers;
3782
3783                 if (service->nameservers)
3784                         len = g_strv_length(service->nameservers);
3785                 if (service->nameservers_auto)
3786                         len_auto = g_strv_length(service->nameservers_auto);
3787
3788                 nameservers = g_try_new0(char *, len + len_auto + 1);
3789                 if (!nameservers)
3790                         return NULL;
3791
3792                 for (i = 0; i < len; i++)
3793                         nameservers[i] = g_strdup(service->nameservers[i]);
3794
3795                 for (i = 0; i < len_auto; i++)
3796                         nameservers[i + len] =
3797                                 g_strdup(service->nameservers_auto[i]);
3798
3799                 return nameservers;
3800         }
3801
3802         return g_strdupv(connman_setting_get_string_list("FallbackNameservers"));
3803 }
3804
3805 char **connman_service_get_timeservers_config(struct connman_service *service)
3806 {
3807         if (!service)
3808                 return NULL;
3809
3810         return service->timeservers_config;
3811 }
3812
3813 char **connman_service_get_timeservers(struct connman_service *service)
3814 {
3815         if (!service)
3816                 return NULL;
3817
3818         return service->timeservers;
3819 }
3820
3821 #if defined TIZEN_EXT
3822 /*
3823  * Description: Telephony plug-in requires manual PROXY setting function
3824  */
3825 int connman_service_set_proxy(struct connman_service *service,
3826                                         const char *proxy, gboolean active)
3827 {
3828         char **proxies_array = NULL;
3829
3830         if (service == NULL)
3831                 return -EINVAL;
3832
3833         switch (service->type) {
3834         case CONNMAN_SERVICE_TYPE_CELLULAR:
3835         case CONNMAN_SERVICE_TYPE_ETHERNET:
3836         case CONNMAN_SERVICE_TYPE_WIFI:
3837                 break;
3838
3839         default:
3840                 return -EINVAL;
3841         }
3842
3843         g_strfreev(service->proxies);
3844         service->proxies = NULL;
3845
3846         if (proxy != NULL)
3847                 proxies_array = g_strsplit(proxy, " ", 0);
3848
3849         service->proxies = proxies_array;
3850
3851         if (proxy == NULL) {
3852                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
3853                 DBG("proxy changed (%d)", active);
3854         } else {
3855                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_MANUAL;
3856                 DBG("proxy chagned %s (%d)", proxy, active);
3857         }
3858
3859         if (active == TRUE) {
3860                 proxy_changed(service);
3861
3862                 __connman_notifier_proxy_changed(service);
3863         }
3864
3865         return 0;
3866 }
3867 #endif
3868
3869 void connman_service_set_proxy_method(struct connman_service *service,
3870                                         enum connman_service_proxy_method method)
3871 {
3872         if (!service || service->hidden)
3873                 return;
3874
3875         service->proxy = method;
3876
3877         proxy_changed(service);
3878
3879         if (method != CONNMAN_SERVICE_PROXY_METHOD_AUTO)
3880                 __connman_notifier_proxy_changed(service);
3881 }
3882
3883 enum connman_service_proxy_method connman_service_get_proxy_method(
3884                                         struct connman_service *service)
3885 {
3886         if (!service)
3887                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
3888
3889         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) {
3890                 if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_AUTO &&
3891                                 !service->pac)
3892                         return service->proxy;
3893
3894                 return service->proxy_config;
3895         }
3896
3897         return service->proxy;
3898 }
3899
3900 char **connman_service_get_proxy_servers(struct connman_service *service)
3901 {
3902         return g_strdupv(service->proxies);
3903 }
3904
3905 char **connman_service_get_proxy_excludes(struct connman_service *service)
3906 {
3907         return g_strdupv(service->excludes);
3908 }
3909
3910 const char *connman_service_get_proxy_url(struct connman_service *service)
3911 {
3912         if (!service)
3913                 return NULL;
3914
3915         return service->pac;
3916 }
3917
3918 void __connman_service_set_proxy_autoconfig(struct connman_service *service,
3919                                                         const char *url)
3920 {
3921         if (!service || service->hidden)
3922                 return;
3923
3924         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_AUTO;
3925
3926         if (service->ipconfig_ipv4) {
3927                 if (__connman_ipconfig_set_proxy_autoconfig(
3928                             service->ipconfig_ipv4, url) < 0)
3929                         return;
3930         } else if (service->ipconfig_ipv6) {
3931                 if (__connman_ipconfig_set_proxy_autoconfig(
3932                             service->ipconfig_ipv6, url) < 0)
3933                         return;
3934         } else
3935                 return;
3936
3937         proxy_changed(service);
3938
3939         __connman_notifier_proxy_changed(service);
3940 }
3941
3942 const char *connman_service_get_proxy_autoconfig(struct connman_service *service)
3943 {
3944         if (!service)
3945                 return NULL;
3946
3947         if (service->ipconfig_ipv4)
3948                 return __connman_ipconfig_get_proxy_autoconfig(
3949                                                 service->ipconfig_ipv4);
3950         else if (service->ipconfig_ipv6)
3951                 return __connman_ipconfig_get_proxy_autoconfig(
3952                                                 service->ipconfig_ipv6);
3953         return NULL;
3954 }
3955
3956 #if defined TIZEN_EXT
3957 int connman_service_get_ipv6_dns_method(struct connman_service *service)
3958 {
3959         if (!service) {
3960                 DBG("Service is NULL");
3961                 return -1;
3962         }
3963
3964         return service->dns_config_method_ipv6;
3965 }
3966 #endif
3967
3968 void __connman_service_set_timeservers(struct connman_service *service,
3969                                 char **timeservers)
3970 {
3971         int i;
3972
3973         if (!service)
3974                 return;
3975
3976         g_strfreev(service->timeservers);
3977         service->timeservers = NULL;
3978
3979         for (i = 0; timeservers && timeservers[i]; i++)
3980                 __connman_service_timeserver_append(service, timeservers[i]);
3981 }
3982
3983 int __connman_service_timeserver_append(struct connman_service *service,
3984                                                 const char *timeserver)
3985 {
3986         int len;
3987
3988         DBG("service %p timeserver %s", service, timeserver);
3989
3990         if (!timeserver)
3991                 return -EINVAL;
3992
3993         if (service->timeservers) {
3994                 int i;
3995
3996                 for (i = 0; service->timeservers[i]; i++)
3997                         if (g_strcmp0(service->timeservers[i], timeserver) == 0)
3998                                 return -EEXIST;
3999
4000                 len = g_strv_length(service->timeservers);
4001                 service->timeservers = g_try_renew(char *, service->timeservers,
4002                                                         len + 2);
4003         } else {
4004                 len = 0;
4005                 service->timeservers = g_try_new0(char *, len + 2);
4006         }
4007
4008         if (!service->timeservers)
4009                 return -ENOMEM;
4010
4011         service->timeservers[len] = g_strdup(timeserver);
4012         service->timeservers[len + 1] = NULL;
4013
4014         return 0;
4015 }
4016
4017 int __connman_service_timeserver_remove(struct connman_service *service,
4018                                                 const char *timeserver)
4019 {
4020         char **servers;
4021         int len, i, j, found = 0;
4022
4023         DBG("service %p timeserver %s", service, timeserver);
4024
4025         if (!timeserver)
4026                 return -EINVAL;
4027
4028         if (!service->timeservers)
4029                 return 0;
4030
4031         for (i = 0; service->timeservers &&
4032                                         service->timeservers[i]; i++)
4033                 if (g_strcmp0(service->timeservers[i], timeserver) == 0) {
4034                         found = 1;
4035                         break;
4036                 }
4037
4038         if (found == 0)
4039                 return 0;
4040
4041         len = g_strv_length(service->timeservers);
4042
4043         if (len == 1) {
4044                 g_strfreev(service->timeservers);
4045                 service->timeservers = NULL;
4046
4047                 return 0;
4048         }
4049
4050         servers = g_try_new0(char *, len);
4051         if (!servers)
4052                 return -ENOMEM;
4053
4054         for (i = 0, j = 0; i < len; i++) {
4055                 if (g_strcmp0(service->timeservers[i], timeserver) != 0) {
4056                         servers[j] = g_strdup(service->timeservers[i]);
4057                         if (!servers[j])
4058                                 return -ENOMEM;
4059                         j++;
4060                 }
4061         }
4062         servers[len - 1] = NULL;
4063
4064         g_strfreev(service->timeservers);
4065         service->timeservers = servers;
4066
4067         return 0;
4068 }
4069
4070 void __connman_service_timeserver_changed(struct connman_service *service,
4071                 GSList *ts_list)
4072 {
4073         if (!service)
4074                 return;
4075
4076         if (!allow_property_changed(service))
4077                 return;
4078
4079         connman_dbus_property_changed_array(service->path,
4080                         CONNMAN_SERVICE_INTERFACE, "Timeservers",
4081                         DBUS_TYPE_STRING, append_ts, ts_list);
4082 }
4083
4084 void __connman_service_set_pac(struct connman_service *service,
4085                                         const char *pac)
4086 {
4087         if (service->hidden)
4088                 return;
4089         g_free(service->pac);
4090         service->pac = g_strdup(pac);
4091
4092         proxy_changed(service);
4093 }
4094
4095 #if defined TIZEN_EXT
4096 void __connman_service_set_proxy(struct connman_service *service,
4097                                        const char *proxies)
4098 {
4099        char **proxies_array = NULL;
4100
4101        g_strfreev(service->proxies);
4102        service->proxies = NULL;
4103
4104        if (proxies != NULL)
4105                proxies_array = g_strsplit(proxies, " ", 0);
4106
4107        service->proxies = proxies_array;
4108 }
4109 #endif
4110
4111 void __connman_service_set_identity(struct connman_service *service,
4112                                         const char *identity)
4113 {
4114         if (service->immutable || service->hidden)
4115                 return;
4116
4117         g_free(service->identity);
4118         service->identity = g_strdup(identity);
4119
4120         if (service->network)
4121                 connman_network_set_string(service->network,
4122                                         "WiFi.Identity",
4123                                         service->identity);
4124 }
4125
4126 void __connman_service_set_anonymous_identity(struct connman_service *service,
4127                                                 const char *anonymous_identity)
4128 {
4129         if (service->immutable || service->hidden)
4130                 return;
4131
4132         g_free(service->anonymous_identity);
4133         service->anonymous_identity = g_strdup(anonymous_identity);
4134
4135         if (service->network)
4136                 connman_network_set_string(service->network,
4137                                         "WiFi.AnonymousIdentity",
4138                                         service->anonymous_identity);
4139 }
4140
4141 void __connman_service_set_subject_match(struct connman_service *service,
4142                                                 const char *subject_match)
4143 {
4144         if (service->immutable || service->hidden)
4145                 return;
4146
4147         g_free(service->subject_match);
4148         service->subject_match = g_strdup(subject_match);
4149
4150         if (service->network)
4151                 connman_network_set_string(service->network,
4152                                         "WiFi.SubjectMatch",
4153                                         service->subject_match);
4154 }
4155
4156 void __connman_service_set_altsubject_match(struct connman_service *service,
4157                                                 const char *altsubject_match)
4158 {
4159         if (service->immutable || service->hidden)
4160                 return;
4161
4162         g_free(service->altsubject_match);
4163         service->altsubject_match = g_strdup(altsubject_match);
4164
4165         if (service->network)
4166                 connman_network_set_string(service->network,
4167                                         "WiFi.AltSubjectMatch",
4168                                         service->altsubject_match);
4169 }
4170
4171 void __connman_service_set_domain_suffix_match(struct connman_service *service,
4172                                                 const char *domain_suffix_match)
4173 {
4174         if (service->immutable || service->hidden)
4175                 return;
4176
4177         g_free(service->domain_suffix_match);
4178         service->domain_suffix_match = g_strdup(domain_suffix_match);
4179
4180         if (service->network)
4181                 connman_network_set_string(service->network,
4182                                         "WiFi.DomainSuffixMatch",
4183                                         service->domain_suffix_match);
4184 }
4185
4186 void __connman_service_set_domain_match(struct connman_service *service,
4187                                                 const char *domain_match)
4188 {
4189         if (service->immutable || service->hidden)
4190                 return;
4191
4192         g_free(service->domain_match);
4193         service->domain_match = g_strdup(domain_match);
4194
4195         if (service->network)
4196                 connman_network_set_string(service->network,
4197                                         "WiFi.DomainMatch",
4198                                         service->domain_match);
4199 }
4200
4201 void __connman_service_set_agent_identity(struct connman_service *service,
4202                                                 const char *agent_identity)
4203 {
4204         if (service->hidden)
4205                 return;
4206         g_free(service->agent_identity);
4207         service->agent_identity = g_strdup(agent_identity);
4208
4209         if (service->network)
4210                 connman_network_set_string(service->network,
4211                                         "WiFi.AgentIdentity",
4212                                         service->agent_identity);
4213 }
4214
4215 int __connman_service_check_passphrase(enum connman_service_security security,
4216                 const char *passphrase)
4217 {
4218         guint i;
4219         gsize length;
4220
4221         if (!passphrase)
4222                 return 0;
4223
4224         length = strlen(passphrase);
4225
4226         switch (security) {
4227         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
4228         case CONNMAN_SERVICE_SECURITY_NONE:
4229         case CONNMAN_SERVICE_SECURITY_WPA:
4230 #if !defined TIZEN_EXT
4231         case CONNMAN_SERVICE_SECURITY_RSN:
4232 #endif
4233
4234                 DBG("service security '%s' (%d) not handled",
4235                                 security2string(security), security);
4236
4237                 return -EOPNOTSUPP;
4238
4239         case CONNMAN_SERVICE_SECURITY_PSK:
4240 #if defined TIZEN_EXT
4241         case CONNMAN_SERVICE_SECURITY_RSN:
4242         /* TO CHECK: We need to check the key length supported by SAE */
4243         case CONNMAN_SERVICE_SECURITY_SAE:
4244 #endif
4245                 /* A raw key is always 64 bytes length,
4246                  * its content is in hex representation.
4247                  * A PSK key must be between [8..63].
4248                  */
4249                 if (length == 64) {
4250                         for (i = 0; i < 64; i++)
4251                                 if (!isxdigit((unsigned char)
4252                                               passphrase[i]))
4253                                         return -ENOKEY;
4254                 } else if (length < 8 || length > 63)
4255                         return -ENOKEY;
4256                 break;
4257         case CONNMAN_SERVICE_SECURITY_WEP:
4258                 /* length of WEP key is 10 or 26
4259                  * length of WEP passphrase is 5 or 13
4260                  */
4261                 if (length == 10 || length == 26) {
4262                         for (i = 0; i < length; i++)
4263                                 if (!isxdigit((unsigned char)
4264                                               passphrase[i]))
4265                                         return -ENOKEY;
4266                 } else if (length != 5 && length != 13)
4267                         return -ENOKEY;
4268                 break;
4269
4270         case CONNMAN_SERVICE_SECURITY_8021X:
4271 #if defined TIZEN_EXT
4272         case CONNMAN_SERVICE_SECURITY_OWE:
4273         case CONNMAN_SERVICE_SECURITY_DPP:
4274 #endif
4275                 break;
4276         }
4277
4278         return 0;
4279 }
4280
4281 int __connman_service_set_passphrase(struct connman_service *service,
4282                                         const char *passphrase)
4283 {
4284         int err;
4285
4286         if (service->hidden)
4287                 return -EINVAL;
4288
4289         if (service->immutable &&
4290                         service->security != CONNMAN_SERVICE_SECURITY_8021X)
4291                 return -EINVAL;
4292
4293 #if defined TIZEN_EXT
4294         if (service->immutable &&
4295                         service->security != CONNMAN_SERVICE_SECURITY_DPP)
4296                 return -EINVAL;
4297         /* The encrypted passphrase is used here
4298          * and validation is done by net-config before being encrypted.
4299          */
4300         err = 0;
4301         if (service->security != CONNMAN_SERVICE_SECURITY_PSK &&
4302                         service->security != CONNMAN_SERVICE_SECURITY_RSN &&
4303                         service->security != CONNMAN_SERVICE_SECURITY_SAE &&
4304                         service->security != CONNMAN_SERVICE_SECURITY_WEP)
4305 #endif
4306         err = __connman_service_check_passphrase(service->security, passphrase);
4307
4308         if (err < 0)
4309                 return err;
4310
4311         g_free(service->passphrase);
4312         service->passphrase = g_strdup(passphrase);
4313
4314         if (service->network)
4315                 connman_network_set_string(service->network, "WiFi.Passphrase",
4316                                 service->passphrase);
4317
4318         return 0;
4319 }
4320
4321 const char *__connman_service_get_passphrase(struct connman_service *service)
4322 {
4323         if (!service)
4324                 return NULL;
4325
4326         return service->passphrase;
4327 }
4328
4329 static DBusMessage *get_properties(DBusConnection *conn,
4330                                         DBusMessage *msg, void *user_data)
4331 {
4332         struct connman_service *service = user_data;
4333         DBusMessage *reply;
4334         DBusMessageIter array, dict;
4335
4336         reply = dbus_message_new_method_return(msg);
4337         if (!reply)
4338                 return NULL;
4339
4340         dbus_message_iter_init_append(reply, &array);
4341
4342         connman_dbus_dict_open(&array, &dict);
4343         append_properties(&dict, FALSE, service);
4344         connman_dbus_dict_close(&array, &dict);
4345
4346         return reply;
4347 }
4348
4349 static char **remove_empty_strings(char **strv)
4350 {
4351         int index = 0;
4352         char **iter = strv;
4353
4354         while (*iter) {
4355                 if (**iter)
4356                         strv[index++] = *iter;
4357                 else
4358                         g_free(*iter);
4359                 iter++;
4360         }
4361
4362         strv[index] = NULL;
4363         return strv;
4364 }
4365
4366 static int update_proxy_configuration(struct connman_service *service,
4367                                 DBusMessageIter *array)
4368 {
4369         DBusMessageIter dict;
4370         enum connman_service_proxy_method method;
4371         GString *servers_str = NULL;
4372         GString *excludes_str = NULL;
4373         const char *url = NULL;
4374
4375         method = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
4376
4377         dbus_message_iter_recurse(array, &dict);
4378
4379         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
4380                 DBusMessageIter entry, variant;
4381                 const char *key;
4382                 int type;
4383
4384                 dbus_message_iter_recurse(&dict, &entry);
4385
4386                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
4387                         goto error;
4388
4389                 dbus_message_iter_get_basic(&entry, &key);
4390                 dbus_message_iter_next(&entry);
4391
4392                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
4393                         goto error;
4394
4395                 dbus_message_iter_recurse(&entry, &variant);
4396
4397                 type = dbus_message_iter_get_arg_type(&variant);
4398
4399                 if (g_str_equal(key, "Method")) {
4400                         const char *val;
4401
4402                         if (type != DBUS_TYPE_STRING)
4403                                 goto error;
4404
4405                         dbus_message_iter_get_basic(&variant, &val);
4406                         method = string2proxymethod(val);
4407                 } else if (g_str_equal(key, "URL")) {
4408                         if (type != DBUS_TYPE_STRING)
4409                                 goto error;
4410
4411                         dbus_message_iter_get_basic(&variant, &url);
4412                 } else if (g_str_equal(key, "Servers")) {
4413                         DBusMessageIter str_array;
4414
4415                         if (type != DBUS_TYPE_ARRAY)
4416                                 goto error;
4417
4418                         servers_str = g_string_new(NULL);
4419                         if (!servers_str)
4420                                 goto error;
4421
4422                         dbus_message_iter_recurse(&variant, &str_array);
4423
4424                         while (dbus_message_iter_get_arg_type(&str_array) ==
4425                                                         DBUS_TYPE_STRING) {
4426                                 char *val = NULL;
4427
4428                                 dbus_message_iter_get_basic(&str_array, &val);
4429
4430                                 if (servers_str->len > 0)
4431                                         g_string_append_printf(servers_str,
4432                                                         " %s", val);
4433                                 else
4434                                         g_string_append(servers_str, val);
4435
4436                                 dbus_message_iter_next(&str_array);
4437                         }
4438                 } else if (g_str_equal(key, "Excludes")) {
4439                         DBusMessageIter str_array;
4440
4441                         if (type != DBUS_TYPE_ARRAY)
4442                                 goto error;
4443
4444                         excludes_str = g_string_new(NULL);
4445                         if (!excludes_str)
4446                                 goto error;
4447
4448                         dbus_message_iter_recurse(&variant, &str_array);
4449
4450                         while (dbus_message_iter_get_arg_type(&str_array) ==
4451                                                         DBUS_TYPE_STRING) {
4452                                 char *val = NULL;
4453
4454                                 dbus_message_iter_get_basic(&str_array, &val);
4455
4456                                 if (excludes_str->len > 0)
4457                                         g_string_append_printf(excludes_str,
4458                                                         " %s", val);
4459                                 else
4460                                         g_string_append(excludes_str, val);
4461
4462                                 dbus_message_iter_next(&str_array);
4463                         }
4464                 }
4465
4466                 dbus_message_iter_next(&dict);
4467         }
4468
4469         switch (method) {
4470         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
4471                 break;
4472         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
4473                 if (!servers_str && !service->proxies)
4474                         goto error;
4475
4476                 if (servers_str) {
4477                         g_strfreev(service->proxies);
4478
4479                         if (servers_str->len > 0) {
4480                                 char **proxies = g_strsplit_set(
4481                                         servers_str->str, " ", 0);
4482                                 proxies = remove_empty_strings(proxies);
4483                                 service->proxies = proxies;
4484                         } else
4485                                 service->proxies = NULL;
4486                 }
4487
4488                 if (excludes_str) {
4489                         g_strfreev(service->excludes);
4490
4491                         if (excludes_str->len > 0) {
4492                                 char **excludes = g_strsplit_set(
4493                                         excludes_str->str, " ", 0);
4494                                 excludes = remove_empty_strings(excludes);
4495                                 service->excludes = excludes;
4496                         } else
4497                                 service->excludes = NULL;
4498                 }
4499
4500                 if (!service->proxies)
4501                         method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
4502
4503                 break;
4504         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
4505                 g_free(service->pac);
4506
4507                 if (url && strlen(url) > 0)
4508                         service->pac = g_strstrip(g_strdup(url));
4509                 else
4510                         service->pac = NULL;
4511
4512                 /* if we are connected:
4513                    - if service->pac == NULL
4514                    - if __connman_ipconfig_get_proxy_autoconfig(
4515                    service->ipconfig) == NULL
4516                    --> We should start WPAD */
4517
4518                 break;
4519         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
4520                 goto error;
4521         }
4522
4523         if (servers_str)
4524                 g_string_free(servers_str, TRUE);
4525
4526         if (excludes_str)
4527                 g_string_free(excludes_str, TRUE);
4528
4529         service->proxy_config = method;
4530
4531         return 0;
4532
4533 error:
4534         if (servers_str)
4535                 g_string_free(servers_str, TRUE);
4536
4537         if (excludes_str)
4538                 g_string_free(excludes_str, TRUE);
4539
4540         return -EINVAL;
4541 }
4542
4543 int __connman_service_reset_ipconfig(struct connman_service *service,
4544                 enum connman_ipconfig_type type, DBusMessageIter *array,
4545                 enum connman_service_state *new_state)
4546 {
4547         struct connman_ipconfig *ipconfig, *new_ipconfig;
4548         enum connman_ipconfig_method old_method, new_method;
4549         enum connman_service_state state;
4550         int err = 0, index;
4551
4552         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
4553                 ipconfig = service->ipconfig_ipv4;
4554                 state = service->state_ipv4;
4555                 new_method = CONNMAN_IPCONFIG_METHOD_DHCP;
4556         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
4557                 ipconfig = service->ipconfig_ipv6;
4558                 state = service->state_ipv6;
4559                 new_method = CONNMAN_IPCONFIG_METHOD_AUTO;
4560         } else
4561                 return -EINVAL;
4562
4563         if (!ipconfig)
4564                 return -ENXIO;
4565
4566         old_method = __connman_ipconfig_get_method(ipconfig);
4567         index = __connman_ipconfig_get_index(ipconfig);
4568
4569         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4570                 new_ipconfig = create_ip4config(service, index,
4571                                 CONNMAN_IPCONFIG_METHOD_UNKNOWN);
4572         else
4573                 new_ipconfig = create_ip6config(service, index);
4574
4575         if (array) {
4576                 err = __connman_ipconfig_set_config(new_ipconfig, array);
4577                 if (err < 0) {
4578                         __connman_ipconfig_unref(new_ipconfig);
4579                         return err;
4580                 }
4581
4582                 new_method = __connman_ipconfig_get_method(new_ipconfig);
4583         }
4584
4585         if (is_connecting(state) || is_connected(state))
4586                 __connman_network_clear_ipconfig(service->network, ipconfig);
4587
4588         __connman_ipconfig_unref(ipconfig);
4589
4590         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4591                 service->ipconfig_ipv4 = new_ipconfig;
4592         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
4593                 service->ipconfig_ipv6 = new_ipconfig;
4594
4595         if (is_connecting(state) || is_connected(state))
4596                 __connman_ipconfig_enable(new_ipconfig);
4597
4598         if (new_state && new_method != old_method) {
4599                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4600                         *new_state = service->state_ipv4;
4601                 else
4602                         *new_state = service->state_ipv6;
4603
4604                 settings_changed(service, new_ipconfig);
4605                 address_updated(service, type);
4606
4607                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4608         }
4609
4610         DBG("err %d ipconfig %p type %d method %d state %s", err,
4611                 new_ipconfig, type, new_method,
4612                 !new_state  ? "-" : state2string(*new_state));
4613
4614         return err;
4615 }
4616
4617 /*
4618  * We set the timeout to 1 sec so that we have a chance to get
4619  * necessary IPv6 router advertisement messages that might have
4620  * DNS data etc.
4621  */
4622 #define ONLINE_CHECK_INITIAL_INTERVAL 1
4623 #define ONLINE_CHECK_MAX_INTERVAL 12
4624
4625 void __connman_service_wispr_start(struct connman_service *service,
4626                                         enum connman_ipconfig_type type)
4627 {
4628         DBG("service %p type %s", service, __connman_ipconfig_type2string(type));
4629
4630         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4631                 service->online_check_interval_ipv4 =
4632                                         ONLINE_CHECK_INITIAL_INTERVAL;
4633         else
4634                 service->online_check_interval_ipv6 =
4635                                         ONLINE_CHECK_INITIAL_INTERVAL;
4636
4637         __connman_wispr_start(service, type);
4638 }
4639
4640 static DBusMessage *set_property(DBusConnection *conn,
4641                                         DBusMessage *msg, void *user_data)
4642 {
4643         struct connman_service *service = user_data;
4644         DBusMessageIter iter, value;
4645         const char *name;
4646         int type;
4647
4648         DBG("service %p", service);
4649
4650         if (!dbus_message_iter_init(msg, &iter))
4651                 return __connman_error_invalid_arguments(msg);
4652
4653         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
4654                 return __connman_error_invalid_arguments(msg);
4655
4656         dbus_message_iter_get_basic(&iter, &name);
4657         dbus_message_iter_next(&iter);
4658
4659         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
4660                 return __connman_error_invalid_arguments(msg);
4661
4662         dbus_message_iter_recurse(&iter, &value);
4663
4664         type = dbus_message_iter_get_arg_type(&value);
4665
4666         if (g_str_equal(name, "AutoConnect")) {
4667                 dbus_bool_t autoconnect;
4668
4669                 if (type != DBUS_TYPE_BOOLEAN)
4670                         return __connman_error_invalid_arguments(msg);
4671
4672                 if (!service->favorite)
4673                         return __connman_error_invalid_service(msg);
4674
4675                 dbus_message_iter_get_basic(&value, &autoconnect);
4676
4677                 if (service->autoconnect == autoconnect)
4678                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4679
4680                 service->autoconnect = autoconnect;
4681
4682                 autoconnect_changed(service);
4683
4684                 if (autoconnect)
4685                         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4686
4687                 service_save(service);
4688         } else if (g_str_equal(name, "Nameservers.Configuration")) {
4689                 DBusMessageIter entry;
4690                 GString *str;
4691                 int index;
4692                 const char *gw;
4693 #if defined TIZEN_EXT
4694                 enum connman_ipconfig_type ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4695                 DBG("%s", name);
4696 #endif
4697
4698                 if (__connman_provider_is_immutable(service->provider) ||
4699                                 service->immutable)
4700                         return __connman_error_not_supported(msg);
4701
4702                 if (type != DBUS_TYPE_ARRAY)
4703                         return __connman_error_invalid_arguments(msg);
4704
4705                 str = g_string_new(NULL);
4706                 if (!str)
4707                         return __connman_error_invalid_arguments(msg);
4708
4709                 index = __connman_service_get_index(service);
4710                 gw = __connman_ipconfig_get_gateway_from_index(index,
4711                         CONNMAN_IPCONFIG_TYPE_ALL);
4712
4713 #if !defined TIZEN_EXT
4714                 if (gw && strlen(gw))
4715                         __connman_service_nameserver_del_routes(service,
4716                                                 CONNMAN_IPCONFIG_TYPE_ALL);
4717
4718 #endif
4719                 dbus_message_iter_recurse(&value, &entry);
4720
4721 #if defined TIZEN_EXT
4722                 /* IPv4/IPv6 Last DNS config method */
4723                 int last_dns_ipv4 = service->dns_config_method_ipv4;
4724                 int last_dns_ipv6 = service->dns_config_method_ipv6;
4725                 DBG("Last DNS Config Method IPv4: %d IPv6: %d", last_dns_ipv4, last_dns_ipv6);
4726 #endif
4727
4728                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
4729                         const char *val;
4730                         dbus_message_iter_get_basic(&entry, &val);
4731                         dbus_message_iter_next(&entry);
4732 #ifdef TIZEN_EXT
4733                         /* First unpack the DNS Config Method */
4734                         DBG("DNS Config Method: %s", val);
4735                         if((g_strcmp0(val, "ipv4.manual") == 0)) {
4736                                 service->dns_config_method_ipv4 =
4737                                         CONNMAN_DNSCONFIG_METHOD_MANUAL;
4738
4739                                 if(last_dns_ipv4 != CONNMAN_DNSCONFIG_METHOD_MANUAL) {
4740                                         if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN)
4741                                                 ip_type = CONNMAN_IPCONFIG_TYPE_IPV4;
4742                                         else
4743                                                 ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4744                                 }
4745                                 continue;
4746                         } else if(g_strcmp0(val, "ipv4.dhcp") == 0) {
4747                                 service->dns_config_method_ipv4 =
4748                                         CONNMAN_DNSCONFIG_METHOD_DHCP;
4749                                 if(last_dns_ipv4 == CONNMAN_DNSCONFIG_METHOD_MANUAL)
4750                                         ip_type = CONNMAN_IPCONFIG_TYPE_IPV4;
4751
4752                                 continue;
4753                         } else if(g_strcmp0(val, "ipv6.manual") == 0) {
4754                                 service->dns_config_method_ipv6 =
4755                                         CONNMAN_DNSCONFIG_METHOD_MANUAL;
4756                                 if(last_dns_ipv6 != CONNMAN_DNSCONFIG_METHOD_MANUAL) {
4757                                         if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN)
4758                                                 ip_type = CONNMAN_IPCONFIG_TYPE_IPV6;
4759                                         else
4760                                                 ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4761                                 }
4762                                 continue;
4763                         } else if(g_strcmp0(val, "ipv6.dhcp") == 0) {
4764                                 service->dns_config_method_ipv6 =
4765                                         CONNMAN_DNSCONFIG_METHOD_DHCP;
4766                                 if(last_dns_ipv6 == CONNMAN_DNSCONFIG_METHOD_MANUAL)
4767                                         ip_type = CONNMAN_IPCONFIG_TYPE_IPV6;
4768
4769                                 continue;
4770                         }
4771 #endif
4772                         if (!val[0])
4773                                 continue;
4774
4775                         if (str->len > 0)
4776                                 g_string_append_printf(str, " %s", val);
4777                         else
4778                                 g_string_append(str, val);
4779                 }
4780
4781 #if defined TIZEN_EXT
4782                 if (service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_DHCP &&
4783                         service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_DHCP) {
4784                                         DBG("Both IPv4 and IPv6 DNS Method DHCP");
4785                                         ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4786                 }
4787                 if (gw && strlen(gw))
4788                         __connman_service_nameserver_del_routes(service,
4789                                                 ip_type);
4790
4791                 DBG("%s ip_type: %d nameserver remove all", name, ip_type);
4792                 nameserver_remove_all(service, ip_type);
4793 #else
4794                 nameserver_remove_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
4795 #endif
4796                 g_strfreev(service->nameservers_config);
4797
4798                 if (str->len > 0) {
4799                         char **nameservers, **iter;
4800
4801                         nameservers = g_strsplit_set(str->str, " ", 0);
4802
4803                         for (iter = nameservers; *iter; iter++)
4804                                 if (connman_inet_check_ipaddress(*iter) <= 0)
4805                                         *iter[0] = '\0';
4806
4807                         nameservers = remove_empty_strings(nameservers);
4808                         service->nameservers_config = nameservers;
4809                 } else {
4810                         service->nameservers_config = NULL;
4811                 }
4812
4813                 g_string_free(str, TRUE);
4814
4815                 if (gw && strlen(gw))
4816                         __connman_service_nameserver_add_routes(service, gw);
4817
4818 #if defined TIZEN_EXT
4819                 DBG("%s ip_type: %d nameserver add all", name, ip_type);
4820                 nameserver_add_all(service, ip_type);
4821 #else
4822                 nameserver_add_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
4823 #endif
4824                 dns_configuration_changed(service);
4825
4826                 if (__connman_service_is_connected_state(service,
4827                                                 CONNMAN_IPCONFIG_TYPE_IPV4))
4828                         __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
4829
4830                 if (__connman_service_is_connected_state(service,
4831                                                 CONNMAN_IPCONFIG_TYPE_IPV6))
4832                         __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
4833
4834                 service_save(service);
4835         } else if (g_str_equal(name, "Timeservers.Configuration")) {
4836                 DBusMessageIter entry;
4837                 GString *str;
4838
4839                 if (service->immutable)
4840                         return __connman_error_not_supported(msg);
4841
4842                 if (type != DBUS_TYPE_ARRAY)
4843                         return __connman_error_invalid_arguments(msg);
4844
4845                 str = g_string_new(NULL);
4846                 if (!str)
4847                         return __connman_error_invalid_arguments(msg);
4848
4849                 dbus_message_iter_recurse(&value, &entry);
4850
4851                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
4852                         const char *val;
4853                         dbus_message_iter_get_basic(&entry, &val);
4854                         dbus_message_iter_next(&entry);
4855
4856                         if (!val[0])
4857                                 continue;
4858
4859                         if (str->len > 0)
4860                                 g_string_append_printf(str, " %s", val);
4861                         else
4862                                 g_string_append(str, val);
4863                 }
4864
4865                 g_strfreev(service->timeservers_config);
4866                 service->timeservers_config = NULL;
4867
4868                 if (str->len > 0) {
4869                         char **timeservers = g_strsplit_set(str->str, " ", 0);
4870                         timeservers = remove_empty_strings(timeservers);
4871                         service->timeservers_config = timeservers;
4872                 }
4873
4874                 g_string_free(str, TRUE);
4875
4876                 service_save(service);
4877                 timeservers_configuration_changed(service);
4878
4879                 if (service == connman_service_get_default())
4880                         __connman_timeserver_sync(service);
4881
4882         } else if (g_str_equal(name, "Domains.Configuration")) {
4883                 DBusMessageIter entry;
4884                 GString *str;
4885
4886                 if (service->immutable)
4887                         return __connman_error_not_supported(msg);
4888
4889                 if (type != DBUS_TYPE_ARRAY)
4890                         return __connman_error_invalid_arguments(msg);
4891
4892                 str = g_string_new(NULL);
4893                 if (!str)
4894                         return __connman_error_invalid_arguments(msg);
4895
4896                 dbus_message_iter_recurse(&value, &entry);
4897
4898                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
4899                         const char *val;
4900                         dbus_message_iter_get_basic(&entry, &val);
4901                         dbus_message_iter_next(&entry);
4902
4903                         if (!val[0])
4904                                 continue;
4905
4906                         if (str->len > 0)
4907                                 g_string_append_printf(str, " %s", val);
4908                         else
4909                                 g_string_append(str, val);
4910                 }
4911
4912                 searchdomain_remove_all(service);
4913                 g_strfreev(service->domains);
4914
4915                 if (str->len > 0) {
4916                         char **domains = g_strsplit_set(str->str, " ", 0);
4917                         domains = remove_empty_strings(domains);
4918                         service->domains = domains;
4919                 } else
4920                         service->domains = NULL;
4921
4922                 g_string_free(str, TRUE);
4923
4924                 searchdomain_add_all(service);
4925                 domain_configuration_changed(service);
4926                 domain_changed(service);
4927
4928                 service_save(service);
4929         } else if (g_str_equal(name, "Proxy.Configuration")) {
4930                 int err;
4931
4932                 if (service->immutable)
4933                         return __connman_error_not_supported(msg);
4934
4935                 if (type != DBUS_TYPE_ARRAY)
4936                         return __connman_error_invalid_arguments(msg);
4937
4938                 err = update_proxy_configuration(service, &value);
4939
4940                 if (err < 0)
4941                         return __connman_error_failed(msg, -err);
4942
4943                 proxy_configuration_changed(service);
4944
4945                 __connman_notifier_proxy_changed(service);
4946
4947                 service_save(service);
4948         } else if (g_str_equal(name, "mDNS.Configuration")) {
4949                 dbus_bool_t val;
4950
4951                 if (service->immutable)
4952                         return __connman_error_not_supported(msg);
4953
4954                 if (type != DBUS_TYPE_BOOLEAN)
4955                         return __connman_error_invalid_arguments(msg);
4956
4957                 dbus_message_iter_get_basic(&value, &val);
4958                 service->mdns_config = val;
4959
4960                 mdns_configuration_changed(service);
4961
4962                 set_mdns(service, service->mdns_config);
4963
4964                 service_save(service);
4965         } else if (g_str_equal(name, "IPv4.Configuration") ||
4966                         g_str_equal(name, "IPv6.Configuration")) {
4967
4968                 enum connman_service_state state =
4969                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
4970                 enum connman_ipconfig_type type =
4971                         CONNMAN_IPCONFIG_TYPE_UNKNOWN;
4972                 int err = 0;
4973
4974                 if (service->type == CONNMAN_SERVICE_TYPE_VPN ||
4975                                 service->immutable)
4976                         return __connman_error_not_supported(msg);
4977
4978                 DBG("%s", name);
4979
4980                 if (!service->ipconfig_ipv4 &&
4981                                         !service->ipconfig_ipv6)
4982                         return __connman_error_invalid_property(msg);
4983
4984                 if (g_str_equal(name, "IPv4.Configuration"))
4985                         type = CONNMAN_IPCONFIG_TYPE_IPV4;
4986                 else
4987                         type = CONNMAN_IPCONFIG_TYPE_IPV6;
4988
4989                 err = __connman_service_reset_ipconfig(service, type, &value,
4990                                                                 &state);
4991
4992                 if (err < 0) {
4993                         if (is_connected(state) || is_connecting(state)) {
4994                                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4995                                         __connman_network_enable_ipconfig(service->network,
4996                                                         service->ipconfig_ipv4);
4997                                 else
4998                                         __connman_network_enable_ipconfig(service->network,
4999                                                         service->ipconfig_ipv6);
5000                         }
5001
5002                         return __connman_error_failed(msg, -err);
5003                 }
5004
5005                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
5006                         ipv4_configuration_changed(service);
5007                 else
5008                         ipv6_configuration_changed(service);
5009
5010                 if (is_connecting(service->state) ||
5011                                 is_connected(service->state)) {
5012                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
5013                                 __connman_network_enable_ipconfig(service->network,
5014                                                                 service->ipconfig_ipv4);
5015                         else
5016                                 __connman_network_enable_ipconfig(service->network,
5017                                                                 service->ipconfig_ipv6);
5018                 }
5019
5020                 service_save(service);
5021 #if defined TIZEN_EXT
5022                 /* When AP is connected using WPS without SSID then its password needs
5023                  * to be saved for autoconnection */
5024         } else if (g_str_equal(name, "Passphrase")) {
5025                 char *passphrase;
5026
5027                 if (type != DBUS_TYPE_STRING)
5028                         return __connman_error_invalid_arguments(msg);
5029
5030                 dbus_message_iter_get_basic(&value, &passphrase);
5031
5032                 __connman_service_set_passphrase(service, passphrase);
5033 #endif
5034         } else
5035                 return __connman_error_invalid_property(msg);
5036
5037         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5038 }
5039
5040 static void set_error(struct connman_service *service,
5041                                         enum connman_service_error error)
5042 {
5043         const char *str;
5044
5045         if (service->error == error)
5046                 return;
5047
5048         service->error = error;
5049
5050         if (!service->path)
5051                 return;
5052
5053 #if !defined TIZEN_EXT
5054         if (!allow_property_changed(service))
5055                 return;
5056 #endif
5057
5058         str = error2string(service->error);
5059
5060         if (!str)
5061                 str = "";
5062
5063         connman_dbus_property_changed_basic(service->path,
5064                                 CONNMAN_SERVICE_INTERFACE, "Error",
5065                                 DBUS_TYPE_STRING, &str);
5066 }
5067
5068 static void remove_timeout(struct connman_service *service)
5069 {
5070         if (service->timeout > 0) {
5071                 g_source_remove(service->timeout);
5072                 service->timeout = 0;
5073         }
5074 }
5075
5076 static void reply_pending(struct connman_service *service, int error)
5077 {
5078         remove_timeout(service);
5079
5080         if (service->pending) {
5081                 connman_dbus_reply_pending(service->pending, error, NULL);
5082                 service->pending = NULL;
5083         }
5084
5085         if (service->provider_pending) {
5086                 connman_dbus_reply_pending(service->provider_pending,
5087                                 error, service->path);
5088                 service->provider_pending = NULL;
5089         }
5090 }
5091
5092 static void service_complete(struct connman_service *service)
5093 {
5094         reply_pending(service, EIO);
5095
5096         if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
5097                 __connman_service_auto_connect(service->connect_reason);
5098
5099         g_get_current_time(&service->modified);
5100         service_save(service);
5101 }
5102
5103 static DBusMessage *clear_property(DBusConnection *conn,
5104                                         DBusMessage *msg, void *user_data)
5105 {
5106         struct connman_service *service = user_data;
5107         const char *name;
5108
5109         DBG("service %p", service);
5110
5111         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
5112                                                         DBUS_TYPE_INVALID);
5113
5114         if (g_str_equal(name, "Error")) {
5115                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
5116
5117                 __connman_service_clear_error(service);
5118                 service_complete(service);
5119         } else
5120                 return __connman_error_invalid_property(msg);
5121
5122         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5123 }
5124
5125 static bool is_ipconfig_usable(struct connman_service *service)
5126 {
5127         if (!__connman_ipconfig_is_usable(service->ipconfig_ipv4) &&
5128                         !__connman_ipconfig_is_usable(service->ipconfig_ipv6))
5129                 return false;
5130
5131         return true;
5132 }
5133
5134 static bool is_ignore(struct connman_service *service)
5135 {
5136         if (!service->autoconnect)
5137                 return true;
5138
5139         if (service->roaming &&
5140                 !connman_setting_get_bool("AutoConnectRoamingServices"))
5141                 return true;
5142
5143         if (service->ignore)
5144                 return true;
5145
5146         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
5147                 return true;
5148
5149         if (!is_ipconfig_usable(service))
5150                 return true;
5151
5152         return false;
5153 }
5154
5155 static void disconnect_on_last_session(enum connman_service_type type)
5156 {
5157         GList *list;
5158
5159         for (list = service_list; list; list = list->next) {
5160                 struct connman_service *service = list->data;
5161
5162                 if (service->type != type)
5163                         continue;
5164
5165                 if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_SESSION)
5166                          continue;
5167
5168                 __connman_service_disconnect(service);
5169                 return;
5170         }
5171 }
5172
5173 static int active_sessions[MAX_CONNMAN_SERVICE_TYPES] = {};
5174 static int always_connect[MAX_CONNMAN_SERVICE_TYPES] = {};
5175 static int active_count = 0;
5176
5177 void __connman_service_set_active_session(bool enable, GSList *list)
5178 {
5179         if (!list)
5180                 return;
5181
5182         if (enable)
5183                 active_count++;
5184         else
5185                 active_count--;
5186
5187         while (list) {
5188                 enum connman_service_type type = GPOINTER_TO_INT(list->data);
5189
5190                 switch (type) {
5191                 case CONNMAN_SERVICE_TYPE_ETHERNET:
5192                 case CONNMAN_SERVICE_TYPE_WIFI:
5193                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
5194                 case CONNMAN_SERVICE_TYPE_CELLULAR:
5195                 case CONNMAN_SERVICE_TYPE_GADGET:
5196                         if (enable)
5197                                 active_sessions[type]++;
5198                         else
5199                                 active_sessions[type]--;
5200                         break;
5201
5202                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
5203                 case CONNMAN_SERVICE_TYPE_SYSTEM:
5204                 case CONNMAN_SERVICE_TYPE_GPS:
5205                 case CONNMAN_SERVICE_TYPE_VPN:
5206                 case CONNMAN_SERVICE_TYPE_P2P:
5207 #if defined TIZEN_EXT_WIFI_MESH
5208                 case CONNMAN_SERVICE_TYPE_MESH:
5209 #endif
5210                         break;
5211                 }
5212
5213                 if (active_sessions[type] == 0)
5214                         disconnect_on_last_session(type);
5215
5216                 list = g_slist_next(list);
5217         }
5218
5219         DBG("eth %d wifi %d bt %d cellular %d gadget %d sessions %d",
5220                         active_sessions[CONNMAN_SERVICE_TYPE_ETHERNET],
5221                         active_sessions[CONNMAN_SERVICE_TYPE_WIFI],
5222                         active_sessions[CONNMAN_SERVICE_TYPE_BLUETOOTH],
5223                         active_sessions[CONNMAN_SERVICE_TYPE_CELLULAR],
5224                         active_sessions[CONNMAN_SERVICE_TYPE_GADGET],
5225                         active_count);
5226 }
5227
5228 struct preferred_tech_data {
5229         GList *preferred_list;
5230         enum connman_service_type type;
5231 };
5232
5233 static void preferred_tech_add_by_type(gpointer data, gpointer user_data)
5234 {
5235         struct connman_service *service = data;
5236         struct preferred_tech_data *tech_data = user_data;
5237
5238         if (service->type == tech_data->type) {
5239                 tech_data->preferred_list =
5240                         g_list_append(tech_data->preferred_list, service);
5241
5242                 DBG("type %d service %p %s", tech_data->type, service,
5243                                 service->name);
5244         }
5245 }
5246
5247 static GList *preferred_tech_list_get(void)
5248 {
5249         unsigned int *tech_array;
5250         struct preferred_tech_data tech_data = { 0, };
5251         int i;
5252
5253         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
5254         if (!tech_array)
5255                 return NULL;
5256
5257         if (connman_setting_get_bool("SingleConnectedTechnology")) {
5258                 GList *list;
5259                 for (list = service_list; list; list = list->next) {
5260                         struct connman_service *service = list->data;
5261
5262                         if (!is_connected(service->state))
5263                                 break;
5264
5265                         if (service->connect_reason ==
5266                                         CONNMAN_SERVICE_CONNECT_REASON_USER) {
5267                                 DBG("service %p name %s is user connected",
5268                                                 service, service->name);
5269 #if defined TIZEN_EXT
5270                                 /* We can connect to a favorite service like
5271                                  * wifi even we have a userconnect for cellular
5272                                  * because we have refount for cellular service
5273                                  */
5274                                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5275                                         break;
5276
5277                                 if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
5278                                         break;
5279 #endif
5280                                 return NULL;
5281                         }
5282                 }
5283         }
5284
5285         for (i = 0; tech_array[i] != 0; i += 1) {
5286                 tech_data.type = tech_array[i];
5287                 g_list_foreach(service_list, preferred_tech_add_by_type,
5288                                 &tech_data);
5289         }
5290
5291         return tech_data.preferred_list;
5292 }
5293
5294 static void set_always_connecting_technologies()
5295 {
5296         unsigned int *always_connected_techs =
5297                 connman_setting_get_uint_list("AlwaysConnectedTechnologies");
5298         int i;
5299         for (i = 0; always_connected_techs && always_connected_techs[i]; i++)
5300                 always_connect[always_connected_techs[i]] = 1;
5301 }
5302
5303 static bool autoconnect_no_session_active(struct connman_service *service)
5304 {
5305         /*
5306          * Test active_count to see if there are no sessions set up and
5307          * stop autoconnecting, but continue connecting if the service
5308          * belongs to a technology which should always autoconnect.
5309          */
5310         if (!active_count && !always_connect[service->type])
5311                 return true;
5312
5313         return false;
5314 }
5315
5316 static bool autoconnect_already_connecting(struct connman_service *service,
5317                                            bool autoconnecting)
5318 {
5319         /*
5320          * If another service is already connecting and this service type has
5321          * not been marked as always connecting, stop the connecting procedure.
5322          */
5323         if (autoconnecting &&
5324                         !active_sessions[service->type] &&
5325                         !always_connect[service->type])
5326                 return true;
5327
5328         return false;
5329 }
5330
5331 static bool auto_connect_service(GList *services,
5332                                 enum connman_service_connect_reason reason,
5333                                 bool preferred)
5334 {
5335         struct connman_service *service = NULL;
5336         bool ignore[MAX_CONNMAN_SERVICE_TYPES] = { };
5337         bool autoconnecting = false;
5338         GList *list;
5339
5340         DBG("preferred %d sessions %d reason %s", preferred, active_count,
5341                 reason2string(reason));
5342
5343         ignore[CONNMAN_SERVICE_TYPE_VPN] = true;
5344
5345 #if defined TIZEN_EXT_WIFI_MESH
5346         /* Don't auto connect wifi if mesh interface is created */
5347         if (connman_mesh_is_interface_created())
5348                 ignore[CONNMAN_SERVICE_TYPE_WIFI] = true;
5349 #endif
5350
5351         for (list = services; list; list = list->next) {
5352                 service = list->data;
5353
5354                 if (ignore[service->type]) {
5355                         DBG("service %p type %s ignore", service,
5356                                 __connman_service_type2string(service->type));
5357                         continue;
5358                 }
5359
5360 #if defined TIZEN_EXT
5361                 DBG("service %p %s %s %s, favorite(%d), ignore(%d), hidden(%d, %d)",
5362                                 service, service->name,
5363                                 state2string(service->state),
5364                                 __connman_service_type2string(service->type),
5365                                 service->favorite, is_ignore(service),
5366                                 service->hidden, service->hidden_service);
5367
5368                 /* Tizen takes Wi-Fi as the highest priority into consideration. */
5369                 if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
5370                         if (is_connecting(service->state) == TRUE || is_connected(service->state) == TRUE)
5371                                 continue;
5372 #endif
5373
5374                 if (service->pending ||
5375                                 is_connecting(service->state) ||
5376                                 is_connected(service->state)) {
5377                         if (autoconnect_no_session_active(service))
5378                                         return true;
5379
5380                         ignore[service->type] = true;
5381                         autoconnecting = true;
5382
5383                         DBG("service %p type %s busy", service,
5384                                 __connman_service_type2string(service->type));
5385
5386                         continue;
5387                 }
5388
5389                 if (!service->favorite) {
5390                         if (preferred)
5391                                continue;
5392
5393 #if defined TIZEN_EXT
5394                         DBG("Service is not favorite, autoconnecting %d",
5395                                         autoconnecting);
5396 #endif
5397                         return autoconnecting;
5398                 }
5399
5400 #if defined TIZEN_EXT
5401                 DBG("service %p identifier %s roaming %d ignore %d "
5402                                 "ipconfig_usable %d autoconnect %d state %d",
5403                                 service,
5404                                 service->identifier, service->roaming,
5405                                 service->ignore, is_ipconfig_usable(service),
5406                                 service->autoconnect, service->state);
5407 #endif
5408                 if (is_ignore(service) || service->state !=
5409                                 CONNMAN_SERVICE_STATE_IDLE)
5410                         continue;
5411
5412                 if (autoconnect_already_connecting(service, autoconnecting)) {
5413                         DBG("service %p type %s has no users", service,
5414                                 __connman_service_type2string(service->type));
5415                         continue;
5416                 }
5417
5418                 DBG("service %p %s %s", service, service->name,
5419                         (preferred) ? "preferred" : reason2string(reason));
5420
5421                 __connman_service_connect(service, reason);
5422
5423                 if (autoconnect_no_session_active(service))
5424                         return true;
5425
5426                 ignore[service->type] = true;
5427         }
5428
5429         return autoconnecting;
5430 }
5431
5432 static gboolean run_auto_connect(gpointer data)
5433 {
5434         enum connman_service_connect_reason reason = GPOINTER_TO_UINT(data);
5435         bool autoconnecting = false;
5436         GList *preferred_tech;
5437
5438         autoconnect_id = 0;
5439
5440         DBG("");
5441
5442         preferred_tech = preferred_tech_list_get();
5443         if (preferred_tech) {
5444                 autoconnecting = auto_connect_service(preferred_tech, reason,
5445                                                         true);
5446                 g_list_free(preferred_tech);
5447         }
5448
5449         if (!autoconnecting || active_count)
5450                 auto_connect_service(service_list, reason, false);
5451
5452         return FALSE;
5453 }
5454
5455 #if defined TIZEN_EXT
5456 bool __connman_service_get_auto_connect_mode(void)
5457 {
5458         return auto_connect_mode;
5459 }
5460
5461 void __connman_service_set_auto_connect_mode(bool enable)
5462 {
5463         DBG("set auto_connect_mode = %d", enable);
5464
5465         if (auto_connect_mode != enable)
5466                 auto_connect_mode = enable;
5467 }
5468 #endif
5469
5470 void __connman_service_auto_connect(enum connman_service_connect_reason reason)
5471 {
5472         DBG("");
5473
5474         if (autoconnect_id != 0)
5475                 return;
5476
5477 #if defined TIZEN_EXT
5478         if (auto_connect_mode == FALSE) {
5479                 DBG("Currently, not auto connection mode");
5480                 return;
5481         }
5482 #endif
5483
5484         if (!__connman_session_policy_autoconnect(reason))
5485                 return;
5486
5487 #if defined TIZEN_EXT
5488         /* Adding Timeout of 500ms before trying to auto connect.
5489          * This is done because of below scenario
5490          * 1. Device is connected to AP1
5491          * 2. WPS Connection request is initiated for AP2
5492          * 3. Immediately WPS Connection is Cancelled
5493          * When WPS Connection Connection is initiated for AP2 then
5494          * sometimes there is a scenario where connman gets in ASSOCIATED
5495          * state with AP1 due to autoconnect and subsequently the connection
5496          * initiated by AP1 fails and connman service for AP1 comes in
5497          * FAILURE state due to this when connection with AP2 is cancelled
5498          * then autoconnect with AP1 doesn't works because its autoconnection
5499          * is ignored as its last state was FAILURE rather than IDLE */
5500         autoconnect_id = g_timeout_add(500, run_auto_connect,
5501 #else
5502         autoconnect_id = g_idle_add(run_auto_connect,
5503 #endif
5504                                                 GUINT_TO_POINTER(reason));
5505 }
5506
5507 static gboolean run_vpn_auto_connect(gpointer data) {
5508         GList *list;
5509         bool need_split = false;
5510
5511         vpn_autoconnect_id = 0;
5512
5513         for (list = service_list; list; list = list->next) {
5514                 struct connman_service *service = list->data;
5515                 int res;
5516
5517                 if (service->type != CONNMAN_SERVICE_TYPE_VPN)
5518                         continue;
5519
5520                 if (is_connected(service->state) ||
5521                                 is_connecting(service->state)) {
5522                         if (!service->do_split_routing)
5523                                 need_split = true;
5524                         continue;
5525                 }
5526
5527                 if (is_ignore(service) || !service->favorite)
5528                         continue;
5529
5530                 if (need_split && !service->do_split_routing) {
5531                         DBG("service %p no split routing", service);
5532                         continue;
5533                 }
5534
5535                 DBG("service %p %s %s", service, service->name,
5536                                 service->do_split_routing ?
5537                                 "split routing" : "");
5538
5539                 res = __connman_service_connect(service,
5540                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
5541                 if (res < 0 && res != -EINPROGRESS)
5542                         continue;
5543
5544                 if (!service->do_split_routing)
5545                         need_split = true;
5546         }
5547
5548         return FALSE;
5549 }
5550
5551 static void vpn_auto_connect(void)
5552 {
5553         if (vpn_autoconnect_id)
5554                 return;
5555
5556         vpn_autoconnect_id =
5557                 g_idle_add(run_vpn_auto_connect, NULL);
5558 }
5559
5560 bool
5561 __connman_service_is_provider_pending(struct connman_service *service)
5562 {
5563         if (!service)
5564                 return false;
5565
5566         if (service->provider_pending)
5567                 return true;
5568
5569         return false;
5570 }
5571
5572 void __connman_service_set_provider_pending(struct connman_service *service,
5573                                                         DBusMessage *msg)
5574 {
5575         if (service->provider_pending) {
5576                 DBG("service %p provider pending msg %p already exists",
5577                         service, service->provider_pending);
5578                 return;
5579         }
5580
5581         service->provider_pending = msg;
5582 }
5583
5584 static void check_pending_msg(struct connman_service *service)
5585 {
5586         if (!service->pending)
5587                 return;
5588
5589         DBG("service %p pending msg %p already exists", service,
5590                                                 service->pending);
5591         dbus_message_unref(service->pending);
5592 }
5593
5594 void __connman_service_set_hidden_data(struct connman_service *service,
5595                                                         gpointer user_data)
5596 {
5597         DBusMessage *pending = user_data;
5598
5599         DBG("service %p pending %p", service, pending);
5600
5601         if (!pending)
5602                 return;
5603
5604         check_pending_msg(service);
5605
5606         service->pending = pending;
5607 }
5608
5609 void __connman_service_return_error(struct connman_service *service,
5610                                 int error, gpointer user_data)
5611 {
5612         DBG("service %p error %d user_data %p", service, error, user_data);
5613
5614         __connman_service_set_hidden_data(service, user_data);
5615
5616         reply_pending(service, error);
5617 }
5618
5619 static gboolean connect_timeout(gpointer user_data)
5620 {
5621         struct connman_service *service = user_data;
5622         bool autoconnect = false;
5623
5624         DBG("service %p", service);
5625
5626         service->timeout = 0;
5627
5628         if (service->network)
5629                 __connman_network_disconnect(service->network);
5630         else if (service->provider)
5631                 connman_provider_disconnect(service->provider);
5632
5633         __connman_stats_service_unregister(service);
5634
5635         if (service->pending) {
5636                 DBusMessage *reply;
5637
5638                 reply = __connman_error_operation_timeout(service->pending);
5639                 if (reply)
5640                         g_dbus_send_message(connection, reply);
5641
5642                 dbus_message_unref(service->pending);
5643                 service->pending = NULL;
5644         } else
5645                 autoconnect = true;
5646
5647         __connman_service_ipconfig_indicate_state(service,
5648                                         CONNMAN_SERVICE_STATE_FAILURE,
5649                                         CONNMAN_IPCONFIG_TYPE_IPV4);
5650         __connman_service_ipconfig_indicate_state(service,
5651                                         CONNMAN_SERVICE_STATE_FAILURE,
5652                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5653
5654         if (autoconnect &&
5655                         service->connect_reason !=
5656                                 CONNMAN_SERVICE_CONNECT_REASON_USER)
5657                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
5658
5659         return FALSE;
5660 }
5661
5662 static DBusMessage *connect_service(DBusConnection *conn,
5663                                         DBusMessage *msg, void *user_data)
5664 {
5665         struct connman_service *service = user_data;
5666 #if defined TIZEN_EXT
5667         int err = 0;
5668 #else
5669         int index, err = 0;
5670         GList *list;
5671 #endif
5672
5673         DBG("service %p", service);
5674
5675 #if defined TIZEN_EXT
5676         /*
5677          * Description: TIZEN implements system global connection management.
5678          */
5679         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5680                 connman_service_user_pdn_connection_ref(service);
5681
5682         /*Reset the Disconnect Reason while issue connect request*/
5683         service->disconnect_reason = 0;
5684
5685         /*Reset the association status code while issue connect request*/
5686         service->assoc_status_code = 0;
5687
5688         /* Reset the disconnection_requested while issue connect request*/
5689         connman_service_set_disconnection_requested(service, false);
5690 #endif
5691
5692         if (service->pending)
5693                 return __connman_error_in_progress(msg);
5694
5695 #if !defined TIZEN_EXT
5696         index = __connman_service_get_index(service);
5697
5698         for (list = service_list; list; list = list->next) {
5699                 struct connman_service *temp = list->data;
5700
5701 #if defined TIZEN_EXT
5702                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5703                         break;
5704 #endif
5705                 if (!is_connecting(temp->state) && !is_connected(temp->state))
5706                         break;
5707
5708                 if (service == temp)
5709                         continue;
5710
5711                 if (service->type != temp->type)
5712                         continue;
5713
5714                 if (__connman_service_get_index(temp) == index &&
5715                                 __connman_service_disconnect(temp) == -EINPROGRESS)
5716                         err = -EINPROGRESS;
5717
5718         }
5719         if (err == -EINPROGRESS)
5720                 return __connman_error_operation_timeout(msg);
5721 #endif
5722
5723         service->ignore = false;
5724
5725         service->pending = dbus_message_ref(msg);
5726
5727         err = __connman_service_connect(service,
5728                         CONNMAN_SERVICE_CONNECT_REASON_USER);
5729
5730         if (err != -EINPROGRESS)
5731                 reply_pending(service, -err);
5732
5733         return NULL;
5734 }
5735
5736 static DBusMessage *disconnect_service(DBusConnection *conn,
5737                                         DBusMessage *msg, void *user_data)
5738 {
5739         struct connman_service *service = user_data;
5740         int err;
5741
5742         DBG("service %p", service);
5743
5744 #if defined TIZEN_EXT
5745         /*
5746          * Description: TIZEN implements system global connection management.
5747          */
5748         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
5749                 if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE)
5750                         return __connman_error_failed(msg, EISCONN);
5751
5752                 if (is_connected(service->state) == TRUE &&
5753                                 service == connman_service_get_default_connection())
5754                         return __connman_error_failed(msg, EISCONN);
5755         }
5756 #endif
5757
5758         service->ignore = true;
5759
5760         err = __connman_service_disconnect(service);
5761         if (err < 0 && err != -EINPROGRESS)
5762                 return __connman_error_failed(msg, -err);
5763
5764         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5765 }
5766
5767 #if defined TIZEN_EXT
5768 static void __connman_service_cleanup_network_8021x(struct connman_service *service)
5769 {
5770         if (service == NULL)
5771                 return;
5772
5773         DBG("service %p ", service);
5774
5775         connman_network_set_string(service->network, "WiFi.EAP", NULL);
5776         connman_network_set_string(service->network, "WiFi.Identity", NULL);
5777         connman_network_set_string(service->network, "WiFi.CACertFile", NULL);
5778         connman_network_set_string(service->network, "WiFi.ClientCertFile", NULL);
5779         connman_network_set_string(service->network, "WiFi.PrivateKeyFile", NULL);
5780         connman_network_set_string(service->network, "WiFi.PrivateKeyPassphrase", NULL);
5781         connman_network_set_string(service->network, "WiFi.Phase2", NULL);
5782         connman_network_set_string(service->network, "WiFi.AnonymousIdentity", NULL);
5783 }
5784 static void __connman_service_cleanup_network_dpp(struct connman_service *service)
5785 {
5786         if (service == NULL)
5787                 return;
5788
5789         DBG("service %p ", service);
5790
5791         connman_network_set_string(service->network, "WiFi.Connector", NULL);
5792         connman_network_set_string(service->network, "WiFi.CSignKey", NULL);
5793         connman_network_set_string(service->network, "WiFi.NetAccessKey", NULL);
5794 }
5795 #endif
5796
5797 bool __connman_service_remove(struct connman_service *service)
5798 {
5799         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET ||
5800                         service->type == CONNMAN_SERVICE_TYPE_GADGET)
5801                 return false;
5802
5803         if (service->immutable || service->hidden ||
5804                         __connman_provider_is_immutable(service->provider))
5805                 return false;
5806
5807 #if !defined TIZEN_EXT
5808         if (!service->favorite && !is_idle(service->state))
5809                 return false;
5810 #endif
5811
5812         __connman_service_disconnect(service);
5813
5814         g_free(service->passphrase);
5815         service->passphrase = NULL;
5816
5817         g_free(service->identity);
5818         service->identity = NULL;
5819
5820         g_free(service->anonymous_identity);
5821         service->anonymous_identity = NULL;
5822
5823         g_free(service->subject_match);
5824         service->subject_match = NULL;
5825
5826         g_free(service->altsubject_match);
5827         service->altsubject_match = NULL;
5828
5829         g_free(service->domain_suffix_match);
5830         service->domain_suffix_match = NULL;
5831
5832         g_free(service->domain_match);
5833         service->domain_match = NULL;
5834
5835         g_free(service->agent_identity);
5836         service->agent_identity = NULL;
5837
5838         g_free(service->eap);
5839         service->eap = NULL;
5840
5841 #if defined TIZEN_EXT
5842         g_free(service->ca_cert_file);
5843         service->ca_cert_file = NULL;
5844
5845         g_free(service->client_cert_file);
5846         service->client_cert_file = NULL;
5847
5848         g_free(service->private_key_file);
5849         service->private_key_file = NULL;
5850
5851         g_free(service->private_key_passphrase);
5852         service->private_key_passphrase = NULL;
5853
5854         g_free(service->phase2);
5855         service->phase2 = NULL;
5856
5857         __connman_service_cleanup_network_8021x(service);
5858
5859         __connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP);
5860         __connman_ipconfig_set_method(service->ipconfig_ipv6, CONNMAN_IPCONFIG_METHOD_AUTO);
5861         connman_service_set_proxy(service, NULL, false);
5862
5863         __connman_service_nameserver_clear(service);
5864
5865         g_strfreev(service->nameservers_config);
5866         service->nameservers_config = NULL;
5867
5868         g_free(service->connector);
5869         service->connector = NULL;
5870
5871         g_free(service->c_sign_key);
5872         service->c_sign_key = NULL;
5873
5874         g_free(service->net_access_key);
5875         service->net_access_key = NULL;
5876
5877         __connman_service_cleanup_network_dpp(service);
5878 #endif
5879
5880         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
5881
5882         __connman_service_set_favorite(service, false);
5883
5884         __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
5885
5886 #if defined TIZEN_EXT
5887         /* Reset IP Method and DNS Method to DHCP */
5888         __connman_ipconfig_set_method(service->ipconfig_ipv4,
5889                         CONNMAN_IPCONFIG_METHOD_DHCP);
5890         service->dns_config_method_ipv4 = CONNMAN_DNSCONFIG_METHOD_DHCP;
5891         g_strfreev(service->nameservers_config);
5892         service->nameservers_config = NULL;
5893 #endif
5894
5895 #if defined TIZEN_EXT
5896         __connman_storage_remove_service(service->identifier);
5897 #else
5898         service_save(service);
5899 #endif
5900
5901         return true;
5902 }
5903
5904 static DBusMessage *remove_service(DBusConnection *conn,
5905                                         DBusMessage *msg, void *user_data)
5906 {
5907         struct connman_service *service = user_data;
5908
5909         DBG("service %p", service);
5910
5911         if (!__connman_service_remove(service))
5912                 return __connman_error_not_supported(msg);
5913
5914         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5915 }
5916
5917 static bool check_suitable_state(enum connman_service_state a,
5918                                         enum connman_service_state b)
5919 {
5920         /*
5921          * Special check so that "ready" service can be moved before
5922          * "online" one.
5923          */
5924         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
5925                         b == CONNMAN_SERVICE_STATE_READY) ||
5926                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
5927                         a == CONNMAN_SERVICE_STATE_READY))
5928                 return true;
5929
5930         return a == b;
5931 }
5932
5933 static void downgrade_state(struct connman_service *service)
5934 {
5935         if (!service)
5936                 return;
5937
5938         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
5939                                                 service->state_ipv6);
5940
5941         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
5942                 __connman_service_ipconfig_indicate_state(service,
5943                                                 CONNMAN_SERVICE_STATE_READY,
5944                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
5945
5946         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
5947                 __connman_service_ipconfig_indicate_state(service,
5948                                                 CONNMAN_SERVICE_STATE_READY,
5949                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5950 }
5951
5952 static void apply_relevant_default_downgrade(struct connman_service *service)
5953 {
5954         struct connman_service *def_service;
5955
5956         def_service = connman_service_get_default();
5957         if (!def_service)
5958                 return;
5959
5960         if (def_service == service &&
5961                         def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
5962                 def_service->state = CONNMAN_SERVICE_STATE_READY;
5963                 __connman_notifier_leave_online(def_service->type);
5964                 state_changed(def_service);
5965         }
5966 }
5967
5968 static void switch_default_service(struct connman_service *default_service,
5969                 struct connman_service *downgrade_service)
5970 {
5971         struct connman_service *service;
5972         GList *src, *dst;
5973
5974         apply_relevant_default_downgrade(default_service);
5975         src = g_list_find(service_list, downgrade_service);
5976         dst = g_list_find(service_list, default_service);
5977
5978         /* Nothing to do */
5979         if (src == dst || src->next == dst)
5980                 return;
5981
5982         service = src->data;
5983         service_list = g_list_delete_link(service_list, src);
5984         service_list = g_list_insert_before(service_list, dst, service);
5985
5986         downgrade_state(downgrade_service);
5987 }
5988
5989 static struct _services_notify {
5990         int id;
5991         GHashTable *add;
5992         GHashTable *remove;
5993 } *services_notify;
5994
5995
5996 static void service_append_added_foreach(gpointer data, gpointer user_data)
5997 {
5998         struct connman_service *service = data;
5999         DBusMessageIter *iter = user_data;
6000
6001         if (!service || !service->path) {
6002                 DBG("service %p or path is NULL", service);
6003                 return;
6004         }
6005
6006         if (g_hash_table_lookup(services_notify->add, service->path)) {
6007                 DBG("new %s", service->path);
6008
6009                 append_struct(service, iter);
6010                 g_hash_table_remove(services_notify->add, service->path);
6011         } else {
6012                 DBG("changed %s", service->path);
6013
6014                 append_struct_service(iter, NULL, service);
6015         }
6016 }
6017
6018 static void service_append_ordered(DBusMessageIter *iter, void *user_data)
6019 {
6020         g_list_foreach(service_list, service_append_added_foreach, iter);
6021 }
6022
6023 static void append_removed(gpointer key, gpointer value, gpointer user_data)
6024 {
6025         char *objpath = key;
6026         DBusMessageIter *iter = user_data;
6027
6028         DBG("removed %s", objpath);
6029         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
6030 }
6031
6032 static void service_append_removed(DBusMessageIter *iter, void *user_data)
6033 {
6034         g_hash_table_foreach(services_notify->remove, append_removed, iter);
6035 }
6036
6037 static gboolean service_send_changed(gpointer data)
6038 {
6039         DBusMessage *signal;
6040
6041         DBG("");
6042
6043         services_notify->id = 0;
6044
6045         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
6046                         CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
6047         if (!signal)
6048                 return FALSE;
6049
6050         __connman_dbus_append_objpath_dict_array(signal,
6051                                         service_append_ordered, NULL);
6052         __connman_dbus_append_objpath_array(signal,
6053                                         service_append_removed, NULL);
6054
6055         dbus_connection_send(connection, signal, NULL);
6056         dbus_message_unref(signal);
6057
6058         g_hash_table_remove_all(services_notify->remove);
6059         g_hash_table_remove_all(services_notify->add);
6060
6061         return FALSE;
6062 }
6063
6064 static void service_schedule_changed(void)
6065 {
6066         if (services_notify->id != 0)
6067                 return;
6068
6069         services_notify->id = g_timeout_add(100, service_send_changed, NULL);
6070 }
6071
6072 static DBusMessage *move_service(DBusConnection *conn,
6073                                         DBusMessage *msg, void *user_data,
6074                                                                 bool before)
6075 {
6076         struct connman_service *service = user_data;
6077         struct connman_service *target;
6078         const char *path;
6079         enum connman_ipconfig_method target4, target6;
6080         enum connman_ipconfig_method service4, service6;
6081
6082         DBG("service %p", service);
6083
6084         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
6085                                                         DBUS_TYPE_INVALID);
6086
6087         if (!service->favorite)
6088                 return __connman_error_not_supported(msg);
6089
6090         target = find_service(path);
6091         if (!target || !target->favorite || target == service)
6092                 return __connman_error_invalid_service(msg);
6093
6094         if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
6095                 /*
6096                  * We only allow VPN route splitting if there are
6097                  * routes defined for a given VPN.
6098                  */
6099                 if (!__connman_provider_check_routes(target->provider)) {
6100                         connman_info("Cannot move service. "
6101                                 "No routes defined for provider %s",
6102                                 __connman_provider_get_ident(target->provider));
6103                         return __connman_error_invalid_service(msg);
6104                 }
6105
6106                 set_split_routing(target, true);
6107         } else
6108                 set_split_routing(target, false);
6109
6110         set_split_routing(service, false);
6111
6112         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
6113         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
6114         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
6115         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
6116
6117         DBG("target %s method %d/%d state %d/%d split %d", target->identifier,
6118                 target4, target6, target->state_ipv4, target->state_ipv6,
6119                 target->do_split_routing);
6120
6121         DBG("service %s method %d/%d state %d/%d", service->identifier,
6122                                 service4, service6,
6123                                 service->state_ipv4, service->state_ipv6);
6124
6125         /*
6126          * If method is OFF, then we do not need to check the corresponding
6127          * ipconfig state.
6128          */
6129         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
6130                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
6131                         if (!check_suitable_state(target->state_ipv6,
6132                                                         service->state_ipv6))
6133                                 return __connman_error_invalid_service(msg);
6134                 }
6135         }
6136
6137         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
6138                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
6139                         if (!check_suitable_state(target->state_ipv4,
6140                                                         service->state_ipv4))
6141                                 return __connman_error_invalid_service(msg);
6142                 }
6143         }
6144
6145         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
6146                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
6147                         if (!check_suitable_state(target->state_ipv6,
6148                                                         service->state_ipv6))
6149                                 return __connman_error_invalid_service(msg);
6150                 }
6151         }
6152
6153         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
6154                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
6155                         if (!check_suitable_state(target->state_ipv4,
6156                                                         service->state_ipv4))
6157                                 return __connman_error_invalid_service(msg);
6158                 }
6159         }
6160
6161         g_get_current_time(&service->modified);
6162         service_save(service);
6163         service_save(target);
6164
6165         /*
6166          * If the service which goes down is the default service and is
6167          * online, we downgrade directly its state to ready so:
6168          * the service which goes up, needs to recompute its state which
6169          * is triggered via downgrading it - if relevant - to state ready.
6170          */
6171         if (before)
6172                 switch_default_service(target, service);
6173         else
6174                 switch_default_service(service, target);
6175
6176         __connman_connection_update_gateway();
6177
6178         service_schedule_changed();
6179
6180         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
6181 }
6182
6183 static DBusMessage *move_before(DBusConnection *conn,
6184                                         DBusMessage *msg, void *user_data)
6185 {
6186         return move_service(conn, msg, user_data, true);
6187 }
6188
6189 static DBusMessage *move_after(DBusConnection *conn,
6190                                         DBusMessage *msg, void *user_data)
6191 {
6192         return move_service(conn, msg, user_data, false);
6193 }
6194
6195 static DBusMessage *reset_counters(DBusConnection *conn,
6196                                         DBusMessage *msg, void *user_data)
6197 {
6198         struct connman_service *service = user_data;
6199
6200         reset_stats(service);
6201
6202         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
6203 }
6204
6205 #if defined TIZEN_MAINTAIN_ONLINE
6206 static DBusMessage *downgrade_service(DBusConnection *conn,
6207                                         DBusMessage *msg, void *user_data)
6208 {
6209         struct connman_service *service = user_data;
6210
6211         downgrade_state(service);
6212         __connman_connection_update_gateway();
6213
6214         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
6215 }
6216 #endif
6217
6218 static void service_schedule_added(struct connman_service *service)
6219 {
6220         DBG("service %p", service);
6221
6222         g_hash_table_remove(services_notify->remove, service->path);
6223         g_hash_table_replace(services_notify->add, service->path, service);
6224
6225         service_schedule_changed();
6226 }
6227
6228 static void service_schedule_removed(struct connman_service *service)
6229 {
6230         if (!service || !service->path) {
6231                 DBG("service %p or path is NULL", service);
6232                 return;
6233         }
6234
6235         DBG("service %p %s", service, service->path);
6236
6237         g_hash_table_remove(services_notify->add, service->path);
6238         g_hash_table_replace(services_notify->remove, g_strdup(service->path),
6239                         NULL);
6240
6241         service_schedule_changed();
6242 }
6243
6244 static bool allow_property_changed(struct connman_service *service)
6245 {
6246 #if defined TIZEN_EXT
6247         if (service->path == NULL)
6248                 return FALSE;
6249 #endif
6250         if (g_hash_table_lookup_extended(services_notify->add, service->path,
6251                                         NULL, NULL))
6252                 return false;
6253
6254         return true;
6255 }
6256
6257 static const GDBusMethodTable service_methods[] = {
6258         { GDBUS_DEPRECATED_METHOD("GetProperties",
6259                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
6260                         get_properties) },
6261         { GDBUS_METHOD("SetProperty",
6262                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
6263                         NULL, set_property) },
6264         { GDBUS_METHOD("ClearProperty",
6265                         GDBUS_ARGS({ "name", "s" }), NULL,
6266                         clear_property) },
6267         { GDBUS_ASYNC_METHOD("Connect", NULL, NULL,
6268                               connect_service) },
6269         { GDBUS_METHOD("Disconnect", NULL, NULL,
6270                         disconnect_service) },
6271         { GDBUS_METHOD("Remove", NULL, NULL, remove_service) },
6272         { GDBUS_METHOD("MoveBefore",
6273                         GDBUS_ARGS({ "service", "o" }), NULL,
6274                         move_before) },
6275         { GDBUS_METHOD("MoveAfter",
6276                         GDBUS_ARGS({ "service", "o" }), NULL,
6277                         move_after) },
6278         { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
6279 #if defined TIZEN_MAINTAIN_ONLINE
6280         { GDBUS_METHOD("Downgrade", NULL, NULL, downgrade_service) },
6281 #endif
6282         { },
6283 };
6284
6285 static const GDBusSignalTable service_signals[] = {
6286         { GDBUS_SIGNAL("PropertyChanged",
6287                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
6288         { },
6289 };
6290
6291 static void service_free(gpointer user_data)
6292 {
6293         struct connman_service *service = user_data;
6294         char *path = service->path;
6295
6296         DBG("service %p", service);
6297
6298         reply_pending(service, ENOENT);
6299
6300         if (service->nameservers_timeout) {
6301                 g_source_remove(service->nameservers_timeout);
6302                 dns_changed(service);
6303         }
6304
6305         __connman_notifier_service_remove(service);
6306         service_schedule_removed(service);
6307
6308         __connman_wispr_stop(service);
6309         stats_stop(service);
6310
6311         service->path = NULL;
6312
6313         if (path) {
6314                 __connman_connection_update_gateway();
6315
6316                 g_dbus_unregister_interface(connection, path,
6317                                                 CONNMAN_SERVICE_INTERFACE);
6318                 g_free(path);
6319         }
6320
6321         g_hash_table_destroy(service->counter_table);
6322
6323         if (service->network) {
6324                 __connman_network_disconnect(service->network);
6325                 connman_network_unref(service->network);
6326                 service->network = NULL;
6327         }
6328
6329         if (service->provider)
6330                 connman_provider_unref(service->provider);
6331
6332         if (service->ipconfig_ipv4) {
6333                 __connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
6334                 __connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
6335                 __connman_ipconfig_unref(service->ipconfig_ipv4);
6336                 service->ipconfig_ipv4 = NULL;
6337         }
6338
6339         if (service->ipconfig_ipv6) {
6340                 __connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
6341                 __connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
6342                 __connman_ipconfig_unref(service->ipconfig_ipv6);
6343                 service->ipconfig_ipv6 = NULL;
6344         }
6345
6346         g_strfreev(service->timeservers);
6347         g_strfreev(service->timeservers_config);
6348         g_strfreev(service->nameservers);
6349         g_strfreev(service->nameservers_config);
6350         g_strfreev(service->nameservers_auto);
6351         g_strfreev(service->domains);
6352         g_strfreev(service->proxies);
6353         g_strfreev(service->excludes);
6354
6355         g_free(service->hostname);
6356         g_free(service->domainname);
6357         g_free(service->pac);
6358         g_free(service->name);
6359         g_free(service->passphrase);
6360         g_free(service->identifier);
6361         g_free(service->eap);
6362         g_free(service->identity);
6363         g_free(service->anonymous_identity);
6364         g_free(service->agent_identity);
6365         g_free(service->ca_cert_file);
6366         g_free(service->subject_match);
6367         g_free(service->altsubject_match);
6368         g_free(service->domain_suffix_match);
6369         g_free(service->domain_match);
6370         g_free(service->client_cert_file);
6371         g_free(service->private_key_file);
6372         g_free(service->private_key_passphrase);
6373         g_free(service->phase2);
6374         g_free(service->config_file);
6375         g_free(service->config_entry);
6376 #if defined TIZEN_EXT
6377         g_free(service->connector);
6378         g_free(service->c_sign_key);
6379         g_free(service->net_access_key);
6380 #endif
6381
6382         if (service->stats.timer)
6383                 g_timer_destroy(service->stats.timer);
6384         if (service->stats_roaming.timer)
6385                 g_timer_destroy(service->stats_roaming.timer);
6386
6387         if (current_default == service)
6388                 current_default = NULL;
6389
6390         g_free(service);
6391 }
6392
6393 static void stats_init(struct connman_service *service)
6394 {
6395         /* home */
6396         service->stats.valid = false;
6397         service->stats.enabled = false;
6398         service->stats.timer = g_timer_new();
6399
6400         /* roaming */
6401         service->stats_roaming.valid = false;
6402         service->stats_roaming.enabled = false;
6403         service->stats_roaming.timer = g_timer_new();
6404 }
6405
6406 static void service_initialize(struct connman_service *service)
6407 {
6408         DBG("service %p", service);
6409
6410         service->refcount = 1;
6411
6412         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
6413
6414         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
6415         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
6416
6417         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
6418         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
6419         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
6420
6421         service->favorite  = false;
6422         service->immutable = false;
6423         service->hidden = false;
6424
6425         service->ignore = false;
6426
6427         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
6428
6429         service->order = 0;
6430
6431         stats_init(service);
6432
6433         service->provider = NULL;
6434
6435         service->wps = false;
6436         service->wps_advertizing = false;
6437 #if defined TIZEN_EXT
6438         service->disconnection_requested = false;
6439         service->storage_reload = false;
6440         /*
6441          * Description: TIZEN implements system global connection management.
6442          */
6443         service->user_pdn_connection_refcount = 0;
6444         __sync_synchronize();
6445 #endif
6446 }
6447
6448 /**
6449  * connman_service_create:
6450  *
6451  * Allocate a new service.
6452  *
6453  * Returns: a newly-allocated #connman_service structure
6454  */
6455 struct connman_service *connman_service_create(void)
6456 {
6457         GSList *list;
6458         struct connman_stats_counter *counters;
6459         const char *counter;
6460
6461         struct connman_service *service;
6462
6463         service = g_try_new0(struct connman_service, 1);
6464         if (!service)
6465                 return NULL;
6466
6467         DBG("service %p", service);
6468
6469         service->counter_table = g_hash_table_new_full(g_str_hash,
6470                                                 g_str_equal, NULL, g_free);
6471
6472         for (list = counter_list; list; list = list->next) {
6473                 counter = list->data;
6474
6475                 counters = g_try_new0(struct connman_stats_counter, 1);
6476                 if (!counters) {
6477                         g_hash_table_destroy(service->counter_table);
6478                         g_free(service);
6479                         return NULL;
6480                 }
6481
6482                 counters->append_all = true;
6483
6484                 g_hash_table_replace(service->counter_table, (gpointer)counter,
6485                                 counters);
6486         }
6487
6488         service_initialize(service);
6489
6490         return service;
6491 }
6492
6493 /**
6494  * connman_service_ref:
6495  * @service: service structure
6496  *
6497  * Increase reference counter of service
6498  */
6499 struct connman_service *
6500 connman_service_ref_debug(struct connman_service *service,
6501                         const char *file, int line, const char *caller)
6502 {
6503         DBG("%p ref %d by %s:%d:%s()", service, service->refcount + 1,
6504                 file, line, caller);
6505
6506         __sync_fetch_and_add(&service->refcount, 1);
6507
6508         return service;
6509 }
6510
6511 /**
6512  * connman_service_unref:
6513  * @service: service structure
6514  *
6515  * Decrease reference counter of service and release service if no
6516  * longer needed.
6517  */
6518 void connman_service_unref_debug(struct connman_service *service,
6519                         const char *file, int line, const char *caller)
6520 {
6521         DBG("%p ref %d by %s:%d:%s()", service, service->refcount - 1,
6522                 file, line, caller);
6523
6524         if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
6525                 return;
6526
6527         service_list = g_list_remove(service_list, service);
6528
6529         __connman_service_disconnect(service);
6530
6531         g_hash_table_remove(service_hash, service->identifier);
6532 }
6533
6534 static gint service_compare(gconstpointer a, gconstpointer b)
6535 {
6536         struct connman_service *service_a = (void *) a;
6537         struct connman_service *service_b = (void *) b;
6538         enum connman_service_state state_a, state_b;
6539         bool a_connected, b_connected;
6540         gint strength;
6541
6542         state_a = service_a->state;
6543         state_b = service_b->state;
6544         a_connected = is_connected(state_a);
6545         b_connected = is_connected(state_b);
6546
6547         if (a_connected && b_connected) {
6548                 if (service_a->order > service_b->order)
6549                         return -1;
6550
6551                 if (service_a->order < service_b->order)
6552                         return 1;
6553         }
6554
6555         if (state_a != state_b) {
6556                 if (a_connected && b_connected) {
6557                         /* We prefer online over ready state */
6558                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
6559                                 return -1;
6560
6561                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
6562                                 return 1;
6563                 }
6564
6565                 if (a_connected)
6566                         return -1;
6567                 if (b_connected)
6568                         return 1;
6569
6570                 if (is_connecting(state_a))
6571                         return -1;
6572                 if (is_connecting(state_b))
6573                         return 1;
6574         }
6575
6576         if (service_a->favorite && !service_b->favorite)
6577                 return -1;
6578
6579         if (!service_a->favorite && service_b->favorite)
6580                 return 1;
6581
6582         if (service_a->type != service_b->type) {
6583                 unsigned int *tech_array;
6584                 int i;
6585
6586                 tech_array = connman_setting_get_uint_list(
6587                                                 "PreferredTechnologies");
6588                 if (tech_array) {
6589                         for (i = 0; tech_array[i]; i++) {
6590                                 if (tech_array[i] == service_a->type)
6591                                         return -1;
6592
6593                                 if (tech_array[i] == service_b->type)
6594                                         return 1;
6595                         }
6596                 }
6597
6598                 if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
6599                         return -1;
6600                 if (service_b->type == CONNMAN_SERVICE_TYPE_ETHERNET)
6601                         return 1;
6602
6603                 if (service_a->type == CONNMAN_SERVICE_TYPE_WIFI)
6604                         return -1;
6605                 if (service_b->type == CONNMAN_SERVICE_TYPE_WIFI)
6606                         return 1;
6607
6608                 if (service_a->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6609                         return -1;
6610                 if (service_b->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6611                         return 1;
6612
6613                 if (service_a->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
6614                         return -1;
6615                 if (service_b->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
6616                         return 1;
6617
6618                 if (service_a->type == CONNMAN_SERVICE_TYPE_VPN)
6619                         return -1;
6620                 if (service_b->type == CONNMAN_SERVICE_TYPE_VPN)
6621                         return 1;
6622
6623                 if (service_a->type == CONNMAN_SERVICE_TYPE_GADGET)
6624                         return -1;
6625                 if (service_b->type == CONNMAN_SERVICE_TYPE_GADGET)
6626                         return 1;
6627         }
6628
6629         strength = (gint) service_b->strength - (gint) service_a->strength;
6630         if (strength)
6631                 return strength;
6632
6633         return g_strcmp0(service_a->name, service_b->name);
6634 }
6635
6636 static void service_list_sort(void)
6637 {
6638         if (service_list && service_list->next) {
6639                 service_list = g_list_sort(service_list, service_compare);
6640                 service_schedule_changed();
6641         }
6642 }
6643
6644 int __connman_service_compare(const struct connman_service *a,
6645                                         const struct connman_service *b)
6646 {
6647         return service_compare(a, b);
6648 }
6649
6650 /**
6651  * connman_service_get_type:
6652  * @service: service structure
6653  *
6654  * Get the type of service
6655  */
6656 enum connman_service_type connman_service_get_type(struct connman_service *service)
6657 {
6658         if (!service)
6659                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
6660
6661         return service->type;
6662 }
6663
6664 /**
6665  * connman_service_get_interface:
6666  * @service: service structure
6667  *
6668  * Get network interface of service
6669  */
6670 char *connman_service_get_interface(struct connman_service *service)
6671 {
6672         int index;
6673
6674         if (!service)
6675                 return NULL;
6676
6677         index = __connman_service_get_index(service);
6678
6679         return connman_inet_ifname(index);
6680 }
6681
6682 /**
6683  * connman_service_get_network:
6684  * @service: service structure
6685  *
6686  * Get the service network
6687  */
6688 struct connman_network *
6689 __connman_service_get_network(struct connman_service *service)
6690 {
6691         if (!service)
6692                 return NULL;
6693
6694         return service->network;
6695 }
6696
6697 struct connman_ipconfig *
6698 __connman_service_get_ip4config(struct connman_service *service)
6699 {
6700         if (!service)
6701                 return NULL;
6702
6703         return service->ipconfig_ipv4;
6704 }
6705
6706 struct connman_ipconfig *
6707 __connman_service_get_ip6config(struct connman_service *service)
6708 {
6709         if (!service)
6710                 return NULL;
6711
6712         return service->ipconfig_ipv6;
6713 }
6714
6715 struct connman_ipconfig *
6716 __connman_service_get_ipconfig(struct connman_service *service, int family)
6717 {
6718         if (family == AF_INET)
6719                 return __connman_service_get_ip4config(service);
6720         else if (family == AF_INET6)
6721                 return __connman_service_get_ip6config(service);
6722         else
6723                 return NULL;
6724
6725 }
6726
6727 bool __connman_service_is_connected_state(struct connman_service *service,
6728                                         enum connman_ipconfig_type type)
6729 {
6730         if (!service)
6731                 return false;
6732
6733         switch (type) {
6734         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
6735                 break;
6736         case CONNMAN_IPCONFIG_TYPE_IPV4:
6737                 return is_connected(service->state_ipv4);
6738         case CONNMAN_IPCONFIG_TYPE_IPV6:
6739                 return is_connected(service->state_ipv6);
6740         case CONNMAN_IPCONFIG_TYPE_ALL:
6741                 return is_connected(service->state_ipv4) &&
6742                         is_connected(service->state_ipv6);
6743         }
6744
6745         return false;
6746 }
6747 enum connman_service_security __connman_service_get_security(
6748                                 struct connman_service *service)
6749 {
6750         if (!service)
6751                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
6752
6753         return service->security;
6754 }
6755
6756 const char *__connman_service_get_phase2(struct connman_service *service)
6757 {
6758         if (!service)
6759                 return NULL;
6760
6761         return service->phase2;
6762 }
6763
6764 bool __connman_service_wps_enabled(struct connman_service *service)
6765 {
6766         if (!service)
6767                 return false;
6768
6769         return service->wps;
6770 }
6771
6772 void __connman_service_mark_dirty(void)
6773 {
6774         services_dirty = true;
6775 }
6776
6777 #if defined TIZEN_EXT
6778 /**
6779   * Returns profile count if there is any connected profiles
6780   * that use same interface
6781   */
6782 int __connman_service_get_connected_count_of_iface(
6783                                         struct connman_service *service)
6784 {
6785         GList *list;
6786         int count = 0;
6787         int index1 = 0;
6788         int index2 = 0;
6789
6790         DBG("");
6791
6792         index1 = __connman_service_get_index(service);
6793
6794         if (index1 <= 0)
6795                 return 0;
6796
6797         for (list = service_list; list; list = list->next) {
6798                 struct connman_service *service2 = list->data;
6799
6800                 if (service == service2)
6801                         continue;
6802
6803                 index2 = __connman_service_get_index(service2);
6804
6805                 if (is_connected(service2->state) && index2 > 0 && index1 == index2)
6806                         count++;
6807
6808                 index2 = 0;
6809         }
6810
6811         DBG("Interface index %d, count %d", index1, count);
6812
6813         return count;
6814 }
6815
6816 void __connman_service_set_storage_reload(struct connman_service *service,
6817                                         bool storage_reload)
6818 {
6819         if (service != NULL)
6820                 service->storage_reload = storage_reload;
6821 }
6822 #endif
6823
6824 /**
6825  * __connman_service_set_favorite_delayed:
6826  * @service: service structure
6827  * @favorite: favorite value
6828  * @delay_ordering: do not order service sequence
6829  *
6830  * Change the favorite setting of service
6831  */
6832 int __connman_service_set_favorite_delayed(struct connman_service *service,
6833                                         bool favorite,
6834                                         bool delay_ordering)
6835 {
6836 #if defined TIZEN_EXT
6837         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6838                 return -EIO;
6839 #endif
6840         if (service->hidden)
6841                 return -EOPNOTSUPP;
6842
6843         if (service->favorite == favorite)
6844                 return -EALREADY;
6845
6846         service->favorite = favorite;
6847
6848         favorite_changed(service);
6849
6850         if (!delay_ordering) {
6851
6852                 service_list_sort();
6853
6854                 __connman_connection_update_gateway();
6855         }
6856
6857         return 0;
6858 }
6859
6860 /**
6861  * __connman_service_set_favorite:
6862  * @service: service structure
6863  * @favorite: favorite value
6864  *
6865  * Change the favorite setting of service
6866  */
6867 int __connman_service_set_favorite(struct connman_service *service,
6868                                                 bool favorite)
6869 {
6870         return __connman_service_set_favorite_delayed(service, favorite,
6871                                                         false);
6872 }
6873
6874 bool connman_service_get_favorite(struct connman_service *service)
6875 {
6876         return service->favorite;
6877 }
6878
6879 bool connman_service_get_autoconnect(struct connman_service *service)
6880 {
6881         return service->autoconnect;
6882 }
6883
6884 int __connman_service_set_immutable(struct connman_service *service,
6885                                                 bool immutable)
6886 {
6887         if (service->hidden)
6888                 return -EOPNOTSUPP;
6889
6890         if (service->immutable == immutable)
6891                 return 0;
6892
6893         service->immutable = immutable;
6894
6895         immutable_changed(service);
6896
6897         return 0;
6898 }
6899
6900 int __connman_service_set_ignore(struct connman_service *service,
6901                                                 bool ignore)
6902 {
6903         if (!service)
6904                 return -EINVAL;
6905
6906         service->ignore = ignore;
6907
6908         return 0;
6909 }
6910
6911 void __connman_service_set_string(struct connman_service *service,
6912                                   const char *key, const char *value)
6913 {
6914         if (service->hidden)
6915                 return;
6916         if (g_str_equal(key, "EAP")) {
6917                 g_free(service->eap);
6918                 service->eap = g_strdup(value);
6919         } else if (g_str_equal(key, "Identity")) {
6920                 g_free(service->identity);
6921                 service->identity = g_strdup(value);
6922         } else if (g_str_equal(key, "AnonymousIdentity")) {
6923                 g_free(service->anonymous_identity);
6924                 service->anonymous_identity = g_strdup(value);
6925         } else if (g_str_equal(key, "CACertFile")) {
6926                 g_free(service->ca_cert_file);
6927                 service->ca_cert_file = g_strdup(value);
6928         } else if (g_str_equal(key, "SubjectMatch")) {
6929                 g_free(service->subject_match);
6930                 service->subject_match = g_strdup(value);
6931         } else if (g_str_equal(key, "AltSubjectMatch")) {
6932                 g_free(service->altsubject_match);
6933                 service->altsubject_match = g_strdup(value);
6934         } else if (g_str_equal(key, "DomainSuffixMatch")) {
6935                 g_free(service->domain_suffix_match);
6936                 service->domain_suffix_match = g_strdup(value);
6937         } else if (g_str_equal(key, "DomainMatch")) {
6938                 g_free(service->domain_match);
6939                 service->domain_match = g_strdup(value);
6940         } else if (g_str_equal(key, "ClientCertFile")) {
6941                 g_free(service->client_cert_file);
6942                 service->client_cert_file = g_strdup(value);
6943         } else if (g_str_equal(key, "PrivateKeyFile")) {
6944                 g_free(service->private_key_file);
6945                 service->private_key_file = g_strdup(value);
6946         } else if (g_str_equal(key, "PrivateKeyPassphrase")) {
6947                 g_free(service->private_key_passphrase);
6948                 service->private_key_passphrase = g_strdup(value);
6949         } else if (g_str_equal(key, "Phase2")) {
6950                 g_free(service->phase2);
6951                 service->phase2 = g_strdup(value);
6952         } else if (g_str_equal(key, "Passphrase"))
6953                 __connman_service_set_passphrase(service, value);
6954 #if defined TIZEN_EXT
6955          else if (g_str_equal(key, "Connector")) {
6956                 g_free(service->connector);
6957                 service->connector = g_strdup(value);
6958          }      else if (g_str_equal(key, "CSignKey")) {
6959                 g_free(service->c_sign_key);
6960                 service->c_sign_key = g_strdup(value);
6961          }      else if (g_str_equal(key, "NetAccessKey")) {
6962                 g_free(service->net_access_key);
6963                 service->net_access_key = g_strdup(value);
6964         } else
6965                 DBG("Unknown key: %s", key);
6966 #endif
6967 }
6968
6969 void __connman_service_set_search_domains(struct connman_service *service,
6970                                         char **domains)
6971 {
6972         searchdomain_remove_all(service);
6973
6974         if (service->domains)
6975                 g_strfreev(service->domains);
6976
6977         service->domains = g_strdupv(domains);
6978
6979         searchdomain_add_all(service);
6980 }
6981
6982 int __connman_service_set_mdns(struct connman_service *service,
6983                         bool enabled)
6984 {
6985         service->mdns_config = enabled;
6986
6987         return set_mdns(service, enabled);
6988 }
6989
6990 static void report_error_cb(void *user_context, bool retry,
6991                                                         void *user_data)
6992 {
6993         struct connman_service *service = user_context;
6994
6995         if (retry)
6996                 __connman_service_connect(service,
6997                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6998         else {
6999                 /* It is not relevant to stay on Failure state
7000                  * when failing is due to wrong user input */
7001                 __connman_service_clear_error(service);
7002 #if defined TIZEN_EXT
7003                 /* Reseting the state back in case of failure state */
7004                 service->state_ipv4 = service->state_ipv6 =
7005                                 CONNMAN_SERVICE_STATE_IDLE;
7006
7007                 if (service->error != CONNMAN_SERVICE_ERROR_AUTH_FAILED)
7008                         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7009 #endif
7010                 service_complete(service);
7011                 __connman_connection_update_gateway();
7012         }
7013 }
7014
7015 static int check_wpspin(struct connman_service *service, const char *wpspin)
7016 {
7017         int length;
7018         guint i;
7019
7020         if (!wpspin)
7021                 return 0;
7022
7023         length = strlen(wpspin);
7024
7025         /* If 0, it will mean user wants to use PBC method */
7026         if (length == 0) {
7027                 connman_network_set_string(service->network,
7028                                                         "WiFi.PinWPS", NULL);
7029                 return 0;
7030         }
7031
7032         /* A WPS PIN is always 8 chars length,
7033          * its content is in digit representation.
7034          */
7035         if (length != 8)
7036                 return -ENOKEY;
7037
7038         for (i = 0; i < 8; i++)
7039                 if (!isdigit((unsigned char) wpspin[i]))
7040                         return -ENOKEY;
7041
7042         connman_network_set_string(service->network, "WiFi.PinWPS", wpspin);
7043
7044         return 0;
7045 }
7046
7047 static void request_input_cb(struct connman_service *service,
7048                         bool values_received,
7049                         const char *name, int name_len,
7050                         const char *identity, const char *passphrase,
7051                         bool wps, const char *wpspin,
7052                         const char *error, void *user_data)
7053 {
7054         struct connman_device *device;
7055         const char *security;
7056         int err = 0;
7057
7058         DBG("RequestInput return, %p", service);
7059
7060         if (error) {
7061                 DBG("error: %s", error);
7062
7063                 if (g_strcmp0(error,
7064                                 "net.connman.Agent.Error.Canceled") == 0) {
7065                         err = -ECONNABORTED;
7066
7067                         if (service->hidden)
7068                                 __connman_service_return_error(service,
7069                                                         ECONNABORTED,
7070                                                         user_data);
7071                         goto done;
7072                 } else {
7073                         if (service->hidden)
7074                                 __connman_service_return_error(service,
7075                                                         ETIMEDOUT, user_data);
7076                 }
7077         }
7078
7079         if (service->hidden && name_len > 0 && name_len <= 32) {
7080                 device = connman_network_get_device(service->network);
7081                 security = connman_network_get_string(service->network,
7082                                                         "WiFi.Security");
7083                 err = __connman_device_request_hidden_scan(device,
7084                                                 name, name_len,
7085                                                 identity, passphrase,
7086                                                 security, user_data);
7087                 if (err < 0)
7088                         __connman_service_return_error(service, -err,
7089                                                         user_data);
7090         }
7091
7092         if (!values_received || service->hidden) {
7093                 err = -EINVAL;
7094                 goto done;
7095         }
7096
7097         if (wps && service->network) {
7098                 err = check_wpspin(service, wpspin);
7099                 if (err < 0)
7100                         goto done;
7101
7102                 connman_network_set_bool(service->network, "WiFi.UseWPS", wps);
7103         }
7104
7105         if (identity)
7106                 __connman_service_set_agent_identity(service, identity);
7107
7108         if (passphrase)
7109                 err = __connman_service_set_passphrase(service, passphrase);
7110
7111  done:
7112         if (err >= 0) {
7113                 /* We forget any previous error. */
7114                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7115
7116                 __connman_service_connect(service,
7117                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
7118
7119         } else if (err == -ENOKEY) {
7120                 __connman_service_indicate_error(service,
7121                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
7122         } else {
7123                 /* It is not relevant to stay on Failure state
7124                  * when failing is due to wrong user input */
7125                 service->state = CONNMAN_SERVICE_STATE_IDLE;
7126
7127                 if (!service->hidden) {
7128                         /*
7129                          * If there was a real error when requesting
7130                          * hidden scan, then that error is returned already
7131                          * to the user somewhere above so do not try to
7132                          * do this again.
7133                          */
7134                         __connman_service_return_error(service, -err,
7135                                                         user_data);
7136                 }
7137
7138                 service_complete(service);
7139                 __connman_connection_update_gateway();
7140         }
7141 }
7142
7143 static void downgrade_connected_services(void)
7144 {
7145         struct connman_service *up_service;
7146         GList *list;
7147
7148         for (list = service_list; list; list = list->next) {
7149                 up_service = list->data;
7150
7151                 if (!is_connected(up_service->state))
7152                         continue;
7153
7154                 if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
7155                         return;
7156
7157                 downgrade_state(up_service);
7158         }
7159 }
7160
7161 static int service_update_preferred_order(struct connman_service *default_service,
7162                 struct connman_service *new_service,
7163                 enum connman_service_state new_state)
7164 {
7165         unsigned int *tech_array;
7166         int i;
7167
7168         if (!default_service || default_service == new_service ||
7169                         default_service->state != new_state)
7170                 return 0;
7171
7172         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
7173         if (tech_array) {
7174
7175                 for (i = 0; tech_array[i] != 0; i += 1) {
7176                         if (default_service->type == tech_array[i])
7177                                 return -EALREADY;
7178
7179                         if (new_service->type == tech_array[i]) {
7180                                 switch_default_service(default_service,
7181                                                 new_service);
7182                                 __connman_connection_update_gateway();
7183                                 return 0;
7184                         }
7185                 }
7186         }
7187
7188         return -EALREADY;
7189 }
7190
7191 #if defined TIZEN_EXT
7192 static gboolean __connman_service_can_drop(struct connman_service *service)
7193 {
7194         if (is_connected(service->state) == TRUE || is_connecting(service->state) == TRUE) {
7195                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
7196                         return TRUE;
7197                 else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE)
7198                         return TRUE;
7199         }
7200         return FALSE;
7201 }
7202
7203 static struct connman_device *default_connecting_device = NULL;
7204
7205 static void __connman_service_disconnect_default(struct connman_service *service)
7206 {
7207         struct connman_device *default_device = NULL;
7208
7209         if (default_connecting_device == NULL)
7210                 return;
7211
7212         default_device = connman_network_get_device(
7213                         __connman_service_get_network(service));
7214
7215         DBG("Disconnecting service %p %s", service, service->path);
7216         DBG("Disconnecting device %p %p %s",
7217                         default_connecting_device,
7218                         default_device,
7219                         connman_device_get_string(default_device, "Name"));
7220
7221         if (default_connecting_device == default_device)
7222                 default_connecting_device = NULL;
7223 }
7224
7225 #if defined TIZEN_MAINTAIN_ONLINE
7226 static void __connman_service_connect_default(struct connman_service *current,
7227                                                                   enum connman_service_state old_state)
7228 #else
7229 static void __connman_service_connect_default(struct connman_service *current)
7230 #endif
7231 {
7232         int err;
7233         GList *list;
7234         bool default_internet;
7235         struct connman_service *service;
7236         struct connman_service *default_service = NULL;
7237         struct connman_device *default_device = NULL;
7238
7239         if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
7240                 switch (current->state) {
7241                 case CONNMAN_SERVICE_STATE_UNKNOWN:
7242                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
7243                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
7244                         return;
7245                 default:
7246                         break;
7247                 }
7248
7249                 if (default_connecting_device &&
7250                                 __connman_service_is_internet_profile(current) == TRUE) {
7251                         if (current->network == NULL)
7252                                 return;
7253
7254                         default_device = connman_network_get_device(current->network);
7255                         if (default_connecting_device == default_device) {
7256                                 DBG("Cellular service[%s]  %p %s",
7257                                                 state2string(current->state), current, current->path);
7258                                 DBG("Cellular device %p %p %s",
7259                                                 default_connecting_device, default_device,
7260                                                 connman_device_get_string(default_device, "Name"));
7261
7262                                 default_connecting_device = NULL;
7263                         }
7264                 }
7265
7266                 return;
7267 #if defined TIZEN_MAINTAIN_ONLINE
7268         } else if (current->state == CONNMAN_SERVICE_STATE_READY &&
7269                            old_state == CONNMAN_SERVICE_STATE_ONLINE) {
7270                 DBG("Device is downgraded: online --> ready");
7271 #endif
7272         } else if (is_connected(current->state) == TRUE || is_connecting(current->state) == TRUE)
7273                 return;
7274
7275         /* Always-on: keep default cellular connection as possible */
7276         for (list = service_list; list; list = list->next) {
7277                 service = list->data;
7278
7279                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7280                                 __connman_service_is_internet_profile(service) != TRUE ||
7281                                 service->network == NULL) {
7282                         continue;
7283                 }
7284
7285                 default_internet =
7286                                 connman_network_get_bool(service->network, "DefaultInternet");
7287
7288                 DBG("service: %p %s %s %s (default: %d)", service, service->name,
7289                                 __connman_service_type2string(service->type),
7290                                 state2string(service->state), default_internet);
7291
7292                 if (default_internet) {
7293                         default_service = service;
7294                         if (is_connected(default_service->state) == TRUE ||
7295                                         is_connecting(default_service->state) == TRUE)
7296                                 return;
7297
7298                         default_device = connman_network_get_device(default_service->network);
7299                         if (default_connecting_device == default_device) {
7300                                 DBG("Device is connecting (%p)", default_connecting_device);
7301                                 return;
7302                         }
7303
7304                         default_connecting_device = default_device;
7305                         default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
7306
7307                         err = __connman_network_connect(default_service->network);
7308                         DBG("Connecting default service %p %s [%d]",
7309                                         default_service, default_service->path, err);
7310                         DBG("Connecting device %p %s", default_connecting_device,
7311                                         connman_device_get_string(default_connecting_device, "Name"));
7312                         if (err < 0 && err != -EINPROGRESS) {
7313                                 default_connecting_device = NULL;
7314                         } else
7315                                 break;
7316                 }
7317         }
7318 }
7319 #endif
7320
7321 static void single_connected_tech(struct connman_service *allowed)
7322 {
7323         struct connman_service *service;
7324         GSList *services = NULL, *list;
7325         GList *iter;
7326
7327         DBG("keeping %p %s", allowed, allowed->path);
7328
7329 #if defined TIZEN_EXT
7330         if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7331                 return;
7332 #endif
7333
7334         for (iter = service_list; iter; iter = iter->next) {
7335                 service = iter->data;
7336
7337 #if defined TIZEN_EXT
7338                 if (service != allowed && service->type != allowed->type &&
7339                                 __connman_service_can_drop(service) == TRUE)
7340 #else
7341                 if (!is_connected(service->state))
7342                         break;
7343
7344                 if (service == allowed)
7345                         continue;
7346 #endif
7347
7348                 services = g_slist_prepend(services, service);
7349         }
7350
7351         for (list = services; list; list = list->next) {
7352                 service = list->data;
7353
7354                 DBG("disconnecting %p %s", service, service->path);
7355 #if defined TIZEN_EXT
7356                 __connman_service_disconnect_default(service);
7357 #endif
7358                 __connman_service_disconnect(service);
7359         }
7360
7361         g_slist_free(services);
7362 }
7363
7364 #if defined TIZEN_EXT
7365 static void set_priority_connected_service(void)
7366 {
7367         struct connman_service *service;
7368         GList *list;
7369
7370         for (list = service_list; list; list = list->next) {
7371                 service = list->data;
7372
7373                 if (is_connected(service->state) == FALSE)
7374                         service->order = 5;
7375                 else
7376 #if defined TIZEN_MAINTAIN_ONLINE
7377                 {
7378                         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7379                                 service->state == CONNMAN_SERVICE_STATE_ONLINE)
7380                                 service->order = 6;
7381                         else if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
7382                                 service->order = 6;
7383                         else
7384                                 service->order = 5;
7385                 }
7386 #else
7387                         service->order = 6;
7388 #endif
7389         }
7390 }
7391 #endif
7392
7393 static const char *get_dbus_sender(struct connman_service *service)
7394 {
7395         if (!service->pending)
7396                 return NULL;
7397
7398         return dbus_message_get_sender(service->pending);
7399 }
7400
7401 static int service_indicate_state(struct connman_service *service)
7402 {
7403         enum connman_service_state old_state, new_state;
7404         struct connman_service *def_service;
7405         enum connman_ipconfig_method method;
7406         int result;
7407
7408         if (!service)
7409                 return -EINVAL;
7410
7411         old_state = service->state;
7412         new_state = combine_state(service->state_ipv4, service->state_ipv6);
7413
7414         DBG("service %p old %s - new %s/%s => %s",
7415                                         service,
7416                                         state2string(old_state),
7417                                         state2string(service->state_ipv4),
7418                                         state2string(service->state_ipv6),
7419                                         state2string(new_state));
7420
7421         if (old_state == new_state)
7422                 return -EALREADY;
7423
7424         def_service = connman_service_get_default();
7425
7426         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
7427                 result = service_update_preferred_order(def_service,
7428                                 service, new_state);
7429                 if (result == -EALREADY)
7430                         return result;
7431         }
7432
7433         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
7434                 __connman_notifier_leave_online(service->type);
7435
7436         if (is_connected(old_state) && !is_connected(new_state))
7437                 searchdomain_remove_all(service);
7438
7439         service->state = new_state;
7440         state_changed(service);
7441
7442         if (!is_connected(old_state) && is_connected(new_state))
7443                 searchdomain_add_all(service);
7444
7445         switch(new_state) {
7446         case CONNMAN_SERVICE_STATE_UNKNOWN:
7447
7448                 break;
7449
7450         case CONNMAN_SERVICE_STATE_IDLE:
7451                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
7452                         __connman_service_disconnect(service);
7453
7454                 break;
7455
7456         case CONNMAN_SERVICE_STATE_ASSOCIATION:
7457
7458                 break;
7459
7460         case CONNMAN_SERVICE_STATE_CONFIGURATION:
7461                 if (!service->new_service &&
7462                                 __connman_stats_service_register(service) == 0) {
7463                         /*
7464                          * For new services the statistics are updated after
7465                          * we have successfully connected.
7466                          */
7467                         __connman_stats_get(service, false,
7468                                                 &service->stats.data);
7469                         __connman_stats_get(service, true,
7470                                                 &service->stats_roaming.data);
7471                 }
7472
7473                 break;
7474
7475         case CONNMAN_SERVICE_STATE_READY:
7476                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7477
7478                 if (service->new_service &&
7479                                 __connman_stats_service_register(service) == 0) {
7480                         /*
7481                          * This is normally done after configuring state
7482                          * but for new service do this after we have connected
7483                          * successfully.
7484                          */
7485                         __connman_stats_get(service, false,
7486                                                 &service->stats.data);
7487                         __connman_stats_get(service, true,
7488                                                 &service->stats_roaming.data);
7489                 }
7490
7491                 service->new_service = false;
7492
7493                 default_changed();
7494
7495                 def_service = connman_service_get_default();
7496
7497                 service_update_preferred_order(def_service, service, new_state);
7498
7499                 __connman_service_set_favorite(service, true);
7500
7501                 reply_pending(service, 0);
7502
7503                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7504                         connman_network_get_bool(service->network,
7505                                                 "WiFi.UseWPS")) {
7506                         const char *pass;
7507
7508                         pass = connman_network_get_string(service->network,
7509                                                         "WiFi.Passphrase");
7510
7511                         __connman_service_set_passphrase(service, pass);
7512
7513                         connman_network_set_bool(service->network,
7514                                                         "WiFi.UseWPS", false);
7515                 }
7516
7517                 g_get_current_time(&service->modified);
7518                 service_save(service);
7519
7520                 domain_changed(service);
7521                 proxy_changed(service);
7522
7523                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
7524                         __connman_notifier_connect(service->type);
7525
7526                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
7527                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
7528                         __connman_ipconfig_disable_ipv6(
7529                                                 service->ipconfig_ipv6);
7530
7531 #if !defined TIZEN_MAINTAIN_ONLINE
7532                 if (connman_setting_get_bool("SingleConnectedTechnology"))
7533                         single_connected_tech(service);
7534                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
7535                         vpn_auto_connect();
7536 #else
7537                 if (service->type != CONNMAN_SERVICE_TYPE_VPN)
7538                         vpn_auto_connect();
7539 #endif
7540
7541 #if defined TIZEN_EXT
7542                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7543                         set_priority_connected_service();
7544 #endif
7545
7546                 break;
7547
7548         case CONNMAN_SERVICE_STATE_ONLINE:
7549 #if defined TIZEN_MAINTAIN_ONLINE
7550 #if defined TIZEN_EXT
7551                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7552                         set_priority_connected_service();
7553 #endif
7554
7555                 if (connman_setting_get_bool("SingleConnectedTechnology"))
7556                         single_connected_tech(service);
7557 #endif
7558
7559                 break;
7560
7561         case CONNMAN_SERVICE_STATE_DISCONNECT:
7562                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7563
7564                 reply_pending(service, ECONNABORTED);
7565
7566                 default_changed();
7567
7568                 __connman_wispr_stop(service);
7569
7570                 __connman_wpad_stop(service);
7571
7572 #if defined TIZEN_EXT
7573                 /**
7574                  * Skip the functions if there is any connected profiles
7575                  * that use same interface
7576                  */
7577                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7578                         __connman_service_get_connected_count_of_iface(
7579                                                         service) <= 0) {
7580 #endif
7581                 domain_changed(service);
7582                 proxy_changed(service);
7583 #if defined TIZEN_EXT
7584                 }
7585 #endif
7586
7587                 /*
7588                  * Previous services which are connected and which states
7589                  * are set to online should reset relevantly ipconfig_state
7590                  * to ready so wispr/portal will be rerun on those
7591                  */
7592                 downgrade_connected_services();
7593
7594                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7595                 break;
7596
7597         case CONNMAN_SERVICE_STATE_FAILURE:
7598 #if defined TIZEN_EXT
7599                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7600                         service->order = 5;
7601                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7602 #endif
7603                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
7604                         connman_agent_report_error(service, service->path,
7605                                                 error2string(service->error),
7606                                                 report_error_cb,
7607                                                 get_dbus_sender(service),
7608                                                 NULL);
7609                 }
7610                 service_complete(service);
7611                 break;
7612         }
7613
7614         service_list_sort();
7615
7616 #if defined TIZEN_EXT
7617 #if defined TIZEN_MAINTAIN_ONLINE
7618         __connman_service_connect_default(service, old_state);
7619 #else
7620         __connman_service_connect_default(service);
7621 #endif
7622 #endif
7623
7624         __connman_connection_update_gateway();
7625
7626         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
7627                         new_state != CONNMAN_SERVICE_STATE_READY) ||
7628                 (old_state == CONNMAN_SERVICE_STATE_READY &&
7629                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
7630                 __connman_notifier_disconnect(service->type);
7631         }
7632
7633         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
7634                 __connman_notifier_enter_online(service->type);
7635                 default_changed();
7636         }
7637
7638         return 0;
7639 }
7640
7641 int __connman_service_indicate_error(struct connman_service *service,
7642                                         enum connman_service_error error)
7643 {
7644         DBG("service %p error %d", service, error);
7645
7646         if (!service)
7647                 return -EINVAL;
7648
7649         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
7650                 return -EALREADY;
7651
7652         set_error(service, error);
7653
7654 /* default internet service: fix not cleared if pdp activation*/
7655 #if defined TIZEN_EXT
7656                 /*
7657                  * If connection failed for default service(DefaultInternet),
7658                  * default_connecting_device should be cleared.
7659                  */
7660                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7661                                 service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED)
7662                         __connman_service_disconnect_default(service);
7663
7664                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7665                                 service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) {
7666                         g_free(service->passphrase);
7667                         service->passphrase = NULL;
7668                 }
7669 #endif
7670
7671         __connman_service_ipconfig_indicate_state(service,
7672                                                 CONNMAN_SERVICE_STATE_FAILURE,
7673                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7674         __connman_service_ipconfig_indicate_state(service,
7675                                                 CONNMAN_SERVICE_STATE_FAILURE,
7676                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7677         return 0;
7678 }
7679
7680 int __connman_service_clear_error(struct connman_service *service)
7681 {
7682         DBusMessage *pending, *provider_pending;
7683
7684         DBG("service %p", service);
7685
7686         if (!service)
7687                 return -EINVAL;
7688
7689         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
7690                 return -EINVAL;
7691
7692         pending = service->pending;
7693         service->pending = NULL;
7694         provider_pending = service->provider_pending;
7695         service->provider_pending = NULL;
7696
7697         __connman_service_ipconfig_indicate_state(service,
7698                                                 CONNMAN_SERVICE_STATE_IDLE,
7699                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7700
7701         __connman_service_ipconfig_indicate_state(service,
7702                                                 CONNMAN_SERVICE_STATE_IDLE,
7703                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7704
7705         service->pending = pending;
7706         service->provider_pending = provider_pending;
7707
7708         return 0;
7709 }
7710
7711 int __connman_service_indicate_default(struct connman_service *service)
7712 {
7713         DBG("service %p state %s", service, state2string(service->state));
7714
7715         if (!is_connected(service->state)) {
7716                 /*
7717                  * If service is not yet fully connected, then we must not
7718                  * change the default yet. The default gw will be changed
7719                  * after the service state is in ready.
7720                  */
7721                 return -EINPROGRESS;
7722         }
7723
7724         default_changed();
7725
7726         return 0;
7727 }
7728
7729 enum connman_service_state __connman_service_ipconfig_get_state(
7730                                         struct connman_service *service,
7731                                         enum connman_ipconfig_type type)
7732 {
7733         if (!service)
7734                 return CONNMAN_SERVICE_STATE_UNKNOWN;
7735
7736         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7737                 return service->state_ipv4;
7738
7739         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
7740                 return service->state_ipv6;
7741
7742         return CONNMAN_SERVICE_STATE_UNKNOWN;
7743 }
7744
7745 static void check_proxy_setup(struct connman_service *service)
7746 {
7747         /*
7748          * We start WPAD if we haven't got a PAC URL from DHCP and
7749          * if our proxy manual configuration is either empty or set
7750          * to AUTO with an empty URL.
7751          */
7752
7753         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
7754                 goto done;
7755
7756         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
7757                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
7758                         service->pac))
7759                 goto done;
7760
7761         if (__connman_wpad_start(service) < 0) {
7762                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
7763                 __connman_notifier_proxy_changed(service);
7764                 goto done;
7765         }
7766
7767         return;
7768
7769 done:
7770         __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
7771 }
7772
7773 #if defined TIZEN_EXT
7774 void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
7775
7776         DBG("check the proxy and start wispr");
7777         check_proxy_setup(service);
7778         return;
7779 }
7780 #endif
7781
7782 /*
7783  * How many networks are connected at the same time. If more than 1,
7784  * then set the rp_filter setting properly (loose mode routing) so that network
7785  * connectivity works ok. This is only done for IPv4 networks as IPv6
7786  * does not have rp_filter knob.
7787  */
7788 static int connected_networks_count;
7789 static int original_rp_filter;
7790
7791 static void service_rp_filter(struct connman_service *service,
7792                                 bool connected)
7793 {
7794         enum connman_ipconfig_method method;
7795
7796         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
7797
7798         switch (method) {
7799         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
7800         case CONNMAN_IPCONFIG_METHOD_OFF:
7801         case CONNMAN_IPCONFIG_METHOD_AUTO:
7802                 return;
7803         case CONNMAN_IPCONFIG_METHOD_FIXED:
7804         case CONNMAN_IPCONFIG_METHOD_MANUAL:
7805         case CONNMAN_IPCONFIG_METHOD_DHCP:
7806                 break;
7807         }
7808
7809         if (connected) {
7810                 if (connected_networks_count == 1) {
7811                         int filter_value;
7812                         filter_value = __connman_ipconfig_set_rp_filter();
7813                         if (filter_value < 0)
7814                                 return;
7815
7816                         original_rp_filter = filter_value;
7817                 }
7818                 connected_networks_count++;
7819
7820         } else {
7821                 if (connected_networks_count == 2)
7822                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
7823
7824                 connected_networks_count--;
7825                 if (connected_networks_count < 0)
7826                         connected_networks_count = 0;
7827         }
7828
7829         DBG("%s %s ipconfig %p method %d count %d filter %d",
7830                 connected ? "connected" : "disconnected", service->identifier,
7831                 service->ipconfig_ipv4, method,
7832                 connected_networks_count, original_rp_filter);
7833 }
7834
7835 static void redo_wispr(struct connman_service *service,
7836                                         enum connman_ipconfig_type type)
7837 {
7838         service->online_timeout = 0;
7839         connman_service_unref(service);
7840
7841         DBG("Retrying %s WISPr for %p %s",
7842                 __connman_ipconfig_type2string(type),
7843                 service, service->name);
7844
7845         __connman_wispr_start(service, type);
7846 }
7847
7848 static gboolean redo_wispr_ipv4(gpointer user_data)
7849 {
7850         struct connman_service *service = user_data;
7851
7852         redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV4);
7853
7854         return FALSE;
7855 }
7856
7857 static gboolean redo_wispr_ipv6(gpointer user_data)
7858 {
7859         struct connman_service *service = user_data;
7860
7861         redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV6);
7862
7863         return FALSE;
7864 }
7865
7866 #if defined TIZEN_MAINTAIN_ONLINE
7867 static gboolean redo_wispr_ipv4(gpointer user_data)
7868 {
7869         struct connman_service *service = user_data;
7870
7871         DBG("");
7872
7873         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
7874
7875         return FALSE;
7876 }
7877 #endif
7878
7879 int __connman_service_online_check_failed(struct connman_service *service,
7880                                         enum connman_ipconfig_type type)
7881 {
7882         GSourceFunc redo_func;
7883         int *interval;
7884
7885         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
7886                 interval = &service->online_check_interval_ipv4;
7887                 redo_func = redo_wispr_ipv4;
7888         } else {
7889                 interval = &service->online_check_interval_ipv6;
7890                 redo_func = redo_wispr_ipv6;
7891         }
7892
7893         DBG("service %p type %s interval %d", service,
7894                 __connman_ipconfig_type2string(type), *interval);
7895
7896         service->online_timeout = g_timeout_add_seconds(*interval * *interval,
7897                                 redo_func, connman_service_ref(service));
7898
7899         /* Increment the interval for the next time, set a maximum timeout of
7900          * ONLINE_CHECK_MAX_INTERVAL * ONLINE_CHECK_MAX_INTERVAL seconds.
7901          */
7902         if (*interval < ONLINE_CHECK_MAX_INTERVAL)
7903                 (*interval)++;
7904
7905         return EAGAIN;
7906 }
7907
7908 static void cancel_online_check(struct connman_service *service)
7909 {
7910         if (service->online_timeout == 0)
7911                 return;
7912
7913         g_source_remove(service->online_timeout);
7914         service->online_timeout = 0;
7915         connman_service_unref(service);
7916 }
7917
7918 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
7919                                         enum connman_service_state new_state,
7920                                         enum connman_ipconfig_type type)
7921 {
7922         struct connman_ipconfig *ipconfig = NULL;
7923         enum connman_service_state old_state;
7924         enum connman_ipconfig_method method;
7925
7926         if (!service)
7927                 return -EINVAL;
7928
7929         switch (type) {
7930         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
7931         case CONNMAN_IPCONFIG_TYPE_ALL:
7932                 return -EINVAL;
7933
7934         case CONNMAN_IPCONFIG_TYPE_IPV4:
7935                 old_state = service->state_ipv4;
7936                 ipconfig = service->ipconfig_ipv4;
7937
7938                 break;
7939
7940         case CONNMAN_IPCONFIG_TYPE_IPV6:
7941                 old_state = service->state_ipv6;
7942                 ipconfig = service->ipconfig_ipv6;
7943
7944                 break;
7945         }
7946
7947         if (!ipconfig)
7948                 return -EINVAL;
7949
7950         method = __connman_ipconfig_get_method(ipconfig);
7951
7952         switch (method) {
7953         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
7954         case CONNMAN_IPCONFIG_METHOD_OFF:
7955                 if (new_state != CONNMAN_SERVICE_STATE_IDLE)
7956                         connman_warn("ipconfig state %d ipconfig method %d",
7957                                 new_state, method);
7958
7959 #if defined TIZEN_EXT
7960                 if (old_state != CONNMAN_SERVICE_STATE_READY &&
7961                                 old_state != CONNMAN_SERVICE_STATE_ONLINE)
7962 #endif
7963                 new_state = CONNMAN_SERVICE_STATE_IDLE;
7964                 break;
7965
7966         case CONNMAN_IPCONFIG_METHOD_FIXED:
7967         case CONNMAN_IPCONFIG_METHOD_MANUAL:
7968         case CONNMAN_IPCONFIG_METHOD_DHCP:
7969         case CONNMAN_IPCONFIG_METHOD_AUTO:
7970                 break;
7971
7972         }
7973
7974         /* Any change? */
7975         if (old_state == new_state)
7976                 return -EALREADY;
7977
7978 #if defined TIZEN_EXT
7979         __sync_synchronize();
7980         if (service->user_pdn_connection_refcount > 0 &&
7981                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7982                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
7983                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
7984                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
7985                         service->user_pdn_connection_refcount = 0;
7986                         __sync_synchronize();
7987                 }
7988 #endif
7989
7990         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
7991                 service, service ? service->identifier : NULL,
7992                 old_state, state2string(old_state),
7993                 new_state, state2string(new_state),
7994                 type, __connman_ipconfig_type2string(type));
7995
7996         switch (new_state) {
7997         case CONNMAN_SERVICE_STATE_UNKNOWN:
7998         case CONNMAN_SERVICE_STATE_ASSOCIATION:
7999                 break;
8000         case CONNMAN_SERVICE_STATE_CONFIGURATION:
8001                 break;
8002         case CONNMAN_SERVICE_STATE_READY:
8003 #if defined TIZEN_EXT
8004                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
8005                                 __connman_service_is_internet_profile(service) != TRUE) {
8006                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
8007                                 service_rp_filter(service, TRUE);
8008
8009                         break;
8010                 }
8011 #endif
8012                 if (connman_setting_get_bool("EnableOnlineCheck"))
8013                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
8014 #if !defined TIZEN_EXT
8015                                 check_proxy_setup(service);
8016 #endif
8017 #if defined TIZEN_MAINTAIN_ONLINE
8018 /*                              if (old_state == CONNMAN_SERVICE_STATE_ONLINE) */
8019                                         check_proxy_setup(service);
8020 #endif
8021                         } else {
8022                                 __connman_service_wispr_start(service, type);
8023                         }
8024                 else
8025                         connman_info("Online check disabled. "
8026                                 "Default service remains in READY state.");
8027                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
8028                         service_rp_filter(service, true);
8029                 set_mdns(service, service->mdns_config);
8030                 break;
8031         case CONNMAN_SERVICE_STATE_ONLINE:
8032                 break;
8033         case CONNMAN_SERVICE_STATE_DISCONNECT:
8034                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
8035                         return -EINVAL;
8036
8037                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
8038                         service_rp_filter(service, false);
8039
8040                 break;
8041
8042         case CONNMAN_SERVICE_STATE_IDLE:
8043         case CONNMAN_SERVICE_STATE_FAILURE:
8044                 __connman_ipconfig_disable(ipconfig);
8045
8046                 break;
8047         }
8048
8049         if (is_connected(old_state) && !is_connected(new_state)) {
8050                 nameserver_remove_all(service, type);
8051                 cancel_online_check(service);
8052         }
8053
8054         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
8055                 service->state_ipv4 = new_state;
8056         else
8057                 service->state_ipv6 = new_state;
8058
8059         if (!is_connected(old_state) && is_connected(new_state))
8060                 nameserver_add_all(service, type);
8061
8062         __connman_timeserver_sync(service);
8063
8064 #if defined TIZEN_EXT
8065         int ret = service_indicate_state(service);
8066         /*Sent the Ready changed signal again in case IPv4 IP set
8067           after IPv6 IP set*/
8068
8069         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
8070                         && new_state == CONNMAN_SERVICE_STATE_READY) {
8071                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
8072                 state_changed(service);
8073         }
8074
8075         return ret;
8076 #endif
8077         return service_indicate_state(service);
8078 }
8079
8080 static bool prepare_network(struct connman_service *service)
8081 {
8082         enum connman_network_type type;
8083         unsigned int ssid_len;
8084
8085         type = connman_network_get_type(service->network);
8086
8087         switch (type) {
8088         case CONNMAN_NETWORK_TYPE_UNKNOWN:
8089         case CONNMAN_NETWORK_TYPE_VENDOR:
8090                 return false;
8091         case CONNMAN_NETWORK_TYPE_WIFI:
8092                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
8093                                                 &ssid_len))
8094                         return false;
8095
8096                 if (service->passphrase)
8097                         connman_network_set_string(service->network,
8098                                 "WiFi.Passphrase", service->passphrase);
8099                 break;
8100         case CONNMAN_NETWORK_TYPE_ETHERNET:
8101         case CONNMAN_NETWORK_TYPE_GADGET:
8102         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
8103         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
8104         case CONNMAN_NETWORK_TYPE_CELLULAR:
8105                 break;
8106         }
8107
8108         return true;
8109 }
8110
8111 static void prepare_8021x(struct connman_service *service)
8112 {
8113         if (service->eap)
8114                 connman_network_set_string(service->network, "WiFi.EAP",
8115                                                                 service->eap);
8116
8117         if (service->identity)
8118                 connman_network_set_string(service->network, "WiFi.Identity",
8119                                                         service->identity);
8120
8121         if (service->anonymous_identity)
8122                 connman_network_set_string(service->network,
8123                                                 "WiFi.AnonymousIdentity",
8124                                                 service->anonymous_identity);
8125
8126         if (service->ca_cert_file)
8127                 connman_network_set_string(service->network, "WiFi.CACertFile",
8128                                                         service->ca_cert_file);
8129
8130         if (service->subject_match)
8131                 connman_network_set_string(service->network, "WiFi.SubjectMatch",
8132                                                         service->subject_match);
8133
8134         if (service->altsubject_match)
8135                 connman_network_set_string(service->network, "WiFi.AltSubjectMatch",
8136                                                         service->altsubject_match);
8137
8138         if (service->domain_suffix_match)
8139                 connman_network_set_string(service->network, "WiFi.DomainSuffixMatch",
8140                                                         service->domain_suffix_match);
8141
8142         if (service->domain_match)
8143                 connman_network_set_string(service->network, "WiFi.DomainMatch",
8144                                                         service->domain_match);
8145
8146         if (service->client_cert_file)
8147                 connman_network_set_string(service->network,
8148                                                 "WiFi.ClientCertFile",
8149                                                 service->client_cert_file);
8150
8151         if (service->private_key_file)
8152                 connman_network_set_string(service->network,
8153                                                 "WiFi.PrivateKeyFile",
8154                                                 service->private_key_file);
8155
8156         if (service->private_key_passphrase)
8157                 connman_network_set_string(service->network,
8158                                         "WiFi.PrivateKeyPassphrase",
8159                                         service->private_key_passphrase);
8160
8161         if (service->phase2)
8162                 connman_network_set_string(service->network, "WiFi.Phase2",
8163                                                         service->phase2);
8164
8165 #if defined TIZEN_EXT
8166         if (service->keymgmt_type)
8167                 connman_network_set_string(service->network, "WiFi.KeymgmtType",
8168                                                         service->keymgmt_type);
8169
8170         DBG("service->phase1 : %s", service->phase1);
8171         if (service->phase1)
8172                 connman_network_set_string(service->network, "WiFi.Phase1",
8173                                                         service->phase1);
8174 #endif
8175 }
8176 #if defined TIZEN_EXT
8177
8178 static bool has_valid_configuration_object(struct connman_service *service)
8179 {
8180         return service->connector && service->c_sign_key && service->net_access_key;
8181 }
8182
8183 static void prepare_dpp(struct connman_service *service)
8184 {
8185         DBG("prepare dpp");
8186         if (service->connector)
8187                 connman_network_set_string(service->network, "WiFi.Connector",
8188                                                                 service->connector);
8189
8190         if (service->c_sign_key)
8191                 connman_network_set_string(service->network, "WiFi.CSignKey",
8192                                                         service->c_sign_key);
8193
8194         if (service->net_access_key)
8195                 connman_network_set_string(service->network, "WiFi.NetAccessKey",
8196                                                         service->net_access_key);
8197 }
8198 #endif
8199
8200 static int service_connect(struct connman_service *service)
8201 {
8202         int err;
8203
8204         if (service->hidden)
8205                 return -EPERM;
8206
8207 #if defined TIZEN_EXT
8208         GList *list;
8209         int index;
8210
8211         index = __connman_service_get_index(service);
8212
8213         for (list = service_list; list; list = list->next) {
8214                 struct connman_service *temp = list->data;
8215
8216                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
8217                         break;
8218
8219                 if (!is_connecting(temp->state) && !is_connected(temp->state))
8220                         break;
8221
8222                 if (service == temp)
8223                         continue;
8224
8225                 if (service->type != temp->type)
8226                         continue;
8227
8228                 if (__connman_service_get_index(temp) == index &&
8229                                 __connman_service_disconnect(temp) == -EINPROGRESS)
8230                         return -EINPROGRESS;
8231         }
8232 #endif
8233
8234         switch (service->type) {
8235         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8236         case CONNMAN_SERVICE_TYPE_SYSTEM:
8237         case CONNMAN_SERVICE_TYPE_GPS:
8238         case CONNMAN_SERVICE_TYPE_P2P:
8239 #if defined TIZEN_EXT_WIFI_MESH
8240         case CONNMAN_SERVICE_TYPE_MESH:
8241 #endif
8242                 return -EINVAL;
8243         case CONNMAN_SERVICE_TYPE_ETHERNET:
8244         case CONNMAN_SERVICE_TYPE_GADGET:
8245         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8246         case CONNMAN_SERVICE_TYPE_CELLULAR:
8247         case CONNMAN_SERVICE_TYPE_VPN:
8248                 break;
8249         case CONNMAN_SERVICE_TYPE_WIFI:
8250                 switch (service->security) {
8251                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
8252                 case CONNMAN_SERVICE_SECURITY_NONE:
8253 #if defined TIZEN_EXT
8254                 case CONNMAN_SERVICE_SECURITY_OWE:
8255 #endif
8256                         break;
8257                 case CONNMAN_SERVICE_SECURITY_WEP:
8258                 case CONNMAN_SERVICE_SECURITY_PSK:
8259                 case CONNMAN_SERVICE_SECURITY_WPA:
8260                 case CONNMAN_SERVICE_SECURITY_RSN:
8261 #if defined TIZEN_EXT
8262                 case CONNMAN_SERVICE_SECURITY_SAE:
8263 #endif
8264                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
8265                                 return -ENOKEY;
8266
8267                         if (!service->passphrase) {
8268                                 if (!service->network)
8269                                         return -EOPNOTSUPP;
8270
8271                                 if (!service->wps ||
8272                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
8273                                         return -ENOKEY;
8274                         }
8275                         break;
8276
8277 #if defined TIZEN_EXT
8278                 case CONNMAN_SERVICE_SECURITY_DPP:
8279                         if (has_valid_configuration_object(service) &&
8280                                         !service->network)
8281                                 return -EINVAL;
8282                         break;
8283 #endif
8284                 case CONNMAN_SERVICE_SECURITY_8021X:
8285                         if (!service->eap) {
8286                                 connman_warn("EAP type has not been found. "
8287                                         "Most likely ConnMan is not able to "
8288                                         "find a configuration for given "
8289                                         "8021X network. "
8290                                         "Check SSID or Name match with the "
8291                                         "network name.");
8292                                 return -EINVAL;
8293                         }
8294
8295 #if defined TIZEN_EXT
8296                         /*
8297                          * never request credentials if using EAP-TLS, EAP-SIM
8298                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
8299                          * need to be fully provisioned)
8300                          */
8301                         DBG("service eap: %s", service->eap);
8302                         if (g_str_equal(service->eap, "tls") ||
8303                                 g_str_equal(service->eap, "sim") ||
8304                                 g_str_equal(service->eap, "aka") ||
8305                                 g_str_equal(service->eap, "aka'") ||
8306                                 g_str_equal(service->eap, "pwd") ||
8307                                 g_str_equal(service->eap, "fast"))
8308                                 break;
8309 #else
8310                         /*
8311                          * never request credentials if using EAP-TLS
8312                          * (EAP-TLS networks need to be fully provisioned)
8313                          */
8314                         if (g_str_equal(service->eap, "tls"))
8315                                 break;
8316
8317 #endif
8318                         /*
8319                          * Return -ENOKEY if either identity or passphrase is
8320                          * missing. Agent provided credentials can be used as
8321                          * fallback if needed.
8322                          */
8323                         if (((!service->identity &&
8324                                         !service->agent_identity) ||
8325                                         !service->passphrase) ||
8326                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
8327                                 return -ENOKEY;
8328
8329                         break;
8330                 }
8331                 break;
8332         }
8333
8334         if (service->network) {
8335                 if (!prepare_network(service))
8336                         return -EINVAL;
8337
8338                 switch (service->security) {
8339                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
8340                 case CONNMAN_SERVICE_SECURITY_NONE:
8341                 case CONNMAN_SERVICE_SECURITY_WEP:
8342                 case CONNMAN_SERVICE_SECURITY_PSK:
8343                 case CONNMAN_SERVICE_SECURITY_WPA:
8344                 case CONNMAN_SERVICE_SECURITY_RSN:
8345 #if defined TIZEN_EXT
8346                 case CONNMAN_SERVICE_SECURITY_SAE:
8347                 case CONNMAN_SERVICE_SECURITY_OWE:
8348                         break;
8349                 case CONNMAN_SERVICE_SECURITY_DPP:
8350                         prepare_dpp(service);
8351 #endif
8352                         break;
8353                 case CONNMAN_SERVICE_SECURITY_8021X:
8354                         prepare_8021x(service);
8355                         break;
8356                 }
8357
8358                 if (__connman_stats_service_register(service) == 0) {
8359                         __connman_stats_get(service, false,
8360                                                 &service->stats.data);
8361                         __connman_stats_get(service, true,
8362                                                 &service->stats_roaming.data);
8363                 }
8364
8365                 err = __connman_network_connect(service->network);
8366         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
8367                                         service->provider)
8368                 err = __connman_provider_connect(service->provider,
8369                                                 get_dbus_sender(service));
8370         else
8371                 return -EOPNOTSUPP;
8372
8373         if (err < 0) {
8374                 if (err != -EINPROGRESS) {
8375                         __connman_service_ipconfig_indicate_state(service,
8376                                                 CONNMAN_SERVICE_STATE_FAILURE,
8377                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
8378                         __connman_service_ipconfig_indicate_state(service,
8379                                                 CONNMAN_SERVICE_STATE_FAILURE,
8380                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
8381                         __connman_stats_service_unregister(service);
8382                 }
8383         }
8384
8385         return err;
8386 }
8387
8388 int __connman_service_connect(struct connman_service *service,
8389                         enum connman_service_connect_reason reason)
8390 {
8391         int err;
8392
8393         DBG("service %p state %s connect reason %s -> %s",
8394                 service, state2string(service->state),
8395                 reason2string(service->connect_reason),
8396                 reason2string(reason));
8397
8398         if (is_connected(service->state))
8399                 return -EISCONN;
8400
8401         if (is_connecting(service->state))
8402                 return -EALREADY;
8403
8404         switch (service->type) {
8405         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8406         case CONNMAN_SERVICE_TYPE_SYSTEM:
8407         case CONNMAN_SERVICE_TYPE_GPS:
8408         case CONNMAN_SERVICE_TYPE_P2P:
8409 #if defined TIZEN_EXT_WIFI_MESH
8410         case CONNMAN_SERVICE_TYPE_MESH:
8411 #endif
8412                 return -EINVAL;
8413
8414         case CONNMAN_SERVICE_TYPE_ETHERNET:
8415         case CONNMAN_SERVICE_TYPE_GADGET:
8416         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8417         case CONNMAN_SERVICE_TYPE_CELLULAR:
8418         case CONNMAN_SERVICE_TYPE_VPN:
8419         case CONNMAN_SERVICE_TYPE_WIFI:
8420                 break;
8421         }
8422
8423         if (!is_ipconfig_usable(service))
8424                 return -ENOLINK;
8425
8426         __connman_service_clear_error(service);
8427
8428         err = service_connect(service);
8429
8430         DBG("service %p err %d", service, err);
8431
8432         service->connect_reason = reason;
8433 #if defined TIZEN_EXT
8434         connect_reason_changed(service);
8435 #endif
8436
8437         if (err >= 0)
8438                 return 0;
8439
8440         if (err == -EINPROGRESS) {
8441                 if (service->timeout == 0)
8442                         service->timeout = g_timeout_add_seconds(
8443                                 CONNECT_TIMEOUT, connect_timeout, service);
8444
8445                 return -EINPROGRESS;
8446         }
8447
8448         if (service->network)
8449                 __connman_network_disconnect(service->network);
8450         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
8451                                 service->provider)
8452                         connman_provider_disconnect(service->provider);
8453
8454         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
8455                 if (err == -ENOKEY || err == -EPERM) {
8456                         DBusMessage *pending = NULL;
8457                         const char *dbus_sender = get_dbus_sender(service);
8458
8459                         /*
8460                          * We steal the reply here. The idea is that the
8461                          * connecting client will see the connection status
8462                          * after the real hidden network is connected or
8463                          * connection failed.
8464                          */
8465                         if (service->hidden) {
8466                                 pending = service->pending;
8467                                 service->pending = NULL;
8468                         }
8469
8470                         err = __connman_agent_request_passphrase_input(service,
8471                                         request_input_cb,
8472                                         dbus_sender,
8473                                         pending);
8474                         if (service->hidden && err != -EINPROGRESS)
8475                                 service->pending = pending;
8476
8477                         return err;
8478                 }
8479         }
8480
8481         return err;
8482 }
8483
8484 int __connman_service_disconnect(struct connman_service *service)
8485 {
8486         int err;
8487
8488         DBG("service %p", service);
8489
8490         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
8491         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
8492
8493         connman_agent_cancel(service);
8494
8495         __connman_stats_service_unregister(service);
8496
8497         if (service->network) {
8498                 err = __connman_network_disconnect(service->network);
8499         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
8500                                         service->provider)
8501                 err = connman_provider_disconnect(service->provider);
8502         else
8503                 return -EOPNOTSUPP;
8504
8505         if (err < 0 && err != -EINPROGRESS)
8506                 return err;
8507
8508         __connman_6to4_remove(service->ipconfig_ipv4);
8509
8510         if (service->ipconfig_ipv4)
8511                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
8512                                                         NULL);
8513         else
8514                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
8515                                                         NULL);
8516
8517 #if defined TIZEN_EXT
8518         /**
8519           * Skip the functions If there is any connected profiles
8520           * that use same interface
8521           */
8522         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
8523                 __connman_service_get_connected_count_of_iface(service) <= 0) {
8524 #endif
8525         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
8526         settings_changed(service, service->ipconfig_ipv4);
8527
8528         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
8529         settings_changed(service, service->ipconfig_ipv6);
8530
8531         __connman_ipconfig_disable(service->ipconfig_ipv4);
8532         __connman_ipconfig_disable(service->ipconfig_ipv6);
8533 #if defined TIZEN_EXT
8534         }
8535 #endif
8536
8537         return err;
8538 }
8539
8540 int __connman_service_disconnect_all(void)
8541 {
8542         struct connman_service *service;
8543         GSList *services = NULL, *list;
8544         GList *iter;
8545
8546         DBG("");
8547
8548         for (iter = service_list; iter; iter = iter->next) {
8549                 service = iter->data;
8550
8551                 if (!is_connected(service->state))
8552                         break;
8553
8554                 services = g_slist_prepend(services, service);
8555         }
8556
8557         for (list = services; list; list = list->next) {
8558                 struct connman_service *service = list->data;
8559
8560                 service->ignore = true;
8561
8562                 __connman_service_disconnect(service);
8563         }
8564
8565         g_slist_free(services);
8566
8567         return 0;
8568 }
8569
8570 /**
8571  * lookup_by_identifier:
8572  * @identifier: service identifier
8573  *
8574  * Look up a service by identifier (reference count will not be increased)
8575  */
8576 static struct connman_service *lookup_by_identifier(const char *identifier)
8577 {
8578         return g_hash_table_lookup(service_hash, identifier);
8579 }
8580
8581 struct connman_service *connman_service_lookup_from_identifier(const char* identifier)
8582 {
8583         return identifier ? lookup_by_identifier(identifier) : NULL;
8584 }
8585
8586 struct provision_user_data {
8587         const char *ident;
8588         int ret;
8589 };
8590
8591 static void provision_changed(gpointer value, gpointer user_data)
8592 {
8593         struct connman_service *service = value;
8594         struct provision_user_data *data = user_data;
8595         const char *path = data->ident;
8596         int ret;
8597
8598         ret = __connman_config_provision_service_ident(service, path,
8599                         service->config_file, service->config_entry);
8600         if (ret > 0)
8601                 data->ret = ret;
8602 }
8603
8604 int __connman_service_provision_changed(const char *ident)
8605 {
8606         struct provision_user_data data = {
8607                 .ident = ident,
8608                 .ret = 0
8609         };
8610
8611         g_list_foreach(service_list, provision_changed, (void *)&data);
8612
8613         /*
8614          * Because the provision_changed() might have set some services
8615          * as favorite, we must sort the sequence now.
8616          */
8617         if (services_dirty) {
8618                 services_dirty = false;
8619
8620                 service_list_sort();
8621
8622                 __connman_connection_update_gateway();
8623         }
8624
8625         return data.ret;
8626 }
8627
8628 void __connman_service_set_config(struct connman_service *service,
8629                                 const char *file_id, const char *entry)
8630 {
8631         if (!service)
8632                 return;
8633
8634         g_free(service->config_file);
8635         service->config_file = g_strdup(file_id);
8636
8637         g_free(service->config_entry);
8638         service->config_entry = g_strdup(entry);
8639 }
8640
8641 /**
8642  * __connman_service_get:
8643  * @identifier: service identifier
8644  *
8645  * Look up a service by identifier or create a new one if not found
8646  */
8647 static struct connman_service *service_get(const char *identifier)
8648 {
8649         struct connman_service *service;
8650
8651         service = g_hash_table_lookup(service_hash, identifier);
8652         if (service) {
8653                 connman_service_ref(service);
8654                 return service;
8655         }
8656
8657         service = connman_service_create();
8658         if (!service)
8659                 return NULL;
8660
8661         DBG("service %p", service);
8662
8663         service->identifier = g_strdup(identifier);
8664
8665         service_list = g_list_insert_sorted(service_list, service,
8666                                                 service_compare);
8667
8668         g_hash_table_insert(service_hash, service->identifier, service);
8669
8670         return service;
8671 }
8672
8673 static int service_register(struct connman_service *service)
8674 {
8675         DBG("service %p", service);
8676
8677         if (service->path)
8678                 return -EALREADY;
8679
8680         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
8681                                                 service->identifier);
8682
8683         DBG("path %s", service->path);
8684
8685 #if defined TIZEN_EXT
8686         service_load(service);
8687         int ret = __connman_config_provision_service(service);
8688         if (ret < 0)
8689                 DBG("Failed to provision service");
8690 #else
8691         if (__connman_config_provision_service(service) < 0)
8692                 service_load(service);
8693 #endif
8694
8695         g_dbus_register_interface(connection, service->path,
8696                                         CONNMAN_SERVICE_INTERFACE,
8697                                         service_methods, service_signals,
8698                                                         NULL, service, NULL);
8699
8700         service_list_sort();
8701
8702         __connman_connection_update_gateway();
8703
8704         return 0;
8705 }
8706
8707 static void service_up(struct connman_ipconfig *ipconfig,
8708                 const char *ifname)
8709 {
8710         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8711
8712         DBG("%s up", ifname);
8713
8714         link_changed(service);
8715
8716         service->stats.valid = false;
8717         service->stats_roaming.valid = false;
8718 }
8719
8720 static void service_down(struct connman_ipconfig *ipconfig,
8721                         const char *ifname)
8722 {
8723         DBG("%s down", ifname);
8724 }
8725
8726 static void service_lower_up(struct connman_ipconfig *ipconfig,
8727                         const char *ifname)
8728 {
8729         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8730
8731         DBG("%s lower up", ifname);
8732
8733         stats_start(service);
8734 }
8735
8736 static void service_lower_down(struct connman_ipconfig *ipconfig,
8737                         const char *ifname)
8738 {
8739         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8740
8741         DBG("%s lower down", ifname);
8742
8743         stats_stop(service);
8744         service_save(service);
8745 }
8746
8747 static void service_ip_bound(struct connman_ipconfig *ipconfig,
8748                         const char *ifname)
8749 {
8750         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8751         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
8752         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
8753 #if defined TIZEN_EXT
8754         int err;
8755 #endif
8756
8757         DBG("%s ip bound", ifname);
8758
8759         type = __connman_ipconfig_get_config_type(ipconfig);
8760         method = __connman_ipconfig_get_method(ipconfig);
8761
8762         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
8763                                                         type, method);
8764
8765         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
8766                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
8767 #if defined TIZEN_EXT
8768         {
8769                 err = __connman_ipconfig_gateway_add(ipconfig, service);
8770
8771                 if(err < 0)
8772                         DBG("Failed to add gateway");
8773         }
8774 #else
8775                 __connman_service_ipconfig_indicate_state(service,
8776                                                 CONNMAN_SERVICE_STATE_READY,
8777                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
8778 #endif
8779
8780         settings_changed(service, ipconfig);
8781         address_updated(service, type);
8782 }
8783
8784 static void service_ip_release(struct connman_ipconfig *ipconfig,
8785                         const char *ifname)
8786 {
8787         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8788         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
8789         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
8790
8791         DBG("%s ip release", ifname);
8792
8793         type = __connman_ipconfig_get_config_type(ipconfig);
8794         method = __connman_ipconfig_get_method(ipconfig);
8795
8796         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
8797                                                         type, method);
8798
8799         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
8800                         method == CONNMAN_IPCONFIG_METHOD_OFF)
8801                 __connman_service_ipconfig_indicate_state(service,
8802                                         CONNMAN_SERVICE_STATE_DISCONNECT,
8803                                         CONNMAN_IPCONFIG_TYPE_IPV6);
8804
8805         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
8806                         method == CONNMAN_IPCONFIG_METHOD_OFF)
8807                 __connman_service_ipconfig_indicate_state(service,
8808                                         CONNMAN_SERVICE_STATE_DISCONNECT,
8809                                         CONNMAN_IPCONFIG_TYPE_IPV4);
8810
8811         settings_changed(service, ipconfig);
8812 }
8813
8814 static void service_route_changed(struct connman_ipconfig *ipconfig,
8815                                 const char *ifname)
8816 {
8817         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8818
8819         DBG("%s route changed", ifname);
8820
8821         settings_changed(service, ipconfig);
8822 }
8823
8824 static const struct connman_ipconfig_ops service_ops = {
8825         .up             = service_up,
8826         .down           = service_down,
8827         .lower_up       = service_lower_up,
8828         .lower_down     = service_lower_down,
8829         .ip_bound       = service_ip_bound,
8830         .ip_release     = service_ip_release,
8831         .route_set      = service_route_changed,
8832         .route_unset    = service_route_changed,
8833 };
8834
8835 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
8836                 int index, enum connman_ipconfig_method method)
8837 {
8838         struct connman_ipconfig *ipconfig_ipv4;
8839
8840         ipconfig_ipv4 = __connman_ipconfig_create(index,
8841                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
8842         if (!ipconfig_ipv4)
8843                 return NULL;
8844
8845         __connman_ipconfig_set_method(ipconfig_ipv4, method);
8846
8847         __connman_ipconfig_set_data(ipconfig_ipv4, service);
8848
8849         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
8850
8851         return ipconfig_ipv4;
8852 }
8853
8854 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
8855                 int index)
8856 {
8857         struct connman_ipconfig *ipconfig_ipv6;
8858
8859         ipconfig_ipv6 = __connman_ipconfig_create(index,
8860                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
8861         if (!ipconfig_ipv6)
8862                 return NULL;
8863
8864         __connman_ipconfig_set_data(ipconfig_ipv6, service);
8865
8866         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
8867
8868         return ipconfig_ipv6;
8869 }
8870
8871 void __connman_service_read_ip4config(struct connman_service *service)
8872 {
8873         GKeyFile *keyfile;
8874
8875         if (!service->ipconfig_ipv4)
8876                 return;
8877
8878         keyfile = connman_storage_load_service(service->identifier);
8879         if (!keyfile)
8880                 return;
8881
8882         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
8883                                 service->identifier, "IPv4.");
8884
8885         g_key_file_free(keyfile);
8886 }
8887
8888 void connman_service_create_ip4config(struct connman_service *service,
8889                                         int index)
8890 {
8891         DBG("ipv4 %p", service->ipconfig_ipv4);
8892
8893         if (service->ipconfig_ipv4)
8894                 return;
8895
8896         service->ipconfig_ipv4 = create_ip4config(service, index,
8897                         CONNMAN_IPCONFIG_METHOD_DHCP);
8898         __connman_service_read_ip4config(service);
8899 }
8900
8901 void __connman_service_read_ip6config(struct connman_service *service)
8902 {
8903         GKeyFile *keyfile;
8904
8905         if (!service->ipconfig_ipv6)
8906                 return;
8907
8908         keyfile = connman_storage_load_service(service->identifier);
8909         if (!keyfile)
8910                 return;
8911
8912         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
8913                                 service->identifier, "IPv6.");
8914
8915         g_key_file_free(keyfile);
8916 }
8917
8918 void connman_service_create_ip6config(struct connman_service *service,
8919                                                                 int index)
8920 {
8921         DBG("ipv6 %p", service->ipconfig_ipv6);
8922
8923         if (service->ipconfig_ipv6)
8924                 return;
8925
8926         service->ipconfig_ipv6 = create_ip6config(service, index);
8927
8928         __connman_service_read_ip6config(service);
8929 }
8930
8931 /**
8932  * connman_service_lookup_from_network:
8933  * @network: network structure
8934  *
8935  * Look up a service by network (reference count will not be increased)
8936  */
8937 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
8938 {
8939         struct connman_service *service;
8940         const char *ident, *group;
8941         char *name;
8942
8943         if (!network)
8944                 return NULL;
8945
8946         ident = __connman_network_get_ident(network);
8947         if (!ident)
8948                 return NULL;
8949
8950         group = connman_network_get_group(network);
8951         if (!group)
8952                 return NULL;
8953
8954         name = g_strdup_printf("%s_%s_%s",
8955                         __connman_network_get_type(network), ident, group);
8956         service = lookup_by_identifier(name);
8957         g_free(name);
8958
8959         return service;
8960 }
8961
8962 struct connman_service *__connman_service_lookup_from_index(int index)
8963 {
8964         struct connman_service *service;
8965         GList *list;
8966
8967         for (list = service_list; list; list = list->next) {
8968                 service = list->data;
8969
8970                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
8971                                                         == index)
8972                         return service;
8973
8974                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
8975                                                         == index)
8976                         return service;
8977         }
8978
8979         return NULL;
8980 }
8981
8982 const char *connman_service_get_identifier(struct connman_service *service)
8983 {
8984         return service ? service->identifier : NULL;
8985 }
8986
8987 const char *__connman_service_get_path(struct connman_service *service)
8988 {
8989         return service->path;
8990 }
8991
8992 const char *__connman_service_get_name(struct connman_service *service)
8993 {
8994         return service->name;
8995 }
8996
8997 enum connman_service_state connman_service_get_state(struct connman_service *service)
8998 {
8999         return service ? service->state : CONNMAN_SERVICE_STATE_UNKNOWN;
9000 }
9001
9002 static enum connman_service_type convert_network_type(struct connman_network *network)
9003 {
9004         enum connman_network_type type = connman_network_get_type(network);
9005
9006         switch (type) {
9007         case CONNMAN_NETWORK_TYPE_UNKNOWN:
9008         case CONNMAN_NETWORK_TYPE_VENDOR:
9009                 break;
9010         case CONNMAN_NETWORK_TYPE_ETHERNET:
9011                 return CONNMAN_SERVICE_TYPE_ETHERNET;
9012         case CONNMAN_NETWORK_TYPE_WIFI:
9013                 return CONNMAN_SERVICE_TYPE_WIFI;
9014         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
9015         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
9016                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
9017         case CONNMAN_NETWORK_TYPE_CELLULAR:
9018                 return CONNMAN_SERVICE_TYPE_CELLULAR;
9019         case CONNMAN_NETWORK_TYPE_GADGET:
9020                 return CONNMAN_SERVICE_TYPE_GADGET;
9021         }
9022
9023         return CONNMAN_SERVICE_TYPE_UNKNOWN;
9024 }
9025
9026 static enum connman_service_security convert_wifi_security(const char *security)
9027 {
9028         if (!security)
9029                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
9030         else if (g_str_equal(security, "none"))
9031                 return CONNMAN_SERVICE_SECURITY_NONE;
9032         else if (g_str_equal(security, "wep"))
9033                 return CONNMAN_SERVICE_SECURITY_WEP;
9034         else if (g_str_equal(security, "psk"))
9035                 return CONNMAN_SERVICE_SECURITY_PSK;
9036         else if (g_str_equal(security, "ieee8021x"))
9037                 return CONNMAN_SERVICE_SECURITY_8021X;
9038         else if (g_str_equal(security, "wpa"))
9039                 return CONNMAN_SERVICE_SECURITY_WPA;
9040         else if (g_str_equal(security, "rsn"))
9041                 return CONNMAN_SERVICE_SECURITY_RSN;
9042 #if defined TIZEN_EXT
9043         else if (g_str_equal(security, "sae"))
9044                 return CONNMAN_SERVICE_SECURITY_SAE;
9045         else if (g_str_equal(security, "owe"))
9046                 return CONNMAN_SERVICE_SECURITY_OWE;
9047         else if (g_str_equal(security, "dpp"))
9048                 return CONNMAN_SERVICE_SECURITY_DPP;
9049         else if (g_str_equal(security, "ft_psk") == TRUE)
9050                 return CONNMAN_SERVICE_SECURITY_PSK;
9051         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
9052                 return CONNMAN_SERVICE_SECURITY_8021X;
9053 #endif
9054         else
9055                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
9056 }
9057
9058 #if defined TIZEN_EXT
9059 int check_passphrase_ext(struct connman_network *network,
9060                                         const char *passphrase)
9061 {
9062         const char *str;
9063         enum connman_service_security security;
9064
9065         str = connman_network_get_string(network, "WiFi.Security");
9066         security = convert_wifi_security(str);
9067
9068         return __connman_service_check_passphrase(security, passphrase);
9069 }
9070 #endif
9071
9072 static void update_wps_values(struct connman_service *service,
9073                                 struct connman_network *network)
9074 {
9075         bool wps = connman_network_get_bool(network, "WiFi.WPS");
9076         bool wps_advertising = connman_network_get_bool(network,
9077                                                         "WiFi.WPSAdvertising");
9078
9079         if (service->wps != wps ||
9080                         service->wps_advertizing != wps_advertising) {
9081                 service->wps = wps;
9082                 service->wps_advertizing = wps_advertising;
9083                 security_changed(service);
9084         }
9085 }
9086
9087 static void update_from_network(struct connman_service *service,
9088                                         struct connman_network *network)
9089 {
9090         uint8_t strength = service->strength;
9091         const char *str;
9092
9093         DBG("service %p network %p", service, network);
9094
9095         if (is_connected(service->state))
9096                 return;
9097
9098         if (is_connecting(service->state))
9099                 return;
9100
9101         str = connman_network_get_string(network, "Name");
9102         if (str) {
9103                 g_free(service->name);
9104                 service->name = g_strdup(str);
9105                 service->hidden = false;
9106         } else {
9107                 g_free(service->name);
9108                 service->name = NULL;
9109                 service->hidden = true;
9110         }
9111
9112         service->strength = connman_network_get_strength(network);
9113         service->roaming = connman_network_get_bool(network, "Roaming");
9114
9115         if (service->strength == 0) {
9116                 /*
9117                  * Filter out 0-values; it's unclear what they mean
9118                  * and they cause anomalous sorting of the priority list.
9119                  */
9120                 service->strength = strength;
9121         }
9122
9123         str = connman_network_get_string(network, "WiFi.Security");
9124         service->security = convert_wifi_security(str);
9125
9126         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
9127                 update_wps_values(service, network);
9128
9129         if (service->strength > strength && service->network) {
9130                 connman_network_unref(service->network);
9131                 service->network = connman_network_ref(network);
9132
9133                 strength_changed(service);
9134         }
9135
9136         if (!service->network)
9137                 service->network = connman_network_ref(network);
9138
9139         service_list_sort();
9140 }
9141
9142 /**
9143  * __connman_service_create_from_network:
9144  * @network: network structure
9145  *
9146  * Look up service by network and if not found, create one
9147  */
9148 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
9149 {
9150         struct connman_service *service;
9151         struct connman_device *device;
9152         const char *ident, *group;
9153         char *name;
9154         unsigned int *auto_connect_types, *favorite_types;
9155         int i, index;
9156
9157         DBG("network %p", network);
9158
9159         if (!network)
9160                 return NULL;
9161
9162         ident = __connman_network_get_ident(network);
9163         if (!ident)
9164                 return NULL;
9165
9166         group = connman_network_get_group(network);
9167         if (!group)
9168                 return NULL;
9169
9170         name = g_strdup_printf("%s_%s_%s",
9171                         __connman_network_get_type(network), ident, group);
9172         service = service_get(name);
9173         g_free(name);
9174
9175         if (!service)
9176                 return NULL;
9177
9178         if (__connman_network_get_weakness(network))
9179                 return service;
9180
9181         if (service->path) {
9182                 update_from_network(service, network);
9183                 __connman_connection_update_gateway();
9184                 return service;
9185         }
9186
9187         service->type = convert_network_type(network);
9188
9189         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
9190         service->autoconnect = false;
9191         for (i = 0; auto_connect_types &&
9192                      auto_connect_types[i] != 0; i++) {
9193                 if (service->type == auto_connect_types[i]) {
9194                         service->autoconnect = true;
9195                         break;
9196                 }
9197         }
9198
9199         favorite_types = connman_setting_get_uint_list("DefaultFavoriteTechnologies");
9200         service->favorite = false;
9201         for (i = 0; favorite_types && favorite_types[i] != 0; i++) {
9202                 if (service->type == favorite_types[i]) {
9203                         service->favorite = true;
9204                         break;
9205                 }
9206         }
9207
9208         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
9209         service->state = combine_state(service->state_ipv4, service->state_ipv6);
9210
9211         update_from_network(service, network);
9212
9213         index = connman_network_get_index(network);
9214
9215         if (!service->ipconfig_ipv4)
9216                 service->ipconfig_ipv4 = create_ip4config(service, index,
9217                                 CONNMAN_IPCONFIG_METHOD_DHCP);
9218
9219         if (!service->ipconfig_ipv6)
9220                 service->ipconfig_ipv6 = create_ip6config(service, index);
9221
9222         service_register(service);
9223         service_schedule_added(service);
9224
9225         if (service->favorite) {
9226                 device = connman_network_get_device(service->network);
9227                 if (device && !connman_device_get_scanning(device,
9228                                                 CONNMAN_SERVICE_TYPE_UNKNOWN)) {
9229
9230                         switch (service->type) {
9231                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
9232                         case CONNMAN_SERVICE_TYPE_SYSTEM:
9233                         case CONNMAN_SERVICE_TYPE_P2P:
9234 #if defined TIZEN_EXT_WIFI_MESH
9235                         case CONNMAN_SERVICE_TYPE_MESH:
9236 #endif
9237                                 break;
9238
9239                         case CONNMAN_SERVICE_TYPE_GADGET:
9240                         case CONNMAN_SERVICE_TYPE_ETHERNET:
9241                                 if (service->autoconnect) {
9242                                         __connman_service_connect(service,
9243                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
9244                                         break;
9245                                 }
9246
9247                                 /* fall through */
9248                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
9249                         case CONNMAN_SERVICE_TYPE_GPS:
9250                         case CONNMAN_SERVICE_TYPE_VPN:
9251                         case CONNMAN_SERVICE_TYPE_WIFI:
9252                         case CONNMAN_SERVICE_TYPE_CELLULAR:
9253                                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
9254                                 break;
9255                         }
9256                 }
9257
9258 #if defined TIZEN_EXT
9259                 /* TIZEN synchronizes below information when the service creates */
9260                 if (service->eap != NULL)
9261                         connman_network_set_string(service->network, "WiFi.EAP",
9262                                                                 service->eap);
9263                 if (service->identity != NULL)
9264                         connman_network_set_string(service->network, "WiFi.Identity",
9265                                                                 service->identity);
9266                 if (service->phase2 != NULL)
9267                         connman_network_set_string(service->network, "WiFi.Phase2",
9268                                                                 service->phase2);
9269                 if (service->eap != NULL)
9270                         connman_network_set_string(service->network, "WiFi.Connector",
9271                                                                 service->connector);
9272                 if (service->identity != NULL)
9273                         connman_network_set_string(service->network, "WiFi.CSignKey",
9274                                                                 service->c_sign_key);
9275                 if (service->phase2 != NULL)
9276                         connman_network_set_string(service->network, "WiFi.NetAccessKey",
9277                                                                 service->net_access_key);
9278 #endif
9279         }
9280
9281         __connman_notifier_service_add(service, service->name);
9282
9283         return service;
9284 }
9285
9286 #if defined TIZEN_EXT
9287 void __connman_service_notify_strength_changed(struct connman_network *network)
9288 {
9289         struct connman_service *service;
9290         uint8_t strength = 0;
9291
9292         service = connman_service_lookup_from_network(network);
9293         if (!service)
9294                 return;
9295
9296         if (!service->network)
9297                 return;
9298
9299         strength = connman_network_get_strength(service->network);
9300         if (strength == service->strength)
9301                 return;
9302
9303         service->strength = strength;
9304         DBG("Strength %d", strength);
9305         strength_changed(service);
9306         service_list_sort();
9307 }
9308 #endif
9309
9310 void __connman_service_update_from_network(struct connman_network *network)
9311 {
9312         bool need_sort = false;
9313         struct connman_service *service;
9314         uint8_t strength;
9315         bool roaming;
9316         const char *name;
9317         bool stats_enable;
9318
9319         service = connman_service_lookup_from_network(network);
9320         if (!service)
9321                 return;
9322
9323         if (!service->network)
9324                 return;
9325
9326 #if defined TIZEN_EXT
9327         if (service->storage_reload) {
9328                 service_load(service);
9329                 __connman_service_set_storage_reload(service, false);
9330         }
9331 #endif
9332
9333         name = connman_network_get_string(service->network, "Name");
9334         if (g_strcmp0(service->name, name) != 0) {
9335                 g_free(service->name);
9336                 service->name = g_strdup(name);
9337
9338                 if (allow_property_changed(service))
9339                         connman_dbus_property_changed_basic(service->path,
9340                                         CONNMAN_SERVICE_INTERFACE, "Name",
9341                                         DBUS_TYPE_STRING, &service->name);
9342         }
9343
9344         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
9345                 update_wps_values(service, network);
9346
9347         strength = connman_network_get_strength(service->network);
9348         if (strength == service->strength)
9349                 goto roaming;
9350
9351         service->strength = strength;
9352         need_sort = true;
9353
9354         strength_changed(service);
9355
9356 roaming:
9357         roaming = connman_network_get_bool(service->network, "Roaming");
9358         if (roaming == service->roaming)
9359                 goto sorting;
9360
9361         stats_enable = stats_enabled(service);
9362         if (stats_enable)
9363                 stats_stop(service);
9364
9365         service->roaming = roaming;
9366         need_sort = true;
9367
9368         if (stats_enable)
9369                 stats_start(service);
9370
9371         roaming_changed(service);
9372
9373 sorting:
9374         if (need_sort) {
9375                 service_list_sort();
9376         }
9377 }
9378
9379 void __connman_service_remove_from_network(struct connman_network *network)
9380 {
9381         struct connman_service *service;
9382
9383         service = connman_service_lookup_from_network(network);
9384
9385         DBG("network %p service %p", network, service);
9386
9387         if (!service)
9388                 return;
9389
9390         service->ignore = true;
9391
9392         __connman_connection_gateway_remove(service,
9393                                         CONNMAN_IPCONFIG_TYPE_ALL);
9394
9395         connman_service_unref(service);
9396 }
9397
9398 /**
9399  * __connman_service_create_from_provider:
9400  * @provider: provider structure
9401  *
9402  * Look up service by provider and if not found, create one
9403  */
9404 struct connman_service *
9405 __connman_service_create_from_provider(struct connman_provider *provider)
9406 {
9407         struct connman_service *service;
9408         const char *ident, *str;
9409         char *name;
9410         int index = connman_provider_get_index(provider);
9411
9412         DBG("provider %p", provider);
9413
9414         ident = __connman_provider_get_ident(provider);
9415         if (!ident)
9416                 return NULL;
9417
9418         name = g_strdup_printf("vpn_%s", ident);
9419         service = service_get(name);
9420         g_free(name);
9421
9422         if (!service)
9423                 return NULL;
9424
9425         service->type = CONNMAN_SERVICE_TYPE_VPN;
9426         service->order = service->do_split_routing ? 0 : 10;
9427         service->provider = connman_provider_ref(provider);
9428         service->autoconnect = false;
9429         service->favorite = true;
9430
9431         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
9432         service->state = combine_state(service->state_ipv4, service->state_ipv6);
9433
9434         str = connman_provider_get_string(provider, "Name");
9435         if (str) {
9436                 g_free(service->name);
9437                 service->name = g_strdup(str);
9438                 service->hidden = false;
9439         } else {
9440                 g_free(service->name);
9441                 service->name = NULL;
9442                 service->hidden = true;
9443         }
9444
9445         service->strength = 0;
9446
9447         if (!service->ipconfig_ipv4)
9448                 service->ipconfig_ipv4 = create_ip4config(service, index,
9449                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
9450
9451         if (!service->ipconfig_ipv6)
9452                 service->ipconfig_ipv6 = create_ip6config(service, index);
9453
9454         service_register(service);
9455
9456         __connman_notifier_service_add(service, service->name);
9457         service_schedule_added(service);
9458
9459         return service;
9460 }
9461
9462 static void remove_unprovisioned_services(void)
9463 {
9464         gchar **services;
9465         GKeyFile *keyfile, *configkeyfile;
9466         char *file, *section;
9467         int i = 0;
9468
9469         services = connman_storage_get_services();
9470         if (!services)
9471                 return;
9472
9473         for (; services[i]; i++) {
9474                 file = section = NULL;
9475                 keyfile = configkeyfile = NULL;
9476
9477                 keyfile = connman_storage_load_service(services[i]);
9478                 if (!keyfile)
9479                         continue;
9480
9481                 file = g_key_file_get_string(keyfile, services[i],
9482                                         "Config.file", NULL);
9483                 if (!file)
9484                         goto next;
9485
9486                 section = g_key_file_get_string(keyfile, services[i],
9487                                         "Config.ident", NULL);
9488                 if (!section)
9489                         goto next;
9490
9491                 configkeyfile = __connman_storage_load_config(file);
9492                 if (!configkeyfile) {
9493                         /*
9494                          * Config file is missing, remove the provisioned
9495                          * service.
9496                          */
9497                         __connman_storage_remove_service(services[i]);
9498                         goto next;
9499                 }
9500
9501                 if (!g_key_file_has_group(configkeyfile, section))
9502                         /*
9503                          * Config section is missing, remove the provisioned
9504                          * service.
9505                          */
9506                         __connman_storage_remove_service(services[i]);
9507
9508         next:
9509                 if (keyfile)
9510                         g_key_file_free(keyfile);
9511
9512                 if (configkeyfile)
9513                         g_key_file_free(configkeyfile);
9514
9515                 g_free(section);
9516                 g_free(file);
9517         }
9518
9519         g_strfreev(services);
9520 }
9521
9522 static int agent_probe(struct connman_agent *agent)
9523 {
9524         DBG("agent %p", agent);
9525         return 0;
9526 }
9527
9528 static void agent_remove(struct connman_agent *agent)
9529 {
9530         DBG("agent %p", agent);
9531 }
9532
9533 static void *agent_context_ref(void *context)
9534 {
9535         struct connman_service *service = context;
9536
9537         return (void *)connman_service_ref(service);
9538 }
9539
9540 static void agent_context_unref(void *context)
9541 {
9542         struct connman_service *service = context;
9543
9544         connman_service_unref(service);
9545 }
9546
9547 static struct connman_agent_driver agent_driver = {
9548         .name           = "service",
9549         .interface      = CONNMAN_AGENT_INTERFACE,
9550         .probe          = agent_probe,
9551         .remove         = agent_remove,
9552         .context_ref    = agent_context_ref,
9553         .context_unref  = agent_context_unref,
9554 };
9555
9556 int __connman_service_init(void)
9557 {
9558         int err;
9559
9560         DBG("");
9561
9562         err = connman_agent_driver_register(&agent_driver);
9563         if (err < 0) {
9564                 connman_error("Cannot register agent driver for %s",
9565                                                 agent_driver.name);
9566                 return err;
9567         }
9568
9569         set_always_connecting_technologies();
9570
9571         connection = connman_dbus_get_connection();
9572
9573         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
9574                                                         NULL, service_free);
9575
9576         services_notify = g_new0(struct _services_notify, 1);
9577         services_notify->remove = g_hash_table_new_full(g_str_hash,
9578                         g_str_equal, g_free, NULL);
9579         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
9580
9581         remove_unprovisioned_services();
9582
9583         return 0;
9584 }
9585
9586 void __connman_service_cleanup(void)
9587 {
9588         DBG("");
9589
9590         if (vpn_autoconnect_id) {
9591                 g_source_remove(vpn_autoconnect_id);
9592                 vpn_autoconnect_id = 0;
9593         }
9594
9595         if (autoconnect_id != 0) {
9596                 g_source_remove(autoconnect_id);
9597                 autoconnect_id = 0;
9598         }
9599
9600         connman_agent_driver_unregister(&agent_driver);
9601
9602         g_list_free(service_list);
9603         service_list = NULL;
9604
9605         g_hash_table_destroy(service_hash);
9606         service_hash = NULL;
9607
9608         g_slist_free(counter_list);
9609         counter_list = NULL;
9610
9611         if (services_notify->id != 0) {
9612                 g_source_remove(services_notify->id);
9613                 service_send_changed(NULL);
9614         }
9615
9616         g_hash_table_destroy(services_notify->remove);
9617         g_hash_table_destroy(services_notify->add);
9618         g_free(services_notify);
9619
9620         dbus_connection_unref(connection);
9621 }