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