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