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