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