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