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