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