Fix wifi connection issue post invalid-key error occurs.
[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 #if !defined TIZEN_EXT
9381                         goto notifier;
9382 #endif
9383                 }
9384                 service_complete(service);
9385                 break;
9386         }
9387
9388         service_list_sort();
9389
9390 #if defined TIZEN_EXT
9391 #if defined TIZEN_MAINTAIN_ONLINE
9392         __connman_service_connect_default(service, old_state);
9393 #else
9394         __connman_service_connect_default(service);
9395 #endif
9396         /* Update Wi-Fi Roaming result */
9397         if (connman_setting_get_bool("WifiRoaming") &&
9398                         connman_network_get_bool(service->network, "WiFi.Roaming")) {
9399                 const char *cur_bssid;
9400                 const char *dst_bssid;
9401                 const char *ifname;
9402                 struct connman_device *device;
9403
9404                 device = connman_network_get_device(service->network);
9405                 if (device) {
9406                         ifname = connman_device_get_string(device, "Interface");
9407                         cur_bssid = connman_network_get_string(service->network,
9408                                                 "WiFi.RoamingCurBSSID");
9409                         dst_bssid = connman_network_get_string(service->network,
9410                                                 "WiFi.RoamingDstBSSID");
9411                 }
9412
9413                 if (device && ifname && cur_bssid && dst_bssid) {
9414                         switch(new_state) {
9415                         case CONNMAN_SERVICE_STATE_UNKNOWN:
9416                         case CONNMAN_SERVICE_STATE_ASSOCIATION:
9417                         case CONNMAN_SERVICE_STATE_CONFIGURATION:
9418                                 break;
9419                         case CONNMAN_SERVICE_STATE_READY:
9420                         case CONNMAN_SERVICE_STATE_ONLINE:
9421                                 __connman_technology_notify_roaming_state(ifname,
9422                                                 "success", cur_bssid, dst_bssid);
9423                                 connman_network_set_bool(service->network,
9424                                                 "WiFi.Roaming", false);
9425                                 connman_network_set_string(service->network,
9426                                                 "WiFi.RoamingCurBSSID", NULL);
9427                                 connman_network_set_string(service->network,
9428                                                 "WiFi.RoamingDstBSSID", NULL);
9429                                 break;
9430                         case CONNMAN_SERVICE_STATE_DISCONNECT:
9431                         case CONNMAN_SERVICE_STATE_FAILURE:
9432                         case CONNMAN_SERVICE_STATE_IDLE:
9433                                 __connman_technology_notify_roaming_state(ifname,
9434                                                 "failure", cur_bssid, dst_bssid);
9435                                 connman_network_set_bool(service->network,
9436                                                 "WiFi.Roaming", false);
9437                                 connman_network_set_string(service->network,
9438                                                 "WiFi.RoamingCurBSSID", NULL);
9439                                 connman_network_set_string(service->network,
9440                                                 "WiFi.RoamingDstBSSID", NULL);
9441                                 break;
9442                         }
9443                 }
9444         }
9445 #endif
9446
9447         __connman_connection_update_gateway();
9448
9449 #if !defined TIZEN_EXT
9450 notifier:
9451 #endif
9452         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
9453                         new_state != CONNMAN_SERVICE_STATE_READY) ||
9454                 (old_state == CONNMAN_SERVICE_STATE_READY &&
9455                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
9456                 __connman_notifier_disconnect(service->type);
9457         }
9458
9459         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
9460                 __connman_notifier_enter_online(service->type);
9461                 default_changed();
9462         }
9463
9464         return 0;
9465 }
9466
9467 int __connman_service_indicate_error(struct connman_service *service,
9468                                         enum connman_service_error error)
9469 {
9470         DBG("service %p error %d", service, error);
9471
9472         if (!service)
9473                 return -EINVAL;
9474
9475         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
9476                 return -EALREADY;
9477
9478         set_error(service, error);
9479
9480 /* default internet service: fix not cleared if pdp activation*/
9481 #if defined TIZEN_EXT
9482                 /*
9483                  * If connection failed for default service(DefaultInternet),
9484                  * default_connecting_device should be cleared.
9485                  */
9486                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
9487                                 service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED)
9488                         __connman_service_disconnect_default(service);
9489
9490                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
9491                                 service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) {
9492                         g_free(service->passphrase);
9493                         service->passphrase = NULL;
9494                 }
9495 #endif
9496
9497         __connman_service_ipconfig_indicate_state(service,
9498                                                 CONNMAN_SERVICE_STATE_FAILURE,
9499                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
9500         __connman_service_ipconfig_indicate_state(service,
9501                                                 CONNMAN_SERVICE_STATE_FAILURE,
9502                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
9503         return 0;
9504 }
9505
9506 int __connman_service_clear_error(struct connman_service *service)
9507 {
9508         DBusMessage *pending, *provider_pending;
9509
9510         DBG("service %p", service);
9511
9512         if (!service)
9513                 return -EINVAL;
9514
9515         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
9516                 return -EINVAL;
9517
9518         pending = service->pending;
9519         service->pending = NULL;
9520         provider_pending = service->provider_pending;
9521         service->provider_pending = NULL;
9522
9523         __connman_service_ipconfig_indicate_state(service,
9524                                                 CONNMAN_SERVICE_STATE_IDLE,
9525                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
9526
9527         __connman_service_ipconfig_indicate_state(service,
9528                                                 CONNMAN_SERVICE_STATE_IDLE,
9529                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
9530
9531         service->pending = pending;
9532         service->provider_pending = provider_pending;
9533
9534         return 0;
9535 }
9536
9537 int __connman_service_indicate_default(struct connman_service *service)
9538 {
9539         DBG("service %p state %s", service, state2string(service->state));
9540
9541         if (!is_connected(service->state)) {
9542                 /*
9543                  * If service is not yet fully connected, then we must not
9544                  * change the default yet. The default gw will be changed
9545                  * after the service state is in ready.
9546                  */
9547                 return -EINPROGRESS;
9548         }
9549
9550         default_changed();
9551
9552         return 0;
9553 }
9554
9555 enum connman_service_state __connman_service_ipconfig_get_state(
9556                                         struct connman_service *service,
9557                                         enum connman_ipconfig_type type)
9558 {
9559         if (!service)
9560                 return CONNMAN_SERVICE_STATE_UNKNOWN;
9561
9562         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9563                 return service->state_ipv4;
9564
9565         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
9566                 return service->state_ipv6;
9567
9568         return CONNMAN_SERVICE_STATE_UNKNOWN;
9569 }
9570
9571 #if defined TIZEN_EXT
9572 void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
9573
9574         DBG("check the proxy and start wispr");
9575         check_proxy_setup(service);
9576         return;
9577 }
9578 #endif
9579
9580 /*
9581  * How many networks are connected at the same time. If more than 1,
9582  * then set the rp_filter setting properly (loose mode routing) so that network
9583  * connectivity works ok. This is only done for IPv4 networks as IPv6
9584  * does not have rp_filter knob.
9585  */
9586 static int connected_networks_count;
9587 static int original_rp_filter;
9588
9589 static void service_rp_filter(struct connman_service *service,
9590                                 bool connected)
9591 {
9592         enum connman_ipconfig_method method;
9593
9594         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
9595
9596         switch (method) {
9597         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
9598         case CONNMAN_IPCONFIG_METHOD_OFF:
9599         case CONNMAN_IPCONFIG_METHOD_AUTO:
9600                 return;
9601         case CONNMAN_IPCONFIG_METHOD_FIXED:
9602         case CONNMAN_IPCONFIG_METHOD_MANUAL:
9603         case CONNMAN_IPCONFIG_METHOD_DHCP:
9604                 break;
9605         }
9606
9607         if (connected) {
9608                 if (connected_networks_count == 1) {
9609                         int filter_value;
9610                         filter_value = __connman_ipconfig_set_rp_filter();
9611                         if (filter_value < 0)
9612                                 return;
9613
9614                         original_rp_filter = filter_value;
9615                 }
9616                 connected_networks_count++;
9617
9618         } else {
9619                 if (connected_networks_count == 2)
9620                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
9621
9622                 connected_networks_count--;
9623                 if (connected_networks_count < 0)
9624                         connected_networks_count = 0;
9625         }
9626
9627         DBG("%s %s ipconfig %p method %d count %d filter %d",
9628                 connected ? "connected" : "disconnected", service->identifier,
9629                 service->ipconfig_ipv4, method,
9630                 connected_networks_count, original_rp_filter);
9631 }
9632
9633 static void redo_wispr(struct connman_service *service,
9634                                         enum connman_ipconfig_type type)
9635 {
9636         service->online_timeout = 0;
9637         connman_service_unref(service);
9638
9639         DBG("Retrying %s WISPr for %p %s",
9640                 __connman_ipconfig_type2string(type),
9641                 service, service->name);
9642
9643         __connman_wispr_start(service, type);
9644 }
9645
9646 static gboolean redo_wispr_ipv4(gpointer user_data)
9647 {
9648         struct connman_service *service = user_data;
9649
9650 #if defined TIZEN_MAINTAIN_ONLINE
9651         DBG("");
9652
9653         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
9654 #else
9655         redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV4);
9656 #endif
9657
9658         return FALSE;
9659 }
9660
9661 static gboolean redo_wispr_ipv6(gpointer user_data)
9662 {
9663         struct connman_service *service = user_data;
9664
9665         redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV6);
9666
9667         return FALSE;
9668 }
9669
9670 void __connman_service_online_check(struct connman_service *service,
9671                                         enum connman_ipconfig_type type,
9672                                         bool success)
9673 {
9674         GSourceFunc redo_func;
9675         unsigned int *interval;
9676         enum connman_service_state current_state;
9677
9678         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
9679                 interval = &service->online_check_interval_ipv4;
9680                 redo_func = redo_wispr_ipv4;
9681         } else {
9682                 interval = &service->online_check_interval_ipv6;
9683                 redo_func = redo_wispr_ipv6;
9684         }
9685
9686         if(!enable_online_to_ready_transition)
9687                 goto redo_func;
9688
9689         if (success) {
9690                 *interval = online_check_max_interval;
9691         } else {
9692                 current_state = service->state;
9693                 downgrade_state(service);
9694                 if (current_state != service->state)
9695                         *interval = online_check_initial_interval;
9696                 if (service != connman_service_get_default()) {
9697                         return;
9698                 }
9699         }
9700
9701 redo_func:
9702         DBG("service %p type %s interval %d", service,
9703                 __connman_ipconfig_type2string(type), *interval);
9704
9705         service->online_timeout = g_timeout_add_seconds(*interval * *interval,
9706                                 redo_func, connman_service_ref(service));
9707
9708         /* Increment the interval for the next time, set a maximum timeout of
9709          * online_check_max_interval seconds * online_check_max_interval seconds.
9710          */
9711         if (*interval < online_check_max_interval)
9712                 (*interval)++;
9713 }
9714
9715 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
9716                                         enum connman_service_state new_state,
9717                                         enum connman_ipconfig_type type)
9718 {
9719         struct connman_ipconfig *ipconfig = NULL;
9720         enum connman_service_state old_state;
9721         enum connman_ipconfig_method method;
9722
9723         if (!service)
9724                 return -EINVAL;
9725
9726         switch (type) {
9727         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
9728         case CONNMAN_IPCONFIG_TYPE_ALL:
9729                 return -EINVAL;
9730
9731         case CONNMAN_IPCONFIG_TYPE_IPV4:
9732                 old_state = service->state_ipv4;
9733                 ipconfig = service->ipconfig_ipv4;
9734
9735                 break;
9736
9737         case CONNMAN_IPCONFIG_TYPE_IPV6:
9738                 old_state = service->state_ipv6;
9739                 ipconfig = service->ipconfig_ipv6;
9740
9741                 break;
9742         }
9743
9744         if (!ipconfig)
9745                 return -EINVAL;
9746
9747         method = __connman_ipconfig_get_method(ipconfig);
9748
9749         switch (method) {
9750         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
9751         case CONNMAN_IPCONFIG_METHOD_OFF:
9752                 if (new_state != CONNMAN_SERVICE_STATE_IDLE)
9753                         connman_warn("ipconfig state %d ipconfig method %d",
9754                                 new_state, method);
9755
9756 #if defined TIZEN_EXT
9757                 if (old_state != CONNMAN_SERVICE_STATE_READY &&
9758                                 old_state != CONNMAN_SERVICE_STATE_ONLINE)
9759 #endif
9760                 new_state = CONNMAN_SERVICE_STATE_IDLE;
9761                 break;
9762
9763         case CONNMAN_IPCONFIG_METHOD_FIXED:
9764         case CONNMAN_IPCONFIG_METHOD_MANUAL:
9765         case CONNMAN_IPCONFIG_METHOD_DHCP:
9766         case CONNMAN_IPCONFIG_METHOD_AUTO:
9767                 break;
9768
9769         }
9770
9771         /* Any change? */
9772         if (old_state == new_state)
9773                 return -EALREADY;
9774
9775 #if defined TIZEN_EXT
9776         __sync_synchronize();
9777         if (service->user_pdn_connection_refcount > 0 &&
9778                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
9779                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
9780                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
9781                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
9782                         service->user_pdn_connection_refcount = 0;
9783                         __sync_synchronize();
9784                 }
9785 #endif
9786
9787         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
9788                 service, service ? service->identifier : NULL,
9789                 old_state, state2string(old_state),
9790                 new_state, state2string(new_state),
9791                 type, __connman_ipconfig_type2string(type));
9792
9793         switch (new_state) {
9794         case CONNMAN_SERVICE_STATE_UNKNOWN:
9795         case CONNMAN_SERVICE_STATE_ASSOCIATION:
9796                 break;
9797         case CONNMAN_SERVICE_STATE_CONFIGURATION:
9798                 break;
9799         case CONNMAN_SERVICE_STATE_READY:
9800 #if defined TIZEN_EXT
9801                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
9802                                 __connman_service_is_internet_profile(service) != TRUE) {
9803                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9804                                 service_rp_filter(service, TRUE);
9805
9806                         break;
9807                 }
9808 #endif
9809                 if (connman_setting_get_bool("EnableOnlineCheck"))
9810                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
9811 #if !defined TIZEN_EXT
9812                                 check_proxy_setup(service);
9813 #endif
9814 #if defined TIZEN_MAINTAIN_ONLINE
9815 /*                              if (old_state == CONNMAN_SERVICE_STATE_ONLINE) */
9816                                         check_proxy_setup(service);
9817 #endif
9818                         } else {
9819                                 __connman_service_wispr_start(service, type);
9820                         }
9821                 else
9822                         connman_info("Online check disabled. "
9823                                 "Default service remains in READY state.");
9824                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9825                         service_rp_filter(service, true);
9826                 set_mdns(service, service->mdns_config);
9827                 break;
9828         case CONNMAN_SERVICE_STATE_ONLINE:
9829                 break;
9830         case CONNMAN_SERVICE_STATE_DISCONNECT:
9831                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
9832                         return -EINVAL;
9833
9834                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9835                         service_rp_filter(service, false);
9836
9837                 break;
9838
9839         case CONNMAN_SERVICE_STATE_IDLE:
9840         case CONNMAN_SERVICE_STATE_FAILURE:
9841                 __connman_ipconfig_disable(ipconfig);
9842
9843                 break;
9844         }
9845
9846         if (is_connected(old_state) && !is_connected(new_state)) {
9847                 nameserver_remove_all(service, type);
9848                 cancel_online_check(service);
9849         }
9850
9851         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9852                 service->state_ipv4 = new_state;
9853         else
9854                 service->state_ipv6 = new_state;
9855
9856         if (!is_connected(old_state) && is_connected(new_state))
9857                 nameserver_add_all(service, type);
9858
9859         __connman_timeserver_sync(service);
9860
9861 #if defined TIZEN_EXT
9862         int ret = service_indicate_state(service);
9863         /*Sent the Ready changed signal again in case IPv4 IP set
9864           after IPv6 IP set*/
9865
9866         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
9867                         && new_state == CONNMAN_SERVICE_STATE_READY) {
9868                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
9869                 state_changed(service);
9870         }
9871
9872         return ret;
9873 #endif
9874         return service_indicate_state(service);
9875 }
9876
9877 static bool prepare_network(struct connman_service *service)
9878 {
9879         enum connman_network_type type;
9880         unsigned int ssid_len;
9881
9882         type = connman_network_get_type(service->network);
9883
9884         switch (type) {
9885         case CONNMAN_NETWORK_TYPE_UNKNOWN:
9886         case CONNMAN_NETWORK_TYPE_VENDOR:
9887                 return false;
9888         case CONNMAN_NETWORK_TYPE_WIFI:
9889                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
9890                                                 &ssid_len))
9891                         return false;
9892
9893                 if (service->passphrase)
9894                         connman_network_set_string(service->network,
9895                                 "WiFi.Passphrase", service->passphrase);
9896                 break;
9897         case CONNMAN_NETWORK_TYPE_ETHERNET:
9898         case CONNMAN_NETWORK_TYPE_GADGET:
9899         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
9900         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
9901         case CONNMAN_NETWORK_TYPE_CELLULAR:
9902                 break;
9903         }
9904
9905         return true;
9906 }
9907
9908 static void prepare_8021x(struct connman_service *service)
9909 {
9910         if (service->eap)
9911                 connman_network_set_string(service->network, "WiFi.EAP",
9912                                                                 service->eap);
9913
9914         if (service->identity)
9915                 connman_network_set_string(service->network, "WiFi.Identity",
9916                                                         service->identity);
9917
9918         if (service->anonymous_identity)
9919                 connman_network_set_string(service->network,
9920                                                 "WiFi.AnonymousIdentity",
9921                                                 service->anonymous_identity);
9922
9923         if (service->ca_cert_file)
9924                 connman_network_set_string(service->network, "WiFi.CACertFile",
9925                                                         service->ca_cert_file);
9926
9927         if (service->subject_match)
9928                 connman_network_set_string(service->network, "WiFi.SubjectMatch",
9929                                                         service->subject_match);
9930
9931         if (service->altsubject_match)
9932                 connman_network_set_string(service->network, "WiFi.AltSubjectMatch",
9933                                                         service->altsubject_match);
9934
9935         if (service->domain_suffix_match)
9936                 connman_network_set_string(service->network, "WiFi.DomainSuffixMatch",
9937                                                         service->domain_suffix_match);
9938
9939         if (service->domain_match)
9940                 connman_network_set_string(service->network, "WiFi.DomainMatch",
9941                                                         service->domain_match);
9942
9943         if (service->client_cert_file)
9944                 connman_network_set_string(service->network,
9945                                                 "WiFi.ClientCertFile",
9946                                                 service->client_cert_file);
9947
9948         if (service->private_key_file)
9949                 connman_network_set_string(service->network,
9950                                                 "WiFi.PrivateKeyFile",
9951                                                 service->private_key_file);
9952
9953         if (service->private_key_passphrase)
9954                 connman_network_set_string(service->network,
9955                                         "WiFi.PrivateKeyPassphrase",
9956                                         service->private_key_passphrase);
9957
9958         if (service->phase2)
9959                 connman_network_set_string(service->network, "WiFi.Phase2",
9960                                                         service->phase2);
9961
9962 #if defined TIZEN_EXT
9963         if (service->keymgmt_type)
9964                 connman_network_set_string(service->network, "WiFi.KeymgmtType",
9965                                                         service->keymgmt_type);
9966
9967         DBG("service->phase1 : %s", service->phase1);
9968         if (service->phase1)
9969                 connman_network_set_string(service->network, "WiFi.Phase1",
9970                                                         service->phase1);
9971 #endif
9972 }
9973
9974 #if defined TIZEN_EXT
9975 static bool has_valid_configuration_object(struct connman_service *service)
9976 {
9977         return service->connector && service->c_sign_key && service->net_access_key;
9978 }
9979
9980 static void prepare_dpp(struct connman_service *service)
9981 {
9982         DBG("prepare dpp");
9983         if (service->connector)
9984                 connman_network_set_string(service->network, "WiFi.Connector",
9985                                                                 service->connector);
9986
9987         if (service->c_sign_key)
9988                 connman_network_set_string(service->network, "WiFi.CSignKey",
9989                                                         service->c_sign_key);
9990
9991         if (service->net_access_key)
9992                 connman_network_set_string(service->network, "WiFi.NetAccessKey",
9993                                                         service->net_access_key);
9994 }
9995 #endif
9996
9997 static int service_connect(struct connman_service *service)
9998 {
9999         int err;
10000
10001         if (service->hidden)
10002                 return -EPERM;
10003
10004 #if defined TIZEN_EXT
10005         GList *list;
10006         int index;
10007
10008         index = __connman_service_get_index(service);
10009
10010         for (list = service_list; list; list = list->next) {
10011                 struct connman_service *temp = list->data;
10012
10013                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
10014                         break;
10015
10016                 if (!is_connecting(temp->state) && !is_connected(temp->state))
10017                         break;
10018
10019                 if (service == temp)
10020                         continue;
10021
10022                 if (service->type != temp->type)
10023                         continue;
10024
10025                 if (__connman_service_get_index(temp) == index &&
10026                                 __connman_service_disconnect(temp) == -EINPROGRESS)
10027                         return -EINPROGRESS;
10028         }
10029 #endif
10030
10031         switch (service->type) {
10032         case CONNMAN_SERVICE_TYPE_UNKNOWN:
10033         case CONNMAN_SERVICE_TYPE_SYSTEM:
10034         case CONNMAN_SERVICE_TYPE_GPS:
10035         case CONNMAN_SERVICE_TYPE_P2P:
10036 #if defined TIZEN_EXT_WIFI_MESH
10037         case CONNMAN_SERVICE_TYPE_MESH:
10038 #endif
10039                 return -EINVAL;
10040         case CONNMAN_SERVICE_TYPE_ETHERNET:
10041         case CONNMAN_SERVICE_TYPE_GADGET:
10042         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
10043         case CONNMAN_SERVICE_TYPE_CELLULAR:
10044         case CONNMAN_SERVICE_TYPE_VPN:
10045                 break;
10046         case CONNMAN_SERVICE_TYPE_WIFI:
10047                 switch (service->security) {
10048                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
10049                 case CONNMAN_SERVICE_SECURITY_NONE:
10050 #if defined TIZEN_EXT
10051                 case CONNMAN_SERVICE_SECURITY_OWE:
10052 #endif
10053                         break;
10054                 case CONNMAN_SERVICE_SECURITY_WEP:
10055                 case CONNMAN_SERVICE_SECURITY_PSK:
10056                 case CONNMAN_SERVICE_SECURITY_WPA:
10057                 case CONNMAN_SERVICE_SECURITY_RSN:
10058 #if defined TIZEN_EXT
10059                 case CONNMAN_SERVICE_SECURITY_SAE:
10060 #endif
10061                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
10062                                 return -ENOKEY;
10063
10064                         if (!service->passphrase) {
10065                                 if (!service->network)
10066                                         return -EOPNOTSUPP;
10067
10068                                 if (!service->wps ||
10069                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
10070                                         return -ENOKEY;
10071                         }
10072                         break;
10073
10074 #if defined TIZEN_EXT
10075                 case CONNMAN_SERVICE_SECURITY_DPP:
10076                         if (has_valid_configuration_object(service) &&
10077                                         !service->network)
10078                                 return -EINVAL;
10079                         break;
10080 #endif
10081                 case CONNMAN_SERVICE_SECURITY_8021X:
10082                         if (!service->eap) {
10083                                 connman_warn("EAP type has not been found. "
10084                                         "Most likely ConnMan is not able to "
10085                                         "find a configuration for given "
10086                                         "8021X network. "
10087                                         "Check SSID or Name match with the "
10088                                         "network name.");
10089                                 return -EINVAL;
10090                         }
10091
10092 #if defined TIZEN_EXT
10093                         /*
10094                          * never request credentials if using EAP-TLS, EAP-SIM
10095                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
10096                          * need to be fully provisioned)
10097                          */
10098                         DBG("service eap: %s", service->eap);
10099                         if (g_str_equal(service->eap, "tls") ||
10100                                 g_str_equal(service->eap, "sim") ||
10101                                 g_str_equal(service->eap, "aka") ||
10102                                 g_str_equal(service->eap, "aka'") ||
10103                                 g_str_equal(service->eap, "pwd") ||
10104                                 g_str_equal(service->eap, "fast"))
10105                                 break;
10106 #else
10107                         /*
10108                          * never request credentials if using EAP-TLS
10109                          * (EAP-TLS networks need to be fully provisioned)
10110                          */
10111                         if (g_str_equal(service->eap, "tls"))
10112                                 break;
10113
10114 #endif
10115                         /*
10116                          * Return -ENOKEY if either identity or passphrase is
10117                          * missing. Agent provided credentials can be used as
10118                          * fallback if needed.
10119                          */
10120                         if (((!service->identity &&
10121                                         !service->agent_identity) ||
10122                                         !service->passphrase) ||
10123                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
10124                                 return -ENOKEY;
10125
10126                         break;
10127                 }
10128                 break;
10129         }
10130
10131         if (service->network) {
10132                 if (!prepare_network(service))
10133                         return -EINVAL;
10134
10135                 switch (service->security) {
10136                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
10137                 case CONNMAN_SERVICE_SECURITY_NONE:
10138                 case CONNMAN_SERVICE_SECURITY_WEP:
10139                 case CONNMAN_SERVICE_SECURITY_PSK:
10140                 case CONNMAN_SERVICE_SECURITY_WPA:
10141                 case CONNMAN_SERVICE_SECURITY_RSN:
10142 #if defined TIZEN_EXT
10143                 case CONNMAN_SERVICE_SECURITY_SAE:
10144                 case CONNMAN_SERVICE_SECURITY_OWE:
10145                         break;
10146                 case CONNMAN_SERVICE_SECURITY_DPP:
10147                         prepare_dpp(service);
10148 #endif
10149                         break;
10150                 case CONNMAN_SERVICE_SECURITY_8021X:
10151                         prepare_8021x(service);
10152                         break;
10153                 }
10154
10155                 if (__connman_stats_service_register(service) == 0) {
10156                         __connman_stats_get(service, false,
10157                                                 &service->stats.data);
10158                         __connman_stats_get(service, true,
10159                                                 &service->stats_roaming.data);
10160                 }
10161
10162                 err = __connman_network_connect(service->network);
10163         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
10164                                         service->provider)
10165                 err = __connman_provider_connect(service->provider,
10166                                                 get_dbus_sender(service));
10167         else
10168                 return -EOPNOTSUPP;
10169
10170         if (err < 0) {
10171                 if (err != -EINPROGRESS) {
10172                         __connman_service_ipconfig_indicate_state(service,
10173                                                 CONNMAN_SERVICE_STATE_FAILURE,
10174                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
10175                         __connman_service_ipconfig_indicate_state(service,
10176                                                 CONNMAN_SERVICE_STATE_FAILURE,
10177                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
10178                         __connman_stats_service_unregister(service);
10179                 }
10180         }
10181
10182         return err;
10183 }
10184
10185 int __connman_service_connect(struct connman_service *service,
10186                         enum connman_service_connect_reason reason)
10187 {
10188         int err;
10189
10190         DBG("service %p state %s connect reason %s -> %s",
10191                 service, state2string(service->state),
10192                 reason2string(service->connect_reason),
10193                 reason2string(reason));
10194
10195         if (is_connected(service->state))
10196                 return -EISCONN;
10197
10198         if (is_connecting(service->state))
10199                 return -EALREADY;
10200
10201         switch (service->type) {
10202         case CONNMAN_SERVICE_TYPE_UNKNOWN:
10203         case CONNMAN_SERVICE_TYPE_SYSTEM:
10204         case CONNMAN_SERVICE_TYPE_GPS:
10205         case CONNMAN_SERVICE_TYPE_P2P:
10206 #if defined TIZEN_EXT_WIFI_MESH
10207         case CONNMAN_SERVICE_TYPE_MESH:
10208 #endif
10209                 return -EINVAL;
10210
10211         case CONNMAN_SERVICE_TYPE_ETHERNET:
10212         case CONNMAN_SERVICE_TYPE_GADGET:
10213         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
10214         case CONNMAN_SERVICE_TYPE_CELLULAR:
10215         case CONNMAN_SERVICE_TYPE_VPN:
10216         case CONNMAN_SERVICE_TYPE_WIFI:
10217                 break;
10218         }
10219
10220         if (!is_ipconfig_usable(service))
10221                 return -ENOLINK;
10222
10223         __connman_service_clear_error(service);
10224
10225         if (service->network && service->autoconnect &&
10226                         __connman_network_native_autoconnect(service->network)) {
10227                 DBG("service %p switch connecting reason to native", service);
10228                 reason = CONNMAN_SERVICE_CONNECT_REASON_NATIVE;
10229         }
10230
10231         err = service_connect(service);
10232
10233         DBG("service %p err %d", service, err);
10234
10235         service->connect_reason = reason;
10236 #if defined TIZEN_EXT
10237         connect_reason_changed(service);
10238 #endif
10239
10240         if (err >= 0)
10241                 return 0;
10242
10243         if (err == -EINPROGRESS) {
10244                 if (service->timeout == 0)
10245                         service->timeout = g_timeout_add_seconds(
10246                                 CONNECT_TIMEOUT, connect_timeout, service);
10247
10248                 return -EINPROGRESS;
10249         }
10250
10251         if (service->network)
10252                 __connman_network_disconnect(service->network);
10253         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
10254                                 service->provider)
10255                         connman_provider_disconnect(service->provider);
10256
10257         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
10258                 if (err == -ENOKEY || err == -EPERM) {
10259                         DBusMessage *pending = NULL;
10260                         const char *dbus_sender = get_dbus_sender(service);
10261
10262                         /*
10263                          * We steal the reply here. The idea is that the
10264                          * connecting client will see the connection status
10265                          * after the real hidden network is connected or
10266                          * connection failed.
10267                          */
10268                         if (service->hidden) {
10269                                 pending = service->pending;
10270                                 service->pending = NULL;
10271                         }
10272
10273                         err = __connman_agent_request_passphrase_input(service,
10274                                         request_input_cb,
10275                                         dbus_sender,
10276                                         pending);
10277                         if (service->hidden && err != -EINPROGRESS)
10278                                 service->pending = pending;
10279
10280                         return err;
10281                 }
10282         }
10283
10284         return err;
10285 }
10286
10287 int __connman_service_disconnect(struct connman_service *service)
10288 {
10289         int err;
10290
10291         DBG("service %p", service);
10292
10293         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
10294         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
10295
10296         connman_agent_cancel(service);
10297
10298         __connman_stats_service_unregister(service);
10299
10300         if (service->network) {
10301                 err = __connman_network_disconnect(service->network);
10302         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
10303                                         service->provider)
10304                 err = connman_provider_disconnect(service->provider);
10305         else
10306                 return -EOPNOTSUPP;
10307
10308         if (err < 0 && err != -EINPROGRESS)
10309                 return err;
10310
10311         __connman_6to4_remove(service->ipconfig_ipv4);
10312
10313         if (service->ipconfig_ipv4)
10314                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
10315                                                         NULL);
10316         else
10317                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
10318                                                         NULL);
10319
10320 #if defined TIZEN_EXT
10321         /**
10322           * Skip the functions If there is any connected profiles
10323           * that use same interface
10324           */
10325         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
10326                 __connman_service_get_connected_count_of_iface(service) <= 0) {
10327 #endif
10328         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
10329         settings_changed(service, service->ipconfig_ipv4);
10330
10331         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
10332         settings_changed(service, service->ipconfig_ipv6);
10333
10334         __connman_ipconfig_disable(service->ipconfig_ipv4);
10335         __connman_ipconfig_disable(service->ipconfig_ipv6);
10336 #if defined TIZEN_EXT
10337         }
10338 #endif
10339
10340         return err;
10341 }
10342
10343 int __connman_service_disconnect_all(void)
10344 {
10345         struct connman_service *service;
10346         GSList *services = NULL, *list;
10347         GList *iter;
10348
10349         DBG("");
10350
10351         for (iter = service_list; iter; iter = iter->next) {
10352                 service = iter->data;
10353
10354                 if (!is_connected(service->state))
10355                         break;
10356
10357                 services = g_slist_prepend(services, service);
10358         }
10359
10360         for (list = services; list; list = list->next) {
10361                 struct connman_service *service = list->data;
10362
10363                 service->ignore = true;
10364
10365                 __connman_service_disconnect(service);
10366         }
10367
10368         g_slist_free(services);
10369
10370         return 0;
10371 }
10372
10373 /**
10374  * lookup_by_identifier:
10375  * @identifier: service identifier
10376  *
10377  * Look up a service by identifier (reference count will not be increased)
10378  */
10379 static struct connman_service *lookup_by_identifier(const char *identifier)
10380 {
10381         return g_hash_table_lookup(service_hash, identifier);
10382 }
10383
10384 struct connman_service *connman_service_lookup_from_identifier(const char* identifier)
10385 {
10386         return identifier ? lookup_by_identifier(identifier) : NULL;
10387 }
10388
10389 struct provision_user_data {
10390         const char *ident;
10391         int ret;
10392 };
10393
10394 static void provision_changed(gpointer value, gpointer user_data)
10395 {
10396         struct connman_service *service = value;
10397         struct provision_user_data *data = user_data;
10398         const char *path = data->ident;
10399         int ret;
10400
10401         ret = __connman_config_provision_service_ident(service, path,
10402                         service->config_file, service->config_entry);
10403         if (ret > 0)
10404                 data->ret = ret;
10405 }
10406
10407 int __connman_service_provision_changed(const char *ident)
10408 {
10409         struct provision_user_data data = {
10410                 .ident = ident,
10411                 .ret = 0
10412         };
10413
10414         g_list_foreach(service_list, provision_changed, (void *)&data);
10415
10416         /*
10417          * Because the provision_changed() might have set some services
10418          * as favorite, we must sort the sequence now.
10419          */
10420         if (services_dirty) {
10421                 services_dirty = false;
10422
10423                 service_list_sort();
10424
10425                 __connman_connection_update_gateway();
10426         }
10427
10428         return data.ret;
10429 }
10430
10431 void __connman_service_set_config(struct connman_service *service,
10432                                 const char *file_id, const char *entry)
10433 {
10434         if (!service)
10435                 return;
10436
10437         g_free(service->config_file);
10438         service->config_file = g_strdup(file_id);
10439
10440         g_free(service->config_entry);
10441         service->config_entry = g_strdup(entry);
10442 }
10443
10444 /**
10445  * __connman_service_get:
10446  * @identifier: service identifier
10447  *
10448  * Look up a service by identifier or create a new one if not found
10449  */
10450 static struct connman_service *service_get(const char *identifier)
10451 {
10452         struct connman_service *service;
10453
10454         service = g_hash_table_lookup(service_hash, identifier);
10455         if (service) {
10456                 connman_service_ref(service);
10457                 return service;
10458         }
10459
10460         service = connman_service_create();
10461         if (!service)
10462                 return NULL;
10463 #if defined TIZEN_EXT
10464         if (!simplified_log)
10465 #endif
10466         DBG("service %p", service);
10467
10468         service->identifier = g_strdup(identifier);
10469
10470         service_list = g_list_insert_sorted(service_list, service,
10471                                                 service_compare);
10472
10473         g_hash_table_insert(service_hash, service->identifier, service);
10474
10475         return service;
10476 }
10477
10478 static int service_register(struct connman_service *service)
10479 {
10480 #if defined TIZEN_EXT
10481         if (!simplified_log)
10482 #endif
10483         DBG("service %p", service);
10484
10485         if (service->path)
10486                 return -EALREADY;
10487
10488         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
10489                                                 service->identifier);
10490
10491         DBG("path %s", service->path);
10492
10493 #if defined TIZEN_EXT
10494         int ret;
10495         service_load(service);
10496         ret = service_ext_load(service);
10497         if (ret == -ERANGE)
10498                 service_ext_save(service);
10499         ret = __connman_config_provision_service(service);
10500         if (ret < 0 && !simplified_log)
10501                 DBG("Failed to provision service");
10502 #else
10503         if (__connman_config_provision_service(service) < 0)
10504                 service_load(service);
10505 #endif
10506
10507         g_dbus_register_interface(connection, service->path,
10508                                         CONNMAN_SERVICE_INTERFACE,
10509                                         service_methods, service_signals,
10510                                                         NULL, service, NULL);
10511
10512         if (__connman_config_provision_service(service) < 0)
10513                 service_load(service);
10514
10515         service_list_sort();
10516
10517         __connman_connection_update_gateway();
10518
10519         return 0;
10520 }
10521
10522 static void service_up(struct connman_ipconfig *ipconfig,
10523                 const char *ifname)
10524 {
10525         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10526
10527         DBG("%s up", ifname);
10528
10529         link_changed(service);
10530
10531         service->stats.valid = false;
10532         service->stats_roaming.valid = false;
10533 }
10534
10535 static void service_down(struct connman_ipconfig *ipconfig,
10536                         const char *ifname)
10537 {
10538         DBG("%s down", ifname);
10539 }
10540
10541 static void service_lower_up(struct connman_ipconfig *ipconfig,
10542                         const char *ifname)
10543 {
10544         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10545
10546         DBG("%s lower up", ifname);
10547
10548         stats_start(service);
10549 }
10550
10551 static void service_lower_down(struct connman_ipconfig *ipconfig,
10552                         const char *ifname)
10553 {
10554         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10555
10556         DBG("%s lower down", ifname);
10557
10558         stats_stop(service);
10559         service_save(service);
10560 }
10561
10562 static void service_ip_bound(struct connman_ipconfig *ipconfig,
10563                         const char *ifname)
10564 {
10565         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10566         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
10567         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
10568 #if defined TIZEN_EXT
10569         int err;
10570 #endif
10571
10572         DBG("%s ip bound", ifname);
10573
10574         type = __connman_ipconfig_get_config_type(ipconfig);
10575         method = __connman_ipconfig_get_method(ipconfig);
10576
10577         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
10578                                                         type, method);
10579
10580         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
10581                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
10582 #if defined TIZEN_EXT
10583         {
10584                 err = __connman_ipconfig_gateway_add(ipconfig, service);
10585
10586                 if(err < 0)
10587                         DBG("Failed to add gateway");
10588         }
10589 #else
10590                 __connman_service_ipconfig_indicate_state(service,
10591                                                 CONNMAN_SERVICE_STATE_READY,
10592                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
10593 #endif
10594
10595         settings_changed(service, ipconfig);
10596         address_updated(service, type);
10597 }
10598
10599 static void service_ip_release(struct connman_ipconfig *ipconfig,
10600                         const char *ifname)
10601 {
10602         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10603         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
10604         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
10605
10606         DBG("%s ip release", ifname);
10607
10608         type = __connman_ipconfig_get_config_type(ipconfig);
10609         method = __connman_ipconfig_get_method(ipconfig);
10610
10611         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
10612                                                         type, method);
10613
10614         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
10615                         method == CONNMAN_IPCONFIG_METHOD_OFF)
10616                 __connman_service_ipconfig_indicate_state(service,
10617                                         CONNMAN_SERVICE_STATE_DISCONNECT,
10618                                         CONNMAN_IPCONFIG_TYPE_IPV6);
10619
10620         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
10621                         method == CONNMAN_IPCONFIG_METHOD_OFF)
10622                 __connman_service_ipconfig_indicate_state(service,
10623                                         CONNMAN_SERVICE_STATE_DISCONNECT,
10624                                         CONNMAN_IPCONFIG_TYPE_IPV4);
10625
10626         settings_changed(service, ipconfig);
10627 }
10628
10629 static void service_route_changed(struct connman_ipconfig *ipconfig,
10630                                 const char *ifname)
10631 {
10632         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10633
10634         DBG("%s route changed", ifname);
10635
10636         settings_changed(service, ipconfig);
10637 }
10638
10639 static const struct connman_ipconfig_ops service_ops = {
10640         .up             = service_up,
10641         .down           = service_down,
10642         .lower_up       = service_lower_up,
10643         .lower_down     = service_lower_down,
10644         .ip_bound       = service_ip_bound,
10645         .ip_release     = service_ip_release,
10646         .route_set      = service_route_changed,
10647         .route_unset    = service_route_changed,
10648 };
10649
10650 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
10651                 int index, enum connman_ipconfig_method method)
10652 {
10653         struct connman_ipconfig *ipconfig_ipv4;
10654
10655         ipconfig_ipv4 = __connman_ipconfig_create(index,
10656                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
10657         if (!ipconfig_ipv4)
10658                 return NULL;
10659
10660         __connman_ipconfig_set_method(ipconfig_ipv4, method);
10661
10662         __connman_ipconfig_set_data(ipconfig_ipv4, service);
10663
10664         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
10665
10666         return ipconfig_ipv4;
10667 }
10668
10669 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
10670                 int index)
10671 {
10672         struct connman_ipconfig *ipconfig_ipv6;
10673
10674         ipconfig_ipv6 = __connman_ipconfig_create(index,
10675                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
10676         if (!ipconfig_ipv6)
10677                 return NULL;
10678
10679         __connman_ipconfig_set_data(ipconfig_ipv6, service);
10680
10681         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
10682
10683         return ipconfig_ipv6;
10684 }
10685
10686 void __connman_service_read_ip4config(struct connman_service *service)
10687 {
10688         GKeyFile *keyfile;
10689
10690         if (!service->ipconfig_ipv4)
10691                 return;
10692
10693         keyfile = connman_storage_load_service(service->identifier);
10694         if (!keyfile)
10695                 return;
10696
10697         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
10698                                 service->identifier, "IPv4.");
10699
10700         g_key_file_free(keyfile);
10701 }
10702
10703 void connman_service_create_ip4config(struct connman_service *service,
10704                                         int index)
10705 {
10706         DBG("ipv4 %p", service->ipconfig_ipv4);
10707
10708         if (service->ipconfig_ipv4)
10709                 return;
10710
10711         service->ipconfig_ipv4 = create_ip4config(service, index,
10712                         CONNMAN_IPCONFIG_METHOD_DHCP);
10713         __connman_service_read_ip4config(service);
10714 }
10715
10716 void __connman_service_read_ip6config(struct connman_service *service)
10717 {
10718         GKeyFile *keyfile;
10719
10720         if (!service->ipconfig_ipv6)
10721                 return;
10722
10723         keyfile = connman_storage_load_service(service->identifier);
10724         if (!keyfile)
10725                 return;
10726
10727         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
10728                                 service->identifier, "IPv6.");
10729
10730         g_key_file_free(keyfile);
10731 }
10732
10733 void connman_service_create_ip6config(struct connman_service *service,
10734                                                                 int index)
10735 {
10736         DBG("ipv6 %p", service->ipconfig_ipv6);
10737
10738         if (service->ipconfig_ipv6)
10739                 return;
10740
10741         service->ipconfig_ipv6 = create_ip6config(service, index);
10742
10743         __connman_service_read_ip6config(service);
10744 }
10745
10746 /**
10747  * connman_service_lookup_from_network:
10748  * @network: network structure
10749  *
10750  * Look up a service by network (reference count will not be increased)
10751  */
10752 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
10753 {
10754         struct connman_service *service;
10755         const char *ident, *group;
10756         char *name;
10757
10758         if (!network)
10759                 return NULL;
10760
10761         ident = __connman_network_get_ident(network);
10762         if (!ident)
10763                 return NULL;
10764
10765         group = connman_network_get_group(network);
10766         if (!group)
10767                 return NULL;
10768
10769         name = g_strdup_printf("%s_%s_%s",
10770                         __connman_network_get_type(network), ident, group);
10771         service = lookup_by_identifier(name);
10772         g_free(name);
10773
10774         return service;
10775 }
10776
10777 struct connman_service *__connman_service_lookup_from_index(int index)
10778 {
10779         struct connman_service *service;
10780         GList *list;
10781
10782         for (list = service_list; list; list = list->next) {
10783                 service = list->data;
10784
10785                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
10786                                                         == index)
10787                         return service;
10788
10789                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
10790                                                         == index)
10791                         return service;
10792         }
10793
10794         return NULL;
10795 }
10796
10797 const char *connman_service_get_identifier(struct connman_service *service)
10798 {
10799         return service ? service->identifier : NULL;
10800 }
10801
10802 const char *__connman_service_get_path(struct connman_service *service)
10803 {
10804         return service->path;
10805 }
10806
10807 const char *__connman_service_get_name(struct connman_service *service)
10808 {
10809         return service->name;
10810 }
10811
10812 enum connman_service_state connman_service_get_state(struct connman_service *service)
10813 {
10814         return service ? service->state : CONNMAN_SERVICE_STATE_UNKNOWN;
10815 }
10816
10817 static enum connman_service_type convert_network_type(struct connman_network *network)
10818 {
10819         enum connman_network_type type = connman_network_get_type(network);
10820
10821         switch (type) {
10822         case CONNMAN_NETWORK_TYPE_UNKNOWN:
10823         case CONNMAN_NETWORK_TYPE_VENDOR:
10824                 break;
10825         case CONNMAN_NETWORK_TYPE_ETHERNET:
10826                 return CONNMAN_SERVICE_TYPE_ETHERNET;
10827         case CONNMAN_NETWORK_TYPE_WIFI:
10828                 return CONNMAN_SERVICE_TYPE_WIFI;
10829         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
10830         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
10831                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
10832         case CONNMAN_NETWORK_TYPE_CELLULAR:
10833                 return CONNMAN_SERVICE_TYPE_CELLULAR;
10834         case CONNMAN_NETWORK_TYPE_GADGET:
10835                 return CONNMAN_SERVICE_TYPE_GADGET;
10836         }
10837
10838         return CONNMAN_SERVICE_TYPE_UNKNOWN;
10839 }
10840
10841 static enum connman_service_security convert_wifi_security(const char *security)
10842 {
10843         if (!security)
10844                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
10845         else if (g_str_equal(security, "none"))
10846                 return CONNMAN_SERVICE_SECURITY_NONE;
10847         else if (g_str_equal(security, "wep"))
10848                 return CONNMAN_SERVICE_SECURITY_WEP;
10849         else if (g_str_equal(security, "psk"))
10850                 return CONNMAN_SERVICE_SECURITY_PSK;
10851         else if (g_str_equal(security, "ieee8021x"))
10852                 return CONNMAN_SERVICE_SECURITY_8021X;
10853         else if (g_str_equal(security, "wpa"))
10854                 return CONNMAN_SERVICE_SECURITY_WPA;
10855         else if (g_str_equal(security, "rsn"))
10856                 return CONNMAN_SERVICE_SECURITY_RSN;
10857 #if defined TIZEN_EXT
10858         else if (g_str_equal(security, "sae"))
10859                 return CONNMAN_SERVICE_SECURITY_SAE;
10860         else if (g_str_equal(security, "owe"))
10861                 return CONNMAN_SERVICE_SECURITY_OWE;
10862         else if (g_str_equal(security, "dpp"))
10863                 return CONNMAN_SERVICE_SECURITY_DPP;
10864         else if (g_str_equal(security, "ft_psk") == TRUE)
10865                 return CONNMAN_SERVICE_SECURITY_PSK;
10866         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
10867                 return CONNMAN_SERVICE_SECURITY_8021X;
10868 #endif
10869         else
10870                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
10871 }
10872
10873 #if defined TIZEN_EXT
10874 int check_passphrase_ext(struct connman_network *network,
10875                                         const char *passphrase)
10876 {
10877         const char *str;
10878         enum connman_service_security security;
10879
10880         str = connman_network_get_string(network, "WiFi.Security");
10881         security = convert_wifi_security(str);
10882
10883         return __connman_service_check_passphrase(security, passphrase);
10884 }
10885 #endif
10886
10887 static void update_wps_values(struct connman_service *service,
10888                                 struct connman_network *network)
10889 {
10890         bool wps = connman_network_get_bool(network, "WiFi.WPS");
10891         bool wps_advertising = connman_network_get_bool(network,
10892                                                         "WiFi.WPSAdvertising");
10893
10894         if (service->wps != wps ||
10895                         service->wps_advertizing != wps_advertising) {
10896                 service->wps = wps;
10897                 service->wps_advertizing = wps_advertising;
10898                 security_changed(service);
10899         }
10900 }
10901
10902 static void update_from_network(struct connman_service *service,
10903                                         struct connman_network *network)
10904 {
10905         uint8_t strength = service->strength;
10906         const char *str;
10907
10908         DBG("service %p network %p", service, network);
10909
10910         if (is_connected(service->state))
10911                 return;
10912
10913         if (is_connecting(service->state))
10914                 return;
10915
10916         str = connman_network_get_string(network, "Name");
10917         if (str) {
10918                 g_free(service->name);
10919                 service->name = g_strdup(str);
10920                 service->hidden = false;
10921         } else {
10922                 g_free(service->name);
10923                 service->name = NULL;
10924                 service->hidden = true;
10925         }
10926
10927         service->strength = connman_network_get_strength(network);
10928         service->roaming = connman_network_get_bool(network, "Roaming");
10929
10930         if (service->strength == 0) {
10931                 /*
10932                  * Filter out 0-values; it's unclear what they mean
10933                  * and they cause anomalous sorting of the priority list.
10934                  */
10935                 service->strength = strength;
10936         }
10937
10938         str = connman_network_get_string(network, "WiFi.Security");
10939         service->security = convert_wifi_security(str);
10940
10941         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
10942                 update_wps_values(service, network);
10943
10944         if (service->strength > strength && service->network) {
10945                 connman_network_unref(service->network);
10946                 service->network = connman_network_ref(network);
10947
10948                 strength_changed(service);
10949         }
10950
10951         if (!service->network)
10952                 service->network = connman_network_ref(network);
10953
10954         service_list_sort();
10955 }
10956
10957 static void trigger_autoconnect(struct connman_service *service)
10958 {
10959         struct connman_device *device;
10960         bool native;
10961
10962         if (!service->favorite)
10963                 return;
10964
10965         native = __connman_network_native_autoconnect(service->network);
10966         if (native && service->autoconnect) {
10967                 DBG("trigger native autoconnect");
10968                 connman_network_set_autoconnect(service->network, true);
10969                 return;
10970         }
10971
10972         device = connman_network_get_device(service->network);
10973         if (device && connman_device_get_scanning(device, CONNMAN_SERVICE_TYPE_UNKNOWN))
10974                 return;
10975
10976         switch (service->type) {
10977         case CONNMAN_SERVICE_TYPE_UNKNOWN:
10978         case CONNMAN_SERVICE_TYPE_SYSTEM:
10979         case CONNMAN_SERVICE_TYPE_P2P:
10980 #if defined TIZEN_EXT_WIFI_MESH
10981                         case CONNMAN_SERVICE_TYPE_MESH:
10982 #endif
10983                 break;
10984
10985         case CONNMAN_SERVICE_TYPE_GADGET:
10986         case CONNMAN_SERVICE_TYPE_ETHERNET:
10987                 if (service->autoconnect) {
10988                         __connman_service_connect(service,
10989                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
10990                         break;
10991                 }
10992
10993                 /* fall through */
10994         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
10995         case CONNMAN_SERVICE_TYPE_GPS:
10996         case CONNMAN_SERVICE_TYPE_VPN:
10997         case CONNMAN_SERVICE_TYPE_WIFI:
10998         case CONNMAN_SERVICE_TYPE_CELLULAR:
10999                 do_auto_connect(service, CONNMAN_SERVICE_CONNECT_REASON_AUTO);
11000                 break;
11001         }
11002
11003 #if defined TIZEN_EXT
11004         /* TIZEN synchronizes below information when the service creates */
11005         if (service->eap != NULL)
11006                 connman_network_set_string(service->network, "WiFi.EAP",
11007                                 service->eap);
11008         if (service->identity != NULL)
11009                 connman_network_set_string(service->network, "WiFi.Identity",
11010                                 service->identity);
11011         if (service->phase2 != NULL)
11012                 connman_network_set_string(service->network, "WiFi.Phase2",
11013                                 service->phase2);
11014         if (service->eap != NULL)
11015                 connman_network_set_string(service->network, "WiFi.Connector",
11016                                 service->connector);
11017         if (service->identity != NULL)
11018                 connman_network_set_string(service->network, "WiFi.CSignKey",
11019                                 service->c_sign_key);
11020         if (service->phase2 != NULL)
11021                 connman_network_set_string(service->network, "WiFi.NetAccessKey",
11022                                 service->net_access_key);
11023 #endif
11024 }
11025
11026 /**
11027  * __connman_service_create_from_network:
11028  * @network: network structure
11029  *
11030  * Look up service by network and if not found, create one
11031  */
11032 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
11033 {
11034         struct connman_service *service;
11035         const char *ident, *group;
11036         char *name;
11037         unsigned int *auto_connect_types, *favorite_types;
11038         int i, index;
11039
11040         DBG("network %p", network);
11041
11042         if (!network)
11043                 return NULL;
11044
11045         ident = __connman_network_get_ident(network);
11046         if (!ident)
11047                 return NULL;
11048
11049         group = connman_network_get_group(network);
11050         if (!group)
11051                 return NULL;
11052
11053         name = g_strdup_printf("%s_%s_%s",
11054                         __connman_network_get_type(network), ident, group);
11055         service = service_get(name);
11056         g_free(name);
11057
11058         if (!service)
11059                 return NULL;
11060
11061         if (__connman_network_get_weakness(network))
11062                 return service;
11063
11064         if (service->path) {
11065                 update_from_network(service, network);
11066                 __connman_connection_update_gateway();
11067                 return service;
11068         }
11069
11070         service->type = convert_network_type(network);
11071
11072         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
11073         service->autoconnect = false;
11074         for (i = 0; auto_connect_types &&
11075                      auto_connect_types[i] != 0; i++) {
11076                 if (service->type == auto_connect_types[i]) {
11077                         service->autoconnect = true;
11078                         break;
11079                 }
11080         }
11081
11082         favorite_types = connman_setting_get_uint_list("DefaultFavoriteTechnologies");
11083         service->favorite = false;
11084         for (i = 0; favorite_types && favorite_types[i] != 0; i++) {
11085                 if (service->type == favorite_types[i]) {
11086                         service->favorite = true;
11087                         break;
11088                 }
11089         }
11090
11091         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
11092         service->state = combine_state(service->state_ipv4, service->state_ipv6);
11093
11094         update_from_network(service, network);
11095
11096         index = connman_network_get_index(network);
11097
11098         if (!service->ipconfig_ipv4)
11099                 service->ipconfig_ipv4 = create_ip4config(service, index,
11100                                 CONNMAN_IPCONFIG_METHOD_DHCP);
11101
11102         if (!service->ipconfig_ipv6)
11103                 service->ipconfig_ipv6 = create_ip6config(service, index);
11104
11105         service_register(service);
11106         service_schedule_added(service);
11107
11108         trigger_autoconnect(service);
11109
11110         __connman_notifier_service_add(service, service->name);
11111
11112         return service;
11113 }
11114
11115 #if defined TIZEN_EXT
11116 void __connman_service_notify_strength_changed(struct connman_network *network)
11117 {
11118         struct connman_service *service;
11119         uint8_t strength = 0;
11120
11121         service = connman_service_lookup_from_network(network);
11122         if (!service)
11123                 return;
11124
11125         if (!service->network)
11126                 return;
11127
11128         strength = connman_network_get_strength(service->network);
11129         if (strength == service->strength)
11130                 return;
11131
11132         service->strength = strength;
11133         if (!simplified_log)
11134                 DBG("Strength %d", strength);
11135         strength_changed(service);
11136         service_list_sort();
11137 }
11138 #endif
11139
11140 void __connman_service_update_from_network(struct connman_network *network)
11141 {
11142         bool need_sort = false;
11143         struct connman_service *service;
11144         uint8_t strength;
11145         bool roaming;
11146         const char *name;
11147         bool stats_enable;
11148 #if defined TIZEN_EXT
11149         bool need_save = false;
11150 #endif
11151
11152         service = connman_service_lookup_from_network(network);
11153         if (!service)
11154                 return;
11155
11156         if (!service->network)
11157                 return;
11158
11159 #if defined TIZEN_EXT
11160         if (service->storage_reload) {
11161                 service_load(service);
11162                 __connman_service_set_storage_reload(service, false);
11163         }
11164 #endif
11165
11166         name = connman_network_get_string(service->network, "Name");
11167         if (g_strcmp0(service->name, name) != 0) {
11168                 g_free(service->name);
11169                 service->name = g_strdup(name);
11170
11171                 if (allow_property_changed(service))
11172                         connman_dbus_property_changed_basic(service->path,
11173                                         CONNMAN_SERVICE_INTERFACE, "Name",
11174                                         DBUS_TYPE_STRING, &service->name);
11175         }
11176
11177         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
11178                 update_wps_values(service, network);
11179
11180         strength = connman_network_get_strength(service->network);
11181         if (strength == service->strength)
11182                 goto roaming;
11183
11184         service->strength = strength;
11185         need_sort = true;
11186
11187         strength_changed(service);
11188
11189 roaming:
11190         roaming = connman_network_get_bool(service->network, "Roaming");
11191         if (roaming == service->roaming)
11192                 goto sorting;
11193
11194         stats_enable = stats_enabled(service);
11195         if (stats_enable)
11196                 stats_stop(service);
11197
11198         service->roaming = roaming;
11199         need_sort = true;
11200
11201         if (stats_enable)
11202                 stats_start(service);
11203
11204         roaming_changed(service);
11205
11206 sorting:
11207 #if defined TIZEN_EXT
11208         need_save |= update_last_connected_bssid(service);
11209         need_save |= update_assoc_reject(service);
11210         if (need_save) {
11211                 g_get_current_time(&service->modified);
11212                 service_ext_save(service);
11213                 need_sort = true;
11214         }
11215 #endif
11216
11217         if (need_sort) {
11218                 service_list_sort();
11219         }
11220 }
11221
11222 void __connman_service_remove_from_network(struct connman_network *network)
11223 {
11224         struct connman_service *service;
11225
11226         service = connman_service_lookup_from_network(network);
11227
11228         DBG("network %p service %p", network, service);
11229
11230         if (!service)
11231                 return;
11232
11233         service->ignore = true;
11234
11235         __connman_connection_gateway_remove(service,
11236                                         CONNMAN_IPCONFIG_TYPE_ALL);
11237
11238         connman_service_unref(service);
11239 }
11240
11241 /**
11242  * __connman_service_create_from_provider:
11243  * @provider: provider structure
11244  *
11245  * Look up service by provider and if not found, create one
11246  */
11247 struct connman_service *
11248 __connman_service_create_from_provider(struct connman_provider *provider)
11249 {
11250         struct connman_service *service;
11251         const char *ident, *str;
11252         char *name;
11253         int index = connman_provider_get_index(provider);
11254
11255         DBG("provider %p", provider);
11256
11257         ident = __connman_provider_get_ident(provider);
11258         if (!ident)
11259                 return NULL;
11260
11261         name = g_strdup_printf("vpn_%s", ident);
11262         service = service_get(name);
11263         g_free(name);
11264
11265         if (!service)
11266                 return NULL;
11267
11268         service->type = CONNMAN_SERVICE_TYPE_VPN;
11269         service->order = service->do_split_routing ? 0 : 10;
11270         service->provider = connman_provider_ref(provider);
11271         service->autoconnect = false;
11272         service->favorite = true;
11273
11274         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
11275         service->state = combine_state(service->state_ipv4, service->state_ipv6);
11276
11277         str = connman_provider_get_string(provider, "Name");
11278         if (str) {
11279                 g_free(service->name);
11280                 service->name = g_strdup(str);
11281                 service->hidden = false;
11282         } else {
11283                 g_free(service->name);
11284                 service->name = NULL;
11285                 service->hidden = true;
11286         }
11287
11288         service->strength = 0;
11289
11290         if (!service->ipconfig_ipv4)
11291                 service->ipconfig_ipv4 = create_ip4config(service, index,
11292                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
11293
11294         if (!service->ipconfig_ipv6)
11295                 service->ipconfig_ipv6 = create_ip6config(service, index);
11296
11297         service_register(service);
11298
11299         __connman_notifier_service_add(service, service->name);
11300         service_schedule_added(service);
11301
11302         return service;
11303 }
11304
11305 static void remove_unprovisioned_services(void)
11306 {
11307         gchar **services;
11308         GKeyFile *keyfile, *configkeyfile;
11309         char *file, *section;
11310         int i = 0;
11311
11312         services = connman_storage_get_services();
11313         if (!services)
11314                 return;
11315
11316         for (; services[i]; i++) {
11317                 file = section = NULL;
11318                 keyfile = configkeyfile = NULL;
11319
11320                 keyfile = connman_storage_load_service(services[i]);
11321                 if (!keyfile)
11322                         continue;
11323
11324                 file = g_key_file_get_string(keyfile, services[i],
11325                                         "Config.file", NULL);
11326                 if (!file)
11327                         goto next;
11328
11329                 section = g_key_file_get_string(keyfile, services[i],
11330                                         "Config.ident", NULL);
11331                 if (!section)
11332                         goto next;
11333
11334                 configkeyfile = __connman_storage_load_config(file);
11335                 if (!configkeyfile) {
11336                         /*
11337                          * Config file is missing, remove the provisioned
11338                          * service.
11339                          */
11340                         __connman_storage_remove_service(services[i]);
11341                         goto next;
11342                 }
11343
11344                 if (!g_key_file_has_group(configkeyfile, section))
11345                         /*
11346                          * Config section is missing, remove the provisioned
11347                          * service.
11348                          */
11349                         __connman_storage_remove_service(services[i]);
11350
11351         next:
11352                 if (keyfile)
11353                         g_key_file_free(keyfile);
11354
11355                 if (configkeyfile)
11356                         g_key_file_free(configkeyfile);
11357
11358                 g_free(section);
11359                 g_free(file);
11360         }
11361
11362         g_strfreev(services);
11363 }
11364
11365 static int agent_probe(struct connman_agent *agent)
11366 {
11367         DBG("agent %p", agent);
11368         return 0;
11369 }
11370
11371 static void agent_remove(struct connman_agent *agent)
11372 {
11373         DBG("agent %p", agent);
11374 }
11375
11376 static void *agent_context_ref(void *context)
11377 {
11378         struct connman_service *service = context;
11379
11380         return (void *)connman_service_ref(service);
11381 }
11382
11383 static void agent_context_unref(void *context)
11384 {
11385         struct connman_service *service = context;
11386
11387         connman_service_unref(service);
11388 }
11389
11390 static struct connman_agent_driver agent_driver = {
11391         .name           = "service",
11392         .interface      = CONNMAN_AGENT_INTERFACE,
11393         .probe          = agent_probe,
11394         .remove         = agent_remove,
11395         .context_ref    = agent_context_ref,
11396         .context_unref  = agent_context_unref,
11397 };
11398
11399 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
11400 static void ins_setting_init(void)
11401 {
11402         int i;
11403         const char *string;
11404         char **string_list;
11405         unsigned int string_count;
11406
11407         ins_settings.last_user_selection = connman_setting_get_bool("INSLastUserSelection");
11408         ins_settings.last_user_selection_time = connman_setting_get_uint("INSLastUserSelectionTime");
11409         ins_settings.last_connected = connman_setting_get_bool("INSLastConnected");
11410
11411         string = connman_setting_get_string("INSPreferredFreq");
11412         if (g_strcmp0(string, "5GHz") == 0)
11413                 ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_5GHZ;
11414         else if (g_strcmp0(string, "2.4GHz") == 0)
11415                 ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_24GHZ;
11416         else
11417                 ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_UNKNOWN;
11418
11419         ins_settings.security_priority_count = connman_setting_get_uint("INSSecurityPriorityCount");
11420         ins_settings.security_priority_score = connman_setting_get_uint("INSSecurityPriorityScore");
11421         string_count = ins_settings.security_priority_count;
11422
11423         memset(ins_settings.security_priority, 0, sizeof(ins_settings.security_priority));
11424         string_list = connman_setting_get_string_list("INSSecurityPriority");
11425         for (i = 0; string_list && string_list[i]; i++) {
11426                 unsigned int security_score = string_count * ins_settings.security_priority_score;
11427
11428                 if (g_strcmp0(string_list[i], "WEP") == 0)
11429                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_WEP] = security_score;
11430                 else if (g_strcmp0(string_list[i], "PSK") == 0)
11431                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_PSK] = security_score;
11432                 else if (g_strcmp0(string_list[i], "8021X") == 0)
11433                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_8021X] = security_score;
11434                 else if (g_strcmp0(string_list[i], "WPA") == 0)
11435                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_WPA] = security_score;
11436                 else if (g_strcmp0(string_list[i], "RSN") == 0)
11437                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_RSN] = security_score;
11438                 else if (g_strcmp0(string_list[i], "SAE") == 0)
11439                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_SAE] = security_score;
11440                 else if (g_strcmp0(string_list[i], "OWE") == 0)
11441                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_OWE] = security_score;
11442                 else if (g_strcmp0(string_list[i], "DPP") == 0)
11443                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_DPP] = security_score;
11444
11445                 string_count--;
11446         }
11447
11448         ins_settings.signal = connman_setting_get_bool("INSSignal");
11449         ins_settings.internet = connman_setting_get_bool("INSInternet");
11450
11451         ins_settings.last_user_selection_score = connman_setting_get_uint("INSLastUserSelectionScore");
11452         ins_settings.last_connected_score = connman_setting_get_uint("INSLastConnectedScore");
11453         ins_settings.preferred_freq_score = connman_setting_get_uint("INSPreferredFreqScore");
11454         ins_settings.internet_score = connman_setting_get_uint("INSInternetScore");
11455
11456         /*
11457          * In ConnMan, signal strength is used after being converted
11458          * to positive value(signal strength + 120).
11459          * So the value for comparison should also be converted to the same.
11460          */
11461         ins_settings.signal_level3_5ghz = connman_setting_get_int("INSSignalLevel3_5GHz") + 120;
11462         ins_settings.signal_level3_24ghz = connman_setting_get_int("INSSignalLevel3_24GHz") + 120;
11463
11464         DBG("last_user_selection [%s]", ins_settings.last_user_selection ? "true" : "false");
11465         DBG("last_user_selection_time [%d]", ins_settings.last_user_selection_time);
11466         DBG("last_user_selection_score [%d]", ins_settings.last_user_selection_score);
11467
11468         DBG("last_connected [%s]", ins_settings.last_connected ? "true" : "false");
11469         DBG("last_connected_score [%d]", ins_settings.last_connected_score);
11470
11471         DBG("preferred_freq [%s]", ins_settings.preferred_freq ? "true" : "false");
11472         DBG("preferred_freq_score [%d]", ins_settings.preferred_freq_score);
11473
11474         DBG("security_priority_count [%d]", ins_settings.security_priority_count);
11475         for (i = 0; i < CONNMAN_SERVICE_SECURITY_MAX; i++) {
11476                 if (ins_settings.security_priority[i])
11477                         DBG("security_priority %s [%d]", security2string(i),
11478                                         ins_settings.security_priority[i]);
11479         }
11480         DBG("security_priority_score [%d]", ins_settings.security_priority_score);
11481
11482         DBG("signal [%s]", ins_settings.signal ? "true" : "false");
11483
11484         DBG("internet [%s]", ins_settings.internet ? "true" : "false");
11485         DBG("internet_score [%d]", ins_settings.internet_score);
11486
11487         DBG("signal_level3_5ghz [%d]", ins_settings.signal_level3_5ghz);
11488         DBG("signal_level3_24ghz [%d]", ins_settings.signal_level3_24ghz);
11489 }
11490 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
11491
11492 int __connman_service_init(void)
11493 {
11494         int err;
11495
11496         DBG("");
11497
11498         err = connman_agent_driver_register(&agent_driver);
11499         if (err < 0) {
11500                 connman_error("Cannot register agent driver for %s",
11501                                                 agent_driver.name);
11502                 return err;
11503         }
11504
11505         set_always_connecting_technologies();
11506
11507         connection = connman_dbus_get_connection();
11508
11509         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
11510                                                         NULL, service_free);
11511
11512         services_notify = g_new0(struct _services_notify, 1);
11513         services_notify->remove = g_hash_table_new_full(g_str_hash,
11514                         g_str_equal, g_free, NULL);
11515         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
11516
11517         remove_unprovisioned_services();
11518
11519 #if defined TIZEN_EXT && defined TIZEN_EXT_INS
11520         ins_setting_init();
11521 #endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
11522
11523         return 0;
11524 }
11525
11526 void __connman_service_cleanup(void)
11527 {
11528         DBG("");
11529
11530         if (vpn_autoconnect_id) {
11531                 g_source_remove(vpn_autoconnect_id);
11532                 vpn_autoconnect_id = 0;
11533         }
11534
11535         if (autoconnect_id != 0) {
11536                 g_source_remove(autoconnect_id);
11537                 autoconnect_id = 0;
11538         }
11539
11540         connman_agent_driver_unregister(&agent_driver);
11541
11542         g_list_free(service_list);
11543         service_list = NULL;
11544
11545         g_hash_table_destroy(service_hash);
11546         service_hash = NULL;
11547
11548         g_slist_free(counter_list);
11549         counter_list = NULL;
11550
11551         if (services_notify->id != 0) {
11552                 g_source_remove(services_notify->id);
11553                 service_send_changed(NULL);
11554         }
11555
11556         g_hash_table_destroy(services_notify->remove);
11557         g_hash_table_destroy(services_notify->add);
11558         g_free(services_notify);
11559
11560         dbus_connection_unref(connection);
11561 }