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