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