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