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