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