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