[SPIN] Update operating frequency properly.
[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         unsigned int keymgmt;
2731         uint16_t frequency;
2732         const char *enc_mode;
2733         gboolean passpoint;
2734
2735         bssid = connman_network_get_bssid(network);
2736         maxrate = connman_network_get_maxrate(network);
2737         frequency = connman_network_get_frequency(network);
2738         enc_mode = connman_network_get_enc_mode(network);
2739         passpoint = connman_network_get_is_hs20AP(network);
2740         keymgmt = connman_network_get_keymgmt(network);
2741
2742         snprintf(bssid_str, WIFI_BSSID_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
2743                                 bssid[0], bssid[1], bssid[2],
2744                                 bssid[3], bssid[4], bssid[5]);
2745
2746         connman_dbus_dict_append_basic(dict, "BSSID",
2747                                         DBUS_TYPE_STRING, &bssid_str);
2748         connman_dbus_dict_append_basic(dict, "MaxRate",
2749                                         DBUS_TYPE_UINT32, &maxrate);
2750         connman_dbus_dict_append_basic(dict, "Frequency",
2751                                         DBUS_TYPE_UINT16, &frequency);
2752         connman_dbus_dict_append_basic(dict, "EncryptionMode",
2753                                         DBUS_TYPE_STRING, &enc_mode);
2754         connman_dbus_dict_append_basic(dict, "Passpoint",
2755                                         DBUS_TYPE_BOOLEAN, &passpoint);
2756         connman_dbus_dict_append_basic(dict, "Keymgmt",
2757                                         DBUS_TYPE_UINT32, &keymgmt);
2758 }
2759 #endif
2760
2761 static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
2762                                         struct connman_service *service)
2763 {
2764         dbus_bool_t val;
2765         const char *str;
2766         GSList *list;
2767
2768         str = __connman_service_type2string(service->type);
2769         if (str)
2770                 connman_dbus_dict_append_basic(dict, "Type",
2771                                                 DBUS_TYPE_STRING, &str);
2772
2773         connman_dbus_dict_append_array(dict, "Security",
2774                                 DBUS_TYPE_STRING, append_security, service);
2775
2776 #if defined TIZEN_EXT
2777         unsigned int frequency = 0U;
2778         if (service && service->network) {
2779                 frequency = connman_network_get_frequency(service->network);
2780                 connman_dbus_dict_append_basic(dict, "Frequency",
2781                                 DBUS_TYPE_UINT16, &frequency);
2782         }
2783 #endif
2784
2785         str = state2string(service->state);
2786         if (str)
2787                 connman_dbus_dict_append_basic(dict, "State",
2788                                                 DBUS_TYPE_STRING, &str);
2789
2790 #if defined TIZEN_TV_EXT
2791         str = state2string(service->state_ipv6);
2792         if (str != NULL)
2793                 connman_dbus_dict_append_basic(dict, "StateIPv6",
2794                                                 DBUS_TYPE_STRING, &str);
2795 #endif
2796
2797         str = error2string(service->error);
2798         if (str)
2799                 connman_dbus_dict_append_basic(dict, "Error",
2800                                                 DBUS_TYPE_STRING, &str);
2801
2802         if (service->strength > 0)
2803                 connman_dbus_dict_append_basic(dict, "Strength",
2804                                         DBUS_TYPE_BYTE, &service->strength);
2805
2806         val = service->favorite;
2807         connman_dbus_dict_append_basic(dict, "Favorite",
2808                                         DBUS_TYPE_BOOLEAN, &val);
2809
2810         val = service->immutable;
2811         connman_dbus_dict_append_basic(dict, "Immutable",
2812                                         DBUS_TYPE_BOOLEAN, &val);
2813
2814         if (service->favorite)
2815                 val = service->autoconnect;
2816         else
2817                 val = service->favorite;
2818
2819         connman_dbus_dict_append_basic(dict, "AutoConnect",
2820                                 DBUS_TYPE_BOOLEAN, &val);
2821
2822         if (service->name)
2823                 connman_dbus_dict_append_basic(dict, "Name",
2824                                         DBUS_TYPE_STRING, &service->name);
2825
2826         switch (service->type) {
2827         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2828         case CONNMAN_SERVICE_TYPE_SYSTEM:
2829         case CONNMAN_SERVICE_TYPE_GPS:
2830         case CONNMAN_SERVICE_TYPE_VPN:
2831         case CONNMAN_SERVICE_TYPE_P2P:
2832                 break;
2833         case CONNMAN_SERVICE_TYPE_CELLULAR:
2834                 val = service->roaming;
2835                 connman_dbus_dict_append_basic(dict, "Roaming",
2836                                         DBUS_TYPE_BOOLEAN, &val);
2837
2838                 connman_dbus_dict_append_dict(dict, "Ethernet",
2839                                                 append_ethernet, service);
2840                 break;
2841         case CONNMAN_SERVICE_TYPE_WIFI:
2842 #if defined TIZEN_EXT
2843                 if (service->network != NULL)
2844                         append_wifi_ext_info(dict, service->network);
2845
2846                 connman_dbus_dict_append_dict(dict, "Ethernet",
2847                                                 append_ethernet, service);
2848                 break;
2849 #endif
2850         case CONNMAN_SERVICE_TYPE_ETHERNET:
2851         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2852         case CONNMAN_SERVICE_TYPE_GADGET:
2853                 connman_dbus_dict_append_dict(dict, "Ethernet",
2854                                                 append_ethernet, service);
2855                 break;
2856         }
2857
2858         connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service);
2859
2860         connman_dbus_dict_append_dict(dict, "IPv4.Configuration",
2861                                                 append_ipv4config, service);
2862
2863         connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service);
2864
2865         connman_dbus_dict_append_dict(dict, "IPv6.Configuration",
2866                                                 append_ipv6config, service);
2867
2868         connman_dbus_dict_append_array(dict, "Nameservers",
2869                                 DBUS_TYPE_STRING, append_dns, service);
2870
2871         connman_dbus_dict_append_array(dict, "Nameservers.Configuration",
2872                                 DBUS_TYPE_STRING, append_dnsconfig, service);
2873
2874         if (service->state == CONNMAN_SERVICE_STATE_READY ||
2875                         service->state == CONNMAN_SERVICE_STATE_ONLINE)
2876                 list = __connman_timeserver_get_all(service);
2877         else
2878                 list = NULL;
2879
2880         connman_dbus_dict_append_array(dict, "Timeservers",
2881                                 DBUS_TYPE_STRING, append_ts, list);
2882
2883         g_slist_free_full(list, g_free);
2884
2885         connman_dbus_dict_append_array(dict, "Timeservers.Configuration",
2886                                 DBUS_TYPE_STRING, append_tsconfig, service);
2887
2888         connman_dbus_dict_append_array(dict, "Domains",
2889                                 DBUS_TYPE_STRING, append_domain, service);
2890
2891         connman_dbus_dict_append_array(dict, "Domains.Configuration",
2892                                 DBUS_TYPE_STRING, append_domainconfig, service);
2893
2894         connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service);
2895
2896         connman_dbus_dict_append_dict(dict, "Proxy.Configuration",
2897                                                 append_proxyconfig, service);
2898
2899         connman_dbus_dict_append_dict(dict, "Provider",
2900                                                 append_provider, service);
2901 }
2902
2903 static void append_struct_service(DBusMessageIter *iter,
2904                 connman_dbus_append_cb_t function,
2905                 struct connman_service *service)
2906 {
2907         DBusMessageIter entry, dict;
2908
2909         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
2910
2911         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
2912                                                         &service->path);
2913
2914         connman_dbus_dict_open(&entry, &dict);
2915         if (function)
2916                 function(&dict, service);
2917         connman_dbus_dict_close(&entry, &dict);
2918
2919         dbus_message_iter_close_container(iter, &entry);
2920 }
2921
2922 static void append_dict_properties(DBusMessageIter *dict, void *user_data)
2923 {
2924         struct connman_service *service = user_data;
2925
2926         append_properties(dict, TRUE, service);
2927 }
2928
2929 static void append_struct(gpointer value, gpointer user_data)
2930 {
2931         struct connman_service *service = value;
2932         DBusMessageIter *iter = user_data;
2933
2934         if (!service->path)
2935                 return;
2936
2937         append_struct_service(iter, append_dict_properties, service);
2938 }
2939
2940 void __connman_service_list_struct(DBusMessageIter *iter)
2941 {
2942         g_list_foreach(service_list, append_struct, iter);
2943 }
2944
2945 bool __connman_service_is_hidden(struct connman_service *service)
2946 {
2947         return service->hidden;
2948 }
2949
2950 bool
2951 __connman_service_is_split_routing(struct connman_service *service)
2952 {
2953         return service->do_split_routing;
2954 }
2955
2956 bool __connman_service_index_is_split_routing(int index)
2957 {
2958         struct connman_service *service;
2959
2960         if (index < 0)
2961                 return false;
2962
2963         service = __connman_service_lookup_from_index(index);
2964         if (!service)
2965                 return false;
2966
2967         return __connman_service_is_split_routing(service);
2968 }
2969
2970 int __connman_service_get_index(struct connman_service *service)
2971 {
2972         if (!service)
2973                 return -1;
2974
2975         if (service->network)
2976                 return connman_network_get_index(service->network);
2977         else if (service->provider)
2978                 return connman_provider_get_index(service->provider);
2979
2980         return -1;
2981 }
2982
2983 void __connman_service_set_hidden(struct connman_service *service)
2984 {
2985         if (!service || service->hidden)
2986                 return;
2987
2988         service->hidden_service = true;
2989 }
2990
2991 void __connman_service_set_hostname(struct connman_service *service,
2992                                                 const char *hostname)
2993 {
2994         if (!service || service->hidden)
2995                 return;
2996
2997         g_free(service->hostname);
2998         service->hostname = g_strdup(hostname);
2999 }
3000
3001 const char *__connman_service_get_hostname(struct connman_service *service)
3002 {
3003         if (!service)
3004                 return NULL;
3005
3006         return service->hostname;
3007 }
3008
3009 void __connman_service_set_domainname(struct connman_service *service,
3010                                                 const char *domainname)
3011 {
3012         if (!service || service->hidden)
3013                 return;
3014
3015         g_free(service->domainname);
3016         service->domainname = g_strdup(domainname);
3017
3018         domain_changed(service);
3019 }
3020
3021 const char *connman_service_get_domainname(struct connman_service *service)
3022 {
3023         if (!service)
3024                 return NULL;
3025
3026         if (service->domains)
3027                 return service->domains[0];
3028         else
3029                 return service->domainname;
3030 }
3031
3032 char **connman_service_get_nameservers(struct connman_service *service)
3033 {
3034         if (!service)
3035                 return NULL;
3036
3037         if (service->nameservers_config)
3038                 return g_strdupv(service->nameservers_config);
3039         else if (service->nameservers ||
3040                                         service->nameservers_auto) {
3041                 int len = 0, len_auto = 0, i;
3042                 char **nameservers;
3043
3044                 if (service->nameservers)
3045                         len = g_strv_length(service->nameservers);
3046                 if (service->nameservers_auto)
3047                         len_auto = g_strv_length(service->nameservers_auto);
3048
3049                 nameservers = g_try_new0(char *, len + len_auto + 1);
3050                 if (!nameservers)
3051                         return NULL;
3052
3053                 for (i = 0; i < len; i++)
3054                         nameservers[i] = g_strdup(service->nameservers[i]);
3055
3056                 for (i = 0; i < len_auto; i++)
3057                         nameservers[i + len] =
3058                                 g_strdup(service->nameservers_auto[i]);
3059
3060                 return nameservers;
3061         }
3062
3063         return g_strdupv(connman_setting_get_string_list("FallbackNameservers"));
3064 }
3065
3066 char **connman_service_get_timeservers_config(struct connman_service *service)
3067 {
3068         if (!service)
3069                 return NULL;
3070
3071         return service->timeservers_config;
3072 }
3073
3074 char **connman_service_get_timeservers(struct connman_service *service)
3075 {
3076         if (!service)
3077                 return NULL;
3078
3079         return service->timeservers;
3080 }
3081
3082 #if defined TIZEN_EXT
3083 /*
3084  * Description: Telephony plug-in requires manual PROXY setting function
3085  */
3086 int connman_service_set_proxy(struct connman_service *service,
3087                                         const char *proxy, gboolean active)
3088 {
3089         char **proxies_array = NULL;
3090
3091         if (service == NULL)
3092                 return -EINVAL;
3093
3094         switch (service->type) {
3095         case CONNMAN_SERVICE_TYPE_CELLULAR:
3096         case CONNMAN_SERVICE_TYPE_ETHERNET:
3097         case CONNMAN_SERVICE_TYPE_WIFI:
3098                 break;
3099
3100         default:
3101                 return -EINVAL;
3102         }
3103
3104         g_strfreev(service->proxies);
3105         service->proxies = NULL;
3106
3107         if (proxy != NULL)
3108                 proxies_array = g_strsplit(proxy, " ", 0);
3109
3110         service->proxies = proxies_array;
3111
3112         if (proxy == NULL) {
3113                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
3114                 DBG("proxy changed (%d)", active);
3115         } else {
3116                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_MANUAL;
3117                 DBG("proxy chagned %s (%d)", proxy, active);
3118         }
3119
3120         if (active == TRUE) {
3121                 proxy_changed(service);
3122
3123                 __connman_notifier_proxy_changed(service);
3124         }
3125
3126         return 0;
3127 }
3128 #endif
3129
3130 void connman_service_set_proxy_method(struct connman_service *service,
3131                                         enum connman_service_proxy_method method)
3132 {
3133         if (!service || service->hidden)
3134                 return;
3135
3136         service->proxy = method;
3137
3138         proxy_changed(service);
3139
3140         if (method != CONNMAN_SERVICE_PROXY_METHOD_AUTO)
3141                 __connman_notifier_proxy_changed(service);
3142 }
3143
3144 enum connman_service_proxy_method connman_service_get_proxy_method(
3145                                         struct connman_service *service)
3146 {
3147         if (!service)
3148                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
3149
3150         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) {
3151                 if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_AUTO &&
3152                                 !service->pac)
3153                         return service->proxy;
3154
3155                 return service->proxy_config;
3156         }
3157
3158         return service->proxy;
3159 }
3160
3161 char **connman_service_get_proxy_servers(struct connman_service *service)
3162 {
3163         return g_strdupv(service->proxies);
3164 }
3165
3166 char **connman_service_get_proxy_excludes(struct connman_service *service)
3167 {
3168         return g_strdupv(service->excludes);
3169 }
3170
3171 const char *connman_service_get_proxy_url(struct connman_service *service)
3172 {
3173         if (!service)
3174                 return NULL;
3175
3176         return service->pac;
3177 }
3178
3179 void __connman_service_set_proxy_autoconfig(struct connman_service *service,
3180                                                         const char *url)
3181 {
3182         if (!service || service->hidden)
3183                 return;
3184
3185         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_AUTO;
3186
3187         if (service->ipconfig_ipv4) {
3188                 if (__connman_ipconfig_set_proxy_autoconfig(
3189                             service->ipconfig_ipv4, url) < 0)
3190                         return;
3191         } else if (service->ipconfig_ipv6) {
3192                 if (__connman_ipconfig_set_proxy_autoconfig(
3193                             service->ipconfig_ipv6, url) < 0)
3194                         return;
3195         } else
3196                 return;
3197
3198         proxy_changed(service);
3199
3200         __connman_notifier_proxy_changed(service);
3201 }
3202
3203 const char *connman_service_get_proxy_autoconfig(struct connman_service *service)
3204 {
3205         if (!service)
3206                 return NULL;
3207
3208         if (service->ipconfig_ipv4)
3209                 return __connman_ipconfig_get_proxy_autoconfig(
3210                                                 service->ipconfig_ipv4);
3211         else if (service->ipconfig_ipv6)
3212                 return __connman_ipconfig_get_proxy_autoconfig(
3213                                                 service->ipconfig_ipv6);
3214         return NULL;
3215 }
3216
3217 void __connman_service_set_timeservers(struct connman_service *service,
3218                                 char **timeservers)
3219 {
3220         int i;
3221
3222         if (!service)
3223                 return;
3224
3225         g_strfreev(service->timeservers);
3226         service->timeservers = NULL;
3227
3228         for (i = 0; timeservers && timeservers[i]; i++)
3229                 __connman_service_timeserver_append(service, timeservers[i]);
3230 }
3231
3232 int __connman_service_timeserver_append(struct connman_service *service,
3233                                                 const char *timeserver)
3234 {
3235         int len;
3236
3237         DBG("service %p timeserver %s", service, timeserver);
3238
3239         if (!timeserver)
3240                 return -EINVAL;
3241
3242         if (service->timeservers) {
3243                 int i;
3244
3245                 for (i = 0; service->timeservers[i]; i++)
3246                         if (g_strcmp0(service->timeservers[i], timeserver) == 0)
3247                                 return -EEXIST;
3248
3249                 len = g_strv_length(service->timeservers);
3250                 service->timeservers = g_try_renew(char *, service->timeservers,
3251                                                         len + 2);
3252         } else {
3253                 len = 0;
3254                 service->timeservers = g_try_new0(char *, len + 2);
3255         }
3256
3257         if (!service->timeservers)
3258                 return -ENOMEM;
3259
3260         service->timeservers[len] = g_strdup(timeserver);
3261         service->timeservers[len + 1] = NULL;
3262
3263         return 0;
3264 }
3265
3266 int __connman_service_timeserver_remove(struct connman_service *service,
3267                                                 const char *timeserver)
3268 {
3269         char **servers;
3270         int len, i, j, found = 0;
3271
3272         DBG("service %p timeserver %s", service, timeserver);
3273
3274         if (!timeserver)
3275                 return -EINVAL;
3276
3277         if (!service->timeservers)
3278                 return 0;
3279
3280         for (i = 0; service->timeservers &&
3281                                         service->timeservers[i]; i++)
3282                 if (g_strcmp0(service->timeservers[i], timeserver) == 0) {
3283                         found = 1;
3284                         break;
3285                 }
3286
3287         if (found == 0)
3288                 return 0;
3289
3290         len = g_strv_length(service->timeservers);
3291
3292         if (len == 1) {
3293                 g_strfreev(service->timeservers);
3294                 service->timeservers = NULL;
3295
3296                 return 0;
3297         }
3298
3299         servers = g_try_new0(char *, len);
3300         if (!servers)
3301                 return -ENOMEM;
3302
3303         for (i = 0, j = 0; i < len; i++) {
3304                 if (g_strcmp0(service->timeservers[i], timeserver) != 0) {
3305                         servers[j] = g_strdup(service->timeservers[i]);
3306                         if (!servers[j])
3307                                 return -ENOMEM;
3308                         j++;
3309                 }
3310         }
3311         servers[len - 1] = NULL;
3312
3313         g_strfreev(service->timeservers);
3314         service->timeservers = servers;
3315
3316         return 0;
3317 }
3318
3319 void __connman_service_timeserver_changed(struct connman_service *service,
3320                 GSList *ts_list)
3321 {
3322         if (!service)
3323                 return;
3324
3325         if (!allow_property_changed(service))
3326                 return;
3327
3328         connman_dbus_property_changed_array(service->path,
3329                         CONNMAN_SERVICE_INTERFACE, "Timeservers",
3330                         DBUS_TYPE_STRING, append_ts, ts_list);
3331 }
3332
3333 void __connman_service_set_pac(struct connman_service *service,
3334                                         const char *pac)
3335 {
3336         if (service->hidden)
3337                 return;
3338         g_free(service->pac);
3339         service->pac = g_strdup(pac);
3340
3341         proxy_changed(service);
3342 }
3343
3344 #if defined TIZEN_EXT
3345 void __connman_service_set_proxy(struct connman_service *service,
3346                                        const char *proxies)
3347 {
3348        char **proxies_array = NULL;
3349
3350        g_strfreev(service->proxies);
3351        service->proxies = NULL;
3352
3353        if (proxies != NULL)
3354                proxies_array = g_strsplit(proxies, " ", 0);
3355
3356        service->proxies = proxies_array;
3357 }
3358 #endif
3359
3360 void __connman_service_set_identity(struct connman_service *service,
3361                                         const char *identity)
3362 {
3363         if (service->immutable || service->hidden)
3364                 return;
3365
3366         g_free(service->identity);
3367         service->identity = g_strdup(identity);
3368
3369         if (service->network)
3370                 connman_network_set_string(service->network,
3371                                         "WiFi.Identity",
3372                                         service->identity);
3373 }
3374
3375 void __connman_service_set_agent_identity(struct connman_service *service,
3376                                                 const char *agent_identity)
3377 {
3378         if (service->hidden)
3379                 return;
3380         g_free(service->agent_identity);
3381         service->agent_identity = g_strdup(agent_identity);
3382
3383         if (service->network)
3384                 connman_network_set_string(service->network,
3385                                         "WiFi.AgentIdentity",
3386                                         service->agent_identity);
3387 }
3388
3389 static int check_passphrase(enum connman_service_security security,
3390                 const char *passphrase)
3391 {
3392         guint i;
3393         gsize length;
3394
3395         if (!passphrase)
3396                 return 0;
3397
3398         length = strlen(passphrase);
3399
3400         switch (security) {
3401         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
3402         case CONNMAN_SERVICE_SECURITY_NONE:
3403         case CONNMAN_SERVICE_SECURITY_WPA:
3404 #if !defined TIZEN_EXT
3405         case CONNMAN_SERVICE_SECURITY_RSN:
3406 #endif
3407
3408                 DBG("service security '%s' (%d) not handled",
3409                                 security2string(security), security);
3410
3411                 return -EOPNOTSUPP;
3412
3413         case CONNMAN_SERVICE_SECURITY_PSK:
3414 #if defined TIZEN_EXT
3415         case CONNMAN_SERVICE_SECURITY_RSN:
3416 #endif
3417                 /* A raw key is always 64 bytes length,
3418                  * its content is in hex representation.
3419                  * A PSK key must be between [8..63].
3420                  */
3421                 if (length == 64) {
3422                         for (i = 0; i < 64; i++)
3423                                 if (!isxdigit((unsigned char)
3424                                               passphrase[i]))
3425                                         return -ENOKEY;
3426                 } else if (length < 8 || length > 63)
3427                         return -ENOKEY;
3428                 break;
3429         case CONNMAN_SERVICE_SECURITY_WEP:
3430                 /* length of WEP key is 10 or 26
3431                  * length of WEP passphrase is 5 or 13
3432                  */
3433                 if (length == 10 || length == 26) {
3434                         for (i = 0; i < length; i++)
3435                                 if (!isxdigit((unsigned char)
3436                                               passphrase[i]))
3437                                         return -ENOKEY;
3438                 } else if (length != 5 && length != 13)
3439                         return -ENOKEY;
3440                 break;
3441
3442         case CONNMAN_SERVICE_SECURITY_8021X:
3443                 break;
3444         }
3445
3446         return 0;
3447 }
3448
3449 int __connman_service_set_passphrase(struct connman_service *service,
3450                                         const char *passphrase)
3451 {
3452         int err;
3453
3454         if (service->hidden)
3455                 return -EINVAL;
3456
3457         if (service->immutable &&
3458                         service->security != CONNMAN_SERVICE_SECURITY_8021X)
3459                 return -EINVAL;
3460
3461         err = check_passphrase(service->security, passphrase);
3462
3463         if (err < 0)
3464                 return err;
3465
3466         g_free(service->passphrase);
3467         service->passphrase = g_strdup(passphrase);
3468
3469         if (service->network)
3470                 connman_network_set_string(service->network, "WiFi.Passphrase",
3471                                 service->passphrase);
3472
3473         return 0;
3474 }
3475
3476 const char *__connman_service_get_passphrase(struct connman_service *service)
3477 {
3478         if (!service)
3479                 return NULL;
3480
3481         return service->passphrase;
3482 }
3483
3484 static DBusMessage *get_properties(DBusConnection *conn,
3485                                         DBusMessage *msg, void *user_data)
3486 {
3487         struct connman_service *service = user_data;
3488         DBusMessage *reply;
3489         DBusMessageIter array, dict;
3490
3491         DBG("service %p", service);
3492
3493         reply = dbus_message_new_method_return(msg);
3494         if (!reply)
3495                 return NULL;
3496
3497         dbus_message_iter_init_append(reply, &array);
3498
3499         connman_dbus_dict_open(&array, &dict);
3500         append_properties(&dict, FALSE, service);
3501         connman_dbus_dict_close(&array, &dict);
3502
3503         return reply;
3504 }
3505
3506 static int update_proxy_configuration(struct connman_service *service,
3507                                 DBusMessageIter *array)
3508 {
3509         DBusMessageIter dict;
3510         enum connman_service_proxy_method method;
3511         GString *servers_str = NULL;
3512         GString *excludes_str = NULL;
3513         const char *url = NULL;
3514
3515         method = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
3516
3517         dbus_message_iter_recurse(array, &dict);
3518
3519         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
3520                 DBusMessageIter entry, variant;
3521                 const char *key;
3522                 int type;
3523
3524                 dbus_message_iter_recurse(&dict, &entry);
3525
3526                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
3527                         goto error;
3528
3529                 dbus_message_iter_get_basic(&entry, &key);
3530                 dbus_message_iter_next(&entry);
3531
3532                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
3533                         goto error;
3534
3535                 dbus_message_iter_recurse(&entry, &variant);
3536
3537                 type = dbus_message_iter_get_arg_type(&variant);
3538
3539                 if (g_str_equal(key, "Method")) {
3540                         const char *val;
3541
3542                         if (type != DBUS_TYPE_STRING)
3543                                 goto error;
3544
3545                         dbus_message_iter_get_basic(&variant, &val);
3546                         method = string2proxymethod(val);
3547                 } else if (g_str_equal(key, "URL")) {
3548                         if (type != DBUS_TYPE_STRING)
3549                                 goto error;
3550
3551                         dbus_message_iter_get_basic(&variant, &url);
3552                 } else if (g_str_equal(key, "Servers")) {
3553                         DBusMessageIter str_array;
3554
3555                         if (type != DBUS_TYPE_ARRAY)
3556                                 goto error;
3557
3558                         servers_str = g_string_new(NULL);
3559                         if (!servers_str)
3560                                 goto error;
3561
3562                         dbus_message_iter_recurse(&variant, &str_array);
3563
3564                         while (dbus_message_iter_get_arg_type(&str_array) ==
3565                                                         DBUS_TYPE_STRING) {
3566                                 char *val = NULL;
3567
3568                                 dbus_message_iter_get_basic(&str_array, &val);
3569
3570                                 if (servers_str->len > 0)
3571                                         g_string_append_printf(servers_str,
3572                                                         " %s", val);
3573                                 else
3574                                         g_string_append(servers_str, val);
3575
3576                                 dbus_message_iter_next(&str_array);
3577                         }
3578                 } else if (g_str_equal(key, "Excludes")) {
3579                         DBusMessageIter str_array;
3580
3581                         if (type != DBUS_TYPE_ARRAY)
3582                                 goto error;
3583
3584                         excludes_str = g_string_new(NULL);
3585                         if (!excludes_str)
3586                                 goto error;
3587
3588                         dbus_message_iter_recurse(&variant, &str_array);
3589
3590                         while (dbus_message_iter_get_arg_type(&str_array) ==
3591                                                         DBUS_TYPE_STRING) {
3592                                 char *val = NULL;
3593
3594                                 dbus_message_iter_get_basic(&str_array, &val);
3595
3596                                 if (excludes_str->len > 0)
3597                                         g_string_append_printf(excludes_str,
3598                                                         " %s", val);
3599                                 else
3600                                         g_string_append(excludes_str, val);
3601
3602                                 dbus_message_iter_next(&str_array);
3603                         }
3604                 }
3605
3606                 dbus_message_iter_next(&dict);
3607         }
3608
3609         switch (method) {
3610         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
3611                 break;
3612         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
3613                 if (!servers_str && !service->proxies)
3614                         goto error;
3615
3616                 if (servers_str) {
3617                         g_strfreev(service->proxies);
3618
3619                         if (servers_str->len > 0)
3620                                 service->proxies = g_strsplit_set(
3621                                         servers_str->str, " ", 0);
3622                         else
3623                                 service->proxies = NULL;
3624                 }
3625
3626                 if (excludes_str) {
3627                         g_strfreev(service->excludes);
3628
3629                         if (excludes_str->len > 0)
3630                                 service->excludes = g_strsplit_set(
3631                                         excludes_str->str, " ", 0);
3632                         else
3633                                 service->excludes = NULL;
3634                 }
3635
3636                 if (!service->proxies)
3637                         method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
3638
3639                 break;
3640         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
3641                 g_free(service->pac);
3642
3643                 if (url && strlen(url) > 0)
3644                         service->pac = g_strdup(url);
3645                 else
3646                         service->pac = NULL;
3647
3648                 /* if we are connected:
3649                    - if service->pac == NULL
3650                    - if __connman_ipconfig_get_proxy_autoconfig(
3651                    service->ipconfig) == NULL
3652                    --> We should start WPAD */
3653
3654                 break;
3655         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
3656                 goto error;
3657         }
3658
3659         if (servers_str)
3660                 g_string_free(servers_str, TRUE);
3661
3662         if (excludes_str)
3663                 g_string_free(excludes_str, TRUE);
3664
3665         service->proxy_config = method;
3666
3667         return 0;
3668
3669 error:
3670         if (servers_str)
3671                 g_string_free(servers_str, TRUE);
3672
3673         if (excludes_str)
3674                 g_string_free(excludes_str, TRUE);
3675
3676         return -EINVAL;
3677 }
3678
3679 int __connman_service_reset_ipconfig(struct connman_service *service,
3680                 enum connman_ipconfig_type type, DBusMessageIter *array,
3681                 enum connman_service_state *new_state)
3682 {
3683         struct connman_ipconfig *ipconfig, *new_ipconfig;
3684         enum connman_ipconfig_method old_method, new_method;
3685         enum connman_service_state state;
3686         int err = 0, index;
3687
3688         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
3689                 ipconfig = service->ipconfig_ipv4;
3690                 state = service->state_ipv4;
3691                 new_method = CONNMAN_IPCONFIG_METHOD_DHCP;
3692         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
3693                 ipconfig = service->ipconfig_ipv6;
3694                 state = service->state_ipv6;
3695                 new_method = CONNMAN_IPCONFIG_METHOD_AUTO;
3696         } else
3697                 return -EINVAL;
3698
3699         if (!ipconfig)
3700                 return -ENXIO;
3701
3702         old_method = __connman_ipconfig_get_method(ipconfig);
3703         index = __connman_ipconfig_get_index(ipconfig);
3704
3705         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
3706                 new_ipconfig = create_ip4config(service, index,
3707                                 CONNMAN_IPCONFIG_METHOD_UNKNOWN);
3708         else
3709                 new_ipconfig = create_ip6config(service, index);
3710
3711         if (array) {
3712                 err = __connman_ipconfig_set_config(new_ipconfig, array);
3713                 if (err < 0) {
3714                         __connman_ipconfig_unref(new_ipconfig);
3715                         return err;
3716                 }
3717
3718                 new_method = __connman_ipconfig_get_method(new_ipconfig);
3719         }
3720
3721         if (is_connecting_state(service, state) ||
3722                                         is_connected_state(service, state))
3723                 __connman_network_clear_ipconfig(service->network, ipconfig);
3724
3725         __connman_ipconfig_unref(ipconfig);
3726
3727         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
3728                 service->ipconfig_ipv4 = new_ipconfig;
3729         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
3730                 service->ipconfig_ipv6 = new_ipconfig;
3731
3732         if (is_connecting_state(service, state) ||
3733                                         is_connected_state(service, state))
3734                 __connman_ipconfig_enable(new_ipconfig);
3735
3736         if (new_state && new_method != old_method) {
3737                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
3738                         *new_state = service->state_ipv4;
3739                 else
3740                         *new_state = service->state_ipv6;
3741
3742                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
3743         }
3744
3745         DBG("err %d ipconfig %p type %d method %d state %s", err,
3746                 new_ipconfig, type, new_method,
3747                 !new_state  ? "-" : state2string(*new_state));
3748
3749         return err;
3750 }
3751
3752 static DBusMessage *set_property(DBusConnection *conn,
3753                                         DBusMessage *msg, void *user_data)
3754 {
3755         struct connman_service *service = user_data;
3756         DBusMessageIter iter, value;
3757         const char *name;
3758         int type;
3759
3760         DBG("service %p", service);
3761
3762         if (!dbus_message_iter_init(msg, &iter))
3763                 return __connman_error_invalid_arguments(msg);
3764
3765         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
3766                 return __connman_error_invalid_arguments(msg);
3767
3768         if (service->type == CONNMAN_SERVICE_TYPE_WIFI && is_connected(service)) {
3769                 uid_t uid;
3770                 if (connman_dbus_get_connection_unix_user_sync(conn,
3771                                                 dbus_message_get_sender(msg),
3772                                                 &uid) < 0) {
3773                         DBG("Can not get unix user id!");
3774                         return __connman_error_permission_denied(msg);
3775                 }
3776
3777                 if (!connman_service_is_user_allowed(service, uid)) {
3778                         DBG("Not allow this user to operate this wifi service now!");
3779                         return __connman_error_permission_denied(msg);
3780                 }
3781         }
3782
3783         dbus_message_iter_get_basic(&iter, &name);
3784         dbus_message_iter_next(&iter);
3785
3786         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
3787                 return __connman_error_invalid_arguments(msg);
3788
3789         dbus_message_iter_recurse(&iter, &value);
3790
3791         type = dbus_message_iter_get_arg_type(&value);
3792
3793         if (g_str_equal(name, "AutoConnect")) {
3794                 dbus_bool_t autoconnect;
3795
3796                 if (type != DBUS_TYPE_BOOLEAN)
3797                         return __connman_error_invalid_arguments(msg);
3798
3799                 if (!service->favorite)
3800                         return __connman_error_invalid_service(msg);
3801
3802                 dbus_message_iter_get_basic(&value, &autoconnect);
3803
3804                 if (service->autoconnect == autoconnect)
3805                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3806
3807                 service->autoconnect = autoconnect;
3808
3809                 autoconnect_changed(service);
3810
3811                 if (autoconnect)
3812                         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
3813
3814                 service_save(service);
3815         } else if (g_str_equal(name, "Nameservers.Configuration")) {
3816                 DBusMessageIter entry;
3817                 GString *str;
3818                 int index;
3819                 const char *gw;
3820
3821                 if (__connman_provider_is_immutable(service->provider) ||
3822                                 service->immutable)
3823                         return __connman_error_not_supported(msg);
3824
3825                 if (type != DBUS_TYPE_ARRAY)
3826                         return __connman_error_invalid_arguments(msg);
3827
3828                 str = g_string_new(NULL);
3829                 if (!str)
3830                         return __connman_error_invalid_arguments(msg);
3831
3832                 index = __connman_service_get_index(service);
3833                 gw = __connman_ipconfig_get_gateway_from_index(index,
3834                         CONNMAN_IPCONFIG_TYPE_ALL);
3835
3836                 if (gw && strlen(gw))
3837                         __connman_service_nameserver_del_routes(service,
3838                                                 CONNMAN_IPCONFIG_TYPE_ALL);
3839
3840                 dbus_message_iter_recurse(&value, &entry);
3841
3842                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
3843                         const char *val;
3844                         dbus_message_iter_get_basic(&entry, &val);
3845                         dbus_message_iter_next(&entry);
3846 #if defined TIZEN_TV_EXT
3847                         /* First unpack the DNS Config Method */
3848                         if(g_strcmp0(val, "manual") == 0) {
3849                                 service->dns_config_method =
3850                                         CONNMAN_DNSCONFIG_METHOD_MANUAL;
3851                                 continue;
3852                         } else if(g_strcmp0(val, "dhcp") == 0) {
3853                                 service->dns_config_method =
3854                                         CONNMAN_DNSCONFIG_METHOD_DHCP;
3855                                 continue;
3856                         }
3857 #endif
3858                         if (connman_inet_check_ipaddress(val) > 0) {
3859                                 if (str->len > 0)
3860                                         g_string_append_printf(str, " %s", val);
3861                                 else
3862                                         g_string_append(str, val);
3863                         }
3864                 }
3865
3866                 nameserver_remove_all(service);
3867                 g_strfreev(service->nameservers_config);
3868
3869                 if (str->len > 0) {
3870                         service->nameservers_config =
3871                                 g_strsplit_set(str->str, " ", 0);
3872                 } else {
3873                         service->nameservers_config = NULL;
3874                 }
3875
3876                 g_string_free(str, TRUE);
3877
3878                 if (gw && strlen(gw))
3879                         __connman_service_nameserver_add_routes(service, gw);
3880
3881                 nameserver_add_all(service);
3882                 dns_configuration_changed(service);
3883
3884                 if (__connman_service_is_connected_state(service,
3885                                                 CONNMAN_IPCONFIG_TYPE_IPV4))
3886                         __connman_wispr_start(service,
3887                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
3888
3889                 if (__connman_service_is_connected_state(service,
3890                                                 CONNMAN_IPCONFIG_TYPE_IPV6))
3891                         __connman_wispr_start(service,
3892                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
3893
3894                 service_save(service);
3895         } else if (g_str_equal(name, "Timeservers.Configuration")) {
3896                 DBusMessageIter entry;
3897                 GSList *list = NULL;
3898                 int count = 0;
3899
3900                 if (service->immutable)
3901                         return __connman_error_not_supported(msg);
3902
3903                 if (type != DBUS_TYPE_ARRAY)
3904                         return __connman_error_invalid_arguments(msg);
3905
3906                 dbus_message_iter_recurse(&value, &entry);
3907
3908                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
3909                         const char *val;
3910                         GSList *new_head;
3911
3912                         dbus_message_iter_get_basic(&entry, &val);
3913
3914                         new_head = __connman_timeserver_add_list(list, val);
3915                         if (list != new_head) {
3916                                 count++;
3917                                 list = new_head;
3918                         }
3919
3920                         dbus_message_iter_next(&entry);
3921                 }
3922
3923                 g_strfreev(service->timeservers_config);
3924                 service->timeservers_config = NULL;
3925
3926                 if (list) {
3927                         service->timeservers_config = g_new0(char *, count+1);
3928
3929                         while (list) {
3930                                 count--;
3931                                 service->timeservers_config[count] = list->data;
3932                                 list = g_slist_delete_link(list, list);
3933                         };
3934                 }
3935
3936                 service_save(service);
3937                 timeservers_configuration_changed(service);
3938
3939                 if (service == __connman_service_get_default())
3940                         __connman_timeserver_sync(service);
3941
3942         } else if (g_str_equal(name, "Domains.Configuration")) {
3943                 DBusMessageIter entry;
3944                 GString *str;
3945
3946                 if (service->immutable)
3947                         return __connman_error_not_supported(msg);
3948
3949                 if (type != DBUS_TYPE_ARRAY)
3950                         return __connman_error_invalid_arguments(msg);
3951
3952                 str = g_string_new(NULL);
3953                 if (!str)
3954                         return __connman_error_invalid_arguments(msg);
3955
3956                 dbus_message_iter_recurse(&value, &entry);
3957
3958                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
3959                         const char *val;
3960                         dbus_message_iter_get_basic(&entry, &val);
3961                         dbus_message_iter_next(&entry);
3962                         if (str->len > 0)
3963                                 g_string_append_printf(str, " %s", val);
3964                         else
3965                                 g_string_append(str, val);
3966                 }
3967
3968                 searchdomain_remove_all(service);
3969                 g_strfreev(service->domains);
3970
3971                 if (str->len > 0)
3972                         service->domains = g_strsplit_set(str->str, " ", 0);
3973                 else
3974                         service->domains = NULL;
3975
3976                 g_string_free(str, TRUE);
3977
3978                 searchdomain_add_all(service);
3979                 domain_configuration_changed(service);
3980                 domain_changed(service);
3981
3982                 service_save(service);
3983         } else if (g_str_equal(name, "Proxy.Configuration")) {
3984                 int err;
3985
3986                 if (service->immutable)
3987                         return __connman_error_not_supported(msg);
3988
3989                 if (type != DBUS_TYPE_ARRAY)
3990                         return __connman_error_invalid_arguments(msg);
3991
3992                 err = update_proxy_configuration(service, &value);
3993
3994                 if (err < 0)
3995                         return __connman_error_failed(msg, -err);
3996
3997                 proxy_configuration_changed(service);
3998
3999                 __connman_notifier_proxy_changed(service);
4000
4001                 service_save(service);
4002         } else if (g_str_equal(name, "IPv4.Configuration") ||
4003                         g_str_equal(name, "IPv6.Configuration")) {
4004
4005                 enum connman_service_state state =
4006                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
4007                 enum connman_ipconfig_type type =
4008                         CONNMAN_IPCONFIG_TYPE_UNKNOWN;
4009                 int err = 0;
4010
4011                 if (service->type == CONNMAN_SERVICE_TYPE_VPN ||
4012                                 service->immutable)
4013                         return __connman_error_not_supported(msg);
4014
4015                 DBG("%s", name);
4016
4017                 if (!service->ipconfig_ipv4 &&
4018                                         !service->ipconfig_ipv6)
4019                         return __connman_error_invalid_property(msg);
4020
4021                 if (g_str_equal(name, "IPv4.Configuration"))
4022                         type = CONNMAN_IPCONFIG_TYPE_IPV4;
4023                 else
4024                         type = CONNMAN_IPCONFIG_TYPE_IPV6;
4025
4026                 err = __connman_service_reset_ipconfig(service, type, &value,
4027                                                                 &state);
4028
4029                 if (err < 0) {
4030                         if (is_connected_state(service, state) ||
4031                                         is_connecting_state(service, state)) {
4032                                 __connman_network_enable_ipconfig(service->network,
4033                                                         service->ipconfig_ipv4);
4034                                 __connman_network_enable_ipconfig(service->network,
4035                                                         service->ipconfig_ipv6);
4036                         }
4037
4038                         return __connman_error_failed(msg, -err);
4039                 }
4040
4041                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4042                         ipv4_configuration_changed(service);
4043                 else
4044                         ipv6_configuration_changed(service);
4045
4046                 if (is_connecting(service) || is_connected(service)) {
4047                         __connman_network_enable_ipconfig(service->network,
4048                                                         service->ipconfig_ipv4);
4049                         __connman_network_enable_ipconfig(service->network,
4050                                                         service->ipconfig_ipv6);
4051                 }
4052
4053                 service_save(service);
4054         } else
4055                 return __connman_error_invalid_property(msg);
4056
4057         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4058 }
4059
4060 static void set_error(struct connman_service *service,
4061                                         enum connman_service_error error)
4062 {
4063         const char *str;
4064
4065         if (service->error == error)
4066                 return;
4067
4068         service->error = error;
4069
4070         if (!service->path)
4071                 return;
4072
4073         if (!allow_property_changed(service))
4074                 return;
4075
4076         str = error2string(service->error);
4077
4078         if (!str)
4079                 str = "";
4080
4081         connman_dbus_property_changed_basic(service->path,
4082                                 CONNMAN_SERVICE_INTERFACE, "Error",
4083                                 DBUS_TYPE_STRING, &str);
4084 }
4085
4086 static void set_idle(struct connman_service *service)
4087 {
4088         service->state = service->state_ipv4 = service->state_ipv6 =
4089                                                 CONNMAN_SERVICE_STATE_IDLE;
4090         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
4091         state_changed(service);
4092 }
4093
4094 static DBusMessage *clear_property(DBusConnection *conn,
4095                                         DBusMessage *msg, void *user_data)
4096 {
4097         struct connman_service *service = user_data;
4098         const char *name;
4099
4100         DBG("service %p", service);
4101
4102         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
4103                                                         DBUS_TYPE_INVALID);
4104
4105         if (g_str_equal(name, "Error")) {
4106                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
4107
4108                 g_get_current_time(&service->modified);
4109                 service_save(service);
4110         } else
4111                 return __connman_error_invalid_property(msg);
4112
4113         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4114 }
4115
4116 static bool is_ipconfig_usable(struct connman_service *service)
4117 {
4118         if (!__connman_ipconfig_is_usable(service->ipconfig_ipv4) &&
4119                         !__connman_ipconfig_is_usable(service->ipconfig_ipv6))
4120                 return false;
4121
4122         return true;
4123 }
4124
4125 static bool is_ignore(struct connman_service *service)
4126 {
4127         if (!service->autoconnect)
4128                 return true;
4129
4130         if (service->roaming)
4131                 return true;
4132
4133         if (service->ignore)
4134                 return true;
4135
4136         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
4137                 return true;
4138
4139         if (!is_ipconfig_usable(service))
4140                 return true;
4141
4142         return false;
4143 }
4144
4145 static void disconnect_on_last_session(enum connman_service_type type)
4146 {
4147         GList *list;
4148
4149         for (list = service_list; list; list = list->next) {
4150                 struct connman_service *service = list->data;
4151
4152                 if (service->type != type)
4153                         continue;
4154
4155                 if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_SESSION)
4156                          continue;
4157
4158                 __connman_service_disconnect(service);
4159                 return;
4160         }
4161 }
4162
4163 static int active_sessions[MAX_CONNMAN_SERVICE_TYPES] = {};
4164 static int active_count = 0;
4165
4166 void __connman_service_set_active_session(bool enable, GSList *list)
4167 {
4168         if (!list)
4169                 return;
4170
4171         if (enable)
4172                 active_count++;
4173         else
4174                 active_count--;
4175
4176         while (list != NULL) {
4177                 enum connman_service_type type = GPOINTER_TO_INT(list->data);
4178
4179                 switch (type) {
4180                 case CONNMAN_SERVICE_TYPE_ETHERNET:
4181                 case CONNMAN_SERVICE_TYPE_WIFI:
4182                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
4183                 case CONNMAN_SERVICE_TYPE_CELLULAR:
4184                 case CONNMAN_SERVICE_TYPE_GADGET:
4185                         if (enable)
4186                                 active_sessions[type]++;
4187                         else
4188                                 active_sessions[type]--;
4189                         break;
4190
4191                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
4192                 case CONNMAN_SERVICE_TYPE_SYSTEM:
4193                 case CONNMAN_SERVICE_TYPE_GPS:
4194                 case CONNMAN_SERVICE_TYPE_VPN:
4195                 case CONNMAN_SERVICE_TYPE_P2P:
4196                         break;
4197                 }
4198
4199                 if (active_sessions[type] == 0)
4200                         disconnect_on_last_session(type);
4201
4202                 list = g_slist_next(list);
4203         }
4204
4205         DBG("eth %d wifi %d bt %d cellular %d gadget %d sessions %d",
4206                         active_sessions[CONNMAN_SERVICE_TYPE_ETHERNET],
4207                         active_sessions[CONNMAN_SERVICE_TYPE_WIFI],
4208                         active_sessions[CONNMAN_SERVICE_TYPE_BLUETOOTH],
4209                         active_sessions[CONNMAN_SERVICE_TYPE_CELLULAR],
4210                         active_sessions[CONNMAN_SERVICE_TYPE_GADGET],
4211                         active_count);
4212 }
4213
4214 #if defined TIZEN_CONNMAN_USE_BLACKLIST
4215 static connman_bool_t is_allowed(struct connman_service *service)
4216 {
4217         connman_bool_t allowed;
4218         const char *security = NULL;
4219
4220         if (!service)
4221                 return false;
4222
4223         security = security2string(service->security);
4224         if (!security)
4225                 return false;
4226
4227         /* check if service is existed in blacklist */
4228         allowed = __connman_agent_request_blacklist_check(service->name,
4229                         security, service->eap);
4230         if (allowed == false) {
4231                 DBG("service %p is not allowed", service);
4232                 service->autoconnect = false;
4233         }
4234
4235         return allowed;
4236 }
4237 #endif
4238
4239 struct preferred_tech_data {
4240         GList *preferred_list;
4241         enum connman_service_type type;
4242 };
4243
4244 static void preferred_tech_add_by_type(gpointer data, gpointer user_data)
4245 {
4246         struct connman_service *service = data;
4247         struct preferred_tech_data *tech_data = user_data;
4248
4249         if (service->type == tech_data->type) {
4250                 tech_data->preferred_list =
4251                         g_list_append(tech_data->preferred_list, service);
4252
4253                 DBG("type %d service %p %s", tech_data->type, service,
4254                                 service->name);
4255         }
4256 }
4257
4258 static GList *preferred_tech_list_get(void)
4259 {
4260         unsigned int *tech_array;
4261         struct preferred_tech_data tech_data = { 0, };
4262         int i;
4263
4264         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
4265         if (!tech_array)
4266                 return NULL;
4267
4268         if (connman_setting_get_bool("SingleConnectedTechnology")) {
4269                 GList *list;
4270                 for (list = service_list; list; list = list->next) {
4271                         struct connman_service *service = list->data;
4272
4273                         if (!is_connected(service))
4274                                 break;
4275
4276                         if (service->connect_reason ==
4277                                         CONNMAN_SERVICE_CONNECT_REASON_USER) {
4278                                 DBG("service %p name %s is user connected",
4279                                                 service, service->name);
4280 #if defined TIZEN_EXT
4281                                 /* We can connect to a favorite service like
4282                                  * wifi even we have a userconnect for cellular
4283                                  * because we have refount for cellular service
4284                                  */
4285                                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
4286                                         break;
4287 #endif
4288                                 return NULL;
4289                         }
4290                 }
4291         }
4292
4293         for (i = 0; tech_array[i] != 0; i += 1) {
4294                 tech_data.type = tech_array[i];
4295                 g_list_foreach(service_list, preferred_tech_add_by_type,
4296                                 &tech_data);
4297         }
4298
4299         return tech_data.preferred_list;
4300 }
4301
4302 static bool auto_connect_service(GList *services,
4303                                 enum connman_service_connect_reason reason,
4304                                 bool preferred)
4305 {
4306         struct connman_service *service = NULL;
4307         bool ignore[MAX_CONNMAN_SERVICE_TYPES] = { };
4308         bool autoconnecting = false;
4309         GList *list;
4310
4311         DBG("preferred %d sessions %d reason %s", preferred, active_count,
4312                 reason2string(reason));
4313
4314         ignore[CONNMAN_SERVICE_TYPE_VPN] = true;
4315
4316         for (list = services; list; list = list->next) {
4317                 service = list->data;
4318
4319                 if (ignore[service->type]) {
4320                         DBG("service %p type %s ignore", service,
4321                                 __connman_service_type2string(service->type));
4322                         continue;
4323                 }
4324
4325 #if defined TIZEN_EXT
4326                 DBG("service %p %s %s %s, favorite(%d), ignore(%d), hidden(%d, %d)",
4327                                 service, service->name,
4328                                 state2string(service->state),
4329                                 __connman_service_type2string(service->type),
4330                                 service->favorite, is_ignore(service),
4331                                 service->hidden, service->hidden_service);
4332
4333                 /* Tizen takes Wi-Fi as the highest priority into consideration. */
4334                 if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
4335                         if (is_connecting(service) == TRUE || is_connected(service) == TRUE)
4336                                 continue;
4337 #endif
4338
4339                 if (service->pending ||
4340                                 is_connecting(service) ||
4341                                 is_connected(service)) {
4342                         if (!active_count)
4343                                 return true;
4344
4345                         ignore[service->type] = true;
4346                         autoconnecting = true;
4347
4348                         DBG("service %p type %s busy", service,
4349                                 __connman_service_type2string(service->type));
4350
4351                         continue;
4352                 }
4353
4354                 if (!service->favorite) {
4355                         if (preferred)
4356                                continue;
4357
4358                         return autoconnecting;
4359                 }
4360
4361                 if (is_ignore(service) || service->state !=
4362                                 CONNMAN_SERVICE_STATE_IDLE)
4363                         continue;
4364
4365 #if defined TIZEN_CONNMAN_USE_BLACKLIST
4366                 if (is_allowed(service) == false)
4367                         continue;
4368 #endif
4369
4370                 if (autoconnecting && !active_sessions[service->type]) {
4371                         DBG("service %p type %s has no users", service,
4372                                 __connman_service_type2string(service->type));
4373                         continue;
4374                 }
4375
4376                 if (!is_service_owner_user_login(service)) {
4377                         DBG("favorite user not login, wifi auto connect denied");
4378                         continue;
4379                 }
4380
4381                 DBG("service %p %s %s", service, service->name,
4382                         (preferred) ? "preferred" : reason2string(reason));
4383
4384                 __connman_service_connect(service, reason);
4385
4386                 if (!active_count)
4387                         return true;
4388
4389                 ignore[service->type] = true;
4390         }
4391
4392         return autoconnecting;
4393 }
4394
4395 static gboolean run_auto_connect(gpointer data)
4396 {
4397         enum connman_service_connect_reason reason = GPOINTER_TO_UINT(data);
4398         bool autoconnecting = false;
4399         GList *preferred_tech;
4400
4401         autoconnect_timeout = 0;
4402
4403         DBG("");
4404
4405         preferred_tech = preferred_tech_list_get();
4406         if (preferred_tech) {
4407                 autoconnecting = auto_connect_service(preferred_tech, reason,
4408                                                         true);
4409                 g_list_free(preferred_tech);
4410         }
4411
4412         if (!autoconnecting || active_count)
4413                 auto_connect_service(service_list, reason, false);
4414
4415         return FALSE;
4416 }
4417
4418 void __connman_service_auto_connect(enum connman_service_connect_reason reason)
4419 {
4420         DBG("");
4421
4422         if (autoconnect_timeout != 0)
4423                 return;
4424
4425         if (!__connman_session_policy_autoconnect(reason))
4426                 return;
4427
4428 #if defined TIZEN_EXT
4429         /* Adding Timeout of 500ms before trying to auto connect.
4430          * This is done because of below scenario
4431          * 1. Device is connected to AP1
4432          * 2. WPS Connection request is initiated for AP2
4433          * 3. Immediately WPS Connection is Cancelled
4434          * When WPS Connection Connection is initiated for AP2 then
4435          * sometimes there is a scenario where connman gets in ASSOCIATED
4436          * state with AP1 due to autoconnect and subsequently the connection
4437          * initiated by AP1 fails and connman service for AP1 comes in
4438          * FAILURE state due to this when connection with AP2 is cancelled
4439          * then autoconnect with AP1 doesn't works because its autoconnection
4440          * is ignored as its last state was FAILURE rather than IDLE */
4441         autoconnect_timeout = g_timeout_add(500, run_auto_connect,
4442 #else
4443         autoconnect_timeout = g_timeout_add_seconds(0, run_auto_connect,
4444 #endif
4445                                                 GUINT_TO_POINTER(reason));
4446 }
4447
4448 static gboolean run_vpn_auto_connect(gpointer data) {
4449         GList *list;
4450         bool need_split = false;
4451
4452         vpn_autoconnect_timeout = 0;
4453
4454         for (list = service_list; list; list = list->next) {
4455                 struct connman_service *service = list->data;
4456                 int res;
4457
4458                 if (service->type != CONNMAN_SERVICE_TYPE_VPN)
4459                         continue;
4460
4461                 if (is_connected(service) || is_connecting(service)) {
4462                         if (!service->do_split_routing)
4463                                 need_split = true;
4464                         continue;
4465                 }
4466
4467                 if (is_ignore(service) || !service->favorite)
4468                         continue;
4469
4470                 if (need_split && !service->do_split_routing) {
4471                         DBG("service %p no split routing", service);
4472                         continue;
4473                 }
4474
4475                 DBG("service %p %s %s", service, service->name,
4476                                 service->do_split_routing ?
4477                                 "split routing" : "");
4478
4479                 res = __connman_service_connect(service,
4480                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4481                 if (res < 0 && res != -EINPROGRESS)
4482                         continue;
4483
4484                 if (!service->do_split_routing)
4485                         need_split = true;
4486         }
4487
4488         return FALSE;
4489 }
4490
4491 static void vpn_auto_connect(void)
4492 {
4493         if (vpn_autoconnect_timeout)
4494                 return;
4495
4496         vpn_autoconnect_timeout =
4497                 g_timeout_add_seconds(0, run_vpn_auto_connect, NULL);
4498 }
4499
4500 static void remove_timeout(struct connman_service *service)
4501 {
4502         if (service->timeout > 0) {
4503                 g_source_remove(service->timeout);
4504                 service->timeout = 0;
4505         }
4506 }
4507
4508 static void reply_pending(struct connman_service *service, int error)
4509 {
4510         remove_timeout(service);
4511
4512         if (service->pending) {
4513                 connman_dbus_reply_pending(service->pending, error, NULL);
4514                 service->pending = NULL;
4515         }
4516
4517         if (service->provider_pending) {
4518                 connman_dbus_reply_pending(service->provider_pending,
4519                                                 error, service->path);
4520                 service->provider_pending = NULL;
4521         }
4522 }
4523
4524 bool
4525 __connman_service_is_provider_pending(struct connman_service *service)
4526 {
4527         if (!service)
4528                 return false;
4529
4530         if (service->provider_pending)
4531                 return true;
4532
4533         return false;
4534 }
4535
4536 void __connman_service_set_provider_pending(struct connman_service *service,
4537                                                         DBusMessage *msg)
4538 {
4539         if (service->provider_pending) {
4540                 DBG("service %p provider pending msg %p already exists",
4541                         service, service->provider_pending);
4542                 return;
4543         }
4544
4545         service->provider_pending = msg;
4546         return;
4547 }
4548
4549 static void check_pending_msg(struct connman_service *service)
4550 {
4551         if (!service->pending)
4552                 return;
4553
4554         DBG("service %p pending msg %p already exists", service,
4555                                                 service->pending);
4556         dbus_message_unref(service->pending);
4557 }
4558
4559 void __connman_service_set_hidden_data(struct connman_service *service,
4560                                                         gpointer user_data)
4561 {
4562         DBusMessage *pending = user_data;
4563
4564         DBG("service %p pending %p", service, pending);
4565
4566         if (!pending)
4567                 return;
4568
4569         check_pending_msg(service);
4570
4571         service->pending = pending;
4572 }
4573
4574 void __connman_service_return_error(struct connman_service *service,
4575                                 int error, gpointer user_data)
4576 {
4577         DBG("service %p error %d user_data %p", service, error, user_data);
4578
4579         __connman_service_set_hidden_data(service, user_data);
4580
4581         reply_pending(service, error);
4582 }
4583
4584 static gboolean connect_timeout(gpointer user_data)
4585 {
4586         struct connman_service *service = user_data;
4587         bool autoconnect = false;
4588
4589         DBG("service %p", service);
4590
4591         service->timeout = 0;
4592
4593         if (service->network)
4594                 __connman_network_disconnect(service->network);
4595         else if (service->provider)
4596                 connman_provider_disconnect(service->provider);
4597
4598         __connman_ipconfig_disable(service->ipconfig_ipv4);
4599         __connman_ipconfig_disable(service->ipconfig_ipv6);
4600
4601         __connman_stats_service_unregister(service);
4602
4603         if (service->pending) {
4604                 DBusMessage *reply;
4605
4606                 reply = __connman_error_operation_timeout(service->pending);
4607                 if (reply)
4608                         g_dbus_send_message(connection, reply);
4609
4610                 dbus_message_unref(service->pending);
4611                 service->pending = NULL;
4612         } else
4613                 autoconnect = true;
4614
4615         __connman_service_ipconfig_indicate_state(service,
4616                                         CONNMAN_SERVICE_STATE_FAILURE,
4617                                         CONNMAN_IPCONFIG_TYPE_IPV4);
4618         __connman_service_ipconfig_indicate_state(service,
4619                                         CONNMAN_SERVICE_STATE_FAILURE,
4620                                         CONNMAN_IPCONFIG_TYPE_IPV6);
4621
4622         if (autoconnect &&
4623                         service->connect_reason !=
4624                                 CONNMAN_SERVICE_CONNECT_REASON_USER)
4625                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4626
4627         return FALSE;
4628 }
4629
4630 static DBusMessage *connect_service(DBusConnection *conn,
4631                                         DBusMessage *msg, void *user_data)
4632 {
4633         struct connman_service *service = user_data;
4634         int index, err = 0;
4635         GList *list;
4636
4637         DBG("service %p", service);
4638
4639 #if defined TIZEN_EXT
4640         /*
4641          * Description: TIZEN implements system global connection management.
4642          */
4643         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
4644                 connman_service_user_pdn_connection_ref(service);
4645 #endif
4646
4647         if (service->pending)
4648                 return __connman_error_in_progress(msg);
4649
4650         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
4651                 uid_t uid;
4652                 if (connman_dbus_get_connection_unix_user_sync(conn,
4653                                                 dbus_message_get_sender(msg),
4654                                                 &uid) < 0) {
4655                         DBG("Can not get unix user id!");
4656                         return __connman_error_permission_denied(msg);
4657                 }
4658
4659                 if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
4660                         DBG("Not allow this user to connect this wifi service now!");
4661                         return __connman_error_permission_denied(msg);
4662                 }
4663
4664                 if (uid != USER_ROOT && uid != service->user.favorite_user)
4665                         service->request_passphrase_input = true;
4666
4667                 service->user.current_user = uid;
4668
4669                 if (!service->passphrase && uid == service->user.favorite_user) {
4670                         DBG("Now load this favorite user's passphrase.");
4671                         service_load_passphrase(service);
4672                 }
4673         }
4674
4675         index = __connman_service_get_index(service);
4676
4677         for (list = service_list; list; list = list->next) {
4678                 struct connman_service *temp = list->data;
4679
4680 #if defined TIZEN_EXT
4681                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
4682                         break;
4683 #endif
4684                 if (!is_connecting(temp) && !is_connected(temp))
4685                         break;
4686
4687                 if (service == temp)
4688                         continue;
4689
4690                 if (service->type != temp->type)
4691                         continue;
4692
4693                 if (__connman_service_get_index(temp) == index &&
4694                                 __connman_service_disconnect(temp) == -EINPROGRESS)
4695                         err = -EINPROGRESS;
4696
4697         }
4698         if (err == -EINPROGRESS)
4699                 return __connman_error_operation_timeout(msg);
4700
4701         service->ignore = false;
4702
4703         service->pending = dbus_message_ref(msg);
4704
4705         err = __connman_service_connect(service,
4706                         CONNMAN_SERVICE_CONNECT_REASON_USER);
4707
4708         if (err == -EINPROGRESS)
4709                 return NULL;
4710
4711         if (service->pending) {
4712                 dbus_message_unref(service->pending);
4713                 service->pending = NULL;
4714         }
4715
4716         if (err < 0)
4717                 return __connman_error_failed(msg, -err);
4718
4719         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4720 }
4721
4722 static DBusMessage *disconnect_service(DBusConnection *conn,
4723                                         DBusMessage *msg, void *user_data)
4724 {
4725         struct connman_service *service = user_data;
4726         int err;
4727
4728         DBG("service %p", service);
4729
4730 #if defined TIZEN_EXT
4731         /*
4732          * Description: TIZEN implements system global connection management.
4733          */
4734         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
4735                 if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE)
4736                         return __connman_error_failed(msg, EISCONN);
4737
4738                 if (is_connected(service) == TRUE &&
4739                                 service == connman_service_get_default_connection())
4740                         return __connman_error_failed(msg, EISCONN);
4741         }
4742 #endif
4743
4744         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
4745                 uid_t uid;
4746                 if (connman_dbus_get_connection_unix_user_sync(conn,
4747                                                 dbus_message_get_sender(msg),
4748                                                 &uid) < 0) {
4749                         DBG("Can not get unix user id!");
4750                         return __connman_error_permission_denied(msg);
4751                 }
4752
4753                 if (!connman_service_is_user_allowed(service, uid)) {
4754                         DBG("Not allow this user to disconnect this wifi service now!");
4755                         return __connman_error_permission_denied(msg);
4756                 }
4757         }
4758
4759         service->ignore = true;
4760
4761         err = __connman_service_disconnect(service);
4762         if (err < 0 && err != -EINPROGRESS)
4763                 return __connman_error_failed(msg, -err);
4764
4765         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4766 }
4767
4768 #if defined TIZEN_EXT
4769 static void __connman_service_cleanup_network_8021x(struct connman_service *service)
4770 {
4771         if (service == NULL)
4772                 return;
4773
4774         DBG("service %p ", service);
4775
4776         connman_network_set_string(service->network, "WiFi.EAP", NULL);
4777         connman_network_set_string(service->network, "WiFi.Identity", NULL);
4778         connman_network_set_string(service->network, "WiFi.CACertFile", NULL);
4779         connman_network_set_string(service->network, "WiFi.ClientCertFile", NULL);
4780         connman_network_set_string(service->network, "WiFi.PrivateKeyFile", NULL);
4781         connman_network_set_string(service->network, "WiFi.PrivateKeyPassphrase", NULL);
4782         connman_network_set_string(service->network, "WiFi.Phase2", NULL);
4783 }
4784 #endif
4785
4786 bool __connman_service_remove(struct connman_service *service)
4787 {
4788         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET ||
4789                         service->type == CONNMAN_SERVICE_TYPE_GADGET)
4790                 return false;
4791
4792         if (service->immutable || service->hidden ||
4793                         __connman_provider_is_immutable(service->provider))
4794                 return false;
4795
4796         if (!service->favorite && service->state !=
4797                                                 CONNMAN_SERVICE_STATE_FAILURE)
4798                 return false;
4799
4800         __connman_service_disconnect(service);
4801
4802         g_free(service->passphrase);
4803         service->passphrase = NULL;
4804
4805         g_free(service->identity);
4806         service->identity = NULL;
4807
4808         g_free(service->agent_identity);
4809         service->agent_identity = NULL;
4810
4811         g_free(service->eap);
4812         service->eap = NULL;
4813
4814 #if defined TIZEN_EXT
4815         g_free(service->ca_cert_file);
4816         service->ca_cert_file = NULL;
4817
4818         g_free(service->client_cert_file);
4819         service->client_cert_file = NULL;
4820
4821         g_free(service->private_key_file);
4822         service->private_key_file = NULL;
4823
4824         g_free(service->private_key_passphrase);
4825         service->private_key_passphrase = NULL;
4826
4827         g_free(service->phase2);
4828         service->phase2 = NULL;
4829
4830         __connman_service_cleanup_network_8021x(service);
4831
4832         __connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP);
4833         __connman_ipconfig_set_method(service->ipconfig_ipv6, CONNMAN_IPCONFIG_METHOD_AUTO);
4834         connman_service_set_proxy(service, NULL, false);
4835
4836         __connman_service_nameserver_clear(service);
4837
4838         g_strfreev(service->nameservers_config);
4839         service->nameservers_config = NULL;
4840
4841 #endif
4842
4843 #if defined TIZEN_EXT
4844         if (service->security != CONNMAN_SERVICE_SECURITY_8021X)
4845 #endif
4846         set_idle(service);
4847
4848         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
4849
4850         service->user.favorite_user = USER_NONE;
4851
4852         __connman_service_set_favorite(service, false);
4853
4854         __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
4855
4856 #if defined TIZEN_EXT
4857         __connman_storage_remove_service(service->identifier);
4858 #else
4859         service_save(service);
4860 #endif
4861
4862         return true;
4863 }
4864
4865 static DBusMessage *remove_service(DBusConnection *conn,
4866                                         DBusMessage *msg, void *user_data)
4867 {
4868         struct connman_service *service = user_data;
4869
4870         DBG("service %p", service);
4871
4872         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
4873                 uid_t uid;
4874                 if (connman_dbus_get_connection_unix_user_sync(conn,
4875                                                 dbus_message_get_sender(msg),
4876                                                 &uid) < 0) {
4877                         DBG("Can not get unix user id!");
4878                         return __connman_error_permission_denied(msg);
4879                 }
4880
4881 #if !defined TIZEN_EXT
4882                 if (!connman_service_is_user_allowed(service, uid)) {
4883                         DBG("Not allow this user to remove this wifi service now!");
4884                         return __connman_error_permission_denied(msg);
4885                 }
4886 #endif
4887         }
4888
4889         if (!__connman_service_remove(service))
4890                 return __connman_error_not_supported(msg);
4891
4892         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4893 }
4894
4895 static bool check_suitable_state(enum connman_service_state a,
4896                                         enum connman_service_state b)
4897 {
4898         /*
4899          * Special check so that "ready" service can be moved before
4900          * "online" one.
4901          */
4902         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
4903                         b == CONNMAN_SERVICE_STATE_READY) ||
4904                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
4905                         a == CONNMAN_SERVICE_STATE_READY))
4906                 return true;
4907
4908         return a == b;
4909 }
4910
4911 static void downgrade_state(struct connman_service *service)
4912 {
4913         if (!service)
4914                 return;
4915
4916         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
4917                                                 service->state_ipv6);
4918
4919         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
4920                 __connman_service_ipconfig_indicate_state(service,
4921                                                 CONNMAN_SERVICE_STATE_READY,
4922                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4923
4924         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
4925                 __connman_service_ipconfig_indicate_state(service,
4926                                                 CONNMAN_SERVICE_STATE_READY,
4927                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
4928 }
4929
4930 static void apply_relevant_default_downgrade(struct connman_service *service)
4931 {
4932         struct connman_service *def_service;
4933
4934         def_service = __connman_service_get_default();
4935         if (!def_service)
4936                 return;
4937
4938         if (def_service == service &&
4939                         def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
4940                 def_service->state = CONNMAN_SERVICE_STATE_READY;
4941                 __connman_notifier_leave_online(def_service->type);
4942                 state_changed(def_service);
4943         }
4944 }
4945
4946 static void switch_default_service(struct connman_service *default_service,
4947                 struct connman_service *downgrade_service)
4948 {
4949         struct connman_service *service;
4950         GList *src, *dst;
4951
4952         apply_relevant_default_downgrade(default_service);
4953         src = g_list_find(service_list, downgrade_service);
4954         dst = g_list_find(service_list, default_service);
4955
4956         /* Nothing to do */
4957         if (src == dst || src->next == dst)
4958                 return;
4959
4960         service = src->data;
4961         service_list = g_list_delete_link(service_list, src);
4962         service_list = g_list_insert_before(service_list, dst, service);
4963
4964         downgrade_state(downgrade_service);
4965 }
4966
4967 static DBusMessage *move_service(DBusConnection *conn,
4968                                         DBusMessage *msg, void *user_data,
4969                                                                 bool before)
4970 {
4971         struct connman_service *service = user_data;
4972         struct connman_service *target;
4973         const char *path;
4974         enum connman_ipconfig_method target4, target6;
4975         enum connman_ipconfig_method service4, service6;
4976
4977         DBG("service %p", service);
4978
4979         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
4980                                                         DBUS_TYPE_INVALID);
4981
4982         if (!service->favorite)
4983                 return __connman_error_not_supported(msg);
4984
4985         target = find_service(path);
4986         if (!target || !target->favorite || target == service)
4987                 return __connman_error_invalid_service(msg);
4988
4989         if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
4990                 /*
4991                  * We only allow VPN route splitting if there are
4992                  * routes defined for a given VPN.
4993                  */
4994                 if (!__connman_provider_check_routes(target->provider)) {
4995                         connman_info("Cannot move service. "
4996                                 "No routes defined for provider %s",
4997                                 __connman_provider_get_ident(target->provider));
4998                         return __connman_error_invalid_service(msg);
4999                 }
5000
5001                 target->do_split_routing = true;
5002         } else
5003                 target->do_split_routing = false;
5004
5005         service->do_split_routing = false;
5006
5007         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
5008         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
5009         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
5010         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
5011
5012         DBG("target %s method %d/%d state %d/%d split %d", target->identifier,
5013                 target4, target6, target->state_ipv4, target->state_ipv6,
5014                 target->do_split_routing);
5015
5016         DBG("service %s method %d/%d state %d/%d", service->identifier,
5017                                 service4, service6,
5018                                 service->state_ipv4, service->state_ipv6);
5019
5020         /*
5021          * If method is OFF, then we do not need to check the corresponding
5022          * ipconfig state.
5023          */
5024         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5025                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5026                         if (!check_suitable_state(target->state_ipv6,
5027                                                         service->state_ipv6))
5028                                 return __connman_error_invalid_service(msg);
5029                 }
5030         }
5031
5032         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5033                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5034                         if (!check_suitable_state(target->state_ipv4,
5035                                                         service->state_ipv4))
5036                                 return __connman_error_invalid_service(msg);
5037                 }
5038         }
5039
5040         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5041                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5042                         if (!check_suitable_state(target->state_ipv6,
5043                                                         service->state_ipv6))
5044                                 return __connman_error_invalid_service(msg);
5045                 }
5046         }
5047
5048         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5049                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5050                         if (!check_suitable_state(target->state_ipv4,
5051                                                         service->state_ipv4))
5052                                 return __connman_error_invalid_service(msg);
5053                 }
5054         }
5055
5056         g_get_current_time(&service->modified);
5057         service_save(service);
5058         service_save(target);
5059
5060         /*
5061          * If the service which goes down is the default service and is
5062          * online, we downgrade directly its state to ready so:
5063          * the service which goes up, needs to recompute its state which
5064          * is triggered via downgrading it - if relevant - to state ready.
5065          */
5066         if (before)
5067                 switch_default_service(target, service);
5068         else
5069                 switch_default_service(service, target);
5070
5071         __connman_connection_update_gateway();
5072
5073         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5074 }
5075
5076 static DBusMessage *move_before(DBusConnection *conn,
5077                                         DBusMessage *msg, void *user_data)
5078 {
5079         return move_service(conn, msg, user_data, true);
5080 }
5081
5082 static DBusMessage *move_after(DBusConnection *conn,
5083                                         DBusMessage *msg, void *user_data)
5084 {
5085         return move_service(conn, msg, user_data, false);
5086 }
5087
5088 static DBusMessage *reset_counters(DBusConnection *conn,
5089                                         DBusMessage *msg, void *user_data)
5090 {
5091         struct connman_service *service = user_data;
5092
5093         reset_stats(service);
5094
5095         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5096 }
5097
5098 static DBusMessage *get_user_favorite(DBusConnection *conn,
5099                                         DBusMessage *msg, void *user_data)
5100 {
5101         DBusMessage *reply;
5102         uid_t uid = USER_NONE;
5103         dbus_bool_t user_favorite = false;
5104         struct connman_service *service = user_data;
5105
5106         connman_dbus_get_connection_unix_user_sync(conn,
5107                                         dbus_message_get_sender(msg),
5108                                         &uid);
5109         if (uid == USER_ROOT)
5110                 user_favorite = service->favorite;
5111         else if (uid != USER_NONE && uid == service->user.favorite_user) {
5112                 DBG("The service is favorite to this user!");
5113                 user_favorite = true;
5114         }
5115
5116         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5117         dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,
5118                                 &user_favorite, DBUS_TYPE_INVALID);
5119         return reply;
5120 }
5121
5122 static struct _services_notify {
5123         int id;
5124         GHashTable *add;
5125         GHashTable *remove;
5126 } *services_notify;
5127
5128 static void service_append_added_foreach(gpointer data, gpointer user_data)
5129 {
5130         struct connman_service *service = data;
5131         DBusMessageIter *iter = user_data;
5132
5133         if (!service || !service->path) {
5134                 DBG("service %p or path is NULL", service);
5135                 return;
5136         }
5137
5138         if (g_hash_table_lookup(services_notify->add, service->path)) {
5139                 DBG("new %s", service->path);
5140
5141                 append_struct(service, iter);
5142                 g_hash_table_remove(services_notify->add, service->path);
5143         } else {
5144                 DBG("changed %s", service->path);
5145
5146                 append_struct_service(iter, NULL, service);
5147         }
5148 }
5149
5150 static void service_append_ordered(DBusMessageIter *iter, void *user_data)
5151 {
5152         g_list_foreach(service_list, service_append_added_foreach, iter);
5153 }
5154
5155 static void append_removed(gpointer key, gpointer value, gpointer user_data)
5156 {
5157         char *objpath = key;
5158         DBusMessageIter *iter = user_data;
5159
5160         DBG("removed %s", objpath);
5161         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
5162 }
5163
5164 static void service_append_removed(DBusMessageIter *iter, void *user_data)
5165 {
5166         g_hash_table_foreach(services_notify->remove, append_removed, iter);
5167 }
5168
5169 static gboolean service_send_changed(gpointer data)
5170 {
5171         DBusMessage *signal;
5172
5173         DBG("");
5174
5175         services_notify->id = 0;
5176
5177         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
5178                         CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
5179         if (!signal)
5180                 return FALSE;
5181
5182         __connman_dbus_append_objpath_dict_array(signal,
5183                                         service_append_ordered, NULL);
5184         __connman_dbus_append_objpath_array(signal,
5185                                         service_append_removed, NULL);
5186
5187         dbus_connection_send(connection, signal, NULL);
5188         dbus_message_unref(signal);
5189
5190         g_hash_table_remove_all(services_notify->remove);
5191         g_hash_table_remove_all(services_notify->add);
5192
5193         return FALSE;
5194 }
5195
5196 static void service_schedule_changed(void)
5197 {
5198         if (services_notify->id != 0)
5199                 return;
5200
5201         services_notify->id = g_timeout_add(100, service_send_changed, NULL);
5202 }
5203
5204 static void service_schedule_added(struct connman_service *service)
5205 {
5206         DBG("service %p", service);
5207
5208         g_hash_table_remove(services_notify->remove, service->path);
5209         g_hash_table_replace(services_notify->add, service->path, service);
5210
5211         service_schedule_changed();
5212 }
5213
5214 static void service_schedule_removed(struct connman_service *service)
5215 {
5216         if (!service || !service->path) {
5217                 DBG("service %p or path is NULL", service);
5218                 return;
5219         }
5220
5221         DBG("service %p %s", service, service->path);
5222
5223         g_hash_table_remove(services_notify->add, service->path);
5224         g_hash_table_replace(services_notify->remove, g_strdup(service->path),
5225                         NULL);
5226
5227         service_schedule_changed();
5228 }
5229
5230 static bool allow_property_changed(struct connman_service *service)
5231 {
5232 #if defined TIZEN_EXT
5233         if (service->path == NULL)
5234                 return FALSE;
5235 #endif
5236         if (g_hash_table_lookup_extended(services_notify->add, service->path,
5237                                         NULL, NULL)) {
5238                 DBG("no property updates for service %p", service);
5239                 return false;
5240         }
5241
5242         return true;
5243 }
5244
5245 static const GDBusMethodTable service_methods[] = {
5246         { GDBUS_DEPRECATED_METHOD("GetProperties",
5247                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
5248                         get_properties) },
5249         { GDBUS_METHOD("SetProperty",
5250                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
5251                         NULL, set_property) },
5252         { GDBUS_METHOD("ClearProperty",
5253                         GDBUS_ARGS({ "name", "s" }), NULL,
5254                         clear_property) },
5255         { GDBUS_ASYNC_METHOD("Connect", NULL, NULL,
5256                               connect_service) },
5257         { GDBUS_METHOD("Disconnect", NULL, NULL,
5258                         disconnect_service) },
5259         { GDBUS_METHOD("Remove", NULL, NULL, remove_service) },
5260         { GDBUS_METHOD("MoveBefore",
5261                         GDBUS_ARGS({ "service", "o" }), NULL,
5262                         move_before) },
5263         { GDBUS_METHOD("MoveAfter",
5264                         GDBUS_ARGS({ "service", "o" }), NULL,
5265                         move_after) },
5266         { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
5267         { GDBUS_METHOD("GetUserFavorite",
5268                         NULL, GDBUS_ARGS({ "value", "v" }),
5269                         get_user_favorite) },
5270         { },
5271 };
5272
5273 static const GDBusSignalTable service_signals[] = {
5274         { GDBUS_SIGNAL("PropertyChanged",
5275                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
5276         { },
5277 };
5278
5279 static void service_free(gpointer user_data)
5280 {
5281         struct connman_service *service = user_data;
5282         char *path = service->path;
5283
5284         DBG("service %p", service);
5285
5286         reply_pending(service, ENOENT);
5287
5288         __connman_notifier_service_remove(service);
5289         service_schedule_removed(service);
5290
5291         __connman_wispr_stop(service);
5292         stats_stop(service);
5293
5294         service->path = NULL;
5295
5296         if (path) {
5297                 __connman_connection_update_gateway();
5298
5299                 g_dbus_unregister_interface(connection, path,
5300                                                 CONNMAN_SERVICE_INTERFACE);
5301                 g_free(path);
5302         }
5303
5304         g_hash_table_destroy(service->counter_table);
5305
5306         if (service->network) {
5307                 __connman_network_disconnect(service->network);
5308                 connman_network_unref(service->network);
5309                 service->network = NULL;
5310         }
5311
5312         if (service->provider)
5313                 connman_provider_unref(service->provider);
5314
5315         if (service->ipconfig_ipv4) {
5316                 __connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
5317                 __connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
5318                 __connman_ipconfig_unref(service->ipconfig_ipv4);
5319                 service->ipconfig_ipv4 = NULL;
5320         }
5321
5322         if (service->ipconfig_ipv6) {
5323                 __connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
5324                 __connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
5325                 __connman_ipconfig_unref(service->ipconfig_ipv6);
5326                 service->ipconfig_ipv6 = NULL;
5327         }
5328
5329         g_strfreev(service->timeservers);
5330         g_strfreev(service->timeservers_config);
5331         g_strfreev(service->nameservers);
5332         g_strfreev(service->nameservers_config);
5333         g_strfreev(service->nameservers_auto);
5334         g_strfreev(service->domains);
5335         g_strfreev(service->proxies);
5336         g_strfreev(service->excludes);
5337
5338         g_free(service->hostname);
5339         g_free(service->domainname);
5340         g_free(service->pac);
5341         g_free(service->name);
5342         g_free(service->passphrase);
5343         g_free(service->identifier);
5344         g_free(service->eap);
5345         g_free(service->identity);
5346         g_free(service->agent_identity);
5347         g_free(service->ca_cert_file);
5348         g_free(service->client_cert_file);
5349         g_free(service->private_key_file);
5350         g_free(service->private_key_passphrase);
5351         g_free(service->phase2);
5352         g_free(service->config_file);
5353         g_free(service->config_entry);
5354
5355         if (service->stats.timer)
5356                 g_timer_destroy(service->stats.timer);
5357         if (service->stats_roaming.timer)
5358                 g_timer_destroy(service->stats_roaming.timer);
5359
5360         if (current_default == service)
5361                 current_default = NULL;
5362
5363         g_free(service);
5364 }
5365
5366 static void stats_init(struct connman_service *service)
5367 {
5368         /* home */
5369         service->stats.valid = false;
5370         service->stats.enabled = false;
5371         service->stats.timer = g_timer_new();
5372
5373         /* roaming */
5374         service->stats_roaming.valid = false;
5375         service->stats_roaming.enabled = false;
5376         service->stats_roaming.timer = g_timer_new();
5377 }
5378
5379 static void service_initialize(struct connman_service *service)
5380 {
5381         DBG("service %p", service);
5382
5383         service->refcount = 1;
5384
5385         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
5386
5387         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
5388         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
5389
5390         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
5391         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
5392         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
5393
5394         service->favorite  = false;
5395         service->immutable = false;
5396         service->hidden = false;
5397
5398         service->ignore = false;
5399
5400         service->user.favorite_user = USER_NONE;
5401         service->user.current_user = USER_NONE;
5402
5403         service->request_passphrase_input = false;
5404
5405         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
5406
5407         service->order = 0;
5408
5409         stats_init(service);
5410
5411         service->provider = NULL;
5412
5413         service->wps = false;
5414 #if defined TIZEN_EXT
5415         service->storage_reload = false;
5416         /*
5417          * Description: TIZEN implements system global connection management.
5418          */
5419         service->user_pdn_connection_refcount = 0;
5420         __sync_synchronize();
5421 #endif
5422 }
5423
5424 /**
5425  * connman_service_create:
5426  *
5427  * Allocate a new service.
5428  *
5429  * Returns: a newly-allocated #connman_service structure
5430  */
5431 struct connman_service *connman_service_create(void)
5432 {
5433         GSList *list;
5434         struct connman_stats_counter *counters;
5435         const char *counter;
5436
5437         struct connman_service *service;
5438
5439         service = g_try_new0(struct connman_service, 1);
5440         if (!service)
5441                 return NULL;
5442
5443         DBG("service %p", service);
5444
5445         service->counter_table = g_hash_table_new_full(g_str_hash,
5446                                                 g_str_equal, NULL, g_free);
5447
5448         for (list = counter_list; list; list = list->next) {
5449                 counter = list->data;
5450
5451                 counters = g_try_new0(struct connman_stats_counter, 1);
5452                 if (!counters) {
5453                         g_hash_table_destroy(service->counter_table);
5454                         g_free(service);
5455                         return NULL;
5456                 }
5457
5458                 counters->append_all = true;
5459
5460                 g_hash_table_replace(service->counter_table, (gpointer)counter,
5461                                 counters);
5462         }
5463
5464         service_initialize(service);
5465
5466         return service;
5467 }
5468
5469 /**
5470  * connman_service_ref:
5471  * @service: service structure
5472  *
5473  * Increase reference counter of service
5474  */
5475 struct connman_service *
5476 connman_service_ref_debug(struct connman_service *service,
5477                         const char *file, int line, const char *caller)
5478 {
5479         DBG("%p ref %d by %s:%d:%s()", service, service->refcount + 1,
5480                 file, line, caller);
5481
5482         __sync_fetch_and_add(&service->refcount, 1);
5483
5484         return service;
5485 }
5486
5487 /**
5488  * connman_service_unref:
5489  * @service: service structure
5490  *
5491  * Decrease reference counter of service and release service if no
5492  * longer needed.
5493  */
5494 void connman_service_unref_debug(struct connman_service *service,
5495                         const char *file, int line, const char *caller)
5496 {
5497         DBG("%p ref %d by %s:%d:%s()", service, service->refcount - 1,
5498                 file, line, caller);
5499
5500         if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
5501                 return;
5502
5503         service_list = g_list_remove(service_list, service);
5504
5505         __connman_service_disconnect(service);
5506
5507         g_hash_table_remove(service_hash, service->identifier);
5508 }
5509
5510 static gint service_compare(gconstpointer a, gconstpointer b)
5511 {
5512         struct connman_service *service_a = (void *) a;
5513         struct connman_service *service_b = (void *) b;
5514         enum connman_service_state state_a, state_b;
5515         bool a_connected, b_connected;
5516         gint strength;
5517
5518         state_a = service_a->state;
5519         state_b = service_b->state;
5520         a_connected = is_connected(service_a);
5521         b_connected = is_connected(service_b);
5522
5523         if (a_connected && b_connected) {
5524                 if (service_a->order > service_b->order)
5525                         return -1;
5526
5527                 if (service_a->order < service_b->order)
5528                         return 1;
5529         }
5530
5531         if (state_a != state_b) {
5532                 if (a_connected && b_connected) {
5533                         /* We prefer online over ready state */
5534                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
5535                                 return -1;
5536
5537                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
5538                                 return 1;
5539                 }
5540
5541                 if (a_connected)
5542                         return -1;
5543                 if (b_connected)
5544                         return 1;
5545
5546                 if (is_connecting(service_a))
5547                         return -1;
5548                 if (is_connecting(service_b))
5549                         return 1;
5550         }
5551
5552         if (service_a->favorite && !service_b->favorite)
5553                 return -1;
5554
5555         if (!service_a->favorite && service_b->favorite)
5556                 return 1;
5557
5558         if (service_a->type != service_b->type) {
5559
5560                 if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
5561                         return -1;
5562                 if (service_b->type == CONNMAN_SERVICE_TYPE_ETHERNET)
5563                         return 1;
5564
5565                 if (service_a->type == CONNMAN_SERVICE_TYPE_WIFI)
5566                         return -1;
5567                 if (service_b->type == CONNMAN_SERVICE_TYPE_WIFI)
5568                         return 1;
5569
5570                 if (service_a->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5571                         return -1;
5572                 if (service_b->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5573                         return 1;
5574
5575                 if (service_a->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
5576                         return -1;
5577                 if (service_b->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
5578                         return 1;
5579
5580                 if (service_a->type == CONNMAN_SERVICE_TYPE_VPN)
5581                         return -1;
5582                 if (service_b->type == CONNMAN_SERVICE_TYPE_VPN)
5583                         return 1;
5584
5585                 if (service_a->type == CONNMAN_SERVICE_TYPE_GADGET)
5586                         return -1;
5587                 if (service_b->type == CONNMAN_SERVICE_TYPE_GADGET)
5588                         return 1;
5589         }
5590
5591         strength = (gint) service_b->strength - (gint) service_a->strength;
5592         if (strength)
5593                 return strength;
5594
5595         return g_strcmp0(service_a->name, service_b->name);
5596 }
5597
5598 static void service_list_sort(void)
5599 {
5600         if (service_list && service_list->next) {
5601                 service_list = g_list_sort(service_list, service_compare);
5602                 service_schedule_changed();
5603         }
5604 }
5605
5606 /**
5607  * connman_service_get_type:
5608  * @service: service structure
5609  *
5610  * Get the type of service
5611  */
5612 enum connman_service_type connman_service_get_type(struct connman_service *service)
5613 {
5614         if (!service)
5615                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
5616
5617         return service->type;
5618 }
5619
5620 /**
5621  * connman_service_get_interface:
5622  * @service: service structure
5623  *
5624  * Get network interface of service
5625  */
5626 char *connman_service_get_interface(struct connman_service *service)
5627 {
5628         int index;
5629
5630         if (!service)
5631                 return NULL;
5632
5633         index = __connman_service_get_index(service);
5634
5635         return connman_inet_ifname(index);
5636 }
5637
5638 /**
5639  * __connman_service_is_user_allowed:
5640  * @type: service type
5641  * @uid: user id
5642  *
5643  * Check a user is allowed to operate a type of service
5644  */
5645 bool __connman_service_is_user_allowed(enum connman_service_type type,
5646                                         uid_t uid)
5647 {
5648         GList *list;
5649         uid_t owner_user = USER_NONE;
5650
5651         for (list = service_list; list; list = list->next) {
5652                 struct connman_service *service = list->data;
5653
5654                 if (service->type != type)
5655                         continue;
5656
5657                 if (is_connected(service)) {
5658                         owner_user = service->user.favorite_user;
5659                         break;
5660                 }
5661         }
5662
5663         if (uid == USER_NONE ||
5664                         (uid != USER_ROOT &&
5665                         owner_user != USER_NONE &&
5666                         owner_user != uid))
5667                 return false;
5668
5669         return true;
5670 }
5671
5672 /**
5673  * connman_service_get_network:
5674  * @service: service structure
5675  *
5676  * Get the service network
5677  */
5678 struct connman_network *
5679 __connman_service_get_network(struct connman_service *service)
5680 {
5681         if (!service)
5682                 return NULL;
5683
5684         return service->network;
5685 }
5686
5687 struct connman_ipconfig *
5688 __connman_service_get_ip4config(struct connman_service *service)
5689 {
5690         if (!service)
5691                 return NULL;
5692
5693         return service->ipconfig_ipv4;
5694 }
5695
5696 struct connman_ipconfig *
5697 __connman_service_get_ip6config(struct connman_service *service)
5698 {
5699         if (!service)
5700                 return NULL;
5701
5702         return service->ipconfig_ipv6;
5703 }
5704
5705 struct connman_ipconfig *
5706 __connman_service_get_ipconfig(struct connman_service *service, int family)
5707 {
5708         if (family == AF_INET)
5709                 return __connman_service_get_ip4config(service);
5710         else if (family == AF_INET6)
5711                 return __connman_service_get_ip6config(service);
5712         else
5713                 return NULL;
5714
5715 }
5716
5717 bool __connman_service_is_connected_state(struct connman_service *service,
5718                                         enum connman_ipconfig_type type)
5719 {
5720         if (!service)
5721                 return false;
5722
5723         switch (type) {
5724         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
5725                 break;
5726         case CONNMAN_IPCONFIG_TYPE_IPV4:
5727                 return is_connected_state(service, service->state_ipv4);
5728         case CONNMAN_IPCONFIG_TYPE_IPV6:
5729                 return is_connected_state(service, service->state_ipv6);
5730         case CONNMAN_IPCONFIG_TYPE_ALL:
5731                 return is_connected_state(service,
5732                                         CONNMAN_IPCONFIG_TYPE_IPV4) &&
5733                         is_connected_state(service,
5734                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5735         }
5736
5737         return false;
5738 }
5739 enum connman_service_security __connman_service_get_security(
5740                                 struct connman_service *service)
5741 {
5742         if (!service)
5743                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
5744
5745         return service->security;
5746 }
5747
5748 const char *__connman_service_get_phase2(struct connman_service *service)
5749 {
5750         if (!service)
5751                 return NULL;
5752
5753         return service->phase2;
5754 }
5755
5756 bool __connman_service_wps_enabled(struct connman_service *service)
5757 {
5758         if (!service)
5759                 return false;
5760
5761         return service->wps;
5762 }
5763
5764 void __connman_service_mark_dirty(void)
5765 {
5766         services_dirty = true;
5767 }
5768
5769 #if defined TIZEN_EXT
5770 /**
5771   * Returns profile count if there is any connected profiles
5772   * that use same interface
5773   */
5774 int __connman_service_get_connected_count_of_iface(
5775                                         struct connman_service *service)
5776 {
5777         GList *list;
5778         int count = 0;
5779         int index1 = 0;
5780         int index2 = 0;
5781
5782         DBG("");
5783
5784         index1 = __connman_service_get_index(service);
5785
5786         if (index1 <= 0)
5787                 return 0;
5788
5789         for (list = service_list; list; list = list->next) {
5790                 struct connman_service *service2 = list->data;
5791
5792                 if (service == service2)
5793                         continue;
5794
5795                 index2 = __connman_service_get_index(service2);
5796
5797                 if (is_connected(service2) && index2 > 0 && index1 == index2)
5798                         count++;
5799
5800                 index2 = 0;
5801         }
5802
5803         DBG("Interface index %d, count %d", index1, count);
5804
5805         return count;
5806 }
5807
5808 void __connman_service_set_storage_reload(struct connman_service *service,
5809                                         bool storage_reload)
5810 {
5811         if (service != NULL)
5812                 service->storage_reload = storage_reload;
5813 }
5814 #endif
5815
5816 /**
5817  * __connman_service_set_favorite_delayed:
5818  * @service: service structure
5819  * @favorite: favorite value
5820  * @delay_ordering: do not order service sequence
5821  *
5822  * Change the favorite setting of service
5823  */
5824 int __connman_service_set_favorite_delayed(struct connman_service *service,
5825                                         bool favorite,
5826                                         bool delay_ordering)
5827 {
5828 #if defined TIZEN_EXT
5829         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5830                 return -EIO;
5831 #endif
5832         if (service->hidden)
5833                 return -EOPNOTSUPP;
5834
5835         if (service->favorite == favorite)
5836                 return -EALREADY;
5837
5838         service->favorite = favorite;
5839
5840         if (!delay_ordering)
5841                 __connman_service_get_order(service);
5842
5843         favorite_changed(service);
5844
5845         if (!delay_ordering) {
5846
5847                 service_list_sort();
5848
5849                 __connman_connection_update_gateway();
5850         }
5851
5852         return 0;
5853 }
5854
5855 /**
5856  * __connman_service_set_favorite:
5857  * @service: service structure
5858  * @favorite: favorite value
5859  *
5860  * Change the favorite setting of service
5861  */
5862 int __connman_service_set_favorite(struct connman_service *service,
5863                                                 bool favorite)
5864 {
5865         return __connman_service_set_favorite_delayed(service, favorite,
5866                                                         false);
5867 }
5868
5869 bool connman_service_get_favorite(struct connman_service *service)
5870 {
5871         return service->favorite;
5872 }
5873
5874 bool connman_service_get_autoconnect(struct connman_service *service)
5875 {
5876         return service->autoconnect;
5877 }
5878
5879 int __connman_service_set_immutable(struct connman_service *service,
5880                                                 bool immutable)
5881 {
5882         if (service->hidden)
5883                 return -EOPNOTSUPP;
5884
5885         if (service->immutable == immutable)
5886                 return 0;
5887
5888         service->immutable = immutable;
5889
5890         immutable_changed(service);
5891
5892         return 0;
5893 }
5894
5895 int __connman_service_set_ignore(struct connman_service *service,
5896                                                 bool ignore)
5897 {
5898         if (!service)
5899                 return -EINVAL;
5900
5901         service->ignore = ignore;
5902
5903         return 0;
5904 }
5905
5906 void __connman_service_set_string(struct connman_service *service,
5907                                   const char *key, const char *value)
5908 {
5909         if (service->hidden)
5910                 return;
5911         if (g_str_equal(key, "EAP")) {
5912                 g_free(service->eap);
5913                 service->eap = g_strdup(value);
5914         } else if (g_str_equal(key, "Identity")) {
5915                 g_free(service->identity);
5916                 service->identity = g_strdup(value);
5917         } else if (g_str_equal(key, "CACertFile")) {
5918                 g_free(service->ca_cert_file);
5919                 service->ca_cert_file = g_strdup(value);
5920         } else if (g_str_equal(key, "ClientCertFile")) {
5921                 g_free(service->client_cert_file);
5922                 service->client_cert_file = g_strdup(value);
5923         } else if (g_str_equal(key, "PrivateKeyFile")) {
5924                 g_free(service->private_key_file);
5925                 service->private_key_file = g_strdup(value);
5926         } else if (g_str_equal(key, "PrivateKeyPassphrase")) {
5927                 g_free(service->private_key_passphrase);
5928                 service->private_key_passphrase = g_strdup(value);
5929         } else if (g_str_equal(key, "Phase2")) {
5930                 g_free(service->phase2);
5931                 service->phase2 = g_strdup(value);
5932         } else if (g_str_equal(key, "Passphrase"))
5933                 __connman_service_set_passphrase(service, value);
5934 }
5935
5936 void __connman_service_set_search_domains(struct connman_service *service,
5937                                         char **domains)
5938 {
5939         searchdomain_remove_all(service);
5940
5941         if (service->domains)
5942                 g_strfreev(service->domains);
5943
5944         service->domains = g_strdupv(domains);
5945
5946         searchdomain_add_all(service);
5947 }
5948
5949 #if defined TIZEN_EXT
5950 void __connman_service_set_autoconnect(struct connman_service *service,
5951                                                 bool autoconnect)
5952 {
5953         if (service == NULL)
5954                 return;
5955
5956         if (service->autoconnect != autoconnect) {
5957                 DBG("updated autoconnect flag (%d)", autoconnect);
5958                 service->autoconnect = autoconnect;
5959                 service_save(service);
5960         }
5961 }
5962 #endif
5963
5964 static void service_complete(struct connman_service *service)
5965 {
5966         reply_pending(service, EIO);
5967
5968         if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
5969                 __connman_service_auto_connect(service->connect_reason);
5970
5971         g_get_current_time(&service->modified);
5972         service_save(service);
5973 }
5974
5975 static void report_error_cb(void *user_context, bool retry,
5976                                                         void *user_data)
5977 {
5978         struct connman_service *service = user_context;
5979
5980         if (retry)
5981                 __connman_service_connect(service,
5982                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
5983         else {
5984                 /* It is not relevant to stay on Failure state
5985                  * when failing is due to wrong user input */
5986                 __connman_service_clear_error(service);
5987
5988                 service_complete(service);
5989                 __connman_connection_update_gateway();
5990         }
5991 }
5992
5993 static int check_wpspin(struct connman_service *service, const char *wpspin)
5994 {
5995         int length;
5996         guint i;
5997
5998         if (!wpspin)
5999                 return 0;
6000
6001         length = strlen(wpspin);
6002
6003         /* If 0, it will mean user wants to use PBC method */
6004         if (length == 0) {
6005                 connman_network_set_string(service->network,
6006                                                         "WiFi.PinWPS", NULL);
6007                 return 0;
6008         }
6009
6010         /* A WPS PIN is always 8 chars length,
6011          * its content is in digit representation.
6012          */
6013         if (length != 8)
6014                 return -ENOKEY;
6015
6016         for (i = 0; i < 8; i++)
6017                 if (!isdigit((unsigned char) wpspin[i]))
6018                         return -ENOKEY;
6019
6020         connman_network_set_string(service->network, "WiFi.PinWPS", wpspin);
6021
6022         return 0;
6023 }
6024
6025 #if defined TIZEN_EXT
6026 static int __connman_service_connect_hidden(struct connman_service *service,
6027                         const char *name, int name_len,
6028                         const char *identity, const char *passphrase, void *user_data)
6029 {
6030         GList *list;
6031
6032         for (list = service_list; list; list = list->next) {
6033                 struct connman_service *target = list->data;
6034                 const char *target_ssid = NULL;
6035                 unsigned int target_ssid_len = 0;
6036
6037                 if (service->network != NULL &&
6038                                         service->security == target->security) {
6039                         target_ssid = connman_network_get_blob(service->network,
6040                                                         "WiFi.SSID", &target_ssid_len);
6041                         if (target_ssid_len == name_len &&
6042                                                         memcmp(target_ssid, name, name_len) == 0) {
6043                                 return connman_network_connect_hidden(service->network,
6044                                                         (char *)identity, (char *)passphrase, user_data);
6045                         }
6046                 }
6047         }
6048
6049         return -ENOENT;
6050 }
6051 #endif
6052
6053 static void request_input_cb(struct connman_service *service,
6054                         bool values_received,
6055                         const char *name, int name_len,
6056                         const char *identity, const char *passphrase,
6057                         bool wps, const char *wpspin,
6058                         const char *error, void *user_data)
6059 {
6060         struct connman_device *device;
6061         const char *security;
6062         int err = 0;
6063
6064         DBG("RequestInput return, %p", service);
6065
6066         if (error) {
6067                 DBG("error: %s", error);
6068
6069                 if (g_strcmp0(error,
6070                                 "net.connman.Agent.Error.Canceled") == 0) {
6071                         err = -EINVAL;
6072
6073                         if (service->hidden)
6074                                 __connman_service_return_error(service,
6075                                                         ECANCELED, user_data);
6076                         goto done;
6077                 } else {
6078                         if (service->hidden)
6079                                 __connman_service_return_error(service,
6080                                                         ETIMEDOUT, user_data);
6081                 }
6082         }
6083
6084         if (service->hidden && name_len > 0 && name_len <= 32) {
6085 #if defined TIZEN_EXT
6086                 /* TIZEN already has Wi-Fi hidden scan before this hidden connection */
6087                 err = __connman_service_connect_hidden(service, name, name_len,
6088                                                 identity, passphrase, user_data);
6089                 if (err == 0 || err == -EALREADY || err == -EINPROGRESS)
6090                         return;
6091 #endif
6092
6093                 device = connman_network_get_device(service->network);
6094                 security = connman_network_get_string(service->network,
6095                                                         "WiFi.Security");
6096                 err = __connman_device_request_hidden_scan(device,
6097                                                 name, name_len,
6098                                                 identity, passphrase,
6099                                                 security, user_data);
6100                 if (err < 0)
6101                         __connman_service_return_error(service, -err,
6102                                                         user_data);
6103         }
6104
6105         if (!values_received || service->hidden) {
6106                 err = -EINVAL;
6107                 goto done;
6108         }
6109
6110         if (wps && service->network) {
6111                 err = check_wpspin(service, wpspin);
6112                 if (err < 0)
6113                         goto done;
6114
6115                 connman_network_set_bool(service->network, "WiFi.UseWPS", wps);
6116         }
6117
6118         if (identity)
6119                 __connman_service_set_agent_identity(service, identity);
6120
6121         if (passphrase)
6122                 err = __connman_service_set_passphrase(service, passphrase);
6123
6124  done:
6125         if (err >= 0) {
6126                 /* We forget any previous error. */
6127                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6128
6129                 __connman_service_connect(service,
6130                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6131
6132         } else if (err == -ENOKEY) {
6133                 __connman_service_indicate_error(service,
6134                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
6135         } else {
6136                 /* It is not relevant to stay on Failure state
6137                  * when failing is due to wrong user input */
6138                 service->state = CONNMAN_SERVICE_STATE_IDLE;
6139
6140                 if (!service->hidden) {
6141                         /*
6142                          * If there was a real error when requesting
6143                          * hidden scan, then that error is returned already
6144                          * to the user somewhere above so do not try to
6145                          * do this again.
6146                          */
6147                         __connman_service_return_error(service, -err,
6148                                                         user_data);
6149                 }
6150
6151                 service_complete(service);
6152                 __connman_connection_update_gateway();
6153         }
6154 }
6155
6156 static void downgrade_connected_services(void)
6157 {
6158         struct connman_service *up_service;
6159         GList *list;
6160
6161         for (list = service_list; list; list = list->next) {
6162                 up_service = list->data;
6163
6164                 if (!is_connected(up_service))
6165                         continue;
6166
6167                 if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
6168                         return;
6169
6170                 downgrade_state(up_service);
6171         }
6172 }
6173
6174 static int service_update_preferred_order(struct connman_service *default_service,
6175                 struct connman_service *new_service,
6176                 enum connman_service_state new_state)
6177 {
6178         unsigned int *tech_array;
6179         int i;
6180
6181         if (!default_service || default_service == new_service ||
6182                         default_service->state != new_state)
6183                 return 0;
6184
6185         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
6186         if (tech_array) {
6187
6188                 for (i = 0; tech_array[i] != 0; i += 1) {
6189                         if (default_service->type == tech_array[i])
6190                                 return -EALREADY;
6191
6192                         if (new_service->type == tech_array[i]) {
6193                                 switch_default_service(default_service,
6194                                                 new_service);
6195                                 __connman_connection_update_gateway();
6196                                 return 0;
6197                         }
6198                 }
6199         }
6200
6201         return -EALREADY;
6202 }
6203
6204 #if defined TIZEN_EXT
6205 static gboolean __connman_service_can_drop(struct connman_service *service)
6206 {
6207         if (is_connected(service) == TRUE || is_connecting(service) == TRUE) {
6208                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
6209                         return TRUE;
6210                 else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE)
6211                         return TRUE;
6212         }
6213         return FALSE;
6214 }
6215
6216 static struct connman_device *default_connecting_device = NULL;
6217
6218 static void __connman_service_disconnect_default(struct connman_service *service)
6219 {
6220         struct connman_device *default_device = NULL;
6221
6222         if (default_connecting_device == NULL)
6223                 return;
6224
6225         default_device = connman_network_get_device(
6226                         __connman_service_get_network(service));
6227
6228         DBG("Disconnecting service %p %s", service, service->path);
6229         DBG("Disconnecting device %p %p %s",
6230                         default_connecting_device,
6231                         default_device,
6232                         connman_device_get_string(default_device, "Name"));
6233
6234         if (default_connecting_device == default_device)
6235                 default_connecting_device = NULL;
6236 }
6237
6238 static void __connman_service_connect_default(struct connman_service *current)
6239 {
6240         int err;
6241         GList *list;
6242         bool default_internet;
6243         struct connman_service *service;
6244         struct connman_service *default_service = NULL;
6245         struct connman_device *default_device = NULL;
6246
6247         if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
6248                 switch (current->state) {
6249                 case CONNMAN_SERVICE_STATE_UNKNOWN:
6250                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
6251                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
6252                         return;
6253                 default:
6254                         break;
6255                 }
6256
6257                 if (default_connecting_device &&
6258                                 __connman_service_is_internet_profile(current) == TRUE) {
6259                         if (current->network == NULL)
6260                                 return;
6261
6262                         default_device = connman_network_get_device(current->network);
6263                         if (default_connecting_device == default_device) {
6264                                 DBG("Cellular service[%s]  %p %s",
6265                                                 state2string(current->state), current, current->path);
6266                                 DBG("Cellular device %p %p %s",
6267                                                 default_connecting_device, default_device,
6268                                                 connman_device_get_string(default_device, "Name"));
6269
6270                                 default_connecting_device = NULL;
6271                         }
6272                 }
6273
6274                 return;
6275         } else if (is_connected(current) == TRUE || is_connecting(current) == TRUE)
6276                 return;
6277
6278         /* Always-on: keep default cellular connection as possible */
6279         for (list = service_list; list; list = list->next) {
6280                 service = list->data;
6281
6282                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6283                                 __connman_service_is_internet_profile(service) != TRUE ||
6284                                 service->network == NULL) {
6285                         continue;
6286                 }
6287
6288                 default_internet =
6289                                 connman_network_get_bool(service->network, "DefaultInternet");
6290
6291                 DBG("service: %p %s %s %s (default: %d)", service, service->name,
6292                                 __connman_service_type2string(service->type),
6293                                 state2string(service->state), default_internet);
6294
6295                 if (default_internet) {
6296                         default_service = service;
6297                         if (is_connected(default_service) == TRUE ||
6298                                         is_connecting(default_service) == TRUE)
6299                                 return;
6300
6301                         default_device = connman_network_get_device(default_service->network);
6302                         if (default_connecting_device == default_device) {
6303                                 DBG("Device is connecting (%p)", default_connecting_device);
6304                                 return;
6305                         }
6306
6307                         default_connecting_device = default_device;
6308                         default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
6309
6310                         err = __connman_network_connect(default_service->network);
6311                         DBG("Connecting default service %p %s [%d]",
6312                                         default_service, default_service->path, err);
6313                         DBG("Connecting device %p %s", default_connecting_device,
6314                                         connman_device_get_string(default_connecting_device, "Name"));
6315                         if (err < 0 && err != -EINPROGRESS) {
6316                                 default_connecting_device = NULL;
6317                         } else
6318                                 break;
6319                 }
6320         }
6321 }
6322 #endif
6323
6324 static void single_connected_tech(struct connman_service *allowed)
6325 {
6326         struct connman_service *service;
6327         GSList *services = NULL, *list;
6328         GList *iter;
6329
6330         DBG("keeping %p %s", allowed, allowed->path);
6331
6332 #if defined TIZEN_EXT
6333         if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6334                 return;
6335 #endif
6336
6337         for (iter = service_list; iter; iter = iter->next) {
6338                 service = iter->data;
6339
6340 #if defined TIZEN_EXT
6341                 if (service != allowed && service->type != allowed->type &&
6342                                 __connman_service_can_drop(service) == TRUE)
6343 #else
6344                 if (!is_connected(service))
6345                         break;
6346
6347                 if (service == allowed)
6348                         continue;
6349 #endif
6350                 services = g_slist_prepend(services, service);
6351         }
6352
6353         for (list = services; list; list = list->next) {
6354                 service = list->data;
6355
6356                 DBG("disconnecting %p %s", service, service->path);
6357 #if defined TIZEN_EXT
6358                 __connman_service_disconnect_default(service);
6359 #endif
6360                 __connman_service_disconnect(service);
6361         }
6362
6363         g_slist_free(services);
6364 }
6365
6366 #if defined TIZEN_EXT
6367 static void set_priority_connected_service(void)
6368 {
6369         struct connman_service *service;
6370         GList *list;
6371
6372         for (list = service_list; list; list = list->next) {
6373                 service = list->data;
6374
6375                 if (is_connected(service) == FALSE)
6376                         service->order = 5;
6377                 else
6378                         service->order = 6;
6379         }
6380 }
6381 #endif
6382
6383 static const char *get_dbus_sender(struct connman_service *service)
6384 {
6385         if (!service->pending)
6386                 return NULL;
6387
6388         return dbus_message_get_sender(service->pending);
6389 }
6390
6391 static int service_indicate_state(struct connman_service *service)
6392 {
6393         enum connman_service_state old_state, new_state;
6394         struct connman_service *def_service;
6395         enum connman_ipconfig_method method;
6396         int result;
6397
6398         if (!service)
6399                 return -EINVAL;
6400
6401         old_state = service->state;
6402         new_state = combine_state(service->state_ipv4, service->state_ipv6);
6403
6404         DBG("service %p old %s - new %s/%s => %s",
6405                                         service,
6406                                         state2string(old_state),
6407                                         state2string(service->state_ipv4),
6408                                         state2string(service->state_ipv6),
6409                                         state2string(new_state));
6410
6411         if (old_state == new_state)
6412                 return -EALREADY;
6413
6414         def_service = __connman_service_get_default();
6415
6416         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
6417                 result = service_update_preferred_order(def_service,
6418                                 service, new_state);
6419                 if (result == -EALREADY)
6420                         return result;
6421         }
6422
6423         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
6424                 __connman_notifier_leave_online(service->type);
6425
6426         if (is_connected_state(service, old_state) &&
6427                         !is_connected_state(service, new_state))
6428                 searchdomain_remove_all(service);
6429
6430         service->state = new_state;
6431         state_changed(service);
6432
6433         switch(new_state) {
6434         case CONNMAN_SERVICE_STATE_UNKNOWN:
6435
6436                 break;
6437
6438         case CONNMAN_SERVICE_STATE_IDLE:
6439                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
6440                         __connman_service_disconnect(service);
6441
6442                 break;
6443
6444         case CONNMAN_SERVICE_STATE_ASSOCIATION:
6445
6446                 break;
6447
6448         case CONNMAN_SERVICE_STATE_CONFIGURATION:
6449                 if (!service->new_service &&
6450                                 __connman_stats_service_register(service) == 0) {
6451                         /*
6452                          * For new services the statistics are updated after
6453                          * we have successfully connected.
6454                          */
6455                         __connman_stats_get(service, false,
6456                                                 &service->stats.data);
6457                         __connman_stats_get(service, true,
6458                                                 &service->stats_roaming.data);
6459                 }
6460
6461                 break;
6462
6463         case CONNMAN_SERVICE_STATE_READY:
6464                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6465
6466                 if (service->new_service &&
6467                                 __connman_stats_service_register(service) == 0) {
6468                         /*
6469                          * This is normally done after configuring state
6470                          * but for new service do this after we have connected
6471                          * successfully.
6472                          */
6473                         __connman_stats_get(service, false,
6474                                                 &service->stats.data);
6475                         __connman_stats_get(service, true,
6476                                                 &service->stats_roaming.data);
6477                 }
6478
6479                 service->new_service = false;
6480
6481                 default_changed();
6482
6483                 def_service = __connman_service_get_default();
6484
6485                 service_update_preferred_order(def_service, service, new_state);
6486
6487                 __connman_service_set_favorite(service, true);
6488
6489                 reply_pending(service, 0);
6490
6491                 g_get_current_time(&service->modified);
6492                 service_save(service);
6493
6494                 searchdomain_add_all(service);
6495                 dns_changed(service);
6496                 domain_changed(service);
6497                 proxy_changed(service);
6498
6499                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
6500                         __connman_notifier_connect(service->type);
6501
6502                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
6503                         connman_network_get_bool(service->network,
6504                                                 "WiFi.UseWPS")) {
6505                         const char *pass;
6506
6507                         pass = connman_network_get_string(service->network,
6508                                                         "WiFi.Passphrase");
6509
6510                         __connman_service_set_passphrase(service, pass);
6511
6512                         connman_network_set_bool(service->network,
6513                                                         "WiFi.UseWPS", false);
6514                 }
6515
6516                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
6517                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
6518                         __connman_ipconfig_disable_ipv6(
6519                                                 service->ipconfig_ipv6);
6520
6521                 if (connman_setting_get_bool("SingleConnectedTechnology"))
6522                         single_connected_tech(service);
6523                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
6524                         vpn_auto_connect();
6525
6526 #if defined TIZEN_EXT
6527                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
6528                         set_priority_connected_service();
6529 #endif
6530
6531                 break;
6532
6533         case CONNMAN_SERVICE_STATE_ONLINE:
6534
6535                 break;
6536
6537         case CONNMAN_SERVICE_STATE_DISCONNECT:
6538                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6539
6540                 reply_pending(service, ECONNABORTED);
6541
6542                 def_service = __connman_service_get_default();
6543
6544                 if (!__connman_notifier_is_connected() &&
6545                         def_service &&
6546                                 def_service->provider)
6547                         connman_provider_disconnect(def_service->provider);
6548
6549                 default_changed();
6550
6551                 __connman_wispr_stop(service);
6552
6553                 __connman_wpad_stop(service);
6554
6555 #if defined TIZEN_EXT
6556                 /**
6557                   * Skip the functions if there is any connected profiles
6558                   * that use same interface
6559                   */
6560                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6561                         __connman_service_get_connected_count_of_iface(
6562                                                         service) <= 0) {
6563 #endif
6564                 dns_changed(service);
6565                 domain_changed(service);
6566                 proxy_changed(service);
6567 #if defined TIZEN_EXT
6568                 }
6569 #endif
6570
6571                 /*
6572                  * Previous services which are connected and which states
6573                  * are set to online should reset relevantly ipconfig_state
6574                  * to ready so wispr/portal will be rerun on those
6575                  */
6576                 downgrade_connected_services();
6577
6578                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
6579                 break;
6580
6581         case CONNMAN_SERVICE_STATE_FAILURE:
6582 #if defined TIZEN_EXT
6583                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
6584                         service->order = 5;
6585 #endif
6586                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
6587                         connman_agent_report_error(service, service->path,
6588                                         error2string(service->error),
6589                                         report_error_cb,
6590                                         get_dbus_sender(service),
6591                                         NULL) == -EINPROGRESS)
6592                         return 0;
6593                 service_complete(service);
6594
6595                 break;
6596         }
6597
6598         service_list_sort();
6599
6600 #if defined TIZEN_EXT
6601         __connman_service_connect_default(service);
6602 #endif
6603
6604         __connman_connection_update_gateway();
6605
6606         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
6607                         new_state != CONNMAN_SERVICE_STATE_READY) ||
6608                 (old_state == CONNMAN_SERVICE_STATE_READY &&
6609                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
6610                 __connman_notifier_disconnect(service->type);
6611         }
6612
6613         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
6614                 __connman_notifier_enter_online(service->type);
6615                 default_changed();
6616         }
6617
6618         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
6619                 service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
6620                 (new_state == CONNMAN_SERVICE_STATE_READY ||
6621                 new_state == CONNMAN_SERVICE_STATE_ONLINE)) {
6622                 if (service->user.favorite_user != service->user.current_user) {
6623                         DBG("Now set service favorite user id from %d to %d",
6624                         service->user.favorite_user, service->user.current_user);
6625
6626                         service->user.favorite_user = service->user.current_user;
6627
6628                         service_save(service);
6629                 }
6630         }
6631
6632         return 0;
6633 }
6634
6635 int __connman_service_indicate_error(struct connman_service *service,
6636                                         enum connman_service_error error)
6637 {
6638         DBG("service %p error %d", service, error);
6639
6640         if (!service)
6641                 return -EINVAL;
6642
6643         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
6644                 return -EALREADY;
6645
6646         set_error(service, error);
6647
6648 /* default internet service: fix not cleared if pdp activation*/
6649 #if defined TIZEN_EXT
6650                 /*
6651                  * If connection failed for default service(DefaultInternet),
6652                  * default_connecting_device should be cleared.
6653                  */
6654                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
6655                                 service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED)
6656                         __connman_service_disconnect_default(service);
6657
6658 #endif
6659
6660         __connman_service_ipconfig_indicate_state(service,
6661                                                 CONNMAN_SERVICE_STATE_FAILURE,
6662                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
6663         __connman_service_ipconfig_indicate_state(service,
6664                                                 CONNMAN_SERVICE_STATE_FAILURE,
6665                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
6666         return 0;
6667 }
6668
6669 int __connman_service_clear_error(struct connman_service *service)
6670 {
6671         DBusMessage *pending, *provider_pending;
6672
6673         DBG("service %p", service);
6674
6675         if (!service)
6676                 return -EINVAL;
6677
6678         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
6679                 return -EINVAL;
6680
6681         pending = service->pending;
6682         service->pending = NULL;
6683         provider_pending = service->provider_pending;
6684         service->provider_pending = NULL;
6685
6686         __connman_service_ipconfig_indicate_state(service,
6687                                                 CONNMAN_SERVICE_STATE_IDLE,
6688                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
6689
6690         __connman_service_ipconfig_indicate_state(service,
6691                                                 CONNMAN_SERVICE_STATE_IDLE,
6692                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
6693
6694         service->pending = pending;
6695         service->provider_pending = provider_pending;
6696
6697         return 0;
6698 }
6699
6700 int __connman_service_indicate_default(struct connman_service *service)
6701 {
6702         DBG("service %p state %s", service, state2string(service->state));
6703
6704         if (!is_connected(service)) {
6705                 /*
6706                  * If service is not yet fully connected, then we must not
6707                  * change the default yet. The default gw will be changed
6708                  * after the service state is in ready.
6709                  */
6710                 return -EINPROGRESS;
6711         }
6712
6713         default_changed();
6714
6715         return 0;
6716 }
6717
6718 enum connman_service_state __connman_service_ipconfig_get_state(
6719                                         struct connman_service *service,
6720                                         enum connman_ipconfig_type type)
6721 {
6722         if (!service)
6723                 return CONNMAN_SERVICE_STATE_UNKNOWN;
6724
6725         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6726                 return service->state_ipv4;
6727
6728         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
6729                 return service->state_ipv6;
6730
6731         return CONNMAN_SERVICE_STATE_UNKNOWN;
6732 }
6733
6734 static void check_proxy_setup(struct connman_service *service)
6735 {
6736         /*
6737          * We start WPAD if we haven't got a PAC URL from DHCP and
6738          * if our proxy manual configuration is either empty or set
6739          * to AUTO with an empty URL.
6740          */
6741
6742         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
6743                 goto done;
6744
6745         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
6746                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
6747                         service->pac))
6748                 goto done;
6749
6750         if (__connman_wpad_start(service) < 0) {
6751                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
6752                 __connman_notifier_proxy_changed(service);
6753                 goto done;
6754         }
6755
6756         return;
6757
6758 done:
6759         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
6760 }
6761
6762 #if defined TIZEN_EXT
6763 void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
6764
6765         DBG("check the proxy and start wispr");
6766         check_proxy_setup(service);
6767         return;
6768 }
6769 #endif
6770
6771 /*
6772  * How many networks are connected at the same time. If more than 1,
6773  * then set the rp_filter setting properly (loose mode routing) so that network
6774  * connectivity works ok. This is only done for IPv4 networks as IPv6
6775  * does not have rp_filter knob.
6776  */
6777 static int connected_networks_count;
6778 static int original_rp_filter;
6779
6780 static void service_rp_filter(struct connman_service *service,
6781                                 bool connected)
6782 {
6783         enum connman_ipconfig_method method;
6784
6785         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
6786
6787         switch (method) {
6788         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
6789         case CONNMAN_IPCONFIG_METHOD_OFF:
6790         case CONNMAN_IPCONFIG_METHOD_AUTO:
6791                 return;
6792         case CONNMAN_IPCONFIG_METHOD_FIXED:
6793         case CONNMAN_IPCONFIG_METHOD_MANUAL:
6794         case CONNMAN_IPCONFIG_METHOD_DHCP:
6795                 break;
6796         }
6797
6798         if (connected) {
6799                 if (connected_networks_count == 1) {
6800                         int filter_value;
6801                         filter_value = __connman_ipconfig_set_rp_filter();
6802                         if (filter_value < 0)
6803                                 return;
6804
6805                         original_rp_filter = filter_value;
6806                 }
6807                 connected_networks_count++;
6808
6809         } else {
6810                 if (connected_networks_count == 2)
6811                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
6812
6813                 connected_networks_count--;
6814                 if (connected_networks_count < 0)
6815                         connected_networks_count = 0;
6816         }
6817
6818         DBG("%s %s ipconfig %p method %d count %d filter %d",
6819                 connected ? "connected" : "disconnected", service->identifier,
6820                 service->ipconfig_ipv4, method,
6821                 connected_networks_count, original_rp_filter);
6822 }
6823
6824 static gboolean redo_wispr(gpointer user_data)
6825 {
6826         struct connman_service *service = user_data;
6827         int refcount = service->refcount - 1;
6828
6829         connman_service_unref(service);
6830         if (refcount == 0) {
6831                 DBG("Service %p already removed", service);
6832                 return FALSE;
6833         }
6834
6835         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
6836
6837         return FALSE;
6838 }
6839
6840 int __connman_service_online_check_failed(struct connman_service *service,
6841                                         enum connman_ipconfig_type type)
6842 {
6843         DBG("service %p type %d count %d", service, type,
6844                                                 service->online_check_count);
6845
6846         /* currently we only retry IPv6 stuff */
6847         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
6848                         service->online_check_count != 1) {
6849                 connman_warn("Online check failed for %p %s", service,
6850                         service->name);
6851                 return 0;
6852         }
6853
6854         service->online_check_count = 0;
6855
6856         /*
6857          * We set the timeout to 1 sec so that we have a chance to get
6858          * necessary IPv6 router advertisement messages that might have
6859          * DNS data etc.
6860          */
6861         g_timeout_add_seconds(1, redo_wispr, connman_service_ref(service));
6862
6863         return EAGAIN;
6864 }
6865
6866 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
6867                                         enum connman_service_state new_state,
6868                                         enum connman_ipconfig_type type)
6869 {
6870         struct connman_ipconfig *ipconfig = NULL;
6871         enum connman_service_state old_state;
6872         enum connman_ipconfig_method method;
6873
6874         if (!service)
6875                 return -EINVAL;
6876
6877         switch (type) {
6878         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
6879         case CONNMAN_IPCONFIG_TYPE_ALL:
6880                 return -EINVAL;
6881
6882         case CONNMAN_IPCONFIG_TYPE_IPV4:
6883                 old_state = service->state_ipv4;
6884                 ipconfig = service->ipconfig_ipv4;
6885
6886                 break;
6887
6888         case CONNMAN_IPCONFIG_TYPE_IPV6:
6889                 old_state = service->state_ipv6;
6890                 ipconfig = service->ipconfig_ipv6;
6891
6892                 break;
6893         }
6894
6895         if (!ipconfig)
6896                 return -EINVAL;
6897
6898         /* Any change? */
6899         if (old_state == new_state)
6900                 return -EALREADY;
6901
6902 #if defined TIZEN_EXT
6903         __sync_synchronize();
6904         if (service->user_pdn_connection_refcount > 0 &&
6905                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6906                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
6907                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
6908                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
6909                         service->user_pdn_connection_refcount = 0;
6910                         __sync_synchronize();
6911                 }
6912 #endif
6913
6914         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
6915                 service, service ? service->identifier : NULL,
6916                 old_state, state2string(old_state),
6917                 new_state, state2string(new_state),
6918                 type, __connman_ipconfig_type2string(type));
6919
6920         switch (new_state) {
6921         case CONNMAN_SERVICE_STATE_UNKNOWN:
6922         case CONNMAN_SERVICE_STATE_IDLE:
6923         case CONNMAN_SERVICE_STATE_ASSOCIATION:
6924                 break;
6925         case CONNMAN_SERVICE_STATE_CONFIGURATION:
6926                 __connman_ipconfig_enable(ipconfig);
6927                 break;
6928         case CONNMAN_SERVICE_STATE_READY:
6929 #if defined TIZEN_EXT
6930                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
6931                                 __connman_service_is_internet_profile(service) != TRUE) {
6932                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6933                                 service_rp_filter(service, TRUE);
6934
6935                         break;
6936                 }
6937 #endif
6938                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
6939 #if !defined TIZEN_EXT
6940                         check_proxy_setup(service);
6941 #endif
6942                         service_rp_filter(service, true);
6943                 } else {
6944                         service->online_check_count = 1;
6945                         __connman_wispr_start(service, type);
6946                 }
6947                 break;
6948         case CONNMAN_SERVICE_STATE_ONLINE:
6949                 break;
6950         case CONNMAN_SERVICE_STATE_DISCONNECT:
6951                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
6952                         return -EINVAL;
6953
6954                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6955                         service_rp_filter(service, false);
6956
6957                 break;
6958         case CONNMAN_SERVICE_STATE_FAILURE:
6959                 break;
6960         }
6961
6962         /* Keep that state, but if the ipconfig method is OFF, then we set
6963            the state to IDLE so that it will not affect the combined state
6964            in the future.
6965          */
6966         method = __connman_ipconfig_get_method(ipconfig);
6967         switch (method) {
6968         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
6969         case CONNMAN_IPCONFIG_METHOD_OFF:
6970                 new_state = CONNMAN_SERVICE_STATE_IDLE;
6971                 break;
6972
6973         case CONNMAN_IPCONFIG_METHOD_FIXED:
6974         case CONNMAN_IPCONFIG_METHOD_MANUAL:
6975         case CONNMAN_IPCONFIG_METHOD_DHCP:
6976         case CONNMAN_IPCONFIG_METHOD_AUTO:
6977                 break;
6978
6979         }
6980
6981         if (is_connected_state(service, old_state) &&
6982                         !is_connected_state(service, new_state))
6983                 nameserver_remove_all(service);
6984
6985         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6986                 service->state_ipv4 = new_state;
6987         else
6988                 service->state_ipv6 = new_state;
6989
6990         if (!is_connected_state(service, old_state) &&
6991                         is_connected_state(service, new_state))
6992                 nameserver_add_all(service);
6993
6994 #if defined TIZEN_EXT
6995         int ret = service_indicate_state(service);
6996         /*Sent the Ready changed signal again in case IPv4 IP set
6997           after IPv6 IP set*/
6998
6999         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
7000                         && new_state == CONNMAN_SERVICE_STATE_READY) {
7001                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
7002                 state_changed(service);
7003         }
7004
7005         return ret;
7006 #endif
7007         return service_indicate_state(service);
7008 }
7009
7010 static bool prepare_network(struct connman_service *service)
7011 {
7012         enum connman_network_type type;
7013         unsigned int ssid_len;
7014
7015         type = connman_network_get_type(service->network);
7016
7017         switch (type) {
7018         case CONNMAN_NETWORK_TYPE_UNKNOWN:
7019         case CONNMAN_NETWORK_TYPE_VENDOR:
7020                 return false;
7021         case CONNMAN_NETWORK_TYPE_WIFI:
7022                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
7023                                                 &ssid_len))
7024                         return false;
7025
7026                 if (service->passphrase)
7027                         connman_network_set_string(service->network,
7028                                 "WiFi.Passphrase", service->passphrase);
7029                 break;
7030         case CONNMAN_NETWORK_TYPE_ETHERNET:
7031         case CONNMAN_NETWORK_TYPE_GADGET:
7032         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
7033         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
7034         case CONNMAN_NETWORK_TYPE_CELLULAR:
7035                 break;
7036         }
7037
7038         return true;
7039 }
7040
7041 static void prepare_8021x(struct connman_service *service)
7042 {
7043         if (service->eap)
7044                 connman_network_set_string(service->network, "WiFi.EAP",
7045                                                                 service->eap);
7046
7047         if (service->identity)
7048                 connman_network_set_string(service->network, "WiFi.Identity",
7049                                                         service->identity);
7050
7051         if (service->ca_cert_file)
7052                 connman_network_set_string(service->network, "WiFi.CACertFile",
7053                                                         service->ca_cert_file);
7054
7055         if (service->client_cert_file)
7056                 connman_network_set_string(service->network,
7057                                                 "WiFi.ClientCertFile",
7058                                                 service->client_cert_file);
7059
7060         if (service->private_key_file)
7061                 connman_network_set_string(service->network,
7062                                                 "WiFi.PrivateKeyFile",
7063                                                 service->private_key_file);
7064
7065         if (service->private_key_passphrase)
7066                 connman_network_set_string(service->network,
7067                                         "WiFi.PrivateKeyPassphrase",
7068                                         service->private_key_passphrase);
7069
7070         if (service->phase2)
7071                 connman_network_set_string(service->network, "WiFi.Phase2",
7072                                                         service->phase2);
7073 }
7074
7075 static int service_connect(struct connman_service *service)
7076 {
7077         int err;
7078
7079         if (service->hidden)
7080                 return -EPERM;
7081
7082         switch (service->type) {
7083         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7084         case CONNMAN_SERVICE_TYPE_SYSTEM:
7085         case CONNMAN_SERVICE_TYPE_GPS:
7086         case CONNMAN_SERVICE_TYPE_P2P:
7087                 return -EINVAL;
7088         case CONNMAN_SERVICE_TYPE_ETHERNET:
7089         case CONNMAN_SERVICE_TYPE_GADGET:
7090         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7091         case CONNMAN_SERVICE_TYPE_CELLULAR:
7092         case CONNMAN_SERVICE_TYPE_VPN:
7093                 break;
7094         case CONNMAN_SERVICE_TYPE_WIFI:
7095                 switch (service->security) {
7096                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7097                 case CONNMAN_SERVICE_SECURITY_NONE:
7098                         break;
7099                 case CONNMAN_SERVICE_SECURITY_WEP:
7100                 case CONNMAN_SERVICE_SECURITY_PSK:
7101                 case CONNMAN_SERVICE_SECURITY_WPA:
7102                 case CONNMAN_SERVICE_SECURITY_RSN:
7103                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7104                                 return -ENOKEY;
7105
7106                         if (service->request_passphrase_input) {
7107                                 DBG("Now try to connect other user's favorite service");
7108                                 service->request_passphrase_input = false;
7109                                 return -ENOKEY;
7110                         } else if (!service->passphrase) {
7111                                 if (!service->network)
7112                                         return -EOPNOTSUPP;
7113
7114                                 if (!service->wps ||
7115                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
7116                                         return -ENOKEY;
7117                         }
7118                         break;
7119
7120                 case CONNMAN_SERVICE_SECURITY_8021X:
7121                         if (!service->eap)
7122                                 return -EINVAL;
7123
7124 #if defined TIZEN_EXT
7125                         /*
7126                          * never request credentials if using EAP-TLS, EAP-SIM
7127                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
7128                          * need to be fully provisioned)
7129                          */
7130                         if (g_str_equal(service->eap, "tls") ||
7131                                 g_str_equal(service->eap, "sim") ||
7132                                 g_str_equal(service->eap, "aka"))
7133                                 break;
7134 #else
7135                         /*
7136                          * never request credentials if using EAP-TLS
7137                          * (EAP-TLS networks need to be fully provisioned)
7138                          */
7139                         if (g_str_equal(service->eap, "tls"))
7140                                 break;
7141 #endif
7142                         /*
7143                          * Return -ENOKEY if either identity or passphrase is
7144                          * missing. Agent provided credentials can be used as
7145                          * fallback if needed.
7146                          */
7147                         if (((!service->identity &&
7148                                         !service->agent_identity) ||
7149                                         !service->passphrase) ||
7150                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7151                                 return -ENOKEY;
7152
7153                         break;
7154                 }
7155                 break;
7156         }
7157
7158         if (service->network) {
7159                 if (!prepare_network(service))
7160                         return -EINVAL;
7161
7162                 switch (service->security) {
7163                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7164                 case CONNMAN_SERVICE_SECURITY_NONE:
7165                 case CONNMAN_SERVICE_SECURITY_WEP:
7166                 case CONNMAN_SERVICE_SECURITY_PSK:
7167                 case CONNMAN_SERVICE_SECURITY_WPA:
7168                 case CONNMAN_SERVICE_SECURITY_RSN:
7169                         break;
7170                 case CONNMAN_SERVICE_SECURITY_8021X:
7171                         prepare_8021x(service);
7172                         break;
7173                 }
7174
7175                 if (__connman_stats_service_register(service) == 0) {
7176                         __connman_stats_get(service, false,
7177                                                 &service->stats.data);
7178                         __connman_stats_get(service, true,
7179                                                 &service->stats_roaming.data);
7180                 }
7181
7182                 if (service->ipconfig_ipv4)
7183                         __connman_ipconfig_enable(service->ipconfig_ipv4);
7184                 if (service->ipconfig_ipv6)
7185                         __connman_ipconfig_enable(service->ipconfig_ipv6);
7186
7187                 err = __connman_network_connect(service->network);
7188         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7189                                         service->provider)
7190                 err = __connman_provider_connect(service->provider);
7191         else
7192                 return -EOPNOTSUPP;
7193
7194         if (err < 0) {
7195                 if (err != -EINPROGRESS) {
7196                         __connman_ipconfig_disable(service->ipconfig_ipv4);
7197                         __connman_ipconfig_disable(service->ipconfig_ipv6);
7198                         __connman_stats_service_unregister(service);
7199                 }
7200         }
7201
7202         return err;
7203 }
7204
7205 int __connman_service_connect(struct connman_service *service,
7206                         enum connman_service_connect_reason reason)
7207 {
7208         int err;
7209
7210         DBG("service %p state %s connect reason %s -> %s",
7211                 service, state2string(service->state),
7212                 reason2string(service->connect_reason),
7213                 reason2string(reason));
7214
7215         if (is_connected(service))
7216                 return -EISCONN;
7217
7218         if (is_connecting(service))
7219                 return -EALREADY;
7220
7221         switch (service->type) {
7222         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7223         case CONNMAN_SERVICE_TYPE_SYSTEM:
7224         case CONNMAN_SERVICE_TYPE_GPS:
7225         case CONNMAN_SERVICE_TYPE_P2P:
7226                 return -EINVAL;
7227
7228         case CONNMAN_SERVICE_TYPE_ETHERNET:
7229         case CONNMAN_SERVICE_TYPE_GADGET:
7230         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7231         case CONNMAN_SERVICE_TYPE_CELLULAR:
7232         case CONNMAN_SERVICE_TYPE_VPN:
7233         case CONNMAN_SERVICE_TYPE_WIFI:
7234                 break;
7235         }
7236
7237         if (!is_ipconfig_usable(service))
7238                 return -ENOLINK;
7239
7240         __connman_service_clear_error(service);
7241
7242         err = service_connect(service);
7243
7244         service->connect_reason = reason;
7245         if (err >= 0)
7246                 return 0;
7247
7248         if (err == -EINPROGRESS) {
7249                 if (service->timeout == 0)
7250                         service->timeout = g_timeout_add_seconds(
7251                                 CONNECT_TIMEOUT, connect_timeout, service);
7252
7253                 return -EINPROGRESS;
7254         }
7255
7256         if (service->network)
7257                 __connman_network_disconnect(service->network);
7258         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7259                                 service->provider)
7260                         connman_provider_disconnect(service->provider);
7261
7262         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
7263                 if (err == -ENOKEY || err == -EPERM) {
7264                         DBusMessage *pending = NULL;
7265
7266                         /*
7267                          * We steal the reply here. The idea is that the
7268                          * connecting client will see the connection status
7269                          * after the real hidden network is connected or
7270                          * connection failed.
7271                          */
7272                         if (service->hidden) {
7273                                 pending = service->pending;
7274                                 service->pending = NULL;
7275                         }
7276
7277                         err = __connman_agent_request_passphrase_input(service,
7278                                         request_input_cb,
7279                                         get_dbus_sender(service),
7280                                         pending);
7281                         if (service->hidden && err != -EINPROGRESS)
7282                                 service->pending = pending;
7283
7284                         return err;
7285                 }
7286                 reply_pending(service, -err);
7287         }
7288
7289         return err;
7290 }
7291
7292 int __connman_service_disconnect(struct connman_service *service)
7293 {
7294         int err;
7295
7296         DBG("service %p", service);
7297
7298         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
7299         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
7300
7301         connman_agent_cancel(service);
7302
7303         reply_pending(service, ECONNABORTED);
7304
7305         if (service->network) {
7306                 err = __connman_network_disconnect(service->network);
7307         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7308                                         service->provider)
7309                 err = connman_provider_disconnect(service->provider);
7310         else
7311                 return -EOPNOTSUPP;
7312
7313         if (err < 0 && err != -EINPROGRESS)
7314                 return err;
7315
7316         __connman_6to4_remove(service->ipconfig_ipv4);
7317
7318         if (service->ipconfig_ipv4)
7319                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
7320                                                         NULL);
7321         else
7322                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
7323                                                         NULL);
7324
7325 #if defined TIZEN_EXT
7326         /**
7327           * Skip the functions If there is any connected profiles
7328           * that use same interface
7329           */
7330         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7331                 __connman_service_get_connected_count_of_iface(service) <= 0) {
7332 #endif
7333         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
7334         settings_changed(service, service->ipconfig_ipv4);
7335
7336         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
7337         settings_changed(service, service->ipconfig_ipv6);
7338
7339         __connman_ipconfig_disable(service->ipconfig_ipv4);
7340         __connman_ipconfig_disable(service->ipconfig_ipv6);
7341 #if defined TIZEN_EXT
7342         }
7343 #endif
7344
7345         __connman_stats_service_unregister(service);
7346
7347         return err;
7348 }
7349
7350 int __connman_service_disconnect_all(void)
7351 {
7352         struct connman_service *service;
7353         GSList *services = NULL, *list;
7354         GList *iter;
7355
7356         DBG("");
7357
7358         for (iter = service_list; iter; iter = iter->next) {
7359                 service = iter->data;
7360
7361                 if (!is_connected(service))
7362                         break;
7363
7364                 services = g_slist_prepend(services, service);
7365         }
7366
7367         for (list = services; list; list = list->next) {
7368                 struct connman_service *service = list->data;
7369
7370                 service->ignore = true;
7371
7372                 __connman_service_disconnect(service);
7373         }
7374
7375         g_slist_free(services);
7376
7377         return 0;
7378 }
7379
7380 /**
7381  * lookup_by_identifier:
7382  * @identifier: service identifier
7383  *
7384  * Look up a service by identifier (reference count will not be increased)
7385  */
7386 static struct connman_service *lookup_by_identifier(const char *identifier)
7387 {
7388         return g_hash_table_lookup(service_hash, identifier);
7389 }
7390
7391 struct provision_user_data {
7392         const char *ident;
7393         int ret;
7394 };
7395
7396 static void provision_changed(gpointer value, gpointer user_data)
7397 {
7398         struct connman_service *service = value;
7399         struct provision_user_data *data = user_data;
7400         const char *path = data->ident;
7401         int ret;
7402
7403         ret = __connman_config_provision_service_ident(service, path,
7404                         service->config_file, service->config_entry);
7405         if (ret > 0)
7406                 data->ret = ret;
7407 }
7408
7409 int __connman_service_provision_changed(const char *ident)
7410 {
7411         struct provision_user_data data = {
7412                 .ident = ident,
7413                 .ret = 0
7414         };
7415
7416         g_list_foreach(service_list, provision_changed, (void *)&data);
7417
7418         /*
7419          * Because the provision_changed() might have set some services
7420          * as favorite, we must sort the sequence now.
7421          */
7422         if (services_dirty) {
7423                 services_dirty = false;
7424
7425                 service_list_sort();
7426
7427                 __connman_connection_update_gateway();
7428         }
7429
7430         return data.ret;
7431 }
7432
7433 void __connman_service_set_config(struct connman_service *service,
7434                                 const char *file_id, const char *entry)
7435 {
7436         if (!service)
7437                 return;
7438
7439         g_free(service->config_file);
7440         service->config_file = g_strdup(file_id);
7441
7442         g_free(service->config_entry);
7443         service->config_entry = g_strdup(entry);
7444 }
7445
7446 /**
7447  * __connman_service_get:
7448  * @identifier: service identifier
7449  *
7450  * Look up a service by identifier or create a new one if not found
7451  */
7452 static struct connman_service *service_get(const char *identifier)
7453 {
7454         struct connman_service *service;
7455
7456         service = g_hash_table_lookup(service_hash, identifier);
7457         if (service) {
7458                 connman_service_ref(service);
7459                 return service;
7460         }
7461
7462         service = connman_service_create();
7463         if (!service)
7464                 return NULL;
7465
7466         DBG("service %p", service);
7467
7468         service->identifier = g_strdup(identifier);
7469
7470         service_list = g_list_insert_sorted(service_list, service,
7471                                                 service_compare);
7472
7473         g_hash_table_insert(service_hash, service->identifier, service);
7474
7475         return service;
7476 }
7477
7478 static int service_register(struct connman_service *service)
7479 {
7480         DBG("service %p", service);
7481
7482         if (service->path)
7483                 return -EALREADY;
7484
7485         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
7486                                                 service->identifier);
7487
7488         DBG("path %s", service->path);
7489
7490         if (__connman_config_provision_service(service) < 0)
7491                 service_load(service);
7492
7493         g_dbus_register_interface(connection, service->path,
7494                                         CONNMAN_SERVICE_INTERFACE,
7495                                         service_methods, service_signals,
7496                                                         NULL, service, NULL);
7497
7498         service_list_sort();
7499
7500         __connman_connection_update_gateway();
7501
7502         return 0;
7503 }
7504
7505 static void service_up(struct connman_ipconfig *ipconfig,
7506                 const char *ifname)
7507 {
7508         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7509
7510         DBG("%s up", ifname);
7511
7512         link_changed(service);
7513
7514         service->stats.valid = false;
7515         service->stats_roaming.valid = false;
7516 }
7517
7518 static void service_down(struct connman_ipconfig *ipconfig,
7519                         const char *ifname)
7520 {
7521         DBG("%s down", ifname);
7522 }
7523
7524 static void service_lower_up(struct connman_ipconfig *ipconfig,
7525                         const char *ifname)
7526 {
7527         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7528
7529         DBG("%s lower up", ifname);
7530
7531         stats_start(service);
7532 }
7533
7534 static void service_lower_down(struct connman_ipconfig *ipconfig,
7535                         const char *ifname)
7536 {
7537         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7538
7539         DBG("%s lower down", ifname);
7540
7541         if (!is_idle_state(service, service->state_ipv4))
7542                 __connman_ipconfig_disable(service->ipconfig_ipv4);
7543
7544         if (!is_idle_state(service, service->state_ipv6))
7545                 __connman_ipconfig_disable(service->ipconfig_ipv6);
7546
7547         stats_stop(service);
7548         service_save(service);
7549 }
7550
7551 static void service_ip_bound(struct connman_ipconfig *ipconfig,
7552                         const char *ifname)
7553 {
7554         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7555         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
7556         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
7557
7558         DBG("%s ip bound", ifname);
7559
7560         type = __connman_ipconfig_get_config_type(ipconfig);
7561         method = __connman_ipconfig_get_method(ipconfig);
7562
7563         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
7564                                                         type, method);
7565
7566         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
7567                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
7568                 __connman_service_ipconfig_indicate_state(service,
7569                                                 CONNMAN_SERVICE_STATE_READY,
7570                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7571
7572         settings_changed(service, ipconfig);
7573 }
7574
7575 static void service_ip_release(struct connman_ipconfig *ipconfig,
7576                         const char *ifname)
7577 {
7578         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7579         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
7580         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
7581
7582         DBG("%s ip release", ifname);
7583
7584         type = __connman_ipconfig_get_config_type(ipconfig);
7585         method = __connman_ipconfig_get_method(ipconfig);
7586
7587         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
7588                                                         type, method);
7589
7590         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
7591                         method == CONNMAN_IPCONFIG_METHOD_OFF)
7592                 __connman_service_ipconfig_indicate_state(service,
7593                                         CONNMAN_SERVICE_STATE_DISCONNECT,
7594                                         CONNMAN_IPCONFIG_TYPE_IPV6);
7595
7596         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
7597                         method == CONNMAN_IPCONFIG_METHOD_OFF)
7598                 __connman_service_ipconfig_indicate_state(service,
7599                                         CONNMAN_SERVICE_STATE_DISCONNECT,
7600                                         CONNMAN_IPCONFIG_TYPE_IPV4);
7601
7602         settings_changed(service, ipconfig);
7603 }
7604
7605 static void service_route_changed(struct connman_ipconfig *ipconfig,
7606                                 const char *ifname)
7607 {
7608         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7609
7610         DBG("%s route changed", ifname);
7611
7612         settings_changed(service, ipconfig);
7613 }
7614
7615 static const struct connman_ipconfig_ops service_ops = {
7616         .up             = service_up,
7617         .down           = service_down,
7618         .lower_up       = service_lower_up,
7619         .lower_down     = service_lower_down,
7620         .ip_bound       = service_ip_bound,
7621         .ip_release     = service_ip_release,
7622         .route_set      = service_route_changed,
7623         .route_unset    = service_route_changed,
7624 };
7625
7626 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
7627                 int index, enum connman_ipconfig_method method)
7628 {
7629         struct connman_ipconfig *ipconfig_ipv4;
7630
7631         ipconfig_ipv4 = __connman_ipconfig_create(index,
7632                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7633         if (!ipconfig_ipv4)
7634                 return NULL;
7635
7636         __connman_ipconfig_set_method(ipconfig_ipv4, method);
7637
7638         __connman_ipconfig_set_data(ipconfig_ipv4, service);
7639
7640         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
7641
7642         return ipconfig_ipv4;
7643 }
7644
7645 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
7646                 int index)
7647 {
7648         struct connman_ipconfig *ipconfig_ipv6;
7649
7650         ipconfig_ipv6 = __connman_ipconfig_create(index,
7651                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7652         if (!ipconfig_ipv6)
7653                 return NULL;
7654
7655         __connman_ipconfig_set_data(ipconfig_ipv6, service);
7656
7657         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
7658
7659         return ipconfig_ipv6;
7660 }
7661
7662 void __connman_service_read_ip4config(struct connman_service *service)
7663 {
7664         GKeyFile *keyfile;
7665
7666         if (!service->ipconfig_ipv4)
7667                 return;
7668
7669         keyfile = connman_storage_load_service(service->identifier);
7670         if (!keyfile)
7671                 return;
7672
7673         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
7674                                 service->identifier, "IPv4.");
7675
7676         g_key_file_free(keyfile);
7677 }
7678
7679 void connman_service_create_ip4config(struct connman_service *service,
7680                                         int index)
7681 {
7682         DBG("ipv4 %p", service->ipconfig_ipv4);
7683
7684         if (service->ipconfig_ipv4)
7685                 return;
7686
7687         service->ipconfig_ipv4 = create_ip4config(service, index,
7688                         CONNMAN_IPCONFIG_METHOD_DHCP);
7689         __connman_service_read_ip4config(service);
7690 }
7691
7692 void __connman_service_read_ip6config(struct connman_service *service)
7693 {
7694         GKeyFile *keyfile;
7695
7696         if (!service->ipconfig_ipv6)
7697                 return;
7698
7699         keyfile = connman_storage_load_service(service->identifier);
7700         if (!keyfile)
7701                 return;
7702
7703         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
7704                                 service->identifier, "IPv6.");
7705
7706         g_key_file_free(keyfile);
7707 }
7708
7709 void connman_service_create_ip6config(struct connman_service *service,
7710                                                                 int index)
7711 {
7712         DBG("ipv6 %p", service->ipconfig_ipv6);
7713
7714         if (service->ipconfig_ipv6)
7715                 return;
7716
7717         service->ipconfig_ipv6 = create_ip6config(service, index);
7718
7719         __connman_service_read_ip6config(service);
7720 }
7721
7722 /**
7723  * connman_service_lookup_from_network:
7724  * @network: network structure
7725  *
7726  * Look up a service by network (reference count will not be increased)
7727  */
7728 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
7729 {
7730         struct connman_service *service;
7731         const char *ident, *group;
7732         char *name;
7733
7734         if (!network)
7735                 return NULL;
7736
7737         ident = __connman_network_get_ident(network);
7738         if (!ident)
7739                 return NULL;
7740
7741         group = connman_network_get_group(network);
7742         if (!group)
7743                 return NULL;
7744
7745         name = g_strdup_printf("%s_%s_%s",
7746                         __connman_network_get_type(network), ident, group);
7747         service = lookup_by_identifier(name);
7748         g_free(name);
7749
7750         return service;
7751 }
7752
7753 struct connman_service *__connman_service_lookup_from_index(int index)
7754 {
7755         struct connman_service *service;
7756         GList *list;
7757
7758         for (list = service_list; list; list = list->next) {
7759                 service = list->data;
7760
7761                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
7762                                                         == index)
7763                         return service;
7764
7765                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
7766                                                         == index)
7767                         return service;
7768         }
7769
7770         return NULL;
7771 }
7772
7773 struct connman_service *__connman_service_lookup_from_ident(const char *identifier)
7774 {
7775         return lookup_by_identifier(identifier);
7776 }
7777
7778 const char *__connman_service_get_ident(struct connman_service *service)
7779 {
7780         return service->identifier;
7781 }
7782
7783 const char *__connman_service_get_path(struct connman_service *service)
7784 {
7785         return service->path;
7786 }
7787
7788 const char *__connman_service_get_name(struct connman_service *service)
7789 {
7790         return service->name;
7791 }
7792
7793 enum connman_service_state __connman_service_get_state(struct connman_service *service)
7794 {
7795         return service->state;
7796 }
7797
7798 unsigned int __connman_service_get_order(struct connman_service *service)
7799 {
7800         unsigned int order = 0;
7801
7802         if (!service)
7803                 return 0;
7804
7805         service->order = 0;
7806
7807         if (!service->favorite)
7808                 return 0;
7809
7810 #if defined TIZEN_EXT
7811         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7812                         service->do_split_routing == FALSE)
7813                 order = 10;
7814         else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
7815                 if (service->order < 5)
7816                         order = 5;
7817         } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
7818                 order = 4;
7819         else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
7820                 order = 3;
7821         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7822                         __connman_service_is_internet_profile(service) == TRUE)
7823                 order = 1;
7824         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7825                         __connman_service_is_tethering_profile(service) == TRUE)
7826                 order = 0;
7827         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7828                 order = 0;
7829         else
7830                 order = 2;
7831 #else
7832         if (service == service_list->data)
7833                 order = 1;
7834
7835         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7836                         !service->do_split_routing) {
7837                 service->order = 10;
7838                 order = 10;
7839         }
7840 #endif
7841         DBG("service %p name %s order %d split %d", service, service->name,
7842                 order, service->do_split_routing);
7843
7844         return order;
7845 }
7846
7847 void __connman_service_update_ordering(void)
7848 {
7849         if (service_list && service_list->next)
7850                 service_list = g_list_sort(service_list, service_compare);
7851 }
7852
7853 static enum connman_service_type convert_network_type(struct connman_network *network)
7854 {
7855         enum connman_network_type type = connman_network_get_type(network);
7856
7857         switch (type) {
7858         case CONNMAN_NETWORK_TYPE_UNKNOWN:
7859         case CONNMAN_NETWORK_TYPE_VENDOR:
7860                 break;
7861         case CONNMAN_NETWORK_TYPE_ETHERNET:
7862                 return CONNMAN_SERVICE_TYPE_ETHERNET;
7863         case CONNMAN_NETWORK_TYPE_WIFI:
7864                 return CONNMAN_SERVICE_TYPE_WIFI;
7865         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
7866         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
7867                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
7868         case CONNMAN_NETWORK_TYPE_CELLULAR:
7869                 return CONNMAN_SERVICE_TYPE_CELLULAR;
7870         case CONNMAN_NETWORK_TYPE_GADGET:
7871                 return CONNMAN_SERVICE_TYPE_GADGET;
7872         }
7873
7874         return CONNMAN_SERVICE_TYPE_UNKNOWN;
7875 }
7876
7877 static enum connman_service_security convert_wifi_security(const char *security)
7878 {
7879         if (!security)
7880                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
7881         else if (g_str_equal(security, "none"))
7882                 return CONNMAN_SERVICE_SECURITY_NONE;
7883         else if (g_str_equal(security, "wep"))
7884                 return CONNMAN_SERVICE_SECURITY_WEP;
7885         else if (g_str_equal(security, "psk"))
7886                 return CONNMAN_SERVICE_SECURITY_PSK;
7887         else if (g_str_equal(security, "ieee8021x"))
7888                 return CONNMAN_SERVICE_SECURITY_8021X;
7889         else if (g_str_equal(security, "wpa"))
7890                 return CONNMAN_SERVICE_SECURITY_WPA;
7891         else if (g_str_equal(security, "rsn"))
7892                 return CONNMAN_SERVICE_SECURITY_RSN;
7893 #if defined TIZEN_EXT
7894         else if (g_str_equal(security, "ft_psk") == TRUE)
7895                 return CONNMAN_SERVICE_SECURITY_PSK;
7896         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
7897                 return CONNMAN_SERVICE_SECURITY_8021X;
7898 #endif
7899         else
7900                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
7901 }
7902
7903 static void update_from_network(struct connman_service *service,
7904                                         struct connman_network *network)
7905 {
7906         uint8_t strength = service->strength;
7907         const char *str;
7908
7909         DBG("service %p network %p", service, network);
7910
7911         if (is_connected(service))
7912                 return;
7913
7914         if (is_connecting(service))
7915                 return;
7916
7917         str = connman_network_get_string(network, "Name");
7918         if (str) {
7919                 g_free(service->name);
7920                 service->name = g_strdup(str);
7921                 service->hidden = false;
7922         } else {
7923                 g_free(service->name);
7924                 service->name = NULL;
7925                 service->hidden = true;
7926         }
7927
7928         service->strength = connman_network_get_strength(network);
7929         service->roaming = connman_network_get_bool(network, "Roaming");
7930
7931         if (service->strength == 0) {
7932                 /*
7933                  * Filter out 0-values; it's unclear what they mean
7934                  * and they cause anomalous sorting of the priority list.
7935                  */
7936                 service->strength = strength;
7937         }
7938
7939         str = connman_network_get_string(network, "WiFi.Security");
7940         service->security = convert_wifi_security(str);
7941
7942         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7943                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
7944
7945         if (service->strength > strength && service->network) {
7946                 connman_network_unref(service->network);
7947                 service->network = connman_network_ref(network);
7948
7949                 strength_changed(service);
7950         }
7951
7952         if (!service->network)
7953                 service->network = connman_network_ref(network);
7954
7955         service_list_sort();
7956 }
7957
7958 /**
7959  * __connman_service_create_from_network:
7960  * @network: network structure
7961  *
7962  * Look up service by network and if not found, create one
7963  */
7964 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
7965 {
7966         struct connman_service *service;
7967         struct connman_device *device;
7968         const char *ident, *group;
7969         char *name;
7970         unsigned int *auto_connect_types;
7971         int i, index;
7972
7973         DBG("network %p", network);
7974
7975         if (!network)
7976                 return NULL;
7977
7978         ident = __connman_network_get_ident(network);
7979         if (!ident)
7980                 return NULL;
7981
7982         group = connman_network_get_group(network);
7983         if (!group)
7984                 return NULL;
7985
7986         name = g_strdup_printf("%s_%s_%s",
7987                         __connman_network_get_type(network), ident, group);
7988         service = service_get(name);
7989         g_free(name);
7990
7991         if (!service)
7992                 return NULL;
7993
7994         if (__connman_network_get_weakness(network))
7995                 return service;
7996
7997         if (service->path) {
7998                 update_from_network(service, network);
7999                 __connman_connection_update_gateway();
8000                 return service;
8001         }
8002
8003         service->type = convert_network_type(network);
8004
8005         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
8006         service->autoconnect = false;
8007         for (i = 0; auto_connect_types &&
8008                      auto_connect_types[i] != 0; i++) {
8009                 if (service->type == auto_connect_types[i]) {
8010                         service->autoconnect = true;
8011                         break;
8012                 }
8013         }
8014
8015         switch (service->type) {
8016         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8017         case CONNMAN_SERVICE_TYPE_SYSTEM:
8018         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8019         case CONNMAN_SERVICE_TYPE_GPS:
8020         case CONNMAN_SERVICE_TYPE_VPN:
8021         case CONNMAN_SERVICE_TYPE_GADGET:
8022         case CONNMAN_SERVICE_TYPE_WIFI:
8023         case CONNMAN_SERVICE_TYPE_CELLULAR:
8024         case CONNMAN_SERVICE_TYPE_P2P:
8025                 break;
8026         case CONNMAN_SERVICE_TYPE_ETHERNET:
8027                 service->favorite = true;
8028                 break;
8029         }
8030
8031         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8032         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8033
8034         update_from_network(service, network);
8035
8036         index = connman_network_get_index(network);
8037
8038         if (!service->ipconfig_ipv4)
8039                 service->ipconfig_ipv4 = create_ip4config(service, index,
8040                                 CONNMAN_IPCONFIG_METHOD_DHCP);
8041
8042         if (!service->ipconfig_ipv6)
8043                 service->ipconfig_ipv6 = create_ip6config(service, index);
8044
8045         service_register(service);
8046
8047         if (service->favorite) {
8048                 device = connman_network_get_device(service->network);
8049                 if (device && !connman_device_get_scanning(device)) {
8050
8051                         switch (service->type) {
8052                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8053                         case CONNMAN_SERVICE_TYPE_SYSTEM:
8054                         case CONNMAN_SERVICE_TYPE_P2P:
8055                                 break;
8056
8057                         case CONNMAN_SERVICE_TYPE_GADGET:
8058                         case CONNMAN_SERVICE_TYPE_ETHERNET:
8059                                 if (service->autoconnect) {
8060                                         __connman_service_connect(service,
8061                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8062                                         break;
8063                                 }
8064
8065                                 /* fall through */
8066                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8067                         case CONNMAN_SERVICE_TYPE_GPS:
8068                         case CONNMAN_SERVICE_TYPE_VPN:
8069                         case CONNMAN_SERVICE_TYPE_WIFI:
8070                         case CONNMAN_SERVICE_TYPE_CELLULAR:
8071                                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8072                                 break;
8073                         }
8074                 }
8075
8076 #if defined TIZEN_EXT
8077                 /* TIZEN synchronizes below information when the service creates */
8078                 if (service->eap != NULL)
8079                         connman_network_set_string(service->network, "WiFi.EAP",
8080                                                                 service->eap);
8081                 if (service->identity != NULL)
8082                         connman_network_set_string(service->network, "WiFi.Identity",
8083                                                                 service->identity);
8084                 if (service->phase2 != NULL)
8085                         connman_network_set_string(service->network, "WiFi.Phase2",
8086                                                                 service->phase2);
8087 #endif
8088         }
8089
8090         __connman_notifier_service_add(service, service->name);
8091         service_schedule_added(service);
8092
8093         return service;
8094 }
8095
8096 void __connman_service_update_from_network(struct connman_network *network)
8097 {
8098         bool need_sort = false;
8099         struct connman_service *service;
8100         uint8_t strength;
8101         bool roaming;
8102         const char *name;
8103         bool stats_enable;
8104
8105         service = connman_service_lookup_from_network(network);
8106         if (!service)
8107                 return;
8108
8109         if (!service->network)
8110                 return;
8111
8112 #if defined TIZEN_EXT
8113         if (service->storage_reload) {
8114                 service_load(service);
8115                 __connman_service_set_storage_reload(service, false);
8116         }
8117 #endif
8118
8119         name = connman_network_get_string(service->network, "Name");
8120         if (g_strcmp0(service->name, name) != 0) {
8121                 g_free(service->name);
8122                 service->name = g_strdup(name);
8123
8124                 if (allow_property_changed(service))
8125                         connman_dbus_property_changed_basic(service->path,
8126                                         CONNMAN_SERVICE_INTERFACE, "Name",
8127                                         DBUS_TYPE_STRING, &service->name);
8128         }
8129
8130         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8131                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
8132
8133         strength = connman_network_get_strength(service->network);
8134         if (strength == service->strength)
8135                 goto roaming;
8136
8137         service->strength = strength;
8138         need_sort = true;
8139
8140         strength_changed(service);
8141
8142 roaming:
8143         roaming = connman_network_get_bool(service->network, "Roaming");
8144         if (roaming == service->roaming)
8145                 goto sorting;
8146
8147         stats_enable = stats_enabled(service);
8148         if (stats_enable)
8149                 stats_stop(service);
8150
8151         service->roaming = roaming;
8152         need_sort = true;
8153
8154         if (stats_enable)
8155                 stats_start(service);
8156
8157         roaming_changed(service);
8158
8159 sorting:
8160         if (need_sort) {
8161                 service_list_sort();
8162         }
8163 }
8164
8165 void __connman_service_remove_from_network(struct connman_network *network)
8166 {
8167         struct connman_service *service;
8168
8169         service = connman_service_lookup_from_network(network);
8170
8171         DBG("network %p service %p", network, service);
8172
8173         if (!service)
8174                 return;
8175
8176         service->ignore = true;
8177
8178         __connman_connection_gateway_remove(service,
8179                                         CONNMAN_IPCONFIG_TYPE_ALL);
8180
8181         connman_service_unref(service);
8182 }
8183
8184 /**
8185  * __connman_service_create_from_provider:
8186  * @provider: provider structure
8187  *
8188  * Look up service by provider and if not found, create one
8189  */
8190 struct connman_service *
8191 __connman_service_create_from_provider(struct connman_provider *provider)
8192 {
8193         struct connman_service *service;
8194         const char *ident, *str;
8195         char *name;
8196         int index = connman_provider_get_index(provider);
8197
8198         DBG("provider %p", provider);
8199
8200         ident = __connman_provider_get_ident(provider);
8201         if (!ident)
8202                 return NULL;
8203
8204         name = g_strdup_printf("vpn_%s", ident);
8205         service = service_get(name);
8206         g_free(name);
8207
8208         if (!service)
8209                 return NULL;
8210
8211         service->type = CONNMAN_SERVICE_TYPE_VPN;
8212         service->provider = connman_provider_ref(provider);
8213         service->autoconnect = false;
8214         service->favorite = true;
8215
8216         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8217         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8218
8219         str = connman_provider_get_string(provider, "Name");
8220         if (str) {
8221                 g_free(service->name);
8222                 service->name = g_strdup(str);
8223                 service->hidden = false;
8224         } else {
8225                 g_free(service->name);
8226                 service->name = NULL;
8227                 service->hidden = true;
8228         }
8229
8230         service->strength = 0;
8231
8232         if (!service->ipconfig_ipv4)
8233                 service->ipconfig_ipv4 = create_ip4config(service, index,
8234                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
8235
8236         if (!service->ipconfig_ipv6)
8237                 service->ipconfig_ipv6 = create_ip6config(service, index);
8238
8239         service_register(service);
8240
8241         __connman_notifier_service_add(service, service->name);
8242         service_schedule_added(service);
8243
8244         return service;
8245 }
8246
8247 static void remove_unprovisioned_services(void)
8248 {
8249         gchar **services;
8250         GKeyFile *keyfile, *configkeyfile;
8251         char *file, *section;
8252         int i = 0;
8253
8254         services = connman_storage_get_services();
8255         if (!services)
8256                 return;
8257
8258         for (; services[i]; i++) {
8259                 file = section = NULL;
8260                 keyfile = configkeyfile = NULL;
8261
8262                 keyfile = connman_storage_load_service(services[i]);
8263                 if (!keyfile)
8264                         continue;
8265
8266                 file = g_key_file_get_string(keyfile, services[i],
8267                                         "Config.file", NULL);
8268                 if (!file)
8269                         goto next;
8270
8271                 section = g_key_file_get_string(keyfile, services[i],
8272                                         "Config.ident", NULL);
8273                 if (!section)
8274                         goto next;
8275
8276                 configkeyfile = __connman_storage_load_config(file);
8277                 if (!configkeyfile) {
8278                         /*
8279                          * Config file is missing, remove the provisioned
8280                          * service.
8281                          */
8282                         __connman_storage_remove_service(services[i]);
8283                         goto next;
8284                 }
8285
8286                 if (!g_key_file_has_group(configkeyfile, section))
8287                         /*
8288                          * Config section is missing, remove the provisioned
8289                          * service.
8290                          */
8291                         __connman_storage_remove_service(services[i]);
8292
8293         next:
8294                 if (keyfile)
8295                         g_key_file_free(keyfile);
8296
8297                 if (configkeyfile)
8298                         g_key_file_free(configkeyfile);
8299
8300                 g_free(section);
8301                 g_free(file);
8302         }
8303
8304         g_strfreev(services);
8305 }
8306
8307 static int agent_probe(struct connman_agent *agent)
8308 {
8309         DBG("agent %p", agent);
8310         return 0;
8311 }
8312
8313 static void agent_remove(struct connman_agent *agent)
8314 {
8315         DBG("agent %p", agent);
8316 }
8317
8318 static void *agent_context_ref(void *context)
8319 {
8320         struct connman_service *service = context;
8321
8322         return (void *)connman_service_ref(service);
8323 }
8324
8325 static void agent_context_unref(void *context)
8326 {
8327         struct connman_service *service = context;
8328
8329         connman_service_unref(service);
8330 }
8331
8332 static struct connman_agent_driver agent_driver = {
8333         .name           = "service",
8334         .interface      = CONNMAN_AGENT_INTERFACE,
8335         .probe          = agent_probe,
8336         .remove         = agent_remove,
8337         .context_ref    = agent_context_ref,
8338         .context_unref  = agent_context_unref,
8339 };
8340
8341 int __connman_service_init(void)
8342 {
8343         int err;
8344
8345         DBG("");
8346
8347         err = connman_agent_driver_register(&agent_driver);
8348         if (err < 0) {
8349                 connman_error("Cannot register agent driver for %s",
8350                                                 agent_driver.name);
8351                 return err;
8352         }
8353
8354         connection = connman_dbus_get_connection();
8355
8356         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
8357                                                         NULL, service_free);
8358
8359         services_notify = g_new0(struct _services_notify, 1);
8360         services_notify->remove = g_hash_table_new_full(g_str_hash,
8361                         g_str_equal, g_free, NULL);
8362         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
8363
8364         remove_unprovisioned_services();
8365
8366         return 0;
8367 }
8368
8369 void __connman_service_cleanup(void)
8370 {
8371         DBG("");
8372
8373         if (vpn_autoconnect_timeout) {
8374                 g_source_remove(vpn_autoconnect_timeout);
8375                 vpn_autoconnect_timeout = 0;
8376         }
8377
8378         if (autoconnect_timeout != 0) {
8379                 g_source_remove(autoconnect_timeout);
8380                 autoconnect_timeout = 0;
8381         }
8382
8383         connman_agent_driver_unregister(&agent_driver);
8384
8385         g_list_free(service_list);
8386         service_list = NULL;
8387
8388         g_hash_table_destroy(service_hash);
8389         service_hash = NULL;
8390
8391         g_slist_free(counter_list);
8392         counter_list = NULL;
8393
8394         if (services_notify->id != 0) {
8395                 g_source_remove(services_notify->id);
8396                 service_send_changed(NULL);
8397                 g_hash_table_destroy(services_notify->remove);
8398                 g_hash_table_destroy(services_notify->add);
8399         }
8400         g_free(services_notify);
8401
8402         dbus_connection_unref(connection);
8403 }