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