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