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