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