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