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