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