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