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