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