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