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