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