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