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