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