connman: Get HS20 property of service correctly
[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         const void *wifi_vsie;
3252         unsigned int wifi_vsie_len;
3253         wifi_vsie = connman_network_get_blob(service->network, "WiFi.Vsie", &wifi_vsie_len);
3254         if(wifi_vsie_len > 0) {
3255                 DBG("ConnMan, service->path=%s vsie length=%d", service->path, wifi_vsie_len);
3256         }
3257         connman_dbus_dict_append_fixed_array(dict, "Vsie", DBUS_TYPE_BYTE,
3258                         &wifi_vsie, wifi_vsie_len);
3259 #endif
3260
3261         str = __connman_service_type2string(service->type);
3262         if (str)
3263                 connman_dbus_dict_append_basic(dict, "Type",
3264                                                 DBUS_TYPE_STRING, &str);
3265
3266         connman_dbus_dict_append_array(dict, "Security",
3267                                 DBUS_TYPE_STRING, append_security, service);
3268
3269         str = state2string(service->state);
3270         if (str)
3271                 connman_dbus_dict_append_basic(dict, "State",
3272                                                 DBUS_TYPE_STRING, &str);
3273
3274 #ifdef TIZEN_EXT
3275         str = state2string(service->state_ipv6);
3276         if (str != NULL)
3277                 connman_dbus_dict_append_basic(dict, "StateIPv6",
3278                                 DBUS_TYPE_STRING, &str);
3279 #endif
3280
3281         str = error2string(service->error);
3282         if (str)
3283                 connman_dbus_dict_append_basic(dict, "Error",
3284                                                 DBUS_TYPE_STRING, &str);
3285
3286         if (service->strength > 0)
3287                 connman_dbus_dict_append_basic(dict, "Strength",
3288                                         DBUS_TYPE_BYTE, &service->strength);
3289
3290         val = service->favorite;
3291         connman_dbus_dict_append_basic(dict, "Favorite",
3292                                         DBUS_TYPE_BOOLEAN, &val);
3293
3294         val = service->immutable;
3295         connman_dbus_dict_append_basic(dict, "Immutable",
3296                                         DBUS_TYPE_BOOLEAN, &val);
3297
3298         if (service->favorite)
3299                 val = service->autoconnect;
3300         else
3301                 val = service->favorite;
3302
3303         connman_dbus_dict_append_basic(dict, "AutoConnect",
3304                                 DBUS_TYPE_BOOLEAN, &val);
3305
3306         if (service->name)
3307                 connman_dbus_dict_append_basic(dict, "Name",
3308                                         DBUS_TYPE_STRING, &service->name);
3309
3310         switch (service->type) {
3311         case CONNMAN_SERVICE_TYPE_UNKNOWN:
3312         case CONNMAN_SERVICE_TYPE_SYSTEM:
3313         case CONNMAN_SERVICE_TYPE_GPS:
3314         case CONNMAN_SERVICE_TYPE_VPN:
3315         case CONNMAN_SERVICE_TYPE_P2P:
3316                 break;
3317         case CONNMAN_SERVICE_TYPE_CELLULAR:
3318                 val = service->roaming;
3319                 connman_dbus_dict_append_basic(dict, "Roaming",
3320                                         DBUS_TYPE_BOOLEAN, &val);
3321
3322                 connman_dbus_dict_append_dict(dict, "Ethernet",
3323                                                 append_ethernet, service);
3324                 break;
3325         case CONNMAN_SERVICE_TYPE_WIFI:
3326 #if defined TIZEN_EXT
3327                 if (service->network != NULL)
3328                         append_wifi_ext_info(dict, service->network);
3329
3330                 connman_dbus_dict_append_dict(dict, "Ethernet",
3331                                                 append_ethernet, service);
3332
3333                 connman_dbus_dict_append_basic(dict, "DisconnectReason",
3334                                 DBUS_TYPE_INT32, &service->disconnect_reason);
3335
3336                 connman_dbus_dict_append_basic(dict, "AssocStatusCode",
3337                                 DBUS_TYPE_INT32, &service->assoc_status_code);
3338
3339                 break;
3340 #endif
3341         case CONNMAN_SERVICE_TYPE_ETHERNET:
3342         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
3343         case CONNMAN_SERVICE_TYPE_GADGET:
3344                 connman_dbus_dict_append_dict(dict, "Ethernet",
3345                                                 append_ethernet, service);
3346                 break;
3347         }
3348
3349         connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service);
3350
3351         connman_dbus_dict_append_dict(dict, "IPv4.Configuration",
3352                                                 append_ipv4config, service);
3353
3354         connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service);
3355
3356         connman_dbus_dict_append_dict(dict, "IPv6.Configuration",
3357                                                 append_ipv6config, service);
3358
3359         connman_dbus_dict_append_array(dict, "Nameservers",
3360                                 DBUS_TYPE_STRING, append_dns, service);
3361
3362         connman_dbus_dict_append_array(dict, "Nameservers.Configuration",
3363                                 DBUS_TYPE_STRING, append_dnsconfig, service);
3364
3365         if (service->state == CONNMAN_SERVICE_STATE_READY ||
3366                         service->state == CONNMAN_SERVICE_STATE_ONLINE)
3367                 list = __connman_timeserver_get_all(service);
3368         else
3369                 list = NULL;
3370
3371         connman_dbus_dict_append_array(dict, "Timeservers",
3372                                 DBUS_TYPE_STRING, append_ts, list);
3373
3374         g_slist_free_full(list, g_free);
3375
3376         connman_dbus_dict_append_array(dict, "Timeservers.Configuration",
3377                                 DBUS_TYPE_STRING, append_tsconfig, service);
3378
3379         connman_dbus_dict_append_array(dict, "Domains",
3380                                 DBUS_TYPE_STRING, append_domain, service);
3381
3382         connman_dbus_dict_append_array(dict, "Domains.Configuration",
3383                                 DBUS_TYPE_STRING, append_domainconfig, service);
3384
3385         connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service);
3386
3387         connman_dbus_dict_append_dict(dict, "Proxy.Configuration",
3388                                                 append_proxyconfig, service);
3389
3390         connman_dbus_dict_append_dict(dict, "Provider",
3391                                                 append_provider, service);
3392 }
3393
3394 static void append_struct_service(DBusMessageIter *iter,
3395                 connman_dbus_append_cb_t function,
3396                 struct connman_service *service)
3397 {
3398         DBusMessageIter entry, dict;
3399
3400         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
3401
3402         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
3403                                                         &service->path);
3404
3405         connman_dbus_dict_open(&entry, &dict);
3406         if (function)
3407                 function(&dict, service);
3408         connman_dbus_dict_close(&entry, &dict);
3409
3410         dbus_message_iter_close_container(iter, &entry);
3411 }
3412
3413 static void append_dict_properties(DBusMessageIter *dict, void *user_data)
3414 {
3415         struct connman_service *service = user_data;
3416
3417         append_properties(dict, TRUE, service);
3418 }
3419
3420 static void append_struct(gpointer value, gpointer user_data)
3421 {
3422         struct connman_service *service = value;
3423         DBusMessageIter *iter = user_data;
3424
3425         if (!service->path)
3426                 return;
3427
3428         append_struct_service(iter, append_dict_properties, service);
3429 }
3430
3431 void __connman_service_list_struct(DBusMessageIter *iter)
3432 {
3433         g_list_foreach(service_list, append_struct, iter);
3434 }
3435
3436 bool __connman_service_is_hidden(struct connman_service *service)
3437 {
3438         return service->hidden;
3439 }
3440
3441 bool
3442 __connman_service_is_split_routing(struct connman_service *service)
3443 {
3444         return service->do_split_routing;
3445 }
3446
3447 bool __connman_service_index_is_split_routing(int index)
3448 {
3449         struct connman_service *service;
3450
3451         if (index < 0)
3452                 return false;
3453
3454         service = __connman_service_lookup_from_index(index);
3455         if (!service)
3456                 return false;
3457
3458         return __connman_service_is_split_routing(service);
3459 }
3460
3461 int __connman_service_get_index(struct connman_service *service)
3462 {
3463         if (!service)
3464                 return -1;
3465
3466         if (service->network)
3467                 return connman_network_get_index(service->network);
3468         else if (service->provider)
3469                 return connman_provider_get_index(service->provider);
3470
3471         return -1;
3472 }
3473
3474 void __connman_service_set_hidden(struct connman_service *service)
3475 {
3476         if (!service || service->hidden)
3477                 return;
3478
3479         service->hidden_service = true;
3480 }
3481
3482 void __connman_service_set_hostname(struct connman_service *service,
3483                                                 const char *hostname)
3484 {
3485         if (!service || service->hidden)
3486                 return;
3487
3488         g_free(service->hostname);
3489         service->hostname = g_strdup(hostname);
3490 }
3491
3492 const char *__connman_service_get_hostname(struct connman_service *service)
3493 {
3494         if (!service)
3495                 return NULL;
3496
3497         return service->hostname;
3498 }
3499
3500 void __connman_service_set_domainname(struct connman_service *service,
3501                                                 const char *domainname)
3502 {
3503         if (!service || service->hidden)
3504                 return;
3505
3506         g_free(service->domainname);
3507         service->domainname = g_strdup(domainname);
3508
3509         domain_changed(service);
3510 }
3511
3512 const char *connman_service_get_domainname(struct connman_service *service)
3513 {
3514         if (!service)
3515                 return NULL;
3516
3517         if (service->domains)
3518                 return service->domains[0];
3519         else
3520                 return service->domainname;
3521 }
3522
3523 char **connman_service_get_nameservers(struct connman_service *service)
3524 {
3525         if (!service)
3526                 return NULL;
3527
3528         if (service->nameservers_config)
3529                 return g_strdupv(service->nameservers_config);
3530         else if (service->nameservers ||
3531                                         service->nameservers_auto) {
3532                 int len = 0, len_auto = 0, i;
3533                 char **nameservers;
3534
3535                 if (service->nameservers)
3536                         len = g_strv_length(service->nameservers);
3537                 if (service->nameservers_auto)
3538                         len_auto = g_strv_length(service->nameservers_auto);
3539
3540                 nameservers = g_try_new0(char *, len + len_auto + 1);
3541                 if (!nameservers)
3542                         return NULL;
3543
3544                 for (i = 0; i < len; i++)
3545                         nameservers[i] = g_strdup(service->nameservers[i]);
3546
3547                 for (i = 0; i < len_auto; i++)
3548                         nameservers[i + len] =
3549                                 g_strdup(service->nameservers_auto[i]);
3550
3551                 return nameservers;
3552         }
3553
3554         return g_strdupv(connman_setting_get_string_list("FallbackNameservers"));
3555 }
3556
3557 char **connman_service_get_timeservers_config(struct connman_service *service)
3558 {
3559         if (!service)
3560                 return NULL;
3561
3562         return service->timeservers_config;
3563 }
3564
3565 char **connman_service_get_timeservers(struct connman_service *service)
3566 {
3567         if (!service)
3568                 return NULL;
3569
3570         return service->timeservers;
3571 }
3572
3573 #if defined TIZEN_EXT
3574 /*
3575  * Description: Telephony plug-in requires manual PROXY setting function
3576  */
3577 int connman_service_set_proxy(struct connman_service *service,
3578                                         const char *proxy, gboolean active)
3579 {
3580         char **proxies_array = NULL;
3581
3582         if (service == NULL)
3583                 return -EINVAL;
3584
3585         switch (service->type) {
3586         case CONNMAN_SERVICE_TYPE_CELLULAR:
3587         case CONNMAN_SERVICE_TYPE_ETHERNET:
3588         case CONNMAN_SERVICE_TYPE_WIFI:
3589                 break;
3590
3591         default:
3592                 return -EINVAL;
3593         }
3594
3595         g_strfreev(service->proxies);
3596         service->proxies = NULL;
3597
3598         if (proxy != NULL)
3599                 proxies_array = g_strsplit(proxy, " ", 0);
3600
3601         service->proxies = proxies_array;
3602
3603         if (proxy == NULL) {
3604                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
3605                 DBG("proxy changed (%d)", active);
3606         } else {
3607                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_MANUAL;
3608                 DBG("proxy chagned %s (%d)", proxy, active);
3609         }
3610
3611         if (active == TRUE) {
3612                 proxy_changed(service);
3613
3614                 __connman_notifier_proxy_changed(service);
3615         }
3616
3617         return 0;
3618 }
3619 #endif
3620
3621 void connman_service_set_proxy_method(struct connman_service *service,
3622                                         enum connman_service_proxy_method method)
3623 {
3624         if (!service || service->hidden)
3625                 return;
3626
3627         service->proxy = method;
3628
3629         proxy_changed(service);
3630
3631         if (method != CONNMAN_SERVICE_PROXY_METHOD_AUTO)
3632                 __connman_notifier_proxy_changed(service);
3633 }
3634
3635 enum connman_service_proxy_method connman_service_get_proxy_method(
3636                                         struct connman_service *service)
3637 {
3638         if (!service)
3639                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
3640
3641         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) {
3642                 if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_AUTO &&
3643                                 !service->pac)
3644                         return service->proxy;
3645
3646                 return service->proxy_config;
3647         }
3648
3649         return service->proxy;
3650 }
3651
3652 char **connman_service_get_proxy_servers(struct connman_service *service)
3653 {
3654         return g_strdupv(service->proxies);
3655 }
3656
3657 char **connman_service_get_proxy_excludes(struct connman_service *service)
3658 {
3659         return g_strdupv(service->excludes);
3660 }
3661
3662 const char *connman_service_get_proxy_url(struct connman_service *service)
3663 {
3664         if (!service)
3665                 return NULL;
3666
3667         return service->pac;
3668 }
3669
3670 void __connman_service_set_proxy_autoconfig(struct connman_service *service,
3671                                                         const char *url)
3672 {
3673         if (!service || service->hidden)
3674                 return;
3675
3676         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_AUTO;
3677
3678         if (service->ipconfig_ipv4) {
3679                 if (__connman_ipconfig_set_proxy_autoconfig(
3680                             service->ipconfig_ipv4, url) < 0)
3681                         return;
3682         } else if (service->ipconfig_ipv6) {
3683                 if (__connman_ipconfig_set_proxy_autoconfig(
3684                             service->ipconfig_ipv6, url) < 0)
3685                         return;
3686         } else
3687                 return;
3688
3689         proxy_changed(service);
3690
3691         __connman_notifier_proxy_changed(service);
3692 }
3693
3694 const char *connman_service_get_proxy_autoconfig(struct connman_service *service)
3695 {
3696         if (!service)
3697                 return NULL;
3698
3699         if (service->ipconfig_ipv4)
3700                 return __connman_ipconfig_get_proxy_autoconfig(
3701                                                 service->ipconfig_ipv4);
3702         else if (service->ipconfig_ipv6)
3703                 return __connman_ipconfig_get_proxy_autoconfig(
3704                                                 service->ipconfig_ipv6);
3705         return NULL;
3706 }
3707
3708 #if defined TIZEN_EXT
3709 int connman_service_get_ipv6_dns_method(struct connman_service *service)
3710 {
3711         if (!service) {
3712                 DBG("Service is NULL");
3713                 return -1;
3714         }
3715
3716         return service->dns_config_method_ipv6;
3717 }
3718 #endif
3719
3720 void __connman_service_set_timeservers(struct connman_service *service,
3721                                 char **timeservers)
3722 {
3723         int i;
3724
3725         if (!service)
3726                 return;
3727
3728         g_strfreev(service->timeservers);
3729         service->timeservers = NULL;
3730
3731         for (i = 0; timeservers && timeservers[i]; i++)
3732                 __connman_service_timeserver_append(service, timeservers[i]);
3733 }
3734
3735 int __connman_service_timeserver_append(struct connman_service *service,
3736                                                 const char *timeserver)
3737 {
3738         int len;
3739
3740         DBG("service %p timeserver %s", service, timeserver);
3741
3742         if (!timeserver)
3743                 return -EINVAL;
3744
3745         if (service->timeservers) {
3746                 int i;
3747
3748                 for (i = 0; service->timeservers[i]; i++)
3749                         if (g_strcmp0(service->timeservers[i], timeserver) == 0)
3750                                 return -EEXIST;
3751
3752                 len = g_strv_length(service->timeservers);
3753                 service->timeservers = g_try_renew(char *, service->timeservers,
3754                                                         len + 2);
3755         } else {
3756                 len = 0;
3757                 service->timeservers = g_try_new0(char *, len + 2);
3758         }
3759
3760         if (!service->timeservers)
3761                 return -ENOMEM;
3762
3763         service->timeservers[len] = g_strdup(timeserver);
3764         service->timeservers[len + 1] = NULL;
3765
3766         return 0;
3767 }
3768
3769 int __connman_service_timeserver_remove(struct connman_service *service,
3770                                                 const char *timeserver)
3771 {
3772         char **servers;
3773         int len, i, j, found = 0;
3774
3775         DBG("service %p timeserver %s", service, timeserver);
3776
3777         if (!timeserver)
3778                 return -EINVAL;
3779
3780         if (!service->timeservers)
3781                 return 0;
3782
3783         for (i = 0; service->timeservers &&
3784                                         service->timeservers[i]; i++)
3785                 if (g_strcmp0(service->timeservers[i], timeserver) == 0) {
3786                         found = 1;
3787                         break;
3788                 }
3789
3790         if (found == 0)
3791                 return 0;
3792
3793         len = g_strv_length(service->timeservers);
3794
3795         if (len == 1) {
3796                 g_strfreev(service->timeservers);
3797                 service->timeservers = NULL;
3798
3799                 return 0;
3800         }
3801
3802         servers = g_try_new0(char *, len);
3803         if (!servers)
3804                 return -ENOMEM;
3805
3806         for (i = 0, j = 0; i < len; i++) {
3807                 if (g_strcmp0(service->timeservers[i], timeserver) != 0) {
3808                         servers[j] = g_strdup(service->timeservers[i]);
3809                         if (!servers[j])
3810                                 return -ENOMEM;
3811                         j++;
3812                 }
3813         }
3814         servers[len - 1] = NULL;
3815
3816         g_strfreev(service->timeservers);
3817         service->timeservers = servers;
3818
3819         return 0;
3820 }
3821
3822 void __connman_service_timeserver_changed(struct connman_service *service,
3823                 GSList *ts_list)
3824 {
3825         if (!service)
3826                 return;
3827
3828         if (!allow_property_changed(service))
3829                 return;
3830
3831         connman_dbus_property_changed_array(service->path,
3832                         CONNMAN_SERVICE_INTERFACE, "Timeservers",
3833                         DBUS_TYPE_STRING, append_ts, ts_list);
3834 }
3835
3836 void __connman_service_set_pac(struct connman_service *service,
3837                                         const char *pac)
3838 {
3839         if (service->hidden)
3840                 return;
3841         g_free(service->pac);
3842         service->pac = g_strdup(pac);
3843
3844         proxy_changed(service);
3845 }
3846
3847 #if defined TIZEN_EXT
3848 void __connman_service_set_proxy(struct connman_service *service,
3849                                        const char *proxies)
3850 {
3851        char **proxies_array = NULL;
3852
3853        g_strfreev(service->proxies);
3854        service->proxies = NULL;
3855
3856        if (proxies != NULL)
3857                proxies_array = g_strsplit(proxies, " ", 0);
3858
3859        service->proxies = proxies_array;
3860 }
3861 #endif
3862
3863 void __connman_service_set_identity(struct connman_service *service,
3864                                         const char *identity)
3865 {
3866         if (service->immutable || service->hidden)
3867                 return;
3868
3869         g_free(service->identity);
3870         service->identity = g_strdup(identity);
3871
3872         if (service->network)
3873                 connman_network_set_string(service->network,
3874                                         "WiFi.Identity",
3875                                         service->identity);
3876 }
3877
3878 void __connman_service_set_agent_identity(struct connman_service *service,
3879                                                 const char *agent_identity)
3880 {
3881         if (service->hidden)
3882                 return;
3883         g_free(service->agent_identity);
3884         service->agent_identity = g_strdup(agent_identity);
3885
3886         if (service->network)
3887                 connman_network_set_string(service->network,
3888                                         "WiFi.AgentIdentity",
3889                                         service->agent_identity);
3890 }
3891
3892 static int check_passphrase(enum connman_service_security security,
3893                 const char *passphrase)
3894 {
3895         guint i;
3896         gsize length;
3897
3898         if (!passphrase)
3899                 return 0;
3900
3901         length = strlen(passphrase);
3902
3903         switch (security) {
3904         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
3905         case CONNMAN_SERVICE_SECURITY_NONE:
3906         case CONNMAN_SERVICE_SECURITY_WPA:
3907 #if !defined TIZEN_EXT
3908         case CONNMAN_SERVICE_SECURITY_RSN:
3909 #endif
3910
3911                 DBG("service security '%s' (%d) not handled",
3912                                 security2string(security), security);
3913
3914                 return -EOPNOTSUPP;
3915
3916         case CONNMAN_SERVICE_SECURITY_PSK:
3917 #if defined TIZEN_EXT
3918         case CONNMAN_SERVICE_SECURITY_RSN:
3919 #endif
3920                 /* A raw key is always 64 bytes length,
3921                  * its content is in hex representation.
3922                  * A PSK key must be between [8..63].
3923                  */
3924                 if (length == 64) {
3925                         for (i = 0; i < 64; i++)
3926                                 if (!isxdigit((unsigned char)
3927                                               passphrase[i]))
3928                                         return -ENOKEY;
3929                 } else if (length < 8 || length > 63)
3930                         return -ENOKEY;
3931                 break;
3932         case CONNMAN_SERVICE_SECURITY_WEP:
3933                 /* length of WEP key is 10 or 26
3934                  * length of WEP passphrase is 5 or 13
3935                  */
3936                 if (length == 10 || length == 26) {
3937                         for (i = 0; i < length; i++)
3938                                 if (!isxdigit((unsigned char)
3939                                               passphrase[i]))
3940                                         return -ENOKEY;
3941                 } else if (length != 5 && length != 13)
3942                         return -ENOKEY;
3943                 break;
3944
3945         case CONNMAN_SERVICE_SECURITY_8021X:
3946                 break;
3947         }
3948
3949         return 0;
3950 }
3951
3952 int __connman_service_set_passphrase(struct connman_service *service,
3953                                         const char *passphrase)
3954 {
3955         int err;
3956
3957         if (service->hidden)
3958                 return -EINVAL;
3959
3960         if (service->immutable &&
3961                         service->security != CONNMAN_SERVICE_SECURITY_8021X)
3962                 return -EINVAL;
3963 #if defined TIZEN_EXT
3964         /* The encrypted passphrase is used here
3965          * and validation is done by net-config before being encrypted.
3966          */
3967         if (service->security != CONNMAN_SERVICE_SECURITY_PSK &&
3968                         service->security != CONNMAN_SERVICE_SECURITY_RSN &&
3969                         service->security != CONNMAN_SERVICE_SECURITY_WEP)
3970 #endif
3971         err = check_passphrase(service->security, passphrase);
3972
3973         if (err < 0)
3974                 return err;
3975
3976         g_free(service->passphrase);
3977         service->passphrase = g_strdup(passphrase);
3978
3979         if (service->network)
3980                 connman_network_set_string(service->network, "WiFi.Passphrase",
3981                                 service->passphrase);
3982
3983         return 0;
3984 }
3985
3986 const char *__connman_service_get_passphrase(struct connman_service *service)
3987 {
3988         if (!service)
3989                 return NULL;
3990
3991         return service->passphrase;
3992 }
3993
3994 static DBusMessage *get_properties(DBusConnection *conn,
3995                                         DBusMessage *msg, void *user_data)
3996 {
3997         struct connman_service *service = user_data;
3998         DBusMessage *reply;
3999         DBusMessageIter array, dict;
4000
4001         DBG("service %p", service);
4002
4003         reply = dbus_message_new_method_return(msg);
4004         if (!reply)
4005                 return NULL;
4006
4007         dbus_message_iter_init_append(reply, &array);
4008
4009         connman_dbus_dict_open(&array, &dict);
4010         append_properties(&dict, FALSE, service);
4011         connman_dbus_dict_close(&array, &dict);
4012
4013         return reply;
4014 }
4015
4016 static int update_proxy_configuration(struct connman_service *service,
4017                                 DBusMessageIter *array)
4018 {
4019         DBusMessageIter dict;
4020         enum connman_service_proxy_method method;
4021         GString *servers_str = NULL;
4022         GString *excludes_str = NULL;
4023         const char *url = NULL;
4024
4025         method = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
4026
4027         dbus_message_iter_recurse(array, &dict);
4028
4029         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
4030                 DBusMessageIter entry, variant;
4031                 const char *key;
4032                 int type;
4033
4034                 dbus_message_iter_recurse(&dict, &entry);
4035
4036                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
4037                         goto error;
4038
4039                 dbus_message_iter_get_basic(&entry, &key);
4040                 dbus_message_iter_next(&entry);
4041
4042                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
4043                         goto error;
4044
4045                 dbus_message_iter_recurse(&entry, &variant);
4046
4047                 type = dbus_message_iter_get_arg_type(&variant);
4048
4049                 if (g_str_equal(key, "Method")) {
4050                         const char *val;
4051
4052                         if (type != DBUS_TYPE_STRING)
4053                                 goto error;
4054
4055                         dbus_message_iter_get_basic(&variant, &val);
4056                         method = string2proxymethod(val);
4057                 } else if (g_str_equal(key, "URL")) {
4058                         if (type != DBUS_TYPE_STRING)
4059                                 goto error;
4060
4061                         dbus_message_iter_get_basic(&variant, &url);
4062                 } else if (g_str_equal(key, "Servers")) {
4063                         DBusMessageIter str_array;
4064
4065                         if (type != DBUS_TYPE_ARRAY)
4066                                 goto error;
4067
4068                         servers_str = g_string_new(NULL);
4069                         if (!servers_str)
4070                                 goto error;
4071
4072                         dbus_message_iter_recurse(&variant, &str_array);
4073
4074                         while (dbus_message_iter_get_arg_type(&str_array) ==
4075                                                         DBUS_TYPE_STRING) {
4076                                 char *val = NULL;
4077
4078                                 dbus_message_iter_get_basic(&str_array, &val);
4079
4080                                 if (servers_str->len > 0)
4081                                         g_string_append_printf(servers_str,
4082                                                         " %s", val);
4083                                 else
4084                                         g_string_append(servers_str, val);
4085
4086                                 dbus_message_iter_next(&str_array);
4087                         }
4088                 } else if (g_str_equal(key, "Excludes")) {
4089                         DBusMessageIter str_array;
4090
4091                         if (type != DBUS_TYPE_ARRAY)
4092                                 goto error;
4093
4094                         excludes_str = g_string_new(NULL);
4095                         if (!excludes_str)
4096                                 goto error;
4097
4098                         dbus_message_iter_recurse(&variant, &str_array);
4099
4100                         while (dbus_message_iter_get_arg_type(&str_array) ==
4101                                                         DBUS_TYPE_STRING) {
4102                                 char *val = NULL;
4103
4104                                 dbus_message_iter_get_basic(&str_array, &val);
4105
4106                                 if (excludes_str->len > 0)
4107                                         g_string_append_printf(excludes_str,
4108                                                         " %s", val);
4109                                 else
4110                                         g_string_append(excludes_str, val);
4111
4112                                 dbus_message_iter_next(&str_array);
4113                         }
4114                 }
4115
4116                 dbus_message_iter_next(&dict);
4117         }
4118
4119         switch (method) {
4120         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
4121                 break;
4122         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
4123                 if (!servers_str && !service->proxies)
4124                         goto error;
4125
4126                 if (servers_str) {
4127                         g_strfreev(service->proxies);
4128
4129                         if (servers_str->len > 0)
4130                                 service->proxies = g_strsplit_set(
4131                                         servers_str->str, " ", 0);
4132                         else
4133                                 service->proxies = NULL;
4134                 }
4135
4136                 if (excludes_str) {
4137                         g_strfreev(service->excludes);
4138
4139                         if (excludes_str->len > 0)
4140                                 service->excludes = g_strsplit_set(
4141                                         excludes_str->str, " ", 0);
4142                         else
4143                                 service->excludes = NULL;
4144                 }
4145
4146                 if (!service->proxies)
4147                         method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
4148
4149                 break;
4150         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
4151                 g_free(service->pac);
4152
4153                 if (url && strlen(url) > 0)
4154                         service->pac = g_strdup(url);
4155                 else
4156                         service->pac = NULL;
4157
4158                 /* if we are connected:
4159                    - if service->pac == NULL
4160                    - if __connman_ipconfig_get_proxy_autoconfig(
4161                    service->ipconfig) == NULL
4162                    --> We should start WPAD */
4163
4164                 break;
4165         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
4166                 goto error;
4167         }
4168
4169         if (servers_str)
4170                 g_string_free(servers_str, TRUE);
4171
4172         if (excludes_str)
4173                 g_string_free(excludes_str, TRUE);
4174
4175         service->proxy_config = method;
4176
4177         return 0;
4178
4179 error:
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         return -EINVAL;
4187 }
4188
4189 int __connman_service_reset_ipconfig(struct connman_service *service,
4190                 enum connman_ipconfig_type type, DBusMessageIter *array,
4191                 enum connman_service_state *new_state)
4192 {
4193         struct connman_ipconfig *ipconfig, *new_ipconfig;
4194         enum connman_ipconfig_method old_method, new_method;
4195         enum connman_service_state state;
4196         int err = 0, index;
4197
4198         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
4199                 ipconfig = service->ipconfig_ipv4;
4200                 state = service->state_ipv4;
4201                 new_method = CONNMAN_IPCONFIG_METHOD_DHCP;
4202         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
4203                 ipconfig = service->ipconfig_ipv6;
4204                 state = service->state_ipv6;
4205                 new_method = CONNMAN_IPCONFIG_METHOD_AUTO;
4206         } else
4207                 return -EINVAL;
4208
4209         if (!ipconfig)
4210                 return -ENXIO;
4211
4212         old_method = __connman_ipconfig_get_method(ipconfig);
4213         index = __connman_ipconfig_get_index(ipconfig);
4214
4215         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4216                 new_ipconfig = create_ip4config(service, index,
4217                                 CONNMAN_IPCONFIG_METHOD_UNKNOWN);
4218         else
4219                 new_ipconfig = create_ip6config(service, index);
4220
4221         if (array) {
4222                 err = __connman_ipconfig_set_config(new_ipconfig, array);
4223                 if (err < 0) {
4224                         __connman_ipconfig_unref(new_ipconfig);
4225                         return err;
4226                 }
4227
4228                 new_method = __connman_ipconfig_get_method(new_ipconfig);
4229         }
4230
4231         if (is_connecting_state(service, state) ||
4232                                         is_connected_state(service, state))
4233                 __connman_network_clear_ipconfig(service->network, ipconfig);
4234
4235         __connman_ipconfig_unref(ipconfig);
4236
4237         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4238                 service->ipconfig_ipv4 = new_ipconfig;
4239         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
4240                 service->ipconfig_ipv6 = new_ipconfig;
4241
4242         if (is_connecting_state(service, state) ||
4243                                         is_connected_state(service, state))
4244                 __connman_ipconfig_enable(new_ipconfig);
4245
4246         if (new_state && new_method != old_method) {
4247                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4248                         *new_state = service->state_ipv4;
4249                 else
4250                         *new_state = service->state_ipv6;
4251
4252                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4253         }
4254
4255         DBG("err %d ipconfig %p type %d method %d state %s", err,
4256                 new_ipconfig, type, new_method,
4257                 !new_state  ? "-" : state2string(*new_state));
4258
4259         return err;
4260 }
4261
4262 static DBusMessage *set_property(DBusConnection *conn,
4263                                         DBusMessage *msg, void *user_data)
4264 {
4265         struct connman_service *service = user_data;
4266         DBusMessageIter iter, value;
4267         const char *name;
4268         int type;
4269
4270         DBG("service %p", service);
4271
4272         if (!dbus_message_iter_init(msg, &iter))
4273                 return __connman_error_invalid_arguments(msg);
4274
4275         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
4276                 return __connman_error_invalid_arguments(msg);
4277
4278         if (service->type == CONNMAN_SERVICE_TYPE_WIFI && is_connected(service)) {
4279                 uid_t uid;
4280                 if (connman_dbus_get_connection_unix_user_sync(conn,
4281                                                 dbus_message_get_sender(msg),
4282                                                 &uid) < 0) {
4283                         DBG("Can not get unix user id!");
4284                         return __connman_error_permission_denied(msg);
4285                 }
4286
4287                 if (!connman_service_is_user_allowed(service, uid)) {
4288                         DBG("Not allow this user to operate this wifi service now!");
4289                         return __connman_error_permission_denied(msg);
4290                 }
4291         }
4292
4293         dbus_message_iter_get_basic(&iter, &name);
4294         dbus_message_iter_next(&iter);
4295
4296         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
4297                 return __connman_error_invalid_arguments(msg);
4298
4299         dbus_message_iter_recurse(&iter, &value);
4300
4301         type = dbus_message_iter_get_arg_type(&value);
4302
4303         if (g_str_equal(name, "AutoConnect")) {
4304                 dbus_bool_t autoconnect;
4305
4306                 if (type != DBUS_TYPE_BOOLEAN)
4307                         return __connman_error_invalid_arguments(msg);
4308
4309                 if (!service->favorite)
4310                         return __connman_error_invalid_service(msg);
4311
4312                 dbus_message_iter_get_basic(&value, &autoconnect);
4313
4314                 if (service->autoconnect == autoconnect)
4315                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4316
4317                 service->autoconnect = autoconnect;
4318
4319                 autoconnect_changed(service);
4320
4321                 if (autoconnect)
4322                         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4323
4324                 service_save(service);
4325         } else if (g_str_equal(name, "Nameservers.Configuration")) {
4326                 DBusMessageIter entry;
4327                 GString *str;
4328                 int index;
4329                 const char *gw;
4330 #if defined TIZEN_EXT
4331                 enum connman_ipconfig_type ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4332                 DBG("%s", name);
4333 #endif
4334
4335                 if (__connman_provider_is_immutable(service->provider) ||
4336                                 service->immutable)
4337                         return __connman_error_not_supported(msg);
4338
4339                 if (type != DBUS_TYPE_ARRAY)
4340                         return __connman_error_invalid_arguments(msg);
4341
4342                 str = g_string_new(NULL);
4343                 if (!str)
4344                         return __connman_error_invalid_arguments(msg);
4345
4346                 index = __connman_service_get_index(service);
4347                 gw = __connman_ipconfig_get_gateway_from_index(index,
4348                         CONNMAN_IPCONFIG_TYPE_ALL);
4349
4350                 if (gw && strlen(gw))
4351                         __connman_service_nameserver_del_routes(service,
4352                                                 CONNMAN_IPCONFIG_TYPE_ALL);
4353
4354                 dbus_message_iter_recurse(&value, &entry);
4355
4356 #if defined TIZEN_EXT
4357                 /* IPv4/IPv6 Last DNS config method */
4358                 int last_dns_ipv4 = service->dns_config_method_ipv4;
4359                 int last_dns_ipv6 = service->dns_config_method_ipv6;
4360                 DBG("Last DNS Config Method IPv4: %d IPv6: %d", last_dns_ipv4, last_dns_ipv6);
4361 #endif
4362
4363                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
4364                         const char *val;
4365                         dbus_message_iter_get_basic(&entry, &val);
4366                         dbus_message_iter_next(&entry);
4367 #ifdef TIZEN_EXT
4368                         /* First unpack the DNS Config Method */
4369                         DBG("DNS Config Method: %s", val);
4370                         if((g_strcmp0(val, "ipv4.manual") == 0)) {
4371                                 service->dns_config_method_ipv4 =
4372                                         CONNMAN_DNSCONFIG_METHOD_MANUAL;
4373
4374                                 if(last_dns_ipv4 != CONNMAN_DNSCONFIG_METHOD_MANUAL) {
4375                                         if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN)
4376                                                 ip_type = CONNMAN_IPCONFIG_TYPE_IPV4;
4377                                         else
4378                                                 ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4379                                 }
4380                                 continue;
4381                         } else if(g_strcmp0(val, "ipv4.dhcp") == 0) {
4382                                 service->dns_config_method_ipv4 =
4383                                         CONNMAN_DNSCONFIG_METHOD_DHCP;
4384                                 if(last_dns_ipv4 == CONNMAN_DNSCONFIG_METHOD_MANUAL)
4385                                         ip_type = CONNMAN_IPCONFIG_TYPE_IPV4;
4386
4387                                 continue;
4388                         } else if(g_strcmp0(val, "ipv6.manual") == 0) {
4389                                 service->dns_config_method_ipv6 =
4390                                         CONNMAN_DNSCONFIG_METHOD_MANUAL;
4391                                 if(last_dns_ipv6 != CONNMAN_DNSCONFIG_METHOD_MANUAL) {
4392                                         if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN)
4393                                                 ip_type = CONNMAN_IPCONFIG_TYPE_IPV6;
4394                                         else
4395                                                 ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4396                                 }
4397                                 continue;
4398                         } else if(g_strcmp0(val, "ipv6.dhcp") == 0) {
4399                                 service->dns_config_method_ipv6 =
4400                                         CONNMAN_DNSCONFIG_METHOD_DHCP;
4401                                 if(last_dns_ipv6 == CONNMAN_DNSCONFIG_METHOD_MANUAL)
4402                                         ip_type = CONNMAN_IPCONFIG_TYPE_IPV6;
4403
4404                                 continue;
4405                         }
4406 #endif
4407                         if (connman_inet_check_ipaddress(val) > 0) {
4408                                 if (str->len > 0)
4409                                         g_string_append_printf(str, " %s", val);
4410                                 else
4411                                         g_string_append(str, val);
4412                         }
4413                 }
4414
4415 #if defined TIZEN_EXT
4416                 if (service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_DHCP &&
4417                         service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_DHCP) {
4418                                         DBG("Both IPv4 and IPv6 DNS Method DHCP");
4419                                         ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4420                 }
4421                 if (gw && strlen(gw))
4422                         __connman_service_nameserver_del_routes(service,
4423                                                 ip_type);
4424
4425                 DBG("%s ip_type: %d nameserver remove all", name, ip_type);
4426                 nameserver_remove_all(service, ip_type);
4427 #else
4428                 nameserver_remove_all(service);
4429 #endif
4430                 g_strfreev(service->nameservers_config);
4431
4432                 if (str->len > 0) {
4433                         service->nameservers_config =
4434                                 g_strsplit_set(str->str, " ", 0);
4435                 } else {
4436                         service->nameservers_config = NULL;
4437                 }
4438
4439                 g_string_free(str, TRUE);
4440
4441                 if (gw && strlen(gw))
4442                         __connman_service_nameserver_add_routes(service, gw);
4443
4444 #if defined TIZEN_EXT
4445                 DBG("%s ip_type: %d nameserver add all", name, ip_type);
4446                 nameserver_add_all(service, ip_type);
4447 #else
4448                 nameserver_add_all(service);
4449 #endif
4450                 dns_configuration_changed(service);
4451
4452                 if (__connman_service_is_connected_state(service,
4453                                                 CONNMAN_IPCONFIG_TYPE_IPV4))
4454                         __connman_wispr_start(service,
4455                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4456
4457                 if (__connman_service_is_connected_state(service,
4458                                                 CONNMAN_IPCONFIG_TYPE_IPV6))
4459                         __connman_wispr_start(service,
4460                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
4461
4462                 service_save(service);
4463         } else if (g_str_equal(name, "Timeservers.Configuration")) {
4464                 DBusMessageIter entry;
4465                 GSList *list = NULL;
4466                 int count = 0;
4467
4468                 if (service->immutable)
4469                         return __connman_error_not_supported(msg);
4470
4471                 if (type != DBUS_TYPE_ARRAY)
4472                         return __connman_error_invalid_arguments(msg);
4473
4474                 dbus_message_iter_recurse(&value, &entry);
4475
4476                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
4477                         const char *val;
4478                         GSList *new_head;
4479
4480                         dbus_message_iter_get_basic(&entry, &val);
4481
4482                         new_head = __connman_timeserver_add_list(list, val);
4483                         if (list != new_head) {
4484                                 count++;
4485                                 list = new_head;
4486                         }
4487
4488                         dbus_message_iter_next(&entry);
4489                 }
4490
4491                 g_strfreev(service->timeservers_config);
4492                 service->timeservers_config = NULL;
4493
4494                 if (list) {
4495                         service->timeservers_config = g_new0(char *, count+1);
4496
4497                         while (list) {
4498                                 count--;
4499                                 service->timeservers_config[count] = list->data;
4500                                 list = g_slist_delete_link(list, list);
4501                         };
4502                 }
4503
4504                 service_save(service);
4505                 timeservers_configuration_changed(service);
4506
4507                 if (service == __connman_service_get_default())
4508                         __connman_timeserver_sync(service);
4509
4510         } else if (g_str_equal(name, "Domains.Configuration")) {
4511                 DBusMessageIter entry;
4512                 GString *str;
4513
4514                 if (service->immutable)
4515                         return __connman_error_not_supported(msg);
4516
4517                 if (type != DBUS_TYPE_ARRAY)
4518                         return __connman_error_invalid_arguments(msg);
4519
4520                 str = g_string_new(NULL);
4521                 if (!str)
4522                         return __connman_error_invalid_arguments(msg);
4523
4524                 dbus_message_iter_recurse(&value, &entry);
4525
4526                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
4527                         const char *val;
4528                         dbus_message_iter_get_basic(&entry, &val);
4529                         dbus_message_iter_next(&entry);
4530                         if (str->len > 0)
4531                                 g_string_append_printf(str, " %s", val);
4532                         else
4533                                 g_string_append(str, val);
4534                 }
4535
4536                 searchdomain_remove_all(service);
4537                 g_strfreev(service->domains);
4538
4539                 if (str->len > 0)
4540                         service->domains = g_strsplit_set(str->str, " ", 0);
4541                 else
4542                         service->domains = NULL;
4543
4544                 g_string_free(str, TRUE);
4545
4546                 searchdomain_add_all(service);
4547                 domain_configuration_changed(service);
4548                 domain_changed(service);
4549
4550                 service_save(service);
4551         } else if (g_str_equal(name, "Proxy.Configuration")) {
4552                 int err;
4553
4554                 if (service->immutable)
4555                         return __connman_error_not_supported(msg);
4556
4557                 if (type != DBUS_TYPE_ARRAY)
4558                         return __connman_error_invalid_arguments(msg);
4559
4560                 err = update_proxy_configuration(service, &value);
4561
4562                 if (err < 0)
4563                         return __connman_error_failed(msg, -err);
4564
4565                 proxy_configuration_changed(service);
4566
4567                 __connman_notifier_proxy_changed(service);
4568
4569                 service_save(service);
4570         } else if (g_str_equal(name, "IPv4.Configuration") ||
4571                         g_str_equal(name, "IPv6.Configuration")) {
4572
4573                 enum connman_service_state state =
4574                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
4575                 enum connman_ipconfig_type type =
4576                         CONNMAN_IPCONFIG_TYPE_UNKNOWN;
4577                 int err = 0;
4578
4579                 if (service->type == CONNMAN_SERVICE_TYPE_VPN ||
4580                                 service->immutable)
4581                         return __connman_error_not_supported(msg);
4582
4583                 DBG("%s", name);
4584
4585                 if (!service->ipconfig_ipv4 &&
4586                                         !service->ipconfig_ipv6)
4587                         return __connman_error_invalid_property(msg);
4588
4589                 if (g_str_equal(name, "IPv4.Configuration"))
4590                         type = CONNMAN_IPCONFIG_TYPE_IPV4;
4591                 else
4592                         type = CONNMAN_IPCONFIG_TYPE_IPV6;
4593
4594                 err = __connman_service_reset_ipconfig(service, type, &value,
4595                                                                 &state);
4596
4597                 if (err < 0) {
4598                         if (is_connected_state(service, state) ||
4599                                         is_connecting_state(service, state)) {
4600                                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4601                                         __connman_network_enable_ipconfig(service->network,
4602                                                         service->ipconfig_ipv4);
4603                                 else
4604                                         __connman_network_enable_ipconfig(service->network,
4605                                                         service->ipconfig_ipv6);
4606                         }
4607
4608                         return __connman_error_failed(msg, -err);
4609                 }
4610
4611                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4612                         ipv4_configuration_changed(service);
4613                 else
4614                         ipv6_configuration_changed(service);
4615
4616                 if (is_connecting(service) || is_connected(service)) {
4617                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4618                                 __connman_network_enable_ipconfig(service->network,
4619                                                                 service->ipconfig_ipv4);
4620                         else
4621                                 __connman_network_enable_ipconfig(service->network,
4622                                                                 service->ipconfig_ipv6);
4623                 }
4624
4625                 service_save(service);
4626         } else
4627                 return __connman_error_invalid_property(msg);
4628
4629         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4630 }
4631
4632 static void set_error(struct connman_service *service,
4633                                         enum connman_service_error error)
4634 {
4635         const char *str;
4636
4637         if (service->error == error)
4638                 return;
4639
4640         service->error = error;
4641
4642         if (!service->path)
4643                 return;
4644
4645 #if !defined TIZEN_EXT
4646         if (!allow_property_changed(service))
4647                 return;
4648 #endif
4649
4650         str = error2string(service->error);
4651
4652         if (!str)
4653                 str = "";
4654
4655         connman_dbus_property_changed_basic(service->path,
4656                                 CONNMAN_SERVICE_INTERFACE, "Error",
4657                                 DBUS_TYPE_STRING, &str);
4658 }
4659
4660 static void set_idle(struct connman_service *service)
4661 {
4662         service->state = service->state_ipv4 = service->state_ipv6 =
4663                                                 CONNMAN_SERVICE_STATE_IDLE;
4664         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
4665         state_changed(service);
4666 }
4667
4668 static DBusMessage *clear_property(DBusConnection *conn,
4669                                         DBusMessage *msg, void *user_data)
4670 {
4671         struct connman_service *service = user_data;
4672         const char *name;
4673
4674         DBG("service %p", service);
4675
4676         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
4677                                                         DBUS_TYPE_INVALID);
4678
4679         if (g_str_equal(name, "Error")) {
4680                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
4681
4682                 g_get_current_time(&service->modified);
4683                 service_save(service);
4684         } else
4685                 return __connman_error_invalid_property(msg);
4686
4687         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4688 }
4689
4690 static bool is_ipconfig_usable(struct connman_service *service)
4691 {
4692         if (!__connman_ipconfig_is_usable(service->ipconfig_ipv4) &&
4693                         !__connman_ipconfig_is_usable(service->ipconfig_ipv6))
4694                 return false;
4695
4696         return true;
4697 }
4698
4699 static bool is_ignore(struct connman_service *service)
4700 {
4701         if (!service->autoconnect)
4702                 return true;
4703
4704         if (service->roaming)
4705                 return true;
4706
4707         if (service->ignore)
4708                 return true;
4709
4710         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
4711                 return true;
4712
4713         if (!is_ipconfig_usable(service))
4714                 return true;
4715
4716         return false;
4717 }
4718
4719 static void disconnect_on_last_session(enum connman_service_type type)
4720 {
4721         GList *list;
4722
4723         for (list = service_list; list; list = list->next) {
4724                 struct connman_service *service = list->data;
4725
4726                 if (service->type != type)
4727                         continue;
4728
4729                 if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_SESSION)
4730                          continue;
4731
4732                 __connman_service_disconnect(service);
4733                 return;
4734         }
4735 }
4736
4737 static int active_sessions[MAX_CONNMAN_SERVICE_TYPES] = {};
4738 static int active_count = 0;
4739
4740 void __connman_service_set_active_session(bool enable, GSList *list)
4741 {
4742         if (!list)
4743                 return;
4744
4745         if (enable)
4746                 active_count++;
4747         else
4748                 active_count--;
4749
4750         while (list != NULL) {
4751                 enum connman_service_type type = GPOINTER_TO_INT(list->data);
4752
4753                 switch (type) {
4754                 case CONNMAN_SERVICE_TYPE_ETHERNET:
4755                 case CONNMAN_SERVICE_TYPE_WIFI:
4756                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
4757                 case CONNMAN_SERVICE_TYPE_CELLULAR:
4758                 case CONNMAN_SERVICE_TYPE_GADGET:
4759                         if (enable)
4760                                 active_sessions[type]++;
4761                         else
4762                                 active_sessions[type]--;
4763                         break;
4764
4765                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
4766                 case CONNMAN_SERVICE_TYPE_SYSTEM:
4767                 case CONNMAN_SERVICE_TYPE_GPS:
4768                 case CONNMAN_SERVICE_TYPE_VPN:
4769                 case CONNMAN_SERVICE_TYPE_P2P:
4770                         break;
4771                 }
4772
4773                 if (active_sessions[type] == 0)
4774                         disconnect_on_last_session(type);
4775
4776                 list = g_slist_next(list);
4777         }
4778
4779         DBG("eth %d wifi %d bt %d cellular %d gadget %d sessions %d",
4780                         active_sessions[CONNMAN_SERVICE_TYPE_ETHERNET],
4781                         active_sessions[CONNMAN_SERVICE_TYPE_WIFI],
4782                         active_sessions[CONNMAN_SERVICE_TYPE_BLUETOOTH],
4783                         active_sessions[CONNMAN_SERVICE_TYPE_CELLULAR],
4784                         active_sessions[CONNMAN_SERVICE_TYPE_GADGET],
4785                         active_count);
4786 }
4787
4788 struct preferred_tech_data {
4789         GList *preferred_list;
4790         enum connman_service_type type;
4791 };
4792
4793 static void preferred_tech_add_by_type(gpointer data, gpointer user_data)
4794 {
4795         struct connman_service *service = data;
4796         struct preferred_tech_data *tech_data = user_data;
4797
4798         if (service->type == tech_data->type) {
4799                 tech_data->preferred_list =
4800                         g_list_append(tech_data->preferred_list, service);
4801
4802                 DBG("type %d service %p %s", tech_data->type, service,
4803                                 service->name);
4804         }
4805 }
4806
4807 static GList *preferred_tech_list_get(void)
4808 {
4809         unsigned int *tech_array;
4810         struct preferred_tech_data tech_data = { 0, };
4811         int i;
4812
4813         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
4814         if (!tech_array)
4815                 return NULL;
4816
4817         if (connman_setting_get_bool("SingleConnectedTechnology")) {
4818                 GList *list;
4819                 for (list = service_list; list; list = list->next) {
4820                         struct connman_service *service = list->data;
4821
4822                         if (!is_connected(service))
4823                                 break;
4824
4825                         if (service->connect_reason ==
4826                                         CONNMAN_SERVICE_CONNECT_REASON_USER) {
4827                                 DBG("service %p name %s is user connected",
4828                                                 service, service->name);
4829 #if defined TIZEN_EXT
4830                                 /* We can connect to a favorite service like
4831                                  * wifi even we have a userconnect for cellular
4832                                  * because we have refount for cellular service
4833                                  */
4834                                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
4835                                         break;
4836
4837                                 if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
4838                                         break;
4839 #endif
4840                                 return NULL;
4841                         }
4842                 }
4843         }
4844
4845         for (i = 0; tech_array[i] != 0; i += 1) {
4846                 tech_data.type = tech_array[i];
4847                 g_list_foreach(service_list, preferred_tech_add_by_type,
4848                                 &tech_data);
4849         }
4850
4851         return tech_data.preferred_list;
4852 }
4853
4854 static bool auto_connect_service(GList *services,
4855                                 enum connman_service_connect_reason reason,
4856                                 bool preferred)
4857 {
4858         struct connman_service *service = NULL;
4859         bool ignore[MAX_CONNMAN_SERVICE_TYPES] = { };
4860         bool autoconnecting = false;
4861         GList *list;
4862
4863         DBG("preferred %d sessions %d reason %s", preferred, active_count,
4864                 reason2string(reason));
4865
4866         ignore[CONNMAN_SERVICE_TYPE_VPN] = true;
4867
4868         for (list = services; list; list = list->next) {
4869                 service = list->data;
4870
4871                 if (ignore[service->type]) {
4872                         DBG("service %p type %s ignore", service,
4873                                 __connman_service_type2string(service->type));
4874                         continue;
4875                 }
4876
4877 #if defined TIZEN_EXT
4878                 DBG("service %p %s %s %s, favorite(%d), ignore(%d), hidden(%d, %d)",
4879                                 service, service->name,
4880                                 state2string(service->state),
4881                                 __connman_service_type2string(service->type),
4882                                 service->favorite, is_ignore(service),
4883                                 service->hidden, service->hidden_service);
4884
4885                 /* Tizen takes Wi-Fi as the highest priority into consideration. */
4886                 if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
4887                         if (is_connecting(service) == TRUE || is_connected(service) == TRUE)
4888                                 continue;
4889 #endif
4890
4891                 if (service->pending ||
4892                                 is_connecting(service) ||
4893                                 is_connected(service)) {
4894                         if (!active_count)
4895                                 return true;
4896
4897                         ignore[service->type] = true;
4898                         autoconnecting = true;
4899
4900                         DBG("service %p type %s busy", service,
4901                                 __connman_service_type2string(service->type));
4902
4903                         continue;
4904                 }
4905
4906                 if (!service->favorite) {
4907                         if (preferred)
4908                                continue;
4909
4910 #if defined TIZEN_EXT
4911                         DBG("Service is not favorite, autoconnecting %d",
4912                                         autoconnecting);
4913 #endif
4914                         return autoconnecting;
4915                 }
4916
4917 #if defined TIZEN_EXT
4918                 DBG("service %p identifier %s roaming %d ignore %d "
4919                                 "ipconfig_usable %d autoconnect %d state %d",
4920                                 service,
4921                                 service->identifier, service->roaming,
4922                                 service->ignore, is_ipconfig_usable(service),
4923                                 service->autoconnect, service->state);
4924 #endif
4925                 if (is_ignore(service) || service->state !=
4926                                 CONNMAN_SERVICE_STATE_IDLE)
4927                         continue;
4928
4929                 if (autoconnecting && !active_sessions[service->type]) {
4930                         DBG("service %p type %s has no users", service,
4931                                 __connman_service_type2string(service->type));
4932                         continue;
4933                 }
4934
4935                 if (!is_service_owner_user_login(service)) {
4936                         DBG("favorite user not login, wifi auto connect denied");
4937                         continue;
4938                 }
4939
4940                 DBG("service %p %s %s", service, service->name,
4941                         (preferred) ? "preferred" : reason2string(reason));
4942
4943                 __connman_service_connect(service, reason);
4944
4945                 if (!active_count)
4946                         return true;
4947
4948                 ignore[service->type] = true;
4949         }
4950
4951         return autoconnecting;
4952 }
4953
4954 static gboolean run_auto_connect(gpointer data)
4955 {
4956         enum connman_service_connect_reason reason = GPOINTER_TO_UINT(data);
4957         bool autoconnecting = false;
4958         GList *preferred_tech;
4959
4960         autoconnect_timeout = 0;
4961
4962         DBG("");
4963
4964         preferred_tech = preferred_tech_list_get();
4965         if (preferred_tech) {
4966                 autoconnecting = auto_connect_service(preferred_tech, reason,
4967                                                         true);
4968                 g_list_free(preferred_tech);
4969         }
4970
4971         if (!autoconnecting || active_count)
4972                 auto_connect_service(service_list, reason, false);
4973
4974         return FALSE;
4975 }
4976
4977 #if defined TIZEN_EXT
4978 bool __connman_service_get_auto_connect_mode(void)
4979 {
4980         return auto_connect_mode;
4981 }
4982
4983 void __connman_service_set_auto_connect_mode(bool enable)
4984 {
4985         DBG("set auto_connect_mode = %d", enable);
4986
4987         if (auto_connect_mode != enable)
4988                 auto_connect_mode = enable;
4989 }
4990 #endif
4991
4992 void __connman_service_auto_connect(enum connman_service_connect_reason reason)
4993 {
4994         DBG("");
4995
4996         if (autoconnect_timeout != 0)
4997                 return;
4998
4999 #if defined TIZEN_EXT
5000         if (auto_connect_mode == FALSE) {
5001                 DBG("Currently, not auto connection mode");
5002                 return;
5003         }
5004 #endif
5005
5006         if (!__connman_session_policy_autoconnect(reason))
5007                 return;
5008
5009 #if defined TIZEN_EXT
5010         /* Adding Timeout of 500ms before trying to auto connect.
5011          * This is done because of below scenario
5012          * 1. Device is connected to AP1
5013          * 2. WPS Connection request is initiated for AP2
5014          * 3. Immediately WPS Connection is Cancelled
5015          * When WPS Connection Connection is initiated for AP2 then
5016          * sometimes there is a scenario where connman gets in ASSOCIATED
5017          * state with AP1 due to autoconnect and subsequently the connection
5018          * initiated by AP1 fails and connman service for AP1 comes in
5019          * FAILURE state due to this when connection with AP2 is cancelled
5020          * then autoconnect with AP1 doesn't works because its autoconnection
5021          * is ignored as its last state was FAILURE rather than IDLE */
5022         autoconnect_timeout = g_timeout_add(500, run_auto_connect,
5023 #else
5024         autoconnect_timeout = g_timeout_add_seconds(0, run_auto_connect,
5025 #endif
5026                                                 GUINT_TO_POINTER(reason));
5027 }
5028
5029 static gboolean run_vpn_auto_connect(gpointer data) {
5030         GList *list;
5031         bool need_split = false;
5032
5033         vpn_autoconnect_timeout = 0;
5034
5035         for (list = service_list; list; list = list->next) {
5036                 struct connman_service *service = list->data;
5037                 int res;
5038
5039                 if (service->type != CONNMAN_SERVICE_TYPE_VPN)
5040                         continue;
5041
5042                 if (is_connected(service) || is_connecting(service)) {
5043                         if (!service->do_split_routing)
5044                                 need_split = true;
5045                         continue;
5046                 }
5047
5048                 if (is_ignore(service) || !service->favorite)
5049                         continue;
5050
5051                 if (need_split && !service->do_split_routing) {
5052                         DBG("service %p no split routing", service);
5053                         continue;
5054                 }
5055
5056                 DBG("service %p %s %s", service, service->name,
5057                                 service->do_split_routing ?
5058                                 "split routing" : "");
5059
5060                 res = __connman_service_connect(service,
5061                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
5062                 if (res < 0 && res != -EINPROGRESS)
5063                         continue;
5064
5065                 if (!service->do_split_routing)
5066                         need_split = true;
5067         }
5068
5069         return FALSE;
5070 }
5071
5072 static void vpn_auto_connect(void)
5073 {
5074         if (vpn_autoconnect_timeout)
5075                 return;
5076
5077         vpn_autoconnect_timeout =
5078                 g_timeout_add_seconds(0, run_vpn_auto_connect, NULL);
5079 }
5080
5081 static void remove_timeout(struct connman_service *service)
5082 {
5083         if (service->timeout > 0) {
5084                 g_source_remove(service->timeout);
5085                 service->timeout = 0;
5086         }
5087 }
5088
5089 static void reply_pending(struct connman_service *service, int error)
5090 {
5091         remove_timeout(service);
5092
5093         if (service->pending) {
5094                 connman_dbus_reply_pending(service->pending, error, NULL);
5095                 service->pending = NULL;
5096         }
5097
5098         if (service->provider_pending) {
5099                 connman_dbus_reply_pending(service->provider_pending,
5100                                                 error, service->path);
5101                 service->provider_pending = NULL;
5102         }
5103 }
5104
5105 bool
5106 __connman_service_is_provider_pending(struct connman_service *service)
5107 {
5108         if (!service)
5109                 return false;
5110
5111         if (service->provider_pending)
5112                 return true;
5113
5114         return false;
5115 }
5116
5117 void __connman_service_set_provider_pending(struct connman_service *service,
5118                                                         DBusMessage *msg)
5119 {
5120         if (service->provider_pending) {
5121                 DBG("service %p provider pending msg %p already exists",
5122                         service, service->provider_pending);
5123                 return;
5124         }
5125
5126         service->provider_pending = msg;
5127         return;
5128 }
5129
5130 static void check_pending_msg(struct connman_service *service)
5131 {
5132         if (!service->pending)
5133                 return;
5134
5135         DBG("service %p pending msg %p already exists", service,
5136                                                 service->pending);
5137         dbus_message_unref(service->pending);
5138 }
5139
5140 void __connman_service_set_hidden_data(struct connman_service *service,
5141                                                         gpointer user_data)
5142 {
5143         DBusMessage *pending = user_data;
5144
5145         DBG("service %p pending %p", service, pending);
5146
5147         if (!pending)
5148                 return;
5149
5150         check_pending_msg(service);
5151
5152         service->pending = pending;
5153 }
5154
5155 void __connman_service_return_error(struct connman_service *service,
5156                                 int error, gpointer user_data)
5157 {
5158         DBG("service %p error %d user_data %p", service, error, user_data);
5159
5160         __connman_service_set_hidden_data(service, user_data);
5161
5162         reply_pending(service, error);
5163 }
5164
5165 static gboolean connect_timeout(gpointer user_data)
5166 {
5167         struct connman_service *service = user_data;
5168         bool autoconnect = false;
5169
5170         DBG("service %p", service);
5171
5172         service->timeout = 0;
5173
5174         if (service->network)
5175                 __connman_network_disconnect(service->network);
5176         else if (service->provider)
5177                 connman_provider_disconnect(service->provider);
5178
5179         __connman_ipconfig_disable(service->ipconfig_ipv4);
5180         __connman_ipconfig_disable(service->ipconfig_ipv6);
5181
5182         __connman_stats_service_unregister(service);
5183
5184         if (service->pending) {
5185                 DBusMessage *reply;
5186
5187                 reply = __connman_error_operation_timeout(service->pending);
5188                 if (reply)
5189                         g_dbus_send_message(connection, reply);
5190
5191                 dbus_message_unref(service->pending);
5192                 service->pending = NULL;
5193         } else
5194                 autoconnect = true;
5195
5196         __connman_service_ipconfig_indicate_state(service,
5197                                         CONNMAN_SERVICE_STATE_FAILURE,
5198                                         CONNMAN_IPCONFIG_TYPE_IPV4);
5199         __connman_service_ipconfig_indicate_state(service,
5200                                         CONNMAN_SERVICE_STATE_FAILURE,
5201                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5202
5203         if (autoconnect &&
5204                         service->connect_reason !=
5205                                 CONNMAN_SERVICE_CONNECT_REASON_USER)
5206                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
5207
5208         return FALSE;
5209 }
5210
5211 static DBusMessage *connect_service(DBusConnection *conn,
5212                                         DBusMessage *msg, void *user_data)
5213 {
5214         struct connman_service *service = user_data;
5215 #if defined TIZEN_EXT
5216         int err = 0;
5217 #else
5218         int index, err = 0;
5219         GList *list;
5220 #endif
5221
5222         DBG("service %p", service);
5223
5224 #if defined TIZEN_EXT
5225         /*
5226          * Description: TIZEN implements system global connection management.
5227          */
5228         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5229                 connman_service_user_pdn_connection_ref(service);
5230
5231         /*Reset the Disconnect Reason while issue connect request*/
5232         service->disconnect_reason = 0;
5233
5234         /*Reset the association status code while issue connect request*/
5235         service->assoc_status_code = 0;
5236 #endif
5237
5238         if (service->pending)
5239                 return __connman_error_in_progress(msg);
5240
5241         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
5242                 uid_t uid;
5243                 if (connman_dbus_get_connection_unix_user_sync(conn,
5244                                                 dbus_message_get_sender(msg),
5245                                                 &uid) < 0) {
5246                         DBG("Can not get unix user id!");
5247                         return __connman_error_permission_denied(msg);
5248                 }
5249
5250                 if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
5251                         DBG("Not allow this user to connect this wifi service now!");
5252                         return __connman_error_permission_denied(msg);
5253                 }
5254
5255                 if (uid != USER_ROOT && uid != service->user.favorite_user)
5256                         service->request_passphrase_input = true;
5257
5258                 service->user.current_user = uid;
5259
5260                 if (!service->passphrase && uid == service->user.favorite_user) {
5261                         DBG("Now load this favorite user's passphrase.");
5262                         service_load_passphrase(service);
5263                 }
5264         }
5265
5266 #if !defined TIZEN_EXT
5267         index = __connman_service_get_index(service);
5268
5269         for (list = service_list; list; list = list->next) {
5270                 struct connman_service *temp = list->data;
5271
5272 #if defined TIZEN_EXT
5273                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5274                         break;
5275 #endif
5276                 if (!is_connecting(temp) && !is_connected(temp))
5277                         break;
5278
5279                 if (service == temp)
5280                         continue;
5281
5282                 if (service->type != temp->type)
5283                         continue;
5284
5285                 if (__connman_service_get_index(temp) == index &&
5286                                 __connman_service_disconnect(temp) == -EINPROGRESS)
5287                         err = -EINPROGRESS;
5288
5289         }
5290         if (err == -EINPROGRESS)
5291                 return __connman_error_operation_timeout(msg);
5292 #endif
5293
5294         service->ignore = false;
5295
5296         service->pending = dbus_message_ref(msg);
5297
5298         err = __connman_service_connect(service,
5299                         CONNMAN_SERVICE_CONNECT_REASON_USER);
5300
5301         if (err == -EINPROGRESS)
5302                 return NULL;
5303
5304         if (service->pending) {
5305                 dbus_message_unref(service->pending);
5306                 service->pending = NULL;
5307         }
5308
5309         if (err < 0)
5310                 return __connman_error_failed(msg, -err);
5311
5312         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5313 }
5314
5315 static DBusMessage *disconnect_service(DBusConnection *conn,
5316                                         DBusMessage *msg, void *user_data)
5317 {
5318         struct connman_service *service = user_data;
5319         int err;
5320
5321         DBG("service %p", service);
5322
5323 #if defined TIZEN_EXT
5324         /*
5325          * Description: TIZEN implements system global connection management.
5326          */
5327         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
5328                 if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE)
5329                         return __connman_error_failed(msg, EISCONN);
5330
5331                 if (is_connected(service) == TRUE &&
5332                                 service == connman_service_get_default_connection())
5333                         return __connman_error_failed(msg, EISCONN);
5334         }
5335 #endif
5336
5337         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
5338                 uid_t uid;
5339                 if (connman_dbus_get_connection_unix_user_sync(conn,
5340                                                 dbus_message_get_sender(msg),
5341                                                 &uid) < 0) {
5342                         DBG("Can not get unix user id!");
5343                         return __connman_error_permission_denied(msg);
5344                 }
5345
5346                 if (!connman_service_is_user_allowed(service, uid)) {
5347                         DBG("Not allow this user to disconnect this wifi service now!");
5348                         return __connman_error_permission_denied(msg);
5349                 }
5350         }
5351
5352         service->ignore = true;
5353
5354         err = __connman_service_disconnect(service);
5355         if (err < 0 && err != -EINPROGRESS)
5356                 return __connman_error_failed(msg, -err);
5357
5358         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5359 }
5360
5361 #if defined TIZEN_EXT
5362 static void __connman_service_cleanup_network_8021x(struct connman_service *service)
5363 {
5364         if (service == NULL)
5365                 return;
5366
5367         DBG("service %p ", service);
5368
5369         connman_network_set_string(service->network, "WiFi.EAP", NULL);
5370         connman_network_set_string(service->network, "WiFi.Identity", NULL);
5371         connman_network_set_string(service->network, "WiFi.CACertFile", NULL);
5372         connman_network_set_string(service->network, "WiFi.ClientCertFile", NULL);
5373         connman_network_set_string(service->network, "WiFi.PrivateKeyFile", NULL);
5374         connman_network_set_string(service->network, "WiFi.PrivateKeyPassphrase", NULL);
5375         connman_network_set_string(service->network, "WiFi.Phase2", NULL);
5376 }
5377 #endif
5378
5379 bool __connman_service_remove(struct connman_service *service)
5380 {
5381         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET ||
5382                         service->type == CONNMAN_SERVICE_TYPE_GADGET)
5383                 return false;
5384
5385         if (service->immutable || service->hidden ||
5386                         __connman_provider_is_immutable(service->provider))
5387                 return false;
5388
5389 #if !defined TIZEN_EXT
5390         if (!service->favorite && service->state !=
5391                                                 CONNMAN_SERVICE_STATE_FAILURE)
5392                 return false;
5393 #endif
5394
5395         __connman_service_disconnect(service);
5396
5397         g_free(service->passphrase);
5398         service->passphrase = NULL;
5399
5400         g_free(service->identity);
5401         service->identity = NULL;
5402
5403         g_free(service->agent_identity);
5404         service->agent_identity = NULL;
5405
5406         g_free(service->eap);
5407         service->eap = NULL;
5408
5409 #if defined TIZEN_EXT
5410         g_free(service->ca_cert_file);
5411         service->ca_cert_file = NULL;
5412
5413         g_free(service->client_cert_file);
5414         service->client_cert_file = NULL;
5415
5416         g_free(service->private_key_file);
5417         service->private_key_file = NULL;
5418
5419         g_free(service->private_key_passphrase);
5420         service->private_key_passphrase = NULL;
5421
5422         g_free(service->phase2);
5423         service->phase2 = NULL;
5424
5425         __connman_service_cleanup_network_8021x(service);
5426
5427         __connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP);
5428         __connman_ipconfig_set_method(service->ipconfig_ipv6, CONNMAN_IPCONFIG_METHOD_AUTO);
5429         connman_service_set_proxy(service, NULL, false);
5430
5431         __connman_service_nameserver_clear(service);
5432
5433         g_strfreev(service->nameservers_config);
5434         service->nameservers_config = NULL;
5435
5436 #endif
5437
5438 #if defined TIZEN_EXT
5439         if (service->security != CONNMAN_SERVICE_SECURITY_8021X)
5440 #endif
5441         set_idle(service);
5442
5443         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
5444
5445         service->user.favorite_user = USER_NONE;
5446
5447         __connman_service_set_favorite(service, false);
5448
5449         __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
5450
5451 #if defined TIZEN_EXT
5452         /* Reset IP Method and DNS Method to DHCP */
5453         __connman_ipconfig_set_method(service->ipconfig_ipv4,
5454                         CONNMAN_IPCONFIG_METHOD_DHCP);
5455         service->dns_config_method_ipv4 = CONNMAN_DNSCONFIG_METHOD_DHCP;
5456         g_strfreev(service->nameservers_config);
5457         service->nameservers_config = NULL;
5458 #endif
5459
5460 #if defined TIZEN_EXT
5461         __connman_storage_remove_service(service->identifier);
5462 #else
5463         service_save(service);
5464 #endif
5465
5466         return true;
5467 }
5468
5469 static DBusMessage *remove_service(DBusConnection *conn,
5470                                         DBusMessage *msg, void *user_data)
5471 {
5472         struct connman_service *service = user_data;
5473
5474         DBG("service %p", service);
5475
5476         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
5477                 uid_t uid;
5478                 if (connman_dbus_get_connection_unix_user_sync(conn,
5479                                                 dbus_message_get_sender(msg),
5480                                                 &uid) < 0) {
5481                         DBG("Can not get unix user id!");
5482                         return __connman_error_permission_denied(msg);
5483                 }
5484
5485 #if !defined TIZEN_EXT
5486                 if (!connman_service_is_user_allowed(service, uid)) {
5487                         DBG("Not allow this user to remove this wifi service now!");
5488                         return __connman_error_permission_denied(msg);
5489                 }
5490 #endif
5491         }
5492
5493         if (!__connman_service_remove(service))
5494                 return __connman_error_not_supported(msg);
5495
5496         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5497 }
5498
5499 static bool check_suitable_state(enum connman_service_state a,
5500                                         enum connman_service_state b)
5501 {
5502         /*
5503          * Special check so that "ready" service can be moved before
5504          * "online" one.
5505          */
5506         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
5507                         b == CONNMAN_SERVICE_STATE_READY) ||
5508                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
5509                         a == CONNMAN_SERVICE_STATE_READY))
5510                 return true;
5511
5512         return a == b;
5513 }
5514
5515 static void downgrade_state(struct connman_service *service)
5516 {
5517         if (!service)
5518                 return;
5519
5520         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
5521                                                 service->state_ipv6);
5522
5523         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
5524                 __connman_service_ipconfig_indicate_state(service,
5525                                                 CONNMAN_SERVICE_STATE_READY,
5526                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
5527
5528         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
5529                 __connman_service_ipconfig_indicate_state(service,
5530                                                 CONNMAN_SERVICE_STATE_READY,
5531                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5532 }
5533
5534 static void apply_relevant_default_downgrade(struct connman_service *service)
5535 {
5536         struct connman_service *def_service;
5537
5538         def_service = __connman_service_get_default();
5539         if (!def_service)
5540                 return;
5541
5542         if (def_service == service &&
5543                         def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
5544                 def_service->state = CONNMAN_SERVICE_STATE_READY;
5545                 __connman_notifier_leave_online(def_service->type);
5546                 state_changed(def_service);
5547         }
5548 }
5549
5550 static void switch_default_service(struct connman_service *default_service,
5551                 struct connman_service *downgrade_service)
5552 {
5553         struct connman_service *service;
5554         GList *src, *dst;
5555
5556         apply_relevant_default_downgrade(default_service);
5557         src = g_list_find(service_list, downgrade_service);
5558         dst = g_list_find(service_list, default_service);
5559
5560         /* Nothing to do */
5561         if (src == dst || src->next == dst)
5562                 return;
5563
5564         service = src->data;
5565         service_list = g_list_delete_link(service_list, src);
5566         service_list = g_list_insert_before(service_list, dst, service);
5567
5568         downgrade_state(downgrade_service);
5569 }
5570
5571 static DBusMessage *move_service(DBusConnection *conn,
5572                                         DBusMessage *msg, void *user_data,
5573                                                                 bool before)
5574 {
5575         struct connman_service *service = user_data;
5576         struct connman_service *target;
5577         const char *path;
5578         enum connman_ipconfig_method target4, target6;
5579         enum connman_ipconfig_method service4, service6;
5580
5581         DBG("service %p", service);
5582
5583         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
5584                                                         DBUS_TYPE_INVALID);
5585
5586         if (!service->favorite)
5587                 return __connman_error_not_supported(msg);
5588
5589         target = find_service(path);
5590         if (!target || !target->favorite || target == service)
5591                 return __connman_error_invalid_service(msg);
5592
5593         if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
5594                 /*
5595                  * We only allow VPN route splitting if there are
5596                  * routes defined for a given VPN.
5597                  */
5598                 if (!__connman_provider_check_routes(target->provider)) {
5599                         connman_info("Cannot move service. "
5600                                 "No routes defined for provider %s",
5601                                 __connman_provider_get_ident(target->provider));
5602                         return __connman_error_invalid_service(msg);
5603                 }
5604
5605                 target->do_split_routing = true;
5606         } else
5607                 target->do_split_routing = false;
5608
5609         service->do_split_routing = false;
5610
5611         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
5612         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
5613         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
5614         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
5615
5616         DBG("target %s method %d/%d state %d/%d split %d", target->identifier,
5617                 target4, target6, target->state_ipv4, target->state_ipv6,
5618                 target->do_split_routing);
5619
5620         DBG("service %s method %d/%d state %d/%d", service->identifier,
5621                                 service4, service6,
5622                                 service->state_ipv4, service->state_ipv6);
5623
5624         /*
5625          * If method is OFF, then we do not need to check the corresponding
5626          * ipconfig state.
5627          */
5628         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5629                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5630                         if (!check_suitable_state(target->state_ipv6,
5631                                                         service->state_ipv6))
5632                                 return __connman_error_invalid_service(msg);
5633                 }
5634         }
5635
5636         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5637                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5638                         if (!check_suitable_state(target->state_ipv4,
5639                                                         service->state_ipv4))
5640                                 return __connman_error_invalid_service(msg);
5641                 }
5642         }
5643
5644         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5645                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5646                         if (!check_suitable_state(target->state_ipv6,
5647                                                         service->state_ipv6))
5648                                 return __connman_error_invalid_service(msg);
5649                 }
5650         }
5651
5652         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5653                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5654                         if (!check_suitable_state(target->state_ipv4,
5655                                                         service->state_ipv4))
5656                                 return __connman_error_invalid_service(msg);
5657                 }
5658         }
5659
5660         g_get_current_time(&service->modified);
5661         service_save(service);
5662         service_save(target);
5663
5664         /*
5665          * If the service which goes down is the default service and is
5666          * online, we downgrade directly its state to ready so:
5667          * the service which goes up, needs to recompute its state which
5668          * is triggered via downgrading it - if relevant - to state ready.
5669          */
5670         if (before)
5671                 switch_default_service(target, service);
5672         else
5673                 switch_default_service(service, target);
5674
5675         __connman_connection_update_gateway();
5676
5677         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5678 }
5679
5680 static DBusMessage *move_before(DBusConnection *conn,
5681                                         DBusMessage *msg, void *user_data)
5682 {
5683         return move_service(conn, msg, user_data, true);
5684 }
5685
5686 static DBusMessage *move_after(DBusConnection *conn,
5687                                         DBusMessage *msg, void *user_data)
5688 {
5689         return move_service(conn, msg, user_data, false);
5690 }
5691
5692 static DBusMessage *reset_counters(DBusConnection *conn,
5693                                         DBusMessage *msg, void *user_data)
5694 {
5695         struct connman_service *service = user_data;
5696
5697         reset_stats(service);
5698
5699         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5700 }
5701
5702 static DBusMessage *get_user_favorite(DBusConnection *conn,
5703                                         DBusMessage *msg, void *user_data)
5704 {
5705         DBusMessage *reply;
5706         uid_t uid = USER_NONE;
5707         dbus_bool_t user_favorite = false;
5708         struct connman_service *service = user_data;
5709
5710         connman_dbus_get_connection_unix_user_sync(conn,
5711                                         dbus_message_get_sender(msg),
5712                                         &uid);
5713         if (uid == USER_ROOT)
5714                 user_favorite = service->favorite;
5715         else if (uid != USER_NONE && uid == service->user.favorite_user) {
5716                 DBG("The service is favorite to this user!");
5717                 user_favorite = true;
5718         }
5719
5720         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5721         dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,
5722                                 &user_favorite, DBUS_TYPE_INVALID);
5723         return reply;
5724 }
5725
5726 static struct _services_notify {
5727         int id;
5728         GHashTable *add;
5729         GHashTable *remove;
5730 } *services_notify;
5731
5732 static void service_append_added_foreach(gpointer data, gpointer user_data)
5733 {
5734         struct connman_service *service = data;
5735         DBusMessageIter *iter = user_data;
5736
5737         if (!service || !service->path) {
5738 #if !defined TIZEN_EXT
5739                 DBG("service %p or path is NULL", service);
5740 #endif
5741                 return;
5742         }
5743
5744         if (g_hash_table_lookup(services_notify->add, service->path)) {
5745 #if !defined TIZEN_EXT
5746                 DBG("new %s", service->path);
5747 #endif
5748
5749                 append_struct(service, iter);
5750                 g_hash_table_remove(services_notify->add, service->path);
5751         } else {
5752 #if !defined TIZEN_EXT
5753                 DBG("changed %s", service->path);
5754 #endif
5755
5756                 append_struct_service(iter, NULL, service);
5757         }
5758 }
5759
5760 static void service_append_ordered(DBusMessageIter *iter, void *user_data)
5761 {
5762         g_list_foreach(service_list, service_append_added_foreach, iter);
5763 }
5764
5765 static void append_removed(gpointer key, gpointer value, gpointer user_data)
5766 {
5767         char *objpath = key;
5768         DBusMessageIter *iter = user_data;
5769
5770         DBG("removed %s", objpath);
5771         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
5772 }
5773
5774 static void service_append_removed(DBusMessageIter *iter, void *user_data)
5775 {
5776         g_hash_table_foreach(services_notify->remove, append_removed, iter);
5777 }
5778
5779 static gboolean service_send_changed(gpointer data)
5780 {
5781         DBusMessage *signal;
5782
5783         DBG("");
5784
5785         services_notify->id = 0;
5786
5787         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
5788                         CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
5789         if (!signal)
5790                 return FALSE;
5791
5792         __connman_dbus_append_objpath_dict_array(signal,
5793                                         service_append_ordered, NULL);
5794         __connman_dbus_append_objpath_array(signal,
5795                                         service_append_removed, NULL);
5796
5797         dbus_connection_send(connection, signal, NULL);
5798         dbus_message_unref(signal);
5799
5800         g_hash_table_remove_all(services_notify->remove);
5801         g_hash_table_remove_all(services_notify->add);
5802
5803         return FALSE;
5804 }
5805
5806 static void service_schedule_changed(void)
5807 {
5808         if (services_notify->id != 0)
5809                 return;
5810
5811         services_notify->id = g_timeout_add(100, service_send_changed, NULL);
5812 }
5813
5814 static void service_schedule_added(struct connman_service *service)
5815 {
5816         DBG("service %p", service);
5817
5818         g_hash_table_remove(services_notify->remove, service->path);
5819         g_hash_table_replace(services_notify->add, service->path, service);
5820
5821         service_schedule_changed();
5822 }
5823
5824 static void service_schedule_removed(struct connman_service *service)
5825 {
5826         if (!service || !service->path) {
5827                 DBG("service %p or path is NULL", service);
5828                 return;
5829         }
5830
5831         DBG("service %p %s", service, service->path);
5832
5833         g_hash_table_remove(services_notify->add, service->path);
5834         g_hash_table_replace(services_notify->remove, g_strdup(service->path),
5835                         NULL);
5836
5837         service_schedule_changed();
5838 }
5839
5840 static bool allow_property_changed(struct connman_service *service)
5841 {
5842 #if defined TIZEN_EXT
5843         if (service->path == NULL)
5844                 return FALSE;
5845 #endif
5846         if (g_hash_table_lookup_extended(services_notify->add, service->path,
5847                                         NULL, NULL)) {
5848                 DBG("no property updates for service %p", service);
5849                 return false;
5850         }
5851
5852         return true;
5853 }
5854
5855 static const GDBusMethodTable service_methods[] = {
5856         { GDBUS_DEPRECATED_METHOD("GetProperties",
5857                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
5858                         get_properties) },
5859         { GDBUS_METHOD("SetProperty",
5860                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
5861                         NULL, set_property) },
5862         { GDBUS_METHOD("ClearProperty",
5863                         GDBUS_ARGS({ "name", "s" }), NULL,
5864                         clear_property) },
5865         { GDBUS_ASYNC_METHOD("Connect", NULL, NULL,
5866                               connect_service) },
5867         { GDBUS_METHOD("Disconnect", NULL, NULL,
5868                         disconnect_service) },
5869         { GDBUS_METHOD("Remove", NULL, NULL, remove_service) },
5870         { GDBUS_METHOD("MoveBefore",
5871                         GDBUS_ARGS({ "service", "o" }), NULL,
5872                         move_before) },
5873         { GDBUS_METHOD("MoveAfter",
5874                         GDBUS_ARGS({ "service", "o" }), NULL,
5875                         move_after) },
5876         { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
5877         { GDBUS_METHOD("GetUserFavorite",
5878                         NULL, GDBUS_ARGS({ "value", "v" }),
5879                         get_user_favorite) },
5880         { },
5881 };
5882
5883 static const GDBusSignalTable service_signals[] = {
5884         { GDBUS_SIGNAL("PropertyChanged",
5885                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
5886         { },
5887 };
5888
5889 static void service_free(gpointer user_data)
5890 {
5891         struct connman_service *service = user_data;
5892         char *path = service->path;
5893
5894         DBG("service %p", service);
5895
5896         reply_pending(service, ENOENT);
5897
5898         __connman_notifier_service_remove(service);
5899         service_schedule_removed(service);
5900
5901         __connman_wispr_stop(service);
5902         stats_stop(service);
5903
5904         service->path = NULL;
5905
5906         if (path) {
5907                 __connman_connection_update_gateway();
5908
5909                 g_dbus_unregister_interface(connection, path,
5910                                                 CONNMAN_SERVICE_INTERFACE);
5911                 g_free(path);
5912         }
5913
5914         g_hash_table_destroy(service->counter_table);
5915
5916         if (service->network) {
5917                 __connman_network_disconnect(service->network);
5918                 connman_network_unref(service->network);
5919                 service->network = NULL;
5920         }
5921
5922         if (service->provider)
5923                 connman_provider_unref(service->provider);
5924
5925         if (service->ipconfig_ipv4) {
5926                 __connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
5927                 __connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
5928                 __connman_ipconfig_unref(service->ipconfig_ipv4);
5929                 service->ipconfig_ipv4 = NULL;
5930         }
5931
5932         if (service->ipconfig_ipv6) {
5933                 __connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
5934                 __connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
5935                 __connman_ipconfig_unref(service->ipconfig_ipv6);
5936                 service->ipconfig_ipv6 = NULL;
5937         }
5938
5939         g_strfreev(service->timeservers);
5940         g_strfreev(service->timeservers_config);
5941         g_strfreev(service->nameservers);
5942         g_strfreev(service->nameservers_config);
5943         g_strfreev(service->nameservers_auto);
5944         g_strfreev(service->domains);
5945         g_strfreev(service->proxies);
5946         g_strfreev(service->excludes);
5947
5948         g_free(service->hostname);
5949         g_free(service->domainname);
5950         g_free(service->pac);
5951         g_free(service->name);
5952         g_free(service->passphrase);
5953         g_free(service->identifier);
5954         g_free(service->eap);
5955         g_free(service->identity);
5956         g_free(service->agent_identity);
5957         g_free(service->ca_cert_file);
5958         g_free(service->client_cert_file);
5959         g_free(service->private_key_file);
5960         g_free(service->private_key_passphrase);
5961         g_free(service->phase2);
5962         g_free(service->config_file);
5963         g_free(service->config_entry);
5964
5965         if (service->stats.timer)
5966                 g_timer_destroy(service->stats.timer);
5967         if (service->stats_roaming.timer)
5968                 g_timer_destroy(service->stats_roaming.timer);
5969
5970         if (current_default == service)
5971                 current_default = NULL;
5972
5973         g_free(service);
5974 }
5975
5976 static void stats_init(struct connman_service *service)
5977 {
5978         /* home */
5979         service->stats.valid = false;
5980         service->stats.enabled = false;
5981         service->stats.timer = g_timer_new();
5982
5983         /* roaming */
5984         service->stats_roaming.valid = false;
5985         service->stats_roaming.enabled = false;
5986         service->stats_roaming.timer = g_timer_new();
5987 }
5988
5989 static void service_initialize(struct connman_service *service)
5990 {
5991         DBG("service %p", service);
5992
5993         service->refcount = 1;
5994
5995         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
5996
5997         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
5998         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
5999
6000         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
6001         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
6002         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
6003
6004         service->favorite  = false;
6005         service->immutable = false;
6006         service->hidden = false;
6007
6008         service->ignore = false;
6009
6010         service->user.favorite_user = USER_NONE;
6011         service->user.current_user = USER_NONE;
6012
6013         service->request_passphrase_input = false;
6014
6015         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
6016
6017         service->order = 0;
6018
6019         stats_init(service);
6020
6021         service->provider = NULL;
6022
6023         service->wps = false;
6024 #if defined TIZEN_EXT
6025         service->storage_reload = false;
6026         /*
6027          * Description: TIZEN implements system global connection management.
6028          */
6029         service->user_pdn_connection_refcount = 0;
6030         __sync_synchronize();
6031 #endif
6032 }
6033
6034 /**
6035  * connman_service_create:
6036  *
6037  * Allocate a new service.
6038  *
6039  * Returns: a newly-allocated #connman_service structure
6040  */
6041 struct connman_service *connman_service_create(void)
6042 {
6043         GSList *list;
6044         struct connman_stats_counter *counters;
6045         const char *counter;
6046
6047         struct connman_service *service;
6048
6049         service = g_try_new0(struct connman_service, 1);
6050         if (!service)
6051                 return NULL;
6052
6053         DBG("service %p", service);
6054
6055         service->counter_table = g_hash_table_new_full(g_str_hash,
6056                                                 g_str_equal, NULL, g_free);
6057
6058         for (list = counter_list; list; list = list->next) {
6059                 counter = list->data;
6060
6061                 counters = g_try_new0(struct connman_stats_counter, 1);
6062                 if (!counters) {
6063                         g_hash_table_destroy(service->counter_table);
6064                         g_free(service);
6065                         return NULL;
6066                 }
6067
6068                 counters->append_all = true;
6069
6070                 g_hash_table_replace(service->counter_table, (gpointer)counter,
6071                                 counters);
6072         }
6073
6074         service_initialize(service);
6075
6076         return service;
6077 }
6078
6079 /**
6080  * connman_service_ref:
6081  * @service: service structure
6082  *
6083  * Increase reference counter of service
6084  */
6085 struct connman_service *
6086 connman_service_ref_debug(struct connman_service *service,
6087                         const char *file, int line, const char *caller)
6088 {
6089         DBG("%p ref %d by %s:%d:%s()", service, service->refcount + 1,
6090                 file, line, caller);
6091
6092         __sync_fetch_and_add(&service->refcount, 1);
6093
6094         return service;
6095 }
6096
6097 /**
6098  * connman_service_unref:
6099  * @service: service structure
6100  *
6101  * Decrease reference counter of service and release service if no
6102  * longer needed.
6103  */
6104 void connman_service_unref_debug(struct connman_service *service,
6105                         const char *file, int line, const char *caller)
6106 {
6107         DBG("%p ref %d by %s:%d:%s()", service, service->refcount - 1,
6108                 file, line, caller);
6109
6110         if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
6111                 return;
6112
6113         service_list = g_list_remove(service_list, service);
6114
6115         __connman_service_disconnect(service);
6116
6117         g_hash_table_remove(service_hash, service->identifier);
6118 }
6119
6120 static gint service_compare(gconstpointer a, gconstpointer b)
6121 {
6122         struct connman_service *service_a = (void *) a;
6123         struct connman_service *service_b = (void *) b;
6124         enum connman_service_state state_a, state_b;
6125         bool a_connected, b_connected;
6126         gint strength;
6127
6128         state_a = service_a->state;
6129         state_b = service_b->state;
6130         a_connected = is_connected(service_a);
6131         b_connected = is_connected(service_b);
6132
6133         if (a_connected && b_connected) {
6134                 if (service_a->order > service_b->order)
6135                         return -1;
6136
6137                 if (service_a->order < service_b->order)
6138                         return 1;
6139         }
6140
6141         if (state_a != state_b) {
6142                 if (a_connected && b_connected) {
6143                         /* We prefer online over ready state */
6144                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
6145                                 return -1;
6146
6147                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
6148                                 return 1;
6149                 }
6150
6151                 if (a_connected)
6152                         return -1;
6153                 if (b_connected)
6154                         return 1;
6155
6156                 if (is_connecting(service_a))
6157                         return -1;
6158                 if (is_connecting(service_b))
6159                         return 1;
6160         }
6161
6162         if (service_a->favorite && !service_b->favorite)
6163                 return -1;
6164
6165         if (!service_a->favorite && service_b->favorite)
6166                 return 1;
6167
6168         if (service_a->type != service_b->type) {
6169
6170                 if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
6171                         return -1;
6172                 if (service_b->type == CONNMAN_SERVICE_TYPE_ETHERNET)
6173                         return 1;
6174
6175                 if (service_a->type == CONNMAN_SERVICE_TYPE_WIFI)
6176                         return -1;
6177                 if (service_b->type == CONNMAN_SERVICE_TYPE_WIFI)
6178                         return 1;
6179
6180                 if (service_a->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6181                         return -1;
6182                 if (service_b->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6183                         return 1;
6184
6185                 if (service_a->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
6186                         return -1;
6187                 if (service_b->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
6188                         return 1;
6189
6190                 if (service_a->type == CONNMAN_SERVICE_TYPE_VPN)
6191                         return -1;
6192                 if (service_b->type == CONNMAN_SERVICE_TYPE_VPN)
6193                         return 1;
6194
6195                 if (service_a->type == CONNMAN_SERVICE_TYPE_GADGET)
6196                         return -1;
6197                 if (service_b->type == CONNMAN_SERVICE_TYPE_GADGET)
6198                         return 1;
6199         }
6200
6201         strength = (gint) service_b->strength - (gint) service_a->strength;
6202         if (strength)
6203                 return strength;
6204
6205         return g_strcmp0(service_a->name, service_b->name);
6206 }
6207
6208 static void service_list_sort(void)
6209 {
6210         if (service_list && service_list->next) {
6211                 service_list = g_list_sort(service_list, service_compare);
6212                 service_schedule_changed();
6213         }
6214 }
6215
6216 /**
6217  * connman_service_get_type:
6218  * @service: service structure
6219  *
6220  * Get the type of service
6221  */
6222 enum connman_service_type connman_service_get_type(struct connman_service *service)
6223 {
6224         if (!service)
6225                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
6226
6227         return service->type;
6228 }
6229
6230 /**
6231  * connman_service_get_interface:
6232  * @service: service structure
6233  *
6234  * Get network interface of service
6235  */
6236 char *connman_service_get_interface(struct connman_service *service)
6237 {
6238         int index;
6239
6240         if (!service)
6241                 return NULL;
6242
6243         index = __connman_service_get_index(service);
6244
6245         return connman_inet_ifname(index);
6246 }
6247
6248 /**
6249  * __connman_service_is_user_allowed:
6250  * @type: service type
6251  * @uid: user id
6252  *
6253  * Check a user is allowed to operate a type of service
6254  */
6255 bool __connman_service_is_user_allowed(enum connman_service_type type,
6256                                         uid_t uid)
6257 {
6258         GList *list;
6259         uid_t owner_user = USER_NONE;
6260
6261         for (list = service_list; list; list = list->next) {
6262                 struct connman_service *service = list->data;
6263
6264                 if (service->type != type)
6265                         continue;
6266
6267                 if (is_connected(service)) {
6268                         owner_user = service->user.favorite_user;
6269                         break;
6270                 }
6271         }
6272
6273         if (uid == USER_NONE ||
6274                         (uid != USER_ROOT &&
6275                         owner_user != USER_NONE &&
6276                         owner_user != uid))
6277                 return false;
6278
6279         return true;
6280 }
6281
6282 /**
6283  * connman_service_get_network:
6284  * @service: service structure
6285  *
6286  * Get the service network
6287  */
6288 struct connman_network *
6289 __connman_service_get_network(struct connman_service *service)
6290 {
6291         if (!service)
6292                 return NULL;
6293
6294         return service->network;
6295 }
6296
6297 struct connman_ipconfig *
6298 __connman_service_get_ip4config(struct connman_service *service)
6299 {
6300         if (!service)
6301                 return NULL;
6302
6303         return service->ipconfig_ipv4;
6304 }
6305
6306 struct connman_ipconfig *
6307 __connman_service_get_ip6config(struct connman_service *service)
6308 {
6309         if (!service)
6310                 return NULL;
6311
6312         return service->ipconfig_ipv6;
6313 }
6314
6315 struct connman_ipconfig *
6316 __connman_service_get_ipconfig(struct connman_service *service, int family)
6317 {
6318         if (family == AF_INET)
6319                 return __connman_service_get_ip4config(service);
6320         else if (family == AF_INET6)
6321                 return __connman_service_get_ip6config(service);
6322         else
6323                 return NULL;
6324
6325 }
6326
6327 bool __connman_service_is_connected_state(struct connman_service *service,
6328                                         enum connman_ipconfig_type type)
6329 {
6330         if (!service)
6331                 return false;
6332
6333         switch (type) {
6334         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
6335                 break;
6336         case CONNMAN_IPCONFIG_TYPE_IPV4:
6337                 return is_connected_state(service, service->state_ipv4);
6338         case CONNMAN_IPCONFIG_TYPE_IPV6:
6339                 return is_connected_state(service, service->state_ipv6);
6340         case CONNMAN_IPCONFIG_TYPE_ALL:
6341                 return is_connected_state(service,
6342                                         CONNMAN_IPCONFIG_TYPE_IPV4) &&
6343                         is_connected_state(service,
6344                                         CONNMAN_IPCONFIG_TYPE_IPV6);
6345         }
6346
6347         return false;
6348 }
6349 enum connman_service_security __connman_service_get_security(
6350                                 struct connman_service *service)
6351 {
6352         if (!service)
6353                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
6354
6355         return service->security;
6356 }
6357
6358 const char *__connman_service_get_phase2(struct connman_service *service)
6359 {
6360         if (!service)
6361                 return NULL;
6362
6363         return service->phase2;
6364 }
6365
6366 bool __connman_service_wps_enabled(struct connman_service *service)
6367 {
6368         if (!service)
6369                 return false;
6370
6371         return service->wps;
6372 }
6373
6374 void __connman_service_mark_dirty(void)
6375 {
6376         services_dirty = true;
6377 }
6378
6379 #if defined TIZEN_EXT
6380 /**
6381   * Returns profile count if there is any connected profiles
6382   * that use same interface
6383   */
6384 int __connman_service_get_connected_count_of_iface(
6385                                         struct connman_service *service)
6386 {
6387         GList *list;
6388         int count = 0;
6389         int index1 = 0;
6390         int index2 = 0;
6391
6392         DBG("");
6393
6394         index1 = __connman_service_get_index(service);
6395
6396         if (index1 <= 0)
6397                 return 0;
6398
6399         for (list = service_list; list; list = list->next) {
6400                 struct connman_service *service2 = list->data;
6401
6402                 if (service == service2)
6403                         continue;
6404
6405                 index2 = __connman_service_get_index(service2);
6406
6407                 if (is_connected(service2) && index2 > 0 && index1 == index2)
6408                         count++;
6409
6410                 index2 = 0;
6411         }
6412
6413         DBG("Interface index %d, count %d", index1, count);
6414
6415         return count;
6416 }
6417
6418 void __connman_service_set_storage_reload(struct connman_service *service,
6419                                         bool storage_reload)
6420 {
6421         if (service != NULL)
6422                 service->storage_reload = storage_reload;
6423 }
6424 #endif
6425
6426 /**
6427  * __connman_service_set_favorite_delayed:
6428  * @service: service structure
6429  * @favorite: favorite value
6430  * @delay_ordering: do not order service sequence
6431  *
6432  * Change the favorite setting of service
6433  */
6434 int __connman_service_set_favorite_delayed(struct connman_service *service,
6435                                         bool favorite,
6436                                         bool delay_ordering)
6437 {
6438 #if defined TIZEN_EXT
6439         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6440                 return -EIO;
6441 #endif
6442         if (service->hidden)
6443                 return -EOPNOTSUPP;
6444
6445         if (service->favorite == favorite)
6446                 return -EALREADY;
6447
6448         service->favorite = favorite;
6449
6450         if (!delay_ordering)
6451                 __connman_service_get_order(service);
6452
6453         favorite_changed(service);
6454
6455         if (!delay_ordering) {
6456
6457                 service_list_sort();
6458
6459                 __connman_connection_update_gateway();
6460         }
6461
6462         return 0;
6463 }
6464
6465 /**
6466  * __connman_service_set_favorite:
6467  * @service: service structure
6468  * @favorite: favorite value
6469  *
6470  * Change the favorite setting of service
6471  */
6472 int __connman_service_set_favorite(struct connman_service *service,
6473                                                 bool favorite)
6474 {
6475         return __connman_service_set_favorite_delayed(service, favorite,
6476                                                         false);
6477 }
6478
6479 bool connman_service_get_favorite(struct connman_service *service)
6480 {
6481         return service->favorite;
6482 }
6483
6484 bool connman_service_get_autoconnect(struct connman_service *service)
6485 {
6486         return service->autoconnect;
6487 }
6488
6489 int __connman_service_set_immutable(struct connman_service *service,
6490                                                 bool immutable)
6491 {
6492         if (service->hidden)
6493                 return -EOPNOTSUPP;
6494
6495         if (service->immutable == immutable)
6496                 return 0;
6497
6498         service->immutable = immutable;
6499
6500         immutable_changed(service);
6501
6502         return 0;
6503 }
6504
6505 int __connman_service_set_ignore(struct connman_service *service,
6506                                                 bool ignore)
6507 {
6508         if (!service)
6509                 return -EINVAL;
6510
6511         service->ignore = ignore;
6512
6513         return 0;
6514 }
6515
6516 void __connman_service_set_string(struct connman_service *service,
6517                                   const char *key, const char *value)
6518 {
6519         if (service->hidden)
6520                 return;
6521         if (g_str_equal(key, "EAP")) {
6522                 g_free(service->eap);
6523                 service->eap = g_strdup(value);
6524         } else if (g_str_equal(key, "Identity")) {
6525                 g_free(service->identity);
6526                 service->identity = g_strdup(value);
6527         } else if (g_str_equal(key, "CACertFile")) {
6528                 g_free(service->ca_cert_file);
6529                 service->ca_cert_file = g_strdup(value);
6530         } else if (g_str_equal(key, "ClientCertFile")) {
6531                 g_free(service->client_cert_file);
6532                 service->client_cert_file = g_strdup(value);
6533         } else if (g_str_equal(key, "PrivateKeyFile")) {
6534                 g_free(service->private_key_file);
6535                 service->private_key_file = g_strdup(value);
6536         } else if (g_str_equal(key, "PrivateKeyPassphrase")) {
6537                 g_free(service->private_key_passphrase);
6538                 service->private_key_passphrase = g_strdup(value);
6539         } else if (g_str_equal(key, "Phase2")) {
6540                 g_free(service->phase2);
6541                 service->phase2 = g_strdup(value);
6542         } else if (g_str_equal(key, "Passphrase"))
6543                 __connman_service_set_passphrase(service, value);
6544 }
6545
6546 void __connman_service_set_search_domains(struct connman_service *service,
6547                                         char **domains)
6548 {
6549         searchdomain_remove_all(service);
6550
6551         if (service->domains)
6552                 g_strfreev(service->domains);
6553
6554         service->domains = g_strdupv(domains);
6555
6556         searchdomain_add_all(service);
6557 }
6558
6559 static void service_complete(struct connman_service *service)
6560 {
6561         reply_pending(service, EIO);
6562
6563         if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
6564                 __connman_service_auto_connect(service->connect_reason);
6565
6566         g_get_current_time(&service->modified);
6567         service_save(service);
6568 }
6569
6570 static void report_error_cb(void *user_context, bool retry,
6571                                                         void *user_data)
6572 {
6573         struct connman_service *service = user_context;
6574
6575         if (retry)
6576                 __connman_service_connect(service,
6577                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6578         else {
6579                 /* It is not relevant to stay on Failure state
6580                  * when failing is due to wrong user input */
6581                 __connman_service_clear_error(service);
6582 #if defined TIZEN_EXT
6583                 /* Reseting the state back in case of failure state */
6584                 service->state_ipv4 = service->state_ipv6 =
6585                                 CONNMAN_SERVICE_STATE_IDLE;
6586
6587                 if (service->error != CONNMAN_SERVICE_ERROR_AUTH_FAILED)
6588                         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6589 #endif
6590                 service_complete(service);
6591                 __connman_connection_update_gateway();
6592         }
6593 }
6594
6595 static int check_wpspin(struct connman_service *service, const char *wpspin)
6596 {
6597         int length;
6598         guint i;
6599
6600         if (!wpspin)
6601                 return 0;
6602
6603         length = strlen(wpspin);
6604
6605         /* If 0, it will mean user wants to use PBC method */
6606         if (length == 0) {
6607                 connman_network_set_string(service->network,
6608                                                         "WiFi.PinWPS", NULL);
6609                 return 0;
6610         }
6611
6612         /* A WPS PIN is always 8 chars length,
6613          * its content is in digit representation.
6614          */
6615         if (length != 8)
6616                 return -ENOKEY;
6617
6618         for (i = 0; i < 8; i++)
6619                 if (!isdigit((unsigned char) wpspin[i]))
6620                         return -ENOKEY;
6621
6622         connman_network_set_string(service->network, "WiFi.PinWPS", wpspin);
6623
6624         return 0;
6625 }
6626
6627 static void request_input_cb(struct connman_service *service,
6628                         bool values_received,
6629                         const char *name, int name_len,
6630                         const char *identity, const char *passphrase,
6631                         bool wps, const char *wpspin,
6632                         const char *error, void *user_data)
6633 {
6634         struct connman_device *device;
6635         const char *security;
6636         int err = 0;
6637
6638         DBG("RequestInput return, %p", service);
6639
6640         if (error) {
6641                 DBG("error: %s", error);
6642
6643                 if (g_strcmp0(error,
6644                                 "net.connman.Agent.Error.Canceled") == 0) {
6645                         err = -EINVAL;
6646
6647                         if (service->hidden)
6648                                 __connman_service_return_error(service,
6649                                                         ECANCELED, user_data);
6650                         goto done;
6651                 } else {
6652                         if (service->hidden)
6653                                 __connman_service_return_error(service,
6654                                                         ETIMEDOUT, user_data);
6655                 }
6656         }
6657
6658         if (service->hidden && name_len > 0 && name_len <= 32) {
6659                 device = connman_network_get_device(service->network);
6660                 security = connman_network_get_string(service->network,
6661                                                         "WiFi.Security");
6662                 err = __connman_device_request_hidden_scan(device,
6663                                                 name, name_len,
6664                                                 identity, passphrase,
6665                                                 security, user_data);
6666                 if (err < 0)
6667                         __connman_service_return_error(service, -err,
6668                                                         user_data);
6669         }
6670
6671         if (!values_received || service->hidden) {
6672                 err = -EINVAL;
6673                 goto done;
6674         }
6675
6676         if (wps && service->network) {
6677                 err = check_wpspin(service, wpspin);
6678                 if (err < 0)
6679                         goto done;
6680
6681                 connman_network_set_bool(service->network, "WiFi.UseWPS", wps);
6682         }
6683
6684         if (identity)
6685                 __connman_service_set_agent_identity(service, identity);
6686
6687         if (passphrase)
6688                 err = __connman_service_set_passphrase(service, passphrase);
6689
6690  done:
6691         if (err >= 0) {
6692                 /* We forget any previous error. */
6693                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6694
6695                 __connman_service_connect(service,
6696                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6697
6698         } else if (err == -ENOKEY) {
6699                 __connman_service_indicate_error(service,
6700                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
6701         } else {
6702                 /* It is not relevant to stay on Failure state
6703                  * when failing is due to wrong user input */
6704                 service->state = CONNMAN_SERVICE_STATE_IDLE;
6705
6706                 if (!service->hidden) {
6707                         /*
6708                          * If there was a real error when requesting
6709                          * hidden scan, then that error is returned already
6710                          * to the user somewhere above so do not try to
6711                          * do this again.
6712                          */
6713                         __connman_service_return_error(service, -err,
6714                                                         user_data);
6715                 }
6716
6717                 service_complete(service);
6718                 __connman_connection_update_gateway();
6719         }
6720 }
6721
6722 static void downgrade_connected_services(void)
6723 {
6724         struct connman_service *up_service;
6725         GList *list;
6726
6727         for (list = service_list; list; list = list->next) {
6728                 up_service = list->data;
6729
6730                 if (!is_connected(up_service))
6731                         continue;
6732
6733                 if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
6734                         return;
6735
6736                 downgrade_state(up_service);
6737         }
6738 }
6739
6740 static int service_update_preferred_order(struct connman_service *default_service,
6741                 struct connman_service *new_service,
6742                 enum connman_service_state new_state)
6743 {
6744         unsigned int *tech_array;
6745         int i;
6746
6747         if (!default_service || default_service == new_service ||
6748                         default_service->state != new_state)
6749                 return 0;
6750
6751         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
6752         if (tech_array) {
6753
6754                 for (i = 0; tech_array[i] != 0; i += 1) {
6755                         if (default_service->type == tech_array[i])
6756                                 return -EALREADY;
6757
6758                         if (new_service->type == tech_array[i]) {
6759                                 switch_default_service(default_service,
6760                                                 new_service);
6761                                 __connman_connection_update_gateway();
6762                                 return 0;
6763                         }
6764                 }
6765         }
6766
6767         return -EALREADY;
6768 }
6769
6770 #if defined TIZEN_EXT
6771 static gboolean __connman_service_can_drop(struct connman_service *service)
6772 {
6773         if (is_connected(service) == TRUE || is_connecting(service) == TRUE) {
6774                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
6775                         return TRUE;
6776                 else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE)
6777                         return TRUE;
6778         }
6779         return FALSE;
6780 }
6781
6782 static struct connman_device *default_connecting_device = NULL;
6783
6784 static void __connman_service_disconnect_default(struct connman_service *service)
6785 {
6786         struct connman_device *default_device = NULL;
6787
6788         if (default_connecting_device == NULL)
6789                 return;
6790
6791         default_device = connman_network_get_device(
6792                         __connman_service_get_network(service));
6793
6794         DBG("Disconnecting service %p %s", service, service->path);
6795         DBG("Disconnecting device %p %p %s",
6796                         default_connecting_device,
6797                         default_device,
6798                         connman_device_get_string(default_device, "Name"));
6799
6800         if (default_connecting_device == default_device)
6801                 default_connecting_device = NULL;
6802 }
6803
6804 static void __connman_service_connect_default(struct connman_service *current)
6805 {
6806         int err;
6807         GList *list;
6808         bool default_internet;
6809         struct connman_service *service;
6810         struct connman_service *default_service = NULL;
6811         struct connman_device *default_device = NULL;
6812
6813         if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
6814                 switch (current->state) {
6815                 case CONNMAN_SERVICE_STATE_UNKNOWN:
6816                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
6817                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
6818                         return;
6819                 default:
6820                         break;
6821                 }
6822
6823                 if (default_connecting_device &&
6824                                 __connman_service_is_internet_profile(current) == TRUE) {
6825                         if (current->network == NULL)
6826                                 return;
6827
6828                         default_device = connman_network_get_device(current->network);
6829                         if (default_connecting_device == default_device) {
6830                                 DBG("Cellular service[%s]  %p %s",
6831                                                 state2string(current->state), current, current->path);
6832                                 DBG("Cellular device %p %p %s",
6833                                                 default_connecting_device, default_device,
6834                                                 connman_device_get_string(default_device, "Name"));
6835
6836                                 default_connecting_device = NULL;
6837                         }
6838                 }
6839
6840                 return;
6841         } else if (is_connected(current) == TRUE || is_connecting(current) == TRUE)
6842                 return;
6843
6844         /* Always-on: keep default cellular connection as possible */
6845         for (list = service_list; list; list = list->next) {
6846                 service = list->data;
6847
6848                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6849                                 __connman_service_is_internet_profile(service) != TRUE ||
6850                                 service->network == NULL) {
6851                         continue;
6852                 }
6853
6854                 default_internet =
6855                                 connman_network_get_bool(service->network, "DefaultInternet");
6856
6857                 DBG("service: %p %s %s %s (default: %d)", service, service->name,
6858                                 __connman_service_type2string(service->type),
6859                                 state2string(service->state), default_internet);
6860
6861                 if (default_internet) {
6862                         default_service = service;
6863                         if (is_connected(default_service) == TRUE ||
6864                                         is_connecting(default_service) == TRUE)
6865                                 return;
6866
6867                         default_device = connman_network_get_device(default_service->network);
6868                         if (default_connecting_device == default_device) {
6869                                 DBG("Device is connecting (%p)", default_connecting_device);
6870                                 return;
6871                         }
6872
6873                         default_connecting_device = default_device;
6874                         default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
6875
6876                         err = __connman_network_connect(default_service->network);
6877                         DBG("Connecting default service %p %s [%d]",
6878                                         default_service, default_service->path, err);
6879                         DBG("Connecting device %p %s", default_connecting_device,
6880                                         connman_device_get_string(default_connecting_device, "Name"));
6881                         if (err < 0 && err != -EINPROGRESS) {
6882                                 default_connecting_device = NULL;
6883                         } else
6884                                 break;
6885                 }
6886         }
6887 }
6888 #endif
6889
6890 static void single_connected_tech(struct connman_service *allowed)
6891 {
6892         struct connman_service *service;
6893         GSList *services = NULL, *list;
6894         GList *iter;
6895
6896         DBG("keeping %p %s", allowed, allowed->path);
6897
6898 #if defined TIZEN_EXT
6899         if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6900                 return;
6901 #endif
6902
6903         for (iter = service_list; iter; iter = iter->next) {
6904                 service = iter->data;
6905
6906 #if defined TIZEN_EXT
6907                 if (service != allowed && service->type != allowed->type &&
6908                                 __connman_service_can_drop(service) == TRUE)
6909 #else
6910                 if (!is_connected(service))
6911                         break;
6912
6913                 if (service == allowed)
6914                         continue;
6915 #endif
6916                 services = g_slist_prepend(services, service);
6917         }
6918
6919         for (list = services; list; list = list->next) {
6920                 service = list->data;
6921
6922                 DBG("disconnecting %p %s", service, service->path);
6923 #if defined TIZEN_EXT
6924                 __connman_service_disconnect_default(service);
6925 #endif
6926                 __connman_service_disconnect(service);
6927         }
6928
6929         g_slist_free(services);
6930 }
6931
6932 #if defined TIZEN_EXT
6933 static void set_priority_connected_service(void)
6934 {
6935         struct connman_service *service;
6936         GList *list;
6937
6938         for (list = service_list; list; list = list->next) {
6939                 service = list->data;
6940
6941                 if (is_connected(service) == FALSE)
6942                         service->order = 5;
6943                 else
6944                         service->order = 6;
6945         }
6946 }
6947 #endif
6948
6949 static const char *get_dbus_sender(struct connman_service *service)
6950 {
6951         if (!service->pending)
6952                 return NULL;
6953
6954         return dbus_message_get_sender(service->pending);
6955 }
6956
6957 static int service_indicate_state(struct connman_service *service)
6958 {
6959         enum connman_service_state old_state, new_state;
6960         struct connman_service *def_service;
6961         enum connman_ipconfig_method method;
6962         int result;
6963
6964         if (!service)
6965                 return -EINVAL;
6966
6967         old_state = service->state;
6968         new_state = combine_state(service->state_ipv4, service->state_ipv6);
6969
6970         DBG("service %p old %s - new %s/%s => %s",
6971                                         service,
6972                                         state2string(old_state),
6973                                         state2string(service->state_ipv4),
6974                                         state2string(service->state_ipv6),
6975                                         state2string(new_state));
6976
6977         if (old_state == new_state)
6978                 return -EALREADY;
6979
6980         def_service = __connman_service_get_default();
6981
6982         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
6983                 result = service_update_preferred_order(def_service,
6984                                 service, new_state);
6985                 if (result == -EALREADY)
6986                         return result;
6987         }
6988
6989         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
6990                 __connman_notifier_leave_online(service->type);
6991
6992         if (is_connected_state(service, old_state) &&
6993                         !is_connected_state(service, new_state))
6994                 searchdomain_remove_all(service);
6995
6996         service->state = new_state;
6997         state_changed(service);
6998
6999         switch(new_state) {
7000         case CONNMAN_SERVICE_STATE_UNKNOWN:
7001
7002                 break;
7003
7004         case CONNMAN_SERVICE_STATE_IDLE:
7005                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
7006                         __connman_service_disconnect(service);
7007
7008                 break;
7009
7010         case CONNMAN_SERVICE_STATE_ASSOCIATION:
7011
7012                 break;
7013
7014         case CONNMAN_SERVICE_STATE_CONFIGURATION:
7015                 if (!service->new_service &&
7016                                 __connman_stats_service_register(service) == 0) {
7017                         /*
7018                          * For new services the statistics are updated after
7019                          * we have successfully connected.
7020                          */
7021                         __connman_stats_get(service, false,
7022                                                 &service->stats.data);
7023                         __connman_stats_get(service, true,
7024                                                 &service->stats_roaming.data);
7025                 }
7026
7027                 break;
7028
7029         case CONNMAN_SERVICE_STATE_READY:
7030                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7031
7032                 if (service->new_service &&
7033                                 __connman_stats_service_register(service) == 0) {
7034                         /*
7035                          * This is normally done after configuring state
7036                          * but for new service do this after we have connected
7037                          * successfully.
7038                          */
7039                         __connman_stats_get(service, false,
7040                                                 &service->stats.data);
7041                         __connman_stats_get(service, true,
7042                                                 &service->stats_roaming.data);
7043                 }
7044
7045                 service->new_service = false;
7046
7047                 default_changed();
7048
7049                 def_service = __connman_service_get_default();
7050
7051                 service_update_preferred_order(def_service, service, new_state);
7052
7053                 __connman_service_set_favorite(service, true);
7054
7055                 reply_pending(service, 0);
7056
7057                 g_get_current_time(&service->modified);
7058                 service_save(service);
7059
7060                 searchdomain_add_all(service);
7061                 dns_changed(service);
7062                 domain_changed(service);
7063                 proxy_changed(service);
7064
7065                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
7066                         __connman_notifier_connect(service->type);
7067
7068                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7069                         connman_network_get_bool(service->network,
7070                                                 "WiFi.UseWPS")) {
7071                         const char *pass;
7072
7073                         pass = connman_network_get_string(service->network,
7074                                                         "WiFi.Passphrase");
7075
7076                         __connman_service_set_passphrase(service, pass);
7077
7078                         connman_network_set_bool(service->network,
7079                                                         "WiFi.UseWPS", false);
7080                 }
7081
7082                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
7083                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
7084                         __connman_ipconfig_disable_ipv6(
7085                                                 service->ipconfig_ipv6);
7086
7087                 if (connman_setting_get_bool("SingleConnectedTechnology"))
7088                         single_connected_tech(service);
7089                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
7090                         vpn_auto_connect();
7091
7092 #if defined TIZEN_EXT
7093                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7094                         set_priority_connected_service();
7095 #endif
7096
7097                 break;
7098
7099         case CONNMAN_SERVICE_STATE_ONLINE:
7100
7101                 break;
7102
7103         case CONNMAN_SERVICE_STATE_DISCONNECT:
7104                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7105
7106                 reply_pending(service, ECONNABORTED);
7107
7108                 def_service = __connman_service_get_default();
7109                 service->disconnect_reason = connman_network_get_disconnect_reason(service->network);
7110                 service->assoc_status_code = connman_network_get_assoc_status_code(service->network);
7111
7112                 if (!__connman_notifier_is_connected() &&
7113                         def_service &&
7114                                 def_service->provider)
7115                         connman_provider_disconnect(def_service->provider);
7116
7117                 default_changed();
7118
7119                 __connman_wispr_stop(service);
7120
7121                 __connman_wpad_stop(service);
7122
7123 #if defined TIZEN_EXT
7124                 /**
7125                   * Skip the functions if there is any connected profiles
7126                   * that use same interface
7127                   */
7128                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7129                         __connman_service_get_connected_count_of_iface(
7130                                                         service) <= 0) {
7131 #endif
7132                 dns_changed(service);
7133                 domain_changed(service);
7134                 proxy_changed(service);
7135 #if defined TIZEN_EXT
7136                 }
7137 #endif
7138
7139                 /*
7140                  * Previous services which are connected and which states
7141                  * are set to online should reset relevantly ipconfig_state
7142                  * to ready so wispr/portal will be rerun on those
7143                  */
7144                 downgrade_connected_services();
7145
7146                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7147                 break;
7148
7149         case CONNMAN_SERVICE_STATE_FAILURE:
7150 #if defined TIZEN_EXT
7151
7152                 service->assoc_status_code = connman_network_get_assoc_status_code(service->network);
7153
7154                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7155                         service->order = 5;
7156                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7157 #endif
7158                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
7159                         connman_agent_report_error(service, service->path,
7160                                         error2string(service->error),
7161                                         report_error_cb,
7162                                         get_dbus_sender(service),
7163                                         NULL) == -EINPROGRESS)
7164                         return 0;
7165                 service_complete(service);
7166
7167                 break;
7168         }
7169
7170         service_list_sort();
7171
7172 #if defined TIZEN_EXT
7173         __connman_service_connect_default(service);
7174 #endif
7175
7176         __connman_connection_update_gateway();
7177
7178         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
7179                         new_state != CONNMAN_SERVICE_STATE_READY) ||
7180                 (old_state == CONNMAN_SERVICE_STATE_READY &&
7181                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
7182                 __connman_notifier_disconnect(service->type);
7183         }
7184
7185         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
7186                 __connman_notifier_enter_online(service->type);
7187                 default_changed();
7188         }
7189
7190         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7191                 service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
7192                 (new_state == CONNMAN_SERVICE_STATE_READY ||
7193                 new_state == CONNMAN_SERVICE_STATE_ONLINE)) {
7194                 if (service->user.favorite_user != service->user.current_user) {
7195                         DBG("Now set service favorite user id from %d to %d",
7196                         service->user.favorite_user, service->user.current_user);
7197
7198                         service->user.favorite_user = service->user.current_user;
7199
7200                         service_save(service);
7201                 }
7202         }
7203
7204         return 0;
7205 }
7206
7207 int __connman_service_indicate_error(struct connman_service *service,
7208                                         enum connman_service_error error)
7209 {
7210         DBG("service %p error %d", service, error);
7211
7212         if (!service)
7213                 return -EINVAL;
7214
7215         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
7216                 return -EALREADY;
7217
7218         set_error(service, error);
7219
7220 /* default internet service: fix not cleared if pdp activation*/
7221 #if defined TIZEN_EXT
7222                 /*
7223                  * If connection failed for default service(DefaultInternet),
7224                  * default_connecting_device should be cleared.
7225                  */
7226                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7227                                 service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED)
7228                         __connman_service_disconnect_default(service);
7229
7230                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7231                                 service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) {
7232                         g_free(service->passphrase);
7233                         service->passphrase = NULL;
7234                 }
7235 #endif
7236
7237         __connman_service_ipconfig_indicate_state(service,
7238                                                 CONNMAN_SERVICE_STATE_FAILURE,
7239                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7240         __connman_service_ipconfig_indicate_state(service,
7241                                                 CONNMAN_SERVICE_STATE_FAILURE,
7242                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7243         return 0;
7244 }
7245
7246 int __connman_service_clear_error(struct connman_service *service)
7247 {
7248         DBusMessage *pending, *provider_pending;
7249
7250         DBG("service %p", service);
7251
7252         if (!service)
7253                 return -EINVAL;
7254
7255         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
7256                 return -EINVAL;
7257
7258         pending = service->pending;
7259         service->pending = NULL;
7260         provider_pending = service->provider_pending;
7261         service->provider_pending = NULL;
7262
7263         __connman_service_ipconfig_indicate_state(service,
7264                                                 CONNMAN_SERVICE_STATE_IDLE,
7265                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7266
7267         __connman_service_ipconfig_indicate_state(service,
7268                                                 CONNMAN_SERVICE_STATE_IDLE,
7269                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7270
7271         service->pending = pending;
7272         service->provider_pending = provider_pending;
7273
7274         return 0;
7275 }
7276
7277 int __connman_service_indicate_default(struct connman_service *service)
7278 {
7279         DBG("service %p state %s", service, state2string(service->state));
7280
7281         if (!is_connected(service)) {
7282                 /*
7283                  * If service is not yet fully connected, then we must not
7284                  * change the default yet. The default gw will be changed
7285                  * after the service state is in ready.
7286                  */
7287                 return -EINPROGRESS;
7288         }
7289
7290         default_changed();
7291
7292         return 0;
7293 }
7294
7295 enum connman_service_state __connman_service_ipconfig_get_state(
7296                                         struct connman_service *service,
7297                                         enum connman_ipconfig_type type)
7298 {
7299         if (!service)
7300                 return CONNMAN_SERVICE_STATE_UNKNOWN;
7301
7302         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7303                 return service->state_ipv4;
7304
7305         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
7306                 return service->state_ipv6;
7307
7308         return CONNMAN_SERVICE_STATE_UNKNOWN;
7309 }
7310
7311 static void check_proxy_setup(struct connman_service *service)
7312 {
7313         /*
7314          * We start WPAD if we haven't got a PAC URL from DHCP and
7315          * if our proxy manual configuration is either empty or set
7316          * to AUTO with an empty URL.
7317          */
7318
7319         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
7320                 goto done;
7321
7322         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
7323                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
7324                         service->pac))
7325                 goto done;
7326
7327         if (__connman_wpad_start(service) < 0) {
7328                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
7329                 __connman_notifier_proxy_changed(service);
7330                 goto done;
7331         }
7332
7333         return;
7334
7335 done:
7336         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
7337 }
7338
7339 #if defined TIZEN_EXT
7340 void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
7341
7342         DBG("check the proxy and start wispr");
7343         check_proxy_setup(service);
7344         return;
7345 }
7346 #endif
7347
7348 /*
7349  * How many networks are connected at the same time. If more than 1,
7350  * then set the rp_filter setting properly (loose mode routing) so that network
7351  * connectivity works ok. This is only done for IPv4 networks as IPv6
7352  * does not have rp_filter knob.
7353  */
7354 static int connected_networks_count;
7355 static int original_rp_filter;
7356
7357 static void service_rp_filter(struct connman_service *service,
7358                                 bool connected)
7359 {
7360         enum connman_ipconfig_method method;
7361
7362         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
7363
7364         switch (method) {
7365         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
7366         case CONNMAN_IPCONFIG_METHOD_OFF:
7367         case CONNMAN_IPCONFIG_METHOD_AUTO:
7368                 return;
7369         case CONNMAN_IPCONFIG_METHOD_FIXED:
7370         case CONNMAN_IPCONFIG_METHOD_MANUAL:
7371         case CONNMAN_IPCONFIG_METHOD_DHCP:
7372                 break;
7373         }
7374
7375         if (connected) {
7376                 if (connected_networks_count == 1) {
7377                         int filter_value;
7378                         filter_value = __connman_ipconfig_set_rp_filter();
7379                         if (filter_value < 0)
7380                                 return;
7381
7382                         original_rp_filter = filter_value;
7383                 }
7384                 connected_networks_count++;
7385
7386         } else {
7387                 if (connected_networks_count == 2)
7388                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
7389
7390                 connected_networks_count--;
7391                 if (connected_networks_count < 0)
7392                         connected_networks_count = 0;
7393         }
7394
7395         DBG("%s %s ipconfig %p method %d count %d filter %d",
7396                 connected ? "connected" : "disconnected", service->identifier,
7397                 service->ipconfig_ipv4, method,
7398                 connected_networks_count, original_rp_filter);
7399 }
7400
7401 static gboolean redo_wispr(gpointer user_data)
7402 {
7403         struct connman_service *service = user_data;
7404         int refcount = service->refcount - 1;
7405
7406         connman_service_unref(service);
7407         if (refcount == 0) {
7408                 DBG("Service %p already removed", service);
7409                 return FALSE;
7410         }
7411
7412         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
7413
7414         return FALSE;
7415 }
7416
7417 int __connman_service_online_check_failed(struct connman_service *service,
7418                                         enum connman_ipconfig_type type)
7419 {
7420         DBG("service %p type %d count %d", service, type,
7421                                                 service->online_check_count);
7422
7423         /* currently we only retry IPv6 stuff */
7424         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
7425                         service->online_check_count != 1) {
7426                 connman_warn("Online check failed for %p %s", service,
7427                         service->name);
7428                 return 0;
7429         }
7430
7431         service->online_check_count = 0;
7432
7433         /*
7434          * We set the timeout to 1 sec so that we have a chance to get
7435          * necessary IPv6 router advertisement messages that might have
7436          * DNS data etc.
7437          */
7438         g_timeout_add_seconds(1, redo_wispr, connman_service_ref(service));
7439
7440         return EAGAIN;
7441 }
7442
7443 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
7444                                         enum connman_service_state new_state,
7445                                         enum connman_ipconfig_type type)
7446 {
7447         struct connman_ipconfig *ipconfig = NULL;
7448         enum connman_service_state old_state;
7449         enum connman_ipconfig_method method;
7450
7451         if (!service)
7452                 return -EINVAL;
7453
7454         switch (type) {
7455         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
7456         case CONNMAN_IPCONFIG_TYPE_ALL:
7457                 return -EINVAL;
7458
7459         case CONNMAN_IPCONFIG_TYPE_IPV4:
7460                 old_state = service->state_ipv4;
7461                 ipconfig = service->ipconfig_ipv4;
7462
7463                 break;
7464
7465         case CONNMAN_IPCONFIG_TYPE_IPV6:
7466                 old_state = service->state_ipv6;
7467                 ipconfig = service->ipconfig_ipv6;
7468
7469                 break;
7470         }
7471
7472         if (!ipconfig)
7473                 return -EINVAL;
7474
7475         /* Any change? */
7476         if (old_state == new_state)
7477                 return -EALREADY;
7478
7479 #if defined TIZEN_EXT
7480         __sync_synchronize();
7481         if (service->user_pdn_connection_refcount > 0 &&
7482                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7483                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
7484                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
7485                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
7486                         service->user_pdn_connection_refcount = 0;
7487                         __sync_synchronize();
7488                 }
7489 #endif
7490
7491         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
7492                 service, service ? service->identifier : NULL,
7493                 old_state, state2string(old_state),
7494                 new_state, state2string(new_state),
7495                 type, __connman_ipconfig_type2string(type));
7496
7497         switch (new_state) {
7498         case CONNMAN_SERVICE_STATE_UNKNOWN:
7499         case CONNMAN_SERVICE_STATE_IDLE:
7500         case CONNMAN_SERVICE_STATE_ASSOCIATION:
7501                 break;
7502         case CONNMAN_SERVICE_STATE_CONFIGURATION:
7503                 __connman_ipconfig_enable(ipconfig);
7504                 break;
7505         case CONNMAN_SERVICE_STATE_READY:
7506 #if defined TIZEN_EXT
7507                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7508                                 __connman_service_is_internet_profile(service) != TRUE) {
7509                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7510                                 service_rp_filter(service, TRUE);
7511
7512                         break;
7513                 }
7514 #endif
7515                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
7516 #if !defined TIZEN_EXT
7517                         check_proxy_setup(service);
7518 #endif
7519                         service_rp_filter(service, true);
7520                 } else {
7521                         service->online_check_count = 1;
7522                         __connman_wispr_start(service, type);
7523                 }
7524                 break;
7525         case CONNMAN_SERVICE_STATE_ONLINE:
7526                 break;
7527         case CONNMAN_SERVICE_STATE_DISCONNECT:
7528                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
7529                         return -EINVAL;
7530
7531                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7532                         service_rp_filter(service, false);
7533
7534                 break;
7535         case CONNMAN_SERVICE_STATE_FAILURE:
7536                 break;
7537         }
7538
7539         /* Keep that state, but if the ipconfig method is OFF, then we set
7540            the state to IDLE so that it will not affect the combined state
7541            in the future.
7542          */
7543         method = __connman_ipconfig_get_method(ipconfig);
7544         switch (method) {
7545         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
7546         case CONNMAN_IPCONFIG_METHOD_OFF:
7547                 new_state = CONNMAN_SERVICE_STATE_IDLE;
7548                 break;
7549
7550         case CONNMAN_IPCONFIG_METHOD_FIXED:
7551         case CONNMAN_IPCONFIG_METHOD_MANUAL:
7552         case CONNMAN_IPCONFIG_METHOD_DHCP:
7553         case CONNMAN_IPCONFIG_METHOD_AUTO:
7554                 break;
7555
7556         }
7557
7558         if (is_connected_state(service, old_state) &&
7559                         !is_connected_state(service, new_state))
7560 #if defined TIZEN_EXT
7561         {
7562                 DBG("nameserver remove all, type: %d", type);
7563                 nameserver_remove_all(service, type);
7564 #else
7565                 nameserver_remove_all(service);
7566 #endif
7567 #if defined TIZEN_EXT
7568         }
7569 #endif
7570
7571         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7572                 service->state_ipv4 = new_state;
7573         else
7574                 service->state_ipv6 = new_state;
7575
7576         if (!is_connected_state(service, old_state) &&
7577                         is_connected_state(service, new_state))
7578 #if defined TIZEN_EXT
7579         {
7580                 DBG("nameserver add all, type: %d", type);
7581                 nameserver_add_all(service, type);
7582 #else
7583                 nameserver_add_all(service);
7584 #endif
7585 #if defined TIZEN_EXT
7586         }
7587 #endif
7588
7589 #if defined TIZEN_EXT
7590         int ret = service_indicate_state(service);
7591         /*Sent the Ready changed signal again in case IPv4 IP set
7592           after IPv6 IP set*/
7593
7594         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
7595                         && new_state == CONNMAN_SERVICE_STATE_READY) {
7596                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
7597                 state_changed(service);
7598         }
7599
7600         return ret;
7601 #endif
7602         return service_indicate_state(service);
7603 }
7604
7605 static bool prepare_network(struct connman_service *service)
7606 {
7607         enum connman_network_type type;
7608         unsigned int ssid_len;
7609
7610         type = connman_network_get_type(service->network);
7611
7612         switch (type) {
7613         case CONNMAN_NETWORK_TYPE_UNKNOWN:
7614         case CONNMAN_NETWORK_TYPE_VENDOR:
7615                 return false;
7616         case CONNMAN_NETWORK_TYPE_WIFI:
7617                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
7618                                                 &ssid_len))
7619                         return false;
7620
7621                 if (service->passphrase)
7622                         connman_network_set_string(service->network,
7623                                 "WiFi.Passphrase", service->passphrase);
7624                 break;
7625         case CONNMAN_NETWORK_TYPE_ETHERNET:
7626         case CONNMAN_NETWORK_TYPE_GADGET:
7627         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
7628         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
7629         case CONNMAN_NETWORK_TYPE_CELLULAR:
7630                 break;
7631         }
7632
7633         return true;
7634 }
7635
7636 static void prepare_8021x(struct connman_service *service)
7637 {
7638         if (service->eap)
7639                 connman_network_set_string(service->network, "WiFi.EAP",
7640                                                                 service->eap);
7641
7642         if (service->identity)
7643                 connman_network_set_string(service->network, "WiFi.Identity",
7644                                                         service->identity);
7645
7646         if (service->ca_cert_file)
7647                 connman_network_set_string(service->network, "WiFi.CACertFile",
7648                                                         service->ca_cert_file);
7649
7650         if (service->client_cert_file)
7651                 connman_network_set_string(service->network,
7652                                                 "WiFi.ClientCertFile",
7653                                                 service->client_cert_file);
7654
7655         if (service->private_key_file)
7656                 connman_network_set_string(service->network,
7657                                                 "WiFi.PrivateKeyFile",
7658                                                 service->private_key_file);
7659
7660         if (service->private_key_passphrase)
7661                 connman_network_set_string(service->network,
7662                                         "WiFi.PrivateKeyPassphrase",
7663                                         service->private_key_passphrase);
7664
7665         if (service->phase2)
7666                 connman_network_set_string(service->network, "WiFi.Phase2",
7667                                                         service->phase2);
7668 }
7669
7670 static int service_connect(struct connman_service *service)
7671 {
7672         int err;
7673
7674         if (service->hidden)
7675                 return -EPERM;
7676
7677 #if defined TIZEN_EXT
7678         GList *list;
7679         int index;
7680
7681         index = __connman_service_get_index(service);
7682
7683         for (list = service_list; list; list = list->next) {
7684                 struct connman_service *temp = list->data;
7685
7686                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7687                         break;
7688
7689                 if (!is_connecting(temp) && !is_connected(temp))
7690                         break;
7691
7692                 if (service == temp)
7693                         continue;
7694
7695                 if (service->type != temp->type)
7696                         continue;
7697
7698                 if (__connman_service_get_index(temp) == index &&
7699                                 __connman_service_disconnect(temp) == -EINPROGRESS)
7700                         return -EINPROGRESS;
7701         }
7702 #endif
7703
7704         switch (service->type) {
7705         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7706         case CONNMAN_SERVICE_TYPE_SYSTEM:
7707         case CONNMAN_SERVICE_TYPE_GPS:
7708         case CONNMAN_SERVICE_TYPE_P2P:
7709                 return -EINVAL;
7710         case CONNMAN_SERVICE_TYPE_ETHERNET:
7711         case CONNMAN_SERVICE_TYPE_GADGET:
7712         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7713         case CONNMAN_SERVICE_TYPE_CELLULAR:
7714         case CONNMAN_SERVICE_TYPE_VPN:
7715                 break;
7716         case CONNMAN_SERVICE_TYPE_WIFI:
7717                 switch (service->security) {
7718                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7719                 case CONNMAN_SERVICE_SECURITY_NONE:
7720                         break;
7721                 case CONNMAN_SERVICE_SECURITY_WEP:
7722                 case CONNMAN_SERVICE_SECURITY_PSK:
7723                 case CONNMAN_SERVICE_SECURITY_WPA:
7724                 case CONNMAN_SERVICE_SECURITY_RSN:
7725                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7726                                 return -ENOKEY;
7727
7728                         if (service->request_passphrase_input) {
7729                                 DBG("Now try to connect other user's favorite service");
7730                                 service->request_passphrase_input = false;
7731                                 return -ENOKEY;
7732                         } else if (!service->passphrase) {
7733                                 if (!service->network)
7734                                         return -EOPNOTSUPP;
7735
7736                                 if (!service->wps ||
7737                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
7738                                         return -ENOKEY;
7739                         }
7740                         break;
7741
7742                 case CONNMAN_SERVICE_SECURITY_8021X:
7743                         if (!service->eap)
7744                                 return -EINVAL;
7745
7746 #if defined TIZEN_EXT
7747                         /*
7748                          * never request credentials if using EAP-TLS, EAP-SIM
7749                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
7750                          * need to be fully provisioned)
7751                          */
7752                         DBG("service eap: %s", service->eap);
7753                         if (g_str_equal(service->eap, "tls") ||
7754                                 g_str_equal(service->eap, "sim") ||
7755                                 g_str_equal(service->eap, "aka"))
7756                                 break;
7757 #else
7758                         /*
7759                          * never request credentials if using EAP-TLS
7760                          * (EAP-TLS networks need to be fully provisioned)
7761                          */
7762                         if (g_str_equal(service->eap, "tls"))
7763                                 break;
7764 #endif
7765                         /*
7766                          * Return -ENOKEY if either identity or passphrase is
7767                          * missing. Agent provided credentials can be used as
7768                          * fallback if needed.
7769                          */
7770                         if (((!service->identity &&
7771                                         !service->agent_identity) ||
7772                                         !service->passphrase) ||
7773                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7774                                 return -ENOKEY;
7775
7776                         break;
7777                 }
7778                 break;
7779         }
7780
7781         if (service->network) {
7782                 if (!prepare_network(service))
7783                         return -EINVAL;
7784
7785                 switch (service->security) {
7786                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7787                 case CONNMAN_SERVICE_SECURITY_NONE:
7788                 case CONNMAN_SERVICE_SECURITY_WEP:
7789                 case CONNMAN_SERVICE_SECURITY_PSK:
7790                 case CONNMAN_SERVICE_SECURITY_WPA:
7791                 case CONNMAN_SERVICE_SECURITY_RSN:
7792                         break;
7793                 case CONNMAN_SERVICE_SECURITY_8021X:
7794                         prepare_8021x(service);
7795                         break;
7796                 }
7797
7798                 if (__connman_stats_service_register(service) == 0) {
7799                         __connman_stats_get(service, false,
7800                                                 &service->stats.data);
7801                         __connman_stats_get(service, true,
7802                                                 &service->stats_roaming.data);
7803                 }
7804
7805                 if (service->ipconfig_ipv4)
7806                         __connman_ipconfig_enable(service->ipconfig_ipv4);
7807                 if (service->ipconfig_ipv6)
7808                         __connman_ipconfig_enable(service->ipconfig_ipv6);
7809
7810                 err = __connman_network_connect(service->network);
7811         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7812                                         service->provider)
7813                 err = __connman_provider_connect(service->provider);
7814         else
7815                 return -EOPNOTSUPP;
7816
7817         if (err < 0) {
7818                 if (err != -EINPROGRESS) {
7819                         __connman_ipconfig_disable(service->ipconfig_ipv4);
7820                         __connman_ipconfig_disable(service->ipconfig_ipv6);
7821                         __connman_stats_service_unregister(service);
7822                 }
7823         }
7824
7825         return err;
7826 }
7827
7828 int __connman_service_connect(struct connman_service *service,
7829                         enum connman_service_connect_reason reason)
7830 {
7831         int err;
7832
7833         DBG("service %p state %s connect reason %s -> %s",
7834                 service, state2string(service->state),
7835                 reason2string(service->connect_reason),
7836                 reason2string(reason));
7837
7838         if (is_connected(service))
7839                 return -EISCONN;
7840
7841         if (is_connecting(service))
7842                 return -EALREADY;
7843
7844         switch (service->type) {
7845         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7846         case CONNMAN_SERVICE_TYPE_SYSTEM:
7847         case CONNMAN_SERVICE_TYPE_GPS:
7848         case CONNMAN_SERVICE_TYPE_P2P:
7849                 return -EINVAL;
7850
7851         case CONNMAN_SERVICE_TYPE_ETHERNET:
7852         case CONNMAN_SERVICE_TYPE_GADGET:
7853         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7854         case CONNMAN_SERVICE_TYPE_CELLULAR:
7855         case CONNMAN_SERVICE_TYPE_VPN:
7856         case CONNMAN_SERVICE_TYPE_WIFI:
7857                 break;
7858         }
7859
7860         if (!is_ipconfig_usable(service))
7861                 return -ENOLINK;
7862
7863         __connman_service_clear_error(service);
7864
7865         err = service_connect(service);
7866
7867         service->connect_reason = reason;
7868         if (err >= 0)
7869                 return 0;
7870
7871         if (err == -EINPROGRESS) {
7872                 if (service->timeout == 0)
7873                         service->timeout = g_timeout_add_seconds(
7874                                 CONNECT_TIMEOUT, connect_timeout, service);
7875
7876                 return -EINPROGRESS;
7877         }
7878
7879         if (service->network)
7880                 __connman_network_disconnect(service->network);
7881         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7882                                 service->provider)
7883                         connman_provider_disconnect(service->provider);
7884
7885         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
7886                 if (err == -ENOKEY || err == -EPERM) {
7887                         DBusMessage *pending = NULL;
7888
7889                         /*
7890                          * We steal the reply here. The idea is that the
7891                          * connecting client will see the connection status
7892                          * after the real hidden network is connected or
7893                          * connection failed.
7894                          */
7895                         if (service->hidden) {
7896                                 pending = service->pending;
7897                                 service->pending = NULL;
7898                         }
7899
7900                         err = __connman_agent_request_passphrase_input(service,
7901                                         request_input_cb,
7902                                         get_dbus_sender(service),
7903                                         pending);
7904                         if (service->hidden && err != -EINPROGRESS)
7905                                 service->pending = pending;
7906
7907                         return err;
7908                 }
7909                 reply_pending(service, -err);
7910         }
7911
7912         return err;
7913 }
7914
7915 int __connman_service_disconnect(struct connman_service *service)
7916 {
7917         int err;
7918
7919         DBG("service %p", service);
7920
7921         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
7922         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
7923
7924         connman_agent_cancel(service);
7925
7926         reply_pending(service, ECONNABORTED);
7927
7928         if (service->network) {
7929                 err = __connman_network_disconnect(service->network);
7930         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7931                                         service->provider)
7932                 err = connman_provider_disconnect(service->provider);
7933         else
7934                 return -EOPNOTSUPP;
7935
7936         if (err < 0 && err != -EINPROGRESS)
7937                 return err;
7938
7939         __connman_6to4_remove(service->ipconfig_ipv4);
7940
7941         if (service->ipconfig_ipv4)
7942                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
7943                                                         NULL);
7944         else
7945                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
7946                                                         NULL);
7947
7948 #if defined TIZEN_EXT
7949         /**
7950           * Skip the functions If there is any connected profiles
7951           * that use same interface
7952           */
7953         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7954                 __connman_service_get_connected_count_of_iface(service) <= 0) {
7955 #endif
7956         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
7957         settings_changed(service, service->ipconfig_ipv4);
7958
7959         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
7960         settings_changed(service, service->ipconfig_ipv6);
7961
7962         __connman_ipconfig_disable(service->ipconfig_ipv4);
7963         __connman_ipconfig_disable(service->ipconfig_ipv6);
7964 #if defined TIZEN_EXT
7965         }
7966 #endif
7967
7968         __connman_stats_service_unregister(service);
7969
7970         return err;
7971 }
7972
7973 int __connman_service_disconnect_all(void)
7974 {
7975         struct connman_service *service;
7976         GSList *services = NULL, *list;
7977         GList *iter;
7978
7979         DBG("");
7980
7981         for (iter = service_list; iter; iter = iter->next) {
7982                 service = iter->data;
7983
7984                 if (!is_connected(service))
7985                         break;
7986
7987                 services = g_slist_prepend(services, service);
7988         }
7989
7990         for (list = services; list; list = list->next) {
7991                 struct connman_service *service = list->data;
7992
7993                 service->ignore = true;
7994
7995                 __connman_service_disconnect(service);
7996         }
7997
7998         g_slist_free(services);
7999
8000         return 0;
8001 }
8002
8003 /**
8004  * lookup_by_identifier:
8005  * @identifier: service identifier
8006  *
8007  * Look up a service by identifier (reference count will not be increased)
8008  */
8009 static struct connman_service *lookup_by_identifier(const char *identifier)
8010 {
8011         return g_hash_table_lookup(service_hash, identifier);
8012 }
8013
8014 struct provision_user_data {
8015         const char *ident;
8016         int ret;
8017 };
8018
8019 static void provision_changed(gpointer value, gpointer user_data)
8020 {
8021         struct connman_service *service = value;
8022         struct provision_user_data *data = user_data;
8023         const char *path = data->ident;
8024         int ret;
8025
8026         ret = __connman_config_provision_service_ident(service, path,
8027                         service->config_file, service->config_entry);
8028         if (ret > 0)
8029                 data->ret = ret;
8030 }
8031
8032 int __connman_service_provision_changed(const char *ident)
8033 {
8034         struct provision_user_data data = {
8035                 .ident = ident,
8036                 .ret = 0
8037         };
8038
8039         g_list_foreach(service_list, provision_changed, (void *)&data);
8040
8041         /*
8042          * Because the provision_changed() might have set some services
8043          * as favorite, we must sort the sequence now.
8044          */
8045         if (services_dirty) {
8046                 services_dirty = false;
8047
8048                 service_list_sort();
8049
8050                 __connman_connection_update_gateway();
8051         }
8052
8053         return data.ret;
8054 }
8055
8056 void __connman_service_set_config(struct connman_service *service,
8057                                 const char *file_id, const char *entry)
8058 {
8059         if (!service)
8060                 return;
8061
8062         g_free(service->config_file);
8063         service->config_file = g_strdup(file_id);
8064
8065         g_free(service->config_entry);
8066         service->config_entry = g_strdup(entry);
8067 }
8068
8069 /**
8070  * __connman_service_get:
8071  * @identifier: service identifier
8072  *
8073  * Look up a service by identifier or create a new one if not found
8074  */
8075 static struct connman_service *service_get(const char *identifier)
8076 {
8077         struct connman_service *service;
8078
8079         service = g_hash_table_lookup(service_hash, identifier);
8080         if (service) {
8081                 connman_service_ref(service);
8082                 return service;
8083         }
8084
8085         service = connman_service_create();
8086         if (!service)
8087                 return NULL;
8088
8089         DBG("service %p", service);
8090
8091         service->identifier = g_strdup(identifier);
8092
8093         service_list = g_list_insert_sorted(service_list, service,
8094                                                 service_compare);
8095
8096         g_hash_table_insert(service_hash, service->identifier, service);
8097
8098         return service;
8099 }
8100
8101 static int service_register(struct connman_service *service)
8102 {
8103         DBG("service %p", service);
8104
8105         if (service->path)
8106                 return -EALREADY;
8107
8108         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
8109                                                 service->identifier);
8110
8111         DBG("path %s", service->path);
8112
8113         if (__connman_config_provision_service(service) < 0)
8114                 service_load(service);
8115
8116         g_dbus_register_interface(connection, service->path,
8117                                         CONNMAN_SERVICE_INTERFACE,
8118                                         service_methods, service_signals,
8119                                                         NULL, service, NULL);
8120
8121         service_list_sort();
8122
8123         __connman_connection_update_gateway();
8124
8125         return 0;
8126 }
8127
8128 static void service_up(struct connman_ipconfig *ipconfig,
8129                 const char *ifname)
8130 {
8131         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8132
8133         DBG("%s up", ifname);
8134
8135         link_changed(service);
8136
8137         service->stats.valid = false;
8138         service->stats_roaming.valid = false;
8139 }
8140
8141 static void service_down(struct connman_ipconfig *ipconfig,
8142                         const char *ifname)
8143 {
8144         DBG("%s down", ifname);
8145 }
8146
8147 static void service_lower_up(struct connman_ipconfig *ipconfig,
8148                         const char *ifname)
8149 {
8150         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8151
8152         DBG("%s lower up", ifname);
8153
8154         stats_start(service);
8155 }
8156
8157 static void service_lower_down(struct connman_ipconfig *ipconfig,
8158                         const char *ifname)
8159 {
8160         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8161
8162         DBG("%s lower down", ifname);
8163
8164         if (!is_idle_state(service, service->state_ipv4))
8165                 __connman_ipconfig_disable(service->ipconfig_ipv4);
8166
8167         if (!is_idle_state(service, service->state_ipv6))
8168                 __connman_ipconfig_disable(service->ipconfig_ipv6);
8169
8170         stats_stop(service);
8171         service_save(service);
8172 }
8173
8174 static void service_ip_bound(struct connman_ipconfig *ipconfig,
8175                         const char *ifname)
8176 {
8177         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8178         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
8179         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
8180 #if defined TIZEN_EXT
8181         int err;
8182 #endif
8183
8184         DBG("%s ip bound", ifname);
8185
8186         type = __connman_ipconfig_get_config_type(ipconfig);
8187         method = __connman_ipconfig_get_method(ipconfig);
8188
8189         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
8190                                                         type, method);
8191
8192         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
8193                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
8194 #if defined TIZEN_EXT
8195         {
8196                 err = __connman_ipconfig_gateway_add(ipconfig, service);
8197
8198                 if(err == 0)
8199                         __connman_connection_gateway_activate(service,
8200                                         CONNMAN_IPCONFIG_TYPE_IPV6);
8201         }
8202 #else
8203                 __connman_service_ipconfig_indicate_state(service,
8204                                                 CONNMAN_SERVICE_STATE_READY,
8205                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
8206 #endif
8207
8208         settings_changed(service, ipconfig);
8209 }
8210
8211 static void service_ip_release(struct connman_ipconfig *ipconfig,
8212                         const char *ifname)
8213 {
8214         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8215         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
8216         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
8217
8218         DBG("%s ip release", ifname);
8219
8220         type = __connman_ipconfig_get_config_type(ipconfig);
8221         method = __connman_ipconfig_get_method(ipconfig);
8222
8223         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
8224                                                         type, method);
8225
8226         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
8227                         method == CONNMAN_IPCONFIG_METHOD_OFF)
8228                 __connman_service_ipconfig_indicate_state(service,
8229                                         CONNMAN_SERVICE_STATE_DISCONNECT,
8230                                         CONNMAN_IPCONFIG_TYPE_IPV6);
8231
8232         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
8233                         method == CONNMAN_IPCONFIG_METHOD_OFF)
8234                 __connman_service_ipconfig_indicate_state(service,
8235                                         CONNMAN_SERVICE_STATE_DISCONNECT,
8236                                         CONNMAN_IPCONFIG_TYPE_IPV4);
8237
8238         settings_changed(service, ipconfig);
8239 }
8240
8241 static void service_route_changed(struct connman_ipconfig *ipconfig,
8242                                 const char *ifname)
8243 {
8244         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8245
8246         DBG("%s route changed", ifname);
8247
8248         settings_changed(service, ipconfig);
8249 }
8250
8251 static const struct connman_ipconfig_ops service_ops = {
8252         .up             = service_up,
8253         .down           = service_down,
8254         .lower_up       = service_lower_up,
8255         .lower_down     = service_lower_down,
8256         .ip_bound       = service_ip_bound,
8257         .ip_release     = service_ip_release,
8258         .route_set      = service_route_changed,
8259         .route_unset    = service_route_changed,
8260 };
8261
8262 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
8263                 int index, enum connman_ipconfig_method method)
8264 {
8265         struct connman_ipconfig *ipconfig_ipv4;
8266
8267         ipconfig_ipv4 = __connman_ipconfig_create(index,
8268                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
8269         if (!ipconfig_ipv4)
8270                 return NULL;
8271
8272         __connman_ipconfig_set_method(ipconfig_ipv4, method);
8273
8274         __connman_ipconfig_set_data(ipconfig_ipv4, service);
8275
8276         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
8277
8278         return ipconfig_ipv4;
8279 }
8280
8281 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
8282                 int index)
8283 {
8284         struct connman_ipconfig *ipconfig_ipv6;
8285
8286         ipconfig_ipv6 = __connman_ipconfig_create(index,
8287                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
8288         if (!ipconfig_ipv6)
8289                 return NULL;
8290
8291         __connman_ipconfig_set_data(ipconfig_ipv6, service);
8292
8293         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
8294
8295         return ipconfig_ipv6;
8296 }
8297
8298 void __connman_service_read_ip4config(struct connman_service *service)
8299 {
8300         GKeyFile *keyfile;
8301
8302         if (!service->ipconfig_ipv4)
8303                 return;
8304
8305         keyfile = connman_storage_load_service(service->identifier);
8306         if (!keyfile)
8307                 return;
8308
8309         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
8310                                 service->identifier, "IPv4.");
8311
8312         g_key_file_free(keyfile);
8313 }
8314
8315 void connman_service_create_ip4config(struct connman_service *service,
8316                                         int index)
8317 {
8318         DBG("ipv4 %p", service->ipconfig_ipv4);
8319
8320         if (service->ipconfig_ipv4)
8321                 return;
8322
8323         service->ipconfig_ipv4 = create_ip4config(service, index,
8324                         CONNMAN_IPCONFIG_METHOD_DHCP);
8325         __connman_service_read_ip4config(service);
8326 }
8327
8328 void __connman_service_read_ip6config(struct connman_service *service)
8329 {
8330         GKeyFile *keyfile;
8331
8332         if (!service->ipconfig_ipv6)
8333                 return;
8334
8335         keyfile = connman_storage_load_service(service->identifier);
8336         if (!keyfile)
8337                 return;
8338
8339         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
8340                                 service->identifier, "IPv6.");
8341
8342         g_key_file_free(keyfile);
8343 }
8344
8345 void connman_service_create_ip6config(struct connman_service *service,
8346                                                                 int index)
8347 {
8348         DBG("ipv6 %p", service->ipconfig_ipv6);
8349
8350         if (service->ipconfig_ipv6)
8351                 return;
8352
8353         service->ipconfig_ipv6 = create_ip6config(service, index);
8354
8355         __connman_service_read_ip6config(service);
8356 }
8357
8358 /**
8359  * connman_service_lookup_from_network:
8360  * @network: network structure
8361  *
8362  * Look up a service by network (reference count will not be increased)
8363  */
8364 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
8365 {
8366         struct connman_service *service;
8367         const char *ident, *group;
8368         char *name;
8369
8370         if (!network)
8371                 return NULL;
8372
8373         ident = __connman_network_get_ident(network);
8374         if (!ident)
8375                 return NULL;
8376
8377         group = connman_network_get_group(network);
8378         if (!group)
8379                 return NULL;
8380
8381         name = g_strdup_printf("%s_%s_%s",
8382                         __connman_network_get_type(network), ident, group);
8383         service = lookup_by_identifier(name);
8384         g_free(name);
8385
8386         return service;
8387 }
8388
8389 struct connman_service *__connman_service_lookup_from_index(int index)
8390 {
8391         struct connman_service *service;
8392         GList *list;
8393
8394         for (list = service_list; list; list = list->next) {
8395                 service = list->data;
8396
8397                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
8398                                                         == index)
8399                         return service;
8400
8401                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
8402                                                         == index)
8403                         return service;
8404         }
8405
8406         return NULL;
8407 }
8408
8409 struct connman_service *__connman_service_lookup_from_ident(const char *identifier)
8410 {
8411         return lookup_by_identifier(identifier);
8412 }
8413
8414 const char *__connman_service_get_ident(struct connman_service *service)
8415 {
8416         return service->identifier;
8417 }
8418
8419 const char *__connman_service_get_path(struct connman_service *service)
8420 {
8421         return service->path;
8422 }
8423
8424 const char *__connman_service_get_name(struct connman_service *service)
8425 {
8426         return service->name;
8427 }
8428
8429 enum connman_service_state __connman_service_get_state(struct connman_service *service)
8430 {
8431         return service->state;
8432 }
8433
8434 unsigned int __connman_service_get_order(struct connman_service *service)
8435 {
8436         unsigned int order = 0;
8437
8438         if (!service)
8439                 return 0;
8440
8441         service->order = 0;
8442
8443         if (!service->favorite)
8444                 return 0;
8445
8446 #if defined TIZEN_EXT
8447         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
8448                         service->do_split_routing == FALSE)
8449                 order = 10;
8450         else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
8451                 if (service->order < 5)
8452                         order = 5;
8453         } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
8454                 order = 4;
8455         else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
8456                 order = 3;
8457         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
8458                         __connman_service_is_internet_profile(service) == TRUE)
8459                 order = 1;
8460         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
8461                         __connman_service_is_tethering_profile(service) == TRUE)
8462                 order = 0;
8463         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
8464                 order = 0;
8465         else
8466                 order = 2;
8467 #else
8468         if (service == service_list->data)
8469                 order = 1;
8470
8471         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
8472                         !service->do_split_routing) {
8473                 service->order = 10;
8474                 order = 10;
8475         }
8476 #endif
8477         DBG("service %p name %s order %d split %d", service, service->name,
8478                 order, service->do_split_routing);
8479
8480         return order;
8481 }
8482
8483 void __connman_service_update_ordering(void)
8484 {
8485         if (service_list && service_list->next)
8486                 service_list = g_list_sort(service_list, service_compare);
8487 }
8488
8489 static enum connman_service_type convert_network_type(struct connman_network *network)
8490 {
8491         enum connman_network_type type = connman_network_get_type(network);
8492
8493         switch (type) {
8494         case CONNMAN_NETWORK_TYPE_UNKNOWN:
8495         case CONNMAN_NETWORK_TYPE_VENDOR:
8496                 break;
8497         case CONNMAN_NETWORK_TYPE_ETHERNET:
8498                 return CONNMAN_SERVICE_TYPE_ETHERNET;
8499         case CONNMAN_NETWORK_TYPE_WIFI:
8500                 return CONNMAN_SERVICE_TYPE_WIFI;
8501         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
8502         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
8503                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
8504         case CONNMAN_NETWORK_TYPE_CELLULAR:
8505                 return CONNMAN_SERVICE_TYPE_CELLULAR;
8506         case CONNMAN_NETWORK_TYPE_GADGET:
8507                 return CONNMAN_SERVICE_TYPE_GADGET;
8508         }
8509
8510         return CONNMAN_SERVICE_TYPE_UNKNOWN;
8511 }
8512
8513 static enum connman_service_security convert_wifi_security(const char *security)
8514 {
8515         if (!security)
8516                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
8517         else if (g_str_equal(security, "none"))
8518                 return CONNMAN_SERVICE_SECURITY_NONE;
8519         else if (g_str_equal(security, "wep"))
8520                 return CONNMAN_SERVICE_SECURITY_WEP;
8521         else if (g_str_equal(security, "psk"))
8522                 return CONNMAN_SERVICE_SECURITY_PSK;
8523         else if (g_str_equal(security, "ieee8021x"))
8524                 return CONNMAN_SERVICE_SECURITY_8021X;
8525         else if (g_str_equal(security, "wpa"))
8526                 return CONNMAN_SERVICE_SECURITY_WPA;
8527         else if (g_str_equal(security, "rsn"))
8528                 return CONNMAN_SERVICE_SECURITY_RSN;
8529 #if defined TIZEN_EXT
8530         else if (g_str_equal(security, "ft_psk") == TRUE)
8531                 return CONNMAN_SERVICE_SECURITY_PSK;
8532         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
8533                 return CONNMAN_SERVICE_SECURITY_8021X;
8534 #endif
8535         else
8536                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
8537 }
8538
8539 #if defined TIZEN_EXT
8540 int check_passphrase_ext(struct connman_network *network,
8541                                         const char *passphrase)
8542 {
8543         const char *str;
8544         enum connman_service_security security;
8545
8546         str = connman_network_get_string(network, "WiFi.Security");
8547         security = convert_wifi_security(str);
8548
8549         return check_passphrase(security, passphrase);
8550 }
8551 #endif
8552
8553 static void update_from_network(struct connman_service *service,
8554                                         struct connman_network *network)
8555 {
8556         uint8_t strength = service->strength;
8557         const char *str;
8558
8559         DBG("service %p network %p", service, network);
8560
8561         if (is_connected(service))
8562                 return;
8563
8564         if (is_connecting(service))
8565                 return;
8566
8567         str = connman_network_get_string(network, "Name");
8568         if (str) {
8569                 g_free(service->name);
8570                 service->name = g_strdup(str);
8571                 service->hidden = false;
8572         } else {
8573                 g_free(service->name);
8574                 service->name = NULL;
8575                 service->hidden = true;
8576         }
8577
8578         service->strength = connman_network_get_strength(network);
8579         service->roaming = connman_network_get_bool(network, "Roaming");
8580
8581         if (service->strength == 0) {
8582                 /*
8583                  * Filter out 0-values; it's unclear what they mean
8584                  * and they cause anomalous sorting of the priority list.
8585                  */
8586                 service->strength = strength;
8587         }
8588
8589         str = connman_network_get_string(network, "WiFi.Security");
8590         service->security = convert_wifi_security(str);
8591
8592         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8593                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
8594
8595         if (service->strength > strength && service->network) {
8596                 connman_network_unref(service->network);
8597                 service->network = connman_network_ref(network);
8598
8599                 strength_changed(service);
8600         }
8601
8602         if (!service->network)
8603                 service->network = connman_network_ref(network);
8604
8605         service_list_sort();
8606 }
8607
8608 /**
8609  * __connman_service_create_from_network:
8610  * @network: network structure
8611  *
8612  * Look up service by network and if not found, create one
8613  */
8614 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
8615 {
8616         struct connman_service *service;
8617         struct connman_device *device;
8618         const char *ident, *group;
8619         char *name;
8620         unsigned int *auto_connect_types;
8621         int i, index;
8622
8623         DBG("network %p", network);
8624
8625         if (!network)
8626                 return NULL;
8627
8628         ident = __connman_network_get_ident(network);
8629         if (!ident)
8630                 return NULL;
8631
8632         group = connman_network_get_group(network);
8633         if (!group)
8634                 return NULL;
8635
8636         name = g_strdup_printf("%s_%s_%s",
8637                         __connman_network_get_type(network), ident, group);
8638         service = service_get(name);
8639         g_free(name);
8640
8641         if (!service)
8642                 return NULL;
8643
8644         if (__connman_network_get_weakness(network))
8645                 return service;
8646
8647         if (service->path) {
8648                 update_from_network(service, network);
8649                 __connman_connection_update_gateway();
8650                 return service;
8651         }
8652
8653         service->type = convert_network_type(network);
8654
8655         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
8656         service->autoconnect = false;
8657         for (i = 0; auto_connect_types &&
8658                      auto_connect_types[i] != 0; i++) {
8659                 if (service->type == auto_connect_types[i]) {
8660                         service->autoconnect = true;
8661                         break;
8662                 }
8663         }
8664
8665         switch (service->type) {
8666         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8667         case CONNMAN_SERVICE_TYPE_SYSTEM:
8668         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8669         case CONNMAN_SERVICE_TYPE_GPS:
8670         case CONNMAN_SERVICE_TYPE_VPN:
8671         case CONNMAN_SERVICE_TYPE_GADGET:
8672         case CONNMAN_SERVICE_TYPE_WIFI:
8673         case CONNMAN_SERVICE_TYPE_CELLULAR:
8674         case CONNMAN_SERVICE_TYPE_P2P:
8675                 break;
8676         case CONNMAN_SERVICE_TYPE_ETHERNET:
8677                 service->favorite = true;
8678                 break;
8679         }
8680
8681         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8682         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8683
8684         update_from_network(service, network);
8685
8686         index = connman_network_get_index(network);
8687
8688         if (!service->ipconfig_ipv4)
8689                 service->ipconfig_ipv4 = create_ip4config(service, index,
8690                                 CONNMAN_IPCONFIG_METHOD_DHCP);
8691
8692         if (!service->ipconfig_ipv6)
8693                 service->ipconfig_ipv6 = create_ip6config(service, index);
8694
8695         service_register(service);
8696
8697         if (service->favorite) {
8698                 device = connman_network_get_device(service->network);
8699                 if (device && !connman_device_get_scanning(device)) {
8700
8701                         switch (service->type) {
8702                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8703                         case CONNMAN_SERVICE_TYPE_SYSTEM:
8704                         case CONNMAN_SERVICE_TYPE_P2P:
8705                                 break;
8706
8707                         case CONNMAN_SERVICE_TYPE_GADGET:
8708                         case CONNMAN_SERVICE_TYPE_ETHERNET:
8709                                 if (service->autoconnect) {
8710                                         __connman_service_connect(service,
8711                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8712                                         break;
8713                                 }
8714
8715                                 /* fall through */
8716                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8717                         case CONNMAN_SERVICE_TYPE_GPS:
8718                         case CONNMAN_SERVICE_TYPE_VPN:
8719                         case CONNMAN_SERVICE_TYPE_WIFI:
8720                         case CONNMAN_SERVICE_TYPE_CELLULAR:
8721                                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8722                                 break;
8723                         }
8724                 }
8725
8726 #if defined TIZEN_EXT
8727                 /* TIZEN synchronizes below information when the service creates */
8728                 if (service->eap != NULL)
8729                         connman_network_set_string(service->network, "WiFi.EAP",
8730                                                                 service->eap);
8731                 if (service->identity != NULL)
8732                         connman_network_set_string(service->network, "WiFi.Identity",
8733                                                                 service->identity);
8734                 if (service->phase2 != NULL)
8735                         connman_network_set_string(service->network, "WiFi.Phase2",
8736                                                                 service->phase2);
8737 #endif
8738         }
8739
8740         __connman_notifier_service_add(service, service->name);
8741         service_schedule_added(service);
8742
8743         return service;
8744 }
8745
8746 void __connman_service_update_from_network(struct connman_network *network)
8747 {
8748         bool need_sort = false;
8749         struct connman_service *service;
8750         uint8_t strength;
8751         bool roaming;
8752         const char *name;
8753         bool stats_enable;
8754
8755         service = connman_service_lookup_from_network(network);
8756         if (!service)
8757                 return;
8758
8759         if (!service->network)
8760                 return;
8761
8762 #if defined TIZEN_EXT
8763         if (service->storage_reload) {
8764                 service_load(service);
8765                 __connman_service_set_storage_reload(service, false);
8766         }
8767 #endif
8768
8769         name = connman_network_get_string(service->network, "Name");
8770         if (g_strcmp0(service->name, name) != 0) {
8771                 g_free(service->name);
8772                 service->name = g_strdup(name);
8773
8774                 if (allow_property_changed(service))
8775                         connman_dbus_property_changed_basic(service->path,
8776                                         CONNMAN_SERVICE_INTERFACE, "Name",
8777                                         DBUS_TYPE_STRING, &service->name);
8778         }
8779
8780         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8781                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
8782
8783         strength = connman_network_get_strength(service->network);
8784         if (strength == service->strength)
8785                 goto roaming;
8786
8787         service->strength = strength;
8788         need_sort = true;
8789
8790         strength_changed(service);
8791
8792 roaming:
8793         roaming = connman_network_get_bool(service->network, "Roaming");
8794         if (roaming == service->roaming)
8795                 goto sorting;
8796
8797         stats_enable = stats_enabled(service);
8798         if (stats_enable)
8799                 stats_stop(service);
8800
8801         service->roaming = roaming;
8802         need_sort = true;
8803
8804         if (stats_enable)
8805                 stats_start(service);
8806
8807         roaming_changed(service);
8808
8809 sorting:
8810         if (need_sort) {
8811                 service_list_sort();
8812         }
8813 }
8814
8815 void __connman_service_remove_from_network(struct connman_network *network)
8816 {
8817         struct connman_service *service;
8818
8819         service = connman_service_lookup_from_network(network);
8820
8821         DBG("network %p service %p", network, service);
8822
8823         if (!service)
8824                 return;
8825
8826         service->ignore = true;
8827
8828         __connman_connection_gateway_remove(service,
8829                                         CONNMAN_IPCONFIG_TYPE_ALL);
8830
8831         connman_service_unref(service);
8832 }
8833
8834 /**
8835  * __connman_service_create_from_provider:
8836  * @provider: provider structure
8837  *
8838  * Look up service by provider and if not found, create one
8839  */
8840 struct connman_service *
8841 __connman_service_create_from_provider(struct connman_provider *provider)
8842 {
8843         struct connman_service *service;
8844         const char *ident, *str;
8845         char *name;
8846         int index = connman_provider_get_index(provider);
8847
8848         DBG("provider %p", provider);
8849
8850         ident = __connman_provider_get_ident(provider);
8851         if (!ident)
8852                 return NULL;
8853
8854         name = g_strdup_printf("vpn_%s", ident);
8855         service = service_get(name);
8856         g_free(name);
8857
8858         if (!service)
8859                 return NULL;
8860
8861         service->type = CONNMAN_SERVICE_TYPE_VPN;
8862         service->provider = connman_provider_ref(provider);
8863         service->autoconnect = false;
8864         service->favorite = true;
8865
8866         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8867         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8868
8869         str = connman_provider_get_string(provider, "Name");
8870         if (str) {
8871                 g_free(service->name);
8872                 service->name = g_strdup(str);
8873                 service->hidden = false;
8874         } else {
8875                 g_free(service->name);
8876                 service->name = NULL;
8877                 service->hidden = true;
8878         }
8879
8880         service->strength = 0;
8881
8882         if (!service->ipconfig_ipv4)
8883                 service->ipconfig_ipv4 = create_ip4config(service, index,
8884                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
8885
8886         if (!service->ipconfig_ipv6)
8887                 service->ipconfig_ipv6 = create_ip6config(service, index);
8888
8889         service_register(service);
8890
8891         __connman_notifier_service_add(service, service->name);
8892         service_schedule_added(service);
8893
8894         return service;
8895 }
8896
8897 static void remove_unprovisioned_services(void)
8898 {
8899         gchar **services;
8900         GKeyFile *keyfile, *configkeyfile;
8901         char *file, *section;
8902         int i = 0;
8903
8904         services = connman_storage_get_services();
8905         if (!services)
8906                 return;
8907
8908         for (; services[i]; i++) {
8909                 file = section = NULL;
8910                 keyfile = configkeyfile = NULL;
8911
8912                 keyfile = connman_storage_load_service(services[i]);
8913                 if (!keyfile)
8914                         continue;
8915
8916                 file = g_key_file_get_string(keyfile, services[i],
8917                                         "Config.file", NULL);
8918                 if (!file)
8919                         goto next;
8920
8921                 section = g_key_file_get_string(keyfile, services[i],
8922                                         "Config.ident", NULL);
8923                 if (!section)
8924                         goto next;
8925
8926                 configkeyfile = __connman_storage_load_config(file);
8927                 if (!configkeyfile) {
8928                         /*
8929                          * Config file is missing, remove the provisioned
8930                          * service.
8931                          */
8932                         __connman_storage_remove_service(services[i]);
8933                         goto next;
8934                 }
8935
8936                 if (!g_key_file_has_group(configkeyfile, section))
8937                         /*
8938                          * Config section is missing, remove the provisioned
8939                          * service.
8940                          */
8941                         __connman_storage_remove_service(services[i]);
8942
8943         next:
8944                 if (keyfile)
8945                         g_key_file_free(keyfile);
8946
8947                 if (configkeyfile)
8948                         g_key_file_free(configkeyfile);
8949
8950                 g_free(section);
8951                 g_free(file);
8952         }
8953
8954         g_strfreev(services);
8955 }
8956
8957 static int agent_probe(struct connman_agent *agent)
8958 {
8959         DBG("agent %p", agent);
8960         return 0;
8961 }
8962
8963 static void agent_remove(struct connman_agent *agent)
8964 {
8965         DBG("agent %p", agent);
8966 }
8967
8968 static void *agent_context_ref(void *context)
8969 {
8970         struct connman_service *service = context;
8971
8972         return (void *)connman_service_ref(service);
8973 }
8974
8975 static void agent_context_unref(void *context)
8976 {
8977         struct connman_service *service = context;
8978
8979         connman_service_unref(service);
8980 }
8981
8982 static struct connman_agent_driver agent_driver = {
8983         .name           = "service",
8984         .interface      = CONNMAN_AGENT_INTERFACE,
8985         .probe          = agent_probe,
8986         .remove         = agent_remove,
8987         .context_ref    = agent_context_ref,
8988         .context_unref  = agent_context_unref,
8989 };
8990
8991 int __connman_service_init(void)
8992 {
8993         int err;
8994
8995         DBG("");
8996
8997         err = connman_agent_driver_register(&agent_driver);
8998         if (err < 0) {
8999                 connman_error("Cannot register agent driver for %s",
9000                                                 agent_driver.name);
9001                 return err;
9002         }
9003
9004         connection = connman_dbus_get_connection();
9005
9006         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
9007                                                         NULL, service_free);
9008
9009         services_notify = g_new0(struct _services_notify, 1);
9010         services_notify->remove = g_hash_table_new_full(g_str_hash,
9011                         g_str_equal, g_free, NULL);
9012         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
9013
9014         remove_unprovisioned_services();
9015
9016         return 0;
9017 }
9018
9019 void __connman_service_cleanup(void)
9020 {
9021         DBG("");
9022
9023         if (vpn_autoconnect_timeout) {
9024                 g_source_remove(vpn_autoconnect_timeout);
9025                 vpn_autoconnect_timeout = 0;
9026         }
9027
9028         if (autoconnect_timeout != 0) {
9029                 g_source_remove(autoconnect_timeout);
9030                 autoconnect_timeout = 0;
9031         }
9032
9033         connman_agent_driver_unregister(&agent_driver);
9034
9035         g_list_free(service_list);
9036         service_list = NULL;
9037
9038         g_hash_table_destroy(service_hash);
9039         service_hash = NULL;
9040
9041         g_slist_free(counter_list);
9042         counter_list = NULL;
9043
9044         if (services_notify->id != 0) {
9045                 g_source_remove(services_notify->id);
9046                 service_send_changed(NULL);
9047                 g_hash_table_destroy(services_notify->remove);
9048                 g_hash_table_destroy(services_notify->add);
9049         }
9050         g_free(services_notify);
9051
9052         dbus_connection_unref(connection);
9053 }