Add support for handling wifi authentication failure
[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         char country_code_buff[WIFI_COUNTRY_CODE_LEN + 1] = {0,};
4292         char *country_code_str = country_code_buff;
4293         unsigned char *country_code;
4294         uint16_t connection_mode;
4295         GSList *sec_list = NULL;
4296
4297         ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len);
4298         bssid = connman_network_get_bssid(network);
4299         maxrate = connman_network_get_maxrate(network);
4300         maxspeed = connman_network_get_maxspeed(network);
4301         frequency = connman_network_get_frequency(network);
4302         enc_mode = connman_network_get_enc_mode(network);
4303         passpoint = connman_network_get_bool(network, "WiFi.HS20AP");
4304         keymgmt = connman_network_get_keymgmt(network);
4305         country_code = connman_network_get_countrycode(network);
4306         connection_mode = connman_network_get_connection_mode(network);
4307         sec_list = (GSList *)connman_network_get_sec_list(network);
4308
4309         snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
4310
4311         snprintf(country_code_str, (WIFI_COUNTRY_CODE_LEN + 1), "%c%c",
4312                  country_code[0], country_code[1]);
4313
4314         connman_dbus_dict_append_array(dict, "SecurityList",
4315                                         DBUS_TYPE_STRING,
4316                                         append_security_list, sec_list);
4317
4318         connman_dbus_dict_append_fixed_array(dict, "SSID",
4319                                         DBUS_TYPE_BYTE, &ssid, ssid_len);
4320         connman_dbus_dict_append_basic(dict, "BSSID",
4321                                         DBUS_TYPE_STRING, &bssid_str);
4322         connman_dbus_dict_append_basic(dict, "MaxRate",
4323                                         DBUS_TYPE_UINT32, &maxrate);
4324         connman_dbus_dict_append_basic(dict, "MaxSpeed",
4325                                         DBUS_TYPE_INT32, &maxspeed);
4326         connman_dbus_dict_append_basic(dict, "Frequency",
4327                                         DBUS_TYPE_UINT16, &frequency);
4328         connman_dbus_dict_append_basic(dict, "EncryptionMode",
4329                                         DBUS_TYPE_STRING, &enc_mode);
4330         connman_dbus_dict_append_basic(dict, "Passpoint",
4331                                         DBUS_TYPE_BOOLEAN, &passpoint);
4332         connman_dbus_dict_append_basic(dict, "Keymgmt",
4333                                         DBUS_TYPE_UINT32, &keymgmt);
4334         connman_dbus_dict_append_basic(dict, "Country", DBUS_TYPE_STRING,
4335                                        &country_code_str);
4336         connman_dbus_dict_append_basic(dict, "ConnMode",
4337                                         DBUS_TYPE_UINT16, &connection_mode);
4338
4339         str = connman_network_get_string(network, "WiFi.Security");
4340         if (str != NULL && g_str_equal(str, "ieee8021x") == TRUE) {
4341                 str = connman_network_get_string(network, "WiFi.EAP");
4342                 if (str != NULL)
4343                         connman_dbus_dict_append_basic(dict, "EAP",
4344                                         DBUS_TYPE_STRING, &str);
4345
4346                 str = connman_network_get_string(network, "WiFi.Phase2");
4347                 if (str != NULL)
4348                         connman_dbus_dict_append_basic(dict, "Phase2",
4349                                         DBUS_TYPE_STRING, &str);
4350
4351                 str = connman_network_get_string(network, "WiFi.Identity");
4352                 if (str != NULL)
4353                         connman_dbus_dict_append_basic(dict, "Identity",
4354                                         DBUS_TYPE_STRING, &str);
4355
4356                 str = connman_network_get_string(network, "WiFi.CACertFile");
4357                 if (str != NULL)
4358                         connman_dbus_dict_append_basic(dict, "CACertFile",
4359                                         DBUS_TYPE_STRING, &str);
4360
4361                 str = connman_network_get_string(network,
4362                                 "WiFi.ClientCertFile");
4363                 if (str != NULL)
4364                         connman_dbus_dict_append_basic(dict, "ClientCertFile",
4365                                         DBUS_TYPE_STRING, &str);
4366
4367                 str = connman_network_get_string(network,
4368                                 "WiFi.PrivateKeyFile");
4369                 if (str != NULL)
4370                         connman_dbus_dict_append_basic(dict, "PrivateKeyFile",
4371                                         DBUS_TYPE_STRING, &str);
4372         }
4373 }
4374
4375 static void append_bssid_info(DBusMessageIter *iter, void *user_data)
4376 {
4377         GSList *bssid_list = NULL;
4378         struct connman_network *network = user_data;
4379         struct connman_bssids *bssids;
4380         char bssid_buf[MAC_ADDRESS_LENGTH] = {0,};
4381         char *bssid_str = bssid_buf;
4382
4383         bssid_list = (GSList *)connman_network_get_bssid_list(network);
4384         if(bssid_list) {
4385                 GSList *list;
4386                 for (list = bssid_list; list; list = list->next) {
4387                         bssids = (struct connman_bssids *)list->data;
4388                         g_snprintf(bssid_buf, MAC_ADDRESS_LENGTH, MACSTR, MAC2STR(bssids->bssid));
4389
4390                         connman_dbus_dict_append_basic(iter, "BSSID",
4391                                         DBUS_TYPE_STRING, &bssid_str);
4392
4393                         connman_dbus_dict_append_basic(iter, "Strength",
4394                                         DBUS_TYPE_UINT16, &bssids->strength);
4395
4396                         connman_dbus_dict_append_basic(iter, "Frequency",
4397                                         DBUS_TYPE_UINT16, &bssids->frequency);
4398                 }
4399         }
4400 }
4401 #endif
4402
4403 static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
4404                                         struct connman_service *service)
4405 {
4406         dbus_bool_t val;
4407         const char *str;
4408         GSList *list;
4409
4410 #if defined TIZEN_EXT
4411         unsigned int frequency = 0U;
4412         unsigned char *wifi_vsie;
4413         unsigned int wifi_vsie_len;
4414         GSList *vsie_list = NULL;
4415
4416         if (service->network) {
4417                 frequency = connman_network_get_frequency(service->network);
4418                 connman_dbus_dict_append_basic(dict, "Frequency",
4419                                 DBUS_TYPE_UINT16, &frequency);
4420                 vsie_list = (GSList *)connman_network_get_vsie_list(service->network);
4421         }
4422
4423         if (vsie_list) {
4424                 GSList *list;
4425                 for (list = vsie_list; list; list = list->next) {
4426                         wifi_vsie = (unsigned char *)list->data;
4427                         wifi_vsie_len = wifi_vsie[1] + 2;
4428
4429                         connman_dbus_dict_append_fixed_array(dict, "Vsie", DBUS_TYPE_BYTE,
4430                                         &wifi_vsie, wifi_vsie_len);
4431                 }
4432         }
4433 #endif
4434
4435         str = __connman_service_type2string(service->type);
4436         if (str)
4437                 connman_dbus_dict_append_basic(dict, "Type",
4438                                                 DBUS_TYPE_STRING, &str);
4439
4440         connman_dbus_dict_append_array(dict, "Security",
4441                                 DBUS_TYPE_STRING, append_security, service);
4442
4443         str = state2string(service->state);
4444         if (str)
4445                 connman_dbus_dict_append_basic(dict, "State",
4446                                                 DBUS_TYPE_STRING, &str);
4447
4448 #ifdef TIZEN_EXT
4449         str = state2string(service->state_ipv6);
4450         if (str != NULL)
4451                 connman_dbus_dict_append_basic(dict, "StateIPv6",
4452                                 DBUS_TYPE_STRING, &str);
4453 #endif
4454
4455         str = error2string(service->error);
4456         if (str)
4457                 connman_dbus_dict_append_basic(dict, "Error",
4458                                                 DBUS_TYPE_STRING, &str);
4459
4460         if (service->strength > 0)
4461                 connman_dbus_dict_append_basic(dict, "Strength",
4462                                         DBUS_TYPE_BYTE, &service->strength);
4463
4464         val = service->favorite;
4465         connman_dbus_dict_append_basic(dict, "Favorite",
4466                                         DBUS_TYPE_BOOLEAN, &val);
4467
4468         val = service->immutable;
4469         connman_dbus_dict_append_basic(dict, "Immutable",
4470                                         DBUS_TYPE_BOOLEAN, &val);
4471
4472         if (service->favorite)
4473                 val = service->autoconnect;
4474         else
4475                 val = service->favorite;
4476
4477         connman_dbus_dict_append_basic(dict, "AutoConnect",
4478                                 DBUS_TYPE_BOOLEAN, &val);
4479
4480         if (service->name)
4481                 connman_dbus_dict_append_basic(dict, "Name",
4482                                         DBUS_TYPE_STRING, &service->name);
4483
4484         switch (service->type) {
4485         case CONNMAN_SERVICE_TYPE_UNKNOWN:
4486         case CONNMAN_SERVICE_TYPE_SYSTEM:
4487         case CONNMAN_SERVICE_TYPE_GPS:
4488         case CONNMAN_SERVICE_TYPE_VPN:
4489         case CONNMAN_SERVICE_TYPE_P2P:
4490 #if defined TIZEN_EXT_WIFI_MESH
4491         case CONNMAN_SERVICE_TYPE_MESH:
4492 #endif
4493                 break;
4494         case CONNMAN_SERVICE_TYPE_CELLULAR:
4495                 val = service->roaming;
4496                 connman_dbus_dict_append_basic(dict, "Roaming",
4497                                         DBUS_TYPE_BOOLEAN, &val);
4498
4499                 connman_dbus_dict_append_dict(dict, "Ethernet",
4500                                                 append_ethernet, service);
4501                 break;
4502         case CONNMAN_SERVICE_TYPE_WIFI:
4503 #if defined TIZEN_EXT
4504                 if (service->network != NULL) {
4505                         append_wifi_ext_info(dict, service->network);
4506                         connman_dbus_dict_append_dict(dict, "BSSID.List",
4507                                         append_bssid_info, service->network);
4508                 }
4509
4510                 connman_dbus_dict_append_dict(dict, "Ethernet",
4511                                                 append_ethernet, service);
4512
4513                 service->disconnect_reason = connman_network_get_disconnect_reason(service->network);
4514                 connman_dbus_dict_append_basic(dict, "DisconnectReason",
4515                                 DBUS_TYPE_INT32, &service->disconnect_reason);
4516
4517                 connman_dbus_dict_append_basic(dict, "AssocStatusCode",
4518                                 DBUS_TYPE_INT32, &service->assoc_status_code);
4519
4520                 val = service->hidden_service;
4521                 connman_dbus_dict_append_basic(dict, "Hidden",
4522                                 DBUS_TYPE_BOOLEAN, &val);
4523
4524                 break;
4525 #endif
4526         case CONNMAN_SERVICE_TYPE_ETHERNET:
4527 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
4528                 connman_dbus_dict_append_dict(dict, "EapOverEthernet",
4529                                                 append_eap_over_ethernet, service);
4530                 /* fall through */
4531 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
4532         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
4533         case CONNMAN_SERVICE_TYPE_GADGET:
4534                 connman_dbus_dict_append_dict(dict, "Ethernet",
4535                                                 append_ethernet, service);
4536                 break;
4537         }
4538
4539         connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service);
4540
4541         connman_dbus_dict_append_dict(dict, "IPv4.Configuration",
4542                                                 append_ipv4config, service);
4543
4544         connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service);
4545
4546         connman_dbus_dict_append_dict(dict, "IPv6.Configuration",
4547                                                 append_ipv6config, service);
4548
4549         connman_dbus_dict_append_array(dict, "Nameservers",
4550                                 DBUS_TYPE_STRING, append_dns, service);
4551
4552         connman_dbus_dict_append_array(dict, "Nameservers.Configuration",
4553                                 DBUS_TYPE_STRING, append_dnsconfig, service);
4554
4555         if (service->state == CONNMAN_SERVICE_STATE_READY ||
4556                         service->state == CONNMAN_SERVICE_STATE_ONLINE)
4557                 list = __connman_timeserver_get_all(service);
4558         else
4559                 list = NULL;
4560
4561         connman_dbus_dict_append_array(dict, "Timeservers",
4562                                 DBUS_TYPE_STRING, append_ts, list);
4563
4564         g_slist_free_full(list, g_free);
4565
4566         connman_dbus_dict_append_array(dict, "Timeservers.Configuration",
4567                                 DBUS_TYPE_STRING, append_tsconfig, service);
4568
4569         connman_dbus_dict_append_array(dict, "Domains",
4570                                 DBUS_TYPE_STRING, append_domain, service);
4571
4572         connman_dbus_dict_append_array(dict, "Domains.Configuration",
4573                                 DBUS_TYPE_STRING, append_domainconfig, service);
4574
4575         connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service);
4576
4577         connman_dbus_dict_append_dict(dict, "Proxy.Configuration",
4578                                                 append_proxyconfig, service);
4579
4580         val = service->mdns;
4581         connman_dbus_dict_append_basic(dict, "mDNS", DBUS_TYPE_BOOLEAN,
4582                                 &val);
4583
4584         val = service->mdns_config;
4585         connman_dbus_dict_append_basic(dict, "mDNS.Configuration",
4586                                 DBUS_TYPE_BOOLEAN, &val);
4587
4588         connman_dbus_dict_append_dict(dict, "Provider",
4589                                                 append_provider, service);
4590
4591         if (service->network)
4592                 connman_network_append_acddbus(dict, service->network);
4593 }
4594
4595 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
4596 static void append_ins_bssid_info(DBusMessageIter *iter, void *user_data)
4597 {
4598         GSList *bssid_list = NULL;
4599         struct connman_network *network = user_data;
4600         struct connman_bssids *bssids;
4601         char bssid_buf[MAC_ADDRESS_LENGTH] = {0,};
4602         char *bssid_str = bssid_buf;
4603
4604         bssid_list = (GSList *)connman_network_get_bssid_list(network);
4605         if(bssid_list) {
4606                 GSList *list;
4607                 for (list = bssid_list; list; list = list->next) {
4608                         bssids = (struct connman_bssids *)list->data;
4609                         g_snprintf(bssid_buf, MAC_ADDRESS_LENGTH, MACSTR, MAC2STR(bssids->bssid));
4610
4611                         connman_dbus_dict_append_basic(iter, "BSSID",
4612                                         DBUS_TYPE_STRING, &bssid_str);
4613
4614                         connman_dbus_dict_append_basic(iter, "ScoreINS",
4615                                         DBUS_TYPE_INT32, &bssids->ins_score);
4616
4617                         connman_dbus_dict_append_basic(iter, "ScoreLastConnected",
4618                                         DBUS_TYPE_INT32, &bssids->score_last_connected_bssid);
4619
4620                         connman_dbus_dict_append_basic(iter, "ScoreAssocReject",
4621                                         DBUS_TYPE_INT32, &bssids->score_assoc_reject);
4622
4623                         connman_dbus_dict_append_basic(iter, "Frequency",
4624                                         DBUS_TYPE_UINT16, &bssids->frequency);
4625
4626                         connman_dbus_dict_append_basic(iter, "ScoreFrequency",
4627                                         DBUS_TYPE_INT32, &bssids->score_frequency);
4628
4629                         connman_dbus_dict_append_basic(iter, "Strength",
4630                                         DBUS_TYPE_UINT16, &bssids->strength);
4631
4632                         connman_dbus_dict_append_basic(iter, "ScoreStrength",
4633                                         DBUS_TYPE_INT32, &bssids->score_strength);
4634                 }
4635         }
4636 }
4637
4638 static void append_ins_properties(DBusMessageIter *dict,
4639                                         struct connman_service *service)
4640 {
4641         const char *str;
4642         unsigned int frequency = 0U;
4643
4644         if (service->name)
4645                 connman_dbus_dict_append_basic(dict, "Name",
4646                                         DBUS_TYPE_STRING, &service->name);
4647
4648         connman_dbus_dict_append_basic(dict, "ScoreINS",
4649                                 DBUS_TYPE_INT32, &service->ins_score);
4650
4651         connman_dbus_dict_append_basic(dict, "ScoreLastUserSelection",
4652                                 DBUS_TYPE_INT32, &service->score_last_user_selection);
4653
4654         connman_dbus_dict_append_basic(dict, "ScoreLastConnected",
4655                                 DBUS_TYPE_INT32, &service->score_last_connected);
4656
4657         str = security2string(service->security);
4658         if (str)
4659                 connman_dbus_dict_append_basic(dict, "Security",
4660                                 DBUS_TYPE_STRING, &str);
4661
4662         connman_dbus_dict_append_basic(dict, "ScoreSecurityPriority",
4663                                 DBUS_TYPE_INT32, &service->score_security_priority);
4664
4665         connman_dbus_dict_append_basic(dict, "Strength",
4666                                 DBUS_TYPE_BYTE, &service->strength);
4667
4668         connman_dbus_dict_append_basic(dict, "ScoreStrength",
4669                                 DBUS_TYPE_INT32, &service->score_strength);
4670
4671         connman_dbus_dict_append_basic(dict, "ScoreInternetConnection",
4672                                 DBUS_TYPE_INT32, &service->score_internet_connection);
4673
4674         if (service->network) {
4675                 frequency = connman_network_get_frequency(service->network);
4676                 connman_dbus_dict_append_basic(dict, "Frequency",
4677                                 DBUS_TYPE_UINT16, &frequency);
4678
4679                 connman_dbus_dict_append_basic(dict, "ScoreFrequency",
4680                                 DBUS_TYPE_INT32, &service->score_frequency);
4681
4682                 connman_dbus_dict_append_dict(dict, "BSSID.List",
4683                                 append_ins_bssid_info, service->network);
4684         }
4685 }
4686 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
4687
4688 static void append_struct_service(DBusMessageIter *iter,
4689                 connman_dbus_append_cb_t function,
4690                 struct connman_service *service)
4691 {
4692         DBusMessageIter entry, dict;
4693
4694         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
4695
4696         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
4697                                                         &service->path);
4698
4699         connman_dbus_dict_open(&entry, &dict);
4700         if (function)
4701                 function(&dict, service);
4702         connman_dbus_dict_close(&entry, &dict);
4703
4704         dbus_message_iter_close_container(iter, &entry);
4705 }
4706
4707 static void append_dict_properties(DBusMessageIter *dict, void *user_data)
4708 {
4709         struct connman_service *service = user_data;
4710
4711         append_properties(dict, TRUE, service);
4712 }
4713
4714 static void append_struct(gpointer value, gpointer user_data)
4715 {
4716         struct connman_service *service = value;
4717         DBusMessageIter *iter = user_data;
4718
4719         if (!service->path)
4720                 return;
4721
4722         append_struct_service(iter, append_dict_properties, service);
4723 }
4724
4725 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
4726 static void append_dict_ins_properties(DBusMessageIter *dict, void *user_data)
4727 {
4728         struct connman_service *service = user_data;
4729
4730         append_ins_properties(dict, service);
4731 }
4732
4733 static void append_ins_struct(gpointer value, gpointer user_data)
4734 {
4735         struct connman_service *service = value;
4736         DBusMessageIter *iter = user_data;
4737
4738         if (!service->path)
4739                 return;
4740
4741         if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
4742                 return;
4743
4744         append_struct_service(iter, append_dict_ins_properties, service);
4745 }
4746
4747 void __connman_ins_list_struct(DBusMessageIter *iter)
4748 {
4749         g_list_foreach(service_list, append_ins_struct, iter);
4750 }
4751 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
4752
4753 void __connman_service_list_struct(DBusMessageIter *iter)
4754 {
4755         g_list_foreach(service_list, append_struct, iter);
4756 }
4757
4758 bool __connman_service_is_hidden(struct connman_service *service)
4759 {
4760         return service->hidden;
4761 }
4762
4763 bool
4764 __connman_service_is_split_routing(struct connman_service *service)
4765 {
4766         return service->do_split_routing;
4767 }
4768
4769 bool __connman_service_index_is_split_routing(int index)
4770 {
4771         struct connman_service *service;
4772
4773         if (index < 0)
4774                 return false;
4775
4776         service = __connman_service_lookup_from_index(index);
4777         if (!service)
4778                 return false;
4779
4780         return __connman_service_is_split_routing(service);
4781 }
4782
4783 int __connman_service_get_index(struct connman_service *service)
4784 {
4785         if (!service)
4786                 return -1;
4787
4788         if (service->network)
4789                 return connman_network_get_index(service->network);
4790         else if (service->provider)
4791                 return connman_provider_get_index(service->provider);
4792
4793         return -1;
4794 }
4795
4796 void __connman_service_set_hidden(struct connman_service *service)
4797 {
4798         if (!service || service->hidden)
4799                 return;
4800
4801         service->hidden_service = true;
4802 }
4803
4804 void __connman_service_set_hostname(struct connman_service *service,
4805                                                 const char *hostname)
4806 {
4807         if (!service || service->hidden)
4808                 return;
4809
4810         g_free(service->hostname);
4811         service->hostname = NULL;
4812
4813         if (hostname && g_str_is_ascii(hostname))
4814                 service->hostname = g_strdup(hostname);
4815 }
4816
4817 const char *__connman_service_get_hostname(struct connman_service *service)
4818 {
4819         if (!service)
4820                 return NULL;
4821
4822         return service->hostname;
4823 }
4824
4825 void __connman_service_set_domainname(struct connman_service *service,
4826                                                 const char *domainname)
4827 {
4828         if (!service || service->hidden)
4829                 return;
4830
4831         g_free(service->domainname);
4832         service->domainname = NULL;
4833
4834         if (domainname && g_str_is_ascii(domainname))
4835                 service->domainname = g_strdup(domainname);
4836
4837         domain_changed(service);
4838 }
4839
4840 const char *connman_service_get_domainname(struct connman_service *service)
4841 {
4842         if (!service)
4843                 return NULL;
4844
4845         if (service->domains)
4846                 return service->domains[0];
4847         else
4848                 return service->domainname;
4849 }
4850
4851 const char *connman_service_get_dbuspath(struct connman_service *service)
4852 {
4853         if (!service)
4854                 return NULL;
4855
4856         return service->path;
4857 }
4858
4859 char **connman_service_get_nameservers(struct connman_service *service)
4860 {
4861         if (!service)
4862                 return NULL;
4863
4864         if (service->nameservers_config)
4865                 return g_strdupv(service->nameservers_config);
4866         else if (service->nameservers ||
4867                                         service->nameservers_auto) {
4868                 int len = 0, len_auto = 0, i;
4869                 char **nameservers;
4870
4871                 if (service->nameservers)
4872                         len = g_strv_length(service->nameservers);
4873                 if (service->nameservers_auto)
4874                         len_auto = g_strv_length(service->nameservers_auto);
4875
4876                 nameservers = g_try_new0(char *, len + len_auto + 1);
4877                 if (!nameservers)
4878                         return NULL;
4879
4880                 for (i = 0; i < len; i++)
4881                         nameservers[i] = g_strdup(service->nameservers[i]);
4882
4883                 for (i = 0; i < len_auto; i++)
4884                         nameservers[i + len] =
4885                                 g_strdup(service->nameservers_auto[i]);
4886
4887                 return nameservers;
4888         }
4889
4890         return g_strdupv(connman_setting_get_string_list("FallbackNameservers"));
4891 }
4892
4893 char **connman_service_get_timeservers_config(struct connman_service *service)
4894 {
4895         if (!service)
4896                 return NULL;
4897
4898         return service->timeservers_config;
4899 }
4900
4901 char **connman_service_get_timeservers(struct connman_service *service)
4902 {
4903         if (!service)
4904                 return NULL;
4905
4906         return service->timeservers;
4907 }
4908
4909 #if defined TIZEN_EXT
4910 /*
4911  * Description: Telephony plug-in requires manual PROXY setting function
4912  */
4913 int connman_service_set_proxy(struct connman_service *service,
4914                                         const char *proxy, gboolean active)
4915 {
4916         char **proxies_array = NULL;
4917
4918         if (service == NULL)
4919                 return -EINVAL;
4920
4921         switch (service->type) {
4922         case CONNMAN_SERVICE_TYPE_CELLULAR:
4923         case CONNMAN_SERVICE_TYPE_ETHERNET:
4924         case CONNMAN_SERVICE_TYPE_WIFI:
4925                 break;
4926
4927         default:
4928                 return -EINVAL;
4929         }
4930
4931         g_strfreev(service->proxies);
4932         service->proxies = NULL;
4933
4934         if (proxy != NULL)
4935                 proxies_array = g_strsplit(proxy, " ", 0);
4936
4937         service->proxies = proxies_array;
4938
4939         if (proxy == NULL) {
4940                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
4941                 DBG("proxy changed (%d)", active);
4942         } else {
4943                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_MANUAL;
4944                 DBG("proxy chagned %s (%d)", proxy, active);
4945         }
4946
4947         if (active == TRUE) {
4948                 proxy_changed(service);
4949
4950                 __connman_notifier_proxy_changed(service);
4951         }
4952
4953         return 0;
4954 }
4955 #endif
4956
4957 void connman_service_set_proxy_method(struct connman_service *service,
4958                                         enum connman_service_proxy_method method)
4959 {
4960         if (!service || service->hidden)
4961                 return;
4962
4963         service->proxy = method;
4964
4965         proxy_changed(service);
4966
4967         if (method != CONNMAN_SERVICE_PROXY_METHOD_AUTO)
4968                 __connman_notifier_proxy_changed(service);
4969 }
4970
4971 enum connman_service_proxy_method connman_service_get_proxy_method(
4972                                         struct connman_service *service)
4973 {
4974         if (!service)
4975                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
4976
4977         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) {
4978                 if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_AUTO &&
4979                                 !service->pac)
4980                         return service->proxy;
4981
4982                 return service->proxy_config;
4983         }
4984
4985         return service->proxy;
4986 }
4987
4988 char **connman_service_get_proxy_servers(struct connman_service *service)
4989 {
4990         return g_strdupv(service->proxies);
4991 }
4992
4993 char **connman_service_get_proxy_excludes(struct connman_service *service)
4994 {
4995         return g_strdupv(service->excludes);
4996 }
4997
4998 const char *connman_service_get_proxy_url(struct connman_service *service)
4999 {
5000         if (!service)
5001                 return NULL;
5002
5003         return service->pac;
5004 }
5005
5006 #if defined TIZEN_EXT
5007 void connman_service_set_internet_connection(struct connman_service *service,
5008                                                         bool internet_connection)
5009 {
5010         if (!service)
5011                 return;
5012
5013         if (service->is_internet_connection != internet_connection) {
5014                 service->is_internet_connection = internet_connection;
5015
5016                 g_get_current_time(&service->modified);
5017                 service_save(service);
5018         }
5019 }
5020
5021 bool connman_service_get_internet_connection(struct connman_service *service)
5022 {
5023         if (!service)
5024                 return false;
5025
5026         return service->is_internet_connection;
5027 }
5028
5029 DBusMessage *connman_service_create_dbus_service_reply(DBusMessage *msg,
5030                                                         struct connman_service *service)
5031 {
5032         DBusMessage *reply;
5033         DBusMessageIter array, dict;
5034
5035         reply = dbus_message_new_method_return(msg);
5036         if (!reply)
5037                 return NULL;
5038
5039         dbus_message_iter_init_append(reply, &array);
5040
5041         if (service)
5042                 dbus_message_iter_append_basic(&array, DBUS_TYPE_OBJECT_PATH,
5043                                                                 &service->path);
5044
5045         connman_dbus_dict_open(&array, &dict);
5046         if (service)
5047                 append_properties(&dict, FALSE, service);
5048         connman_dbus_dict_close(&array, &dict);
5049
5050         return reply;
5051 }
5052 #endif
5053
5054 void __connman_service_set_proxy_autoconfig(struct connman_service *service,
5055                                                         const char *url)
5056 {
5057         if (!service || service->hidden)
5058                 return;
5059
5060         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_AUTO;
5061
5062         if (service->ipconfig_ipv4) {
5063                 if (__connman_ipconfig_set_proxy_autoconfig(
5064                             service->ipconfig_ipv4, url) < 0)
5065                         return;
5066         } else if (service->ipconfig_ipv6) {
5067                 if (__connman_ipconfig_set_proxy_autoconfig(
5068                             service->ipconfig_ipv6, url) < 0)
5069                         return;
5070         } else
5071                 return;
5072
5073         proxy_changed(service);
5074
5075         __connman_notifier_proxy_changed(service);
5076 }
5077
5078 const char *connman_service_get_proxy_autoconfig(struct connman_service *service)
5079 {
5080         if (!service)
5081                 return NULL;
5082
5083         if (service->ipconfig_ipv4)
5084                 return __connman_ipconfig_get_proxy_autoconfig(
5085                                                 service->ipconfig_ipv4);
5086         else if (service->ipconfig_ipv6)
5087                 return __connman_ipconfig_get_proxy_autoconfig(
5088                                                 service->ipconfig_ipv6);
5089         return NULL;
5090 }
5091
5092 #if defined TIZEN_EXT
5093 int connman_service_get_ipv6_dns_method(struct connman_service *service)
5094 {
5095         if (!service) {
5096                 DBG("Service is NULL");
5097                 return -1;
5098         }
5099
5100         return service->dns_config_method_ipv6;
5101 }
5102 #endif
5103
5104 void __connman_service_set_timeservers(struct connman_service *service,
5105                                 char **timeservers)
5106 {
5107         int i;
5108
5109         if (!service)
5110                 return;
5111
5112         g_strfreev(service->timeservers);
5113         service->timeservers = NULL;
5114
5115         for (i = 0; timeservers && timeservers[i]; i++)
5116                 __connman_service_timeserver_append(service, timeservers[i]);
5117 }
5118
5119 int __connman_service_timeserver_append(struct connman_service *service,
5120                                                 const char *timeserver)
5121 {
5122         int len;
5123
5124         DBG("service %p timeserver %s", service, timeserver);
5125
5126         if (!timeserver)
5127                 return -EINVAL;
5128
5129         if (service->timeservers) {
5130                 int i;
5131
5132                 for (i = 0; service->timeservers[i]; i++)
5133                         if (g_strcmp0(service->timeservers[i], timeserver) == 0)
5134                                 return -EEXIST;
5135
5136                 len = g_strv_length(service->timeservers);
5137                 service->timeservers = g_try_renew(char *, service->timeservers,
5138                                                         len + 2);
5139         } else {
5140                 len = 0;
5141                 service->timeservers = g_try_new0(char *, len + 2);
5142         }
5143
5144         if (!service->timeservers)
5145                 return -ENOMEM;
5146
5147         service->timeservers[len] = g_strdup(timeserver);
5148         service->timeservers[len + 1] = NULL;
5149
5150         return 0;
5151 }
5152
5153 int __connman_service_timeserver_remove(struct connman_service *service,
5154                                                 const char *timeserver)
5155 {
5156         char **servers;
5157         int len, i, j, found = 0;
5158
5159         DBG("service %p timeserver %s", service, timeserver);
5160
5161         if (!timeserver)
5162                 return -EINVAL;
5163
5164         if (!service->timeservers)
5165                 return 0;
5166
5167         for (i = 0; service->timeservers &&
5168                                         service->timeservers[i]; i++)
5169                 if (g_strcmp0(service->timeservers[i], timeserver) == 0) {
5170                         found = 1;
5171                         break;
5172                 }
5173
5174         if (found == 0)
5175                 return 0;
5176
5177         len = g_strv_length(service->timeservers);
5178
5179         if (len == 1) {
5180                 g_strfreev(service->timeservers);
5181                 service->timeservers = NULL;
5182
5183                 return 0;
5184         }
5185
5186         servers = g_try_new0(char *, len);
5187         if (!servers)
5188                 return -ENOMEM;
5189
5190         for (i = 0, j = 0; i < len; i++) {
5191                 if (g_strcmp0(service->timeservers[i], timeserver) != 0) {
5192                         servers[j] = g_strdup(service->timeservers[i]);
5193                         if (!servers[j])
5194                                 return -ENOMEM;
5195                         j++;
5196                 }
5197         }
5198         servers[len - 1] = NULL;
5199
5200         g_strfreev(service->timeservers);
5201         service->timeservers = servers;
5202
5203         return 0;
5204 }
5205
5206 void __connman_service_timeserver_changed(struct connman_service *service,
5207                 GSList *ts_list)
5208 {
5209         if (!service)
5210                 return;
5211
5212         if (!allow_property_changed(service))
5213                 return;
5214
5215         connman_dbus_property_changed_array(service->path,
5216                         CONNMAN_SERVICE_INTERFACE, "Timeservers",
5217                         DBUS_TYPE_STRING, append_ts, ts_list);
5218 }
5219
5220 void __connman_service_set_pac(struct connman_service *service,
5221                                         const char *pac)
5222 {
5223         if (service->hidden)
5224                 return;
5225         g_free(service->pac);
5226         service->pac = g_strdup(pac);
5227
5228         proxy_changed(service);
5229 }
5230
5231 #if defined TIZEN_EXT
5232 void __connman_service_set_proxy(struct connman_service *service,
5233                                        const char *proxies)
5234 {
5235        char **proxies_array = NULL;
5236
5237        g_strfreev(service->proxies);
5238        service->proxies = NULL;
5239
5240        if (proxies != NULL)
5241                proxies_array = g_strsplit(proxies, " ", 0);
5242
5243        service->proxies = proxies_array;
5244 }
5245 #endif
5246
5247 void __connman_service_set_identity(struct connman_service *service,
5248                                         const char *identity)
5249 {
5250         if (service->immutable || service->hidden)
5251                 return;
5252
5253         g_free(service->identity);
5254         service->identity = g_strdup(identity);
5255
5256         if (service->network)
5257                 connman_network_set_string(service->network,
5258                                         "WiFi.Identity",
5259                                         service->identity);
5260 }
5261
5262 void __connman_service_set_anonymous_identity(struct connman_service *service,
5263                                                 const char *anonymous_identity)
5264 {
5265         if (service->immutable || service->hidden)
5266                 return;
5267
5268         g_free(service->anonymous_identity);
5269         service->anonymous_identity = g_strdup(anonymous_identity);
5270
5271         if (service->network)
5272                 connman_network_set_string(service->network,
5273                                         "WiFi.AnonymousIdentity",
5274                                         service->anonymous_identity);
5275 }
5276
5277 void __connman_service_set_subject_match(struct connman_service *service,
5278                                                 const char *subject_match)
5279 {
5280         if (service->immutable || service->hidden)
5281                 return;
5282
5283         g_free(service->subject_match);
5284         service->subject_match = g_strdup(subject_match);
5285
5286         if (service->network)
5287                 connman_network_set_string(service->network,
5288                                         "WiFi.SubjectMatch",
5289                                         service->subject_match);
5290 }
5291
5292 void __connman_service_set_altsubject_match(struct connman_service *service,
5293                                                 const char *altsubject_match)
5294 {
5295         if (service->immutable || service->hidden)
5296                 return;
5297
5298         g_free(service->altsubject_match);
5299         service->altsubject_match = g_strdup(altsubject_match);
5300
5301         if (service->network)
5302                 connman_network_set_string(service->network,
5303                                         "WiFi.AltSubjectMatch",
5304                                         service->altsubject_match);
5305 }
5306
5307 void __connman_service_set_domain_suffix_match(struct connman_service *service,
5308                                                 const char *domain_suffix_match)
5309 {
5310         if (service->immutable || service->hidden)
5311                 return;
5312
5313         g_free(service->domain_suffix_match);
5314         service->domain_suffix_match = g_strdup(domain_suffix_match);
5315
5316         if (service->network)
5317                 connman_network_set_string(service->network,
5318                                         "WiFi.DomainSuffixMatch",
5319                                         service->domain_suffix_match);
5320 }
5321
5322 void __connman_service_set_domain_match(struct connman_service *service,
5323                                                 const char *domain_match)
5324 {
5325         if (service->immutable || service->hidden)
5326                 return;
5327
5328         g_free(service->domain_match);
5329         service->domain_match = g_strdup(domain_match);
5330
5331         if (service->network)
5332                 connman_network_set_string(service->network,
5333                                         "WiFi.DomainMatch",
5334                                         service->domain_match);
5335 }
5336
5337 void __connman_service_set_agent_identity(struct connman_service *service,
5338                                                 const char *agent_identity)
5339 {
5340         if (service->hidden)
5341                 return;
5342         g_free(service->agent_identity);
5343         service->agent_identity = g_strdup(agent_identity);
5344
5345         if (service->network)
5346                 connman_network_set_string(service->network,
5347                                         "WiFi.AgentIdentity",
5348                                         service->agent_identity);
5349 }
5350
5351 int __connman_service_check_passphrase(enum connman_service_security security,
5352                 const char *passphrase)
5353 {
5354         guint i;
5355         gsize length;
5356
5357         if (!passphrase)
5358                 return 0;
5359
5360         length = strlen(passphrase);
5361
5362         switch (security) {
5363         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
5364         case CONNMAN_SERVICE_SECURITY_NONE:
5365         case CONNMAN_SERVICE_SECURITY_WPA:
5366 #if !defined TIZEN_EXT
5367         case CONNMAN_SERVICE_SECURITY_RSN:
5368 #endif
5369
5370                 DBG("service security '%s' (%d) not handled",
5371                                 security2string(security), security);
5372
5373                 return -EOPNOTSUPP;
5374
5375         case CONNMAN_SERVICE_SECURITY_PSK:
5376 #if defined TIZEN_EXT
5377         case CONNMAN_SERVICE_SECURITY_RSN:
5378         /* TO CHECK: We need to check the key length supported by SAE */
5379         case CONNMAN_SERVICE_SECURITY_SAE:
5380 #endif
5381                 /* A raw key is always 64 bytes length,
5382                  * its content is in hex representation.
5383                  * A PSK key must be between [8..63].
5384                  */
5385                 if (length == 64) {
5386                         for (i = 0; i < 64; i++)
5387                                 if (!isxdigit((unsigned char)
5388                                               passphrase[i]))
5389                                         return -ENOKEY;
5390                 } else if (length < 8 || length > 63)
5391                         return -ENOKEY;
5392                 break;
5393         case CONNMAN_SERVICE_SECURITY_WEP:
5394                 /* length of WEP key is 10 or 26
5395                  * length of WEP passphrase is 5 or 13
5396                  */
5397                 if (length == 10 || length == 26) {
5398                         for (i = 0; i < length; i++)
5399                                 if (!isxdigit((unsigned char)
5400                                               passphrase[i]))
5401                                         return -ENOKEY;
5402                 } else if (length != 5 && length != 13)
5403                         return -ENOKEY;
5404                 break;
5405
5406         case CONNMAN_SERVICE_SECURITY_8021X:
5407 #if defined TIZEN_EXT
5408         case CONNMAN_SERVICE_SECURITY_OWE:
5409         case CONNMAN_SERVICE_SECURITY_DPP:
5410 #endif
5411                 break;
5412         }
5413
5414         return 0;
5415 }
5416
5417 int __connman_service_set_passphrase(struct connman_service *service,
5418                                         const char *passphrase)
5419 {
5420         int err;
5421
5422         if (service->hidden)
5423                 return -EINVAL;
5424
5425         if (service->immutable &&
5426                         service->security != CONNMAN_SERVICE_SECURITY_8021X)
5427                 return -EINVAL;
5428
5429 #if defined TIZEN_EXT
5430         if (service->immutable &&
5431                         service->security != CONNMAN_SERVICE_SECURITY_DPP)
5432                 return -EINVAL;
5433         /* The encrypted passphrase is used here
5434          * and validation is done by net-config before being encrypted.
5435          */
5436         err = 0;
5437         if (service->security != CONNMAN_SERVICE_SECURITY_PSK &&
5438                         service->security != CONNMAN_SERVICE_SECURITY_RSN &&
5439                         service->security != CONNMAN_SERVICE_SECURITY_SAE &&
5440                         service->security != CONNMAN_SERVICE_SECURITY_WEP)
5441 #endif
5442         err = __connman_service_check_passphrase(service->security, passphrase);
5443
5444         if (err < 0)
5445                 return err;
5446
5447         g_free(service->passphrase);
5448         service->passphrase = g_strdup(passphrase);
5449
5450         if (service->network)
5451                 connman_network_set_string(service->network, "WiFi.Passphrase",
5452                                 service->passphrase);
5453
5454         return 0;
5455 }
5456
5457 const char *__connman_service_get_passphrase(struct connman_service *service)
5458 {
5459         if (!service)
5460                 return NULL;
5461
5462         return service->passphrase;
5463 }
5464
5465 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
5466 int __connman_service_get_use_eapol(struct connman_service *service)
5467 {
5468         if (!service) {
5469                 DBG("Service is NULL");
5470                 return -1;
5471         }
5472
5473         return service->use_eapol;
5474 }
5475
5476 int __connman_service_get_connect_reason(struct connman_service *service)
5477 {
5478         if (!service) {
5479                 DBG("Service is NULL");
5480                 return -1;
5481         }
5482
5483         return service->connect_reason;
5484 }
5485 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
5486
5487 static DBusMessage *get_properties(DBusConnection *conn,
5488                                         DBusMessage *msg, void *user_data)
5489 {
5490         struct connman_service *service = user_data;
5491         DBusMessage *reply;
5492         DBusMessageIter array, dict;
5493
5494         reply = dbus_message_new_method_return(msg);
5495         if (!reply)
5496                 return NULL;
5497
5498         dbus_message_iter_init_append(reply, &array);
5499
5500         connman_dbus_dict_open(&array, &dict);
5501         append_properties(&dict, FALSE, service);
5502         connman_dbus_dict_close(&array, &dict);
5503
5504         return reply;
5505 }
5506
5507 static char **remove_empty_strings(char **strv)
5508 {
5509         int index = 0;
5510         char **iter = strv;
5511
5512         while (*iter) {
5513                 if (**iter)
5514                         strv[index++] = *iter;
5515                 else
5516                         g_free(*iter);
5517                 iter++;
5518         }
5519
5520         strv[index] = NULL;
5521         return strv;
5522 }
5523
5524 static int update_proxy_configuration(struct connman_service *service,
5525                                 DBusMessageIter *array)
5526 {
5527         DBusMessageIter dict;
5528         enum connman_service_proxy_method method;
5529         GString *servers_str = NULL;
5530         GString *excludes_str = NULL;
5531         const char *url = NULL;
5532
5533         method = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
5534
5535         dbus_message_iter_recurse(array, &dict);
5536
5537         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
5538                 DBusMessageIter entry, variant;
5539                 const char *key;
5540                 int type;
5541
5542                 dbus_message_iter_recurse(&dict, &entry);
5543
5544                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
5545                         goto error;
5546
5547                 dbus_message_iter_get_basic(&entry, &key);
5548                 dbus_message_iter_next(&entry);
5549
5550                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
5551                         goto error;
5552
5553                 dbus_message_iter_recurse(&entry, &variant);
5554
5555                 type = dbus_message_iter_get_arg_type(&variant);
5556
5557                 if (g_str_equal(key, "Method")) {
5558                         const char *val;
5559
5560                         if (type != DBUS_TYPE_STRING)
5561                                 goto error;
5562
5563                         dbus_message_iter_get_basic(&variant, &val);
5564                         method = string2proxymethod(val);
5565                 } else if (g_str_equal(key, "URL")) {
5566                         if (type != DBUS_TYPE_STRING)
5567                                 goto error;
5568
5569                         dbus_message_iter_get_basic(&variant, &url);
5570                 } else if (g_str_equal(key, "Servers")) {
5571                         DBusMessageIter str_array;
5572
5573                         if (type != DBUS_TYPE_ARRAY)
5574                                 goto error;
5575
5576                         servers_str = g_string_new(NULL);
5577                         if (!servers_str)
5578                                 goto error;
5579
5580                         dbus_message_iter_recurse(&variant, &str_array);
5581
5582                         while (dbus_message_iter_get_arg_type(&str_array) ==
5583                                                         DBUS_TYPE_STRING) {
5584                                 char *val = NULL;
5585
5586                                 dbus_message_iter_get_basic(&str_array, &val);
5587
5588                                 if (servers_str->len > 0)
5589                                         g_string_append_printf(servers_str,
5590                                                         " %s", val);
5591                                 else
5592                                         g_string_append(servers_str, val);
5593
5594                                 dbus_message_iter_next(&str_array);
5595                         }
5596                 } else if (g_str_equal(key, "Excludes")) {
5597                         DBusMessageIter str_array;
5598
5599                         if (type != DBUS_TYPE_ARRAY)
5600                                 goto error;
5601
5602                         excludes_str = g_string_new(NULL);
5603                         if (!excludes_str)
5604                                 goto error;
5605
5606                         dbus_message_iter_recurse(&variant, &str_array);
5607
5608                         while (dbus_message_iter_get_arg_type(&str_array) ==
5609                                                         DBUS_TYPE_STRING) {
5610                                 char *val = NULL;
5611
5612                                 dbus_message_iter_get_basic(&str_array, &val);
5613
5614                                 if (excludes_str->len > 0)
5615                                         g_string_append_printf(excludes_str,
5616                                                         " %s", val);
5617                                 else
5618                                         g_string_append(excludes_str, val);
5619
5620                                 dbus_message_iter_next(&str_array);
5621                         }
5622                 }
5623
5624                 dbus_message_iter_next(&dict);
5625         }
5626
5627         switch (method) {
5628         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
5629                 break;
5630         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
5631                 if (!servers_str && !service->proxies)
5632                         goto error;
5633
5634                 if (servers_str) {
5635                         g_strfreev(service->proxies);
5636
5637                         if (servers_str->len > 0) {
5638                                 char **proxies = g_strsplit_set(
5639                                         servers_str->str, " ", 0);
5640                                 proxies = remove_empty_strings(proxies);
5641                                 service->proxies = proxies;
5642                         } else
5643                                 service->proxies = NULL;
5644                 }
5645
5646                 if (excludes_str) {
5647                         g_strfreev(service->excludes);
5648
5649                         if (excludes_str->len > 0) {
5650                                 char **excludes = g_strsplit_set(
5651                                         excludes_str->str, " ", 0);
5652                                 excludes = remove_empty_strings(excludes);
5653                                 service->excludes = excludes;
5654                         } else
5655                                 service->excludes = NULL;
5656                 }
5657
5658                 if (!service->proxies)
5659                         method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
5660
5661                 break;
5662         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
5663                 g_free(service->pac);
5664
5665                 if (url && strlen(url) > 0)
5666                         service->pac = g_strstrip(g_strdup(url));
5667                 else
5668                         service->pac = NULL;
5669
5670                 /* if we are connected:
5671                    - if service->pac == NULL
5672                    - if __connman_ipconfig_get_proxy_autoconfig(
5673                    service->ipconfig) == NULL
5674                    --> We should start WPAD */
5675
5676                 break;
5677         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
5678                 goto error;
5679         }
5680
5681         if (servers_str)
5682                 g_string_free(servers_str, TRUE);
5683
5684         if (excludes_str)
5685                 g_string_free(excludes_str, TRUE);
5686
5687         service->proxy_config = method;
5688
5689         return 0;
5690
5691 error:
5692         if (servers_str)
5693                 g_string_free(servers_str, TRUE);
5694
5695         if (excludes_str)
5696                 g_string_free(excludes_str, TRUE);
5697
5698         return -EINVAL;
5699 }
5700
5701 static void do_auto_connect(struct connman_service *service,
5702         enum connman_service_connect_reason reason)
5703 {
5704         /*
5705          * CONNMAN_SERVICE_CONNECT_REASON_NONE must be ignored for VPNs. VPNs
5706          * always have reason CONNMAN_SERVICE_CONNECT_REASON_USER/AUTO.
5707          */
5708         if (!service || (service->type == CONNMAN_SERVICE_TYPE_VPN &&
5709                                 reason == CONNMAN_SERVICE_CONNECT_REASON_NONE))
5710                 return;
5711
5712         /*
5713          * Run service auto connect for other than VPN services. Afterwards
5714          * start also VPN auto connect process.
5715          */
5716         if (service->type != CONNMAN_SERVICE_TYPE_VPN)
5717                 __connman_service_auto_connect(reason);
5718         /* Only user interaction should get VPN connected in failure state. */
5719         else if (service->state == CONNMAN_SERVICE_STATE_FAILURE &&
5720                                 reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
5721                 return;
5722
5723         vpn_auto_connect();
5724 }
5725
5726 int __connman_service_reset_ipconfig(struct connman_service *service,
5727                 enum connman_ipconfig_type type, DBusMessageIter *array,
5728                 enum connman_service_state *new_state)
5729 {
5730         struct connman_ipconfig *ipconfig, *new_ipconfig;
5731         enum connman_ipconfig_method old_method, new_method;
5732         enum connman_service_state state;
5733         int err = 0, index;
5734
5735         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
5736                 ipconfig = service->ipconfig_ipv4;
5737                 state = service->state_ipv4;
5738                 new_method = CONNMAN_IPCONFIG_METHOD_DHCP;
5739         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
5740                 ipconfig = service->ipconfig_ipv6;
5741                 state = service->state_ipv6;
5742                 new_method = CONNMAN_IPCONFIG_METHOD_AUTO;
5743         } else
5744                 return -EINVAL;
5745
5746         if (!ipconfig)
5747                 return -ENXIO;
5748
5749         old_method = __connman_ipconfig_get_method(ipconfig);
5750         index = __connman_ipconfig_get_index(ipconfig);
5751
5752         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
5753                 new_ipconfig = create_ip4config(service, index,
5754                                 CONNMAN_IPCONFIG_METHOD_UNKNOWN);
5755         else
5756                 new_ipconfig = create_ip6config(service, index);
5757
5758         if (array) {
5759                 err = __connman_ipconfig_set_config(new_ipconfig, array);
5760                 if (err < 0) {
5761                         __connman_ipconfig_unref(new_ipconfig);
5762                         return err;
5763                 }
5764
5765                 new_method = __connman_ipconfig_get_method(new_ipconfig);
5766         }
5767
5768         if (is_connecting(state) || is_connected(state))
5769                 __connman_network_clear_ipconfig(service->network, ipconfig);
5770
5771         __connman_ipconfig_unref(ipconfig);
5772
5773         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
5774                 service->ipconfig_ipv4 = new_ipconfig;
5775         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
5776                 service->ipconfig_ipv6 = new_ipconfig;
5777
5778         if (is_connecting(state) || is_connected(state))
5779                 __connman_ipconfig_enable(new_ipconfig);
5780
5781         if (new_state && new_method != old_method) {
5782                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
5783                         *new_state = service->state_ipv4;
5784                 else
5785                         *new_state = service->state_ipv6;
5786
5787                 settings_changed(service, new_ipconfig);
5788                 address_updated(service, type);
5789
5790                 do_auto_connect(service, CONNMAN_SERVICE_CONNECT_REASON_AUTO);
5791         }
5792
5793         DBG("err %d ipconfig %p type %d method %d state %s", err,
5794                 new_ipconfig, type, new_method,
5795                 !new_state  ? "-" : state2string(*new_state));
5796
5797         return err;
5798 }
5799
5800 /*
5801  * We set the timeout to 1 sec so that we have a chance to get
5802  * necessary IPv6 router advertisement messages that might have
5803  * DNS data etc.
5804  */
5805 #define ONLINE_CHECK_INITIAL_INTERVAL 1
5806 #define ONLINE_CHECK_MAX_INTERVAL 12
5807
5808 void __connman_service_wispr_start(struct connman_service *service,
5809                                         enum connman_ipconfig_type type)
5810 {
5811         DBG("service %p type %s", service, __connman_ipconfig_type2string(type));
5812
5813         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
5814                 service->online_check_interval_ipv4 =
5815                                         ONLINE_CHECK_INITIAL_INTERVAL;
5816         else
5817                 service->online_check_interval_ipv6 =
5818                                         ONLINE_CHECK_INITIAL_INTERVAL;
5819
5820         __connman_wispr_start(service, type);
5821 }
5822
5823 static void set_error(struct connman_service *service,
5824                                         enum connman_service_error error);
5825
5826 static DBusMessage *set_property(DBusConnection *conn,
5827                                         DBusMessage *msg, void *user_data)
5828 {
5829         struct connman_service *service = user_data;
5830         DBusMessageIter iter, value;
5831         const char *name;
5832         int type;
5833
5834         DBG("service %p", service);
5835
5836         if (!dbus_message_iter_init(msg, &iter))
5837                 return __connman_error_invalid_arguments(msg);
5838
5839         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
5840                 return __connman_error_invalid_arguments(msg);
5841
5842         dbus_message_iter_get_basic(&iter, &name);
5843         dbus_message_iter_next(&iter);
5844
5845         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
5846                 return __connman_error_invalid_arguments(msg);
5847
5848         dbus_message_iter_recurse(&iter, &value);
5849
5850         type = dbus_message_iter_get_arg_type(&value);
5851
5852         if (g_str_equal(name, "AutoConnect")) {
5853                 dbus_bool_t autoconnect;
5854
5855                 if (type != DBUS_TYPE_BOOLEAN)
5856                         return __connman_error_invalid_arguments(msg);
5857
5858                 if (!service->favorite)
5859                         return __connman_error_invalid_service(msg);
5860
5861                 dbus_message_iter_get_basic(&value, &autoconnect);
5862
5863                 if (autoconnect && service->type == CONNMAN_SERVICE_TYPE_VPN) {
5864                         /*
5865                          * Changing the autoconnect flag on VPN to "on" should
5866                          * have the same effect as user connecting the VPN =
5867                          * clear previous error and change state to idle.
5868                          */
5869                         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
5870
5871                         if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
5872                                 service->state = CONNMAN_SERVICE_STATE_IDLE;
5873                                 state_changed(service);
5874                         }
5875                 }
5876
5877                 if (connman_service_set_autoconnect(service, autoconnect)) {
5878                         service_save(service);
5879                         if (autoconnect)
5880                                 do_auto_connect(service,
5881                                         CONNMAN_SERVICE_CONNECT_REASON_AUTO);
5882                 }
5883         } else if (g_str_equal(name, "Nameservers.Configuration")) {
5884                 DBusMessageIter entry;
5885                 GString *str;
5886                 int index;
5887                 const char *gw;
5888 #if defined TIZEN_EXT
5889                 enum connman_ipconfig_type ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
5890                 DBG("%s", name);
5891 #endif
5892
5893                 if (__connman_provider_is_immutable(service->provider) ||
5894                                 service->immutable)
5895                         return __connman_error_not_supported(msg);
5896
5897                 if (type != DBUS_TYPE_ARRAY)
5898                         return __connman_error_invalid_arguments(msg);
5899
5900                 str = g_string_new(NULL);
5901                 if (!str)
5902                         return __connman_error_invalid_arguments(msg);
5903
5904                 index = __connman_service_get_index(service);
5905                 gw = __connman_ipconfig_get_gateway_from_index(index,
5906                         CONNMAN_IPCONFIG_TYPE_ALL);
5907
5908 #if !defined TIZEN_EXT
5909                 if (gw && strlen(gw))
5910                         __connman_service_nameserver_del_routes(service,
5911                                                 CONNMAN_IPCONFIG_TYPE_ALL);
5912
5913 #endif
5914                 dbus_message_iter_recurse(&value, &entry);
5915
5916 #if defined TIZEN_EXT
5917                 /* IPv4/IPv6 Last DNS config method */
5918                 int last_dns_ipv4 = service->dns_config_method_ipv4;
5919                 int last_dns_ipv6 = service->dns_config_method_ipv6;
5920                 DBG("Last DNS Config Method IPv4: %d IPv6: %d", last_dns_ipv4, last_dns_ipv6);
5921 #endif
5922
5923                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
5924                         const char *val;
5925                         dbus_message_iter_get_basic(&entry, &val);
5926                         dbus_message_iter_next(&entry);
5927 #ifdef TIZEN_EXT
5928                         /* First unpack the DNS Config Method */
5929                         DBG("DNS Config Method: %s", val);
5930                         if((g_strcmp0(val, "ipv4.manual") == 0)) {
5931                                 service->dns_config_method_ipv4 =
5932                                         CONNMAN_DNSCONFIG_METHOD_MANUAL;
5933
5934                                 if(last_dns_ipv4 != CONNMAN_DNSCONFIG_METHOD_MANUAL) {
5935                                         if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN)
5936                                                 ip_type = CONNMAN_IPCONFIG_TYPE_IPV4;
5937                                         else
5938                                                 ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
5939                                 }
5940                                 continue;
5941                         } else if(g_strcmp0(val, "ipv4.dhcp") == 0) {
5942                                 service->dns_config_method_ipv4 =
5943                                         CONNMAN_DNSCONFIG_METHOD_DHCP;
5944                                 if(last_dns_ipv4 == CONNMAN_DNSCONFIG_METHOD_MANUAL)
5945                                         ip_type = CONNMAN_IPCONFIG_TYPE_IPV4;
5946
5947                                 continue;
5948                         } else if(g_strcmp0(val, "ipv6.manual") == 0) {
5949                                 service->dns_config_method_ipv6 =
5950                                         CONNMAN_DNSCONFIG_METHOD_MANUAL;
5951                                 if(last_dns_ipv6 != CONNMAN_DNSCONFIG_METHOD_MANUAL) {
5952                                         if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN)
5953                                                 ip_type = CONNMAN_IPCONFIG_TYPE_IPV6;
5954                                         else
5955                                                 ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
5956                                 }
5957                                 continue;
5958                         } else if(g_strcmp0(val, "ipv6.dhcp") == 0) {
5959                                 service->dns_config_method_ipv6 =
5960                                         CONNMAN_DNSCONFIG_METHOD_DHCP;
5961                                 if(last_dns_ipv6 == CONNMAN_DNSCONFIG_METHOD_MANUAL)
5962                                         ip_type = CONNMAN_IPCONFIG_TYPE_IPV6;
5963
5964                                 continue;
5965                         }
5966 #endif
5967                         if (!val[0])
5968                                 continue;
5969
5970                         if (str->len > 0)
5971                                 g_string_append_printf(str, " %s", val);
5972                         else
5973                                 g_string_append(str, val);
5974                 }
5975
5976 #if defined TIZEN_EXT
5977                 if (service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_DHCP &&
5978                         service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_DHCP) {
5979                                         DBG("Both IPv4 and IPv6 DNS Method DHCP");
5980                                         ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
5981                 }
5982                 if (gw && strlen(gw))
5983                         __connman_service_nameserver_del_routes(service,
5984                                                 ip_type);
5985
5986                 DBG("%s ip_type: %d nameserver remove all", name, ip_type);
5987                 nameserver_remove_all(service, ip_type);
5988 #else
5989                 nameserver_remove_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
5990 #endif
5991                 g_strfreev(service->nameservers_config);
5992
5993                 if (str->len > 0) {
5994                         char **nameservers, **iter;
5995
5996                         nameservers = g_strsplit_set(str->str, " ", 0);
5997
5998                         for (iter = nameservers; *iter; iter++)
5999                                 if (connman_inet_check_ipaddress(*iter) <= 0)
6000                                         *iter[0] = '\0';
6001
6002                         nameservers = remove_empty_strings(nameservers);
6003                         service->nameservers_config = nameservers;
6004                 } else {
6005                         service->nameservers_config = NULL;
6006                 }
6007
6008                 g_string_free(str, TRUE);
6009
6010                 if (gw && strlen(gw))
6011                         __connman_service_nameserver_add_routes(service, gw);
6012
6013 #if defined TIZEN_EXT
6014                 DBG("%s ip_type: %d nameserver add all", name, ip_type);
6015                 nameserver_add_all(service, ip_type);
6016 #else
6017                 nameserver_add_all(service, CONNMAN_IPCONFIG_TYPE_ALL);
6018 #endif
6019                 dns_configuration_changed(service);
6020
6021                 if (__connman_service_is_connected_state(service,
6022                                                 CONNMAN_IPCONFIG_TYPE_IPV4))
6023                         __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
6024
6025                 if (__connman_service_is_connected_state(service,
6026                                                 CONNMAN_IPCONFIG_TYPE_IPV6))
6027                         __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
6028
6029                 service_save(service);
6030         } else if (g_str_equal(name, "Timeservers.Configuration")) {
6031                 DBusMessageIter entry;
6032                 GString *str;
6033
6034                 if (service->immutable)
6035                         return __connman_error_not_supported(msg);
6036
6037                 if (type != DBUS_TYPE_ARRAY)
6038                         return __connman_error_invalid_arguments(msg);
6039
6040                 str = g_string_new(NULL);
6041                 if (!str)
6042                         return __connman_error_invalid_arguments(msg);
6043
6044                 dbus_message_iter_recurse(&value, &entry);
6045
6046                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
6047                         const char *val;
6048                         dbus_message_iter_get_basic(&entry, &val);
6049                         dbus_message_iter_next(&entry);
6050
6051                         if (!val[0])
6052                                 continue;
6053
6054                         if (str->len > 0)
6055                                 g_string_append_printf(str, " %s", val);
6056                         else
6057                                 g_string_append(str, val);
6058                 }
6059
6060                 g_strfreev(service->timeservers_config);
6061                 service->timeservers_config = NULL;
6062
6063                 if (str->len > 0) {
6064                         char **timeservers = g_strsplit_set(str->str, " ", 0);
6065                         timeservers = remove_empty_strings(timeservers);
6066                         service->timeservers_config = timeservers;
6067                 }
6068
6069                 g_string_free(str, TRUE);
6070
6071                 service_save(service);
6072                 timeservers_configuration_changed(service);
6073
6074                 if (service == connman_service_get_default())
6075                         __connman_timeserver_sync(service);
6076
6077         } else if (g_str_equal(name, "Domains.Configuration")) {
6078                 DBusMessageIter entry;
6079                 GString *str;
6080
6081                 if (service->immutable)
6082                         return __connman_error_not_supported(msg);
6083
6084                 if (type != DBUS_TYPE_ARRAY)
6085                         return __connman_error_invalid_arguments(msg);
6086
6087                 str = g_string_new(NULL);
6088                 if (!str)
6089                         return __connman_error_invalid_arguments(msg);
6090
6091                 dbus_message_iter_recurse(&value, &entry);
6092
6093                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
6094                         const char *val;
6095                         dbus_message_iter_get_basic(&entry, &val);
6096                         dbus_message_iter_next(&entry);
6097
6098                         if (!val[0])
6099                                 continue;
6100
6101                         if (str->len > 0)
6102                                 g_string_append_printf(str, " %s", val);
6103                         else
6104                                 g_string_append(str, val);
6105                 }
6106
6107                 searchdomain_remove_all(service);
6108                 g_strfreev(service->domains);
6109
6110                 if (str->len > 0) {
6111                         char **domains = g_strsplit_set(str->str, " ", 0);
6112                         domains = remove_empty_strings(domains);
6113                         service->domains = domains;
6114                 } else
6115                         service->domains = NULL;
6116
6117                 g_string_free(str, TRUE);
6118
6119                 searchdomain_add_all(service);
6120                 domain_configuration_changed(service);
6121                 domain_changed(service);
6122
6123                 service_save(service);
6124         } else if (g_str_equal(name, "Proxy.Configuration")) {
6125                 int err;
6126
6127                 if (service->immutable)
6128                         return __connman_error_not_supported(msg);
6129
6130                 if (type != DBUS_TYPE_ARRAY)
6131                         return __connman_error_invalid_arguments(msg);
6132
6133                 err = update_proxy_configuration(service, &value);
6134
6135                 if (err < 0)
6136                         return __connman_error_failed(msg, -err);
6137
6138                 proxy_configuration_changed(service);
6139
6140                 __connman_notifier_proxy_changed(service);
6141
6142                 service_save(service);
6143         } else if (g_str_equal(name, "mDNS.Configuration")) {
6144                 dbus_bool_t val;
6145
6146                 if (service->immutable)
6147                         return __connman_error_not_supported(msg);
6148
6149                 if (type != DBUS_TYPE_BOOLEAN)
6150                         return __connman_error_invalid_arguments(msg);
6151
6152                 dbus_message_iter_get_basic(&value, &val);
6153                 service->mdns_config = val;
6154
6155                 mdns_configuration_changed(service);
6156
6157                 set_mdns(service, service->mdns_config);
6158
6159                 service_save(service);
6160         } else if (g_str_equal(name, "IPv4.Configuration") ||
6161                         g_str_equal(name, "IPv6.Configuration")) {
6162
6163                 enum connman_service_state state =
6164                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
6165                 enum connman_ipconfig_type type =
6166                         CONNMAN_IPCONFIG_TYPE_UNKNOWN;
6167                 int err = 0;
6168
6169                 if (service->type == CONNMAN_SERVICE_TYPE_VPN ||
6170                                 service->immutable)
6171                         return __connman_error_not_supported(msg);
6172
6173                 DBG("%s", name);
6174
6175                 if (!service->ipconfig_ipv4 &&
6176                                         !service->ipconfig_ipv6)
6177                         return __connman_error_invalid_property(msg);
6178
6179                 if (g_str_equal(name, "IPv4.Configuration"))
6180                         type = CONNMAN_IPCONFIG_TYPE_IPV4;
6181                 else
6182                         type = CONNMAN_IPCONFIG_TYPE_IPV6;
6183
6184                 err = __connman_service_reset_ipconfig(service, type, &value,
6185                                                                 &state);
6186
6187                 if (err < 0) {
6188                         if (is_connected(state) || is_connecting(state)) {
6189                                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6190                                         __connman_network_enable_ipconfig(service->network,
6191                                                         service->ipconfig_ipv4);
6192                                 else
6193                                         __connman_network_enable_ipconfig(service->network,
6194                                                         service->ipconfig_ipv6);
6195                         }
6196
6197                         return __connman_error_failed(msg, -err);
6198                 }
6199
6200                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6201                         ipv4_configuration_changed(service);
6202                 else
6203                         ipv6_configuration_changed(service);
6204
6205                 if (is_connecting(service->state) ||
6206                                 is_connected(service->state)) {
6207                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6208                                 __connman_network_enable_ipconfig(service->network,
6209                                                                 service->ipconfig_ipv4);
6210                         else
6211                                 __connman_network_enable_ipconfig(service->network,
6212                                                                 service->ipconfig_ipv6);
6213                 }
6214
6215                 service_save(service);
6216 #if defined TIZEN_EXT
6217                 /* When AP is connected using WPS without SSID then its password needs
6218                  * to be saved for autoconnection */
6219         } else if (g_str_equal(name, "Passphrase")) {
6220                 char *passphrase;
6221
6222                 if (type != DBUS_TYPE_STRING)
6223                         return __connman_error_invalid_arguments(msg);
6224
6225                 dbus_message_iter_get_basic(&value, &passphrase);
6226
6227                 __connman_service_set_passphrase(service, passphrase);
6228 #endif
6229 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
6230         } else if (g_str_equal(name, "EapOverEthernet")) {
6231                 int err = connman_service_set_eapol_property(service, &value);
6232                 if (err < 0)
6233                         return __connman_error_failed(msg, -err);
6234
6235                 service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
6236                 service_save(service);
6237 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
6238         } else
6239                 return __connman_error_invalid_property(msg);
6240
6241         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
6242 }
6243
6244 static void set_error(struct connman_service *service,
6245                                         enum connman_service_error error)
6246 {
6247         const char *str;
6248
6249         if (service->error == error)
6250                 return;
6251
6252         service->error = error;
6253
6254         if (!service->path)
6255                 return;
6256
6257 #if !defined TIZEN_EXT
6258         if (!allow_property_changed(service))
6259                 return;
6260 #endif
6261
6262         str = error2string(service->error);
6263
6264         if (!str)
6265                 str = "";
6266
6267         connman_dbus_property_changed_basic(service->path,
6268                                 CONNMAN_SERVICE_INTERFACE, "Error",
6269                                 DBUS_TYPE_STRING, &str);
6270 }
6271
6272 static void remove_timeout(struct connman_service *service)
6273 {
6274         if (service->timeout > 0) {
6275                 g_source_remove(service->timeout);
6276                 service->timeout = 0;
6277         }
6278 }
6279
6280 static void reply_pending(struct connman_service *service, int error)
6281 {
6282         remove_timeout(service);
6283
6284         if (service->pending) {
6285                 connman_dbus_reply_pending(service->pending, error, NULL);
6286                 service->pending = NULL;
6287         }
6288
6289         if (service->provider_pending) {
6290                 connman_dbus_reply_pending(service->provider_pending,
6291                                 error, service->path);
6292                 service->provider_pending = NULL;
6293         }
6294 }
6295
6296 static void service_complete(struct connman_service *service)
6297 {
6298         reply_pending(service, EIO);
6299
6300         if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
6301                 do_auto_connect(service, service->connect_reason);
6302
6303         gettimeofday(&service->modified, NULL);
6304         service_save(service);
6305 }
6306
6307 static DBusMessage *clear_property(DBusConnection *conn,
6308                                         DBusMessage *msg, void *user_data)
6309 {
6310         struct connman_service *service = user_data;
6311         const char *name;
6312
6313         DBG("service %p", service);
6314
6315         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
6316                                                         DBUS_TYPE_INVALID);
6317
6318         if (g_str_equal(name, "Error")) {
6319                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6320
6321                 __connman_service_clear_error(service);
6322                 service_complete(service);
6323         } else
6324                 return __connman_error_invalid_property(msg);
6325
6326         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
6327 }
6328
6329 static bool is_ipconfig_usable(struct connman_service *service)
6330 {
6331         if (!__connman_ipconfig_is_usable(service->ipconfig_ipv4) &&
6332                         !__connman_ipconfig_is_usable(service->ipconfig_ipv6))
6333                 return false;
6334
6335         return true;
6336 }
6337
6338 static bool is_ignore(struct connman_service *service)
6339 {
6340         if (!service->autoconnect)
6341                 return true;
6342
6343         if (service->roaming &&
6344                 !connman_setting_get_bool("AutoConnectRoamingServices"))
6345                 return true;
6346
6347         if (service->ignore)
6348                 return true;
6349
6350         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
6351                 return true;
6352
6353         if (!is_ipconfig_usable(service))
6354                 return true;
6355
6356         return false;
6357 }
6358
6359 static void disconnect_on_last_session(enum connman_service_type type)
6360 {
6361         GList *list;
6362
6363         for (list = service_list; list; list = list->next) {
6364                 struct connman_service *service = list->data;
6365
6366                 if (service->type != type)
6367                         continue;
6368
6369                 if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_SESSION)
6370                          continue;
6371
6372                 __connman_service_disconnect(service);
6373                 return;
6374         }
6375 }
6376
6377 static int active_sessions[MAX_CONNMAN_SERVICE_TYPES] = {};
6378 static int always_connect[MAX_CONNMAN_SERVICE_TYPES] = {};
6379 static int active_count = 0;
6380
6381 void __connman_service_set_active_session(bool enable, GSList *list)
6382 {
6383         if (!list)
6384                 return;
6385
6386         if (enable)
6387                 active_count++;
6388         else
6389                 active_count--;
6390
6391         while (list) {
6392                 enum connman_service_type type = GPOINTER_TO_INT(list->data);
6393
6394                 switch (type) {
6395                 case CONNMAN_SERVICE_TYPE_ETHERNET:
6396                 case CONNMAN_SERVICE_TYPE_WIFI:
6397                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
6398                 case CONNMAN_SERVICE_TYPE_CELLULAR:
6399                 case CONNMAN_SERVICE_TYPE_GADGET:
6400                         if (enable)
6401                                 active_sessions[type]++;
6402                         else
6403                                 active_sessions[type]--;
6404                         break;
6405
6406                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
6407                 case CONNMAN_SERVICE_TYPE_SYSTEM:
6408                 case CONNMAN_SERVICE_TYPE_GPS:
6409                 case CONNMAN_SERVICE_TYPE_VPN:
6410                 case CONNMAN_SERVICE_TYPE_P2P:
6411 #if defined TIZEN_EXT_WIFI_MESH
6412                 case CONNMAN_SERVICE_TYPE_MESH:
6413 #endif
6414                         break;
6415                 }
6416
6417                 if (active_sessions[type] == 0)
6418                         disconnect_on_last_session(type);
6419
6420                 list = g_slist_next(list);
6421         }
6422
6423         DBG("eth %d wifi %d bt %d cellular %d gadget %d sessions %d",
6424                         active_sessions[CONNMAN_SERVICE_TYPE_ETHERNET],
6425                         active_sessions[CONNMAN_SERVICE_TYPE_WIFI],
6426                         active_sessions[CONNMAN_SERVICE_TYPE_BLUETOOTH],
6427                         active_sessions[CONNMAN_SERVICE_TYPE_CELLULAR],
6428                         active_sessions[CONNMAN_SERVICE_TYPE_GADGET],
6429                         active_count);
6430 }
6431
6432 struct preferred_tech_data {
6433         GList *preferred_list;
6434         enum connman_service_type type;
6435 };
6436
6437 static void preferred_tech_add_by_type(gpointer data, gpointer user_data)
6438 {
6439         struct connman_service *service = data;
6440         struct preferred_tech_data *tech_data = user_data;
6441
6442         if (service->type == tech_data->type) {
6443                 tech_data->preferred_list =
6444                         g_list_append(tech_data->preferred_list, service);
6445
6446 #if defined TIZEN_EXT
6447                 if (!simplified_log)
6448 #endif
6449                 DBG("type %d service %p %s", tech_data->type, service,
6450                                 service->name);
6451         }
6452 }
6453
6454 static GList *preferred_tech_list_get(void)
6455 {
6456         unsigned int *tech_array;
6457         struct preferred_tech_data tech_data = { 0, };
6458         int i;
6459
6460         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
6461         if (!tech_array)
6462                 return NULL;
6463
6464         if (connman_setting_get_bool("SingleConnectedTechnology")) {
6465                 GList *list;
6466                 for (list = service_list; list; list = list->next) {
6467                         struct connman_service *service = list->data;
6468
6469                         if (!is_connected(service->state))
6470                                 break;
6471
6472                         if (service->connect_reason ==
6473                                         CONNMAN_SERVICE_CONNECT_REASON_USER) {
6474                                 DBG("service %p name %s is user connected",
6475                                                 service, service->name);
6476 #if defined TIZEN_EXT
6477                                 /* We can connect to a favorite service like
6478                                  * wifi even we have a userconnect for cellular
6479                                  * because we have refount for cellular service
6480                                  */
6481                                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6482                                         break;
6483
6484                                 if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
6485                                         break;
6486 #endif
6487                                 return NULL;
6488                         }
6489                 }
6490         }
6491
6492         for (i = 0; tech_array[i] != 0; i += 1) {
6493                 tech_data.type = tech_array[i];
6494                 g_list_foreach(service_list, preferred_tech_add_by_type,
6495                                 &tech_data);
6496         }
6497
6498         return tech_data.preferred_list;
6499 }
6500
6501 static void set_always_connecting_technologies()
6502 {
6503         unsigned int *always_connected_techs =
6504                 connman_setting_get_uint_list("AlwaysConnectedTechnologies");
6505         int i;
6506         for (i = 0; always_connected_techs && always_connected_techs[i]; i++)
6507                 always_connect[always_connected_techs[i]] = 1;
6508 }
6509
6510 static bool autoconnect_no_session_active(struct connman_service *service)
6511 {
6512         /*
6513          * Test active_count to see if there are no sessions set up and
6514          * stop autoconnecting, but continue connecting if the service
6515          * belongs to a technology which should always autoconnect.
6516          */
6517         if (!active_count && !always_connect[service->type])
6518                 return true;
6519
6520         return false;
6521 }
6522
6523 static bool autoconnect_already_connecting(struct connman_service *service,
6524                                            bool autoconnecting)
6525 {
6526         /*
6527          * If another service is already connecting and this service type has
6528          * not been marked as always connecting, stop the connecting procedure.
6529          */
6530         if (autoconnecting &&
6531                         !active_sessions[service->type] &&
6532                         !always_connect[service->type])
6533                 return true;
6534
6535         return false;
6536 }
6537
6538 static int service_indicate_state(struct connman_service *service);
6539
6540 static bool auto_connect_service(GList *services,
6541                                 enum connman_service_connect_reason reason,
6542                                 bool preferred)
6543 {
6544         struct connman_service *service = NULL;
6545         bool ignore[MAX_CONNMAN_SERVICE_TYPES] = { };
6546         bool autoconnecting = false;
6547         GList *list;
6548 #if defined TIZEN_EXT
6549         GSList *wifi_ignore = NULL;
6550 #endif
6551
6552         DBG("preferred %d sessions %d reason %s", preferred, active_count,
6553                 reason2string(reason));
6554
6555         ignore[CONNMAN_SERVICE_TYPE_VPN] = true;
6556
6557 #if defined TIZEN_EXT_WIFI_MESH
6558         /* Don't auto connect wifi if mesh interface is created */
6559         if (connman_mesh_is_interface_created())
6560                 ignore[CONNMAN_SERVICE_TYPE_WIFI] = true;
6561 #endif
6562
6563         for (list = services; list; list = list->next) {
6564                 service = list->data;
6565
6566 #if defined TIZEN_EXT
6567                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
6568                         int index = connman_network_get_index(service->network);
6569                         if (g_slist_find(wifi_ignore, GINT_TO_POINTER(index)) != NULL)
6570                                 continue;
6571                 } else
6572 #endif
6573                 if (ignore[service->type]) {
6574                         DBG("service %p type %s ignore", service,
6575                                 __connman_service_type2string(service->type));
6576                         continue;
6577                 }
6578
6579 #if defined TIZEN_EXT
6580                 DBG("service %p %s %s %s, favorite(%d), ignore(%d), hidden(%d, %d)",
6581                                 service, service->name,
6582                                 state2string(service->state),
6583                                 __connman_service_type2string(service->type),
6584                                 service->favorite, is_ignore(service),
6585                                 service->hidden, service->hidden_service);
6586
6587                 /* Tizen takes Wi-Fi as the highest priority into consideration. */
6588                 if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
6589                         if (is_connecting(service->state) == TRUE || is_connected(service->state) == TRUE)
6590                                 continue;
6591 #endif
6592
6593                 if (service->pending ||
6594                                 is_connecting(service->state) ||
6595                                 is_connected(service->state)) {
6596 #if defined TIZEN_EXT
6597                         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
6598                                 int index = connman_network_get_index(service->network);
6599                                 wifi_ignore = g_slist_prepend(wifi_ignore, GINT_TO_POINTER(index));
6600
6601                                 autoconnecting = true;
6602                                 continue;
6603                         }
6604 #else
6605                         if (autoconnect_no_session_active(service))
6606                                         return true;
6607 #endif
6608                         ignore[service->type] = true;
6609                         autoconnecting = true;
6610
6611                         DBG("service %p type %s busy", service,
6612                                 __connman_service_type2string(service->type));
6613
6614                         continue;
6615                 }
6616
6617                 if (!service->favorite) {
6618                         if (preferred)
6619                                continue;
6620
6621 #if defined TIZEN_EXT
6622                         DBG("Service is not favorite, autoconnecting %d",
6623                                         autoconnecting);
6624                         g_slist_free(wifi_ignore);
6625 #endif
6626                         return autoconnecting;
6627                 }
6628
6629 #if defined TIZEN_EXT
6630                 DBG("service %p identifier %s roaming %d ignore %d "
6631                                 "ipconfig_usable %d autoconnect %d state %d",
6632                                 service,
6633                                 service->identifier, service->roaming,
6634                                 service->ignore, is_ipconfig_usable(service),
6635                                 service->autoconnect, service->state);
6636 #endif
6637                 if (is_ignore(service) || service->state !=
6638                                 CONNMAN_SERVICE_STATE_IDLE)
6639                         continue;
6640 #if defined TIZEN_EXT
6641                 if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
6642 #endif
6643                 if (autoconnect_already_connecting(service, autoconnecting)) {
6644                         DBG("service %p type %s has no users", service,
6645                                 __connman_service_type2string(service->type));
6646                         continue;
6647                 }
6648
6649                 DBG("service %p %s %s", service, service->name,
6650                         (preferred) ? "preferred" : reason2string(reason));
6651
6652 #if defined TIZEN_EXT
6653                 __connman_service_connect(service, reason);
6654 #else
6655                 if (__connman_service_connect(service, reason) == 0)
6656                         service_indicate_state(service);
6657
6658                 if (autoconnect_no_session_active(service))
6659                         return true;
6660 #endif
6661 #if defined TIZEN_EXT
6662                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
6663                         int index = connman_network_get_index(service->network);
6664                         wifi_ignore = g_slist_prepend(wifi_ignore, GINT_TO_POINTER(index));
6665                         autoconnecting = true;
6666                 }
6667 #endif
6668                 ignore[service->type] = true;
6669         }
6670 #if defined TIZEN_EXT
6671         g_slist_free(wifi_ignore);
6672 #endif
6673         return autoconnecting;
6674 }
6675
6676 static gboolean run_auto_connect(gpointer data)
6677 {
6678         enum connman_service_connect_reason reason = GPOINTER_TO_UINT(data);
6679         bool autoconnecting = false;
6680         GList *preferred_tech;
6681
6682         autoconnect_id = 0;
6683
6684         DBG("");
6685
6686         preferred_tech = preferred_tech_list_get();
6687         if (preferred_tech) {
6688                 autoconnecting = auto_connect_service(preferred_tech, reason,
6689                                                         true);
6690                 g_list_free(preferred_tech);
6691         }
6692
6693         if (!autoconnecting || active_count)
6694                 auto_connect_service(service_list, reason, false);
6695
6696         return FALSE;
6697 }
6698
6699 #if defined TIZEN_EXT
6700 bool __connman_service_get_auto_connect_mode(void)
6701 {
6702         return auto_connect_mode;
6703 }
6704
6705 void __connman_service_set_auto_connect_mode(bool enable)
6706 {
6707         DBG("set auto_connect_mode = %d", enable);
6708
6709         if (auto_connect_mode != enable)
6710                 auto_connect_mode = enable;
6711 }
6712 #endif
6713
6714 void __connman_service_auto_connect(enum connman_service_connect_reason reason)
6715 {
6716         DBG("");
6717
6718         if (autoconnect_id != 0)
6719                 return;
6720
6721 #if defined TIZEN_EXT
6722         if (auto_connect_mode == FALSE) {
6723                 DBG("Currently, not auto connection mode");
6724                 return;
6725         }
6726 #endif
6727
6728         if (!__connman_session_policy_autoconnect(reason))
6729                 return;
6730
6731 #if defined TIZEN_EXT
6732         /* Adding Timeout of 500ms before trying to auto connect.
6733          * This is done because of below scenario
6734          * 1. Device is connected to AP1
6735          * 2. WPS Connection request is initiated for AP2
6736          * 3. Immediately WPS Connection is Cancelled
6737          * When WPS Connection Connection is initiated for AP2 then
6738          * sometimes there is a scenario where connman gets in ASSOCIATED
6739          * state with AP1 due to autoconnect and subsequently the connection
6740          * initiated by AP1 fails and connman service for AP1 comes in
6741          * FAILURE state due to this when connection with AP2 is cancelled
6742          * then autoconnect with AP1 doesn't works because its autoconnection
6743          * is ignored as its last state was FAILURE rather than IDLE */
6744         autoconnect_id = g_timeout_add(500, run_auto_connect,
6745 #else
6746         autoconnect_id = g_idle_add(run_auto_connect,
6747 #endif
6748                                                 GUINT_TO_POINTER(reason));
6749 }
6750
6751 static gboolean run_vpn_auto_connect(gpointer data) {
6752         GList *list;
6753         bool need_split = false;
6754         bool autoconnectable_vpns = false;
6755         int attempts = 0;
6756         int timeout = VPN_AUTOCONNECT_TIMEOUT_DEFAULT;
6757         struct connman_service *def_service;
6758
6759         attempts = GPOINTER_TO_INT(data);
6760         def_service = connman_service_get_default();
6761
6762         /*
6763          * Stop auto connecting VPN if there is no transport service or the
6764          * transport service is not connected or if the  current default service
6765          * is a connected VPN (in ready state).
6766          */
6767         if (!def_service || !is_connected(def_service->state) ||
6768                 (def_service->type == CONNMAN_SERVICE_TYPE_VPN &&
6769                 is_connected(def_service->state))) {
6770
6771                 DBG("stopped, default service %s connected %d",
6772                         def_service ? def_service->identifier : "NULL",
6773                         def_service ? is_connected(def_service->state) : -1);
6774                 goto out;
6775         }
6776
6777         for (list = service_list; list; list = list->next) {
6778                 struct connman_service *service = list->data;
6779                 int res;
6780
6781                 if (service->type != CONNMAN_SERVICE_TYPE_VPN)
6782                         continue;
6783
6784                 if (is_connected(service->state) ||
6785                                         is_connecting(service->state)) {
6786                         if (!service->do_split_routing)
6787                                 need_split = true;
6788
6789                         /*
6790                          * If the service is connecting it must be accounted
6791                          * for to keep the autoconnection in main loop.
6792                          */
6793                         if (is_connecting(service->state))
6794                                 autoconnectable_vpns = true;
6795
6796                         continue;
6797                 }
6798
6799                 if (is_ignore(service) || !service->favorite)
6800                         continue;
6801
6802                 if (need_split && !service->do_split_routing) {
6803                         DBG("service %p no split routing", service);
6804                         continue;
6805                 }
6806
6807                 DBG("service %p %s %s", service, service->name,
6808                                 service->do_split_routing ?
6809                                 "split routing" : "");
6810
6811                 res = __connman_service_connect(service,
6812                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
6813
6814                 switch (res) {
6815                 case 0:
6816                         service_indicate_state(service);
6817                         /* fall through */
6818                 case -EINPROGRESS:
6819                         autoconnectable_vpns = true;
6820                         break;
6821                 default:
6822                         continue;
6823                 }
6824
6825                 if (!service->do_split_routing)
6826                         need_split = true;
6827         }
6828
6829         /* Stop if there is no VPN to automatically connect.*/
6830         if (!autoconnectable_vpns) {
6831                 DBG("stopping, no autoconnectable VPNs found");
6832                 goto out;
6833         }
6834
6835         /* Increase the attempt count up to the threshold.*/
6836         if (attempts < VPN_AUTOCONNECT_TIMEOUT_ATTEMPTS_THRESHOLD)
6837                 attempts++;
6838
6839         /*
6840          * Timeout increases with 1s after VPN_AUTOCONNECT_TIMEOUT_STEP amount
6841          * of attempts made. After VPN_AUTOCONNECT_TIMEOUT_ATTEMPTS_THRESHOLD is
6842          * reached the delay does not increase.
6843          */
6844         timeout = timeout + (int)(attempts / VPN_AUTOCONNECT_TIMEOUT_STEP);
6845
6846         /* Re add this to main loop */
6847         vpn_autoconnect_id =
6848                 g_timeout_add_seconds(timeout, run_vpn_auto_connect,
6849                         GINT_TO_POINTER(attempts));
6850
6851         DBG("re-added to main loop, next VPN autoconnect in %d seconds (#%d)",
6852                 timeout, attempts);
6853
6854         return G_SOURCE_REMOVE;
6855
6856 out:
6857         vpn_autoconnect_id = 0;
6858         return G_SOURCE_REMOVE;
6859 }
6860
6861 static void vpn_auto_connect(void)
6862 {
6863         /*
6864          * Remove existing autoconnect from main loop to reset the attempt
6865          * counter in order to get VPN connected when there is a network change.
6866          */
6867         if (vpn_autoconnect_id) {
6868                 if (!g_source_remove(vpn_autoconnect_id))
6869                         return;
6870         }
6871
6872         vpn_autoconnect_id =
6873                 g_idle_add(run_vpn_auto_connect, NULL);
6874 }
6875
6876 bool
6877 __connman_service_is_provider_pending(struct connman_service *service)
6878 {
6879         if (!service)
6880                 return false;
6881
6882         if (service->provider_pending)
6883                 return true;
6884
6885         return false;
6886 }
6887
6888 void __connman_service_set_provider_pending(struct connman_service *service,
6889                                                         DBusMessage *msg)
6890 {
6891         if (service->provider_pending) {
6892                 DBG("service %p provider pending msg %p already exists",
6893                         service, service->provider_pending);
6894                 return;
6895         }
6896
6897         service->provider_pending = msg;
6898 }
6899
6900 static void check_pending_msg(struct connman_service *service)
6901 {
6902         if (!service->pending)
6903                 return;
6904
6905         DBG("service %p pending msg %p already exists", service,
6906                                                 service->pending);
6907         dbus_message_unref(service->pending);
6908 }
6909
6910 void __connman_service_set_hidden_data(struct connman_service *service,
6911                                                         gpointer user_data)
6912 {
6913         DBusMessage *pending = user_data;
6914
6915         DBG("service %p pending %p", service, pending);
6916
6917         if (!pending)
6918                 return;
6919
6920         check_pending_msg(service);
6921
6922         service->pending = pending;
6923 }
6924
6925 void __connman_service_return_error(struct connman_service *service,
6926                                 int error, gpointer user_data)
6927 {
6928         DBG("service %p error %d user_data %p", service, error, user_data);
6929
6930         __connman_service_set_hidden_data(service, user_data);
6931
6932         reply_pending(service, error);
6933 }
6934
6935 static gboolean connect_timeout(gpointer user_data)
6936 {
6937         struct connman_service *service = user_data;
6938         bool autoconnect = false;
6939
6940         DBG("service %p", service);
6941
6942         service->timeout = 0;
6943
6944         if (service->network)
6945                 __connman_network_disconnect(service->network);
6946         else if (service->provider)
6947                 connman_provider_disconnect(service->provider);
6948
6949         __connman_stats_service_unregister(service);
6950
6951         if (service->pending) {
6952                 DBusMessage *reply;
6953
6954                 reply = __connman_error_operation_timeout(service->pending);
6955                 if (reply)
6956                         g_dbus_send_message(connection, reply);
6957
6958                 dbus_message_unref(service->pending);
6959                 service->pending = NULL;
6960         } else
6961                 autoconnect = true;
6962
6963         __connman_service_ipconfig_indicate_state(service,
6964                                         CONNMAN_SERVICE_STATE_FAILURE,
6965                                         CONNMAN_IPCONFIG_TYPE_IPV4);
6966         __connman_service_ipconfig_indicate_state(service,
6967                                         CONNMAN_SERVICE_STATE_FAILURE,
6968                                         CONNMAN_IPCONFIG_TYPE_IPV6);
6969
6970         if (autoconnect &&
6971                         service->connect_reason !=
6972                                 CONNMAN_SERVICE_CONNECT_REASON_USER)
6973                 do_auto_connect(service, CONNMAN_SERVICE_CONNECT_REASON_AUTO);
6974
6975         return FALSE;
6976 }
6977
6978 static DBusMessage *connect_service(DBusConnection *conn,
6979                                         DBusMessage *msg, void *user_data)
6980 {
6981         struct connman_service *service = user_data;
6982 #if defined TIZEN_EXT
6983         int err = 0;
6984 #else
6985         int index, err = 0;
6986         GList *list;
6987 #endif
6988
6989         DBG("service %p", service);
6990
6991 #if defined TIZEN_EXT
6992         /*
6993          * Description: TIZEN implements system global connection management.
6994          */
6995         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6996                 connman_service_user_pdn_connection_ref(service);
6997
6998         /*Reset the Disconnect Reason while issue connect request*/
6999         service->disconnect_reason = 0;
7000
7001         /*Reset the association status code while issue connect request*/
7002         service->assoc_status_code = 0;
7003
7004         /* Reset the disconnection_requested while issue connect request*/
7005         connman_service_set_disconnection_requested(service, false);
7006 #endif
7007
7008         if (service->pending)
7009                 return __connman_error_in_progress(msg);
7010
7011 #if !defined TIZEN_EXT
7012         index = __connman_service_get_index(service);
7013
7014         for (list = service_list; list; list = list->next) {
7015                 struct connman_service *temp = list->data;
7016
7017 #if defined TIZEN_EXT
7018                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7019                         break;
7020 #endif
7021                 if (!is_connecting(temp->state) && !is_connected(temp->state))
7022                         break;
7023
7024                 if (service == temp)
7025                         continue;
7026
7027                 if (service->type != temp->type)
7028                         continue;
7029
7030                 if (__connman_service_get_index(temp) == index &&
7031                                 __connman_service_disconnect(temp) == -EINPROGRESS)
7032                         err = -EINPROGRESS;
7033
7034         }
7035         if (err == -EINPROGRESS)
7036                 return __connman_error_operation_timeout(msg);
7037 #endif
7038
7039         service->ignore = false;
7040
7041         service->pending = dbus_message_ref(msg);
7042
7043         err = __connman_service_connect(service,
7044                         CONNMAN_SERVICE_CONNECT_REASON_USER);
7045
7046         if (err != -EINPROGRESS)
7047                 reply_pending(service, -err);
7048
7049         return NULL;
7050 }
7051
7052 static DBusMessage *disconnect_service(DBusConnection *conn,
7053                                         DBusMessage *msg, void *user_data)
7054 {
7055         struct connman_service *service = user_data;
7056         int err;
7057
7058         DBG("service %p", service);
7059
7060 #if defined TIZEN_EXT
7061         /*
7062          * Description: TIZEN implements system global connection management.
7063          */
7064         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
7065                 if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE)
7066                         return __connman_error_failed(msg, EISCONN);
7067
7068                 if (is_connected(service->state) == TRUE &&
7069                                 service == connman_service_get_default_connection())
7070                         return __connman_error_failed(msg, EISCONN);
7071         }
7072 #endif
7073
7074         service->ignore = true;
7075
7076         err = __connman_service_disconnect(service);
7077         if (err < 0 && err != -EINPROGRESS)
7078                 return __connman_error_failed(msg, -err);
7079
7080         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
7081 }
7082
7083 #if defined TIZEN_EXT
7084 static void __connman_service_cleanup_network_8021x(struct connman_service *service)
7085 {
7086         if (service == NULL)
7087                 return;
7088
7089         DBG("service %p ", service);
7090
7091         connman_network_set_string(service->network, "WiFi.EAP", NULL);
7092         connman_network_set_string(service->network, "WiFi.Identity", NULL);
7093         connman_network_set_string(service->network, "WiFi.CACertFile", NULL);
7094         connman_network_set_string(service->network, "WiFi.ClientCertFile", NULL);
7095         connman_network_set_string(service->network, "WiFi.PrivateKeyFile", NULL);
7096         connman_network_set_string(service->network, "WiFi.PrivateKeyPassphrase", NULL);
7097         connman_network_set_string(service->network, "WiFi.Phase2", NULL);
7098         connman_network_set_string(service->network, "WiFi.AnonymousIdentity", NULL);
7099 }
7100 static void __connman_service_cleanup_network_dpp(struct connman_service *service)
7101 {
7102         if (service == NULL)
7103                 return;
7104
7105         DBG("service %p ", service);
7106
7107         connman_network_set_string(service->network, "WiFi.Connector", NULL);
7108         connman_network_set_string(service->network, "WiFi.CSignKey", NULL);
7109         connman_network_set_string(service->network, "WiFi.NetAccessKey", NULL);
7110 }
7111 #endif
7112
7113 bool __connman_service_remove(struct connman_service *service)
7114 {
7115         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET ||
7116                         service->type == CONNMAN_SERVICE_TYPE_GADGET)
7117                 return false;
7118
7119         if (service->immutable || service->hidden ||
7120                         __connman_provider_is_immutable(service->provider))
7121                 return false;
7122
7123 #if !defined TIZEN_EXT
7124         if (!service->favorite && !is_idle(service->state))
7125                 return false;
7126 #endif
7127
7128         __connman_service_disconnect(service);
7129
7130         g_free(service->passphrase);
7131         service->passphrase = NULL;
7132
7133         g_free(service->identity);
7134         service->identity = NULL;
7135
7136         g_free(service->anonymous_identity);
7137         service->anonymous_identity = NULL;
7138
7139         g_free(service->subject_match);
7140         service->subject_match = NULL;
7141
7142         g_free(service->altsubject_match);
7143         service->altsubject_match = NULL;
7144
7145         g_free(service->domain_suffix_match);
7146         service->domain_suffix_match = NULL;
7147
7148         g_free(service->domain_match);
7149         service->domain_match = NULL;
7150
7151         g_free(service->agent_identity);
7152         service->agent_identity = NULL;
7153
7154         g_free(service->eap);
7155         service->eap = NULL;
7156
7157 #if defined TIZEN_EXT
7158         g_free(service->ca_cert_file);
7159         service->ca_cert_file = NULL;
7160
7161         g_free(service->client_cert_file);
7162         service->client_cert_file = NULL;
7163
7164         g_free(service->private_key_file);
7165         service->private_key_file = NULL;
7166
7167         g_free(service->private_key_passphrase);
7168         service->private_key_passphrase = NULL;
7169
7170         g_free(service->phase2);
7171         service->phase2 = NULL;
7172
7173         __connman_service_cleanup_network_8021x(service);
7174
7175         __connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP);
7176         __connman_ipconfig_set_method(service->ipconfig_ipv6, CONNMAN_IPCONFIG_METHOD_AUTO);
7177         connman_service_set_proxy(service, NULL, false);
7178
7179         __connman_service_nameserver_clear(service);
7180
7181         g_strfreev(service->nameservers_config);
7182         service->nameservers_config = NULL;
7183
7184         g_free(service->connector);
7185         service->connector = NULL;
7186
7187         g_free(service->c_sign_key);
7188         service->c_sign_key = NULL;
7189
7190         g_free(service->net_access_key);
7191         service->net_access_key = NULL;
7192
7193         __connman_service_cleanup_network_dpp(service);
7194 #endif
7195
7196         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
7197
7198         __connman_service_set_favorite(service, false);
7199
7200         __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
7201
7202 #if defined TIZEN_EXT
7203         /* Reset IP Method and DNS Method to DHCP */
7204         __connman_ipconfig_set_method(service->ipconfig_ipv4,
7205                         CONNMAN_IPCONFIG_METHOD_DHCP);
7206         service->dns_config_method_ipv4 = CONNMAN_DNSCONFIG_METHOD_DHCP;
7207         g_strfreev(service->nameservers_config);
7208         service->nameservers_config = NULL;
7209 #endif
7210
7211 #if defined TIZEN_EXT
7212         __connman_storage_remove_service(service->identifier);
7213 #else
7214         service_save(service);
7215 #endif
7216
7217         return true;
7218 }
7219
7220 static DBusMessage *remove_service(DBusConnection *conn,
7221                                         DBusMessage *msg, void *user_data)
7222 {
7223         struct connman_service *service = user_data;
7224
7225         DBG("service %p", service);
7226
7227         if (!__connman_service_remove(service))
7228                 return __connman_error_not_supported(msg);
7229
7230         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
7231 }
7232
7233 static bool check_suitable_state(enum connman_service_state a,
7234                                         enum connman_service_state b)
7235 {
7236         /*
7237          * Special check so that "ready" service can be moved before
7238          * "online" one.
7239          */
7240         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
7241                         b == CONNMAN_SERVICE_STATE_READY) ||
7242                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
7243                         a == CONNMAN_SERVICE_STATE_READY))
7244                 return true;
7245
7246         return a == b;
7247 }
7248
7249 static void downgrade_state(struct connman_service *service)
7250 {
7251         if (!service)
7252                 return;
7253
7254         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
7255                                                 service->state_ipv6);
7256
7257         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
7258                 __connman_service_ipconfig_indicate_state(service,
7259                                                 CONNMAN_SERVICE_STATE_READY,
7260                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7261
7262         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
7263                 __connman_service_ipconfig_indicate_state(service,
7264                                                 CONNMAN_SERVICE_STATE_READY,
7265                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7266 }
7267
7268 static void apply_relevant_default_downgrade(struct connman_service *service)
7269 {
7270         struct connman_service *def_service;
7271
7272         def_service = connman_service_get_default();
7273         if (!def_service)
7274                 return;
7275
7276         if (def_service == service &&
7277                         def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
7278                 def_service->state = CONNMAN_SERVICE_STATE_READY;
7279                 __connman_notifier_leave_online(def_service->type);
7280                 state_changed(def_service);
7281         }
7282 }
7283
7284 static void switch_default_service(struct connman_service *default_service,
7285                 struct connman_service *downgrade_service)
7286 {
7287         struct connman_service *service;
7288         GList *src, *dst;
7289
7290         apply_relevant_default_downgrade(default_service);
7291         src = g_list_find(service_list, downgrade_service);
7292         dst = g_list_find(service_list, default_service);
7293
7294         /* Nothing to do */
7295         if (src == dst || src->next == dst)
7296                 return;
7297
7298         service = src->data;
7299         service_list = g_list_delete_link(service_list, src);
7300         service_list = g_list_insert_before(service_list, dst, service);
7301
7302         downgrade_state(downgrade_service);
7303 }
7304
7305 static struct _services_notify {
7306         int id;
7307         GHashTable *add;
7308         GHashTable *remove;
7309 } *services_notify;
7310
7311
7312 static void service_append_added_foreach(gpointer data, gpointer user_data)
7313 {
7314         struct connman_service *service = data;
7315         DBusMessageIter *iter = user_data;
7316
7317         if (!service || !service->path) {
7318                 DBG("service %p or path is NULL", service);
7319                 return;
7320         }
7321
7322         if (g_hash_table_lookup(services_notify->add, service->path)) {
7323                 DBG("new %s", service->path);
7324
7325                 append_struct(service, iter);
7326                 g_hash_table_remove(services_notify->add, service->path);
7327         } else {
7328 #if defined TIZEN_EXT
7329                 if (!simplified_log)
7330 #endif
7331                 DBG("changed %s", service->path);
7332
7333                 append_struct_service(iter, NULL, service);
7334         }
7335 }
7336
7337 static void service_append_ordered(DBusMessageIter *iter, void *user_data)
7338 {
7339         g_list_foreach(service_list, service_append_added_foreach, iter);
7340 }
7341
7342 static void append_removed(gpointer key, gpointer value, gpointer user_data)
7343 {
7344         char *objpath = key;
7345         DBusMessageIter *iter = user_data;
7346
7347         DBG("removed %s", objpath);
7348         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
7349 }
7350
7351 static void service_append_removed(DBusMessageIter *iter, void *user_data)
7352 {
7353         g_hash_table_foreach(services_notify->remove, append_removed, iter);
7354 }
7355
7356 static gboolean service_send_changed(gpointer data)
7357 {
7358         DBusMessage *signal;
7359
7360         DBG("");
7361
7362         services_notify->id = 0;
7363
7364         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
7365                         CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
7366         if (!signal)
7367                 return FALSE;
7368
7369         __connman_dbus_append_objpath_dict_array(signal,
7370                                         service_append_ordered, NULL);
7371         __connman_dbus_append_objpath_array(signal,
7372                                         service_append_removed, NULL);
7373
7374         dbus_connection_send(connection, signal, NULL);
7375         dbus_message_unref(signal);
7376
7377         g_hash_table_remove_all(services_notify->remove);
7378         g_hash_table_remove_all(services_notify->add);
7379
7380         return FALSE;
7381 }
7382
7383 static void service_schedule_changed(void)
7384 {
7385         if (services_notify->id != 0)
7386                 return;
7387
7388         services_notify->id = g_timeout_add(100, service_send_changed, NULL);
7389 }
7390
7391 static DBusMessage *move_service(DBusConnection *conn,
7392                                         DBusMessage *msg, void *user_data,
7393                                                                 bool before)
7394 {
7395         struct connman_service *service = user_data;
7396         struct connman_service *target;
7397         const char *path;
7398         enum connman_ipconfig_method target4, target6;
7399         enum connman_ipconfig_method service4, service6;
7400
7401         DBG("service %p", service);
7402
7403         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
7404                                                         DBUS_TYPE_INVALID);
7405
7406         if (!service->favorite)
7407                 return __connman_error_not_supported(msg);
7408
7409         target = find_service(path);
7410         if (!target || !target->favorite || target == service)
7411                 return __connman_error_invalid_service(msg);
7412
7413         if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
7414                 /*
7415                  * We only allow VPN route splitting if there are
7416                  * routes defined for a given VPN.
7417                  */
7418                 if (!__connman_provider_check_routes(target->provider)) {
7419                         connman_info("Cannot move service. "
7420                                 "No routes defined for provider %s",
7421                                 __connman_provider_get_ident(target->provider));
7422                         return __connman_error_invalid_service(msg);
7423                 }
7424
7425                 set_split_routing(target, true);
7426         } else
7427                 set_split_routing(target, false);
7428
7429         set_split_routing(service, false);
7430
7431         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
7432         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
7433         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
7434         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
7435
7436         DBG("target %s method %d/%d state %d/%d split %d", target->identifier,
7437                 target4, target6, target->state_ipv4, target->state_ipv6,
7438                 target->do_split_routing);
7439
7440         DBG("service %s method %d/%d state %d/%d", service->identifier,
7441                                 service4, service6,
7442                                 service->state_ipv4, service->state_ipv6);
7443
7444         /*
7445          * If method is OFF, then we do not need to check the corresponding
7446          * ipconfig state.
7447          */
7448         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
7449                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
7450                         if (!check_suitable_state(target->state_ipv6,
7451                                                         service->state_ipv6))
7452                                 return __connman_error_invalid_service(msg);
7453                 }
7454         }
7455
7456         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
7457                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
7458                         if (!check_suitable_state(target->state_ipv4,
7459                                                         service->state_ipv4))
7460                                 return __connman_error_invalid_service(msg);
7461                 }
7462         }
7463
7464         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
7465                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
7466                         if (!check_suitable_state(target->state_ipv6,
7467                                                         service->state_ipv6))
7468                                 return __connman_error_invalid_service(msg);
7469                 }
7470         }
7471
7472         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
7473                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
7474                         if (!check_suitable_state(target->state_ipv4,
7475                                                         service->state_ipv4))
7476                                 return __connman_error_invalid_service(msg);
7477                 }
7478         }
7479
7480         gettimeofday(&service->modified, NULL);
7481         service_save(service);
7482         service_save(target);
7483
7484         /*
7485          * If the service which goes down is the default service and is
7486          * online, we downgrade directly its state to ready so:
7487          * the service which goes up, needs to recompute its state which
7488          * is triggered via downgrading it - if relevant - to state ready.
7489          */
7490         if (before)
7491                 switch_default_service(target, service);
7492         else
7493                 switch_default_service(service, target);
7494
7495         __connman_connection_update_gateway();
7496
7497         service_schedule_changed();
7498
7499         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
7500 }
7501
7502 static DBusMessage *move_before(DBusConnection *conn,
7503                                         DBusMessage *msg, void *user_data)
7504 {
7505         return move_service(conn, msg, user_data, true);
7506 }
7507
7508 static DBusMessage *move_after(DBusConnection *conn,
7509                                         DBusMessage *msg, void *user_data)
7510 {
7511         return move_service(conn, msg, user_data, false);
7512 }
7513
7514 static DBusMessage *reset_counters(DBusConnection *conn,
7515                                         DBusMessage *msg, void *user_data)
7516 {
7517         struct connman_service *service = user_data;
7518
7519         reset_stats(service);
7520
7521         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
7522 }
7523
7524 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
7525 static DBusMessage *is_eapol_enabled(DBusConnection *conn,
7526                                         DBusMessage *msg, void *user_data)
7527 {
7528         struct connman_service *service = user_data;
7529         DBG("service: %p path: %s UseEapol: %d", service, service->path, service->use_eapol);
7530
7531         dbus_bool_t eapol_status = service->use_eapol;
7532
7533         DBusMessage *reply = dbus_message_new_method_return(msg);
7534         if (!reply) {
7535                 DBG("Failed to initialize reply");
7536                 return NULL;
7537         }
7538
7539         dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &eapol_status, DBUS_TYPE_INVALID);
7540         return reply;
7541 }
7542 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
7543
7544 #if defined TIZEN_EXT
7545 static DBusMessage *downgrade_service(DBusConnection *conn,
7546                                         DBusMessage *msg, void *user_data)
7547 {
7548         struct connman_service *service = user_data;
7549
7550         downgrade_state(service);
7551         __connman_connection_update_gateway();
7552         start_online_check(service, CONNMAN_IPCONFIG_TYPE_IPV4);
7553
7554         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
7555 }
7556 #endif
7557
7558 static void service_schedule_added(struct connman_service *service)
7559 {
7560 #if defined TIZEN_EXT
7561         if (!simplified_log)
7562 #endif
7563         DBG("service %p", service);
7564
7565         g_hash_table_remove(services_notify->remove, service->path);
7566         g_hash_table_replace(services_notify->add, service->path, service);
7567
7568         service_schedule_changed();
7569 }
7570
7571 static void service_schedule_removed(struct connman_service *service)
7572 {
7573         if (!service || !service->path) {
7574                 DBG("service %p or path is NULL", service);
7575                 return;
7576         }
7577
7578         DBG("service %p %s", service, service->path);
7579
7580         g_hash_table_remove(services_notify->add, service->path);
7581         g_hash_table_replace(services_notify->remove, g_strdup(service->path),
7582                         NULL);
7583
7584         service_schedule_changed();
7585 }
7586
7587 static bool allow_property_changed(struct connman_service *service)
7588 {
7589 #if defined TIZEN_EXT
7590         if (service->path == NULL)
7591                 return FALSE;
7592 #endif
7593         if (g_hash_table_lookup_extended(services_notify->add, service->path,
7594                                         NULL, NULL))
7595                 return false;
7596
7597         return true;
7598 }
7599
7600 static const GDBusMethodTable service_methods[] = {
7601         { GDBUS_DEPRECATED_METHOD("GetProperties",
7602                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
7603                         get_properties) },
7604         { GDBUS_METHOD("SetProperty",
7605                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
7606                         NULL, set_property) },
7607         { GDBUS_METHOD("ClearProperty",
7608                         GDBUS_ARGS({ "name", "s" }), NULL,
7609                         clear_property) },
7610         { GDBUS_ASYNC_METHOD("Connect", NULL, NULL,
7611                               connect_service) },
7612         { GDBUS_METHOD("Disconnect", NULL, NULL,
7613                         disconnect_service) },
7614         { GDBUS_METHOD("Remove", NULL, NULL, remove_service) },
7615         { GDBUS_METHOD("MoveBefore",
7616                         GDBUS_ARGS({ "service", "o" }), NULL,
7617                         move_before) },
7618         { GDBUS_METHOD("MoveAfter",
7619                         GDBUS_ARGS({ "service", "o" }), NULL,
7620                         move_after) },
7621         { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
7622 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
7623         { GDBUS_METHOD("IsEapolEnabled", NULL, GDBUS_ARGS({ "eapol", "b" }), is_eapol_enabled) },
7624 #endif
7625 #if defined TIZEN_EXT
7626         { GDBUS_METHOD("Downgrade", NULL, NULL, downgrade_service) },
7627 #endif
7628         { },
7629 };
7630
7631 static const GDBusSignalTable service_signals[] = {
7632         { GDBUS_SIGNAL("PropertyChanged",
7633                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
7634 #if defined TIZEN_EXT
7635         { GDBUS_SIGNAL("StateChangedProperties",
7636                         GDBUS_ARGS({ "properties", "a{sv}" })) },
7637 #endif
7638         { },
7639 };
7640
7641 static void service_free(gpointer user_data)
7642 {
7643         struct connman_service *service = user_data;
7644         char *path = service->path;
7645
7646         DBG("service %p", service);
7647
7648         reply_pending(service, ENOENT);
7649
7650         if (service->nameservers_timeout) {
7651                 g_source_remove(service->nameservers_timeout);
7652                 dns_changed(service);
7653         }
7654
7655         __connman_notifier_service_remove(service);
7656         service_schedule_removed(service);
7657
7658         __connman_wispr_stop(service);
7659         stats_stop(service);
7660
7661         service->path = NULL;
7662
7663         if (path) {
7664                 __connman_connection_update_gateway();
7665
7666                 g_dbus_unregister_interface(connection, path,
7667                                                 CONNMAN_SERVICE_INTERFACE);
7668                 g_free(path);
7669         }
7670
7671         g_hash_table_destroy(service->counter_table);
7672
7673         if (service->network) {
7674                 __connman_network_disconnect(service->network);
7675                 connman_network_unref(service->network);
7676                 service->network = NULL;
7677         }
7678
7679         if (service->provider)
7680                 connman_provider_unref(service->provider);
7681
7682         if (service->ipconfig_ipv4) {
7683                 __connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
7684                 __connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
7685                 __connman_ipconfig_unref(service->ipconfig_ipv4);
7686                 service->ipconfig_ipv4 = NULL;
7687         }
7688
7689         if (service->ipconfig_ipv6) {
7690                 __connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
7691                 __connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
7692                 __connman_ipconfig_unref(service->ipconfig_ipv6);
7693                 service->ipconfig_ipv6 = NULL;
7694         }
7695
7696         g_strfreev(service->timeservers);
7697         g_strfreev(service->timeservers_config);
7698         g_strfreev(service->nameservers);
7699         g_strfreev(service->nameservers_config);
7700         g_strfreev(service->nameservers_auto);
7701         g_strfreev(service->domains);
7702         g_strfreev(service->proxies);
7703         g_strfreev(service->excludes);
7704
7705         g_free(service->hostname);
7706         g_free(service->domainname);
7707         g_free(service->pac);
7708         g_free(service->name);
7709         g_free(service->passphrase);
7710         g_free(service->identifier);
7711         g_free(service->eap);
7712         g_free(service->identity);
7713         g_free(service->anonymous_identity);
7714         g_free(service->agent_identity);
7715         g_free(service->ca_cert_file);
7716         g_free(service->subject_match);
7717         g_free(service->altsubject_match);
7718         g_free(service->domain_suffix_match);
7719         g_free(service->domain_match);
7720         g_free(service->client_cert_file);
7721         g_free(service->private_key_file);
7722         g_free(service->private_key_passphrase);
7723         g_free(service->phase2);
7724         g_free(service->config_file);
7725         g_free(service->config_entry);
7726 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
7727         g_free(service->pac_file);
7728         g_free(service->phase1);
7729 #endif
7730
7731 #if defined TIZEN_EXT
7732         g_free(service->connector);
7733         g_free(service->c_sign_key);
7734         g_free(service->net_access_key);
7735 #endif
7736
7737         if (service->stats.timer)
7738                 g_timer_destroy(service->stats.timer);
7739         if (service->stats_roaming.timer)
7740                 g_timer_destroy(service->stats_roaming.timer);
7741
7742         if (current_default == service)
7743                 current_default = NULL;
7744
7745         g_free(service);
7746 }
7747
7748 static void stats_init(struct connman_service *service)
7749 {
7750         /* home */
7751         service->stats.valid = false;
7752         service->stats.enabled = false;
7753         service->stats.timer = g_timer_new();
7754
7755         /* roaming */
7756         service->stats_roaming.valid = false;
7757         service->stats_roaming.enabled = false;
7758         service->stats_roaming.timer = g_timer_new();
7759 }
7760
7761 static void service_initialize(struct connman_service *service)
7762 {
7763 #if defined TIZEN_EXT
7764         if (!simplified_log)
7765 #endif
7766         DBG("service %p", service);
7767
7768         service->refcount = 1;
7769
7770         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
7771
7772         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
7773         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
7774
7775         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
7776         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
7777         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
7778
7779         service->favorite  = false;
7780         service->immutable = false;
7781         service->hidden = false;
7782
7783         service->ignore = false;
7784
7785         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
7786
7787         service->order = 0;
7788
7789         stats_init(service);
7790
7791         service->provider = NULL;
7792
7793         service->wps = false;
7794         service->wps_advertizing = false;
7795 #if defined TIZEN_EXT
7796         memset(service->last_connected_bssid, 0, WIFI_BSSID_LEN_MAX);
7797         service->is_internet_connection = false;
7798         service->assoc_reject_count = 0;
7799 #endif
7800 #if defined TIZEN_EXT
7801         service->disconnection_requested = false;
7802         service->storage_reload = false;
7803         /*
7804          * Description: TIZEN implements system global connection management.
7805          */
7806         service->user_pdn_connection_refcount = 0;
7807         __sync_synchronize();
7808 #endif
7809 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
7810         service->use_eapol = false;
7811 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
7812 }
7813
7814 /**
7815  * connman_service_create:
7816  *
7817  * Allocate a new service.
7818  *
7819  * Returns: a newly-allocated #connman_service structure
7820  */
7821 struct connman_service *connman_service_create(void)
7822 {
7823         GSList *list;
7824         struct connman_stats_counter *counters;
7825         const char *counter;
7826
7827         struct connman_service *service;
7828
7829         service = g_try_new0(struct connman_service, 1);
7830         if (!service)
7831                 return NULL;
7832
7833         DBG("service %p", service);
7834
7835         service->counter_table = g_hash_table_new_full(g_str_hash,
7836                                                 g_str_equal, NULL, g_free);
7837
7838         for (list = counter_list; list; list = list->next) {
7839                 counter = list->data;
7840
7841                 counters = g_try_new0(struct connman_stats_counter, 1);
7842                 if (!counters) {
7843                         g_hash_table_destroy(service->counter_table);
7844                         g_free(service);
7845                         return NULL;
7846                 }
7847
7848                 counters->append_all = true;
7849
7850                 g_hash_table_replace(service->counter_table, (gpointer)counter,
7851                                 counters);
7852         }
7853
7854         service_initialize(service);
7855
7856         return service;
7857 }
7858
7859 /**
7860  * connman_service_ref:
7861  * @service: service structure
7862  *
7863  * Increase reference counter of service
7864  */
7865 struct connman_service *
7866 connman_service_ref_debug(struct connman_service *service,
7867                         const char *file, int line, const char *caller)
7868 {
7869         DBG("%p ref %d by %s:%d:%s()", service, service->refcount + 1,
7870                 file, line, caller);
7871
7872         __sync_fetch_and_add(&service->refcount, 1);
7873
7874         return service;
7875 }
7876
7877 /**
7878  * connman_service_unref:
7879  * @service: service structure
7880  *
7881  * Decrease reference counter of service and release service if no
7882  * longer needed.
7883  */
7884 void connman_service_unref_debug(struct connman_service *service,
7885                         const char *file, int line, const char *caller)
7886 {
7887         DBG("%p ref %d by %s:%d:%s()", service, service->refcount - 1,
7888                 file, line, caller);
7889
7890         if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
7891                 return;
7892
7893         service_list = g_list_remove(service_list, service);
7894
7895         __connman_service_disconnect(service);
7896
7897         g_hash_table_remove(service_hash, service->identifier);
7898 }
7899
7900 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
7901 static int calculate_score_last_user_selection(struct connman_service *service)
7902 {
7903         int score = 0;
7904         struct connman_device *device;
7905         const char *last_user_selection_ident;
7906         time_t last_user_selection_time;
7907         unsigned int frequency;
7908         time_t curr_time;
7909         time_t ref_time;
7910         struct tm* ref_timeinfo;
7911
7912         device = connman_network_get_device(service->network);
7913         if (!device)
7914                 return 0;
7915
7916         last_user_selection_time = connman_device_get_last_user_selection_time(device);
7917         last_user_selection_ident = connman_device_get_last_user_selection_ident(device);
7918         frequency = connman_network_get_frequency(service->network);
7919
7920         if (ins_settings.last_user_selection) {
7921                 if (g_strcmp0(last_user_selection_ident, service->identifier) == 0 &&
7922                         (((frequency >= FREQ_RANGE_24GHZ_CHANNEL_1 &&
7923                         frequency <= FREQ_RANGE_24GHZ_CHANNEL_14) &&
7924                         service->strength >= ins_settings.signal_level3_24ghz) ||
7925                         ((frequency >= FREQ_RANGE_5GHZ_CHANNEL_32 &&
7926                         frequency <= FREQ_RANGE_5GHZ_CHANNEL_165) &&
7927                         service->strength >= ins_settings.signal_level3_5ghz))) {
7928
7929                         /* Only events that occur within 8 hours are counted. */
7930                         curr_time = time(NULL);
7931                         ref_timeinfo = localtime(&curr_time);
7932                         ref_timeinfo->tm_hour -= 8;
7933                         ref_time = mktime(ref_timeinfo);
7934
7935                         if (last_user_selection_time > ref_time) {
7936                                 int time_diff = (curr_time - last_user_selection_time) / 60;
7937                                 int denominator = ins_settings.last_user_selection_time - time_diff;
7938                                 int numerator = ins_settings.last_user_selection_time /
7939                                                                         ins_settings.last_user_selection_score;
7940                                 int last_user_score = denominator / numerator;
7941
7942                                 score += (last_user_score > ins_settings.last_user_selection_score ?
7943                                         ins_settings.last_user_selection_score : last_user_score);
7944                         }
7945                 }
7946         }
7947
7948         return score;
7949 }
7950
7951 static int calculate_score_last_connected(struct connman_service *service)
7952 {
7953         int score = 0;
7954         struct connman_device *device;
7955         const char *last_connected_ident;
7956         unsigned int frequency;
7957
7958         device = connman_network_get_device(service->network);
7959         if (!device)
7960                 return 0;
7961
7962         last_connected_ident = connman_device_get_last_connected_ident(device);
7963         frequency = connman_network_get_frequency(service->network);
7964
7965         if (ins_settings.last_connected) {
7966                 if (g_strcmp0(last_connected_ident, service->identifier) == 0 &&
7967                                 (((frequency >= FREQ_RANGE_24GHZ_CHANNEL_1 &&
7968                                 frequency <= FREQ_RANGE_24GHZ_CHANNEL_14) &&
7969                                 service->strength >= ins_settings.signal_level3_24ghz) ||
7970                                 ((frequency >= FREQ_RANGE_5GHZ_CHANNEL_32 &&
7971                                 frequency <= FREQ_RANGE_5GHZ_CHANNEL_165) &&
7972                                 service->strength >= ins_settings.signal_level3_5ghz))) {
7973                         score += ins_settings.last_connected_score;
7974                 }
7975         }
7976
7977         return score;
7978 }
7979
7980 static int calculate_score_frequency(struct connman_service *service)
7981 {
7982         int score = 0;
7983         unsigned int frequency;
7984
7985         frequency = connman_network_get_frequency(service->network);
7986
7987         switch (ins_settings.preferred_freq) {
7988         case CONNMAN_INS_PREFERRED_FREQ_24GHZ:
7989                 if ((frequency >= FREQ_RANGE_24GHZ_CHANNEL_1 &&
7990                         frequency <= FREQ_RANGE_24GHZ_CHANNEL_14) &&
7991                         (service->strength >= ins_settings.signal_level3_24ghz))
7992                         score += ins_settings.preferred_freq_score;
7993
7994                 break;
7995         case CONNMAN_INS_PREFERRED_FREQ_5GHZ:
7996                 if ((frequency >= FREQ_RANGE_5GHZ_CHANNEL_32 &&
7997                         frequency <= FREQ_RANGE_5GHZ_CHANNEL_165) &&
7998                         (service->strength >= ins_settings.signal_level3_5ghz))
7999                         score += ins_settings.preferred_freq_score;
8000
8001                 break;
8002         default:
8003                 break;
8004         }
8005
8006         return score;
8007 }
8008
8009 static int calculate_score_security_priority(struct connman_service *service)
8010 {
8011         int score = 0;
8012
8013         if (ins_settings.security_priority_count)
8014                 score += ins_settings.security_priority[service->security];
8015
8016         return score;
8017 }
8018
8019 static int calculate_score_internet_connection(struct connman_service *service)
8020 {
8021         int score = 0;
8022
8023         if (ins_settings.internet) {
8024                 if (service->is_internet_connection)
8025                         score += ins_settings.internet_score;
8026         }
8027
8028         return score;
8029 }
8030
8031 static int calculate_score_strength(struct connman_service *service)
8032 {
8033         int score = 0;
8034
8035         if (ins_settings.signal)
8036                 score += (((service->strength > 60) ? 60 : service->strength) - 35);
8037
8038         return score;
8039 }
8040
8041 static int calculate_score(struct connman_service *service)
8042 {
8043         int score_last_user_selection;
8044         int score_last_connected;
8045         int score_frequency;
8046         int score_security_priority;
8047         int score_internet_connection;
8048         int score_strength;
8049         int score = 0;
8050
8051         if (service->type != CONNMAN_SERVICE_TYPE_WIFI) {
8052                 score += calculate_score_internet_connection(service);
8053                 service->ins_score = score;
8054                 return score;
8055         }
8056
8057         score_last_user_selection = calculate_score_last_user_selection(service);
8058         score_last_connected = calculate_score_last_connected(service);
8059         score_frequency = calculate_score_frequency(service);
8060         score_security_priority = calculate_score_security_priority(service);
8061         score_internet_connection = calculate_score_internet_connection(service);
8062         score_strength = calculate_score_strength(service);
8063
8064         score = score_last_user_selection + score_last_connected +
8065                 score_frequency + score_security_priority +
8066                 score_internet_connection + score_strength;
8067
8068         service->score_last_user_selection = score_last_user_selection;
8069         service->score_last_connected = score_last_connected;
8070         service->score_frequency = score_frequency;
8071         service->score_security_priority = score_security_priority;
8072         service->score_internet_connection = score_internet_connection;
8073         service->score_strength = score_strength;
8074
8075         service->ins_score = score;
8076         return score;
8077 }
8078 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
8079
8080 static gint service_compare(gconstpointer a, gconstpointer b)
8081 {
8082         struct connman_service *service_a = (void *) a;
8083         struct connman_service *service_b = (void *) b;
8084         enum connman_service_state state_a, state_b;
8085         bool a_connected, b_connected;
8086 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
8087         int score_a;
8088         int score_b;
8089 #else /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
8090         gint strength;
8091 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
8092
8093         state_a = service_a->state;
8094         state_b = service_b->state;
8095         a_connected = is_connected(state_a);
8096         b_connected = is_connected(state_b);
8097
8098 #if defined TIZEN_EXT
8099         if ((a_connected && b_connected) &&
8100                         state_a == state_b &&
8101                         service_a->type == CONNMAN_SERVICE_TYPE_WIFI &&
8102                         service_b->type == CONNMAN_SERVICE_TYPE_WIFI) {
8103                 const char *default_interface =
8104                                 connman_option_get_string("DefaultWifiInterface");
8105                 const char *ifname_a = connman_device_get_string(
8106                                 connman_network_get_device(service_a->network), "Interface");
8107                 const char *ifname_b = connman_device_get_string(
8108                                 connman_network_get_device(service_b->network), "Interface");
8109
8110                 if (g_strcmp0(default_interface, ifname_a) == 0)
8111                         return -1;
8112                 else if (g_strcmp0(default_interface, ifname_b) == 0)
8113                         return 1;
8114         }
8115 #endif
8116
8117         if (a_connected && b_connected) {
8118                 if (service_a->order > service_b->order)
8119                         return -1;
8120
8121                 if (service_a->order < service_b->order)
8122                         return 1;
8123         }
8124
8125         if (state_a != state_b) {
8126                 if (a_connected && b_connected) {
8127                         /* We prefer online over ready state */
8128                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
8129                                 return -1;
8130
8131                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
8132                                 return 1;
8133                 }
8134
8135                 if (a_connected)
8136                         return -1;
8137                 if (b_connected)
8138                         return 1;
8139
8140                 if (is_connecting(state_a))
8141                         return -1;
8142                 if (is_connecting(state_b))
8143                         return 1;
8144         }
8145
8146         if (service_a->favorite && !service_b->favorite)
8147                 return -1;
8148
8149         if (!service_a->favorite && service_b->favorite)
8150                 return 1;
8151
8152         if (service_a->type != service_b->type) {
8153                 unsigned int *tech_array;
8154                 int i;
8155
8156                 tech_array = connman_setting_get_uint_list(
8157                                                 "PreferredTechnologies");
8158                 if (tech_array) {
8159                         for (i = 0; tech_array[i]; i++) {
8160                                 if (tech_array[i] == service_a->type)
8161                                         return -1;
8162
8163                                 if (tech_array[i] == service_b->type)
8164                                         return 1;
8165                         }
8166                 }
8167
8168                 if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
8169                         return -1;
8170                 if (service_b->type == CONNMAN_SERVICE_TYPE_ETHERNET)
8171                         return 1;
8172
8173                 if (service_a->type == CONNMAN_SERVICE_TYPE_WIFI)
8174                         return -1;
8175                 if (service_b->type == CONNMAN_SERVICE_TYPE_WIFI)
8176                         return 1;
8177
8178                 if (service_a->type == CONNMAN_SERVICE_TYPE_CELLULAR)
8179                         return -1;
8180                 if (service_b->type == CONNMAN_SERVICE_TYPE_CELLULAR)
8181                         return 1;
8182
8183                 if (service_a->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
8184                         return -1;
8185                 if (service_b->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
8186                         return 1;
8187
8188                 if (service_a->type == CONNMAN_SERVICE_TYPE_VPN)
8189                         return -1;
8190                 if (service_b->type == CONNMAN_SERVICE_TYPE_VPN)
8191                         return 1;
8192
8193                 if (service_a->type == CONNMAN_SERVICE_TYPE_GADGET)
8194                         return -1;
8195                 if (service_b->type == CONNMAN_SERVICE_TYPE_GADGET)
8196                         return 1;
8197         }
8198
8199 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
8200         score_a = calculate_score(service_a);
8201         score_b = calculate_score(service_b);
8202         if (score_b != score_a)
8203                 return score_b - score_a;
8204 #else /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
8205         strength = (gint) service_b->strength - (gint) service_a->strength;
8206         if (strength)
8207                 return strength;
8208 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
8209
8210         return g_strcmp0(service_a->name, service_b->name);
8211 }
8212
8213 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
8214 static void print_service_sort(gpointer data, gpointer user_data)
8215 {
8216         struct connman_service *service = data;
8217
8218         if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
8219                 return;
8220
8221         DBG("name[%-20s] total[%2d] last_usr[%2d] last_conn[%2d] "
8222                 "freq[%2d] sec[%2d] internet[%2d] strength[%2d]",
8223                 service->name, service->ins_score, service->score_last_user_selection,
8224                 service->score_last_connected, service->score_frequency,
8225                 service->score_security_priority, service->score_internet_connection,
8226                 service->score_strength);
8227 }
8228 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
8229
8230 static void service_list_sort(void)
8231 {
8232         if (service_list && service_list->next) {
8233                 service_list = g_list_sort(service_list, service_compare);
8234 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
8235                 g_list_foreach(service_list, print_service_sort, NULL);
8236 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
8237                 service_schedule_changed();
8238         }
8239 }
8240
8241 int __connman_service_compare(const struct connman_service *a,
8242                                         const struct connman_service *b)
8243 {
8244         return service_compare(a, b);
8245 }
8246
8247 /**
8248  * connman_service_get_type:
8249  * @service: service structure
8250  *
8251  * Get the type of service
8252  */
8253 enum connman_service_type connman_service_get_type(struct connman_service *service)
8254 {
8255         if (!service)
8256                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
8257
8258         return service->type;
8259 }
8260
8261 /**
8262  * connman_service_get_interface:
8263  * @service: service structure
8264  *
8265  * Get network interface of service
8266  */
8267 char *connman_service_get_interface(struct connman_service *service)
8268 {
8269         int index;
8270
8271         if (!service)
8272                 return NULL;
8273
8274         index = __connman_service_get_index(service);
8275
8276         return connman_inet_ifname(index);
8277 }
8278
8279 /**
8280  * connman_service_get_network:
8281  * @service: service structure
8282  *
8283  * Get the service network
8284  */
8285 struct connman_network *
8286 __connman_service_get_network(struct connman_service *service)
8287 {
8288         if (!service)
8289                 return NULL;
8290
8291         return service->network;
8292 }
8293
8294 struct connman_ipconfig *
8295 __connman_service_get_ip4config(struct connman_service *service)
8296 {
8297         if (!service)
8298                 return NULL;
8299
8300         return service->ipconfig_ipv4;
8301 }
8302
8303 struct connman_ipconfig *
8304 __connman_service_get_ip6config(struct connman_service *service)
8305 {
8306         if (!service)
8307                 return NULL;
8308
8309         return service->ipconfig_ipv6;
8310 }
8311
8312 struct connman_ipconfig *
8313 __connman_service_get_ipconfig(struct connman_service *service, int family)
8314 {
8315         if (family == AF_INET)
8316                 return __connman_service_get_ip4config(service);
8317         else if (family == AF_INET6)
8318                 return __connman_service_get_ip6config(service);
8319         else
8320                 return NULL;
8321
8322 }
8323
8324 bool __connman_service_is_connected_state(struct connman_service *service,
8325                                         enum connman_ipconfig_type type)
8326 {
8327         if (!service)
8328                 return false;
8329
8330         switch (type) {
8331         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
8332                 break;
8333         case CONNMAN_IPCONFIG_TYPE_IPV4:
8334                 return is_connected(service->state_ipv4);
8335         case CONNMAN_IPCONFIG_TYPE_IPV6:
8336                 return is_connected(service->state_ipv6);
8337         case CONNMAN_IPCONFIG_TYPE_ALL:
8338                 return is_connected(service->state_ipv4) &&
8339                         is_connected(service->state_ipv6);
8340         }
8341
8342         return false;
8343 }
8344 enum connman_service_security __connman_service_get_security(
8345                                 struct connman_service *service)
8346 {
8347         if (!service)
8348                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
8349
8350         return service->security;
8351 }
8352
8353 const char *__connman_service_get_phase2(struct connman_service *service)
8354 {
8355         if (!service)
8356                 return NULL;
8357
8358         return service->phase2;
8359 }
8360
8361 bool __connman_service_wps_enabled(struct connman_service *service)
8362 {
8363         if (!service)
8364                 return false;
8365
8366         return service->wps;
8367 }
8368
8369 void __connman_service_mark_dirty(void)
8370 {
8371         services_dirty = true;
8372 }
8373
8374 #if defined TIZEN_EXT
8375 /**
8376   * Returns profile count if there is any connected profiles
8377   * that use same interface
8378   */
8379 int __connman_service_get_connected_count_of_iface(
8380                                         struct connman_service *service)
8381 {
8382         GList *list;
8383         int count = 0;
8384         int index1 = 0;
8385         int index2 = 0;
8386
8387         DBG("");
8388
8389         index1 = __connman_service_get_index(service);
8390
8391         if (index1 <= 0)
8392                 return 0;
8393
8394         for (list = service_list; list; list = list->next) {
8395                 struct connman_service *service2 = list->data;
8396
8397                 if (service == service2)
8398                         continue;
8399
8400                 index2 = __connman_service_get_index(service2);
8401
8402                 if (is_connected(service2->state) && index2 > 0 && index1 == index2)
8403                         count++;
8404
8405                 index2 = 0;
8406         }
8407
8408         DBG("Interface index %d, count %d", index1, count);
8409
8410         return count;
8411 }
8412
8413 void __connman_service_set_storage_reload(struct connman_service *service,
8414                                         bool storage_reload)
8415 {
8416         if (service != NULL)
8417                 service->storage_reload = storage_reload;
8418 }
8419 #endif
8420
8421 /**
8422  * __connman_service_set_favorite_delayed:
8423  * @service: service structure
8424  * @favorite: favorite value
8425  * @delay_ordering: do not order service sequence
8426  *
8427  * Change the favorite setting of service
8428  */
8429 int __connman_service_set_favorite_delayed(struct connman_service *service,
8430                                         bool favorite,
8431                                         bool delay_ordering)
8432 {
8433 #if defined TIZEN_EXT
8434         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
8435                 return -EIO;
8436 #endif
8437         if (service->hidden)
8438                 return -EOPNOTSUPP;
8439
8440         if (service->favorite == favorite)
8441                 return -EALREADY;
8442
8443         service->favorite = favorite;
8444
8445         favorite_changed(service);
8446
8447         if (!delay_ordering) {
8448
8449                 service_list_sort();
8450
8451                 __connman_connection_update_gateway();
8452         }
8453
8454         return 0;
8455 }
8456
8457 /**
8458  * __connman_service_set_favorite:
8459  * @service: service structure
8460  * @favorite: favorite value
8461  *
8462  * Change the favorite setting of service
8463  */
8464 int __connman_service_set_favorite(struct connman_service *service,
8465                                                 bool favorite)
8466 {
8467         return __connman_service_set_favorite_delayed(service, favorite,
8468                                                         false);
8469 }
8470
8471 bool connman_service_get_favorite(struct connman_service *service)
8472 {
8473         return service->favorite;
8474 }
8475
8476 bool connman_service_get_autoconnect(struct connman_service *service)
8477 {
8478         return service->autoconnect;
8479 }
8480
8481 int __connman_service_set_immutable(struct connman_service *service,
8482                                                 bool immutable)
8483 {
8484         if (service->hidden)
8485                 return -EOPNOTSUPP;
8486
8487         if (service->immutable == immutable)
8488                 return 0;
8489
8490         service->immutable = immutable;
8491
8492         immutable_changed(service);
8493
8494         return 0;
8495 }
8496
8497 int __connman_service_set_ignore(struct connman_service *service,
8498                                                 bool ignore)
8499 {
8500         if (!service)
8501                 return -EINVAL;
8502
8503         service->ignore = ignore;
8504
8505         return 0;
8506 }
8507
8508 void __connman_service_set_string(struct connman_service *service,
8509                                   const char *key, const char *value)
8510 {
8511         if (service->hidden)
8512                 return;
8513         if (g_str_equal(key, "EAP")) {
8514                 g_free(service->eap);
8515                 service->eap = g_strdup(value);
8516         } else if (g_str_equal(key, "Identity")) {
8517                 g_free(service->identity);
8518                 service->identity = g_strdup(value);
8519         } else if (g_str_equal(key, "AnonymousIdentity")) {
8520                 g_free(service->anonymous_identity);
8521                 service->anonymous_identity = g_strdup(value);
8522         } else if (g_str_equal(key, "CACertFile")) {
8523                 g_free(service->ca_cert_file);
8524                 service->ca_cert_file = g_strdup(value);
8525         } else if (g_str_equal(key, "SubjectMatch")) {
8526                 g_free(service->subject_match);
8527                 service->subject_match = g_strdup(value);
8528         } else if (g_str_equal(key, "AltSubjectMatch")) {
8529                 g_free(service->altsubject_match);
8530                 service->altsubject_match = g_strdup(value);
8531         } else if (g_str_equal(key, "DomainSuffixMatch")) {
8532                 g_free(service->domain_suffix_match);
8533                 service->domain_suffix_match = g_strdup(value);
8534         } else if (g_str_equal(key, "DomainMatch")) {
8535                 g_free(service->domain_match);
8536                 service->domain_match = g_strdup(value);
8537         } else if (g_str_equal(key, "ClientCertFile")) {
8538                 g_free(service->client_cert_file);
8539                 service->client_cert_file = g_strdup(value);
8540         } else if (g_str_equal(key, "PrivateKeyFile")) {
8541                 g_free(service->private_key_file);
8542                 service->private_key_file = g_strdup(value);
8543         } else if (g_str_equal(key, "PrivateKeyPassphrase")) {
8544                 g_free(service->private_key_passphrase);
8545                 service->private_key_passphrase = g_strdup(value);
8546         } else if (g_str_equal(key, "Phase2")) {
8547                 g_free(service->phase2);
8548                 service->phase2 = g_strdup(value);
8549         } else if (g_str_equal(key, "Passphrase"))
8550                 __connman_service_set_passphrase(service, value);
8551 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
8552         else if (g_str_equal(key, "Phase1")) {
8553                 g_free(service->phase1);
8554                 service->phase1 = g_strdup(value);
8555         } else if (g_str_equal(key, "PacFile")) {
8556                 g_free(service->pac_file);
8557                 service->pac_file = g_strdup(value);
8558         }
8559 #endif
8560 #if defined TIZEN_EXT
8561          else if (g_str_equal(key, "Connector")) {
8562                 g_free(service->connector);
8563                 service->connector = g_strdup(value);
8564          }      else if (g_str_equal(key, "CSignKey")) {
8565                 g_free(service->c_sign_key);
8566                 service->c_sign_key = g_strdup(value);
8567          }      else if (g_str_equal(key, "NetAccessKey")) {
8568                 g_free(service->net_access_key);
8569                 service->net_access_key = g_strdup(value);
8570         } else
8571                 DBG("Unknown key: %s", key);
8572 #endif
8573 }
8574
8575 void __connman_service_set_search_domains(struct connman_service *service,
8576                                         char **domains)
8577 {
8578         searchdomain_remove_all(service);
8579
8580         if (service->domains)
8581                 g_strfreev(service->domains);
8582
8583         service->domains = g_strdupv(domains);
8584
8585         searchdomain_add_all(service);
8586 }
8587
8588 int __connman_service_set_mdns(struct connman_service *service,
8589                         bool enabled)
8590 {
8591         service->mdns_config = enabled;
8592
8593         return set_mdns(service, enabled);
8594 }
8595
8596 static void report_error_cb(void *user_context, bool retry,
8597                                                         void *user_data)
8598 {
8599         struct connman_service *service = user_context;
8600
8601         if (retry)
8602                 __connman_service_connect(service,
8603                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
8604         else {
8605                 /* It is not relevant to stay on Failure state
8606                  * when failing is due to wrong user input */
8607                 __connman_service_clear_error(service);
8608 #if defined TIZEN_EXT
8609                 /* Reseting the state back in case of failure state */
8610                 service->state_ipv4 = service->state_ipv6 =
8611                                 CONNMAN_SERVICE_STATE_IDLE;
8612
8613                 if (service->error != CONNMAN_SERVICE_ERROR_AUTH_FAILED &&
8614                                 service->error != CONNMAN_SERVICE_ERROR_ASSOC_FAILED)
8615                         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
8616 #endif
8617                 service_complete(service);
8618                 __connman_connection_update_gateway();
8619         }
8620 }
8621
8622 static int check_wpspin(struct connman_service *service, const char *wpspin)
8623 {
8624         int length;
8625         guint i;
8626
8627         if (!wpspin)
8628                 return 0;
8629
8630         length = strlen(wpspin);
8631
8632         /* If 0, it will mean user wants to use PBC method */
8633         if (length == 0) {
8634                 connman_network_set_string(service->network,
8635                                                         "WiFi.PinWPS", NULL);
8636                 return 0;
8637         }
8638
8639         /* A WPS PIN is always 8 chars length,
8640          * its content is in digit representation.
8641          */
8642         if (length != 8)
8643                 return -ENOKEY;
8644
8645         for (i = 0; i < 8; i++)
8646                 if (!isdigit((unsigned char) wpspin[i]))
8647                         return -ENOKEY;
8648
8649         connman_network_set_string(service->network, "WiFi.PinWPS", wpspin);
8650
8651         return 0;
8652 }
8653
8654 static void request_input_cb(struct connman_service *service,
8655                         bool values_received,
8656                         const char *name, int name_len,
8657                         const char *identity, const char *passphrase,
8658                         bool wps, const char *wpspin,
8659                         const char *error, void *user_data)
8660 {
8661         struct connman_device *device;
8662         const char *security;
8663         int err = 0;
8664
8665         DBG("RequestInput return, %p", service);
8666
8667         if (error) {
8668                 DBG("error: %s", error);
8669
8670                 if (g_strcmp0(error,
8671                                 "net.connman.Agent.Error.Canceled") == 0) {
8672                         err = -ECONNABORTED;
8673
8674                         if (service->hidden)
8675                                 __connman_service_return_error(service,
8676                                                         ECONNABORTED,
8677                                                         user_data);
8678                 } else {
8679                         err = -ETIMEDOUT;
8680
8681                         if (service->hidden)
8682                                 __connman_service_return_error(service,
8683                                                         ETIMEDOUT, user_data);
8684                 }
8685
8686                 goto done;
8687         }
8688
8689         if (service->hidden && name_len > 0 && name_len <= 32) {
8690                 device = connman_network_get_device(service->network);
8691                 security = connman_network_get_string(service->network,
8692                                                         "WiFi.Security");
8693                 err = __connman_device_request_hidden_scan(device,
8694                                                 name, name_len,
8695                                                 identity, passphrase,
8696                                                 security, user_data);
8697                 if (err < 0)
8698                         __connman_service_return_error(service, -err,
8699                                                         user_data);
8700         }
8701
8702         if (!values_received || service->hidden) {
8703                 err = -EINVAL;
8704                 goto done;
8705         }
8706
8707         if (wps && service->network) {
8708                 err = check_wpspin(service, wpspin);
8709                 if (err < 0)
8710                         goto done;
8711
8712                 connman_network_set_bool(service->network, "WiFi.UseWPS", wps);
8713         }
8714
8715         if (identity)
8716                 __connman_service_set_agent_identity(service, identity);
8717
8718         if (passphrase)
8719                 err = __connman_service_set_passphrase(service, passphrase);
8720
8721  done:
8722         if (err >= 0) {
8723                 /* We forget any previous error. */
8724                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
8725
8726                 __connman_service_connect(service,
8727                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
8728
8729         } else if (err == -ENOKEY) {
8730                 __connman_service_indicate_error(service,
8731                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
8732         } else {
8733                 /* It is not relevant to stay on Failure state
8734                  * when failing is due to wrong user input */
8735                 service->state = CONNMAN_SERVICE_STATE_IDLE;
8736
8737                 if (!service->hidden) {
8738                         /*
8739                          * If there was a real error when requesting
8740                          * hidden scan, then that error is returned already
8741                          * to the user somewhere above so do not try to
8742                          * do this again.
8743                          */
8744                         __connman_service_return_error(service, -err,
8745                                                         user_data);
8746                 }
8747
8748                 service_complete(service);
8749                 __connman_connection_update_gateway();
8750         }
8751 }
8752
8753 static void downgrade_connected_services(void)
8754 {
8755         struct connman_service *up_service;
8756         GList *list;
8757
8758         for (list = service_list; list; list = list->next) {
8759                 up_service = list->data;
8760
8761                 if (!is_connected(up_service->state))
8762                         continue;
8763
8764                 if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
8765                         return;
8766
8767                 downgrade_state(up_service);
8768         }
8769 }
8770
8771 static int service_update_preferred_order(struct connman_service *default_service,
8772                 struct connman_service *new_service,
8773                 enum connman_service_state new_state)
8774 {
8775         unsigned int *tech_array;
8776         int i;
8777
8778         if (!default_service || default_service == new_service ||
8779                         default_service->state != new_state)
8780                 return 0;
8781
8782         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
8783         if (tech_array) {
8784
8785                 for (i = 0; tech_array[i] != 0; i += 1) {
8786                         if (default_service->type == tech_array[i])
8787                                 return -EALREADY;
8788
8789                         if (new_service->type == tech_array[i]) {
8790                                 switch_default_service(default_service,
8791                                                 new_service);
8792                                 __connman_connection_update_gateway();
8793                                 return 0;
8794                         }
8795                 }
8796         }
8797
8798         return -EALREADY;
8799 }
8800
8801 #if defined TIZEN_EXT
8802 static gboolean __connman_service_can_drop(struct connman_service *service)
8803 {
8804         if (is_connected(service->state) == TRUE || is_connecting(service->state) == TRUE) {
8805                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
8806                         return TRUE;
8807                 else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE)
8808                         return TRUE;
8809         }
8810         return FALSE;
8811 }
8812
8813 static struct connman_device *default_connecting_device = NULL;
8814
8815 static void __connman_service_disconnect_default(struct connman_service *service)
8816 {
8817         struct connman_device *default_device = NULL;
8818         struct connman_network *network = __connman_service_get_network(service);
8819
8820         if (!network)
8821                 return;
8822
8823         if (default_connecting_device == NULL)
8824                 return;
8825
8826         default_device = connman_network_get_device(network);
8827
8828         DBG("Disconnecting service %p %s", service, service->path);
8829         DBG("Disconnecting device %p %p %s",
8830                         default_connecting_device,
8831                         default_device,
8832                         connman_device_get_string(default_device, "Name"));
8833
8834         if (default_connecting_device == default_device)
8835                 default_connecting_device = NULL;
8836 }
8837
8838 #if defined TIZEN_MAINTAIN_ONLINE
8839 static void __connman_service_connect_default(struct connman_service *current,
8840                                                                   enum connman_service_state old_state)
8841 #else
8842 static void __connman_service_connect_default(struct connman_service *current)
8843 #endif
8844 {
8845         int err;
8846         GList *list;
8847         bool default_internet;
8848         struct connman_service *service;
8849         struct connman_service *default_service = NULL;
8850         struct connman_device *default_device = NULL;
8851
8852         if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
8853                 switch (current->state) {
8854                 case CONNMAN_SERVICE_STATE_UNKNOWN:
8855                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
8856                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
8857                         return;
8858                 default:
8859                         break;
8860                 }
8861
8862                 if (default_connecting_device &&
8863                                 __connman_service_is_internet_profile(current) == TRUE) {
8864                         if (current->network == NULL)
8865                                 return;
8866
8867                         default_device = connman_network_get_device(current->network);
8868                         if (default_connecting_device == default_device) {
8869                                 DBG("Cellular service[%s]  %p %s",
8870                                                 state2string(current->state), current, current->path);
8871                                 DBG("Cellular device %p %p %s",
8872                                                 default_connecting_device, default_device,
8873                                                 connman_device_get_string(default_device, "Name"));
8874
8875                                 default_connecting_device = NULL;
8876                         }
8877                 }
8878
8879                 return;
8880 #if defined TIZEN_MAINTAIN_ONLINE
8881         } else if (current->state == CONNMAN_SERVICE_STATE_READY &&
8882                            old_state == CONNMAN_SERVICE_STATE_ONLINE) {
8883                 DBG("Device is downgraded: online --> ready");
8884 #endif
8885         } else if (is_connected(current->state) == TRUE || is_connecting(current->state) == TRUE)
8886                 return;
8887
8888         /* Always-on: keep default cellular connection as possible */
8889         for (list = service_list; list; list = list->next) {
8890                 service = list->data;
8891
8892                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
8893                                 __connman_service_is_internet_profile(service) != TRUE ||
8894                                 service->network == NULL) {
8895                         continue;
8896                 }
8897
8898                 default_internet =
8899                                 connman_network_get_bool(service->network, "DefaultInternet");
8900
8901                 DBG("service: %p %s %s %s (default: %d)", service, service->name,
8902                                 __connman_service_type2string(service->type),
8903                                 state2string(service->state), default_internet);
8904
8905                 if (default_internet) {
8906                         default_service = service;
8907                         if (is_connected(default_service->state) == TRUE ||
8908                                         is_connecting(default_service->state) == TRUE)
8909                                 return;
8910
8911                         default_device = connman_network_get_device(default_service->network);
8912                         if (default_connecting_device == default_device) {
8913                                 DBG("Device is connecting (%p)", default_connecting_device);
8914                                 return;
8915                         }
8916
8917                         default_connecting_device = default_device;
8918                         default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
8919
8920                         err = __connman_network_connect(default_service->network);
8921                         DBG("Connecting default service %p %s [%d]",
8922                                         default_service, default_service->path, err);
8923                         DBG("Connecting device %p %s", default_connecting_device,
8924                                         connman_device_get_string(default_connecting_device, "Name"));
8925                         if (err < 0 && err != -EINPROGRESS) {
8926                                 default_connecting_device = NULL;
8927                         } else
8928                                 break;
8929                 }
8930         }
8931 }
8932 #endif
8933
8934 static void single_connected_tech(struct connman_service *allowed)
8935 {
8936         struct connman_service *service;
8937         GSList *services = NULL, *list;
8938         GList *iter;
8939
8940         DBG("keeping %p %s", allowed, allowed->path);
8941
8942 #if defined TIZEN_EXT
8943         if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR)
8944                 return;
8945 #endif
8946
8947         for (iter = service_list; iter; iter = iter->next) {
8948                 service = iter->data;
8949
8950 #if defined TIZEN_EXT
8951                 if (service != allowed && service->type != allowed->type &&
8952                                 __connman_service_can_drop(service) == TRUE)
8953 #else
8954                 if (!is_connected(service->state))
8955                         break;
8956
8957                 if (service == allowed)
8958                         continue;
8959 #endif
8960
8961                 services = g_slist_prepend(services, service);
8962         }
8963
8964         for (list = services; list; list = list->next) {
8965                 service = list->data;
8966
8967                 DBG("disconnecting %p %s", service, service->path);
8968 #if defined TIZEN_EXT
8969                 __connman_service_disconnect_default(service);
8970 #endif
8971                 __connman_service_disconnect(service);
8972         }
8973
8974         g_slist_free(services);
8975 }
8976
8977 #if defined TIZEN_EXT
8978 static void set_priority_connected_service(void)
8979 {
8980         struct connman_service *service;
8981         GList *list;
8982
8983         for (list = service_list; list; list = list->next) {
8984                 service = list->data;
8985
8986                 if (is_connected(service->state) == FALSE)
8987                         service->order = 5;
8988                 else
8989 #if defined TIZEN_MAINTAIN_ONLINE
8990                 {
8991                         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
8992                                 service->state == CONNMAN_SERVICE_STATE_ONLINE)
8993                                 service->order = 6;
8994                         else if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
8995                                 service->order = 6;
8996                         else
8997                                 service->order = 5;
8998                 }
8999 #else
9000                         service->order = 6;
9001 #endif
9002         }
9003 }
9004 #endif
9005
9006 static const char *get_dbus_sender(struct connman_service *service)
9007 {
9008         if (!service->pending)
9009                 return NULL;
9010
9011         return dbus_message_get_sender(service->pending);
9012 }
9013
9014 static int service_indicate_state(struct connman_service *service)
9015 {
9016         enum connman_service_state old_state, new_state;
9017         struct connman_service *def_service;
9018         enum connman_ipconfig_method method;
9019         int result;
9020
9021         if (!service)
9022                 return -EINVAL;
9023
9024         old_state = service->state;
9025         new_state = combine_state(service->state_ipv4, service->state_ipv6);
9026
9027         DBG("service %p old %s - new %s/%s => %s",
9028                                         service,
9029                                         state2string(old_state),
9030                                         state2string(service->state_ipv4),
9031                                         state2string(service->state_ipv6),
9032                                         state2string(new_state));
9033
9034         if (old_state == new_state)
9035                 return -EALREADY;
9036
9037         def_service = connman_service_get_default();
9038
9039         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
9040                 result = service_update_preferred_order(def_service,
9041                                 service, new_state);
9042                 if (result == -EALREADY)
9043                         return result;
9044         }
9045
9046         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
9047                 __connman_notifier_leave_online(service->type);
9048
9049         if (is_connected(old_state) && !is_connected(new_state))
9050                 searchdomain_remove_all(service);
9051
9052         service->state = new_state;
9053 #if defined TIZEN_EXT
9054         if (!is_connected(old_state) && is_connected(new_state))
9055                 connman_device_send_connected_signal(
9056                                 connman_network_get_device(service->network), true);
9057         else if (is_connected(old_state) && !is_connected(new_state))
9058                 connman_device_send_connected_signal(
9059                                 connman_network_get_device(service->network), false);
9060 #endif
9061         state_changed(service);
9062
9063         if (!is_connected(old_state) && is_connected(new_state))
9064                 searchdomain_add_all(service);
9065
9066         switch(new_state) {
9067         case CONNMAN_SERVICE_STATE_UNKNOWN:
9068
9069                 break;
9070
9071         case CONNMAN_SERVICE_STATE_IDLE:
9072                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
9073                         __connman_service_disconnect(service);
9074
9075                 break;
9076
9077         case CONNMAN_SERVICE_STATE_ASSOCIATION:
9078
9079                 break;
9080
9081         case CONNMAN_SERVICE_STATE_CONFIGURATION:
9082                 if (!service->new_service &&
9083                                 __connman_stats_service_register(service) == 0) {
9084                         /*
9085                          * For new services the statistics are updated after
9086                          * we have successfully connected.
9087                          */
9088                         __connman_stats_get(service, false,
9089                                                 &service->stats.data);
9090                         __connman_stats_get(service, true,
9091                                                 &service->stats_roaming.data);
9092                 }
9093
9094                 break;
9095
9096         case CONNMAN_SERVICE_STATE_READY:
9097                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
9098
9099                 if (service->new_service &&
9100                                 __connman_stats_service_register(service) == 0) {
9101                         /*
9102                          * This is normally done after configuring state
9103                          * but for new service do this after we have connected
9104                          * successfully.
9105                          */
9106                         __connman_stats_get(service, false,
9107                                                 &service->stats.data);
9108                         __connman_stats_get(service, true,
9109                                                 &service->stats_roaming.data);
9110                 }
9111
9112                 service->new_service = false;
9113
9114                 default_changed();
9115
9116                 def_service = connman_service_get_default();
9117
9118                 service_update_preferred_order(def_service, service, new_state);
9119
9120                 __connman_service_set_favorite(service, true);
9121
9122                 reply_pending(service, 0);
9123
9124                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
9125                         connman_network_get_bool(service->network,
9126                                                 "WiFi.UseWPS")) {
9127                         const char *pass;
9128
9129                         pass = connman_network_get_string(service->network,
9130                                                         "WiFi.Passphrase");
9131
9132                         __connman_service_set_passphrase(service, pass);
9133
9134                         connman_network_set_bool(service->network,
9135                                                         "WiFi.UseWPS", false);
9136                 }
9137
9138                 gettimeofday(&service->modified, NULL);
9139                 service_save(service);
9140
9141                 domain_changed(service);
9142                 proxy_changed(service);
9143
9144                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
9145                         __connman_notifier_connect(service->type);
9146
9147                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
9148                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
9149                         __connman_ipconfig_disable_ipv6(
9150                                                 service->ipconfig_ipv6);
9151
9152 #if !defined TIZEN_MAINTAIN_ONLINE
9153                 if (connman_setting_get_bool("SingleConnectedTechnology"))
9154                         single_connected_tech(service);
9155                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
9156                         vpn_auto_connect();
9157 #else
9158                 if (service->type != CONNMAN_SERVICE_TYPE_VPN)
9159                         vpn_auto_connect();
9160 #endif
9161
9162 #if defined TIZEN_EXT
9163                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
9164                         set_priority_connected_service();
9165 #endif
9166
9167                 break;
9168
9169         case CONNMAN_SERVICE_STATE_ONLINE:
9170 #if defined TIZEN_MAINTAIN_ONLINE
9171 #if defined TIZEN_EXT
9172                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
9173                         set_priority_connected_service();
9174 #endif
9175
9176                 if (connman_setting_get_bool("SingleConnectedTechnology"))
9177                         single_connected_tech(service);
9178 #endif
9179
9180 #if defined TIZEN_EXT
9181                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
9182                         connman_service_set_internet_connection(service, true);
9183 #endif
9184                 break;
9185
9186         case CONNMAN_SERVICE_STATE_DISCONNECT:
9187                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
9188
9189                 reply_pending(service, ECONNABORTED);
9190
9191                 default_changed();
9192
9193                 __connman_wispr_stop(service);
9194
9195                 __connman_wpad_stop(service);
9196
9197 #if defined TIZEN_EXT
9198                 /**
9199                  * Skip the functions if there is any connected profiles
9200                  * that use same interface
9201                  */
9202                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
9203                         __connman_service_get_connected_count_of_iface(
9204                                                         service) <= 0) {
9205 #endif
9206                 domain_changed(service);
9207                 proxy_changed(service);
9208 #if defined TIZEN_EXT
9209                 }
9210 #endif
9211
9212                 /*
9213                  * Previous services which are connected and which states
9214                  * are set to online should reset relevantly ipconfig_state
9215                  * to ready so wispr/portal will be rerun on those
9216                  */
9217                 downgrade_connected_services();
9218
9219                 do_auto_connect(service, CONNMAN_SERVICE_CONNECT_REASON_AUTO);
9220                 break;
9221
9222         case CONNMAN_SERVICE_STATE_FAILURE:
9223 #if defined TIZEN_EXT
9224                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
9225                         service->order = 5;
9226                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
9227 #endif
9228                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
9229                         connman_agent_report_error(service, service->path,
9230                                                 error2string(service->error),
9231                                                 report_error_cb,
9232                                                 get_dbus_sender(service),
9233                                                 NULL);
9234                 }
9235                 service_complete(service);
9236                 break;
9237         }
9238
9239         service_list_sort();
9240
9241 #if defined TIZEN_EXT
9242 #if defined TIZEN_MAINTAIN_ONLINE
9243         __connman_service_connect_default(service, old_state);
9244 #else
9245         __connman_service_connect_default(service);
9246 #endif
9247         /* Update Wi-Fi Roaming result */
9248         if (connman_setting_get_bool("WifiRoaming") &&
9249                         connman_network_get_bool(service->network, "WiFi.Roaming")) {
9250                 const char *cur_bssid;
9251                 const char *dst_bssid;
9252                 const char *ifname;
9253                 struct connman_device *device;
9254
9255                 device = connman_network_get_device(service->network);
9256                 if (device) {
9257                         ifname = connman_device_get_string(device, "Interface");
9258                         cur_bssid = connman_network_get_string(service->network,
9259                                                 "WiFi.RoamingCurBSSID");
9260                         dst_bssid = connman_network_get_string(service->network,
9261                                                 "WiFi.RoamingDstBSSID");
9262                 }
9263
9264                 if (device && ifname && cur_bssid && dst_bssid) {
9265                         switch(new_state) {
9266                         case CONNMAN_SERVICE_STATE_UNKNOWN:
9267                         case CONNMAN_SERVICE_STATE_ASSOCIATION:
9268                         case CONNMAN_SERVICE_STATE_CONFIGURATION:
9269                                 break;
9270                         case CONNMAN_SERVICE_STATE_READY:
9271                         case CONNMAN_SERVICE_STATE_ONLINE:
9272                                 __connman_technology_notify_roaming_state(ifname,
9273                                                 "success", cur_bssid, dst_bssid);
9274                                 connman_network_set_bool(service->network,
9275                                                 "WiFi.Roaming", false);
9276                                 connman_network_set_string(service->network,
9277                                                 "WiFi.RoamingCurBSSID", NULL);
9278                                 connman_network_set_string(service->network,
9279                                                 "WiFi.RoamingDstBSSID", NULL);
9280                                 break;
9281                         case CONNMAN_SERVICE_STATE_DISCONNECT:
9282                         case CONNMAN_SERVICE_STATE_FAILURE:
9283                         case CONNMAN_SERVICE_STATE_IDLE:
9284                                 __connman_technology_notify_roaming_state(ifname,
9285                                                 "failure", cur_bssid, dst_bssid);
9286                                 connman_network_set_bool(service->network,
9287                                                 "WiFi.Roaming", false);
9288                                 connman_network_set_string(service->network,
9289                                                 "WiFi.RoamingCurBSSID", NULL);
9290                                 connman_network_set_string(service->network,
9291                                                 "WiFi.RoamingDstBSSID", NULL);
9292                                 break;
9293                         }
9294                 }
9295         }
9296 #endif
9297
9298         __connman_connection_update_gateway();
9299
9300         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
9301                         new_state != CONNMAN_SERVICE_STATE_READY) ||
9302                 (old_state == CONNMAN_SERVICE_STATE_READY &&
9303                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
9304                 __connman_notifier_disconnect(service->type);
9305         }
9306
9307         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
9308                 __connman_notifier_enter_online(service->type);
9309                 default_changed();
9310         }
9311
9312         return 0;
9313 }
9314
9315 int __connman_service_indicate_error(struct connman_service *service,
9316                                         enum connman_service_error error)
9317 {
9318         DBG("service %p error %d", service, error);
9319
9320         if (!service)
9321                 return -EINVAL;
9322
9323         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
9324                 return -EALREADY;
9325
9326         set_error(service, error);
9327
9328 /* default internet service: fix not cleared if pdp activation*/
9329 #if defined TIZEN_EXT
9330                 /*
9331                  * If connection failed for default service(DefaultInternet),
9332                  * default_connecting_device should be cleared.
9333                  */
9334                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
9335                                 service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED)
9336                         __connman_service_disconnect_default(service);
9337
9338                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
9339                                 service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) {
9340                         g_free(service->passphrase);
9341                         service->passphrase = NULL;
9342                 }
9343 #endif
9344
9345         __connman_service_ipconfig_indicate_state(service,
9346                                                 CONNMAN_SERVICE_STATE_FAILURE,
9347                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
9348         __connman_service_ipconfig_indicate_state(service,
9349                                                 CONNMAN_SERVICE_STATE_FAILURE,
9350                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
9351         return 0;
9352 }
9353
9354 int __connman_service_clear_error(struct connman_service *service)
9355 {
9356         DBusMessage *pending, *provider_pending;
9357
9358         DBG("service %p", service);
9359
9360         if (!service)
9361                 return -EINVAL;
9362
9363         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
9364                 return -EINVAL;
9365
9366         pending = service->pending;
9367         service->pending = NULL;
9368         provider_pending = service->provider_pending;
9369         service->provider_pending = NULL;
9370
9371         __connman_service_ipconfig_indicate_state(service,
9372                                                 CONNMAN_SERVICE_STATE_IDLE,
9373                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
9374
9375         __connman_service_ipconfig_indicate_state(service,
9376                                                 CONNMAN_SERVICE_STATE_IDLE,
9377                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
9378
9379         service->pending = pending;
9380         service->provider_pending = provider_pending;
9381
9382         return 0;
9383 }
9384
9385 int __connman_service_indicate_default(struct connman_service *service)
9386 {
9387         DBG("service %p state %s", service, state2string(service->state));
9388
9389         if (!is_connected(service->state)) {
9390                 /*
9391                  * If service is not yet fully connected, then we must not
9392                  * change the default yet. The default gw will be changed
9393                  * after the service state is in ready.
9394                  */
9395                 return -EINPROGRESS;
9396         }
9397
9398         default_changed();
9399
9400         return 0;
9401 }
9402
9403 enum connman_service_state __connman_service_ipconfig_get_state(
9404                                         struct connman_service *service,
9405                                         enum connman_ipconfig_type type)
9406 {
9407         if (!service)
9408                 return CONNMAN_SERVICE_STATE_UNKNOWN;
9409
9410         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9411                 return service->state_ipv4;
9412
9413         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
9414                 return service->state_ipv6;
9415
9416         return CONNMAN_SERVICE_STATE_UNKNOWN;
9417 }
9418
9419 #if defined TIZEN_EXT
9420 void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
9421
9422         DBG("check the proxy and start wispr");
9423         check_proxy_setup(service);
9424         return;
9425 }
9426 #endif
9427
9428 /*
9429  * How many networks are connected at the same time. If more than 1,
9430  * then set the rp_filter setting properly (loose mode routing) so that network
9431  * connectivity works ok. This is only done for IPv4 networks as IPv6
9432  * does not have rp_filter knob.
9433  */
9434 static int connected_networks_count;
9435 static int original_rp_filter;
9436
9437 static void service_rp_filter(struct connman_service *service,
9438                                 bool connected)
9439 {
9440         enum connman_ipconfig_method method;
9441
9442         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
9443
9444         switch (method) {
9445         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
9446         case CONNMAN_IPCONFIG_METHOD_OFF:
9447         case CONNMAN_IPCONFIG_METHOD_AUTO:
9448                 return;
9449         case CONNMAN_IPCONFIG_METHOD_FIXED:
9450         case CONNMAN_IPCONFIG_METHOD_MANUAL:
9451         case CONNMAN_IPCONFIG_METHOD_DHCP:
9452                 break;
9453         }
9454
9455         if (connected) {
9456                 if (connected_networks_count == 1) {
9457                         int filter_value;
9458                         filter_value = __connman_ipconfig_set_rp_filter();
9459                         if (filter_value < 0)
9460                                 return;
9461
9462                         original_rp_filter = filter_value;
9463                 }
9464                 connected_networks_count++;
9465
9466         } else {
9467                 if (connected_networks_count == 2)
9468                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
9469
9470                 connected_networks_count--;
9471                 if (connected_networks_count < 0)
9472                         connected_networks_count = 0;
9473         }
9474
9475         DBG("%s %s ipconfig %p method %d count %d filter %d",
9476                 connected ? "connected" : "disconnected", service->identifier,
9477                 service->ipconfig_ipv4, method,
9478                 connected_networks_count, original_rp_filter);
9479 }
9480
9481 static void redo_wispr(struct connman_service *service,
9482                                         enum connman_ipconfig_type type)
9483 {
9484         service->online_timeout = 0;
9485         connman_service_unref(service);
9486
9487         DBG("Retrying %s WISPr for %p %s",
9488                 __connman_ipconfig_type2string(type),
9489                 service, service->name);
9490
9491         __connman_wispr_start(service, type);
9492 }
9493
9494 static gboolean redo_wispr_ipv4(gpointer user_data)
9495 {
9496         struct connman_service *service = user_data;
9497
9498 #if defined TIZEN_MAINTAIN_ONLINE
9499         DBG("");
9500
9501         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
9502 #else
9503         redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV4);
9504 #endif
9505
9506         return FALSE;
9507 }
9508
9509 static gboolean redo_wispr_ipv6(gpointer user_data)
9510 {
9511         struct connman_service *service = user_data;
9512
9513         redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV6);
9514
9515         return FALSE;
9516 }
9517
9518 int __connman_service_online_check_failed(struct connman_service *service,
9519                                         enum connman_ipconfig_type type)
9520 {
9521         GSourceFunc redo_func;
9522         int *interval;
9523
9524         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
9525                 interval = &service->online_check_interval_ipv4;
9526                 redo_func = redo_wispr_ipv4;
9527         } else {
9528                 interval = &service->online_check_interval_ipv6;
9529                 redo_func = redo_wispr_ipv6;
9530         }
9531
9532         DBG("service %p type %s interval %d", service,
9533                 __connman_ipconfig_type2string(type), *interval);
9534
9535         service->online_timeout = g_timeout_add_seconds(*interval * *interval,
9536                                 redo_func, connman_service_ref(service));
9537
9538         /* Increment the interval for the next time, set a maximum timeout of
9539          * ONLINE_CHECK_MAX_INTERVAL * ONLINE_CHECK_MAX_INTERVAL seconds.
9540          */
9541         if (*interval < ONLINE_CHECK_MAX_INTERVAL)
9542                 (*interval)++;
9543
9544         return EAGAIN;
9545 }
9546
9547 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
9548                                         enum connman_service_state new_state,
9549                                         enum connman_ipconfig_type type)
9550 {
9551         struct connman_ipconfig *ipconfig = NULL;
9552         enum connman_service_state old_state;
9553         enum connman_ipconfig_method method;
9554
9555         if (!service)
9556                 return -EINVAL;
9557
9558         switch (type) {
9559         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
9560         case CONNMAN_IPCONFIG_TYPE_ALL:
9561                 return -EINVAL;
9562
9563         case CONNMAN_IPCONFIG_TYPE_IPV4:
9564                 old_state = service->state_ipv4;
9565                 ipconfig = service->ipconfig_ipv4;
9566
9567                 break;
9568
9569         case CONNMAN_IPCONFIG_TYPE_IPV6:
9570                 old_state = service->state_ipv6;
9571                 ipconfig = service->ipconfig_ipv6;
9572
9573                 break;
9574         }
9575
9576         if (!ipconfig)
9577                 return -EINVAL;
9578
9579         method = __connman_ipconfig_get_method(ipconfig);
9580
9581         switch (method) {
9582         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
9583         case CONNMAN_IPCONFIG_METHOD_OFF:
9584                 if (new_state != CONNMAN_SERVICE_STATE_IDLE)
9585                         connman_warn("ipconfig state %d ipconfig method %d",
9586                                 new_state, method);
9587
9588 #if defined TIZEN_EXT
9589                 if (old_state != CONNMAN_SERVICE_STATE_READY &&
9590                                 old_state != CONNMAN_SERVICE_STATE_ONLINE)
9591 #endif
9592                 new_state = CONNMAN_SERVICE_STATE_IDLE;
9593                 break;
9594
9595         case CONNMAN_IPCONFIG_METHOD_FIXED:
9596         case CONNMAN_IPCONFIG_METHOD_MANUAL:
9597         case CONNMAN_IPCONFIG_METHOD_DHCP:
9598         case CONNMAN_IPCONFIG_METHOD_AUTO:
9599                 break;
9600
9601         }
9602
9603         /* Any change? */
9604         if (old_state == new_state)
9605                 return -EALREADY;
9606
9607 #if defined TIZEN_EXT
9608         __sync_synchronize();
9609         if (service->user_pdn_connection_refcount > 0 &&
9610                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
9611                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
9612                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
9613                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
9614                         service->user_pdn_connection_refcount = 0;
9615                         __sync_synchronize();
9616                 }
9617 #endif
9618
9619         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
9620                 service, service ? service->identifier : NULL,
9621                 old_state, state2string(old_state),
9622                 new_state, state2string(new_state),
9623                 type, __connman_ipconfig_type2string(type));
9624
9625         switch (new_state) {
9626         case CONNMAN_SERVICE_STATE_UNKNOWN:
9627         case CONNMAN_SERVICE_STATE_ASSOCIATION:
9628                 break;
9629         case CONNMAN_SERVICE_STATE_CONFIGURATION:
9630                 break;
9631         case CONNMAN_SERVICE_STATE_READY:
9632 #if defined TIZEN_EXT
9633                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
9634                                 __connman_service_is_internet_profile(service) != TRUE) {
9635                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9636                                 service_rp_filter(service, TRUE);
9637
9638                         break;
9639                 }
9640 #endif
9641                 if (connman_setting_get_bool("EnableOnlineCheck"))
9642                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
9643 #if !defined TIZEN_EXT
9644                                 check_proxy_setup(service);
9645 #endif
9646 #if defined TIZEN_MAINTAIN_ONLINE
9647 /*                              if (old_state == CONNMAN_SERVICE_STATE_ONLINE) */
9648                                         check_proxy_setup(service);
9649 #endif
9650                         } else {
9651                                 __connman_service_wispr_start(service, type);
9652                         }
9653                 else
9654                         connman_info("Online check disabled. "
9655                                 "Default service remains in READY state.");
9656                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9657                         service_rp_filter(service, true);
9658                 set_mdns(service, service->mdns_config);
9659                 break;
9660         case CONNMAN_SERVICE_STATE_ONLINE:
9661                 break;
9662         case CONNMAN_SERVICE_STATE_DISCONNECT:
9663                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
9664                         return -EINVAL;
9665
9666                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9667                         service_rp_filter(service, false);
9668
9669                 break;
9670
9671         case CONNMAN_SERVICE_STATE_IDLE:
9672         case CONNMAN_SERVICE_STATE_FAILURE:
9673                 __connman_ipconfig_disable(ipconfig);
9674
9675                 break;
9676         }
9677
9678         if (is_connected(old_state) && !is_connected(new_state)) {
9679                 nameserver_remove_all(service, type);
9680                 cancel_online_check(service);
9681         }
9682
9683         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9684                 service->state_ipv4 = new_state;
9685         else
9686                 service->state_ipv6 = new_state;
9687
9688         if (!is_connected(old_state) && is_connected(new_state))
9689                 nameserver_add_all(service, type);
9690
9691         __connman_timeserver_sync(service);
9692
9693 #if defined TIZEN_EXT
9694         int ret = service_indicate_state(service);
9695         /*Sent the Ready changed signal again in case IPv4 IP set
9696           after IPv6 IP set*/
9697
9698         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
9699                         && new_state == CONNMAN_SERVICE_STATE_READY) {
9700                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
9701                 state_changed(service);
9702         }
9703
9704         return ret;
9705 #endif
9706         return service_indicate_state(service);
9707 }
9708
9709 static bool prepare_network(struct connman_service *service)
9710 {
9711         enum connman_network_type type;
9712         unsigned int ssid_len;
9713
9714         type = connman_network_get_type(service->network);
9715
9716         switch (type) {
9717         case CONNMAN_NETWORK_TYPE_UNKNOWN:
9718         case CONNMAN_NETWORK_TYPE_VENDOR:
9719                 return false;
9720         case CONNMAN_NETWORK_TYPE_WIFI:
9721                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
9722                                                 &ssid_len))
9723                         return false;
9724
9725                 if (service->passphrase)
9726                         connman_network_set_string(service->network,
9727                                 "WiFi.Passphrase", service->passphrase);
9728                 break;
9729         case CONNMAN_NETWORK_TYPE_ETHERNET:
9730         case CONNMAN_NETWORK_TYPE_GADGET:
9731         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
9732         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
9733         case CONNMAN_NETWORK_TYPE_CELLULAR:
9734                 break;
9735         }
9736
9737         return true;
9738 }
9739
9740 static void prepare_8021x(struct connman_service *service)
9741 {
9742         if (service->eap)
9743                 connman_network_set_string(service->network, "WiFi.EAP",
9744                                                                 service->eap);
9745
9746         if (service->identity)
9747                 connman_network_set_string(service->network, "WiFi.Identity",
9748                                                         service->identity);
9749
9750         if (service->anonymous_identity)
9751                 connman_network_set_string(service->network,
9752                                                 "WiFi.AnonymousIdentity",
9753                                                 service->anonymous_identity);
9754
9755         if (service->ca_cert_file)
9756                 connman_network_set_string(service->network, "WiFi.CACertFile",
9757                                                         service->ca_cert_file);
9758
9759         if (service->subject_match)
9760                 connman_network_set_string(service->network, "WiFi.SubjectMatch",
9761                                                         service->subject_match);
9762
9763         if (service->altsubject_match)
9764                 connman_network_set_string(service->network, "WiFi.AltSubjectMatch",
9765                                                         service->altsubject_match);
9766
9767         if (service->domain_suffix_match)
9768                 connman_network_set_string(service->network, "WiFi.DomainSuffixMatch",
9769                                                         service->domain_suffix_match);
9770
9771         if (service->domain_match)
9772                 connman_network_set_string(service->network, "WiFi.DomainMatch",
9773                                                         service->domain_match);
9774
9775         if (service->client_cert_file)
9776                 connman_network_set_string(service->network,
9777                                                 "WiFi.ClientCertFile",
9778                                                 service->client_cert_file);
9779
9780         if (service->private_key_file)
9781                 connman_network_set_string(service->network,
9782                                                 "WiFi.PrivateKeyFile",
9783                                                 service->private_key_file);
9784
9785         if (service->private_key_passphrase)
9786                 connman_network_set_string(service->network,
9787                                         "WiFi.PrivateKeyPassphrase",
9788                                         service->private_key_passphrase);
9789
9790         if (service->phase2)
9791                 connman_network_set_string(service->network, "WiFi.Phase2",
9792                                                         service->phase2);
9793
9794 #if defined TIZEN_EXT
9795         if (service->keymgmt_type)
9796                 connman_network_set_string(service->network, "WiFi.KeymgmtType",
9797                                                         service->keymgmt_type);
9798
9799         DBG("service->phase1 : %s", service->phase1);
9800         if (service->phase1)
9801                 connman_network_set_string(service->network, "WiFi.Phase1",
9802                                                         service->phase1);
9803 #endif
9804 }
9805 #if defined TIZEN_EXT
9806
9807 static bool has_valid_configuration_object(struct connman_service *service)
9808 {
9809         return service->connector && service->c_sign_key && service->net_access_key;
9810 }
9811
9812 static void prepare_dpp(struct connman_service *service)
9813 {
9814         DBG("prepare dpp");
9815         if (service->connector)
9816                 connman_network_set_string(service->network, "WiFi.Connector",
9817                                                                 service->connector);
9818
9819         if (service->c_sign_key)
9820                 connman_network_set_string(service->network, "WiFi.CSignKey",
9821                                                         service->c_sign_key);
9822
9823         if (service->net_access_key)
9824                 connman_network_set_string(service->network, "WiFi.NetAccessKey",
9825                                                         service->net_access_key);
9826 }
9827 #endif
9828
9829 static int service_connect(struct connman_service *service)
9830 {
9831         int err;
9832
9833         if (service->hidden)
9834                 return -EPERM;
9835
9836 #if defined TIZEN_EXT
9837         GList *list;
9838         int index;
9839
9840         index = __connman_service_get_index(service);
9841
9842         for (list = service_list; list; list = list->next) {
9843                 struct connman_service *temp = list->data;
9844
9845                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
9846                         break;
9847
9848                 if (!is_connecting(temp->state) && !is_connected(temp->state))
9849                         break;
9850
9851                 if (service == temp)
9852                         continue;
9853
9854                 if (service->type != temp->type)
9855                         continue;
9856
9857                 if (__connman_service_get_index(temp) == index &&
9858                                 __connman_service_disconnect(temp) == -EINPROGRESS)
9859                         return -EINPROGRESS;
9860         }
9861 #endif
9862
9863         switch (service->type) {
9864         case CONNMAN_SERVICE_TYPE_UNKNOWN:
9865         case CONNMAN_SERVICE_TYPE_SYSTEM:
9866         case CONNMAN_SERVICE_TYPE_GPS:
9867         case CONNMAN_SERVICE_TYPE_P2P:
9868 #if defined TIZEN_EXT_WIFI_MESH
9869         case CONNMAN_SERVICE_TYPE_MESH:
9870 #endif
9871                 return -EINVAL;
9872         case CONNMAN_SERVICE_TYPE_ETHERNET:
9873         case CONNMAN_SERVICE_TYPE_GADGET:
9874         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
9875         case CONNMAN_SERVICE_TYPE_CELLULAR:
9876         case CONNMAN_SERVICE_TYPE_VPN:
9877                 break;
9878         case CONNMAN_SERVICE_TYPE_WIFI:
9879                 switch (service->security) {
9880                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
9881                 case CONNMAN_SERVICE_SECURITY_NONE:
9882 #if defined TIZEN_EXT
9883                 case CONNMAN_SERVICE_SECURITY_OWE:
9884 #endif
9885                         break;
9886                 case CONNMAN_SERVICE_SECURITY_WEP:
9887                 case CONNMAN_SERVICE_SECURITY_PSK:
9888                 case CONNMAN_SERVICE_SECURITY_WPA:
9889                 case CONNMAN_SERVICE_SECURITY_RSN:
9890 #if defined TIZEN_EXT
9891                 case CONNMAN_SERVICE_SECURITY_SAE:
9892 #endif
9893                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
9894                                 return -ENOKEY;
9895
9896                         if (!service->passphrase) {
9897                                 if (!service->network)
9898                                         return -EOPNOTSUPP;
9899
9900                                 if (!service->wps ||
9901                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
9902                                         return -ENOKEY;
9903                         }
9904                         break;
9905
9906 #if defined TIZEN_EXT
9907                 case CONNMAN_SERVICE_SECURITY_DPP:
9908                         if (has_valid_configuration_object(service) &&
9909                                         !service->network)
9910                                 return -EINVAL;
9911                         break;
9912 #endif
9913                 case CONNMAN_SERVICE_SECURITY_8021X:
9914                         if (!service->eap) {
9915                                 connman_warn("EAP type has not been found. "
9916                                         "Most likely ConnMan is not able to "
9917                                         "find a configuration for given "
9918                                         "8021X network. "
9919                                         "Check SSID or Name match with the "
9920                                         "network name.");
9921                                 return -EINVAL;
9922                         }
9923
9924 #if defined TIZEN_EXT
9925                         /*
9926                          * never request credentials if using EAP-TLS, EAP-SIM
9927                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
9928                          * need to be fully provisioned)
9929                          */
9930                         DBG("service eap: %s", service->eap);
9931                         if (g_str_equal(service->eap, "tls") ||
9932                                 g_str_equal(service->eap, "sim") ||
9933                                 g_str_equal(service->eap, "aka") ||
9934                                 g_str_equal(service->eap, "aka'") ||
9935                                 g_str_equal(service->eap, "pwd") ||
9936                                 g_str_equal(service->eap, "fast"))
9937                                 break;
9938 #else
9939                         /*
9940                          * never request credentials if using EAP-TLS
9941                          * (EAP-TLS networks need to be fully provisioned)
9942                          */
9943                         if (g_str_equal(service->eap, "tls"))
9944                                 break;
9945
9946 #endif
9947                         /*
9948                          * Return -ENOKEY if either identity or passphrase is
9949                          * missing. Agent provided credentials can be used as
9950                          * fallback if needed.
9951                          */
9952                         if (((!service->identity &&
9953                                         !service->agent_identity) ||
9954                                         !service->passphrase) ||
9955                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
9956                                 return -ENOKEY;
9957
9958                         break;
9959                 }
9960                 break;
9961         }
9962
9963         if (service->network) {
9964                 if (!prepare_network(service))
9965                         return -EINVAL;
9966
9967                 switch (service->security) {
9968                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
9969                 case CONNMAN_SERVICE_SECURITY_NONE:
9970                 case CONNMAN_SERVICE_SECURITY_WEP:
9971                 case CONNMAN_SERVICE_SECURITY_PSK:
9972                 case CONNMAN_SERVICE_SECURITY_WPA:
9973                 case CONNMAN_SERVICE_SECURITY_RSN:
9974 #if defined TIZEN_EXT
9975                 case CONNMAN_SERVICE_SECURITY_SAE:
9976                 case CONNMAN_SERVICE_SECURITY_OWE:
9977                         break;
9978                 case CONNMAN_SERVICE_SECURITY_DPP:
9979                         prepare_dpp(service);
9980 #endif
9981                         break;
9982                 case CONNMAN_SERVICE_SECURITY_8021X:
9983                         prepare_8021x(service);
9984                         break;
9985                 }
9986
9987                 if (__connman_stats_service_register(service) == 0) {
9988                         __connman_stats_get(service, false,
9989                                                 &service->stats.data);
9990                         __connman_stats_get(service, true,
9991                                                 &service->stats_roaming.data);
9992                 }
9993
9994                 err = __connman_network_connect(service->network);
9995         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
9996                                         service->provider)
9997                 err = __connman_provider_connect(service->provider,
9998                                                 get_dbus_sender(service));
9999         else
10000                 return -EOPNOTSUPP;
10001
10002         if (err < 0) {
10003                 if (err != -EINPROGRESS) {
10004                         __connman_service_ipconfig_indicate_state(service,
10005                                                 CONNMAN_SERVICE_STATE_FAILURE,
10006                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
10007                         __connman_service_ipconfig_indicate_state(service,
10008                                                 CONNMAN_SERVICE_STATE_FAILURE,
10009                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
10010                         __connman_stats_service_unregister(service);
10011                 }
10012         }
10013
10014         return err;
10015 }
10016
10017 int __connman_service_connect(struct connman_service *service,
10018                         enum connman_service_connect_reason reason)
10019 {
10020         int err;
10021
10022         DBG("service %p state %s connect reason %s -> %s",
10023                 service, state2string(service->state),
10024                 reason2string(service->connect_reason),
10025                 reason2string(reason));
10026
10027         if (is_connected(service->state))
10028                 return -EISCONN;
10029
10030         if (is_connecting(service->state))
10031                 return -EALREADY;
10032
10033         switch (service->type) {
10034         case CONNMAN_SERVICE_TYPE_UNKNOWN:
10035         case CONNMAN_SERVICE_TYPE_SYSTEM:
10036         case CONNMAN_SERVICE_TYPE_GPS:
10037         case CONNMAN_SERVICE_TYPE_P2P:
10038 #if defined TIZEN_EXT_WIFI_MESH
10039         case CONNMAN_SERVICE_TYPE_MESH:
10040 #endif
10041                 return -EINVAL;
10042
10043         case CONNMAN_SERVICE_TYPE_ETHERNET:
10044         case CONNMAN_SERVICE_TYPE_GADGET:
10045         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
10046         case CONNMAN_SERVICE_TYPE_CELLULAR:
10047         case CONNMAN_SERVICE_TYPE_VPN:
10048         case CONNMAN_SERVICE_TYPE_WIFI:
10049                 break;
10050         }
10051
10052         if (!is_ipconfig_usable(service))
10053                 return -ENOLINK;
10054
10055         __connman_service_clear_error(service);
10056
10057         err = service_connect(service);
10058
10059         DBG("service %p err %d", service, err);
10060
10061         service->connect_reason = reason;
10062 #if defined TIZEN_EXT
10063         connect_reason_changed(service);
10064 #endif
10065
10066         if (err >= 0)
10067                 return 0;
10068
10069         if (err == -EINPROGRESS) {
10070                 if (service->timeout == 0)
10071                         service->timeout = g_timeout_add_seconds(
10072                                 CONNECT_TIMEOUT, connect_timeout, service);
10073
10074                 return -EINPROGRESS;
10075         }
10076
10077         if (service->network)
10078                 __connman_network_disconnect(service->network);
10079         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
10080                                 service->provider)
10081                         connman_provider_disconnect(service->provider);
10082
10083         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
10084                 if (err == -ENOKEY || err == -EPERM) {
10085                         DBusMessage *pending = NULL;
10086                         const char *dbus_sender = get_dbus_sender(service);
10087
10088                         /*
10089                          * We steal the reply here. The idea is that the
10090                          * connecting client will see the connection status
10091                          * after the real hidden network is connected or
10092                          * connection failed.
10093                          */
10094                         if (service->hidden) {
10095                                 pending = service->pending;
10096                                 service->pending = NULL;
10097                         }
10098
10099                         err = __connman_agent_request_passphrase_input(service,
10100                                         request_input_cb,
10101                                         dbus_sender,
10102                                         pending);
10103                         if (service->hidden && err != -EINPROGRESS)
10104                                 service->pending = pending;
10105
10106                         return err;
10107                 }
10108         }
10109
10110         return err;
10111 }
10112
10113 int __connman_service_disconnect(struct connman_service *service)
10114 {
10115         int err;
10116
10117         DBG("service %p", service);
10118
10119         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
10120         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
10121
10122         connman_agent_cancel(service);
10123
10124         __connman_stats_service_unregister(service);
10125
10126         if (service->network) {
10127                 err = __connman_network_disconnect(service->network);
10128         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
10129                                         service->provider)
10130                 err = connman_provider_disconnect(service->provider);
10131         else
10132                 return -EOPNOTSUPP;
10133
10134         if (err < 0 && err != -EINPROGRESS)
10135                 return err;
10136
10137         __connman_6to4_remove(service->ipconfig_ipv4);
10138
10139         if (service->ipconfig_ipv4)
10140                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
10141                                                         NULL);
10142         else
10143                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
10144                                                         NULL);
10145
10146 #if defined TIZEN_EXT
10147         /**
10148           * Skip the functions If there is any connected profiles
10149           * that use same interface
10150           */
10151         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
10152                 __connman_service_get_connected_count_of_iface(service) <= 0) {
10153 #endif
10154         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
10155         settings_changed(service, service->ipconfig_ipv4);
10156
10157         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
10158         settings_changed(service, service->ipconfig_ipv6);
10159
10160         __connman_ipconfig_disable(service->ipconfig_ipv4);
10161         __connman_ipconfig_disable(service->ipconfig_ipv6);
10162 #if defined TIZEN_EXT
10163         }
10164 #endif
10165
10166         return err;
10167 }
10168
10169 int __connman_service_disconnect_all(void)
10170 {
10171         struct connman_service *service;
10172         GSList *services = NULL, *list;
10173         GList *iter;
10174
10175         DBG("");
10176
10177         for (iter = service_list; iter; iter = iter->next) {
10178                 service = iter->data;
10179
10180                 if (!is_connected(service->state))
10181                         break;
10182
10183                 services = g_slist_prepend(services, service);
10184         }
10185
10186         for (list = services; list; list = list->next) {
10187                 struct connman_service *service = list->data;
10188
10189                 service->ignore = true;
10190
10191                 __connman_service_disconnect(service);
10192         }
10193
10194         g_slist_free(services);
10195
10196         return 0;
10197 }
10198
10199 /**
10200  * lookup_by_identifier:
10201  * @identifier: service identifier
10202  *
10203  * Look up a service by identifier (reference count will not be increased)
10204  */
10205 static struct connman_service *lookup_by_identifier(const char *identifier)
10206 {
10207         return g_hash_table_lookup(service_hash, identifier);
10208 }
10209
10210 struct connman_service *connman_service_lookup_from_identifier(const char* identifier)
10211 {
10212         return identifier ? lookup_by_identifier(identifier) : NULL;
10213 }
10214
10215 struct provision_user_data {
10216         const char *ident;
10217         int ret;
10218 };
10219
10220 static void provision_changed(gpointer value, gpointer user_data)
10221 {
10222         struct connman_service *service = value;
10223         struct provision_user_data *data = user_data;
10224         const char *path = data->ident;
10225         int ret;
10226
10227         ret = __connman_config_provision_service_ident(service, path,
10228                         service->config_file, service->config_entry);
10229         if (ret > 0)
10230                 data->ret = ret;
10231 }
10232
10233 int __connman_service_provision_changed(const char *ident)
10234 {
10235         struct provision_user_data data = {
10236                 .ident = ident,
10237                 .ret = 0
10238         };
10239
10240         g_list_foreach(service_list, provision_changed, (void *)&data);
10241
10242         /*
10243          * Because the provision_changed() might have set some services
10244          * as favorite, we must sort the sequence now.
10245          */
10246         if (services_dirty) {
10247                 services_dirty = false;
10248
10249                 service_list_sort();
10250
10251                 __connman_connection_update_gateway();
10252         }
10253
10254         return data.ret;
10255 }
10256
10257 void __connman_service_set_config(struct connman_service *service,
10258                                 const char *file_id, const char *entry)
10259 {
10260         if (!service)
10261                 return;
10262
10263         g_free(service->config_file);
10264         service->config_file = g_strdup(file_id);
10265
10266         g_free(service->config_entry);
10267         service->config_entry = g_strdup(entry);
10268 }
10269
10270 /**
10271  * __connman_service_get:
10272  * @identifier: service identifier
10273  *
10274  * Look up a service by identifier or create a new one if not found
10275  */
10276 static struct connman_service *service_get(const char *identifier)
10277 {
10278         struct connman_service *service;
10279
10280         service = g_hash_table_lookup(service_hash, identifier);
10281         if (service) {
10282                 connman_service_ref(service);
10283                 return service;
10284         }
10285
10286         service = connman_service_create();
10287         if (!service)
10288                 return NULL;
10289 #if defined TIZEN_EXT
10290         if (!simplified_log)
10291 #endif
10292         DBG("service %p", service);
10293
10294         service->identifier = g_strdup(identifier);
10295
10296         service_list = g_list_insert_sorted(service_list, service,
10297                                                 service_compare);
10298
10299         g_hash_table_insert(service_hash, service->identifier, service);
10300
10301         return service;
10302 }
10303
10304 static int service_register(struct connman_service *service)
10305 {
10306 #if defined TIZEN_EXT
10307         if (!simplified_log)
10308 #endif
10309         DBG("service %p", service);
10310
10311         if (service->path)
10312                 return -EALREADY;
10313
10314         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
10315                                                 service->identifier);
10316
10317         DBG("path %s", service->path);
10318
10319 #if defined TIZEN_EXT
10320         int ret;
10321         service_load(service);
10322         ret = service_ext_load(service);
10323         if (ret == -ERANGE)
10324                 service_ext_save(service);
10325         ret = __connman_config_provision_service(service);
10326         if (ret < 0 && !simplified_log)
10327                 DBG("Failed to provision service");
10328 #else
10329         if (__connman_config_provision_service(service) < 0)
10330                 service_load(service);
10331 #endif
10332
10333         g_dbus_register_interface(connection, service->path,
10334                                         CONNMAN_SERVICE_INTERFACE,
10335                                         service_methods, service_signals,
10336                                                         NULL, service, NULL);
10337
10338         service_list_sort();
10339
10340         __connman_connection_update_gateway();
10341
10342         return 0;
10343 }
10344
10345 static void service_up(struct connman_ipconfig *ipconfig,
10346                 const char *ifname)
10347 {
10348         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10349
10350         DBG("%s up", ifname);
10351
10352         link_changed(service);
10353
10354         service->stats.valid = false;
10355         service->stats_roaming.valid = false;
10356 }
10357
10358 static void service_down(struct connman_ipconfig *ipconfig,
10359                         const char *ifname)
10360 {
10361         DBG("%s down", ifname);
10362 }
10363
10364 static void service_lower_up(struct connman_ipconfig *ipconfig,
10365                         const char *ifname)
10366 {
10367         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10368
10369         DBG("%s lower up", ifname);
10370
10371         stats_start(service);
10372 }
10373
10374 static void service_lower_down(struct connman_ipconfig *ipconfig,
10375                         const char *ifname)
10376 {
10377         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10378
10379         DBG("%s lower down", ifname);
10380
10381         stats_stop(service);
10382         service_save(service);
10383 }
10384
10385 static void service_ip_bound(struct connman_ipconfig *ipconfig,
10386                         const char *ifname)
10387 {
10388         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10389         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
10390         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
10391 #if defined TIZEN_EXT
10392         int err;
10393 #endif
10394
10395         DBG("%s ip bound", ifname);
10396
10397         type = __connman_ipconfig_get_config_type(ipconfig);
10398         method = __connman_ipconfig_get_method(ipconfig);
10399
10400         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
10401                                                         type, method);
10402
10403         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
10404                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
10405 #if defined TIZEN_EXT
10406         {
10407                 err = __connman_ipconfig_gateway_add(ipconfig, service);
10408
10409                 if(err < 0)
10410                         DBG("Failed to add gateway");
10411         }
10412 #else
10413                 __connman_service_ipconfig_indicate_state(service,
10414                                                 CONNMAN_SERVICE_STATE_READY,
10415                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
10416 #endif
10417
10418         settings_changed(service, ipconfig);
10419         address_updated(service, type);
10420 }
10421
10422 static void service_ip_release(struct connman_ipconfig *ipconfig,
10423                         const char *ifname)
10424 {
10425         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10426         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
10427         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
10428
10429         DBG("%s ip release", ifname);
10430
10431         type = __connman_ipconfig_get_config_type(ipconfig);
10432         method = __connman_ipconfig_get_method(ipconfig);
10433
10434         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
10435                                                         type, method);
10436
10437         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
10438                         method == CONNMAN_IPCONFIG_METHOD_OFF)
10439                 __connman_service_ipconfig_indicate_state(service,
10440                                         CONNMAN_SERVICE_STATE_DISCONNECT,
10441                                         CONNMAN_IPCONFIG_TYPE_IPV6);
10442
10443         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
10444                         method == CONNMAN_IPCONFIG_METHOD_OFF)
10445                 __connman_service_ipconfig_indicate_state(service,
10446                                         CONNMAN_SERVICE_STATE_DISCONNECT,
10447                                         CONNMAN_IPCONFIG_TYPE_IPV4);
10448
10449         settings_changed(service, ipconfig);
10450 }
10451
10452 static void service_route_changed(struct connman_ipconfig *ipconfig,
10453                                 const char *ifname)
10454 {
10455         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10456
10457         DBG("%s route changed", ifname);
10458
10459         settings_changed(service, ipconfig);
10460 }
10461
10462 static const struct connman_ipconfig_ops service_ops = {
10463         .up             = service_up,
10464         .down           = service_down,
10465         .lower_up       = service_lower_up,
10466         .lower_down     = service_lower_down,
10467         .ip_bound       = service_ip_bound,
10468         .ip_release     = service_ip_release,
10469         .route_set      = service_route_changed,
10470         .route_unset    = service_route_changed,
10471 };
10472
10473 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
10474                 int index, enum connman_ipconfig_method method)
10475 {
10476         struct connman_ipconfig *ipconfig_ipv4;
10477
10478         ipconfig_ipv4 = __connman_ipconfig_create(index,
10479                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
10480         if (!ipconfig_ipv4)
10481                 return NULL;
10482
10483         __connman_ipconfig_set_method(ipconfig_ipv4, method);
10484
10485         __connman_ipconfig_set_data(ipconfig_ipv4, service);
10486
10487         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
10488
10489         return ipconfig_ipv4;
10490 }
10491
10492 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
10493                 int index)
10494 {
10495         struct connman_ipconfig *ipconfig_ipv6;
10496
10497         ipconfig_ipv6 = __connman_ipconfig_create(index,
10498                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
10499         if (!ipconfig_ipv6)
10500                 return NULL;
10501
10502         __connman_ipconfig_set_data(ipconfig_ipv6, service);
10503
10504         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
10505
10506         return ipconfig_ipv6;
10507 }
10508
10509 void __connman_service_read_ip4config(struct connman_service *service)
10510 {
10511         GKeyFile *keyfile;
10512
10513         if (!service->ipconfig_ipv4)
10514                 return;
10515
10516         keyfile = connman_storage_load_service(service->identifier);
10517         if (!keyfile)
10518                 return;
10519
10520         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
10521                                 service->identifier, "IPv4.");
10522
10523         g_key_file_free(keyfile);
10524 }
10525
10526 void connman_service_create_ip4config(struct connman_service *service,
10527                                         int index)
10528 {
10529         DBG("ipv4 %p", service->ipconfig_ipv4);
10530
10531         if (service->ipconfig_ipv4)
10532                 return;
10533
10534         service->ipconfig_ipv4 = create_ip4config(service, index,
10535                         CONNMAN_IPCONFIG_METHOD_DHCP);
10536         __connman_service_read_ip4config(service);
10537 }
10538
10539 void __connman_service_read_ip6config(struct connman_service *service)
10540 {
10541         GKeyFile *keyfile;
10542
10543         if (!service->ipconfig_ipv6)
10544                 return;
10545
10546         keyfile = connman_storage_load_service(service->identifier);
10547         if (!keyfile)
10548                 return;
10549
10550         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
10551                                 service->identifier, "IPv6.");
10552
10553         g_key_file_free(keyfile);
10554 }
10555
10556 void connman_service_create_ip6config(struct connman_service *service,
10557                                                                 int index)
10558 {
10559         DBG("ipv6 %p", service->ipconfig_ipv6);
10560
10561         if (service->ipconfig_ipv6)
10562                 return;
10563
10564         service->ipconfig_ipv6 = create_ip6config(service, index);
10565
10566         __connman_service_read_ip6config(service);
10567 }
10568
10569 /**
10570  * connman_service_lookup_from_network:
10571  * @network: network structure
10572  *
10573  * Look up a service by network (reference count will not be increased)
10574  */
10575 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
10576 {
10577         struct connman_service *service;
10578         const char *ident, *group;
10579         char *name;
10580
10581         if (!network)
10582                 return NULL;
10583
10584         ident = __connman_network_get_ident(network);
10585         if (!ident)
10586                 return NULL;
10587
10588         group = connman_network_get_group(network);
10589         if (!group)
10590                 return NULL;
10591
10592         name = g_strdup_printf("%s_%s_%s",
10593                         __connman_network_get_type(network), ident, group);
10594         service = lookup_by_identifier(name);
10595         g_free(name);
10596
10597         return service;
10598 }
10599
10600 struct connman_service *__connman_service_lookup_from_index(int index)
10601 {
10602         struct connman_service *service;
10603         GList *list;
10604
10605         for (list = service_list; list; list = list->next) {
10606                 service = list->data;
10607
10608                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
10609                                                         == index)
10610                         return service;
10611
10612                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
10613                                                         == index)
10614                         return service;
10615         }
10616
10617         return NULL;
10618 }
10619
10620 const char *connman_service_get_identifier(struct connman_service *service)
10621 {
10622         return service ? service->identifier : NULL;
10623 }
10624
10625 const char *__connman_service_get_path(struct connman_service *service)
10626 {
10627         return service->path;
10628 }
10629
10630 const char *__connman_service_get_name(struct connman_service *service)
10631 {
10632         return service->name;
10633 }
10634
10635 enum connman_service_state connman_service_get_state(struct connman_service *service)
10636 {
10637         return service ? service->state : CONNMAN_SERVICE_STATE_UNKNOWN;
10638 }
10639
10640 static enum connman_service_type convert_network_type(struct connman_network *network)
10641 {
10642         enum connman_network_type type = connman_network_get_type(network);
10643
10644         switch (type) {
10645         case CONNMAN_NETWORK_TYPE_UNKNOWN:
10646         case CONNMAN_NETWORK_TYPE_VENDOR:
10647                 break;
10648         case CONNMAN_NETWORK_TYPE_ETHERNET:
10649                 return CONNMAN_SERVICE_TYPE_ETHERNET;
10650         case CONNMAN_NETWORK_TYPE_WIFI:
10651                 return CONNMAN_SERVICE_TYPE_WIFI;
10652         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
10653         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
10654                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
10655         case CONNMAN_NETWORK_TYPE_CELLULAR:
10656                 return CONNMAN_SERVICE_TYPE_CELLULAR;
10657         case CONNMAN_NETWORK_TYPE_GADGET:
10658                 return CONNMAN_SERVICE_TYPE_GADGET;
10659         }
10660
10661         return CONNMAN_SERVICE_TYPE_UNKNOWN;
10662 }
10663
10664 static enum connman_service_security convert_wifi_security(const char *security)
10665 {
10666         if (!security)
10667                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
10668         else if (g_str_equal(security, "none"))
10669                 return CONNMAN_SERVICE_SECURITY_NONE;
10670         else if (g_str_equal(security, "wep"))
10671                 return CONNMAN_SERVICE_SECURITY_WEP;
10672         else if (g_str_equal(security, "psk"))
10673                 return CONNMAN_SERVICE_SECURITY_PSK;
10674         else if (g_str_equal(security, "ieee8021x"))
10675                 return CONNMAN_SERVICE_SECURITY_8021X;
10676         else if (g_str_equal(security, "wpa"))
10677                 return CONNMAN_SERVICE_SECURITY_WPA;
10678         else if (g_str_equal(security, "rsn"))
10679                 return CONNMAN_SERVICE_SECURITY_RSN;
10680 #if defined TIZEN_EXT
10681         else if (g_str_equal(security, "sae"))
10682                 return CONNMAN_SERVICE_SECURITY_SAE;
10683         else if (g_str_equal(security, "owe"))
10684                 return CONNMAN_SERVICE_SECURITY_OWE;
10685         else if (g_str_equal(security, "dpp"))
10686                 return CONNMAN_SERVICE_SECURITY_DPP;
10687         else if (g_str_equal(security, "ft_psk") == TRUE)
10688                 return CONNMAN_SERVICE_SECURITY_PSK;
10689         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
10690                 return CONNMAN_SERVICE_SECURITY_8021X;
10691 #endif
10692         else
10693                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
10694 }
10695
10696 #if defined TIZEN_EXT
10697 int check_passphrase_ext(struct connman_network *network,
10698                                         const char *passphrase)
10699 {
10700         const char *str;
10701         enum connman_service_security security;
10702
10703         str = connman_network_get_string(network, "WiFi.Security");
10704         security = convert_wifi_security(str);
10705
10706         return __connman_service_check_passphrase(security, passphrase);
10707 }
10708 #endif
10709
10710 static void update_wps_values(struct connman_service *service,
10711                                 struct connman_network *network)
10712 {
10713         bool wps = connman_network_get_bool(network, "WiFi.WPS");
10714         bool wps_advertising = connman_network_get_bool(network,
10715                                                         "WiFi.WPSAdvertising");
10716
10717         if (service->wps != wps ||
10718                         service->wps_advertizing != wps_advertising) {
10719                 service->wps = wps;
10720                 service->wps_advertizing = wps_advertising;
10721                 security_changed(service);
10722         }
10723 }
10724
10725 static void update_from_network(struct connman_service *service,
10726                                         struct connman_network *network)
10727 {
10728         uint8_t strength = service->strength;
10729         const char *str;
10730
10731         DBG("service %p network %p", service, network);
10732
10733         if (is_connected(service->state))
10734                 return;
10735
10736         if (is_connecting(service->state))
10737                 return;
10738
10739         str = connman_network_get_string(network, "Name");
10740         if (str) {
10741                 g_free(service->name);
10742                 service->name = g_strdup(str);
10743                 service->hidden = false;
10744         } else {
10745                 g_free(service->name);
10746                 service->name = NULL;
10747                 service->hidden = true;
10748         }
10749
10750         service->strength = connman_network_get_strength(network);
10751         service->roaming = connman_network_get_bool(network, "Roaming");
10752
10753         if (service->strength == 0) {
10754                 /*
10755                  * Filter out 0-values; it's unclear what they mean
10756                  * and they cause anomalous sorting of the priority list.
10757                  */
10758                 service->strength = strength;
10759         }
10760
10761         str = connman_network_get_string(network, "WiFi.Security");
10762         service->security = convert_wifi_security(str);
10763
10764         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
10765                 update_wps_values(service, network);
10766
10767         if (service->strength > strength && service->network) {
10768                 connman_network_unref(service->network);
10769                 service->network = connman_network_ref(network);
10770
10771                 strength_changed(service);
10772         }
10773
10774         if (!service->network)
10775                 service->network = connman_network_ref(network);
10776
10777         service_list_sort();
10778 }
10779
10780 /**
10781  * __connman_service_create_from_network:
10782  * @network: network structure
10783  *
10784  * Look up service by network and if not found, create one
10785  */
10786 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
10787 {
10788         struct connman_service *service;
10789         struct connman_device *device;
10790         const char *ident, *group;
10791         char *name;
10792         unsigned int *auto_connect_types, *favorite_types;
10793         int i, index;
10794
10795         DBG("network %p", network);
10796
10797         if (!network)
10798                 return NULL;
10799
10800         ident = __connman_network_get_ident(network);
10801         if (!ident)
10802                 return NULL;
10803
10804         group = connman_network_get_group(network);
10805         if (!group)
10806                 return NULL;
10807
10808         name = g_strdup_printf("%s_%s_%s",
10809                         __connman_network_get_type(network), ident, group);
10810         service = service_get(name);
10811         g_free(name);
10812
10813         if (!service)
10814                 return NULL;
10815
10816         if (__connman_network_get_weakness(network))
10817                 return service;
10818
10819         if (service->path) {
10820                 update_from_network(service, network);
10821                 __connman_connection_update_gateway();
10822                 return service;
10823         }
10824
10825         service->type = convert_network_type(network);
10826
10827         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
10828         service->autoconnect = false;
10829         for (i = 0; auto_connect_types &&
10830                      auto_connect_types[i] != 0; i++) {
10831                 if (service->type == auto_connect_types[i]) {
10832                         service->autoconnect = true;
10833                         break;
10834                 }
10835         }
10836
10837         favorite_types = connman_setting_get_uint_list("DefaultFavoriteTechnologies");
10838         service->favorite = false;
10839         for (i = 0; favorite_types && favorite_types[i] != 0; i++) {
10840                 if (service->type == favorite_types[i]) {
10841                         service->favorite = true;
10842                         break;
10843                 }
10844         }
10845
10846         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
10847         service->state = combine_state(service->state_ipv4, service->state_ipv6);
10848
10849         update_from_network(service, network);
10850
10851         index = connman_network_get_index(network);
10852
10853         if (!service->ipconfig_ipv4)
10854                 service->ipconfig_ipv4 = create_ip4config(service, index,
10855                                 CONNMAN_IPCONFIG_METHOD_DHCP);
10856
10857         if (!service->ipconfig_ipv6)
10858                 service->ipconfig_ipv6 = create_ip6config(service, index);
10859
10860         service_register(service);
10861         service_schedule_added(service);
10862
10863         if (service->favorite) {
10864                 device = connman_network_get_device(service->network);
10865                 if (device && !connman_device_get_scanning(device,
10866                                                 CONNMAN_SERVICE_TYPE_UNKNOWN)) {
10867
10868                         switch (service->type) {
10869                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
10870                         case CONNMAN_SERVICE_TYPE_SYSTEM:
10871                         case CONNMAN_SERVICE_TYPE_P2P:
10872 #if defined TIZEN_EXT_WIFI_MESH
10873                         case CONNMAN_SERVICE_TYPE_MESH:
10874 #endif
10875                                 break;
10876
10877                         case CONNMAN_SERVICE_TYPE_GADGET:
10878                         case CONNMAN_SERVICE_TYPE_ETHERNET:
10879                                 if (service->autoconnect) {
10880                                         __connman_service_connect(service,
10881                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
10882                                         break;
10883                                 }
10884
10885                                 /* fall through */
10886                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
10887                         case CONNMAN_SERVICE_TYPE_GPS:
10888                         case CONNMAN_SERVICE_TYPE_VPN:
10889                         case CONNMAN_SERVICE_TYPE_WIFI:
10890                         case CONNMAN_SERVICE_TYPE_CELLULAR:
10891                                 do_auto_connect(service,
10892                                         CONNMAN_SERVICE_CONNECT_REASON_AUTO);
10893                                 break;
10894                         }
10895                 }
10896
10897 #if defined TIZEN_EXT
10898                 /* TIZEN synchronizes below information when the service creates */
10899                 if (service->eap != NULL)
10900                         connman_network_set_string(service->network, "WiFi.EAP",
10901                                                                 service->eap);
10902                 if (service->identity != NULL)
10903                         connman_network_set_string(service->network, "WiFi.Identity",
10904                                                                 service->identity);
10905                 if (service->phase2 != NULL)
10906                         connman_network_set_string(service->network, "WiFi.Phase2",
10907                                                                 service->phase2);
10908                 if (service->eap != NULL)
10909                         connman_network_set_string(service->network, "WiFi.Connector",
10910                                                                 service->connector);
10911                 if (service->identity != NULL)
10912                         connman_network_set_string(service->network, "WiFi.CSignKey",
10913                                                                 service->c_sign_key);
10914                 if (service->phase2 != NULL)
10915                         connman_network_set_string(service->network, "WiFi.NetAccessKey",
10916                                                                 service->net_access_key);
10917 #endif
10918         }
10919
10920         __connman_notifier_service_add(service, service->name);
10921
10922         return service;
10923 }
10924
10925 #if defined TIZEN_EXT
10926 void __connman_service_notify_strength_changed(struct connman_network *network)
10927 {
10928         struct connman_service *service;
10929         uint8_t strength = 0;
10930
10931         service = connman_service_lookup_from_network(network);
10932         if (!service)
10933                 return;
10934
10935         if (!service->network)
10936                 return;
10937
10938         strength = connman_network_get_strength(service->network);
10939         if (strength == service->strength)
10940                 return;
10941
10942         service->strength = strength;
10943         if (!simplified_log)
10944                 DBG("Strength %d", strength);
10945         strength_changed(service);
10946         service_list_sort();
10947 }
10948 #endif
10949
10950 void __connman_service_update_from_network(struct connman_network *network)
10951 {
10952         bool need_sort = false;
10953         struct connman_service *service;
10954         uint8_t strength;
10955         bool roaming;
10956         const char *name;
10957         bool stats_enable;
10958 #if defined TIZEN_EXT
10959         bool need_save = false;
10960 #endif
10961
10962         service = connman_service_lookup_from_network(network);
10963         if (!service)
10964                 return;
10965
10966         if (!service->network)
10967                 return;
10968
10969 #if defined TIZEN_EXT
10970         if (service->storage_reload) {
10971                 service_load(service);
10972                 __connman_service_set_storage_reload(service, false);
10973         }
10974 #endif
10975
10976         name = connman_network_get_string(service->network, "Name");
10977         if (g_strcmp0(service->name, name) != 0) {
10978                 g_free(service->name);
10979                 service->name = g_strdup(name);
10980
10981                 if (allow_property_changed(service))
10982                         connman_dbus_property_changed_basic(service->path,
10983                                         CONNMAN_SERVICE_INTERFACE, "Name",
10984                                         DBUS_TYPE_STRING, &service->name);
10985         }
10986
10987         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
10988                 update_wps_values(service, network);
10989
10990         strength = connman_network_get_strength(service->network);
10991         if (strength == service->strength)
10992                 goto roaming;
10993
10994         service->strength = strength;
10995         need_sort = true;
10996
10997         strength_changed(service);
10998
10999 roaming:
11000         roaming = connman_network_get_bool(service->network, "Roaming");
11001         if (roaming == service->roaming)
11002                 goto sorting;
11003
11004         stats_enable = stats_enabled(service);
11005         if (stats_enable)
11006                 stats_stop(service);
11007
11008         service->roaming = roaming;
11009         need_sort = true;
11010
11011         if (stats_enable)
11012                 stats_start(service);
11013
11014         roaming_changed(service);
11015
11016 sorting:
11017 #if defined TIZEN_EXT
11018         need_save |= update_last_connected_bssid(service);
11019         need_save |= update_assoc_reject(service);
11020         if (need_save) {
11021                 g_get_current_time(&service->modified);
11022                 service_ext_save(service);
11023                 need_sort = true;
11024         }
11025 #endif
11026
11027         if (need_sort) {
11028                 service_list_sort();
11029         }
11030 }
11031
11032 void __connman_service_remove_from_network(struct connman_network *network)
11033 {
11034         struct connman_service *service;
11035
11036         service = connman_service_lookup_from_network(network);
11037
11038         DBG("network %p service %p", network, service);
11039
11040         if (!service)
11041                 return;
11042
11043         service->ignore = true;
11044
11045         __connman_connection_gateway_remove(service,
11046                                         CONNMAN_IPCONFIG_TYPE_ALL);
11047
11048         connman_service_unref(service);
11049 }
11050
11051 /**
11052  * __connman_service_create_from_provider:
11053  * @provider: provider structure
11054  *
11055  * Look up service by provider and if not found, create one
11056  */
11057 struct connman_service *
11058 __connman_service_create_from_provider(struct connman_provider *provider)
11059 {
11060         struct connman_service *service;
11061         const char *ident, *str;
11062         char *name;
11063         int index = connman_provider_get_index(provider);
11064
11065         DBG("provider %p", provider);
11066
11067         ident = __connman_provider_get_ident(provider);
11068         if (!ident)
11069                 return NULL;
11070
11071         name = g_strdup_printf("vpn_%s", ident);
11072         service = service_get(name);
11073         g_free(name);
11074
11075         if (!service)
11076                 return NULL;
11077
11078         service->type = CONNMAN_SERVICE_TYPE_VPN;
11079         service->order = service->do_split_routing ? 0 : 10;
11080         service->provider = connman_provider_ref(provider);
11081         service->autoconnect = false;
11082         service->favorite = true;
11083
11084         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
11085         service->state = combine_state(service->state_ipv4, service->state_ipv6);
11086
11087         str = connman_provider_get_string(provider, "Name");
11088         if (str) {
11089                 g_free(service->name);
11090                 service->name = g_strdup(str);
11091                 service->hidden = false;
11092         } else {
11093                 g_free(service->name);
11094                 service->name = NULL;
11095                 service->hidden = true;
11096         }
11097
11098         service->strength = 0;
11099
11100         if (!service->ipconfig_ipv4)
11101                 service->ipconfig_ipv4 = create_ip4config(service, index,
11102                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
11103
11104         if (!service->ipconfig_ipv6)
11105                 service->ipconfig_ipv6 = create_ip6config(service, index);
11106
11107         service_register(service);
11108
11109         __connman_notifier_service_add(service, service->name);
11110         service_schedule_added(service);
11111
11112         return service;
11113 }
11114
11115 static void remove_unprovisioned_services(void)
11116 {
11117         gchar **services;
11118         GKeyFile *keyfile, *configkeyfile;
11119         char *file, *section;
11120         int i = 0;
11121
11122         services = connman_storage_get_services();
11123         if (!services)
11124                 return;
11125
11126         for (; services[i]; i++) {
11127                 file = section = NULL;
11128                 keyfile = configkeyfile = NULL;
11129
11130                 keyfile = connman_storage_load_service(services[i]);
11131                 if (!keyfile)
11132                         continue;
11133
11134                 file = g_key_file_get_string(keyfile, services[i],
11135                                         "Config.file", NULL);
11136                 if (!file)
11137                         goto next;
11138
11139                 section = g_key_file_get_string(keyfile, services[i],
11140                                         "Config.ident", NULL);
11141                 if (!section)
11142                         goto next;
11143
11144                 configkeyfile = __connman_storage_load_config(file);
11145                 if (!configkeyfile) {
11146                         /*
11147                          * Config file is missing, remove the provisioned
11148                          * service.
11149                          */
11150                         __connman_storage_remove_service(services[i]);
11151                         goto next;
11152                 }
11153
11154                 if (!g_key_file_has_group(configkeyfile, section))
11155                         /*
11156                          * Config section is missing, remove the provisioned
11157                          * service.
11158                          */
11159                         __connman_storage_remove_service(services[i]);
11160
11161         next:
11162                 if (keyfile)
11163                         g_key_file_free(keyfile);
11164
11165                 if (configkeyfile)
11166                         g_key_file_free(configkeyfile);
11167
11168                 g_free(section);
11169                 g_free(file);
11170         }
11171
11172         g_strfreev(services);
11173 }
11174
11175 static int agent_probe(struct connman_agent *agent)
11176 {
11177         DBG("agent %p", agent);
11178         return 0;
11179 }
11180
11181 static void agent_remove(struct connman_agent *agent)
11182 {
11183         DBG("agent %p", agent);
11184 }
11185
11186 static void *agent_context_ref(void *context)
11187 {
11188         struct connman_service *service = context;
11189
11190         return (void *)connman_service_ref(service);
11191 }
11192
11193 static void agent_context_unref(void *context)
11194 {
11195         struct connman_service *service = context;
11196
11197         connman_service_unref(service);
11198 }
11199
11200 static struct connman_agent_driver agent_driver = {
11201         .name           = "service",
11202         .interface      = CONNMAN_AGENT_INTERFACE,
11203         .probe          = agent_probe,
11204         .remove         = agent_remove,
11205         .context_ref    = agent_context_ref,
11206         .context_unref  = agent_context_unref,
11207 };
11208
11209 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
11210 static void ins_setting_init(void)
11211 {
11212         int i;
11213         const char *string;
11214         char **string_list;
11215         unsigned int string_count;
11216
11217         ins_settings.last_user_selection = connman_setting_get_bool("INSLastUserSelection");
11218         ins_settings.last_user_selection_time = connman_setting_get_uint("INSLastUserSelectionTime");
11219         ins_settings.last_connected = connman_setting_get_bool("INSLastConnected");
11220
11221         string = connman_option_get_string("INSPreferredFreq");
11222         if (g_strcmp0(string, "5GHz") == 0)
11223                 ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_5GHZ;
11224         else if (g_strcmp0(string, "2.4GHz") == 0)
11225                 ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_24GHZ;
11226         else
11227                 ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_UNKNOWN;
11228
11229         ins_settings.security_priority_count = connman_setting_get_uint("INSSecurityPriorityCount");
11230         ins_settings.security_priority_score = connman_setting_get_uint("INSSecurityPriorityScore");
11231         string_count = ins_settings.security_priority_count;
11232
11233         memset(ins_settings.security_priority, 0, sizeof(ins_settings.security_priority));
11234         string_list = connman_setting_get_string_list("INSSecurityPriority");
11235         for (i = 0; string_list && string_list[i]; i++) {
11236                 unsigned int security_score = string_count * ins_settings.security_priority_score;
11237
11238                 if (g_strcmp0(string_list[i], "WEP") == 0)
11239                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_WEP] = security_score;
11240                 else if (g_strcmp0(string_list[i], "PSK") == 0)
11241                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_PSK] = security_score;
11242                 else if (g_strcmp0(string_list[i], "8021X") == 0)
11243                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_8021X] = security_score;
11244                 else if (g_strcmp0(string_list[i], "WPA") == 0)
11245                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_WPA] = security_score;
11246                 else if (g_strcmp0(string_list[i], "RSN") == 0)
11247                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_RSN] = security_score;
11248                 else if (g_strcmp0(string_list[i], "SAE") == 0)
11249                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_SAE] = security_score;
11250                 else if (g_strcmp0(string_list[i], "OWE") == 0)
11251                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_OWE] = security_score;
11252                 else if (g_strcmp0(string_list[i], "DPP") == 0)
11253                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_DPP] = security_score;
11254
11255                 string_count--;
11256         }
11257
11258         ins_settings.signal = connman_setting_get_bool("INSSignal");
11259         ins_settings.internet = connman_setting_get_bool("INSInternet");
11260
11261         ins_settings.last_user_selection_score = connman_setting_get_uint("INSLastUserSelectionScore");
11262         ins_settings.last_connected_score = connman_setting_get_uint("INSLastConnectedScore");
11263         ins_settings.preferred_freq_score = connman_setting_get_uint("INSPreferredFreqScore");
11264         ins_settings.internet_score = connman_setting_get_uint("INSInternetScore");
11265
11266         /*
11267          * In ConnMan, signal strength is used after being converted
11268          * to positive value(signal strength + 120).
11269          * So the value for comparison should also be converted to the same.
11270          */
11271         ins_settings.signal_level3_5ghz = connman_setting_get_int("INSSignalLevel3_5GHz") + 120;
11272         ins_settings.signal_level3_24ghz = connman_setting_get_int("INSSignalLevel3_24GHz") + 120;
11273
11274         DBG("last_user_selection [%s]", ins_settings.last_user_selection ? "true" : "false");
11275         DBG("last_user_selection_time [%d]", ins_settings.last_user_selection_time);
11276         DBG("last_user_selection_score [%d]", ins_settings.last_user_selection_score);
11277
11278         DBG("last_connected [%s]", ins_settings.last_connected ? "true" : "false");
11279         DBG("last_connected_score [%d]", ins_settings.last_connected_score);
11280
11281         DBG("preferred_freq [%s]", ins_settings.preferred_freq ? "true" : "false");
11282         DBG("preferred_freq_score [%d]", ins_settings.preferred_freq_score);
11283
11284         DBG("security_priority_count [%d]", ins_settings.security_priority_count);
11285         for (i = 0; i < CONNMAN_SERVICE_SECURITY_MAX; i++) {
11286                 if (ins_settings.security_priority[i])
11287                         DBG("security_priority %s [%d]", security2string(i),
11288                                         ins_settings.security_priority[i]);
11289         }
11290         DBG("security_priority_score [%d]", ins_settings.security_priority_score);
11291
11292         DBG("signal [%s]", ins_settings.signal ? "true" : "false");
11293
11294         DBG("internet [%s]", ins_settings.internet ? "true" : "false");
11295         DBG("internet_score [%d]", ins_settings.internet_score);
11296
11297         DBG("signal_level3_5ghz [%d]", ins_settings.signal_level3_5ghz);
11298         DBG("signal_level3_24ghz [%d]", ins_settings.signal_level3_24ghz);
11299 }
11300 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
11301
11302 int __connman_service_init(void)
11303 {
11304         int err;
11305
11306         DBG("");
11307
11308         err = connman_agent_driver_register(&agent_driver);
11309         if (err < 0) {
11310                 connman_error("Cannot register agent driver for %s",
11311                                                 agent_driver.name);
11312                 return err;
11313         }
11314
11315         set_always_connecting_technologies();
11316
11317         connection = connman_dbus_get_connection();
11318
11319         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
11320                                                         NULL, service_free);
11321
11322         services_notify = g_new0(struct _services_notify, 1);
11323         services_notify->remove = g_hash_table_new_full(g_str_hash,
11324                         g_str_equal, g_free, NULL);
11325         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
11326
11327         remove_unprovisioned_services();
11328
11329 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
11330         ins_setting_init();
11331 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
11332
11333         return 0;
11334 }
11335
11336 void __connman_service_cleanup(void)
11337 {
11338         DBG("");
11339
11340         if (vpn_autoconnect_id) {
11341                 g_source_remove(vpn_autoconnect_id);
11342                 vpn_autoconnect_id = 0;
11343         }
11344
11345         if (autoconnect_id != 0) {
11346                 g_source_remove(autoconnect_id);
11347                 autoconnect_id = 0;
11348         }
11349
11350         connman_agent_driver_unregister(&agent_driver);
11351
11352         g_list_free(service_list);
11353         service_list = NULL;
11354
11355         g_hash_table_destroy(service_hash);
11356         service_hash = NULL;
11357
11358         g_slist_free(counter_list);
11359         counter_list = NULL;
11360
11361         if (services_notify->id != 0) {
11362                 g_source_remove(services_notify->id);
11363                 service_send_changed(NULL);
11364         }
11365
11366         g_hash_table_destroy(services_notify->remove);
11367         g_hash_table_destroy(services_notify->add);
11368         g_free(services_notify);
11369
11370         dbus_connection_unref(connection);
11371 }