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