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