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