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