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