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