[SPIN] wifi: enable to reload service profile from storage.
[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 static const char *get_dbus_sender(struct connman_service *service)
6324 {
6325         if (!service->pending)
6326                 return NULL;
6327
6328         return dbus_message_get_sender(service->pending);
6329 }
6330
6331 static int service_indicate_state(struct connman_service *service)
6332 {
6333         enum connman_service_state old_state, new_state;
6334         struct connman_service *def_service;
6335         enum connman_ipconfig_method method;
6336         int result;
6337
6338         if (!service)
6339                 return -EINVAL;
6340
6341         old_state = service->state;
6342         new_state = combine_state(service->state_ipv4, service->state_ipv6);
6343
6344         DBG("service %p old %s - new %s/%s => %s",
6345                                         service,
6346                                         state2string(old_state),
6347                                         state2string(service->state_ipv4),
6348                                         state2string(service->state_ipv6),
6349                                         state2string(new_state));
6350
6351         if (old_state == new_state)
6352                 return -EALREADY;
6353
6354         def_service = __connman_service_get_default();
6355
6356         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
6357                 result = service_update_preferred_order(def_service,
6358                                 service, new_state);
6359                 if (result == -EALREADY)
6360                         return result;
6361         }
6362
6363         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
6364                 __connman_notifier_leave_online(service->type);
6365
6366         if (is_connected_state(service, old_state) &&
6367                         !is_connected_state(service, new_state))
6368                 searchdomain_remove_all(service);
6369
6370         service->state = new_state;
6371         state_changed(service);
6372
6373         switch(new_state) {
6374         case CONNMAN_SERVICE_STATE_UNKNOWN:
6375
6376                 break;
6377
6378         case CONNMAN_SERVICE_STATE_IDLE:
6379                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
6380                         __connman_service_disconnect(service);
6381
6382                 break;
6383
6384         case CONNMAN_SERVICE_STATE_ASSOCIATION:
6385
6386                 break;
6387
6388         case CONNMAN_SERVICE_STATE_CONFIGURATION:
6389                 if (!service->new_service &&
6390                                 __connman_stats_service_register(service) == 0) {
6391                         /*
6392                          * For new services the statistics are updated after
6393                          * we have successfully connected.
6394                          */
6395                         __connman_stats_get(service, false,
6396                                                 &service->stats.data);
6397                         __connman_stats_get(service, true,
6398                                                 &service->stats_roaming.data);
6399                 }
6400
6401                 break;
6402
6403         case CONNMAN_SERVICE_STATE_READY:
6404                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6405
6406                 if (service->new_service &&
6407                                 __connman_stats_service_register(service) == 0) {
6408                         /*
6409                          * This is normally done after configuring state
6410                          * but for new service do this after we have connected
6411                          * successfully.
6412                          */
6413                         __connman_stats_get(service, false,
6414                                                 &service->stats.data);
6415                         __connman_stats_get(service, true,
6416                                                 &service->stats_roaming.data);
6417                 }
6418
6419                 service->new_service = false;
6420
6421                 default_changed();
6422
6423                 def_service = __connman_service_get_default();
6424
6425                 service_update_preferred_order(def_service, service, new_state);
6426
6427                 __connman_service_set_favorite(service, true);
6428
6429                 reply_pending(service, 0);
6430
6431                 g_get_current_time(&service->modified);
6432                 service_save(service);
6433
6434                 searchdomain_add_all(service);
6435                 dns_changed(service);
6436                 domain_changed(service);
6437                 proxy_changed(service);
6438
6439                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
6440                         __connman_notifier_connect(service->type);
6441
6442                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
6443                         connman_network_get_bool(service->network,
6444                                                 "WiFi.UseWPS")) {
6445                         const char *pass;
6446
6447                         pass = connman_network_get_string(service->network,
6448                                                         "WiFi.Passphrase");
6449
6450                         __connman_service_set_passphrase(service, pass);
6451
6452                         connman_network_set_bool(service->network,
6453                                                         "WiFi.UseWPS", false);
6454                 }
6455
6456                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
6457                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
6458                         __connman_ipconfig_disable_ipv6(
6459                                                 service->ipconfig_ipv6);
6460
6461                 if (connman_setting_get_bool("SingleConnectedTechnology"))
6462                         single_connected_tech(service);
6463                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
6464                         vpn_auto_connect();
6465
6466                 break;
6467
6468         case CONNMAN_SERVICE_STATE_ONLINE:
6469
6470                 break;
6471
6472         case CONNMAN_SERVICE_STATE_DISCONNECT:
6473                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6474
6475                 reply_pending(service, ECONNABORTED);
6476
6477                 def_service = __connman_service_get_default();
6478
6479                 if (!__connman_notifier_is_connected() &&
6480                         def_service &&
6481                                 def_service->provider)
6482                         connman_provider_disconnect(def_service->provider);
6483
6484                 default_changed();
6485
6486                 __connman_wispr_stop(service);
6487
6488                 __connman_wpad_stop(service);
6489
6490 #if defined TIZEN_EXT
6491                 /**
6492                   * Skip the functions if there is any connected profiles
6493                   * that use same interface
6494                   */
6495                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6496                         __connman_service_get_connected_count_of_iface(
6497                                                         service) <= 0) {
6498 #endif
6499                 dns_changed(service);
6500                 domain_changed(service);
6501                 proxy_changed(service);
6502 #if defined TIZEN_EXT
6503                 }
6504 #endif
6505
6506                 /*
6507                  * Previous services which are connected and which states
6508                  * are set to online should reset relevantly ipconfig_state
6509                  * to ready so wispr/portal will be rerun on those
6510                  */
6511                 downgrade_connected_services();
6512
6513                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
6514                 break;
6515
6516         case CONNMAN_SERVICE_STATE_FAILURE:
6517
6518                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
6519                         connman_agent_report_error(service, service->path,
6520                                         error2string(service->error),
6521                                         report_error_cb,
6522                                         get_dbus_sender(service),
6523                                         NULL) == -EINPROGRESS)
6524                         return 0;
6525                 service_complete(service);
6526
6527                 break;
6528         }
6529
6530         service_list_sort();
6531
6532 #if defined TIZEN_EXT
6533         __connman_service_connect_default(service);
6534 #endif
6535
6536         __connman_connection_update_gateway();
6537
6538         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
6539                         new_state != CONNMAN_SERVICE_STATE_READY) ||
6540                 (old_state == CONNMAN_SERVICE_STATE_READY &&
6541                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
6542                 __connman_notifier_disconnect(service->type);
6543         }
6544
6545         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
6546                 __connman_notifier_enter_online(service->type);
6547                 default_changed();
6548         }
6549
6550         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
6551                 service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
6552                 (new_state == CONNMAN_SERVICE_STATE_READY ||
6553                 new_state == CONNMAN_SERVICE_STATE_ONLINE)) {
6554                 if (service->user.favorite_user != service->user.current_user) {
6555                         DBG("Now set service favorite user id from %d to %d",
6556                         service->user.favorite_user, service->user.current_user);
6557
6558                         service->user.favorite_user = service->user.current_user;
6559
6560                         service_save(service);
6561                 }
6562         }
6563
6564         return 0;
6565 }
6566
6567 int __connman_service_indicate_error(struct connman_service *service,
6568                                         enum connman_service_error error)
6569 {
6570         DBG("service %p error %d", service, error);
6571
6572         if (!service)
6573                 return -EINVAL;
6574
6575         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
6576                 return -EALREADY;
6577
6578         set_error(service, error);
6579
6580         __connman_service_ipconfig_indicate_state(service,
6581                                                 CONNMAN_SERVICE_STATE_FAILURE,
6582                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
6583         __connman_service_ipconfig_indicate_state(service,
6584                                                 CONNMAN_SERVICE_STATE_FAILURE,
6585                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
6586         return 0;
6587 }
6588
6589 int __connman_service_clear_error(struct connman_service *service)
6590 {
6591         DBusMessage *pending, *provider_pending;
6592
6593         DBG("service %p", service);
6594
6595         if (!service)
6596                 return -EINVAL;
6597
6598         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
6599                 return -EINVAL;
6600
6601         pending = service->pending;
6602         service->pending = NULL;
6603         provider_pending = service->provider_pending;
6604         service->provider_pending = NULL;
6605
6606         __connman_service_ipconfig_indicate_state(service,
6607                                                 CONNMAN_SERVICE_STATE_IDLE,
6608                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
6609
6610         __connman_service_ipconfig_indicate_state(service,
6611                                                 CONNMAN_SERVICE_STATE_IDLE,
6612                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
6613
6614         service->pending = pending;
6615         service->provider_pending = provider_pending;
6616
6617         return 0;
6618 }
6619
6620 int __connman_service_indicate_default(struct connman_service *service)
6621 {
6622         DBG("service %p state %s", service, state2string(service->state));
6623
6624         if (!is_connected(service)) {
6625                 /*
6626                  * If service is not yet fully connected, then we must not
6627                  * change the default yet. The default gw will be changed
6628                  * after the service state is in ready.
6629                  */
6630                 return -EINPROGRESS;
6631         }
6632
6633         default_changed();
6634
6635         return 0;
6636 }
6637
6638 enum connman_service_state __connman_service_ipconfig_get_state(
6639                                         struct connman_service *service,
6640                                         enum connman_ipconfig_type type)
6641 {
6642         if (!service)
6643                 return CONNMAN_SERVICE_STATE_UNKNOWN;
6644
6645         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6646                 return service->state_ipv4;
6647
6648         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
6649                 return service->state_ipv6;
6650
6651         return CONNMAN_SERVICE_STATE_UNKNOWN;
6652 }
6653
6654 static void check_proxy_setup(struct connman_service *service)
6655 {
6656         /*
6657          * We start WPAD if we haven't got a PAC URL from DHCP and
6658          * if our proxy manual configuration is either empty or set
6659          * to AUTO with an empty URL.
6660          */
6661
6662         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
6663                 goto done;
6664
6665         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
6666                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
6667                         service->pac))
6668                 goto done;
6669
6670         if (__connman_wpad_start(service) < 0) {
6671                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
6672                 __connman_notifier_proxy_changed(service);
6673                 goto done;
6674         }
6675
6676         return;
6677
6678 done:
6679         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
6680 }
6681
6682 /*
6683  * How many networks are connected at the same time. If more than 1,
6684  * then set the rp_filter setting properly (loose mode routing) so that network
6685  * connectivity works ok. This is only done for IPv4 networks as IPv6
6686  * does not have rp_filter knob.
6687  */
6688 static int connected_networks_count;
6689 static int original_rp_filter;
6690
6691 static void service_rp_filter(struct connman_service *service,
6692                                 bool connected)
6693 {
6694         enum connman_ipconfig_method method;
6695
6696         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
6697
6698         switch (method) {
6699         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
6700         case CONNMAN_IPCONFIG_METHOD_OFF:
6701         case CONNMAN_IPCONFIG_METHOD_AUTO:
6702                 return;
6703         case CONNMAN_IPCONFIG_METHOD_FIXED:
6704         case CONNMAN_IPCONFIG_METHOD_MANUAL:
6705         case CONNMAN_IPCONFIG_METHOD_DHCP:
6706                 break;
6707         }
6708
6709         if (connected) {
6710                 if (connected_networks_count == 1) {
6711                         int filter_value;
6712                         filter_value = __connman_ipconfig_set_rp_filter();
6713                         if (filter_value < 0)
6714                                 return;
6715
6716                         original_rp_filter = filter_value;
6717                 }
6718                 connected_networks_count++;
6719
6720         } else {
6721                 if (connected_networks_count == 2)
6722                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
6723
6724                 connected_networks_count--;
6725                 if (connected_networks_count < 0)
6726                         connected_networks_count = 0;
6727         }
6728
6729         DBG("%s %s ipconfig %p method %d count %d filter %d",
6730                 connected ? "connected" : "disconnected", service->identifier,
6731                 service->ipconfig_ipv4, method,
6732                 connected_networks_count, original_rp_filter);
6733 }
6734
6735 static gboolean redo_wispr(gpointer user_data)
6736 {
6737         struct connman_service *service = user_data;
6738         int refcount = service->refcount - 1;
6739
6740         connman_service_unref(service);
6741         if (refcount == 0) {
6742                 DBG("Service %p already removed", service);
6743                 return FALSE;
6744         }
6745
6746         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
6747
6748         return FALSE;
6749 }
6750
6751 int __connman_service_online_check_failed(struct connman_service *service,
6752                                         enum connman_ipconfig_type type)
6753 {
6754         DBG("service %p type %d count %d", service, type,
6755                                                 service->online_check_count);
6756
6757         /* currently we only retry IPv6 stuff */
6758         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
6759                         service->online_check_count != 1) {
6760                 connman_warn("Online check failed for %p %s", service,
6761                         service->name);
6762                 return 0;
6763         }
6764
6765         service->online_check_count = 0;
6766
6767         /*
6768          * We set the timeout to 1 sec so that we have a chance to get
6769          * necessary IPv6 router advertisement messages that might have
6770          * DNS data etc.
6771          */
6772         g_timeout_add_seconds(1, redo_wispr, connman_service_ref(service));
6773
6774         return EAGAIN;
6775 }
6776
6777 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
6778                                         enum connman_service_state new_state,
6779                                         enum connman_ipconfig_type type)
6780 {
6781         struct connman_ipconfig *ipconfig = NULL;
6782         enum connman_service_state old_state;
6783         enum connman_ipconfig_method method;
6784
6785         if (!service)
6786                 return -EINVAL;
6787
6788         switch (type) {
6789         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
6790         case CONNMAN_IPCONFIG_TYPE_ALL:
6791                 return -EINVAL;
6792
6793         case CONNMAN_IPCONFIG_TYPE_IPV4:
6794                 old_state = service->state_ipv4;
6795                 ipconfig = service->ipconfig_ipv4;
6796
6797                 break;
6798
6799         case CONNMAN_IPCONFIG_TYPE_IPV6:
6800                 old_state = service->state_ipv6;
6801                 ipconfig = service->ipconfig_ipv6;
6802
6803                 break;
6804         }
6805
6806         if (!ipconfig)
6807                 return -EINVAL;
6808
6809         /* Any change? */
6810         if (old_state == new_state)
6811                 return -EALREADY;
6812
6813 #if defined TIZEN_EXT
6814         __sync_synchronize();
6815         if (service->user_pdn_connection_refcount > 0 &&
6816                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6817                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
6818                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
6819                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
6820                         service->user_pdn_connection_refcount = 0;
6821                         __sync_synchronize();
6822                 }
6823 #endif
6824
6825         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
6826                 service, service ? service->identifier : NULL,
6827                 old_state, state2string(old_state),
6828                 new_state, state2string(new_state),
6829                 type, __connman_ipconfig_type2string(type));
6830
6831         switch (new_state) {
6832         case CONNMAN_SERVICE_STATE_UNKNOWN:
6833         case CONNMAN_SERVICE_STATE_IDLE:
6834         case CONNMAN_SERVICE_STATE_ASSOCIATION:
6835                 break;
6836         case CONNMAN_SERVICE_STATE_CONFIGURATION:
6837                 __connman_ipconfig_enable(ipconfig);
6838                 break;
6839         case CONNMAN_SERVICE_STATE_READY:
6840 #if defined TIZEN_EXT
6841                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
6842                                 __connman_service_is_internet_profile(service) != TRUE) {
6843                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6844                                 service_rp_filter(service, TRUE);
6845
6846                         break;
6847                 }
6848 #endif
6849                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
6850                         check_proxy_setup(service);
6851                         service_rp_filter(service, true);
6852                 } else {
6853                         service->online_check_count = 1;
6854                         __connman_wispr_start(service, type);
6855                 }
6856                 break;
6857         case CONNMAN_SERVICE_STATE_ONLINE:
6858                 break;
6859         case CONNMAN_SERVICE_STATE_DISCONNECT:
6860                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
6861                         return -EINVAL;
6862
6863                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6864                         service_rp_filter(service, false);
6865
6866                 break;
6867         case CONNMAN_SERVICE_STATE_FAILURE:
6868                 break;
6869         }
6870
6871         /* Keep that state, but if the ipconfig method is OFF, then we set
6872            the state to IDLE so that it will not affect the combined state
6873            in the future.
6874          */
6875         method = __connman_ipconfig_get_method(ipconfig);
6876         switch (method) {
6877         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
6878         case CONNMAN_IPCONFIG_METHOD_OFF:
6879                 new_state = CONNMAN_SERVICE_STATE_IDLE;
6880                 break;
6881
6882         case CONNMAN_IPCONFIG_METHOD_FIXED:
6883         case CONNMAN_IPCONFIG_METHOD_MANUAL:
6884         case CONNMAN_IPCONFIG_METHOD_DHCP:
6885         case CONNMAN_IPCONFIG_METHOD_AUTO:
6886                 break;
6887
6888         }
6889
6890         if (is_connected_state(service, old_state) &&
6891                         !is_connected_state(service, new_state))
6892                 nameserver_remove_all(service);
6893
6894         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6895                 service->state_ipv4 = new_state;
6896         else
6897                 service->state_ipv6 = new_state;
6898
6899         if (!is_connected_state(service, old_state) &&
6900                         is_connected_state(service, new_state))
6901                 nameserver_add_all(service);
6902
6903 #if defined TIZEN_EXT
6904         int ret = service_indicate_state(service);
6905         /*Sent the Ready changed signal again in case IPv4 IP set
6906           after IPv6 IP set*/
6907
6908         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
6909                         && new_state == CONNMAN_SERVICE_STATE_READY) {
6910                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
6911                 state_changed(service);
6912         }
6913
6914         return ret;
6915 #endif
6916         return service_indicate_state(service);
6917 }
6918
6919 static bool prepare_network(struct connman_service *service)
6920 {
6921         enum connman_network_type type;
6922         unsigned int ssid_len;
6923
6924         type = connman_network_get_type(service->network);
6925
6926         switch (type) {
6927         case CONNMAN_NETWORK_TYPE_UNKNOWN:
6928         case CONNMAN_NETWORK_TYPE_VENDOR:
6929                 return false;
6930         case CONNMAN_NETWORK_TYPE_WIFI:
6931                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
6932                                                 &ssid_len))
6933                         return false;
6934
6935                 if (service->passphrase)
6936                         connman_network_set_string(service->network,
6937                                 "WiFi.Passphrase", service->passphrase);
6938                 break;
6939         case CONNMAN_NETWORK_TYPE_ETHERNET:
6940         case CONNMAN_NETWORK_TYPE_GADGET:
6941         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
6942         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
6943         case CONNMAN_NETWORK_TYPE_CELLULAR:
6944                 break;
6945         }
6946
6947         return true;
6948 }
6949
6950 static void prepare_8021x(struct connman_service *service)
6951 {
6952         if (service->eap)
6953                 connman_network_set_string(service->network, "WiFi.EAP",
6954                                                                 service->eap);
6955
6956         if (service->identity)
6957                 connman_network_set_string(service->network, "WiFi.Identity",
6958                                                         service->identity);
6959
6960         if (service->ca_cert_file)
6961                 connman_network_set_string(service->network, "WiFi.CACertFile",
6962                                                         service->ca_cert_file);
6963
6964         if (service->client_cert_file)
6965                 connman_network_set_string(service->network,
6966                                                 "WiFi.ClientCertFile",
6967                                                 service->client_cert_file);
6968
6969         if (service->private_key_file)
6970                 connman_network_set_string(service->network,
6971                                                 "WiFi.PrivateKeyFile",
6972                                                 service->private_key_file);
6973
6974         if (service->private_key_passphrase)
6975                 connman_network_set_string(service->network,
6976                                         "WiFi.PrivateKeyPassphrase",
6977                                         service->private_key_passphrase);
6978
6979         if (service->phase2)
6980                 connman_network_set_string(service->network, "WiFi.Phase2",
6981                                                         service->phase2);
6982 }
6983
6984 static int service_connect(struct connman_service *service)
6985 {
6986         int err;
6987
6988         if (service->hidden)
6989                 return -EPERM;
6990
6991         switch (service->type) {
6992         case CONNMAN_SERVICE_TYPE_UNKNOWN:
6993         case CONNMAN_SERVICE_TYPE_SYSTEM:
6994         case CONNMAN_SERVICE_TYPE_GPS:
6995         case CONNMAN_SERVICE_TYPE_P2P:
6996                 return -EINVAL;
6997         case CONNMAN_SERVICE_TYPE_ETHERNET:
6998         case CONNMAN_SERVICE_TYPE_GADGET:
6999         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7000         case CONNMAN_SERVICE_TYPE_CELLULAR:
7001         case CONNMAN_SERVICE_TYPE_VPN:
7002                 break;
7003         case CONNMAN_SERVICE_TYPE_WIFI:
7004                 switch (service->security) {
7005                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7006                 case CONNMAN_SERVICE_SECURITY_NONE:
7007                         break;
7008                 case CONNMAN_SERVICE_SECURITY_WEP:
7009                 case CONNMAN_SERVICE_SECURITY_PSK:
7010                 case CONNMAN_SERVICE_SECURITY_WPA:
7011                 case CONNMAN_SERVICE_SECURITY_RSN:
7012                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7013                                 return -ENOKEY;
7014
7015                         if (service->request_passphrase_input) {
7016                                 DBG("Now try to connect other user's favorite service");
7017                                 service->request_passphrase_input = false;
7018                                 return -ENOKEY;
7019                         } else if (!service->passphrase) {
7020                                 if (!service->network)
7021                                         return -EOPNOTSUPP;
7022
7023                                 if (!service->wps ||
7024                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
7025                                         return -ENOKEY;
7026                         }
7027                         break;
7028
7029                 case CONNMAN_SERVICE_SECURITY_8021X:
7030                         if (!service->eap)
7031                                 return -EINVAL;
7032
7033 #if defined TIZEN_EXT
7034                         /*
7035                          * never request credentials if using EAP-TLS, EAP-SIM
7036                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
7037                          * need to be fully provisioned)
7038                          */
7039                         if (g_str_equal(service->eap, "tls") ||
7040                                 g_str_equal(service->eap, "sim") ||
7041                                 g_str_equal(service->eap, "aka"))
7042                                 break;
7043 #else
7044                         /*
7045                          * never request credentials if using EAP-TLS
7046                          * (EAP-TLS networks need to be fully provisioned)
7047                          */
7048                         if (g_str_equal(service->eap, "tls"))
7049                                 break;
7050 #endif
7051                         /*
7052                          * Return -ENOKEY if either identity or passphrase is
7053                          * missing. Agent provided credentials can be used as
7054                          * fallback if needed.
7055                          */
7056                         if (((!service->identity &&
7057                                         !service->agent_identity) ||
7058                                         !service->passphrase) ||
7059                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7060                                 return -ENOKEY;
7061
7062                         break;
7063                 }
7064                 break;
7065         }
7066
7067         if (service->network) {
7068                 if (!prepare_network(service))
7069                         return -EINVAL;
7070
7071                 switch (service->security) {
7072                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7073                 case CONNMAN_SERVICE_SECURITY_NONE:
7074                 case CONNMAN_SERVICE_SECURITY_WEP:
7075                 case CONNMAN_SERVICE_SECURITY_PSK:
7076                 case CONNMAN_SERVICE_SECURITY_WPA:
7077                 case CONNMAN_SERVICE_SECURITY_RSN:
7078                         break;
7079                 case CONNMAN_SERVICE_SECURITY_8021X:
7080                         prepare_8021x(service);
7081                         break;
7082                 }
7083
7084                 if (__connman_stats_service_register(service) == 0) {
7085                         __connman_stats_get(service, false,
7086                                                 &service->stats.data);
7087                         __connman_stats_get(service, true,
7088                                                 &service->stats_roaming.data);
7089                 }
7090
7091                 if (service->ipconfig_ipv4)
7092                         __connman_ipconfig_enable(service->ipconfig_ipv4);
7093                 if (service->ipconfig_ipv6)
7094                         __connman_ipconfig_enable(service->ipconfig_ipv6);
7095
7096                 err = __connman_network_connect(service->network);
7097         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7098                                         service->provider)
7099                 err = __connman_provider_connect(service->provider);
7100         else
7101                 return -EOPNOTSUPP;
7102
7103         if (err < 0) {
7104                 if (err != -EINPROGRESS) {
7105                         __connman_ipconfig_disable(service->ipconfig_ipv4);
7106                         __connman_ipconfig_disable(service->ipconfig_ipv6);
7107                         __connman_stats_service_unregister(service);
7108                 }
7109         }
7110
7111         return err;
7112 }
7113
7114 int __connman_service_connect(struct connman_service *service,
7115                         enum connman_service_connect_reason reason)
7116 {
7117         int err;
7118
7119         DBG("service %p state %s connect reason %s -> %s",
7120                 service, state2string(service->state),
7121                 reason2string(service->connect_reason),
7122                 reason2string(reason));
7123
7124         if (is_connected(service))
7125                 return -EISCONN;
7126
7127         if (is_connecting(service))
7128                 return -EALREADY;
7129
7130         switch (service->type) {
7131         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7132         case CONNMAN_SERVICE_TYPE_SYSTEM:
7133         case CONNMAN_SERVICE_TYPE_GPS:
7134         case CONNMAN_SERVICE_TYPE_P2P:
7135                 return -EINVAL;
7136
7137         case CONNMAN_SERVICE_TYPE_ETHERNET:
7138         case CONNMAN_SERVICE_TYPE_GADGET:
7139         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7140         case CONNMAN_SERVICE_TYPE_CELLULAR:
7141         case CONNMAN_SERVICE_TYPE_VPN:
7142         case CONNMAN_SERVICE_TYPE_WIFI:
7143                 break;
7144         }
7145
7146         if (!is_ipconfig_usable(service))
7147                 return -ENOLINK;
7148
7149         __connman_service_clear_error(service);
7150
7151         err = service_connect(service);
7152
7153         service->connect_reason = reason;
7154         if (err >= 0)
7155                 return 0;
7156
7157         if (err == -EINPROGRESS) {
7158                 if (service->timeout == 0)
7159                         service->timeout = g_timeout_add_seconds(
7160                                 CONNECT_TIMEOUT, connect_timeout, service);
7161
7162                 return -EINPROGRESS;
7163         }
7164
7165         if (service->network)
7166                 __connman_network_disconnect(service->network);
7167         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7168                                 service->provider)
7169                         connman_provider_disconnect(service->provider);
7170
7171         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
7172                 if (err == -ENOKEY || err == -EPERM) {
7173                         DBusMessage *pending = NULL;
7174
7175                         /*
7176                          * We steal the reply here. The idea is that the
7177                          * connecting client will see the connection status
7178                          * after the real hidden network is connected or
7179                          * connection failed.
7180                          */
7181                         if (service->hidden) {
7182                                 pending = service->pending;
7183                                 service->pending = NULL;
7184                         }
7185
7186                         err = __connman_agent_request_passphrase_input(service,
7187                                         request_input_cb,
7188                                         get_dbus_sender(service),
7189                                         pending);
7190                         if (service->hidden && err != -EINPROGRESS)
7191                                 service->pending = pending;
7192
7193                         return err;
7194                 }
7195                 reply_pending(service, -err);
7196         }
7197
7198         return err;
7199 }
7200
7201 int __connman_service_disconnect(struct connman_service *service)
7202 {
7203         int err;
7204
7205         DBG("service %p", service);
7206
7207         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
7208         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
7209
7210         connman_agent_cancel(service);
7211
7212         reply_pending(service, ECONNABORTED);
7213
7214         if (service->network) {
7215                 err = __connman_network_disconnect(service->network);
7216         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7217                                         service->provider)
7218                 err = connman_provider_disconnect(service->provider);
7219         else
7220                 return -EOPNOTSUPP;
7221
7222         if (err < 0 && err != -EINPROGRESS)
7223                 return err;
7224
7225         __connman_6to4_remove(service->ipconfig_ipv4);
7226
7227         if (service->ipconfig_ipv4)
7228                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
7229                                                         NULL);
7230         else
7231                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
7232                                                         NULL);
7233
7234 #if defined TIZEN_EXT
7235         /**
7236           * Skip the functions If there is any connected profiles
7237           * that use same interface
7238           */
7239         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7240                 __connman_service_get_connected_count_of_iface(service) <= 0) {
7241 #endif
7242         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
7243         settings_changed(service, service->ipconfig_ipv4);
7244
7245         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
7246         settings_changed(service, service->ipconfig_ipv6);
7247
7248         __connman_ipconfig_disable(service->ipconfig_ipv4);
7249         __connman_ipconfig_disable(service->ipconfig_ipv6);
7250 #if defined TIZEN_EXT
7251         }
7252 #endif
7253
7254         __connman_stats_service_unregister(service);
7255
7256         return err;
7257 }
7258
7259 int __connman_service_disconnect_all(void)
7260 {
7261         struct connman_service *service;
7262         GSList *services = NULL, *list;
7263         GList *iter;
7264
7265         DBG("");
7266
7267         for (iter = service_list; iter; iter = iter->next) {
7268                 service = iter->data;
7269
7270                 if (!is_connected(service))
7271                         break;
7272
7273                 services = g_slist_prepend(services, service);
7274         }
7275
7276         for (list = services; list; list = list->next) {
7277                 struct connman_service *service = list->data;
7278
7279                 service->ignore = true;
7280
7281                 __connman_service_disconnect(service);
7282         }
7283
7284         g_slist_free(services);
7285
7286         return 0;
7287 }
7288
7289 /**
7290  * lookup_by_identifier:
7291  * @identifier: service identifier
7292  *
7293  * Look up a service by identifier (reference count will not be increased)
7294  */
7295 static struct connman_service *lookup_by_identifier(const char *identifier)
7296 {
7297         return g_hash_table_lookup(service_hash, identifier);
7298 }
7299
7300 struct provision_user_data {
7301         const char *ident;
7302         int ret;
7303 };
7304
7305 static void provision_changed(gpointer value, gpointer user_data)
7306 {
7307         struct connman_service *service = value;
7308         struct provision_user_data *data = user_data;
7309         const char *path = data->ident;
7310         int ret;
7311
7312         ret = __connman_config_provision_service_ident(service, path,
7313                         service->config_file, service->config_entry);
7314         if (ret > 0)
7315                 data->ret = ret;
7316 }
7317
7318 int __connman_service_provision_changed(const char *ident)
7319 {
7320         struct provision_user_data data = {
7321                 .ident = ident,
7322                 .ret = 0
7323         };
7324
7325         g_list_foreach(service_list, provision_changed, (void *)&data);
7326
7327         /*
7328          * Because the provision_changed() might have set some services
7329          * as favorite, we must sort the sequence now.
7330          */
7331         if (services_dirty) {
7332                 services_dirty = false;
7333
7334                 service_list_sort();
7335
7336                 __connman_connection_update_gateway();
7337         }
7338
7339         return data.ret;
7340 }
7341
7342 void __connman_service_set_config(struct connman_service *service,
7343                                 const char *file_id, const char *entry)
7344 {
7345         if (!service)
7346                 return;
7347
7348         g_free(service->config_file);
7349         service->config_file = g_strdup(file_id);
7350
7351         g_free(service->config_entry);
7352         service->config_entry = g_strdup(entry);
7353 }
7354
7355 /**
7356  * __connman_service_get:
7357  * @identifier: service identifier
7358  *
7359  * Look up a service by identifier or create a new one if not found
7360  */
7361 static struct connman_service *service_get(const char *identifier)
7362 {
7363         struct connman_service *service;
7364
7365         service = g_hash_table_lookup(service_hash, identifier);
7366         if (service) {
7367                 connman_service_ref(service);
7368                 return service;
7369         }
7370
7371         service = connman_service_create();
7372         if (!service)
7373                 return NULL;
7374
7375         DBG("service %p", service);
7376
7377         service->identifier = g_strdup(identifier);
7378
7379         service_list = g_list_insert_sorted(service_list, service,
7380                                                 service_compare);
7381
7382         g_hash_table_insert(service_hash, service->identifier, service);
7383
7384         return service;
7385 }
7386
7387 static int service_register(struct connman_service *service)
7388 {
7389         DBG("service %p", service);
7390
7391         if (service->path)
7392                 return -EALREADY;
7393
7394         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
7395                                                 service->identifier);
7396
7397         DBG("path %s", service->path);
7398
7399         if (__connman_config_provision_service(service) < 0)
7400                 service_load(service);
7401
7402         g_dbus_register_interface(connection, service->path,
7403                                         CONNMAN_SERVICE_INTERFACE,
7404                                         service_methods, service_signals,
7405                                                         NULL, service, NULL);
7406
7407         service_list_sort();
7408
7409         __connman_connection_update_gateway();
7410
7411         return 0;
7412 }
7413
7414 static void service_up(struct connman_ipconfig *ipconfig,
7415                 const char *ifname)
7416 {
7417         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7418
7419         DBG("%s up", ifname);
7420
7421         link_changed(service);
7422
7423         service->stats.valid = false;
7424         service->stats_roaming.valid = false;
7425 }
7426
7427 static void service_down(struct connman_ipconfig *ipconfig,
7428                         const char *ifname)
7429 {
7430         DBG("%s down", ifname);
7431 }
7432
7433 static void service_lower_up(struct connman_ipconfig *ipconfig,
7434                         const char *ifname)
7435 {
7436         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7437
7438         DBG("%s lower up", ifname);
7439
7440         stats_start(service);
7441 }
7442
7443 static void service_lower_down(struct connman_ipconfig *ipconfig,
7444                         const char *ifname)
7445 {
7446         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7447
7448         DBG("%s lower down", ifname);
7449
7450         if (!is_idle_state(service, service->state_ipv4))
7451                 __connman_ipconfig_disable(service->ipconfig_ipv4);
7452
7453         if (!is_idle_state(service, service->state_ipv6))
7454                 __connman_ipconfig_disable(service->ipconfig_ipv6);
7455
7456         stats_stop(service);
7457         service_save(service);
7458 }
7459
7460 static void service_ip_bound(struct connman_ipconfig *ipconfig,
7461                         const char *ifname)
7462 {
7463         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7464         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
7465         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
7466
7467         DBG("%s ip bound", ifname);
7468
7469         type = __connman_ipconfig_get_config_type(ipconfig);
7470         method = __connman_ipconfig_get_method(ipconfig);
7471
7472         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
7473                                                         type, method);
7474
7475         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
7476                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
7477                 __connman_service_ipconfig_indicate_state(service,
7478                                                 CONNMAN_SERVICE_STATE_READY,
7479                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7480
7481         settings_changed(service, ipconfig);
7482 }
7483
7484 static void service_ip_release(struct connman_ipconfig *ipconfig,
7485                         const char *ifname)
7486 {
7487         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7488         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
7489         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
7490
7491         DBG("%s ip release", ifname);
7492
7493         type = __connman_ipconfig_get_config_type(ipconfig);
7494         method = __connman_ipconfig_get_method(ipconfig);
7495
7496         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
7497                                                         type, method);
7498
7499         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
7500                         method == CONNMAN_IPCONFIG_METHOD_OFF)
7501                 __connman_service_ipconfig_indicate_state(service,
7502                                         CONNMAN_SERVICE_STATE_DISCONNECT,
7503                                         CONNMAN_IPCONFIG_TYPE_IPV6);
7504
7505         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
7506                         method == CONNMAN_IPCONFIG_METHOD_OFF)
7507                 __connman_service_ipconfig_indicate_state(service,
7508                                         CONNMAN_SERVICE_STATE_DISCONNECT,
7509                                         CONNMAN_IPCONFIG_TYPE_IPV4);
7510
7511         settings_changed(service, ipconfig);
7512 }
7513
7514 static void service_route_changed(struct connman_ipconfig *ipconfig,
7515                                 const char *ifname)
7516 {
7517         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7518
7519         DBG("%s route changed", ifname);
7520
7521         settings_changed(service, ipconfig);
7522 }
7523
7524 static const struct connman_ipconfig_ops service_ops = {
7525         .up             = service_up,
7526         .down           = service_down,
7527         .lower_up       = service_lower_up,
7528         .lower_down     = service_lower_down,
7529         .ip_bound       = service_ip_bound,
7530         .ip_release     = service_ip_release,
7531         .route_set      = service_route_changed,
7532         .route_unset    = service_route_changed,
7533 };
7534
7535 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
7536                 int index, enum connman_ipconfig_method method)
7537 {
7538         struct connman_ipconfig *ipconfig_ipv4;
7539
7540         ipconfig_ipv4 = __connman_ipconfig_create(index,
7541                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7542         if (!ipconfig_ipv4)
7543                 return NULL;
7544
7545         __connman_ipconfig_set_method(ipconfig_ipv4, method);
7546
7547         __connman_ipconfig_set_data(ipconfig_ipv4, service);
7548
7549         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
7550
7551         return ipconfig_ipv4;
7552 }
7553
7554 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
7555                 int index)
7556 {
7557         struct connman_ipconfig *ipconfig_ipv6;
7558
7559         ipconfig_ipv6 = __connman_ipconfig_create(index,
7560                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7561         if (!ipconfig_ipv6)
7562                 return NULL;
7563
7564         __connman_ipconfig_set_data(ipconfig_ipv6, service);
7565
7566         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
7567
7568         return ipconfig_ipv6;
7569 }
7570
7571 void __connman_service_read_ip4config(struct connman_service *service)
7572 {
7573         GKeyFile *keyfile;
7574
7575         if (!service->ipconfig_ipv4)
7576                 return;
7577
7578         keyfile = connman_storage_load_service(service->identifier);
7579         if (!keyfile)
7580                 return;
7581
7582         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
7583                                 service->identifier, "IPv4.");
7584
7585         g_key_file_free(keyfile);
7586 }
7587
7588 void connman_service_create_ip4config(struct connman_service *service,
7589                                         int index)
7590 {
7591         DBG("ipv4 %p", service->ipconfig_ipv4);
7592
7593         if (service->ipconfig_ipv4)
7594                 return;
7595
7596         service->ipconfig_ipv4 = create_ip4config(service, index,
7597                         CONNMAN_IPCONFIG_METHOD_DHCP);
7598         __connman_service_read_ip4config(service);
7599 }
7600
7601 void __connman_service_read_ip6config(struct connman_service *service)
7602 {
7603         GKeyFile *keyfile;
7604
7605         if (!service->ipconfig_ipv6)
7606                 return;
7607
7608         keyfile = connman_storage_load_service(service->identifier);
7609         if (!keyfile)
7610                 return;
7611
7612         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
7613                                 service->identifier, "IPv6.");
7614
7615         g_key_file_free(keyfile);
7616 }
7617
7618 void connman_service_create_ip6config(struct connman_service *service,
7619                                                                 int index)
7620 {
7621         DBG("ipv6 %p", service->ipconfig_ipv6);
7622
7623         if (service->ipconfig_ipv6)
7624                 return;
7625
7626         service->ipconfig_ipv6 = create_ip6config(service, index);
7627
7628         __connman_service_read_ip6config(service);
7629 }
7630
7631 /**
7632  * connman_service_lookup_from_network:
7633  * @network: network structure
7634  *
7635  * Look up a service by network (reference count will not be increased)
7636  */
7637 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
7638 {
7639         struct connman_service *service;
7640         const char *ident, *group;
7641         char *name;
7642
7643         if (!network)
7644                 return NULL;
7645
7646         ident = __connman_network_get_ident(network);
7647         if (!ident)
7648                 return NULL;
7649
7650         group = connman_network_get_group(network);
7651         if (!group)
7652                 return NULL;
7653
7654         name = g_strdup_printf("%s_%s_%s",
7655                         __connman_network_get_type(network), ident, group);
7656         service = lookup_by_identifier(name);
7657         g_free(name);
7658
7659         return service;
7660 }
7661
7662 struct connman_service *__connman_service_lookup_from_index(int index)
7663 {
7664         struct connman_service *service;
7665         GList *list;
7666
7667         for (list = service_list; list; list = list->next) {
7668                 service = list->data;
7669
7670                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
7671                                                         == index)
7672                         return service;
7673
7674                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
7675                                                         == index)
7676                         return service;
7677         }
7678
7679         return NULL;
7680 }
7681
7682 struct connman_service *__connman_service_lookup_from_ident(const char *identifier)
7683 {
7684         return lookup_by_identifier(identifier);
7685 }
7686
7687 const char *__connman_service_get_ident(struct connman_service *service)
7688 {
7689         return service->identifier;
7690 }
7691
7692 const char *__connman_service_get_path(struct connman_service *service)
7693 {
7694         return service->path;
7695 }
7696
7697 const char *__connman_service_get_name(struct connman_service *service)
7698 {
7699         return service->name;
7700 }
7701
7702 enum connman_service_state __connman_service_get_state(struct connman_service *service)
7703 {
7704         return service->state;
7705 }
7706
7707 unsigned int __connman_service_get_order(struct connman_service *service)
7708 {
7709         unsigned int order = 0;
7710
7711         if (!service)
7712                 return 0;
7713
7714         service->order = 0;
7715
7716         if (!service->favorite)
7717                 return 0;
7718
7719 #if defined TIZEN_EXT
7720         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7721                         service->do_split_routing == FALSE)
7722                 order = 10;
7723         else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
7724                 if (service->order < 5)
7725                         order = 5;
7726         } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
7727                 order = 4;
7728         else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
7729                 order = 3;
7730         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7731                         __connman_service_is_internet_profile(service) == TRUE)
7732                 order = 1;
7733         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7734                         __connman_service_is_tethering_profile(service) == TRUE)
7735                 order = 0;
7736         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7737                 order = 0;
7738         else
7739                 order = 2;
7740 #else
7741         if (service == service_list->data)
7742                 order = 1;
7743
7744         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7745                         !service->do_split_routing) {
7746                 service->order = 10;
7747                 order = 10;
7748         }
7749 #endif
7750         DBG("service %p name %s order %d split %d", service, service->name,
7751                 order, service->do_split_routing);
7752
7753         return order;
7754 }
7755
7756 void __connman_service_update_ordering(void)
7757 {
7758         if (service_list && service_list->next)
7759                 service_list = g_list_sort(service_list, service_compare);
7760 }
7761
7762 static enum connman_service_type convert_network_type(struct connman_network *network)
7763 {
7764         enum connman_network_type type = connman_network_get_type(network);
7765
7766         switch (type) {
7767         case CONNMAN_NETWORK_TYPE_UNKNOWN:
7768         case CONNMAN_NETWORK_TYPE_VENDOR:
7769                 break;
7770         case CONNMAN_NETWORK_TYPE_ETHERNET:
7771                 return CONNMAN_SERVICE_TYPE_ETHERNET;
7772         case CONNMAN_NETWORK_TYPE_WIFI:
7773                 return CONNMAN_SERVICE_TYPE_WIFI;
7774         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
7775         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
7776                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
7777         case CONNMAN_NETWORK_TYPE_CELLULAR:
7778                 return CONNMAN_SERVICE_TYPE_CELLULAR;
7779         case CONNMAN_NETWORK_TYPE_GADGET:
7780                 return CONNMAN_SERVICE_TYPE_GADGET;
7781         }
7782
7783         return CONNMAN_SERVICE_TYPE_UNKNOWN;
7784 }
7785
7786 static enum connman_service_security convert_wifi_security(const char *security)
7787 {
7788         if (!security)
7789                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
7790         else if (g_str_equal(security, "none"))
7791                 return CONNMAN_SERVICE_SECURITY_NONE;
7792         else if (g_str_equal(security, "wep"))
7793                 return CONNMAN_SERVICE_SECURITY_WEP;
7794         else if (g_str_equal(security, "psk"))
7795                 return CONNMAN_SERVICE_SECURITY_PSK;
7796         else if (g_str_equal(security, "ieee8021x"))
7797                 return CONNMAN_SERVICE_SECURITY_8021X;
7798         else if (g_str_equal(security, "wpa"))
7799                 return CONNMAN_SERVICE_SECURITY_WPA;
7800         else if (g_str_equal(security, "rsn"))
7801                 return CONNMAN_SERVICE_SECURITY_RSN;
7802         else
7803                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
7804 }
7805
7806 static void update_from_network(struct connman_service *service,
7807                                         struct connman_network *network)
7808 {
7809         uint8_t strength = service->strength;
7810         const char *str;
7811
7812         DBG("service %p network %p", service, network);
7813
7814         if (is_connected(service))
7815                 return;
7816
7817         if (is_connecting(service))
7818                 return;
7819
7820         str = connman_network_get_string(network, "Name");
7821         if (str) {
7822                 g_free(service->name);
7823                 service->name = g_strdup(str);
7824                 service->hidden = false;
7825         } else {
7826                 g_free(service->name);
7827                 service->name = NULL;
7828                 service->hidden = true;
7829         }
7830
7831         service->strength = connman_network_get_strength(network);
7832         service->roaming = connman_network_get_bool(network, "Roaming");
7833
7834         if (service->strength == 0) {
7835                 /*
7836                  * Filter out 0-values; it's unclear what they mean
7837                  * and they cause anomalous sorting of the priority list.
7838                  */
7839                 service->strength = strength;
7840         }
7841
7842         str = connman_network_get_string(network, "WiFi.Security");
7843         service->security = convert_wifi_security(str);
7844
7845         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7846                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
7847
7848         if (service->strength > strength && service->network) {
7849                 connman_network_unref(service->network);
7850                 service->network = connman_network_ref(network);
7851
7852                 strength_changed(service);
7853         }
7854
7855         if (!service->network)
7856                 service->network = connman_network_ref(network);
7857
7858         service_list_sort();
7859 }
7860
7861 /**
7862  * __connman_service_create_from_network:
7863  * @network: network structure
7864  *
7865  * Look up service by network and if not found, create one
7866  */
7867 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
7868 {
7869         struct connman_service *service;
7870         struct connman_device *device;
7871         const char *ident, *group;
7872         char *name;
7873         unsigned int *auto_connect_types;
7874         int i, index;
7875
7876         DBG("network %p", network);
7877
7878         if (!network)
7879                 return NULL;
7880
7881         ident = __connman_network_get_ident(network);
7882         if (!ident)
7883                 return NULL;
7884
7885         group = connman_network_get_group(network);
7886         if (!group)
7887                 return NULL;
7888
7889         name = g_strdup_printf("%s_%s_%s",
7890                         __connman_network_get_type(network), ident, group);
7891         service = service_get(name);
7892         g_free(name);
7893
7894         if (!service)
7895                 return NULL;
7896
7897         if (__connman_network_get_weakness(network))
7898                 return service;
7899
7900         if (service->path) {
7901                 update_from_network(service, network);
7902                 __connman_connection_update_gateway();
7903                 return service;
7904         }
7905
7906         service->type = convert_network_type(network);
7907
7908         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
7909         service->autoconnect = false;
7910         for (i = 0; auto_connect_types &&
7911                      auto_connect_types[i] != 0; i++) {
7912                 if (service->type == auto_connect_types[i]) {
7913                         service->autoconnect = true;
7914                         break;
7915                 }
7916         }
7917
7918         switch (service->type) {
7919         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7920         case CONNMAN_SERVICE_TYPE_SYSTEM:
7921         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7922         case CONNMAN_SERVICE_TYPE_GPS:
7923         case CONNMAN_SERVICE_TYPE_VPN:
7924         case CONNMAN_SERVICE_TYPE_GADGET:
7925         case CONNMAN_SERVICE_TYPE_WIFI:
7926         case CONNMAN_SERVICE_TYPE_CELLULAR:
7927         case CONNMAN_SERVICE_TYPE_P2P:
7928                 break;
7929         case CONNMAN_SERVICE_TYPE_ETHERNET:
7930                 service->favorite = true;
7931                 break;
7932         }
7933
7934         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
7935         service->state = combine_state(service->state_ipv4, service->state_ipv6);
7936
7937         update_from_network(service, network);
7938
7939         index = connman_network_get_index(network);
7940
7941         if (!service->ipconfig_ipv4)
7942                 service->ipconfig_ipv4 = create_ip4config(service, index,
7943                                 CONNMAN_IPCONFIG_METHOD_DHCP);
7944
7945         if (!service->ipconfig_ipv6)
7946                 service->ipconfig_ipv6 = create_ip6config(service, index);
7947
7948         service_register(service);
7949
7950         if (service->favorite) {
7951                 device = connman_network_get_device(service->network);
7952                 if (device && !connman_device_get_scanning(device)) {
7953
7954                         switch (service->type) {
7955                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7956                         case CONNMAN_SERVICE_TYPE_SYSTEM:
7957                         case CONNMAN_SERVICE_TYPE_P2P:
7958                                 break;
7959
7960                         case CONNMAN_SERVICE_TYPE_GADGET:
7961                         case CONNMAN_SERVICE_TYPE_ETHERNET:
7962                                 if (service->autoconnect) {
7963                                         __connman_service_connect(service,
7964                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7965                                         break;
7966                                 }
7967
7968                                 /* fall through */
7969                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7970                         case CONNMAN_SERVICE_TYPE_GPS:
7971                         case CONNMAN_SERVICE_TYPE_VPN:
7972                         case CONNMAN_SERVICE_TYPE_WIFI:
7973                         case CONNMAN_SERVICE_TYPE_CELLULAR:
7974                                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7975                                 break;
7976                         }
7977                 }
7978
7979 #if defined TIZEN_EXT
7980                 /* TIZEN synchronizes below information when the service creates */
7981                 if (service->eap != NULL)
7982                         connman_network_set_string(service->network, "WiFi.EAP",
7983                                                                 service->eap);
7984                 if (service->identity != NULL)
7985                         connman_network_set_string(service->network, "WiFi.Identity",
7986                                                                 service->identity);
7987                 if (service->phase2 != NULL)
7988                         connman_network_set_string(service->network, "WiFi.Phase2",
7989                                                                 service->phase2);
7990 #endif
7991         }
7992
7993         __connman_notifier_service_add(service, service->name);
7994         service_schedule_added(service);
7995
7996         return service;
7997 }
7998
7999 void __connman_service_update_from_network(struct connman_network *network)
8000 {
8001         bool need_sort = false;
8002         struct connman_service *service;
8003         uint8_t strength;
8004         bool roaming;
8005         const char *name;
8006         bool stats_enable;
8007
8008         service = connman_service_lookup_from_network(network);
8009         if (!service)
8010                 return;
8011
8012         if (!service->network)
8013                 return;
8014
8015 #if defined TIZEN_EXT
8016         if (service->storage_reload) {
8017                 service_load(service);
8018                 __connman_service_set_storage_reload(service, false);
8019         }
8020 #endif
8021
8022         name = connman_network_get_string(service->network, "Name");
8023         if (g_strcmp0(service->name, name) != 0) {
8024                 g_free(service->name);
8025                 service->name = g_strdup(name);
8026
8027                 if (allow_property_changed(service))
8028                         connman_dbus_property_changed_basic(service->path,
8029                                         CONNMAN_SERVICE_INTERFACE, "Name",
8030                                         DBUS_TYPE_STRING, &service->name);
8031         }
8032
8033         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8034                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
8035
8036         strength = connman_network_get_strength(service->network);
8037         if (strength == service->strength)
8038                 goto roaming;
8039
8040         service->strength = strength;
8041         need_sort = true;
8042
8043         strength_changed(service);
8044
8045 roaming:
8046         roaming = connman_network_get_bool(service->network, "Roaming");
8047         if (roaming == service->roaming)
8048                 goto sorting;
8049
8050         stats_enable = stats_enabled(service);
8051         if (stats_enable)
8052                 stats_stop(service);
8053
8054         service->roaming = roaming;
8055         need_sort = true;
8056
8057         if (stats_enable)
8058                 stats_start(service);
8059
8060         roaming_changed(service);
8061
8062 sorting:
8063         if (need_sort) {
8064                 service_list_sort();
8065         }
8066 }
8067
8068 void __connman_service_remove_from_network(struct connman_network *network)
8069 {
8070         struct connman_service *service;
8071
8072         service = connman_service_lookup_from_network(network);
8073
8074         DBG("network %p service %p", network, service);
8075
8076         if (!service)
8077                 return;
8078
8079         service->ignore = true;
8080
8081         __connman_connection_gateway_remove(service,
8082                                         CONNMAN_IPCONFIG_TYPE_ALL);
8083
8084         connman_service_unref(service);
8085 }
8086
8087 /**
8088  * __connman_service_create_from_provider:
8089  * @provider: provider structure
8090  *
8091  * Look up service by provider and if not found, create one
8092  */
8093 struct connman_service *
8094 __connman_service_create_from_provider(struct connman_provider *provider)
8095 {
8096         struct connman_service *service;
8097         const char *ident, *str;
8098         char *name;
8099         int index = connman_provider_get_index(provider);
8100
8101         DBG("provider %p", provider);
8102
8103         ident = __connman_provider_get_ident(provider);
8104         if (!ident)
8105                 return NULL;
8106
8107         name = g_strdup_printf("vpn_%s", ident);
8108         service = service_get(name);
8109         g_free(name);
8110
8111         if (!service)
8112                 return NULL;
8113
8114         service->type = CONNMAN_SERVICE_TYPE_VPN;
8115         service->provider = connman_provider_ref(provider);
8116         service->autoconnect = false;
8117         service->favorite = true;
8118
8119         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8120         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8121
8122         str = connman_provider_get_string(provider, "Name");
8123         if (str) {
8124                 g_free(service->name);
8125                 service->name = g_strdup(str);
8126                 service->hidden = false;
8127         } else {
8128                 g_free(service->name);
8129                 service->name = NULL;
8130                 service->hidden = true;
8131         }
8132
8133         service->strength = 0;
8134
8135         if (!service->ipconfig_ipv4)
8136                 service->ipconfig_ipv4 = create_ip4config(service, index,
8137                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
8138
8139         if (!service->ipconfig_ipv6)
8140                 service->ipconfig_ipv6 = create_ip6config(service, index);
8141
8142         service_register(service);
8143
8144         __connman_notifier_service_add(service, service->name);
8145         service_schedule_added(service);
8146
8147         return service;
8148 }
8149
8150 static void remove_unprovisioned_services(void)
8151 {
8152         gchar **services;
8153         GKeyFile *keyfile, *configkeyfile;
8154         char *file, *section;
8155         int i = 0;
8156
8157         services = connman_storage_get_services();
8158         if (!services)
8159                 return;
8160
8161         for (; services[i]; i++) {
8162                 file = section = NULL;
8163                 keyfile = configkeyfile = NULL;
8164
8165                 keyfile = connman_storage_load_service(services[i]);
8166                 if (!keyfile)
8167                         continue;
8168
8169                 file = g_key_file_get_string(keyfile, services[i],
8170                                         "Config.file", NULL);
8171                 if (!file)
8172                         goto next;
8173
8174                 section = g_key_file_get_string(keyfile, services[i],
8175                                         "Config.ident", NULL);
8176                 if (!section)
8177                         goto next;
8178
8179                 configkeyfile = __connman_storage_load_config(file);
8180                 if (!configkeyfile) {
8181                         /*
8182                          * Config file is missing, remove the provisioned
8183                          * service.
8184                          */
8185                         __connman_storage_remove_service(services[i]);
8186                         goto next;
8187                 }
8188
8189                 if (!g_key_file_has_group(configkeyfile, section))
8190                         /*
8191                          * Config section is missing, remove the provisioned
8192                          * service.
8193                          */
8194                         __connman_storage_remove_service(services[i]);
8195
8196         next:
8197                 if (keyfile)
8198                         g_key_file_free(keyfile);
8199
8200                 if (configkeyfile)
8201                         g_key_file_free(configkeyfile);
8202
8203                 g_free(section);
8204                 g_free(file);
8205         }
8206
8207         g_strfreev(services);
8208 }
8209
8210 static int agent_probe(struct connman_agent *agent)
8211 {
8212         DBG("agent %p", agent);
8213         return 0;
8214 }
8215
8216 static void agent_remove(struct connman_agent *agent)
8217 {
8218         DBG("agent %p", agent);
8219 }
8220
8221 static void *agent_context_ref(void *context)
8222 {
8223         struct connman_service *service = context;
8224
8225         return (void *)connman_service_ref(service);
8226 }
8227
8228 static void agent_context_unref(void *context)
8229 {
8230         struct connman_service *service = context;
8231
8232         connman_service_unref(service);
8233 }
8234
8235 static struct connman_agent_driver agent_driver = {
8236         .name           = "service",
8237         .interface      = CONNMAN_AGENT_INTERFACE,
8238         .probe          = agent_probe,
8239         .remove         = agent_remove,
8240         .context_ref    = agent_context_ref,
8241         .context_unref  = agent_context_unref,
8242 };
8243
8244 int __connman_service_init(void)
8245 {
8246         int err;
8247
8248         DBG("");
8249
8250         err = connman_agent_driver_register(&agent_driver);
8251         if (err < 0) {
8252                 connman_error("Cannot register agent driver for %s",
8253                                                 agent_driver.name);
8254                 return err;
8255         }
8256
8257         connection = connman_dbus_get_connection();
8258
8259         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
8260                                                         NULL, service_free);
8261
8262         services_notify = g_new0(struct _services_notify, 1);
8263         services_notify->remove = g_hash_table_new_full(g_str_hash,
8264                         g_str_equal, g_free, NULL);
8265         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
8266
8267         remove_unprovisioned_services();
8268
8269         return 0;
8270 }
8271
8272 void __connman_service_cleanup(void)
8273 {
8274         DBG("");
8275
8276         if (vpn_autoconnect_timeout) {
8277                 g_source_remove(vpn_autoconnect_timeout);
8278                 vpn_autoconnect_timeout = 0;
8279         }
8280
8281         if (autoconnect_timeout != 0) {
8282                 g_source_remove(autoconnect_timeout);
8283                 autoconnect_timeout = 0;
8284         }
8285
8286         connman_agent_driver_unregister(&agent_driver);
8287
8288         g_list_free(service_list);
8289         service_list = NULL;
8290
8291         g_hash_table_destroy(service_hash);
8292         service_hash = NULL;
8293
8294         g_slist_free(counter_list);
8295         counter_list = NULL;
8296
8297         if (services_notify->id != 0) {
8298                 g_source_remove(services_notify->id);
8299                 service_send_changed(NULL);
8300                 g_hash_table_destroy(services_notify->remove);
8301                 g_hash_table_destroy(services_notify->add);
8302         }
8303         g_free(services_notify);
8304
8305         dbus_connection_unref(connection);
8306 }