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