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