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