Merge "[CID-32053] Remove dead code" 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
5259         /*Reset the Disconnect Reason while issue connect request*/
5260         service->disconnect_reason = 0;
5261 #endif
5262
5263         if (service->pending)
5264                 return __connman_error_in_progress(msg);
5265
5266         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
5267                 uid_t uid;
5268                 if (connman_dbus_get_connection_unix_user_sync(conn,
5269                                                 dbus_message_get_sender(msg),
5270                                                 &uid) < 0) {
5271                         DBG("Can not get unix user id!");
5272                         return __connman_error_permission_denied(msg);
5273                 }
5274
5275                 if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
5276                         DBG("Not allow this user to connect this wifi service now!");
5277                         return __connman_error_permission_denied(msg);
5278                 }
5279
5280                 if (uid != USER_ROOT && uid != service->user.favorite_user)
5281                         service->request_passphrase_input = true;
5282
5283                 service->user.current_user = uid;
5284
5285                 if (!service->passphrase && uid == service->user.favorite_user) {
5286                         DBG("Now load this favorite user's passphrase.");
5287                         service_load_passphrase(service);
5288                 }
5289         }
5290
5291 #if !defined TIZEN_EXT
5292         index = __connman_service_get_index(service);
5293
5294         for (list = service_list; list; list = list->next) {
5295                 struct connman_service *temp = list->data;
5296
5297 #if defined TIZEN_EXT
5298                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5299                         break;
5300 #endif
5301                 if (!is_connecting(temp) && !is_connected(temp))
5302                         break;
5303
5304                 if (service == temp)
5305                         continue;
5306
5307                 if (service->type != temp->type)
5308                         continue;
5309
5310                 if (__connman_service_get_index(temp) == index &&
5311                                 __connman_service_disconnect(temp) == -EINPROGRESS)
5312                         err = -EINPROGRESS;
5313
5314         }
5315         if (err == -EINPROGRESS)
5316                 return __connman_error_operation_timeout(msg);
5317 #endif
5318
5319         service->ignore = false;
5320
5321         service->pending = dbus_message_ref(msg);
5322
5323         err = __connman_service_connect(service,
5324                         CONNMAN_SERVICE_CONNECT_REASON_USER);
5325
5326         if (err == -EINPROGRESS)
5327                 return NULL;
5328
5329         if (service->pending) {
5330                 dbus_message_unref(service->pending);
5331                 service->pending = NULL;
5332         }
5333
5334         if (err < 0)
5335                 return __connman_error_failed(msg, -err);
5336
5337         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5338 }
5339
5340 static DBusMessage *disconnect_service(DBusConnection *conn,
5341                                         DBusMessage *msg, void *user_data)
5342 {
5343         struct connman_service *service = user_data;
5344         int err;
5345
5346         DBG("service %p", service);
5347
5348 #if defined TIZEN_EXT
5349         /*
5350          * Description: TIZEN implements system global connection management.
5351          */
5352         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
5353                 if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE)
5354                         return __connman_error_failed(msg, EISCONN);
5355
5356                 if (is_connected(service) == TRUE &&
5357                                 service == connman_service_get_default_connection())
5358                         return __connman_error_failed(msg, EISCONN);
5359         }
5360 #endif
5361
5362         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
5363                 uid_t uid;
5364                 if (connman_dbus_get_connection_unix_user_sync(conn,
5365                                                 dbus_message_get_sender(msg),
5366                                                 &uid) < 0) {
5367                         DBG("Can not get unix user id!");
5368                         return __connman_error_permission_denied(msg);
5369                 }
5370
5371                 if (!connman_service_is_user_allowed(service, uid)) {
5372                         DBG("Not allow this user to disconnect this wifi service now!");
5373                         return __connman_error_permission_denied(msg);
5374                 }
5375         }
5376
5377         service->ignore = true;
5378
5379         err = __connman_service_disconnect(service);
5380         if (err < 0 && err != -EINPROGRESS)
5381                 return __connman_error_failed(msg, -err);
5382
5383         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5384 }
5385
5386 #if defined TIZEN_EXT
5387 static void __connman_service_cleanup_network_8021x(struct connman_service *service)
5388 {
5389         if (service == NULL)
5390                 return;
5391
5392         DBG("service %p ", service);
5393
5394         connman_network_set_string(service->network, "WiFi.EAP", NULL);
5395         connman_network_set_string(service->network, "WiFi.Identity", NULL);
5396         connman_network_set_string(service->network, "WiFi.CACertFile", NULL);
5397         connman_network_set_string(service->network, "WiFi.ClientCertFile", NULL);
5398         connman_network_set_string(service->network, "WiFi.PrivateKeyFile", NULL);
5399         connman_network_set_string(service->network, "WiFi.PrivateKeyPassphrase", NULL);
5400         connman_network_set_string(service->network, "WiFi.Phase2", NULL);
5401 }
5402 #endif
5403
5404 bool __connman_service_remove(struct connman_service *service)
5405 {
5406         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET ||
5407                         service->type == CONNMAN_SERVICE_TYPE_GADGET)
5408                 return false;
5409
5410         if (service->immutable || service->hidden ||
5411                         __connman_provider_is_immutable(service->provider))
5412                 return false;
5413
5414 #if !defined TIZEN_EXT
5415         if (!service->favorite && service->state !=
5416                                                 CONNMAN_SERVICE_STATE_FAILURE)
5417                 return false;
5418 #endif
5419
5420         __connman_service_disconnect(service);
5421
5422         g_free(service->passphrase);
5423         service->passphrase = NULL;
5424
5425         g_free(service->identity);
5426         service->identity = NULL;
5427
5428         g_free(service->agent_identity);
5429         service->agent_identity = NULL;
5430
5431         g_free(service->eap);
5432         service->eap = NULL;
5433
5434 #if defined TIZEN_EXT
5435         g_free(service->ca_cert_file);
5436         service->ca_cert_file = NULL;
5437
5438         g_free(service->client_cert_file);
5439         service->client_cert_file = NULL;
5440
5441         g_free(service->private_key_file);
5442         service->private_key_file = NULL;
5443
5444         g_free(service->private_key_passphrase);
5445         service->private_key_passphrase = NULL;
5446
5447         g_free(service->phase2);
5448         service->phase2 = NULL;
5449
5450         __connman_service_cleanup_network_8021x(service);
5451
5452         __connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP);
5453         __connman_ipconfig_set_method(service->ipconfig_ipv6, CONNMAN_IPCONFIG_METHOD_AUTO);
5454         connman_service_set_proxy(service, NULL, false);
5455
5456         __connman_service_nameserver_clear(service);
5457
5458         g_strfreev(service->nameservers_config);
5459         service->nameservers_config = NULL;
5460
5461 #endif
5462
5463 #if defined TIZEN_EXT
5464         if (service->security != CONNMAN_SERVICE_SECURITY_8021X)
5465 #endif
5466         set_idle(service);
5467
5468         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
5469
5470         service->user.favorite_user = USER_NONE;
5471
5472         __connman_service_set_favorite(service, false);
5473
5474         __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
5475
5476 #if defined TIZEN_EXT
5477         /* Reset IP Method and DNS Method to DHCP */
5478         __connman_ipconfig_set_method(service->ipconfig_ipv4,
5479                         CONNMAN_IPCONFIG_METHOD_DHCP);
5480         service->dns_config_method_ipv4 = CONNMAN_DNSCONFIG_METHOD_DHCP;
5481         g_strfreev(service->nameservers_config);
5482         service->nameservers_config = NULL;
5483 #endif
5484
5485 #if defined TIZEN_EXT
5486         __connman_storage_remove_service(service->identifier);
5487 #else
5488         service_save(service);
5489 #endif
5490
5491         return true;
5492 }
5493
5494 static DBusMessage *remove_service(DBusConnection *conn,
5495                                         DBusMessage *msg, void *user_data)
5496 {
5497         struct connman_service *service = user_data;
5498
5499         DBG("service %p", service);
5500
5501         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
5502                 uid_t uid;
5503                 if (connman_dbus_get_connection_unix_user_sync(conn,
5504                                                 dbus_message_get_sender(msg),
5505                                                 &uid) < 0) {
5506                         DBG("Can not get unix user id!");
5507                         return __connman_error_permission_denied(msg);
5508                 }
5509
5510 #if !defined TIZEN_EXT
5511                 if (!connman_service_is_user_allowed(service, uid)) {
5512                         DBG("Not allow this user to remove this wifi service now!");
5513                         return __connman_error_permission_denied(msg);
5514                 }
5515 #endif
5516         }
5517
5518         if (!__connman_service_remove(service))
5519                 return __connman_error_not_supported(msg);
5520
5521         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5522 }
5523
5524 static bool check_suitable_state(enum connman_service_state a,
5525                                         enum connman_service_state b)
5526 {
5527         /*
5528          * Special check so that "ready" service can be moved before
5529          * "online" one.
5530          */
5531         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
5532                         b == CONNMAN_SERVICE_STATE_READY) ||
5533                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
5534                         a == CONNMAN_SERVICE_STATE_READY))
5535                 return true;
5536
5537         return a == b;
5538 }
5539
5540 static void downgrade_state(struct connman_service *service)
5541 {
5542         if (!service)
5543                 return;
5544
5545         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
5546                                                 service->state_ipv6);
5547
5548         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
5549                 __connman_service_ipconfig_indicate_state(service,
5550                                                 CONNMAN_SERVICE_STATE_READY,
5551                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
5552
5553         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
5554                 __connman_service_ipconfig_indicate_state(service,
5555                                                 CONNMAN_SERVICE_STATE_READY,
5556                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5557 }
5558
5559 static void apply_relevant_default_downgrade(struct connman_service *service)
5560 {
5561         struct connman_service *def_service;
5562
5563         def_service = __connman_service_get_default();
5564         if (!def_service)
5565                 return;
5566
5567         if (def_service == service &&
5568                         def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
5569                 def_service->state = CONNMAN_SERVICE_STATE_READY;
5570                 __connman_notifier_leave_online(def_service->type);
5571                 state_changed(def_service);
5572         }
5573 }
5574
5575 static void switch_default_service(struct connman_service *default_service,
5576                 struct connman_service *downgrade_service)
5577 {
5578         struct connman_service *service;
5579         GList *src, *dst;
5580
5581         apply_relevant_default_downgrade(default_service);
5582         src = g_list_find(service_list, downgrade_service);
5583         dst = g_list_find(service_list, default_service);
5584
5585         /* Nothing to do */
5586         if (src == dst || src->next == dst)
5587                 return;
5588
5589         service = src->data;
5590         service_list = g_list_delete_link(service_list, src);
5591         service_list = g_list_insert_before(service_list, dst, service);
5592
5593         downgrade_state(downgrade_service);
5594 }
5595
5596 static DBusMessage *move_service(DBusConnection *conn,
5597                                         DBusMessage *msg, void *user_data,
5598                                                                 bool before)
5599 {
5600         struct connman_service *service = user_data;
5601         struct connman_service *target;
5602         const char *path;
5603         enum connman_ipconfig_method target4, target6;
5604         enum connman_ipconfig_method service4, service6;
5605
5606         DBG("service %p", service);
5607
5608         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
5609                                                         DBUS_TYPE_INVALID);
5610
5611         if (!service->favorite)
5612                 return __connman_error_not_supported(msg);
5613
5614         target = find_service(path);
5615         if (!target || !target->favorite || target == service)
5616                 return __connman_error_invalid_service(msg);
5617
5618         if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
5619                 /*
5620                  * We only allow VPN route splitting if there are
5621                  * routes defined for a given VPN.
5622                  */
5623                 if (!__connman_provider_check_routes(target->provider)) {
5624                         connman_info("Cannot move service. "
5625                                 "No routes defined for provider %s",
5626                                 __connman_provider_get_ident(target->provider));
5627                         return __connman_error_invalid_service(msg);
5628                 }
5629
5630                 target->do_split_routing = true;
5631         } else
5632                 target->do_split_routing = false;
5633
5634         service->do_split_routing = false;
5635
5636         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
5637         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
5638         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
5639         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
5640
5641         DBG("target %s method %d/%d state %d/%d split %d", target->identifier,
5642                 target4, target6, target->state_ipv4, target->state_ipv6,
5643                 target->do_split_routing);
5644
5645         DBG("service %s method %d/%d state %d/%d", service->identifier,
5646                                 service4, service6,
5647                                 service->state_ipv4, service->state_ipv6);
5648
5649         /*
5650          * If method is OFF, then we do not need to check the corresponding
5651          * ipconfig state.
5652          */
5653         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5654                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5655                         if (!check_suitable_state(target->state_ipv6,
5656                                                         service->state_ipv6))
5657                                 return __connman_error_invalid_service(msg);
5658                 }
5659         }
5660
5661         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5662                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5663                         if (!check_suitable_state(target->state_ipv4,
5664                                                         service->state_ipv4))
5665                                 return __connman_error_invalid_service(msg);
5666                 }
5667         }
5668
5669         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5670                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5671                         if (!check_suitable_state(target->state_ipv6,
5672                                                         service->state_ipv6))
5673                                 return __connman_error_invalid_service(msg);
5674                 }
5675         }
5676
5677         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5678                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5679                         if (!check_suitable_state(target->state_ipv4,
5680                                                         service->state_ipv4))
5681                                 return __connman_error_invalid_service(msg);
5682                 }
5683         }
5684
5685         g_get_current_time(&service->modified);
5686         service_save(service);
5687         service_save(target);
5688
5689         /*
5690          * If the service which goes down is the default service and is
5691          * online, we downgrade directly its state to ready so:
5692          * the service which goes up, needs to recompute its state which
5693          * is triggered via downgrading it - if relevant - to state ready.
5694          */
5695         if (before)
5696                 switch_default_service(target, service);
5697         else
5698                 switch_default_service(service, target);
5699
5700         __connman_connection_update_gateway();
5701
5702         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5703 }
5704
5705 static DBusMessage *move_before(DBusConnection *conn,
5706                                         DBusMessage *msg, void *user_data)
5707 {
5708         return move_service(conn, msg, user_data, true);
5709 }
5710
5711 static DBusMessage *move_after(DBusConnection *conn,
5712                                         DBusMessage *msg, void *user_data)
5713 {
5714         return move_service(conn, msg, user_data, false);
5715 }
5716
5717 static DBusMessage *reset_counters(DBusConnection *conn,
5718                                         DBusMessage *msg, void *user_data)
5719 {
5720         struct connman_service *service = user_data;
5721
5722         reset_stats(service);
5723
5724         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5725 }
5726
5727 static DBusMessage *get_user_favorite(DBusConnection *conn,
5728                                         DBusMessage *msg, void *user_data)
5729 {
5730         DBusMessage *reply;
5731         uid_t uid = USER_NONE;
5732         dbus_bool_t user_favorite = false;
5733         struct connman_service *service = user_data;
5734
5735         connman_dbus_get_connection_unix_user_sync(conn,
5736                                         dbus_message_get_sender(msg),
5737                                         &uid);
5738         if (uid == USER_ROOT)
5739                 user_favorite = service->favorite;
5740         else if (uid != USER_NONE && uid == service->user.favorite_user) {
5741                 DBG("The service is favorite to this user!");
5742                 user_favorite = true;
5743         }
5744
5745         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5746         dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,
5747                                 &user_favorite, DBUS_TYPE_INVALID);
5748         return reply;
5749 }
5750
5751 static struct _services_notify {
5752         int id;
5753         GHashTable *add;
5754         GHashTable *remove;
5755 } *services_notify;
5756
5757 static void service_append_added_foreach(gpointer data, gpointer user_data)
5758 {
5759         struct connman_service *service = data;
5760         DBusMessageIter *iter = user_data;
5761
5762         if (!service || !service->path) {
5763 #if !defined TIZEN_EXT
5764                 DBG("service %p or path is NULL", service);
5765 #endif
5766                 return;
5767         }
5768
5769         if (g_hash_table_lookup(services_notify->add, service->path)) {
5770 #if !defined TIZEN_EXT
5771                 DBG("new %s", service->path);
5772 #endif
5773
5774                 append_struct(service, iter);
5775                 g_hash_table_remove(services_notify->add, service->path);
5776         } else {
5777 #if !defined TIZEN_EXT
5778                 DBG("changed %s", service->path);
5779 #endif
5780
5781                 append_struct_service(iter, NULL, service);
5782         }
5783 }
5784
5785 static void service_append_ordered(DBusMessageIter *iter, void *user_data)
5786 {
5787         g_list_foreach(service_list, service_append_added_foreach, iter);
5788 }
5789
5790 static void append_removed(gpointer key, gpointer value, gpointer user_data)
5791 {
5792         char *objpath = key;
5793         DBusMessageIter *iter = user_data;
5794
5795         DBG("removed %s", objpath);
5796         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
5797 }
5798
5799 static void service_append_removed(DBusMessageIter *iter, void *user_data)
5800 {
5801         g_hash_table_foreach(services_notify->remove, append_removed, iter);
5802 }
5803
5804 static gboolean service_send_changed(gpointer data)
5805 {
5806         DBusMessage *signal;
5807
5808         DBG("");
5809
5810         services_notify->id = 0;
5811
5812         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
5813                         CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
5814         if (!signal)
5815                 return FALSE;
5816
5817         __connman_dbus_append_objpath_dict_array(signal,
5818                                         service_append_ordered, NULL);
5819         __connman_dbus_append_objpath_array(signal,
5820                                         service_append_removed, NULL);
5821
5822         dbus_connection_send(connection, signal, NULL);
5823         dbus_message_unref(signal);
5824
5825         g_hash_table_remove_all(services_notify->remove);
5826         g_hash_table_remove_all(services_notify->add);
5827
5828         return FALSE;
5829 }
5830
5831 static void service_schedule_changed(void)
5832 {
5833         if (services_notify->id != 0)
5834                 return;
5835
5836         services_notify->id = g_timeout_add(100, service_send_changed, NULL);
5837 }
5838
5839 static void service_schedule_added(struct connman_service *service)
5840 {
5841         DBG("service %p", service);
5842
5843         g_hash_table_remove(services_notify->remove, service->path);
5844         g_hash_table_replace(services_notify->add, service->path, service);
5845
5846         service_schedule_changed();
5847 }
5848
5849 static void service_schedule_removed(struct connman_service *service)
5850 {
5851         if (!service || !service->path) {
5852                 DBG("service %p or path is NULL", service);
5853                 return;
5854         }
5855
5856         DBG("service %p %s", service, service->path);
5857
5858         g_hash_table_remove(services_notify->add, service->path);
5859         g_hash_table_replace(services_notify->remove, g_strdup(service->path),
5860                         NULL);
5861
5862         service_schedule_changed();
5863 }
5864
5865 static bool allow_property_changed(struct connman_service *service)
5866 {
5867 #if defined TIZEN_EXT
5868         if (service->path == NULL)
5869                 return FALSE;
5870 #endif
5871         if (g_hash_table_lookup_extended(services_notify->add, service->path,
5872                                         NULL, NULL)) {
5873                 DBG("no property updates for service %p", service);
5874                 return false;
5875         }
5876
5877         return true;
5878 }
5879
5880 static const GDBusMethodTable service_methods[] = {
5881         { GDBUS_DEPRECATED_METHOD("GetProperties",
5882                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
5883                         get_properties) },
5884         { GDBUS_METHOD("SetProperty",
5885                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
5886                         NULL, set_property) },
5887         { GDBUS_METHOD("ClearProperty",
5888                         GDBUS_ARGS({ "name", "s" }), NULL,
5889                         clear_property) },
5890         { GDBUS_ASYNC_METHOD("Connect", NULL, NULL,
5891                               connect_service) },
5892         { GDBUS_METHOD("Disconnect", NULL, NULL,
5893                         disconnect_service) },
5894         { GDBUS_METHOD("Remove", NULL, NULL, remove_service) },
5895         { GDBUS_METHOD("MoveBefore",
5896                         GDBUS_ARGS({ "service", "o" }), NULL,
5897                         move_before) },
5898         { GDBUS_METHOD("MoveAfter",
5899                         GDBUS_ARGS({ "service", "o" }), NULL,
5900                         move_after) },
5901         { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
5902         { GDBUS_METHOD("GetUserFavorite",
5903                         NULL, GDBUS_ARGS({ "value", "v" }),
5904                         get_user_favorite) },
5905         { },
5906 };
5907
5908 static const GDBusSignalTable service_signals[] = {
5909         { GDBUS_SIGNAL("PropertyChanged",
5910                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
5911         { },
5912 };
5913
5914 static void service_free(gpointer user_data)
5915 {
5916         struct connman_service *service = user_data;
5917         char *path = service->path;
5918
5919         DBG("service %p", service);
5920
5921         reply_pending(service, ENOENT);
5922
5923         __connman_notifier_service_remove(service);
5924         service_schedule_removed(service);
5925
5926         __connman_wispr_stop(service);
5927         stats_stop(service);
5928
5929         service->path = NULL;
5930
5931         if (path) {
5932                 __connman_connection_update_gateway();
5933
5934                 g_dbus_unregister_interface(connection, path,
5935                                                 CONNMAN_SERVICE_INTERFACE);
5936                 g_free(path);
5937         }
5938
5939         g_hash_table_destroy(service->counter_table);
5940
5941         if (service->network) {
5942                 __connman_network_disconnect(service->network);
5943                 connman_network_unref(service->network);
5944                 service->network = NULL;
5945         }
5946
5947         if (service->provider)
5948                 connman_provider_unref(service->provider);
5949
5950         if (service->ipconfig_ipv4) {
5951                 __connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
5952                 __connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
5953                 __connman_ipconfig_unref(service->ipconfig_ipv4);
5954                 service->ipconfig_ipv4 = NULL;
5955         }
5956
5957         if (service->ipconfig_ipv6) {
5958                 __connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
5959                 __connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
5960                 __connman_ipconfig_unref(service->ipconfig_ipv6);
5961                 service->ipconfig_ipv6 = NULL;
5962         }
5963
5964         g_strfreev(service->timeservers);
5965         g_strfreev(service->timeservers_config);
5966         g_strfreev(service->nameservers);
5967         g_strfreev(service->nameservers_config);
5968         g_strfreev(service->nameservers_auto);
5969         g_strfreev(service->domains);
5970         g_strfreev(service->proxies);
5971         g_strfreev(service->excludes);
5972
5973         g_free(service->hostname);
5974         g_free(service->domainname);
5975         g_free(service->pac);
5976         g_free(service->name);
5977         g_free(service->passphrase);
5978         g_free(service->identifier);
5979         g_free(service->eap);
5980         g_free(service->identity);
5981         g_free(service->agent_identity);
5982         g_free(service->ca_cert_file);
5983         g_free(service->client_cert_file);
5984         g_free(service->private_key_file);
5985         g_free(service->private_key_passphrase);
5986         g_free(service->phase2);
5987         g_free(service->config_file);
5988         g_free(service->config_entry);
5989
5990         if (service->stats.timer)
5991                 g_timer_destroy(service->stats.timer);
5992         if (service->stats_roaming.timer)
5993                 g_timer_destroy(service->stats_roaming.timer);
5994
5995         if (current_default == service)
5996                 current_default = NULL;
5997
5998         g_free(service);
5999 }
6000
6001 static void stats_init(struct connman_service *service)
6002 {
6003         /* home */
6004         service->stats.valid = false;
6005         service->stats.enabled = false;
6006         service->stats.timer = g_timer_new();
6007
6008         /* roaming */
6009         service->stats_roaming.valid = false;
6010         service->stats_roaming.enabled = false;
6011         service->stats_roaming.timer = g_timer_new();
6012 }
6013
6014 static void service_initialize(struct connman_service *service)
6015 {
6016         DBG("service %p", service);
6017
6018         service->refcount = 1;
6019
6020         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
6021
6022         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
6023         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
6024
6025         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
6026         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
6027         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
6028
6029         service->favorite  = false;
6030         service->immutable = false;
6031         service->hidden = false;
6032
6033         service->ignore = false;
6034
6035         service->user.favorite_user = USER_NONE;
6036         service->user.current_user = USER_NONE;
6037
6038         service->request_passphrase_input = false;
6039
6040         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
6041
6042         service->order = 0;
6043
6044         stats_init(service);
6045
6046         service->provider = NULL;
6047
6048         service->wps = false;
6049 #if defined TIZEN_EXT
6050         service->storage_reload = false;
6051         /*
6052          * Description: TIZEN implements system global connection management.
6053          */
6054         service->user_pdn_connection_refcount = 0;
6055         __sync_synchronize();
6056 #endif
6057 }
6058
6059 /**
6060  * connman_service_create:
6061  *
6062  * Allocate a new service.
6063  *
6064  * Returns: a newly-allocated #connman_service structure
6065  */
6066 struct connman_service *connman_service_create(void)
6067 {
6068         GSList *list;
6069         struct connman_stats_counter *counters;
6070         const char *counter;
6071
6072         struct connman_service *service;
6073
6074         service = g_try_new0(struct connman_service, 1);
6075         if (!service)
6076                 return NULL;
6077
6078         DBG("service %p", service);
6079
6080         service->counter_table = g_hash_table_new_full(g_str_hash,
6081                                                 g_str_equal, NULL, g_free);
6082
6083         for (list = counter_list; list; list = list->next) {
6084                 counter = list->data;
6085
6086                 counters = g_try_new0(struct connman_stats_counter, 1);
6087                 if (!counters) {
6088                         g_hash_table_destroy(service->counter_table);
6089                         g_free(service);
6090                         return NULL;
6091                 }
6092
6093                 counters->append_all = true;
6094
6095                 g_hash_table_replace(service->counter_table, (gpointer)counter,
6096                                 counters);
6097         }
6098
6099         service_initialize(service);
6100
6101         return service;
6102 }
6103
6104 /**
6105  * connman_service_ref:
6106  * @service: service structure
6107  *
6108  * Increase reference counter of service
6109  */
6110 struct connman_service *
6111 connman_service_ref_debug(struct connman_service *service,
6112                         const char *file, int line, const char *caller)
6113 {
6114         DBG("%p ref %d by %s:%d:%s()", service, service->refcount + 1,
6115                 file, line, caller);
6116
6117         __sync_fetch_and_add(&service->refcount, 1);
6118
6119         return service;
6120 }
6121
6122 /**
6123  * connman_service_unref:
6124  * @service: service structure
6125  *
6126  * Decrease reference counter of service and release service if no
6127  * longer needed.
6128  */
6129 void connman_service_unref_debug(struct connman_service *service,
6130                         const char *file, int line, const char *caller)
6131 {
6132         DBG("%p ref %d by %s:%d:%s()", service, service->refcount - 1,
6133                 file, line, caller);
6134
6135         if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
6136                 return;
6137
6138         service_list = g_list_remove(service_list, service);
6139
6140         __connman_service_disconnect(service);
6141
6142         g_hash_table_remove(service_hash, service->identifier);
6143 }
6144
6145 static gint service_compare(gconstpointer a, gconstpointer b)
6146 {
6147         struct connman_service *service_a = (void *) a;
6148         struct connman_service *service_b = (void *) b;
6149         enum connman_service_state state_a, state_b;
6150         bool a_connected, b_connected;
6151         gint strength;
6152
6153         state_a = service_a->state;
6154         state_b = service_b->state;
6155         a_connected = is_connected(service_a);
6156         b_connected = is_connected(service_b);
6157
6158         if (a_connected && b_connected) {
6159                 if (service_a->order > service_b->order)
6160                         return -1;
6161
6162                 if (service_a->order < service_b->order)
6163                         return 1;
6164         }
6165
6166         if (state_a != state_b) {
6167                 if (a_connected && b_connected) {
6168                         /* We prefer online over ready state */
6169                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
6170                                 return -1;
6171
6172                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
6173                                 return 1;
6174                 }
6175
6176                 if (a_connected)
6177                         return -1;
6178                 if (b_connected)
6179                         return 1;
6180
6181                 if (is_connecting(service_a))
6182                         return -1;
6183                 if (is_connecting(service_b))
6184                         return 1;
6185         }
6186
6187         if (service_a->favorite && !service_b->favorite)
6188                 return -1;
6189
6190         if (!service_a->favorite && service_b->favorite)
6191                 return 1;
6192
6193         if (service_a->type != service_b->type) {
6194
6195                 if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
6196                         return -1;
6197                 if (service_b->type == CONNMAN_SERVICE_TYPE_ETHERNET)
6198                         return 1;
6199
6200                 if (service_a->type == CONNMAN_SERVICE_TYPE_WIFI)
6201                         return -1;
6202                 if (service_b->type == CONNMAN_SERVICE_TYPE_WIFI)
6203                         return 1;
6204
6205                 if (service_a->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6206                         return -1;
6207                 if (service_b->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6208                         return 1;
6209
6210                 if (service_a->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
6211                         return -1;
6212                 if (service_b->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
6213                         return 1;
6214
6215                 if (service_a->type == CONNMAN_SERVICE_TYPE_VPN)
6216                         return -1;
6217                 if (service_b->type == CONNMAN_SERVICE_TYPE_VPN)
6218                         return 1;
6219
6220                 if (service_a->type == CONNMAN_SERVICE_TYPE_GADGET)
6221                         return -1;
6222                 if (service_b->type == CONNMAN_SERVICE_TYPE_GADGET)
6223                         return 1;
6224         }
6225
6226         strength = (gint) service_b->strength - (gint) service_a->strength;
6227         if (strength)
6228                 return strength;
6229
6230         return g_strcmp0(service_a->name, service_b->name);
6231 }
6232
6233 static void service_list_sort(void)
6234 {
6235         if (service_list && service_list->next) {
6236                 service_list = g_list_sort(service_list, service_compare);
6237                 service_schedule_changed();
6238         }
6239 }
6240
6241 /**
6242  * connman_service_get_type:
6243  * @service: service structure
6244  *
6245  * Get the type of service
6246  */
6247 enum connman_service_type connman_service_get_type(struct connman_service *service)
6248 {
6249         if (!service)
6250                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
6251
6252         return service->type;
6253 }
6254
6255 /**
6256  * connman_service_get_interface:
6257  * @service: service structure
6258  *
6259  * Get network interface of service
6260  */
6261 char *connman_service_get_interface(struct connman_service *service)
6262 {
6263         int index;
6264
6265         if (!service)
6266                 return NULL;
6267
6268         index = __connman_service_get_index(service);
6269
6270         return connman_inet_ifname(index);
6271 }
6272
6273 /**
6274  * __connman_service_is_user_allowed:
6275  * @type: service type
6276  * @uid: user id
6277  *
6278  * Check a user is allowed to operate a type of service
6279  */
6280 bool __connman_service_is_user_allowed(enum connman_service_type type,
6281                                         uid_t uid)
6282 {
6283         GList *list;
6284         uid_t owner_user = USER_NONE;
6285
6286         for (list = service_list; list; list = list->next) {
6287                 struct connman_service *service = list->data;
6288
6289                 if (service->type != type)
6290                         continue;
6291
6292                 if (is_connected(service)) {
6293                         owner_user = service->user.favorite_user;
6294                         break;
6295                 }
6296         }
6297
6298         if (uid == USER_NONE ||
6299                         (uid != USER_ROOT &&
6300                         owner_user != USER_NONE &&
6301                         owner_user != uid))
6302                 return false;
6303
6304         return true;
6305 }
6306
6307 /**
6308  * connman_service_get_network:
6309  * @service: service structure
6310  *
6311  * Get the service network
6312  */
6313 struct connman_network *
6314 __connman_service_get_network(struct connman_service *service)
6315 {
6316         if (!service)
6317                 return NULL;
6318
6319         return service->network;
6320 }
6321
6322 struct connman_ipconfig *
6323 __connman_service_get_ip4config(struct connman_service *service)
6324 {
6325         if (!service)
6326                 return NULL;
6327
6328         return service->ipconfig_ipv4;
6329 }
6330
6331 struct connman_ipconfig *
6332 __connman_service_get_ip6config(struct connman_service *service)
6333 {
6334         if (!service)
6335                 return NULL;
6336
6337         return service->ipconfig_ipv6;
6338 }
6339
6340 struct connman_ipconfig *
6341 __connman_service_get_ipconfig(struct connman_service *service, int family)
6342 {
6343         if (family == AF_INET)
6344                 return __connman_service_get_ip4config(service);
6345         else if (family == AF_INET6)
6346                 return __connman_service_get_ip6config(service);
6347         else
6348                 return NULL;
6349
6350 }
6351
6352 bool __connman_service_is_connected_state(struct connman_service *service,
6353                                         enum connman_ipconfig_type type)
6354 {
6355         if (!service)
6356                 return false;
6357
6358         switch (type) {
6359         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
6360                 break;
6361         case CONNMAN_IPCONFIG_TYPE_IPV4:
6362                 return is_connected_state(service, service->state_ipv4);
6363         case CONNMAN_IPCONFIG_TYPE_IPV6:
6364                 return is_connected_state(service, service->state_ipv6);
6365         case CONNMAN_IPCONFIG_TYPE_ALL:
6366                 return is_connected_state(service,
6367                                         CONNMAN_IPCONFIG_TYPE_IPV4) &&
6368                         is_connected_state(service,
6369                                         CONNMAN_IPCONFIG_TYPE_IPV6);
6370         }
6371
6372         return false;
6373 }
6374 enum connman_service_security __connman_service_get_security(
6375                                 struct connman_service *service)
6376 {
6377         if (!service)
6378                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
6379
6380         return service->security;
6381 }
6382
6383 const char *__connman_service_get_phase2(struct connman_service *service)
6384 {
6385         if (!service)
6386                 return NULL;
6387
6388         return service->phase2;
6389 }
6390
6391 bool __connman_service_wps_enabled(struct connman_service *service)
6392 {
6393         if (!service)
6394                 return false;
6395
6396         return service->wps;
6397 }
6398
6399 void __connman_service_mark_dirty(void)
6400 {
6401         services_dirty = true;
6402 }
6403
6404 #if defined TIZEN_EXT
6405 /**
6406   * Returns profile count if there is any connected profiles
6407   * that use same interface
6408   */
6409 int __connman_service_get_connected_count_of_iface(
6410                                         struct connman_service *service)
6411 {
6412         GList *list;
6413         int count = 0;
6414         int index1 = 0;
6415         int index2 = 0;
6416
6417         DBG("");
6418
6419         index1 = __connman_service_get_index(service);
6420
6421         if (index1 <= 0)
6422                 return 0;
6423
6424         for (list = service_list; list; list = list->next) {
6425                 struct connman_service *service2 = list->data;
6426
6427                 if (service == service2)
6428                         continue;
6429
6430                 index2 = __connman_service_get_index(service2);
6431
6432                 if (is_connected(service2) && index2 > 0 && index1 == index2)
6433                         count++;
6434
6435                 index2 = 0;
6436         }
6437
6438         DBG("Interface index %d, count %d", index1, count);
6439
6440         return count;
6441 }
6442
6443 void __connman_service_set_storage_reload(struct connman_service *service,
6444                                         bool storage_reload)
6445 {
6446         if (service != NULL)
6447                 service->storage_reload = storage_reload;
6448 }
6449 #endif
6450
6451 /**
6452  * __connman_service_set_favorite_delayed:
6453  * @service: service structure
6454  * @favorite: favorite value
6455  * @delay_ordering: do not order service sequence
6456  *
6457  * Change the favorite setting of service
6458  */
6459 int __connman_service_set_favorite_delayed(struct connman_service *service,
6460                                         bool favorite,
6461                                         bool delay_ordering)
6462 {
6463 #if defined TIZEN_EXT
6464         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6465                 return -EIO;
6466 #endif
6467         if (service->hidden)
6468                 return -EOPNOTSUPP;
6469
6470         if (service->favorite == favorite)
6471                 return -EALREADY;
6472
6473         service->favorite = favorite;
6474
6475         if (!delay_ordering)
6476                 __connman_service_get_order(service);
6477
6478         favorite_changed(service);
6479
6480         if (!delay_ordering) {
6481
6482                 service_list_sort();
6483
6484                 __connman_connection_update_gateway();
6485         }
6486
6487         return 0;
6488 }
6489
6490 /**
6491  * __connman_service_set_favorite:
6492  * @service: service structure
6493  * @favorite: favorite value
6494  *
6495  * Change the favorite setting of service
6496  */
6497 int __connman_service_set_favorite(struct connman_service *service,
6498                                                 bool favorite)
6499 {
6500         return __connman_service_set_favorite_delayed(service, favorite,
6501                                                         false);
6502 }
6503
6504 bool connman_service_get_favorite(struct connman_service *service)
6505 {
6506         return service->favorite;
6507 }
6508
6509 bool connman_service_get_autoconnect(struct connman_service *service)
6510 {
6511         return service->autoconnect;
6512 }
6513
6514 int __connman_service_set_immutable(struct connman_service *service,
6515                                                 bool immutable)
6516 {
6517         if (service->hidden)
6518                 return -EOPNOTSUPP;
6519
6520         if (service->immutable == immutable)
6521                 return 0;
6522
6523         service->immutable = immutable;
6524
6525         immutable_changed(service);
6526
6527         return 0;
6528 }
6529
6530 int __connman_service_set_ignore(struct connman_service *service,
6531                                                 bool ignore)
6532 {
6533         if (!service)
6534                 return -EINVAL;
6535
6536         service->ignore = ignore;
6537
6538         return 0;
6539 }
6540
6541 void __connman_service_set_string(struct connman_service *service,
6542                                   const char *key, const char *value)
6543 {
6544         if (service->hidden)
6545                 return;
6546         if (g_str_equal(key, "EAP")) {
6547                 g_free(service->eap);
6548                 service->eap = g_strdup(value);
6549         } else if (g_str_equal(key, "Identity")) {
6550                 g_free(service->identity);
6551                 service->identity = g_strdup(value);
6552         } else if (g_str_equal(key, "CACertFile")) {
6553                 g_free(service->ca_cert_file);
6554                 service->ca_cert_file = g_strdup(value);
6555         } else if (g_str_equal(key, "ClientCertFile")) {
6556                 g_free(service->client_cert_file);
6557                 service->client_cert_file = g_strdup(value);
6558         } else if (g_str_equal(key, "PrivateKeyFile")) {
6559                 g_free(service->private_key_file);
6560                 service->private_key_file = g_strdup(value);
6561         } else if (g_str_equal(key, "PrivateKeyPassphrase")) {
6562                 g_free(service->private_key_passphrase);
6563                 service->private_key_passphrase = g_strdup(value);
6564         } else if (g_str_equal(key, "Phase2")) {
6565                 g_free(service->phase2);
6566                 service->phase2 = g_strdup(value);
6567         } else if (g_str_equal(key, "Passphrase"))
6568                 __connman_service_set_passphrase(service, value);
6569 }
6570
6571 void __connman_service_set_search_domains(struct connman_service *service,
6572                                         char **domains)
6573 {
6574         searchdomain_remove_all(service);
6575
6576         if (service->domains)
6577                 g_strfreev(service->domains);
6578
6579         service->domains = g_strdupv(domains);
6580
6581         searchdomain_add_all(service);
6582 }
6583
6584 static void service_complete(struct connman_service *service)
6585 {
6586         reply_pending(service, EIO);
6587
6588         if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
6589                 __connman_service_auto_connect(service->connect_reason);
6590
6591         g_get_current_time(&service->modified);
6592         service_save(service);
6593 }
6594
6595 static void report_error_cb(void *user_context, bool retry,
6596                                                         void *user_data)
6597 {
6598         struct connman_service *service = user_context;
6599
6600         if (retry)
6601                 __connman_service_connect(service,
6602                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6603         else {
6604                 /* It is not relevant to stay on Failure state
6605                  * when failing is due to wrong user input */
6606                 __connman_service_clear_error(service);
6607 #if defined TIZEN_EXT
6608                 /* Reseting the state back in case of failure state */
6609                 service->state_ipv4 = service->state_ipv6 =
6610                                 CONNMAN_SERVICE_STATE_IDLE;
6611
6612                 if (service->error != CONNMAN_SERVICE_ERROR_AUTH_FAILED)
6613                         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6614 #endif
6615                 service_complete(service);
6616                 __connman_connection_update_gateway();
6617         }
6618 }
6619
6620 static int check_wpspin(struct connman_service *service, const char *wpspin)
6621 {
6622         int length;
6623         guint i;
6624
6625         if (!wpspin)
6626                 return 0;
6627
6628         length = strlen(wpspin);
6629
6630         /* If 0, it will mean user wants to use PBC method */
6631         if (length == 0) {
6632                 connman_network_set_string(service->network,
6633                                                         "WiFi.PinWPS", NULL);
6634                 return 0;
6635         }
6636
6637         /* A WPS PIN is always 8 chars length,
6638          * its content is in digit representation.
6639          */
6640         if (length != 8)
6641                 return -ENOKEY;
6642
6643         for (i = 0; i < 8; i++)
6644                 if (!isdigit((unsigned char) wpspin[i]))
6645                         return -ENOKEY;
6646
6647         connman_network_set_string(service->network, "WiFi.PinWPS", wpspin);
6648
6649         return 0;
6650 }
6651
6652 static void request_input_cb(struct connman_service *service,
6653                         bool values_received,
6654                         const char *name, int name_len,
6655                         const char *identity, const char *passphrase,
6656                         bool wps, const char *wpspin,
6657                         const char *error, void *user_data)
6658 {
6659         struct connman_device *device;
6660         const char *security;
6661         int err = 0;
6662
6663         DBG("RequestInput return, %p", service);
6664
6665         if (error) {
6666                 DBG("error: %s", error);
6667
6668                 if (g_strcmp0(error,
6669                                 "net.connman.Agent.Error.Canceled") == 0) {
6670                         err = -EINVAL;
6671
6672                         if (service->hidden)
6673                                 __connman_service_return_error(service,
6674                                                         ECANCELED, user_data);
6675                         goto done;
6676                 } else {
6677                         if (service->hidden)
6678                                 __connman_service_return_error(service,
6679                                                         ETIMEDOUT, user_data);
6680                 }
6681         }
6682
6683         if (service->hidden && name_len > 0 && name_len <= 32) {
6684                 device = connman_network_get_device(service->network);
6685                 security = connman_network_get_string(service->network,
6686                                                         "WiFi.Security");
6687                 err = __connman_device_request_hidden_scan(device,
6688                                                 name, name_len,
6689                                                 identity, passphrase,
6690                                                 security, user_data);
6691                 if (err < 0)
6692                         __connman_service_return_error(service, -err,
6693                                                         user_data);
6694         }
6695
6696         if (!values_received || service->hidden) {
6697                 err = -EINVAL;
6698                 goto done;
6699         }
6700
6701         if (wps && service->network) {
6702                 err = check_wpspin(service, wpspin);
6703                 if (err < 0)
6704                         goto done;
6705
6706                 connman_network_set_bool(service->network, "WiFi.UseWPS", wps);
6707         }
6708
6709         if (identity)
6710                 __connman_service_set_agent_identity(service, identity);
6711
6712         if (passphrase)
6713                 err = __connman_service_set_passphrase(service, passphrase);
6714
6715  done:
6716         if (err >= 0) {
6717                 /* We forget any previous error. */
6718                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6719
6720                 __connman_service_connect(service,
6721                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6722
6723         } else if (err == -ENOKEY) {
6724                 __connman_service_indicate_error(service,
6725                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
6726         } else {
6727                 /* It is not relevant to stay on Failure state
6728                  * when failing is due to wrong user input */
6729                 service->state = CONNMAN_SERVICE_STATE_IDLE;
6730
6731                 if (!service->hidden) {
6732                         /*
6733                          * If there was a real error when requesting
6734                          * hidden scan, then that error is returned already
6735                          * to the user somewhere above so do not try to
6736                          * do this again.
6737                          */
6738                         __connman_service_return_error(service, -err,
6739                                                         user_data);
6740                 }
6741
6742                 service_complete(service);
6743                 __connman_connection_update_gateway();
6744         }
6745 }
6746
6747 static void downgrade_connected_services(void)
6748 {
6749         struct connman_service *up_service;
6750         GList *list;
6751
6752         for (list = service_list; list; list = list->next) {
6753                 up_service = list->data;
6754
6755                 if (!is_connected(up_service))
6756                         continue;
6757
6758                 if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
6759                         return;
6760
6761                 downgrade_state(up_service);
6762         }
6763 }
6764
6765 static int service_update_preferred_order(struct connman_service *default_service,
6766                 struct connman_service *new_service,
6767                 enum connman_service_state new_state)
6768 {
6769         unsigned int *tech_array;
6770         int i;
6771
6772         if (!default_service || default_service == new_service ||
6773                         default_service->state != new_state)
6774                 return 0;
6775
6776         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
6777         if (tech_array) {
6778
6779                 for (i = 0; tech_array[i] != 0; i += 1) {
6780                         if (default_service->type == tech_array[i])
6781                                 return -EALREADY;
6782
6783                         if (new_service->type == tech_array[i]) {
6784                                 switch_default_service(default_service,
6785                                                 new_service);
6786                                 __connman_connection_update_gateway();
6787                                 return 0;
6788                         }
6789                 }
6790         }
6791
6792         return -EALREADY;
6793 }
6794
6795 #if defined TIZEN_EXT
6796 static gboolean __connman_service_can_drop(struct connman_service *service)
6797 {
6798         if (is_connected(service) == TRUE || is_connecting(service) == TRUE) {
6799                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
6800                         return TRUE;
6801                 else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE)
6802                         return TRUE;
6803         }
6804         return FALSE;
6805 }
6806
6807 static struct connman_device *default_connecting_device = NULL;
6808
6809 static void __connman_service_disconnect_default(struct connman_service *service)
6810 {
6811         struct connman_device *default_device = NULL;
6812
6813         if (default_connecting_device == NULL)
6814                 return;
6815
6816         default_device = connman_network_get_device(
6817                         __connman_service_get_network(service));
6818
6819         DBG("Disconnecting service %p %s", service, service->path);
6820         DBG("Disconnecting device %p %p %s",
6821                         default_connecting_device,
6822                         default_device,
6823                         connman_device_get_string(default_device, "Name"));
6824
6825         if (default_connecting_device == default_device)
6826                 default_connecting_device = NULL;
6827 }
6828
6829 static void __connman_service_connect_default(struct connman_service *current)
6830 {
6831         int err;
6832         GList *list;
6833         bool default_internet;
6834         struct connman_service *service;
6835         struct connman_service *default_service = NULL;
6836         struct connman_device *default_device = NULL;
6837
6838         if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
6839                 switch (current->state) {
6840                 case CONNMAN_SERVICE_STATE_UNKNOWN:
6841                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
6842                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
6843                         return;
6844                 default:
6845                         break;
6846                 }
6847
6848                 if (default_connecting_device &&
6849                                 __connman_service_is_internet_profile(current) == TRUE) {
6850                         if (current->network == NULL)
6851                                 return;
6852
6853                         default_device = connman_network_get_device(current->network);
6854                         if (default_connecting_device == default_device) {
6855                                 DBG("Cellular service[%s]  %p %s",
6856                                                 state2string(current->state), current, current->path);
6857                                 DBG("Cellular device %p %p %s",
6858                                                 default_connecting_device, default_device,
6859                                                 connman_device_get_string(default_device, "Name"));
6860
6861                                 default_connecting_device = NULL;
6862                         }
6863                 }
6864
6865                 return;
6866         } else if (is_connected(current) == TRUE || is_connecting(current) == TRUE)
6867                 return;
6868
6869         /* Always-on: keep default cellular connection as possible */
6870         for (list = service_list; list; list = list->next) {
6871                 service = list->data;
6872
6873                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6874                                 __connman_service_is_internet_profile(service) != TRUE ||
6875                                 service->network == NULL) {
6876                         continue;
6877                 }
6878
6879                 default_internet =
6880                                 connman_network_get_bool(service->network, "DefaultInternet");
6881
6882                 DBG("service: %p %s %s %s (default: %d)", service, service->name,
6883                                 __connman_service_type2string(service->type),
6884                                 state2string(service->state), default_internet);
6885
6886                 if (default_internet) {
6887                         default_service = service;
6888                         if (is_connected(default_service) == TRUE ||
6889                                         is_connecting(default_service) == TRUE)
6890                                 return;
6891
6892                         default_device = connman_network_get_device(default_service->network);
6893                         if (default_connecting_device == default_device) {
6894                                 DBG("Device is connecting (%p)", default_connecting_device);
6895                                 return;
6896                         }
6897
6898                         default_connecting_device = default_device;
6899                         default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
6900
6901                         err = __connman_network_connect(default_service->network);
6902                         DBG("Connecting default service %p %s [%d]",
6903                                         default_service, default_service->path, err);
6904                         DBG("Connecting device %p %s", default_connecting_device,
6905                                         connman_device_get_string(default_connecting_device, "Name"));
6906                         if (err < 0 && err != -EINPROGRESS) {
6907                                 default_connecting_device = NULL;
6908                         } else
6909                                 break;
6910                 }
6911         }
6912 }
6913 #endif
6914
6915 static void single_connected_tech(struct connman_service *allowed)
6916 {
6917         struct connman_service *service;
6918         GSList *services = NULL, *list;
6919         GList *iter;
6920
6921         DBG("keeping %p %s", allowed, allowed->path);
6922
6923 #if defined TIZEN_EXT
6924         if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6925                 return;
6926 #endif
6927
6928         for (iter = service_list; iter; iter = iter->next) {
6929                 service = iter->data;
6930
6931 #if defined TIZEN_EXT
6932                 if (service != allowed && service->type != allowed->type &&
6933                                 __connman_service_can_drop(service) == TRUE)
6934 #else
6935                 if (!is_connected(service))
6936                         break;
6937
6938                 if (service == allowed)
6939                         continue;
6940 #endif
6941                 services = g_slist_prepend(services, service);
6942         }
6943
6944         for (list = services; list; list = list->next) {
6945                 service = list->data;
6946
6947                 DBG("disconnecting %p %s", service, service->path);
6948 #if defined TIZEN_EXT
6949                 __connman_service_disconnect_default(service);
6950 #endif
6951                 __connman_service_disconnect(service);
6952         }
6953
6954         g_slist_free(services);
6955 }
6956
6957 #if defined TIZEN_EXT
6958 static void set_priority_connected_service(void)
6959 {
6960         struct connman_service *service;
6961         GList *list;
6962
6963         for (list = service_list; list; list = list->next) {
6964                 service = list->data;
6965
6966                 if (is_connected(service) == FALSE)
6967                         service->order = 5;
6968                 else
6969                         service->order = 6;
6970         }
6971 }
6972 #endif
6973
6974 static const char *get_dbus_sender(struct connman_service *service)
6975 {
6976         if (!service->pending)
6977                 return NULL;
6978
6979         return dbus_message_get_sender(service->pending);
6980 }
6981
6982 static int service_indicate_state(struct connman_service *service)
6983 {
6984         enum connman_service_state old_state, new_state;
6985         struct connman_service *def_service;
6986         enum connman_ipconfig_method method;
6987         int result;
6988
6989         if (!service)
6990                 return -EINVAL;
6991
6992         old_state = service->state;
6993         new_state = combine_state(service->state_ipv4, service->state_ipv6);
6994
6995         DBG("service %p old %s - new %s/%s => %s",
6996                                         service,
6997                                         state2string(old_state),
6998                                         state2string(service->state_ipv4),
6999                                         state2string(service->state_ipv6),
7000                                         state2string(new_state));
7001
7002         if (old_state == new_state)
7003                 return -EALREADY;
7004
7005         def_service = __connman_service_get_default();
7006
7007         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
7008                 result = service_update_preferred_order(def_service,
7009                                 service, new_state);
7010                 if (result == -EALREADY)
7011                         return result;
7012         }
7013
7014         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
7015                 __connman_notifier_leave_online(service->type);
7016
7017         if (is_connected_state(service, old_state) &&
7018                         !is_connected_state(service, new_state))
7019                 searchdomain_remove_all(service);
7020
7021         service->state = new_state;
7022         state_changed(service);
7023
7024         switch(new_state) {
7025         case CONNMAN_SERVICE_STATE_UNKNOWN:
7026
7027                 break;
7028
7029         case CONNMAN_SERVICE_STATE_IDLE:
7030                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
7031                         __connman_service_disconnect(service);
7032
7033                 break;
7034
7035         case CONNMAN_SERVICE_STATE_ASSOCIATION:
7036
7037                 break;
7038
7039         case CONNMAN_SERVICE_STATE_CONFIGURATION:
7040                 if (!service->new_service &&
7041                                 __connman_stats_service_register(service) == 0) {
7042                         /*
7043                          * For new services the statistics are updated after
7044                          * we have successfully connected.
7045                          */
7046                         __connman_stats_get(service, false,
7047                                                 &service->stats.data);
7048                         __connman_stats_get(service, true,
7049                                                 &service->stats_roaming.data);
7050                 }
7051
7052                 break;
7053
7054         case CONNMAN_SERVICE_STATE_READY:
7055                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7056
7057                 if (service->new_service &&
7058                                 __connman_stats_service_register(service) == 0) {
7059                         /*
7060                          * This is normally done after configuring state
7061                          * but for new service do this after we have connected
7062                          * successfully.
7063                          */
7064                         __connman_stats_get(service, false,
7065                                                 &service->stats.data);
7066                         __connman_stats_get(service, true,
7067                                                 &service->stats_roaming.data);
7068                 }
7069
7070                 service->new_service = false;
7071
7072                 default_changed();
7073
7074                 def_service = __connman_service_get_default();
7075
7076                 service_update_preferred_order(def_service, service, new_state);
7077
7078                 __connman_service_set_favorite(service, true);
7079
7080                 reply_pending(service, 0);
7081
7082                 g_get_current_time(&service->modified);
7083                 service_save(service);
7084
7085                 searchdomain_add_all(service);
7086                 dns_changed(service);
7087                 domain_changed(service);
7088                 proxy_changed(service);
7089
7090                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
7091                         __connman_notifier_connect(service->type);
7092
7093                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7094                         connman_network_get_bool(service->network,
7095                                                 "WiFi.UseWPS")) {
7096                         const char *pass;
7097
7098                         pass = connman_network_get_string(service->network,
7099                                                         "WiFi.Passphrase");
7100
7101                         __connman_service_set_passphrase(service, pass);
7102
7103                         connman_network_set_bool(service->network,
7104                                                         "WiFi.UseWPS", false);
7105                 }
7106
7107                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
7108                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
7109                         __connman_ipconfig_disable_ipv6(
7110                                                 service->ipconfig_ipv6);
7111
7112                 if (connman_setting_get_bool("SingleConnectedTechnology"))
7113                         single_connected_tech(service);
7114                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
7115                         vpn_auto_connect();
7116
7117 #if defined TIZEN_EXT
7118                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7119                         set_priority_connected_service();
7120 #endif
7121
7122                 break;
7123
7124         case CONNMAN_SERVICE_STATE_ONLINE:
7125
7126                 break;
7127
7128         case CONNMAN_SERVICE_STATE_DISCONNECT:
7129                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7130
7131                 reply_pending(service, ECONNABORTED);
7132
7133                 def_service = __connman_service_get_default();
7134                 service->disconnect_reason = connman_network_get_disconnect_reason(service->network);
7135
7136                 if (!__connman_notifier_is_connected() &&
7137                         def_service &&
7138                                 def_service->provider)
7139                         connman_provider_disconnect(def_service->provider);
7140
7141                 default_changed();
7142
7143                 __connman_wispr_stop(service);
7144
7145                 __connman_wpad_stop(service);
7146
7147 #if defined TIZEN_EXT
7148                 /**
7149                   * Skip the functions if there is any connected profiles
7150                   * that use same interface
7151                   */
7152                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7153                         __connman_service_get_connected_count_of_iface(
7154                                                         service) <= 0) {
7155 #endif
7156                 dns_changed(service);
7157                 domain_changed(service);
7158                 proxy_changed(service);
7159 #if defined TIZEN_EXT
7160                 }
7161 #endif
7162
7163                 /*
7164                  * Previous services which are connected and which states
7165                  * are set to online should reset relevantly ipconfig_state
7166                  * to ready so wispr/portal will be rerun on those
7167                  */
7168                 downgrade_connected_services();
7169
7170                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7171                 break;
7172
7173         case CONNMAN_SERVICE_STATE_FAILURE:
7174 #if defined TIZEN_EXT
7175                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7176                         service->order = 5;
7177                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7178 #endif
7179                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
7180                         connman_agent_report_error(service, service->path,
7181                                         error2string(service->error),
7182                                         report_error_cb,
7183                                         get_dbus_sender(service),
7184                                         NULL) == -EINPROGRESS)
7185                         return 0;
7186                 service_complete(service);
7187
7188                 break;
7189         }
7190
7191         service_list_sort();
7192
7193 #if defined TIZEN_EXT
7194         __connman_service_connect_default(service);
7195 #endif
7196
7197         __connman_connection_update_gateway();
7198
7199         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
7200                         new_state != CONNMAN_SERVICE_STATE_READY) ||
7201                 (old_state == CONNMAN_SERVICE_STATE_READY &&
7202                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
7203                 __connman_notifier_disconnect(service->type);
7204         }
7205
7206         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
7207                 __connman_notifier_enter_online(service->type);
7208                 default_changed();
7209         }
7210
7211         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7212                 service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
7213                 (new_state == CONNMAN_SERVICE_STATE_READY ||
7214                 new_state == CONNMAN_SERVICE_STATE_ONLINE)) {
7215                 if (service->user.favorite_user != service->user.current_user) {
7216                         DBG("Now set service favorite user id from %d to %d",
7217                         service->user.favorite_user, service->user.current_user);
7218
7219                         service->user.favorite_user = service->user.current_user;
7220
7221                         service_save(service);
7222                 }
7223         }
7224
7225         return 0;
7226 }
7227
7228 int __connman_service_indicate_error(struct connman_service *service,
7229                                         enum connman_service_error error)
7230 {
7231         DBG("service %p error %d", service, error);
7232
7233         if (!service)
7234                 return -EINVAL;
7235
7236         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
7237                 return -EALREADY;
7238
7239         set_error(service, error);
7240
7241 /* default internet service: fix not cleared if pdp activation*/
7242 #if defined TIZEN_EXT
7243                 /*
7244                  * If connection failed for default service(DefaultInternet),
7245                  * default_connecting_device should be cleared.
7246                  */
7247                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7248                                 service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED)
7249                         __connman_service_disconnect_default(service);
7250
7251                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7252                                 service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) {
7253                         g_free(service->passphrase);
7254                         service->passphrase = NULL;
7255                 }
7256 #endif
7257
7258         __connman_service_ipconfig_indicate_state(service,
7259                                                 CONNMAN_SERVICE_STATE_FAILURE,
7260                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7261         __connman_service_ipconfig_indicate_state(service,
7262                                                 CONNMAN_SERVICE_STATE_FAILURE,
7263                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7264         return 0;
7265 }
7266
7267 int __connman_service_clear_error(struct connman_service *service)
7268 {
7269         DBusMessage *pending, *provider_pending;
7270
7271         DBG("service %p", service);
7272
7273         if (!service)
7274                 return -EINVAL;
7275
7276         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
7277                 return -EINVAL;
7278
7279         pending = service->pending;
7280         service->pending = NULL;
7281         provider_pending = service->provider_pending;
7282         service->provider_pending = NULL;
7283
7284         __connman_service_ipconfig_indicate_state(service,
7285                                                 CONNMAN_SERVICE_STATE_IDLE,
7286                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7287
7288         __connman_service_ipconfig_indicate_state(service,
7289                                                 CONNMAN_SERVICE_STATE_IDLE,
7290                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7291
7292         service->pending = pending;
7293         service->provider_pending = provider_pending;
7294
7295         return 0;
7296 }
7297
7298 int __connman_service_indicate_default(struct connman_service *service)
7299 {
7300         DBG("service %p state %s", service, state2string(service->state));
7301
7302         if (!is_connected(service)) {
7303                 /*
7304                  * If service is not yet fully connected, then we must not
7305                  * change the default yet. The default gw will be changed
7306                  * after the service state is in ready.
7307                  */
7308                 return -EINPROGRESS;
7309         }
7310
7311         default_changed();
7312
7313         return 0;
7314 }
7315
7316 enum connman_service_state __connman_service_ipconfig_get_state(
7317                                         struct connman_service *service,
7318                                         enum connman_ipconfig_type type)
7319 {
7320         if (!service)
7321                 return CONNMAN_SERVICE_STATE_UNKNOWN;
7322
7323         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7324                 return service->state_ipv4;
7325
7326         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
7327                 return service->state_ipv6;
7328
7329         return CONNMAN_SERVICE_STATE_UNKNOWN;
7330 }
7331
7332 static void check_proxy_setup(struct connman_service *service)
7333 {
7334         /*
7335          * We start WPAD if we haven't got a PAC URL from DHCP and
7336          * if our proxy manual configuration is either empty or set
7337          * to AUTO with an empty URL.
7338          */
7339
7340         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
7341                 goto done;
7342
7343         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
7344                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
7345                         service->pac))
7346                 goto done;
7347
7348         if (__connman_wpad_start(service) < 0) {
7349                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
7350                 __connman_notifier_proxy_changed(service);
7351                 goto done;
7352         }
7353
7354         return;
7355
7356 done:
7357         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
7358 }
7359
7360 #if defined TIZEN_EXT
7361 void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
7362
7363         DBG("check the proxy and start wispr");
7364         check_proxy_setup(service);
7365         return;
7366 }
7367 #endif
7368
7369 /*
7370  * How many networks are connected at the same time. If more than 1,
7371  * then set the rp_filter setting properly (loose mode routing) so that network
7372  * connectivity works ok. This is only done for IPv4 networks as IPv6
7373  * does not have rp_filter knob.
7374  */
7375 static int connected_networks_count;
7376 static int original_rp_filter;
7377
7378 static void service_rp_filter(struct connman_service *service,
7379                                 bool connected)
7380 {
7381         enum connman_ipconfig_method method;
7382
7383         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
7384
7385         switch (method) {
7386         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
7387         case CONNMAN_IPCONFIG_METHOD_OFF:
7388         case CONNMAN_IPCONFIG_METHOD_AUTO:
7389                 return;
7390         case CONNMAN_IPCONFIG_METHOD_FIXED:
7391         case CONNMAN_IPCONFIG_METHOD_MANUAL:
7392         case CONNMAN_IPCONFIG_METHOD_DHCP:
7393                 break;
7394         }
7395
7396         if (connected) {
7397                 if (connected_networks_count == 1) {
7398                         int filter_value;
7399                         filter_value = __connman_ipconfig_set_rp_filter();
7400                         if (filter_value < 0)
7401                                 return;
7402
7403                         original_rp_filter = filter_value;
7404                 }
7405                 connected_networks_count++;
7406
7407         } else {
7408                 if (connected_networks_count == 2)
7409                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
7410
7411                 connected_networks_count--;
7412                 if (connected_networks_count < 0)
7413                         connected_networks_count = 0;
7414         }
7415
7416         DBG("%s %s ipconfig %p method %d count %d filter %d",
7417                 connected ? "connected" : "disconnected", service->identifier,
7418                 service->ipconfig_ipv4, method,
7419                 connected_networks_count, original_rp_filter);
7420 }
7421
7422 static gboolean redo_wispr(gpointer user_data)
7423 {
7424         struct connman_service *service = user_data;
7425         int refcount = service->refcount - 1;
7426
7427         connman_service_unref(service);
7428         if (refcount == 0) {
7429                 DBG("Service %p already removed", service);
7430                 return FALSE;
7431         }
7432
7433         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
7434
7435         return FALSE;
7436 }
7437
7438 int __connman_service_online_check_failed(struct connman_service *service,
7439                                         enum connman_ipconfig_type type)
7440 {
7441         DBG("service %p type %d count %d", service, type,
7442                                                 service->online_check_count);
7443
7444         /* currently we only retry IPv6 stuff */
7445         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
7446                         service->online_check_count != 1) {
7447                 connman_warn("Online check failed for %p %s", service,
7448                         service->name);
7449                 return 0;
7450         }
7451
7452         service->online_check_count = 0;
7453
7454         /*
7455          * We set the timeout to 1 sec so that we have a chance to get
7456          * necessary IPv6 router advertisement messages that might have
7457          * DNS data etc.
7458          */
7459         g_timeout_add_seconds(1, redo_wispr, connman_service_ref(service));
7460
7461         return EAGAIN;
7462 }
7463
7464 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
7465                                         enum connman_service_state new_state,
7466                                         enum connman_ipconfig_type type)
7467 {
7468         struct connman_ipconfig *ipconfig = NULL;
7469         enum connman_service_state old_state;
7470         enum connman_ipconfig_method method;
7471
7472         if (!service)
7473                 return -EINVAL;
7474
7475         switch (type) {
7476         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
7477         case CONNMAN_IPCONFIG_TYPE_ALL:
7478                 return -EINVAL;
7479
7480         case CONNMAN_IPCONFIG_TYPE_IPV4:
7481                 old_state = service->state_ipv4;
7482                 ipconfig = service->ipconfig_ipv4;
7483
7484                 break;
7485
7486         case CONNMAN_IPCONFIG_TYPE_IPV6:
7487                 old_state = service->state_ipv6;
7488                 ipconfig = service->ipconfig_ipv6;
7489
7490                 break;
7491         }
7492
7493         if (!ipconfig)
7494                 return -EINVAL;
7495
7496         /* Any change? */
7497         if (old_state == new_state)
7498                 return -EALREADY;
7499
7500 #if defined TIZEN_EXT
7501         __sync_synchronize();
7502         if (service->user_pdn_connection_refcount > 0 &&
7503                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7504                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
7505                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
7506                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
7507                         service->user_pdn_connection_refcount = 0;
7508                         __sync_synchronize();
7509                 }
7510 #endif
7511
7512         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
7513                 service, service ? service->identifier : NULL,
7514                 old_state, state2string(old_state),
7515                 new_state, state2string(new_state),
7516                 type, __connman_ipconfig_type2string(type));
7517
7518         switch (new_state) {
7519         case CONNMAN_SERVICE_STATE_UNKNOWN:
7520         case CONNMAN_SERVICE_STATE_IDLE:
7521         case CONNMAN_SERVICE_STATE_ASSOCIATION:
7522                 break;
7523         case CONNMAN_SERVICE_STATE_CONFIGURATION:
7524                 __connman_ipconfig_enable(ipconfig);
7525                 break;
7526         case CONNMAN_SERVICE_STATE_READY:
7527 #if defined TIZEN_EXT
7528                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7529                                 __connman_service_is_internet_profile(service) != TRUE) {
7530                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7531                                 service_rp_filter(service, TRUE);
7532
7533                         break;
7534                 }
7535 #endif
7536                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
7537 #if !defined TIZEN_EXT
7538                         check_proxy_setup(service);
7539 #endif
7540                         service_rp_filter(service, true);
7541                 } else {
7542                         service->online_check_count = 1;
7543                         __connman_wispr_start(service, type);
7544                 }
7545                 break;
7546         case CONNMAN_SERVICE_STATE_ONLINE:
7547                 break;
7548         case CONNMAN_SERVICE_STATE_DISCONNECT:
7549                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
7550                         return -EINVAL;
7551
7552                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7553                         service_rp_filter(service, false);
7554
7555                 break;
7556         case CONNMAN_SERVICE_STATE_FAILURE:
7557                 break;
7558         }
7559
7560         /* Keep that state, but if the ipconfig method is OFF, then we set
7561            the state to IDLE so that it will not affect the combined state
7562            in the future.
7563          */
7564         method = __connman_ipconfig_get_method(ipconfig);
7565         switch (method) {
7566         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
7567         case CONNMAN_IPCONFIG_METHOD_OFF:
7568                 new_state = CONNMAN_SERVICE_STATE_IDLE;
7569                 break;
7570
7571         case CONNMAN_IPCONFIG_METHOD_FIXED:
7572         case CONNMAN_IPCONFIG_METHOD_MANUAL:
7573         case CONNMAN_IPCONFIG_METHOD_DHCP:
7574         case CONNMAN_IPCONFIG_METHOD_AUTO:
7575                 break;
7576
7577         }
7578
7579         if (is_connected_state(service, old_state) &&
7580                         !is_connected_state(service, new_state))
7581 #if defined TIZEN_EXT
7582         {
7583                 DBG("nameserver remove all, type: %d", type);
7584                 nameserver_remove_all(service, type);
7585 #else
7586                 nameserver_remove_all(service);
7587 #endif
7588 #if defined TIZEN_EXT
7589         }
7590 #endif
7591
7592         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7593                 service->state_ipv4 = new_state;
7594         else
7595                 service->state_ipv6 = new_state;
7596
7597         if (!is_connected_state(service, old_state) &&
7598                         is_connected_state(service, new_state))
7599 #if defined TIZEN_EXT
7600         {
7601                 DBG("nameserver add all, type: %d", type);
7602                 nameserver_add_all(service, type);
7603 #else
7604                 nameserver_add_all(service);
7605 #endif
7606 #if defined TIZEN_EXT
7607         }
7608 #endif
7609
7610 #if defined TIZEN_EXT
7611         int ret = service_indicate_state(service);
7612         /*Sent the Ready changed signal again in case IPv4 IP set
7613           after IPv6 IP set*/
7614
7615         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
7616                         && new_state == CONNMAN_SERVICE_STATE_READY) {
7617                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
7618                 state_changed(service);
7619         }
7620
7621         return ret;
7622 #endif
7623         return service_indicate_state(service);
7624 }
7625
7626 static bool prepare_network(struct connman_service *service)
7627 {
7628         enum connman_network_type type;
7629         unsigned int ssid_len;
7630
7631         type = connman_network_get_type(service->network);
7632
7633         switch (type) {
7634         case CONNMAN_NETWORK_TYPE_UNKNOWN:
7635         case CONNMAN_NETWORK_TYPE_VENDOR:
7636                 return false;
7637         case CONNMAN_NETWORK_TYPE_WIFI:
7638                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
7639                                                 &ssid_len))
7640                         return false;
7641
7642                 if (service->passphrase)
7643                         connman_network_set_string(service->network,
7644                                 "WiFi.Passphrase", service->passphrase);
7645                 break;
7646         case CONNMAN_NETWORK_TYPE_ETHERNET:
7647         case CONNMAN_NETWORK_TYPE_GADGET:
7648         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
7649         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
7650         case CONNMAN_NETWORK_TYPE_CELLULAR:
7651                 break;
7652         }
7653
7654         return true;
7655 }
7656
7657 static void prepare_8021x(struct connman_service *service)
7658 {
7659         if (service->eap)
7660                 connman_network_set_string(service->network, "WiFi.EAP",
7661                                                                 service->eap);
7662
7663         if (service->identity)
7664                 connman_network_set_string(service->network, "WiFi.Identity",
7665                                                         service->identity);
7666
7667         if (service->ca_cert_file)
7668                 connman_network_set_string(service->network, "WiFi.CACertFile",
7669                                                         service->ca_cert_file);
7670
7671         if (service->client_cert_file)
7672                 connman_network_set_string(service->network,
7673                                                 "WiFi.ClientCertFile",
7674                                                 service->client_cert_file);
7675
7676         if (service->private_key_file)
7677                 connman_network_set_string(service->network,
7678                                                 "WiFi.PrivateKeyFile",
7679                                                 service->private_key_file);
7680
7681         if (service->private_key_passphrase)
7682                 connman_network_set_string(service->network,
7683                                         "WiFi.PrivateKeyPassphrase",
7684                                         service->private_key_passphrase);
7685
7686         if (service->phase2)
7687                 connman_network_set_string(service->network, "WiFi.Phase2",
7688                                                         service->phase2);
7689 }
7690
7691 static int service_connect(struct connman_service *service)
7692 {
7693         int err;
7694
7695         if (service->hidden)
7696                 return -EPERM;
7697
7698 #if defined TIZEN_EXT
7699         GList *list;
7700         int index;
7701
7702         index = __connman_service_get_index(service);
7703
7704         for (list = service_list; list; list = list->next) {
7705                 struct connman_service *temp = list->data;
7706
7707                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7708                         break;
7709
7710                 if (!is_connecting(temp) && !is_connected(temp))
7711                         break;
7712
7713                 if (service == temp)
7714                         continue;
7715
7716                 if (service->type != temp->type)
7717                         continue;
7718
7719                 if (__connman_service_get_index(temp) == index &&
7720                                 __connman_service_disconnect(temp) == -EINPROGRESS)
7721                         return -EINPROGRESS;
7722         }
7723 #endif
7724
7725         switch (service->type) {
7726         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7727         case CONNMAN_SERVICE_TYPE_SYSTEM:
7728         case CONNMAN_SERVICE_TYPE_GPS:
7729         case CONNMAN_SERVICE_TYPE_P2P:
7730                 return -EINVAL;
7731         case CONNMAN_SERVICE_TYPE_ETHERNET:
7732         case CONNMAN_SERVICE_TYPE_GADGET:
7733         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7734         case CONNMAN_SERVICE_TYPE_CELLULAR:
7735         case CONNMAN_SERVICE_TYPE_VPN:
7736                 break;
7737         case CONNMAN_SERVICE_TYPE_WIFI:
7738                 switch (service->security) {
7739                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7740                 case CONNMAN_SERVICE_SECURITY_NONE:
7741                         break;
7742                 case CONNMAN_SERVICE_SECURITY_WEP:
7743                 case CONNMAN_SERVICE_SECURITY_PSK:
7744                 case CONNMAN_SERVICE_SECURITY_WPA:
7745                 case CONNMAN_SERVICE_SECURITY_RSN:
7746                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7747                                 return -ENOKEY;
7748
7749                         if (service->request_passphrase_input) {
7750                                 DBG("Now try to connect other user's favorite service");
7751                                 service->request_passphrase_input = false;
7752                                 return -ENOKEY;
7753                         } else if (!service->passphrase) {
7754                                 if (!service->network)
7755                                         return -EOPNOTSUPP;
7756
7757                                 if (!service->wps ||
7758                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
7759                                         return -ENOKEY;
7760                         }
7761                         break;
7762
7763                 case CONNMAN_SERVICE_SECURITY_8021X:
7764                         if (!service->eap)
7765                                 return -EINVAL;
7766
7767 #if defined TIZEN_EXT
7768                         /*
7769                          * never request credentials if using EAP-TLS, EAP-SIM
7770                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
7771                          * need to be fully provisioned)
7772                          */
7773                         DBG("service eap: %s", service->eap);
7774                         if (g_str_equal(service->eap, "tls") ||
7775                                 g_str_equal(service->eap, "sim") ||
7776                                 g_str_equal(service->eap, "aka"))
7777                                 break;
7778 #else
7779                         /*
7780                          * never request credentials if using EAP-TLS
7781                          * (EAP-TLS networks need to be fully provisioned)
7782                          */
7783                         if (g_str_equal(service->eap, "tls"))
7784                                 break;
7785 #endif
7786                         /*
7787                          * Return -ENOKEY if either identity or passphrase is
7788                          * missing. Agent provided credentials can be used as
7789                          * fallback if needed.
7790                          */
7791                         if (((!service->identity &&
7792                                         !service->agent_identity) ||
7793                                         !service->passphrase) ||
7794                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7795                                 return -ENOKEY;
7796
7797                         break;
7798                 }
7799                 break;
7800         }
7801
7802         if (service->network) {
7803                 if (!prepare_network(service))
7804                         return -EINVAL;
7805
7806                 switch (service->security) {
7807                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7808                 case CONNMAN_SERVICE_SECURITY_NONE:
7809                 case CONNMAN_SERVICE_SECURITY_WEP:
7810                 case CONNMAN_SERVICE_SECURITY_PSK:
7811                 case CONNMAN_SERVICE_SECURITY_WPA:
7812                 case CONNMAN_SERVICE_SECURITY_RSN:
7813                         break;
7814                 case CONNMAN_SERVICE_SECURITY_8021X:
7815                         prepare_8021x(service);
7816                         break;
7817                 }
7818
7819                 if (__connman_stats_service_register(service) == 0) {
7820                         __connman_stats_get(service, false,
7821                                                 &service->stats.data);
7822                         __connman_stats_get(service, true,
7823                                                 &service->stats_roaming.data);
7824                 }
7825
7826                 if (service->ipconfig_ipv4)
7827                         __connman_ipconfig_enable(service->ipconfig_ipv4);
7828                 if (service->ipconfig_ipv6)
7829                         __connman_ipconfig_enable(service->ipconfig_ipv6);
7830
7831                 err = __connman_network_connect(service->network);
7832         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7833                                         service->provider)
7834                 err = __connman_provider_connect(service->provider);
7835         else
7836                 return -EOPNOTSUPP;
7837
7838         if (err < 0) {
7839                 if (err != -EINPROGRESS) {
7840                         __connman_ipconfig_disable(service->ipconfig_ipv4);
7841                         __connman_ipconfig_disable(service->ipconfig_ipv6);
7842                         __connman_stats_service_unregister(service);
7843                 }
7844         }
7845
7846         return err;
7847 }
7848
7849 int __connman_service_connect(struct connman_service *service,
7850                         enum connman_service_connect_reason reason)
7851 {
7852         int err;
7853
7854         DBG("service %p state %s connect reason %s -> %s",
7855                 service, state2string(service->state),
7856                 reason2string(service->connect_reason),
7857                 reason2string(reason));
7858
7859         if (is_connected(service))
7860                 return -EISCONN;
7861
7862         if (is_connecting(service))
7863                 return -EALREADY;
7864
7865         switch (service->type) {
7866         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7867         case CONNMAN_SERVICE_TYPE_SYSTEM:
7868         case CONNMAN_SERVICE_TYPE_GPS:
7869         case CONNMAN_SERVICE_TYPE_P2P:
7870                 return -EINVAL;
7871
7872         case CONNMAN_SERVICE_TYPE_ETHERNET:
7873         case CONNMAN_SERVICE_TYPE_GADGET:
7874         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7875         case CONNMAN_SERVICE_TYPE_CELLULAR:
7876         case CONNMAN_SERVICE_TYPE_VPN:
7877         case CONNMAN_SERVICE_TYPE_WIFI:
7878                 break;
7879         }
7880
7881         if (!is_ipconfig_usable(service))
7882                 return -ENOLINK;
7883
7884         __connman_service_clear_error(service);
7885
7886         err = service_connect(service);
7887
7888         service->connect_reason = reason;
7889         if (err >= 0)
7890                 return 0;
7891
7892         if (err == -EINPROGRESS) {
7893                 if (service->timeout == 0)
7894                         service->timeout = g_timeout_add_seconds(
7895                                 CONNECT_TIMEOUT, connect_timeout, service);
7896
7897                 return -EINPROGRESS;
7898         }
7899
7900         if (service->network)
7901                 __connman_network_disconnect(service->network);
7902         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7903                                 service->provider)
7904                         connman_provider_disconnect(service->provider);
7905
7906         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
7907                 if (err == -ENOKEY || err == -EPERM) {
7908                         DBusMessage *pending = NULL;
7909
7910                         /*
7911                          * We steal the reply here. The idea is that the
7912                          * connecting client will see the connection status
7913                          * after the real hidden network is connected or
7914                          * connection failed.
7915                          */
7916                         if (service->hidden) {
7917                                 pending = service->pending;
7918                                 service->pending = NULL;
7919                         }
7920
7921                         err = __connman_agent_request_passphrase_input(service,
7922                                         request_input_cb,
7923                                         get_dbus_sender(service),
7924                                         pending);
7925                         if (service->hidden && err != -EINPROGRESS)
7926                                 service->pending = pending;
7927
7928                         return err;
7929                 }
7930                 reply_pending(service, -err);
7931         }
7932
7933         return err;
7934 }
7935
7936 int __connman_service_disconnect(struct connman_service *service)
7937 {
7938         int err;
7939
7940         DBG("service %p", service);
7941
7942         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
7943         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
7944
7945         connman_agent_cancel(service);
7946
7947         reply_pending(service, ECONNABORTED);
7948
7949         if (service->network) {
7950                 err = __connman_network_disconnect(service->network);
7951         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7952                                         service->provider)
7953                 err = connman_provider_disconnect(service->provider);
7954         else
7955                 return -EOPNOTSUPP;
7956
7957         if (err < 0 && err != -EINPROGRESS)
7958                 return err;
7959
7960         __connman_6to4_remove(service->ipconfig_ipv4);
7961
7962         if (service->ipconfig_ipv4)
7963                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
7964                                                         NULL);
7965         else
7966                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
7967                                                         NULL);
7968
7969 #if defined TIZEN_EXT
7970         /**
7971           * Skip the functions If there is any connected profiles
7972           * that use same interface
7973           */
7974         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7975                 __connman_service_get_connected_count_of_iface(service) <= 0) {
7976 #endif
7977         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
7978         settings_changed(service, service->ipconfig_ipv4);
7979
7980         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
7981         settings_changed(service, service->ipconfig_ipv6);
7982
7983         __connman_ipconfig_disable(service->ipconfig_ipv4);
7984         __connman_ipconfig_disable(service->ipconfig_ipv6);
7985 #if defined TIZEN_EXT
7986         }
7987 #endif
7988
7989         __connman_stats_service_unregister(service);
7990
7991         return err;
7992 }
7993
7994 int __connman_service_disconnect_all(void)
7995 {
7996         struct connman_service *service;
7997         GSList *services = NULL, *list;
7998         GList *iter;
7999
8000         DBG("");
8001
8002         for (iter = service_list; iter; iter = iter->next) {
8003                 service = iter->data;
8004
8005                 if (!is_connected(service))
8006                         break;
8007
8008                 services = g_slist_prepend(services, service);
8009         }
8010
8011         for (list = services; list; list = list->next) {
8012                 struct connman_service *service = list->data;
8013
8014                 service->ignore = true;
8015
8016                 __connman_service_disconnect(service);
8017         }
8018
8019         g_slist_free(services);
8020
8021         return 0;
8022 }
8023
8024 /**
8025  * lookup_by_identifier:
8026  * @identifier: service identifier
8027  *
8028  * Look up a service by identifier (reference count will not be increased)
8029  */
8030 static struct connman_service *lookup_by_identifier(const char *identifier)
8031 {
8032         return g_hash_table_lookup(service_hash, identifier);
8033 }
8034
8035 struct provision_user_data {
8036         const char *ident;
8037         int ret;
8038 };
8039
8040 static void provision_changed(gpointer value, gpointer user_data)
8041 {
8042         struct connman_service *service = value;
8043         struct provision_user_data *data = user_data;
8044         const char *path = data->ident;
8045         int ret;
8046
8047         ret = __connman_config_provision_service_ident(service, path,
8048                         service->config_file, service->config_entry);
8049         if (ret > 0)
8050                 data->ret = ret;
8051 }
8052
8053 int __connman_service_provision_changed(const char *ident)
8054 {
8055         struct provision_user_data data = {
8056                 .ident = ident,
8057                 .ret = 0
8058         };
8059
8060         g_list_foreach(service_list, provision_changed, (void *)&data);
8061
8062         /*
8063          * Because the provision_changed() might have set some services
8064          * as favorite, we must sort the sequence now.
8065          */
8066         if (services_dirty) {
8067                 services_dirty = false;
8068
8069                 service_list_sort();
8070
8071                 __connman_connection_update_gateway();
8072         }
8073
8074         return data.ret;
8075 }
8076
8077 void __connman_service_set_config(struct connman_service *service,
8078                                 const char *file_id, const char *entry)
8079 {
8080         if (!service)
8081                 return;
8082
8083         g_free(service->config_file);
8084         service->config_file = g_strdup(file_id);
8085
8086         g_free(service->config_entry);
8087         service->config_entry = g_strdup(entry);
8088 }
8089
8090 /**
8091  * __connman_service_get:
8092  * @identifier: service identifier
8093  *
8094  * Look up a service by identifier or create a new one if not found
8095  */
8096 static struct connman_service *service_get(const char *identifier)
8097 {
8098         struct connman_service *service;
8099
8100         service = g_hash_table_lookup(service_hash, identifier);
8101         if (service) {
8102                 connman_service_ref(service);
8103                 return service;
8104         }
8105
8106         service = connman_service_create();
8107         if (!service)
8108                 return NULL;
8109
8110         DBG("service %p", service);
8111
8112         service->identifier = g_strdup(identifier);
8113
8114         service_list = g_list_insert_sorted(service_list, service,
8115                                                 service_compare);
8116
8117         g_hash_table_insert(service_hash, service->identifier, service);
8118
8119         return service;
8120 }
8121
8122 static int service_register(struct connman_service *service)
8123 {
8124         DBG("service %p", service);
8125
8126         if (service->path)
8127                 return -EALREADY;
8128
8129         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
8130                                                 service->identifier);
8131
8132         DBG("path %s", service->path);
8133
8134         if (__connman_config_provision_service(service) < 0)
8135                 service_load(service);
8136
8137         g_dbus_register_interface(connection, service->path,
8138                                         CONNMAN_SERVICE_INTERFACE,
8139                                         service_methods, service_signals,
8140                                                         NULL, service, NULL);
8141
8142         service_list_sort();
8143
8144         __connman_connection_update_gateway();
8145
8146         return 0;
8147 }
8148
8149 static void service_up(struct connman_ipconfig *ipconfig,
8150                 const char *ifname)
8151 {
8152         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8153
8154         DBG("%s up", ifname);
8155
8156         link_changed(service);
8157
8158         service->stats.valid = false;
8159         service->stats_roaming.valid = false;
8160 }
8161
8162 static void service_down(struct connman_ipconfig *ipconfig,
8163                         const char *ifname)
8164 {
8165         DBG("%s down", ifname);
8166 }
8167
8168 static void service_lower_up(struct connman_ipconfig *ipconfig,
8169                         const char *ifname)
8170 {
8171         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8172
8173         DBG("%s lower up", ifname);
8174
8175         stats_start(service);
8176 }
8177
8178 static void service_lower_down(struct connman_ipconfig *ipconfig,
8179                         const char *ifname)
8180 {
8181         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8182
8183         DBG("%s lower down", ifname);
8184
8185         if (!is_idle_state(service, service->state_ipv4))
8186                 __connman_ipconfig_disable(service->ipconfig_ipv4);
8187
8188         if (!is_idle_state(service, service->state_ipv6))
8189                 __connman_ipconfig_disable(service->ipconfig_ipv6);
8190
8191         stats_stop(service);
8192         service_save(service);
8193 }
8194
8195 static void service_ip_bound(struct connman_ipconfig *ipconfig,
8196                         const char *ifname)
8197 {
8198         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8199         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
8200         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
8201 #if defined TIZEN_EXT
8202         int err;
8203 #endif
8204
8205         DBG("%s ip bound", ifname);
8206
8207         type = __connman_ipconfig_get_config_type(ipconfig);
8208         method = __connman_ipconfig_get_method(ipconfig);
8209
8210         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
8211                                                         type, method);
8212
8213         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
8214                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
8215 #if defined TIZEN_EXT
8216         {
8217                 err = __connman_ipconfig_gateway_add(ipconfig, service);
8218
8219                 if(err == 0)
8220                         __connman_connection_gateway_activate(service,
8221                                         CONNMAN_IPCONFIG_TYPE_IPV6);
8222         }
8223 #else
8224                 __connman_service_ipconfig_indicate_state(service,
8225                                                 CONNMAN_SERVICE_STATE_READY,
8226                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
8227 #endif
8228
8229         settings_changed(service, ipconfig);
8230 }
8231
8232 static void service_ip_release(struct connman_ipconfig *ipconfig,
8233                         const char *ifname)
8234 {
8235         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8236         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
8237         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
8238
8239         DBG("%s ip release", ifname);
8240
8241         type = __connman_ipconfig_get_config_type(ipconfig);
8242         method = __connman_ipconfig_get_method(ipconfig);
8243
8244         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
8245                                                         type, method);
8246
8247         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
8248                         method == CONNMAN_IPCONFIG_METHOD_OFF)
8249                 __connman_service_ipconfig_indicate_state(service,
8250                                         CONNMAN_SERVICE_STATE_DISCONNECT,
8251                                         CONNMAN_IPCONFIG_TYPE_IPV6);
8252
8253         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
8254                         method == CONNMAN_IPCONFIG_METHOD_OFF)
8255                 __connman_service_ipconfig_indicate_state(service,
8256                                         CONNMAN_SERVICE_STATE_DISCONNECT,
8257                                         CONNMAN_IPCONFIG_TYPE_IPV4);
8258
8259         settings_changed(service, ipconfig);
8260 }
8261
8262 static void service_route_changed(struct connman_ipconfig *ipconfig,
8263                                 const char *ifname)
8264 {
8265         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8266
8267         DBG("%s route changed", ifname);
8268
8269         settings_changed(service, ipconfig);
8270 }
8271
8272 static const struct connman_ipconfig_ops service_ops = {
8273         .up             = service_up,
8274         .down           = service_down,
8275         .lower_up       = service_lower_up,
8276         .lower_down     = service_lower_down,
8277         .ip_bound       = service_ip_bound,
8278         .ip_release     = service_ip_release,
8279         .route_set      = service_route_changed,
8280         .route_unset    = service_route_changed,
8281 };
8282
8283 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
8284                 int index, enum connman_ipconfig_method method)
8285 {
8286         struct connman_ipconfig *ipconfig_ipv4;
8287
8288         ipconfig_ipv4 = __connman_ipconfig_create(index,
8289                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
8290         if (!ipconfig_ipv4)
8291                 return NULL;
8292
8293         __connman_ipconfig_set_method(ipconfig_ipv4, method);
8294
8295         __connman_ipconfig_set_data(ipconfig_ipv4, service);
8296
8297         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
8298
8299         return ipconfig_ipv4;
8300 }
8301
8302 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
8303                 int index)
8304 {
8305         struct connman_ipconfig *ipconfig_ipv6;
8306
8307         ipconfig_ipv6 = __connman_ipconfig_create(index,
8308                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
8309         if (!ipconfig_ipv6)
8310                 return NULL;
8311
8312         __connman_ipconfig_set_data(ipconfig_ipv6, service);
8313
8314         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
8315
8316         return ipconfig_ipv6;
8317 }
8318
8319 void __connman_service_read_ip4config(struct connman_service *service)
8320 {
8321         GKeyFile *keyfile;
8322
8323         if (!service->ipconfig_ipv4)
8324                 return;
8325
8326         keyfile = connman_storage_load_service(service->identifier);
8327         if (!keyfile)
8328                 return;
8329
8330         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
8331                                 service->identifier, "IPv4.");
8332
8333         g_key_file_free(keyfile);
8334 }
8335
8336 void connman_service_create_ip4config(struct connman_service *service,
8337                                         int index)
8338 {
8339         DBG("ipv4 %p", service->ipconfig_ipv4);
8340
8341         if (service->ipconfig_ipv4)
8342                 return;
8343
8344         service->ipconfig_ipv4 = create_ip4config(service, index,
8345                         CONNMAN_IPCONFIG_METHOD_DHCP);
8346         __connman_service_read_ip4config(service);
8347 }
8348
8349 void __connman_service_read_ip6config(struct connman_service *service)
8350 {
8351         GKeyFile *keyfile;
8352
8353         if (!service->ipconfig_ipv6)
8354                 return;
8355
8356         keyfile = connman_storage_load_service(service->identifier);
8357         if (!keyfile)
8358                 return;
8359
8360         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
8361                                 service->identifier, "IPv6.");
8362
8363         g_key_file_free(keyfile);
8364 }
8365
8366 void connman_service_create_ip6config(struct connman_service *service,
8367                                                                 int index)
8368 {
8369         DBG("ipv6 %p", service->ipconfig_ipv6);
8370
8371         if (service->ipconfig_ipv6)
8372                 return;
8373
8374         service->ipconfig_ipv6 = create_ip6config(service, index);
8375
8376         __connman_service_read_ip6config(service);
8377 }
8378
8379 /**
8380  * connman_service_lookup_from_network:
8381  * @network: network structure
8382  *
8383  * Look up a service by network (reference count will not be increased)
8384  */
8385 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
8386 {
8387         struct connman_service *service;
8388         const char *ident, *group;
8389         char *name;
8390
8391         if (!network)
8392                 return NULL;
8393
8394         ident = __connman_network_get_ident(network);
8395         if (!ident)
8396                 return NULL;
8397
8398         group = connman_network_get_group(network);
8399         if (!group)
8400                 return NULL;
8401
8402         name = g_strdup_printf("%s_%s_%s",
8403                         __connman_network_get_type(network), ident, group);
8404         service = lookup_by_identifier(name);
8405         g_free(name);
8406
8407         return service;
8408 }
8409
8410 struct connman_service *__connman_service_lookup_from_index(int index)
8411 {
8412         struct connman_service *service;
8413         GList *list;
8414
8415         for (list = service_list; list; list = list->next) {
8416                 service = list->data;
8417
8418                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
8419                                                         == index)
8420                         return service;
8421
8422                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
8423                                                         == index)
8424                         return service;
8425         }
8426
8427         return NULL;
8428 }
8429
8430 struct connman_service *__connman_service_lookup_from_ident(const char *identifier)
8431 {
8432         return lookup_by_identifier(identifier);
8433 }
8434
8435 const char *__connman_service_get_ident(struct connman_service *service)
8436 {
8437         return service->identifier;
8438 }
8439
8440 const char *__connman_service_get_path(struct connman_service *service)
8441 {
8442         return service->path;
8443 }
8444
8445 const char *__connman_service_get_name(struct connman_service *service)
8446 {
8447         return service->name;
8448 }
8449
8450 enum connman_service_state __connman_service_get_state(struct connman_service *service)
8451 {
8452         return service->state;
8453 }
8454
8455 unsigned int __connman_service_get_order(struct connman_service *service)
8456 {
8457         unsigned int order = 0;
8458
8459         if (!service)
8460                 return 0;
8461
8462         service->order = 0;
8463
8464         if (!service->favorite)
8465                 return 0;
8466
8467 #if defined TIZEN_EXT
8468         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
8469                         service->do_split_routing == FALSE)
8470                 order = 10;
8471         else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
8472                 if (service->order < 5)
8473                         order = 5;
8474         } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
8475                 order = 4;
8476         else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
8477                 order = 3;
8478         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
8479                         __connman_service_is_internet_profile(service) == TRUE)
8480                 order = 1;
8481         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
8482                         __connman_service_is_tethering_profile(service) == TRUE)
8483                 order = 0;
8484         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
8485                 order = 0;
8486         else
8487                 order = 2;
8488 #else
8489         if (service == service_list->data)
8490                 order = 1;
8491
8492         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
8493                         !service->do_split_routing) {
8494                 service->order = 10;
8495                 order = 10;
8496         }
8497 #endif
8498         DBG("service %p name %s order %d split %d", service, service->name,
8499                 order, service->do_split_routing);
8500
8501         return order;
8502 }
8503
8504 void __connman_service_update_ordering(void)
8505 {
8506         if (service_list && service_list->next)
8507                 service_list = g_list_sort(service_list, service_compare);
8508 }
8509
8510 static enum connman_service_type convert_network_type(struct connman_network *network)
8511 {
8512         enum connman_network_type type = connman_network_get_type(network);
8513
8514         switch (type) {
8515         case CONNMAN_NETWORK_TYPE_UNKNOWN:
8516         case CONNMAN_NETWORK_TYPE_VENDOR:
8517                 break;
8518         case CONNMAN_NETWORK_TYPE_ETHERNET:
8519                 return CONNMAN_SERVICE_TYPE_ETHERNET;
8520         case CONNMAN_NETWORK_TYPE_WIFI:
8521                 return CONNMAN_SERVICE_TYPE_WIFI;
8522         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
8523         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
8524                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
8525         case CONNMAN_NETWORK_TYPE_CELLULAR:
8526                 return CONNMAN_SERVICE_TYPE_CELLULAR;
8527         case CONNMAN_NETWORK_TYPE_GADGET:
8528                 return CONNMAN_SERVICE_TYPE_GADGET;
8529         }
8530
8531         return CONNMAN_SERVICE_TYPE_UNKNOWN;
8532 }
8533
8534 static enum connman_service_security convert_wifi_security(const char *security)
8535 {
8536         if (!security)
8537                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
8538         else if (g_str_equal(security, "none"))
8539                 return CONNMAN_SERVICE_SECURITY_NONE;
8540         else if (g_str_equal(security, "wep"))
8541                 return CONNMAN_SERVICE_SECURITY_WEP;
8542         else if (g_str_equal(security, "psk"))
8543                 return CONNMAN_SERVICE_SECURITY_PSK;
8544         else if (g_str_equal(security, "ieee8021x"))
8545                 return CONNMAN_SERVICE_SECURITY_8021X;
8546         else if (g_str_equal(security, "wpa"))
8547                 return CONNMAN_SERVICE_SECURITY_WPA;
8548         else if (g_str_equal(security, "rsn"))
8549                 return CONNMAN_SERVICE_SECURITY_RSN;
8550 #if defined TIZEN_EXT
8551         else if (g_str_equal(security, "ft_psk") == TRUE)
8552                 return CONNMAN_SERVICE_SECURITY_PSK;
8553         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
8554                 return CONNMAN_SERVICE_SECURITY_8021X;
8555 #endif
8556         else
8557                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
8558 }
8559
8560 static void update_from_network(struct connman_service *service,
8561                                         struct connman_network *network)
8562 {
8563         uint8_t strength = service->strength;
8564         const char *str;
8565
8566         DBG("service %p network %p", service, network);
8567
8568         if (is_connected(service))
8569                 return;
8570
8571         if (is_connecting(service))
8572                 return;
8573
8574         str = connman_network_get_string(network, "Name");
8575         if (str) {
8576                 g_free(service->name);
8577                 service->name = g_strdup(str);
8578                 service->hidden = false;
8579         } else {
8580                 g_free(service->name);
8581                 service->name = NULL;
8582                 service->hidden = true;
8583         }
8584
8585         service->strength = connman_network_get_strength(network);
8586         service->roaming = connman_network_get_bool(network, "Roaming");
8587
8588         if (service->strength == 0) {
8589                 /*
8590                  * Filter out 0-values; it's unclear what they mean
8591                  * and they cause anomalous sorting of the priority list.
8592                  */
8593                 service->strength = strength;
8594         }
8595
8596         str = connman_network_get_string(network, "WiFi.Security");
8597         service->security = convert_wifi_security(str);
8598
8599         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8600                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
8601
8602         if (service->strength > strength && service->network) {
8603                 connman_network_unref(service->network);
8604                 service->network = connman_network_ref(network);
8605
8606                 strength_changed(service);
8607         }
8608
8609         if (!service->network)
8610                 service->network = connman_network_ref(network);
8611
8612         service_list_sort();
8613 }
8614
8615 /**
8616  * __connman_service_create_from_network:
8617  * @network: network structure
8618  *
8619  * Look up service by network and if not found, create one
8620  */
8621 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
8622 {
8623         struct connman_service *service;
8624         struct connman_device *device;
8625         const char *ident, *group;
8626         char *name;
8627         unsigned int *auto_connect_types;
8628         int i, index;
8629
8630         DBG("network %p", network);
8631
8632         if (!network)
8633                 return NULL;
8634
8635         ident = __connman_network_get_ident(network);
8636         if (!ident)
8637                 return NULL;
8638
8639         group = connman_network_get_group(network);
8640         if (!group)
8641                 return NULL;
8642
8643         name = g_strdup_printf("%s_%s_%s",
8644                         __connman_network_get_type(network), ident, group);
8645         service = service_get(name);
8646         g_free(name);
8647
8648         if (!service)
8649                 return NULL;
8650
8651         if (__connman_network_get_weakness(network))
8652                 return service;
8653
8654         if (service->path) {
8655                 update_from_network(service, network);
8656                 __connman_connection_update_gateway();
8657                 return service;
8658         }
8659
8660         service->type = convert_network_type(network);
8661
8662         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
8663         service->autoconnect = false;
8664         for (i = 0; auto_connect_types &&
8665                      auto_connect_types[i] != 0; i++) {
8666                 if (service->type == auto_connect_types[i]) {
8667                         service->autoconnect = true;
8668                         break;
8669                 }
8670         }
8671
8672         switch (service->type) {
8673         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8674         case CONNMAN_SERVICE_TYPE_SYSTEM:
8675         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8676         case CONNMAN_SERVICE_TYPE_GPS:
8677         case CONNMAN_SERVICE_TYPE_VPN:
8678         case CONNMAN_SERVICE_TYPE_GADGET:
8679         case CONNMAN_SERVICE_TYPE_WIFI:
8680         case CONNMAN_SERVICE_TYPE_CELLULAR:
8681         case CONNMAN_SERVICE_TYPE_P2P:
8682                 break;
8683         case CONNMAN_SERVICE_TYPE_ETHERNET:
8684                 service->favorite = true;
8685                 break;
8686         }
8687
8688         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8689         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8690
8691         update_from_network(service, network);
8692
8693         index = connman_network_get_index(network);
8694
8695         if (!service->ipconfig_ipv4)
8696                 service->ipconfig_ipv4 = create_ip4config(service, index,
8697                                 CONNMAN_IPCONFIG_METHOD_DHCP);
8698
8699         if (!service->ipconfig_ipv6)
8700                 service->ipconfig_ipv6 = create_ip6config(service, index);
8701
8702         service_register(service);
8703
8704         if (service->favorite) {
8705                 device = connman_network_get_device(service->network);
8706                 if (device && !connman_device_get_scanning(device)) {
8707
8708                         switch (service->type) {
8709                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8710                         case CONNMAN_SERVICE_TYPE_SYSTEM:
8711                         case CONNMAN_SERVICE_TYPE_P2P:
8712                                 break;
8713
8714                         case CONNMAN_SERVICE_TYPE_GADGET:
8715                         case CONNMAN_SERVICE_TYPE_ETHERNET:
8716                                 if (service->autoconnect) {
8717                                         __connman_service_connect(service,
8718                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8719                                         break;
8720                                 }
8721
8722                                 /* fall through */
8723                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8724                         case CONNMAN_SERVICE_TYPE_GPS:
8725                         case CONNMAN_SERVICE_TYPE_VPN:
8726                         case CONNMAN_SERVICE_TYPE_WIFI:
8727                         case CONNMAN_SERVICE_TYPE_CELLULAR:
8728                                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8729                                 break;
8730                         }
8731                 }
8732
8733 #if defined TIZEN_EXT
8734                 /* TIZEN synchronizes below information when the service creates */
8735                 if (service->eap != NULL)
8736                         connman_network_set_string(service->network, "WiFi.EAP",
8737                                                                 service->eap);
8738                 if (service->identity != NULL)
8739                         connman_network_set_string(service->network, "WiFi.Identity",
8740                                                                 service->identity);
8741                 if (service->phase2 != NULL)
8742                         connman_network_set_string(service->network, "WiFi.Phase2",
8743                                                                 service->phase2);
8744 #endif
8745         }
8746
8747         __connman_notifier_service_add(service, service->name);
8748         service_schedule_added(service);
8749
8750         return service;
8751 }
8752
8753 void __connman_service_update_from_network(struct connman_network *network)
8754 {
8755         bool need_sort = false;
8756         struct connman_service *service;
8757         uint8_t strength;
8758         bool roaming;
8759         const char *name;
8760         bool stats_enable;
8761
8762         service = connman_service_lookup_from_network(network);
8763         if (!service)
8764                 return;
8765
8766         if (!service->network)
8767                 return;
8768
8769 #if defined TIZEN_EXT
8770         if (service->storage_reload) {
8771                 service_load(service);
8772                 __connman_service_set_storage_reload(service, false);
8773         }
8774 #endif
8775
8776         name = connman_network_get_string(service->network, "Name");
8777         if (g_strcmp0(service->name, name) != 0) {
8778                 g_free(service->name);
8779                 service->name = g_strdup(name);
8780
8781                 if (allow_property_changed(service))
8782                         connman_dbus_property_changed_basic(service->path,
8783                                         CONNMAN_SERVICE_INTERFACE, "Name",
8784                                         DBUS_TYPE_STRING, &service->name);
8785         }
8786
8787         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8788                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
8789
8790         strength = connman_network_get_strength(service->network);
8791         if (strength == service->strength)
8792                 goto roaming;
8793
8794         service->strength = strength;
8795         need_sort = true;
8796
8797         strength_changed(service);
8798
8799 roaming:
8800         roaming = connman_network_get_bool(service->network, "Roaming");
8801         if (roaming == service->roaming)
8802                 goto sorting;
8803
8804         stats_enable = stats_enabled(service);
8805         if (stats_enable)
8806                 stats_stop(service);
8807
8808         service->roaming = roaming;
8809         need_sort = true;
8810
8811         if (stats_enable)
8812                 stats_start(service);
8813
8814         roaming_changed(service);
8815
8816 sorting:
8817         if (need_sort) {
8818                 service_list_sort();
8819         }
8820 }
8821
8822 void __connman_service_remove_from_network(struct connman_network *network)
8823 {
8824         struct connman_service *service;
8825
8826         service = connman_service_lookup_from_network(network);
8827
8828         DBG("network %p service %p", network, service);
8829
8830         if (!service)
8831                 return;
8832
8833         service->ignore = true;
8834
8835         __connman_connection_gateway_remove(service,
8836                                         CONNMAN_IPCONFIG_TYPE_ALL);
8837
8838         connman_service_unref(service);
8839 }
8840
8841 /**
8842  * __connman_service_create_from_provider:
8843  * @provider: provider structure
8844  *
8845  * Look up service by provider and if not found, create one
8846  */
8847 struct connman_service *
8848 __connman_service_create_from_provider(struct connman_provider *provider)
8849 {
8850         struct connman_service *service;
8851         const char *ident, *str;
8852         char *name;
8853         int index = connman_provider_get_index(provider);
8854
8855         DBG("provider %p", provider);
8856
8857         ident = __connman_provider_get_ident(provider);
8858         if (!ident)
8859                 return NULL;
8860
8861         name = g_strdup_printf("vpn_%s", ident);
8862         service = service_get(name);
8863         g_free(name);
8864
8865         if (!service)
8866                 return NULL;
8867
8868         service->type = CONNMAN_SERVICE_TYPE_VPN;
8869         service->provider = connman_provider_ref(provider);
8870         service->autoconnect = false;
8871         service->favorite = true;
8872
8873         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8874         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8875
8876         str = connman_provider_get_string(provider, "Name");
8877         if (str) {
8878                 g_free(service->name);
8879                 service->name = g_strdup(str);
8880                 service->hidden = false;
8881         } else {
8882                 g_free(service->name);
8883                 service->name = NULL;
8884                 service->hidden = true;
8885         }
8886
8887         service->strength = 0;
8888
8889         if (!service->ipconfig_ipv4)
8890                 service->ipconfig_ipv4 = create_ip4config(service, index,
8891                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
8892
8893         if (!service->ipconfig_ipv6)
8894                 service->ipconfig_ipv6 = create_ip6config(service, index);
8895
8896         service_register(service);
8897
8898         __connman_notifier_service_add(service, service->name);
8899         service_schedule_added(service);
8900
8901         return service;
8902 }
8903
8904 static void remove_unprovisioned_services(void)
8905 {
8906         gchar **services;
8907         GKeyFile *keyfile, *configkeyfile;
8908         char *file, *section;
8909         int i = 0;
8910
8911         services = connman_storage_get_services();
8912         if (!services)
8913                 return;
8914
8915         for (; services[i]; i++) {
8916                 file = section = NULL;
8917                 keyfile = configkeyfile = NULL;
8918
8919                 keyfile = connman_storage_load_service(services[i]);
8920                 if (!keyfile)
8921                         continue;
8922
8923                 file = g_key_file_get_string(keyfile, services[i],
8924                                         "Config.file", NULL);
8925                 if (!file)
8926                         goto next;
8927
8928                 section = g_key_file_get_string(keyfile, services[i],
8929                                         "Config.ident", NULL);
8930                 if (!section)
8931                         goto next;
8932
8933                 configkeyfile = __connman_storage_load_config(file);
8934                 if (!configkeyfile) {
8935                         /*
8936                          * Config file is missing, remove the provisioned
8937                          * service.
8938                          */
8939                         __connman_storage_remove_service(services[i]);
8940                         goto next;
8941                 }
8942
8943                 if (!g_key_file_has_group(configkeyfile, section))
8944                         /*
8945                          * Config section is missing, remove the provisioned
8946                          * service.
8947                          */
8948                         __connman_storage_remove_service(services[i]);
8949
8950         next:
8951                 if (keyfile)
8952                         g_key_file_free(keyfile);
8953
8954                 if (configkeyfile)
8955                         g_key_file_free(configkeyfile);
8956
8957                 g_free(section);
8958                 g_free(file);
8959         }
8960
8961         g_strfreev(services);
8962 }
8963
8964 static int agent_probe(struct connman_agent *agent)
8965 {
8966         DBG("agent %p", agent);
8967         return 0;
8968 }
8969
8970 static void agent_remove(struct connman_agent *agent)
8971 {
8972         DBG("agent %p", agent);
8973 }
8974
8975 static void *agent_context_ref(void *context)
8976 {
8977         struct connman_service *service = context;
8978
8979         return (void *)connman_service_ref(service);
8980 }
8981
8982 static void agent_context_unref(void *context)
8983 {
8984         struct connman_service *service = context;
8985
8986         connman_service_unref(service);
8987 }
8988
8989 static struct connman_agent_driver agent_driver = {
8990         .name           = "service",
8991         .interface      = CONNMAN_AGENT_INTERFACE,
8992         .probe          = agent_probe,
8993         .remove         = agent_remove,
8994         .context_ref    = agent_context_ref,
8995         .context_unref  = agent_context_unref,
8996 };
8997
8998 int __connman_service_init(void)
8999 {
9000         int err;
9001
9002         DBG("");
9003
9004         err = connman_agent_driver_register(&agent_driver);
9005         if (err < 0) {
9006                 connman_error("Cannot register agent driver for %s",
9007                                                 agent_driver.name);
9008                 return err;
9009         }
9010
9011         connection = connman_dbus_get_connection();
9012
9013         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
9014                                                         NULL, service_free);
9015
9016         services_notify = g_new0(struct _services_notify, 1);
9017         services_notify->remove = g_hash_table_new_full(g_str_hash,
9018                         g_str_equal, g_free, NULL);
9019         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
9020
9021         remove_unprovisioned_services();
9022
9023         return 0;
9024 }
9025
9026 void __connman_service_cleanup(void)
9027 {
9028         DBG("");
9029
9030         if (vpn_autoconnect_timeout) {
9031                 g_source_remove(vpn_autoconnect_timeout);
9032                 vpn_autoconnect_timeout = 0;
9033         }
9034
9035         if (autoconnect_timeout != 0) {
9036                 g_source_remove(autoconnect_timeout);
9037                 autoconnect_timeout = 0;
9038         }
9039
9040         connman_agent_driver_unregister(&agent_driver);
9041
9042         g_list_free(service_list);
9043         service_list = NULL;
9044
9045         g_hash_table_destroy(service_hash);
9046         service_hash = NULL;
9047
9048         g_slist_free(counter_list);
9049         counter_list = NULL;
9050
9051         if (services_notify->id != 0) {
9052                 g_source_remove(services_notify->id);
9053                 service_send_changed(NULL);
9054                 g_hash_table_destroy(services_notify->remove);
9055                 g_hash_table_destroy(services_notify->add);
9056         }
9057         g_free(services_notify);
9058
9059         dbus_connection_unref(connection);
9060 }