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