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