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