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