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