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