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