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