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