Merge "Add support for WPS2-PSK security type in Security property of service interfa...
[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 bool __connman_service_remove(struct connman_service *service)
4725 {
4726         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET ||
4727                         service->type == CONNMAN_SERVICE_TYPE_GADGET)
4728                 return false;
4729
4730         if (service->immutable || service->hidden ||
4731                         __connman_provider_is_immutable(service->provider))
4732                 return false;
4733
4734         if (!service->favorite && service->state !=
4735                                                 CONNMAN_SERVICE_STATE_FAILURE)
4736                 return false;
4737
4738         __connman_service_disconnect(service);
4739
4740         g_free(service->passphrase);
4741         service->passphrase = NULL;
4742
4743         g_free(service->identity);
4744         service->identity = NULL;
4745
4746         g_free(service->agent_identity);
4747         service->agent_identity = NULL;
4748
4749         g_free(service->eap);
4750         service->eap = NULL;
4751
4752 #if defined TIZEN_EXT
4753         g_free(service->ca_cert_file);
4754         service->ca_cert_file = NULL;
4755
4756         g_free(service->client_cert_file);
4757         service->client_cert_file = NULL;
4758
4759         g_free(service->private_key_file);
4760         service->private_key_file = NULL;
4761
4762         g_free(service->private_key_passphrase);
4763         service->private_key_passphrase = NULL;
4764
4765         g_free(service->phase2);
4766         service->phase2 = NULL;
4767
4768         __connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP);
4769         __connman_ipconfig_set_method(service->ipconfig_ipv6, CONNMAN_IPCONFIG_METHOD_AUTO);
4770         connman_service_set_proxy(service, NULL, false);
4771
4772         __connman_service_nameserver_clear(service);
4773
4774         g_strfreev(service->nameservers_config);
4775         service->nameservers_config = NULL;
4776
4777 #endif
4778
4779 #if defined TIZEN_EXT
4780         if (service->security != CONNMAN_SERVICE_SECURITY_8021X)
4781 #endif
4782         set_idle(service);
4783
4784         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
4785
4786         service->user.favorite_user = USER_NONE;
4787
4788         __connman_service_set_favorite(service, false);
4789
4790         __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
4791
4792 #if defined TIZEN_EXT
4793         __connman_storage_remove_service(service->identifier);
4794 #else
4795         service_save(service);
4796 #endif
4797
4798         return true;
4799 }
4800
4801 static DBusMessage *remove_service(DBusConnection *conn,
4802                                         DBusMessage *msg, void *user_data)
4803 {
4804         struct connman_service *service = user_data;
4805
4806         DBG("service %p", service);
4807
4808         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
4809                 uid_t uid;
4810                 if (connman_dbus_get_connection_unix_user_sync(conn,
4811                                                 dbus_message_get_sender(msg),
4812                                                 &uid) < 0) {
4813                         DBG("Can not get unix user id!");
4814                         return __connman_error_permission_denied(msg);
4815                 }
4816
4817 #if !defined TIZEN_EXT
4818                 if (!connman_service_is_user_allowed(service, uid)) {
4819                         DBG("Not allow this user to remove this wifi service now!");
4820                         return __connman_error_permission_denied(msg);
4821                 }
4822 #endif
4823         }
4824
4825         if (!__connman_service_remove(service))
4826                 return __connman_error_not_supported(msg);
4827
4828         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4829 }
4830
4831 static bool check_suitable_state(enum connman_service_state a,
4832                                         enum connman_service_state b)
4833 {
4834         /*
4835          * Special check so that "ready" service can be moved before
4836          * "online" one.
4837          */
4838         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
4839                         b == CONNMAN_SERVICE_STATE_READY) ||
4840                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
4841                         a == CONNMAN_SERVICE_STATE_READY))
4842                 return true;
4843
4844         return a == b;
4845 }
4846
4847 static void downgrade_state(struct connman_service *service)
4848 {
4849         if (!service)
4850                 return;
4851
4852         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
4853                                                 service->state_ipv6);
4854
4855         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
4856                 __connman_service_ipconfig_indicate_state(service,
4857                                                 CONNMAN_SERVICE_STATE_READY,
4858                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4859
4860         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
4861                 __connman_service_ipconfig_indicate_state(service,
4862                                                 CONNMAN_SERVICE_STATE_READY,
4863                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
4864 }
4865
4866 static void apply_relevant_default_downgrade(struct connman_service *service)
4867 {
4868         struct connman_service *def_service;
4869
4870         def_service = __connman_service_get_default();
4871         if (!def_service)
4872                 return;
4873
4874         if (def_service == service &&
4875                         def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
4876                 def_service->state = CONNMAN_SERVICE_STATE_READY;
4877                 __connman_notifier_leave_online(def_service->type);
4878                 state_changed(def_service);
4879         }
4880 }
4881
4882 static void switch_default_service(struct connman_service *default_service,
4883                 struct connman_service *downgrade_service)
4884 {
4885         struct connman_service *service;
4886         GList *src, *dst;
4887
4888         apply_relevant_default_downgrade(default_service);
4889         src = g_list_find(service_list, downgrade_service);
4890         dst = g_list_find(service_list, default_service);
4891
4892         /* Nothing to do */
4893         if (src == dst || src->next == dst)
4894                 return;
4895
4896         service = src->data;
4897         service_list = g_list_delete_link(service_list, src);
4898         service_list = g_list_insert_before(service_list, dst, service);
4899
4900         downgrade_state(downgrade_service);
4901 }
4902
4903 static DBusMessage *move_service(DBusConnection *conn,
4904                                         DBusMessage *msg, void *user_data,
4905                                                                 bool before)
4906 {
4907         struct connman_service *service = user_data;
4908         struct connman_service *target;
4909         const char *path;
4910         enum connman_ipconfig_method target4, target6;
4911         enum connman_ipconfig_method service4, service6;
4912
4913         DBG("service %p", service);
4914
4915         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
4916                                                         DBUS_TYPE_INVALID);
4917
4918         if (!service->favorite)
4919                 return __connman_error_not_supported(msg);
4920
4921         target = find_service(path);
4922         if (!target || !target->favorite || target == service)
4923                 return __connman_error_invalid_service(msg);
4924
4925         if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
4926                 /*
4927                  * We only allow VPN route splitting if there are
4928                  * routes defined for a given VPN.
4929                  */
4930                 if (!__connman_provider_check_routes(target->provider)) {
4931                         connman_info("Cannot move service. "
4932                                 "No routes defined for provider %s",
4933                                 __connman_provider_get_ident(target->provider));
4934                         return __connman_error_invalid_service(msg);
4935                 }
4936
4937                 target->do_split_routing = true;
4938         } else
4939                 target->do_split_routing = false;
4940
4941         service->do_split_routing = false;
4942
4943         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
4944         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
4945         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
4946         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
4947
4948         DBG("target %s method %d/%d state %d/%d split %d", target->identifier,
4949                 target4, target6, target->state_ipv4, target->state_ipv6,
4950                 target->do_split_routing);
4951
4952         DBG("service %s method %d/%d state %d/%d", service->identifier,
4953                                 service4, service6,
4954                                 service->state_ipv4, service->state_ipv6);
4955
4956         /*
4957          * If method is OFF, then we do not need to check the corresponding
4958          * ipconfig state.
4959          */
4960         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
4961                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
4962                         if (!check_suitable_state(target->state_ipv6,
4963                                                         service->state_ipv6))
4964                                 return __connman_error_invalid_service(msg);
4965                 }
4966         }
4967
4968         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
4969                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
4970                         if (!check_suitable_state(target->state_ipv4,
4971                                                         service->state_ipv4))
4972                                 return __connman_error_invalid_service(msg);
4973                 }
4974         }
4975
4976         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
4977                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
4978                         if (!check_suitable_state(target->state_ipv6,
4979                                                         service->state_ipv6))
4980                                 return __connman_error_invalid_service(msg);
4981                 }
4982         }
4983
4984         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
4985                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
4986                         if (!check_suitable_state(target->state_ipv4,
4987                                                         service->state_ipv4))
4988                                 return __connman_error_invalid_service(msg);
4989                 }
4990         }
4991
4992         g_get_current_time(&service->modified);
4993         service_save(service);
4994         service_save(target);
4995
4996         /*
4997          * If the service which goes down is the default service and is
4998          * online, we downgrade directly its state to ready so:
4999          * the service which goes up, needs to recompute its state which
5000          * is triggered via downgrading it - if relevant - to state ready.
5001          */
5002         if (before)
5003                 switch_default_service(target, service);
5004         else
5005                 switch_default_service(service, target);
5006
5007         __connman_connection_update_gateway();
5008
5009         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5010 }
5011
5012 static DBusMessage *move_before(DBusConnection *conn,
5013                                         DBusMessage *msg, void *user_data)
5014 {
5015         return move_service(conn, msg, user_data, true);
5016 }
5017
5018 static DBusMessage *move_after(DBusConnection *conn,
5019                                         DBusMessage *msg, void *user_data)
5020 {
5021         return move_service(conn, msg, user_data, false);
5022 }
5023
5024 static DBusMessage *reset_counters(DBusConnection *conn,
5025                                         DBusMessage *msg, void *user_data)
5026 {
5027         struct connman_service *service = user_data;
5028
5029         reset_stats(service);
5030
5031         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5032 }
5033
5034 static DBusMessage *get_user_favorite(DBusConnection *conn,
5035                                         DBusMessage *msg, void *user_data)
5036 {
5037         DBusMessage *reply;
5038         uid_t uid = USER_NONE;
5039         dbus_bool_t user_favorite = false;
5040         struct connman_service *service = user_data;
5041
5042         connman_dbus_get_connection_unix_user_sync(conn,
5043                                         dbus_message_get_sender(msg),
5044                                         &uid);
5045         if (uid == USER_ROOT)
5046                 user_favorite = service->favorite;
5047         else if (uid != USER_NONE && uid == service->user.favorite_user) {
5048                 DBG("The service is favorite to this user!");
5049                 user_favorite = true;
5050         }
5051
5052         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5053         dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,
5054                                 &user_favorite, DBUS_TYPE_INVALID);
5055         return reply;
5056 }
5057
5058 static struct _services_notify {
5059         int id;
5060         GHashTable *add;
5061         GHashTable *remove;
5062 } *services_notify;
5063
5064 static void service_append_added_foreach(gpointer data, gpointer user_data)
5065 {
5066         struct connman_service *service = data;
5067         DBusMessageIter *iter = user_data;
5068
5069         if (!service || !service->path) {
5070                 DBG("service %p or path is NULL", service);
5071                 return;
5072         }
5073
5074         if (g_hash_table_lookup(services_notify->add, service->path)) {
5075                 DBG("new %s", service->path);
5076
5077                 append_struct(service, iter);
5078                 g_hash_table_remove(services_notify->add, service->path);
5079         } else {
5080                 DBG("changed %s", service->path);
5081
5082                 append_struct_service(iter, NULL, service);
5083         }
5084 }
5085
5086 static void service_append_ordered(DBusMessageIter *iter, void *user_data)
5087 {
5088         g_list_foreach(service_list, service_append_added_foreach, iter);
5089 }
5090
5091 static void append_removed(gpointer key, gpointer value, gpointer user_data)
5092 {
5093         char *objpath = key;
5094         DBusMessageIter *iter = user_data;
5095
5096         DBG("removed %s", objpath);
5097         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
5098 }
5099
5100 static void service_append_removed(DBusMessageIter *iter, void *user_data)
5101 {
5102         g_hash_table_foreach(services_notify->remove, append_removed, iter);
5103 }
5104
5105 static gboolean service_send_changed(gpointer data)
5106 {
5107         DBusMessage *signal;
5108
5109         DBG("");
5110
5111         services_notify->id = 0;
5112
5113         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
5114                         CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
5115         if (!signal)
5116                 return FALSE;
5117
5118         __connman_dbus_append_objpath_dict_array(signal,
5119                                         service_append_ordered, NULL);
5120         __connman_dbus_append_objpath_array(signal,
5121                                         service_append_removed, NULL);
5122
5123         dbus_connection_send(connection, signal, NULL);
5124         dbus_message_unref(signal);
5125
5126         g_hash_table_remove_all(services_notify->remove);
5127         g_hash_table_remove_all(services_notify->add);
5128
5129         return FALSE;
5130 }
5131
5132 static void service_schedule_changed(void)
5133 {
5134         if (services_notify->id != 0)
5135                 return;
5136
5137         services_notify->id = g_timeout_add(100, service_send_changed, NULL);
5138 }
5139
5140 static void service_schedule_added(struct connman_service *service)
5141 {
5142         DBG("service %p", service);
5143
5144         g_hash_table_remove(services_notify->remove, service->path);
5145         g_hash_table_replace(services_notify->add, service->path, service);
5146
5147         service_schedule_changed();
5148 }
5149
5150 static void service_schedule_removed(struct connman_service *service)
5151 {
5152         if (!service || !service->path) {
5153                 DBG("service %p or path is NULL", service);
5154                 return;
5155         }
5156
5157         DBG("service %p %s", service, service->path);
5158
5159         g_hash_table_remove(services_notify->add, service->path);
5160         g_hash_table_replace(services_notify->remove, g_strdup(service->path),
5161                         NULL);
5162
5163         service_schedule_changed();
5164 }
5165
5166 static bool allow_property_changed(struct connman_service *service)
5167 {
5168 #if defined TIZEN_EXT
5169         if (service->path == NULL)
5170                 return FALSE;
5171 #endif
5172         if (g_hash_table_lookup_extended(services_notify->add, service->path,
5173                                         NULL, NULL)) {
5174                 DBG("no property updates for service %p", service);
5175                 return false;
5176         }
5177
5178         return true;
5179 }
5180
5181 static const GDBusMethodTable service_methods[] = {
5182         { GDBUS_DEPRECATED_METHOD("GetProperties",
5183                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
5184                         get_properties) },
5185         { GDBUS_METHOD("SetProperty",
5186                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
5187                         NULL, set_property) },
5188         { GDBUS_METHOD("ClearProperty",
5189                         GDBUS_ARGS({ "name", "s" }), NULL,
5190                         clear_property) },
5191         { GDBUS_ASYNC_METHOD("Connect", NULL, NULL,
5192                               connect_service) },
5193         { GDBUS_METHOD("Disconnect", NULL, NULL,
5194                         disconnect_service) },
5195         { GDBUS_METHOD("Remove", NULL, NULL, remove_service) },
5196         { GDBUS_METHOD("MoveBefore",
5197                         GDBUS_ARGS({ "service", "o" }), NULL,
5198                         move_before) },
5199         { GDBUS_METHOD("MoveAfter",
5200                         GDBUS_ARGS({ "service", "o" }), NULL,
5201                         move_after) },
5202         { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
5203         { GDBUS_METHOD("GetUserFavorite",
5204                         NULL, GDBUS_ARGS({ "value", "v" }),
5205                         get_user_favorite) },
5206         { },
5207 };
5208
5209 static const GDBusSignalTable service_signals[] = {
5210         { GDBUS_SIGNAL("PropertyChanged",
5211                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
5212         { },
5213 };
5214
5215 static void service_free(gpointer user_data)
5216 {
5217         struct connman_service *service = user_data;
5218         char *path = service->path;
5219
5220         DBG("service %p", service);
5221
5222         reply_pending(service, ENOENT);
5223
5224         __connman_notifier_service_remove(service);
5225         service_schedule_removed(service);
5226
5227         __connman_wispr_stop(service);
5228         stats_stop(service);
5229
5230         service->path = NULL;
5231
5232         if (path) {
5233                 __connman_connection_update_gateway();
5234
5235                 g_dbus_unregister_interface(connection, path,
5236                                                 CONNMAN_SERVICE_INTERFACE);
5237                 g_free(path);
5238         }
5239
5240         g_hash_table_destroy(service->counter_table);
5241
5242         if (service->network) {
5243                 __connman_network_disconnect(service->network);
5244                 connman_network_unref(service->network);
5245                 service->network = NULL;
5246         }
5247
5248         if (service->provider)
5249                 connman_provider_unref(service->provider);
5250
5251         if (service->ipconfig_ipv4) {
5252                 __connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
5253                 __connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
5254                 __connman_ipconfig_unref(service->ipconfig_ipv4);
5255                 service->ipconfig_ipv4 = NULL;
5256         }
5257
5258         if (service->ipconfig_ipv6) {
5259                 __connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
5260                 __connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
5261                 __connman_ipconfig_unref(service->ipconfig_ipv6);
5262                 service->ipconfig_ipv6 = NULL;
5263         }
5264
5265         g_strfreev(service->timeservers);
5266         g_strfreev(service->timeservers_config);
5267         g_strfreev(service->nameservers);
5268         g_strfreev(service->nameservers_config);
5269         g_strfreev(service->nameservers_auto);
5270         g_strfreev(service->domains);
5271         g_strfreev(service->proxies);
5272         g_strfreev(service->excludes);
5273
5274         g_free(service->hostname);
5275         g_free(service->domainname);
5276         g_free(service->pac);
5277         g_free(service->name);
5278         g_free(service->passphrase);
5279         g_free(service->identifier);
5280         g_free(service->eap);
5281         g_free(service->identity);
5282         g_free(service->agent_identity);
5283         g_free(service->ca_cert_file);
5284         g_free(service->client_cert_file);
5285         g_free(service->private_key_file);
5286         g_free(service->private_key_passphrase);
5287         g_free(service->phase2);
5288         g_free(service->config_file);
5289         g_free(service->config_entry);
5290
5291         if (service->stats.timer)
5292                 g_timer_destroy(service->stats.timer);
5293         if (service->stats_roaming.timer)
5294                 g_timer_destroy(service->stats_roaming.timer);
5295
5296         if (current_default == service)
5297                 current_default = NULL;
5298
5299         g_free(service);
5300 }
5301
5302 static void stats_init(struct connman_service *service)
5303 {
5304         /* home */
5305         service->stats.valid = false;
5306         service->stats.enabled = false;
5307         service->stats.timer = g_timer_new();
5308
5309         /* roaming */
5310         service->stats_roaming.valid = false;
5311         service->stats_roaming.enabled = false;
5312         service->stats_roaming.timer = g_timer_new();
5313 }
5314
5315 static void service_initialize(struct connman_service *service)
5316 {
5317         DBG("service %p", service);
5318
5319         service->refcount = 1;
5320
5321         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
5322
5323         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
5324         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
5325
5326         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
5327         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
5328         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
5329
5330         service->favorite  = false;
5331         service->immutable = false;
5332         service->hidden = false;
5333
5334         service->ignore = false;
5335
5336         service->user.favorite_user = USER_NONE;
5337         service->user.current_user = USER_NONE;
5338
5339         service->request_passphrase_input = false;
5340
5341         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
5342
5343         service->order = 0;
5344
5345         stats_init(service);
5346
5347         service->provider = NULL;
5348
5349         service->wps = false;
5350 #if defined TIZEN_EXT
5351         /*
5352          * Description: TIZEN implements system global connection management.
5353          */
5354         service->user_pdn_connection_refcount = 0;
5355         __sync_synchronize();
5356 #endif
5357 }
5358
5359 /**
5360  * connman_service_create:
5361  *
5362  * Allocate a new service.
5363  *
5364  * Returns: a newly-allocated #connman_service structure
5365  */
5366 struct connman_service *connman_service_create(void)
5367 {
5368         GSList *list;
5369         struct connman_stats_counter *counters;
5370         const char *counter;
5371
5372         struct connman_service *service;
5373
5374         service = g_try_new0(struct connman_service, 1);
5375         if (!service)
5376                 return NULL;
5377
5378         DBG("service %p", service);
5379
5380         service->counter_table = g_hash_table_new_full(g_str_hash,
5381                                                 g_str_equal, NULL, g_free);
5382
5383         for (list = counter_list; list; list = list->next) {
5384                 counter = list->data;
5385
5386                 counters = g_try_new0(struct connman_stats_counter, 1);
5387                 if (!counters) {
5388                         g_hash_table_destroy(service->counter_table);
5389                         g_free(service);
5390                         return NULL;
5391                 }
5392
5393                 counters->append_all = true;
5394
5395                 g_hash_table_replace(service->counter_table, (gpointer)counter,
5396                                 counters);
5397         }
5398
5399         service_initialize(service);
5400
5401         return service;
5402 }
5403
5404 /**
5405  * connman_service_ref:
5406  * @service: service structure
5407  *
5408  * Increase reference counter of service
5409  */
5410 struct connman_service *
5411 connman_service_ref_debug(struct connman_service *service,
5412                         const char *file, int line, const char *caller)
5413 {
5414         DBG("%p ref %d by %s:%d:%s()", service, service->refcount + 1,
5415                 file, line, caller);
5416
5417         __sync_fetch_and_add(&service->refcount, 1);
5418
5419         return service;
5420 }
5421
5422 /**
5423  * connman_service_unref:
5424  * @service: service structure
5425  *
5426  * Decrease reference counter of service and release service if no
5427  * longer needed.
5428  */
5429 void connman_service_unref_debug(struct connman_service *service,
5430                         const char *file, int line, const char *caller)
5431 {
5432         DBG("%p ref %d by %s:%d:%s()", service, service->refcount - 1,
5433                 file, line, caller);
5434
5435         if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
5436                 return;
5437
5438         service_list = g_list_remove(service_list, service);
5439
5440         __connman_service_disconnect(service);
5441
5442         g_hash_table_remove(service_hash, service->identifier);
5443 }
5444
5445 static gint service_compare(gconstpointer a, gconstpointer b)
5446 {
5447         struct connman_service *service_a = (void *) a;
5448         struct connman_service *service_b = (void *) b;
5449         enum connman_service_state state_a, state_b;
5450         bool a_connected, b_connected;
5451         gint strength;
5452
5453         state_a = service_a->state;
5454         state_b = service_b->state;
5455         a_connected = is_connected(service_a);
5456         b_connected = is_connected(service_b);
5457
5458         if (a_connected && b_connected) {
5459                 if (service_a->order > service_b->order)
5460                         return -1;
5461
5462                 if (service_a->order < service_b->order)
5463                         return 1;
5464         }
5465
5466         if (state_a != state_b) {
5467                 if (a_connected && b_connected) {
5468                         /* We prefer online over ready state */
5469                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
5470                                 return -1;
5471
5472                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
5473                                 return 1;
5474                 }
5475
5476                 if (a_connected)
5477                         return -1;
5478                 if (b_connected)
5479                         return 1;
5480
5481                 if (is_connecting(service_a))
5482                         return -1;
5483                 if (is_connecting(service_b))
5484                         return 1;
5485         }
5486
5487         if (service_a->favorite && !service_b->favorite)
5488                 return -1;
5489
5490         if (!service_a->favorite && service_b->favorite)
5491                 return 1;
5492
5493         if (service_a->type != service_b->type) {
5494
5495                 if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
5496                         return -1;
5497                 if (service_b->type == CONNMAN_SERVICE_TYPE_ETHERNET)
5498                         return 1;
5499
5500                 if (service_a->type == CONNMAN_SERVICE_TYPE_WIFI)
5501                         return -1;
5502                 if (service_b->type == CONNMAN_SERVICE_TYPE_WIFI)
5503                         return 1;
5504
5505                 if (service_a->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5506                         return -1;
5507                 if (service_b->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5508                         return 1;
5509
5510                 if (service_a->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
5511                         return -1;
5512                 if (service_b->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
5513                         return 1;
5514
5515                 if (service_a->type == CONNMAN_SERVICE_TYPE_VPN)
5516                         return -1;
5517                 if (service_b->type == CONNMAN_SERVICE_TYPE_VPN)
5518                         return 1;
5519
5520                 if (service_a->type == CONNMAN_SERVICE_TYPE_GADGET)
5521                         return -1;
5522                 if (service_b->type == CONNMAN_SERVICE_TYPE_GADGET)
5523                         return 1;
5524         }
5525
5526         strength = (gint) service_b->strength - (gint) service_a->strength;
5527         if (strength)
5528                 return strength;
5529
5530         return g_strcmp0(service_a->name, service_b->name);
5531 }
5532
5533 static void service_list_sort(void)
5534 {
5535         if (service_list && service_list->next) {
5536                 service_list = g_list_sort(service_list, service_compare);
5537                 service_schedule_changed();
5538         }
5539 }
5540
5541 /**
5542  * connman_service_get_type:
5543  * @service: service structure
5544  *
5545  * Get the type of service
5546  */
5547 enum connman_service_type connman_service_get_type(struct connman_service *service)
5548 {
5549         if (!service)
5550                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
5551
5552         return service->type;
5553 }
5554
5555 /**
5556  * connman_service_get_interface:
5557  * @service: service structure
5558  *
5559  * Get network interface of service
5560  */
5561 char *connman_service_get_interface(struct connman_service *service)
5562 {
5563         int index;
5564
5565         if (!service)
5566                 return NULL;
5567
5568         index = __connman_service_get_index(service);
5569
5570         return connman_inet_ifname(index);
5571 }
5572
5573 /**
5574  * __connman_service_is_user_allowed:
5575  * @type: service type
5576  * @uid: user id
5577  *
5578  * Check a user is allowed to operate a type of service
5579  */
5580 bool __connman_service_is_user_allowed(enum connman_service_type type,
5581                                         uid_t uid)
5582 {
5583         GList *list;
5584         uid_t owner_user = USER_NONE;
5585
5586         for (list = service_list; list; list = list->next) {
5587                 struct connman_service *service = list->data;
5588
5589                 if (service->type != type)
5590                         continue;
5591
5592                 if (is_connected(service)) {
5593                         owner_user = service->user.favorite_user;
5594                         break;
5595                 }
5596         }
5597
5598         if (uid == USER_NONE ||
5599                         (uid != USER_ROOT &&
5600                         owner_user != USER_NONE &&
5601                         owner_user != uid))
5602                 return false;
5603
5604         return true;
5605 }
5606
5607 /**
5608  * connman_service_get_network:
5609  * @service: service structure
5610  *
5611  * Get the service network
5612  */
5613 struct connman_network *
5614 __connman_service_get_network(struct connman_service *service)
5615 {
5616         if (!service)
5617                 return NULL;
5618
5619         return service->network;
5620 }
5621
5622 struct connman_ipconfig *
5623 __connman_service_get_ip4config(struct connman_service *service)
5624 {
5625         if (!service)
5626                 return NULL;
5627
5628         return service->ipconfig_ipv4;
5629 }
5630
5631 struct connman_ipconfig *
5632 __connman_service_get_ip6config(struct connman_service *service)
5633 {
5634         if (!service)
5635                 return NULL;
5636
5637         return service->ipconfig_ipv6;
5638 }
5639
5640 struct connman_ipconfig *
5641 __connman_service_get_ipconfig(struct connman_service *service, int family)
5642 {
5643         if (family == AF_INET)
5644                 return __connman_service_get_ip4config(service);
5645         else if (family == AF_INET6)
5646                 return __connman_service_get_ip6config(service);
5647         else
5648                 return NULL;
5649
5650 }
5651
5652 bool __connman_service_is_connected_state(struct connman_service *service,
5653                                         enum connman_ipconfig_type type)
5654 {
5655         if (!service)
5656                 return false;
5657
5658         switch (type) {
5659         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
5660                 break;
5661         case CONNMAN_IPCONFIG_TYPE_IPV4:
5662                 return is_connected_state(service, service->state_ipv4);
5663         case CONNMAN_IPCONFIG_TYPE_IPV6:
5664                 return is_connected_state(service, service->state_ipv6);
5665         case CONNMAN_IPCONFIG_TYPE_ALL:
5666                 return is_connected_state(service,
5667                                         CONNMAN_IPCONFIG_TYPE_IPV4) &&
5668                         is_connected_state(service,
5669                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5670         }
5671
5672         return false;
5673 }
5674 enum connman_service_security __connman_service_get_security(
5675                                 struct connman_service *service)
5676 {
5677         if (!service)
5678                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
5679
5680         return service->security;
5681 }
5682
5683 const char *__connman_service_get_phase2(struct connman_service *service)
5684 {
5685         if (!service)
5686                 return NULL;
5687
5688         return service->phase2;
5689 }
5690
5691 bool __connman_service_wps_enabled(struct connman_service *service)
5692 {
5693         if (!service)
5694                 return false;
5695
5696         return service->wps;
5697 }
5698
5699 void __connman_service_mark_dirty(void)
5700 {
5701         services_dirty = true;
5702 }
5703
5704 #if defined TIZEN_EXT
5705 /**
5706   * Returns profile count if there is any connected profiles
5707   * that use same interface
5708   */
5709 int __connman_service_get_connected_count_of_iface(
5710                                         struct connman_service *service)
5711 {
5712         GList *list;
5713         int count = 0;
5714         int index1 = 0;
5715         int index2 = 0;
5716
5717         DBG("");
5718
5719         index1 = __connman_service_get_index(service);
5720
5721         if (index1 <= 0)
5722                 return 0;
5723
5724         for (list = service_list; list; list = list->next) {
5725                 struct connman_service *service2 = list->data;
5726
5727                 if (service == service2)
5728                         continue;
5729
5730                 index2 = __connman_service_get_index(service2);
5731
5732                 if (is_connected(service2) && index2 > 0 && index1 == index2)
5733                         count++;
5734
5735                 index2 = 0;
5736         }
5737
5738         DBG("Interface index %d, count %d", index1, count);
5739
5740         return count;
5741 }
5742 #endif
5743
5744 /**
5745  * __connman_service_set_favorite_delayed:
5746  * @service: service structure
5747  * @favorite: favorite value
5748  * @delay_ordering: do not order service sequence
5749  *
5750  * Change the favorite setting of service
5751  */
5752 int __connman_service_set_favorite_delayed(struct connman_service *service,
5753                                         bool favorite,
5754                                         bool delay_ordering)
5755 {
5756 #if defined TIZEN_EXT
5757         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5758                 return -EIO;
5759 #endif
5760         if (service->hidden)
5761                 return -EOPNOTSUPP;
5762
5763         if (service->favorite == favorite)
5764                 return -EALREADY;
5765
5766         service->favorite = favorite;
5767
5768         if (!delay_ordering)
5769                 __connman_service_get_order(service);
5770
5771         favorite_changed(service);
5772
5773         if (!delay_ordering) {
5774
5775                 service_list_sort();
5776
5777                 __connman_connection_update_gateway();
5778         }
5779
5780         return 0;
5781 }
5782
5783 /**
5784  * __connman_service_set_favorite:
5785  * @service: service structure
5786  * @favorite: favorite value
5787  *
5788  * Change the favorite setting of service
5789  */
5790 int __connman_service_set_favorite(struct connman_service *service,
5791                                                 bool favorite)
5792 {
5793         return __connman_service_set_favorite_delayed(service, favorite,
5794                                                         false);
5795 }
5796
5797 bool connman_service_get_favorite(struct connman_service *service)
5798 {
5799         return service->favorite;
5800 }
5801
5802 bool connman_service_get_autoconnect(struct connman_service *service)
5803 {
5804         return service->autoconnect;
5805 }
5806
5807 int __connman_service_set_immutable(struct connman_service *service,
5808                                                 bool immutable)
5809 {
5810         if (service->hidden)
5811                 return -EOPNOTSUPP;
5812
5813         if (service->immutable == immutable)
5814                 return 0;
5815
5816         service->immutable = immutable;
5817
5818         immutable_changed(service);
5819
5820         return 0;
5821 }
5822
5823 int __connman_service_set_ignore(struct connman_service *service,
5824                                                 bool ignore)
5825 {
5826         if (!service)
5827                 return -EINVAL;
5828
5829         service->ignore = ignore;
5830
5831         return 0;
5832 }
5833
5834 void __connman_service_set_string(struct connman_service *service,
5835                                   const char *key, const char *value)
5836 {
5837         if (service->hidden)
5838                 return;
5839         if (g_str_equal(key, "EAP")) {
5840                 g_free(service->eap);
5841                 service->eap = g_strdup(value);
5842         } else if (g_str_equal(key, "Identity")) {
5843                 g_free(service->identity);
5844                 service->identity = g_strdup(value);
5845         } else if (g_str_equal(key, "CACertFile")) {
5846                 g_free(service->ca_cert_file);
5847                 service->ca_cert_file = g_strdup(value);
5848         } else if (g_str_equal(key, "ClientCertFile")) {
5849                 g_free(service->client_cert_file);
5850                 service->client_cert_file = g_strdup(value);
5851         } else if (g_str_equal(key, "PrivateKeyFile")) {
5852                 g_free(service->private_key_file);
5853                 service->private_key_file = g_strdup(value);
5854         } else if (g_str_equal(key, "PrivateKeyPassphrase")) {
5855                 g_free(service->private_key_passphrase);
5856                 service->private_key_passphrase = g_strdup(value);
5857         } else if (g_str_equal(key, "Phase2")) {
5858                 g_free(service->phase2);
5859                 service->phase2 = g_strdup(value);
5860         } else if (g_str_equal(key, "Passphrase"))
5861                 __connman_service_set_passphrase(service, value);
5862 }
5863
5864 void __connman_service_set_search_domains(struct connman_service *service,
5865                                         char **domains)
5866 {
5867         searchdomain_remove_all(service);
5868
5869         if (service->domains)
5870                 g_strfreev(service->domains);
5871
5872         service->domains = g_strdupv(domains);
5873
5874         searchdomain_add_all(service);
5875 }
5876
5877 #if defined TIZEN_EXT
5878 void __connman_service_set_autoconnect(struct connman_service *service,
5879                                                 bool autoconnect)
5880 {
5881         if (service == NULL)
5882                 return;
5883
5884         if (service->autoconnect != autoconnect) {
5885                 DBG("updated autoconnect flag (%d)", autoconnect);
5886                 service->autoconnect = autoconnect;
5887                 service_save(service);
5888         }
5889 }
5890 #endif
5891
5892 static void service_complete(struct connman_service *service)
5893 {
5894         reply_pending(service, EIO);
5895
5896         if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
5897                 __connman_service_auto_connect(service->connect_reason);
5898
5899         g_get_current_time(&service->modified);
5900         service_save(service);
5901 }
5902
5903 static void report_error_cb(void *user_context, bool retry,
5904                                                         void *user_data)
5905 {
5906         struct connman_service *service = user_context;
5907
5908         if (retry)
5909                 __connman_service_connect(service,
5910                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
5911         else {
5912                 /* It is not relevant to stay on Failure state
5913                  * when failing is due to wrong user input */
5914                 __connman_service_clear_error(service);
5915
5916                 service_complete(service);
5917                 __connman_connection_update_gateway();
5918         }
5919 }
5920
5921 static int check_wpspin(struct connman_service *service, const char *wpspin)
5922 {
5923         int length;
5924         guint i;
5925
5926         if (!wpspin)
5927                 return 0;
5928
5929         length = strlen(wpspin);
5930
5931         /* If 0, it will mean user wants to use PBC method */
5932         if (length == 0) {
5933                 connman_network_set_string(service->network,
5934                                                         "WiFi.PinWPS", NULL);
5935                 return 0;
5936         }
5937
5938         /* A WPS PIN is always 8 chars length,
5939          * its content is in digit representation.
5940          */
5941         if (length != 8)
5942                 return -ENOKEY;
5943
5944         for (i = 0; i < 8; i++)
5945                 if (!isdigit((unsigned char) wpspin[i]))
5946                         return -ENOKEY;
5947
5948         connman_network_set_string(service->network, "WiFi.PinWPS", wpspin);
5949
5950         return 0;
5951 }
5952
5953 #if defined TIZEN_EXT
5954 static int __connman_service_connect_hidden(struct connman_service *service,
5955                         const char *name, int name_len,
5956                         const char *identity, const char *passphrase, void *user_data)
5957 {
5958         GList *list;
5959
5960         for (list = service_list; list; list = list->next) {
5961                 struct connman_service *target = list->data;
5962                 const char *target_ssid = NULL;
5963                 unsigned int target_ssid_len = 0;
5964
5965                 if (service->network != NULL &&
5966                                         service->security == target->security) {
5967                         target_ssid = connman_network_get_blob(service->network,
5968                                                         "WiFi.SSID", &target_ssid_len);
5969                         if (target_ssid_len == name_len &&
5970                                                         memcmp(target_ssid, name, name_len) == 0) {
5971                                 return connman_network_connect_hidden(service->network,
5972                                                         (char *)identity, (char *)passphrase, user_data);
5973                         }
5974                 }
5975         }
5976
5977         return -ENOENT;
5978 }
5979 #endif
5980
5981 static void request_input_cb(struct connman_service *service,
5982                         bool values_received,
5983                         const char *name, int name_len,
5984                         const char *identity, const char *passphrase,
5985                         bool wps, const char *wpspin,
5986                         const char *error, void *user_data)
5987 {
5988         struct connman_device *device;
5989         const char *security;
5990         int err = 0;
5991
5992         DBG("RequestInput return, %p", service);
5993
5994         if (error) {
5995                 DBG("error: %s", error);
5996
5997                 if (g_strcmp0(error,
5998                                 "net.connman.Agent.Error.Canceled") == 0) {
5999                         err = -EINVAL;
6000
6001                         if (service->hidden)
6002                                 __connman_service_return_error(service,
6003                                                         ECANCELED, user_data);
6004                         goto done;
6005                 } else {
6006                         if (service->hidden)
6007                                 __connman_service_return_error(service,
6008                                                         ETIMEDOUT, user_data);
6009                 }
6010         }
6011
6012         if (service->hidden && name_len > 0 && name_len <= 32) {
6013 #if defined TIZEN_EXT
6014                 /* TIZEN already has Wi-Fi hidden scan before this hidden connection */
6015                 err = __connman_service_connect_hidden(service, name, name_len,
6016                                                 identity, passphrase, user_data);
6017                 if (err == 0 || err == -EALREADY || err == -EINPROGRESS)
6018                         return;
6019 #endif
6020
6021                 device = connman_network_get_device(service->network);
6022                 security = connman_network_get_string(service->network,
6023                                                         "WiFi.Security");
6024                 err = __connman_device_request_hidden_scan(device,
6025                                                 name, name_len,
6026                                                 identity, passphrase,
6027                                                 security, user_data);
6028                 if (err < 0)
6029                         __connman_service_return_error(service, -err,
6030                                                         user_data);
6031         }
6032
6033         if (!values_received || service->hidden) {
6034                 err = -EINVAL;
6035                 goto done;
6036         }
6037
6038         if (wps && service->network) {
6039                 err = check_wpspin(service, wpspin);
6040                 if (err < 0)
6041                         goto done;
6042
6043                 connman_network_set_bool(service->network, "WiFi.UseWPS", wps);
6044         }
6045
6046         if (identity)
6047                 __connman_service_set_agent_identity(service, identity);
6048
6049         if (passphrase)
6050                 err = __connman_service_set_passphrase(service, passphrase);
6051
6052  done:
6053         if (err >= 0) {
6054                 /* We forget any previous error. */
6055                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6056
6057                 __connman_service_connect(service,
6058                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6059
6060         } else if (err == -ENOKEY) {
6061                 __connman_service_indicate_error(service,
6062                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
6063         } else {
6064                 /* It is not relevant to stay on Failure state
6065                  * when failing is due to wrong user input */
6066                 service->state = CONNMAN_SERVICE_STATE_IDLE;
6067
6068                 if (!service->hidden) {
6069                         /*
6070                          * If there was a real error when requesting
6071                          * hidden scan, then that error is returned already
6072                          * to the user somewhere above so do not try to
6073                          * do this again.
6074                          */
6075                         __connman_service_return_error(service, -err,
6076                                                         user_data);
6077                 }
6078
6079                 service_complete(service);
6080                 __connman_connection_update_gateway();
6081         }
6082 }
6083
6084 static void downgrade_connected_services(void)
6085 {
6086         struct connman_service *up_service;
6087         GList *list;
6088
6089         for (list = service_list; list; list = list->next) {
6090                 up_service = list->data;
6091
6092                 if (!is_connected(up_service))
6093                         continue;
6094
6095                 if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
6096                         return;
6097
6098                 downgrade_state(up_service);
6099         }
6100 }
6101
6102 static int service_update_preferred_order(struct connman_service *default_service,
6103                 struct connman_service *new_service,
6104                 enum connman_service_state new_state)
6105 {
6106         unsigned int *tech_array;
6107         int i;
6108
6109         if (!default_service || default_service == new_service ||
6110                         default_service->state != new_state)
6111                 return 0;
6112
6113         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
6114         if (tech_array) {
6115
6116                 for (i = 0; tech_array[i] != 0; i += 1) {
6117                         if (default_service->type == tech_array[i])
6118                                 return -EALREADY;
6119
6120                         if (new_service->type == tech_array[i]) {
6121                                 switch_default_service(default_service,
6122                                                 new_service);
6123                                 __connman_connection_update_gateway();
6124                                 return 0;
6125                         }
6126                 }
6127         }
6128
6129         return -EALREADY;
6130 }
6131
6132 #if defined TIZEN_EXT
6133 static gboolean __connman_service_can_drop(struct connman_service *service)
6134 {
6135         if (is_connected(service) == TRUE || is_connecting(service) == TRUE) {
6136                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
6137                         return TRUE;
6138                 else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE)
6139                         return TRUE;
6140         }
6141         return FALSE;
6142 }
6143
6144 static struct connman_device *default_connecting_device = NULL;
6145
6146 static void __connman_service_disconnect_default(struct connman_service *service)
6147 {
6148         struct connman_device *default_device = NULL;
6149
6150         if (default_connecting_device == NULL)
6151                 return;
6152
6153         default_device = connman_network_get_device(
6154                         __connman_service_get_network(service));
6155
6156         DBG("Disconnecting service %p %s", service, service->path);
6157         DBG("Disconnecting device %p %p %s",
6158                         default_connecting_device,
6159                         default_device,
6160                         connman_device_get_string(default_device, "Name"));
6161
6162         if (default_connecting_device == default_device)
6163                 default_connecting_device = NULL;
6164 }
6165
6166 static void __connman_service_connect_default(struct connman_service *current)
6167 {
6168         int err;
6169         GList *list;
6170         bool default_internet;
6171         struct connman_service *service;
6172         struct connman_service *default_service = NULL;
6173         struct connman_device *default_device = NULL;
6174
6175         if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
6176                 switch (current->state) {
6177                 case CONNMAN_SERVICE_STATE_UNKNOWN:
6178                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
6179                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
6180                         return;
6181                 default:
6182                         break;
6183                 }
6184
6185                 if (default_connecting_device &&
6186                                 __connman_service_is_internet_profile(current) == TRUE) {
6187                         if (current->network == NULL)
6188                                 return;
6189
6190                         default_device = connman_network_get_device(current->network);
6191                         if (default_connecting_device == default_device) {
6192                                 DBG("Cellular service[%s]  %p %s",
6193                                                 state2string(current->state), current, current->path);
6194                                 DBG("Cellular device %p %p %s",
6195                                                 default_connecting_device, default_device,
6196                                                 connman_device_get_string(default_device, "Name"));
6197
6198                                 default_connecting_device = NULL;
6199                         }
6200                 }
6201
6202                 return;
6203         } else if (is_connected(current) == TRUE || is_connecting(current) == TRUE)
6204                 return;
6205
6206         /* Always-on: keep default cellular connection as possible */
6207         for (list = service_list; list; list = list->next) {
6208                 service = list->data;
6209
6210                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6211                                 __connman_service_is_internet_profile(service) != TRUE ||
6212                                 service->network == NULL) {
6213                         continue;
6214                 }
6215
6216                 default_internet =
6217                                 connman_network_get_bool(service->network, "DefaultInternet");
6218
6219                 DBG("service: %p %s %s %s (default: %d)", service, service->name,
6220                                 __connman_service_type2string(service->type),
6221                                 state2string(service->state), default_internet);
6222
6223                 if (default_internet) {
6224                         default_service = service;
6225                         if (is_connected(default_service) == TRUE ||
6226                                         is_connecting(default_service) == TRUE)
6227                                 return;
6228
6229                         default_device = connman_network_get_device(default_service->network);
6230                         if (default_connecting_device == default_device) {
6231                                 DBG("Device is connecting (%p)", default_connecting_device);
6232                                 return;
6233                         }
6234
6235                         default_connecting_device = default_device;
6236                         default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
6237
6238                         err = __connman_network_connect(default_service->network);
6239                         DBG("Connecting default service %p %s [%d]",
6240                                         default_service, default_service->path, err);
6241                         DBG("Connecting device %p %s", default_connecting_device,
6242                                         connman_device_get_string(default_connecting_device, "Name"));
6243                         if (err < 0 && err != -EINPROGRESS) {
6244                                 default_connecting_device = NULL;
6245                         } else
6246                                 break;
6247                 }
6248         }
6249 }
6250 #endif
6251
6252 static void single_connected_tech(struct connman_service *allowed)
6253 {
6254         struct connman_service *service;
6255         GSList *services = NULL, *list;
6256         GList *iter;
6257
6258         DBG("keeping %p %s", allowed, allowed->path);
6259
6260 #if defined TIZEN_EXT
6261         if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6262                 return;
6263 #endif
6264
6265         for (iter = service_list; iter; iter = iter->next) {
6266                 service = iter->data;
6267
6268 #if defined TIZEN_EXT
6269                 if (service != allowed && service->type != allowed->type &&
6270                                 __connman_service_can_drop(service) == TRUE)
6271 #else
6272                 if (!is_connected(service))
6273                         break;
6274
6275                 if (service == allowed)
6276                         continue;
6277 #endif
6278                 services = g_slist_prepend(services, service);
6279         }
6280
6281         for (list = services; list; list = list->next) {
6282                 service = list->data;
6283
6284                 DBG("disconnecting %p %s", service, service->path);
6285 #if defined TIZEN_EXT
6286                 __connman_service_disconnect_default(service);
6287 #endif
6288                 __connman_service_disconnect(service);
6289         }
6290
6291         g_slist_free(services);
6292 }
6293
6294 static const char *get_dbus_sender(struct connman_service *service)
6295 {
6296         if (!service->pending)
6297                 return NULL;
6298
6299         return dbus_message_get_sender(service->pending);
6300 }
6301
6302 static int service_indicate_state(struct connman_service *service)
6303 {
6304         enum connman_service_state old_state, new_state;
6305         struct connman_service *def_service;
6306         enum connman_ipconfig_method method;
6307         int result;
6308
6309         if (!service)
6310                 return -EINVAL;
6311
6312         old_state = service->state;
6313         new_state = combine_state(service->state_ipv4, service->state_ipv6);
6314
6315         DBG("service %p old %s - new %s/%s => %s",
6316                                         service,
6317                                         state2string(old_state),
6318                                         state2string(service->state_ipv4),
6319                                         state2string(service->state_ipv6),
6320                                         state2string(new_state));
6321
6322         if (old_state == new_state)
6323                 return -EALREADY;
6324
6325         def_service = __connman_service_get_default();
6326
6327         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
6328                 result = service_update_preferred_order(def_service,
6329                                 service, new_state);
6330                 if (result == -EALREADY)
6331                         return result;
6332         }
6333
6334         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
6335                 __connman_notifier_leave_online(service->type);
6336
6337         if (is_connected_state(service, old_state) &&
6338                         !is_connected_state(service, new_state))
6339                 searchdomain_remove_all(service);
6340
6341         service->state = new_state;
6342         state_changed(service);
6343
6344         switch(new_state) {
6345         case CONNMAN_SERVICE_STATE_UNKNOWN:
6346
6347                 break;
6348
6349         case CONNMAN_SERVICE_STATE_IDLE:
6350                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
6351                         __connman_service_disconnect(service);
6352
6353                 break;
6354
6355         case CONNMAN_SERVICE_STATE_ASSOCIATION:
6356
6357                 break;
6358
6359         case CONNMAN_SERVICE_STATE_CONFIGURATION:
6360                 if (!service->new_service &&
6361                                 __connman_stats_service_register(service) == 0) {
6362                         /*
6363                          * For new services the statistics are updated after
6364                          * we have successfully connected.
6365                          */
6366                         __connman_stats_get(service, false,
6367                                                 &service->stats.data);
6368                         __connman_stats_get(service, true,
6369                                                 &service->stats_roaming.data);
6370                 }
6371
6372                 break;
6373
6374         case CONNMAN_SERVICE_STATE_READY:
6375                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6376
6377                 if (service->new_service &&
6378                                 __connman_stats_service_register(service) == 0) {
6379                         /*
6380                          * This is normally done after configuring state
6381                          * but for new service do this after we have connected
6382                          * successfully.
6383                          */
6384                         __connman_stats_get(service, false,
6385                                                 &service->stats.data);
6386                         __connman_stats_get(service, true,
6387                                                 &service->stats_roaming.data);
6388                 }
6389
6390                 service->new_service = false;
6391
6392                 default_changed();
6393
6394                 def_service = __connman_service_get_default();
6395
6396                 service_update_preferred_order(def_service, service, new_state);
6397
6398                 __connman_service_set_favorite(service, true);
6399
6400                 reply_pending(service, 0);
6401
6402                 g_get_current_time(&service->modified);
6403                 service_save(service);
6404
6405                 searchdomain_add_all(service);
6406                 dns_changed(service);
6407                 domain_changed(service);
6408                 proxy_changed(service);
6409
6410                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
6411                         __connman_notifier_connect(service->type);
6412
6413                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
6414                         connman_network_get_bool(service->network,
6415                                                 "WiFi.UseWPS")) {
6416                         const char *pass;
6417
6418                         pass = connman_network_get_string(service->network,
6419                                                         "WiFi.Passphrase");
6420
6421                         __connman_service_set_passphrase(service, pass);
6422
6423                         connman_network_set_bool(service->network,
6424                                                         "WiFi.UseWPS", false);
6425                 }
6426
6427                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
6428                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
6429                         __connman_ipconfig_disable_ipv6(
6430                                                 service->ipconfig_ipv6);
6431
6432                 if (connman_setting_get_bool("SingleConnectedTechnology"))
6433                         single_connected_tech(service);
6434                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
6435                         vpn_auto_connect();
6436
6437                 break;
6438
6439         case CONNMAN_SERVICE_STATE_ONLINE:
6440
6441                 break;
6442
6443         case CONNMAN_SERVICE_STATE_DISCONNECT:
6444                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6445
6446                 reply_pending(service, ECONNABORTED);
6447
6448                 def_service = __connman_service_get_default();
6449
6450                 if (!__connman_notifier_is_connected() &&
6451                         def_service &&
6452                                 def_service->provider)
6453                         connman_provider_disconnect(def_service->provider);
6454
6455                 default_changed();
6456
6457                 __connman_wispr_stop(service);
6458
6459                 __connman_wpad_stop(service);
6460
6461 #if defined TIZEN_EXT
6462                 /**
6463                   * Skip the functions if there is any connected profiles
6464                   * that use same interface
6465                   */
6466                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6467                         __connman_service_get_connected_count_of_iface(
6468                                                         service) <= 0) {
6469 #endif
6470                 dns_changed(service);
6471                 domain_changed(service);
6472                 proxy_changed(service);
6473 #if defined TIZEN_EXT
6474                 }
6475 #endif
6476
6477                 /*
6478                  * Previous services which are connected and which states
6479                  * are set to online should reset relevantly ipconfig_state
6480                  * to ready so wispr/portal will be rerun on those
6481                  */
6482                 downgrade_connected_services();
6483
6484                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
6485                 break;
6486
6487         case CONNMAN_SERVICE_STATE_FAILURE:
6488
6489                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
6490                         connman_agent_report_error(service, service->path,
6491                                         error2string(service->error),
6492                                         report_error_cb,
6493                                         get_dbus_sender(service),
6494                                         NULL) == -EINPROGRESS)
6495                         return 0;
6496                 service_complete(service);
6497
6498                 break;
6499         }
6500
6501         service_list_sort();
6502
6503 #if defined TIZEN_EXT
6504         __connman_service_connect_default(service);
6505 #endif
6506
6507         __connman_connection_update_gateway();
6508
6509         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
6510                         new_state != CONNMAN_SERVICE_STATE_READY) ||
6511                 (old_state == CONNMAN_SERVICE_STATE_READY &&
6512                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
6513                 __connman_notifier_disconnect(service->type);
6514         }
6515
6516         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
6517                 __connman_notifier_enter_online(service->type);
6518                 default_changed();
6519         }
6520
6521         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
6522                 service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
6523                 (new_state == CONNMAN_SERVICE_STATE_READY ||
6524                 new_state == CONNMAN_SERVICE_STATE_ONLINE)) {
6525                 if (service->user.favorite_user != service->user.current_user) {
6526                         DBG("Now set service favorite user id from %d to %d",
6527                         service->user.favorite_user, service->user.current_user);
6528
6529                         service->user.favorite_user = service->user.current_user;
6530
6531                         service_save(service);
6532                 }
6533         }
6534
6535         return 0;
6536 }
6537
6538 int __connman_service_indicate_error(struct connman_service *service,
6539                                         enum connman_service_error error)
6540 {
6541         DBG("service %p error %d", service, error);
6542
6543         if (!service)
6544                 return -EINVAL;
6545
6546         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
6547                 return -EALREADY;
6548
6549         set_error(service, error);
6550
6551         __connman_service_ipconfig_indicate_state(service,
6552                                                 CONNMAN_SERVICE_STATE_FAILURE,
6553                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
6554         __connman_service_ipconfig_indicate_state(service,
6555                                                 CONNMAN_SERVICE_STATE_FAILURE,
6556                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
6557         return 0;
6558 }
6559
6560 int __connman_service_clear_error(struct connman_service *service)
6561 {
6562         DBusMessage *pending, *provider_pending;
6563
6564         DBG("service %p", service);
6565
6566         if (!service)
6567                 return -EINVAL;
6568
6569         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
6570                 return -EINVAL;
6571
6572         pending = service->pending;
6573         service->pending = NULL;
6574         provider_pending = service->provider_pending;
6575         service->provider_pending = NULL;
6576
6577         __connman_service_ipconfig_indicate_state(service,
6578                                                 CONNMAN_SERVICE_STATE_IDLE,
6579                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
6580
6581         __connman_service_ipconfig_indicate_state(service,
6582                                                 CONNMAN_SERVICE_STATE_IDLE,
6583                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
6584
6585         service->pending = pending;
6586         service->provider_pending = provider_pending;
6587
6588         return 0;
6589 }
6590
6591 int __connman_service_indicate_default(struct connman_service *service)
6592 {
6593         DBG("service %p state %s", service, state2string(service->state));
6594
6595         if (!is_connected(service)) {
6596                 /*
6597                  * If service is not yet fully connected, then we must not
6598                  * change the default yet. The default gw will be changed
6599                  * after the service state is in ready.
6600                  */
6601                 return -EINPROGRESS;
6602         }
6603
6604         default_changed();
6605
6606         return 0;
6607 }
6608
6609 enum connman_service_state __connman_service_ipconfig_get_state(
6610                                         struct connman_service *service,
6611                                         enum connman_ipconfig_type type)
6612 {
6613         if (!service)
6614                 return CONNMAN_SERVICE_STATE_UNKNOWN;
6615
6616         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6617                 return service->state_ipv4;
6618
6619         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
6620                 return service->state_ipv6;
6621
6622         return CONNMAN_SERVICE_STATE_UNKNOWN;
6623 }
6624
6625 static void check_proxy_setup(struct connman_service *service)
6626 {
6627         /*
6628          * We start WPAD if we haven't got a PAC URL from DHCP and
6629          * if our proxy manual configuration is either empty or set
6630          * to AUTO with an empty URL.
6631          */
6632
6633         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
6634                 goto done;
6635
6636         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
6637                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
6638                         service->pac))
6639                 goto done;
6640
6641         if (__connman_wpad_start(service) < 0) {
6642                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
6643                 __connman_notifier_proxy_changed(service);
6644                 goto done;
6645         }
6646
6647         return;
6648
6649 done:
6650         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
6651 }
6652
6653 /*
6654  * How many networks are connected at the same time. If more than 1,
6655  * then set the rp_filter setting properly (loose mode routing) so that network
6656  * connectivity works ok. This is only done for IPv4 networks as IPv6
6657  * does not have rp_filter knob.
6658  */
6659 static int connected_networks_count;
6660 static int original_rp_filter;
6661
6662 static void service_rp_filter(struct connman_service *service,
6663                                 bool connected)
6664 {
6665         enum connman_ipconfig_method method;
6666
6667         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
6668
6669         switch (method) {
6670         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
6671         case CONNMAN_IPCONFIG_METHOD_OFF:
6672         case CONNMAN_IPCONFIG_METHOD_AUTO:
6673                 return;
6674         case CONNMAN_IPCONFIG_METHOD_FIXED:
6675         case CONNMAN_IPCONFIG_METHOD_MANUAL:
6676         case CONNMAN_IPCONFIG_METHOD_DHCP:
6677                 break;
6678         }
6679
6680         if (connected) {
6681                 if (connected_networks_count == 1) {
6682                         int filter_value;
6683                         filter_value = __connman_ipconfig_set_rp_filter();
6684                         if (filter_value < 0)
6685                                 return;
6686
6687                         original_rp_filter = filter_value;
6688                 }
6689                 connected_networks_count++;
6690
6691         } else {
6692                 if (connected_networks_count == 2)
6693                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
6694
6695                 connected_networks_count--;
6696                 if (connected_networks_count < 0)
6697                         connected_networks_count = 0;
6698         }
6699
6700         DBG("%s %s ipconfig %p method %d count %d filter %d",
6701                 connected ? "connected" : "disconnected", service->identifier,
6702                 service->ipconfig_ipv4, method,
6703                 connected_networks_count, original_rp_filter);
6704 }
6705
6706 static gboolean redo_wispr(gpointer user_data)
6707 {
6708         struct connman_service *service = user_data;
6709         int refcount = service->refcount - 1;
6710
6711         connman_service_unref(service);
6712         if (refcount == 0) {
6713                 DBG("Service %p already removed", service);
6714                 return FALSE;
6715         }
6716
6717         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
6718
6719         return FALSE;
6720 }
6721
6722 int __connman_service_online_check_failed(struct connman_service *service,
6723                                         enum connman_ipconfig_type type)
6724 {
6725         DBG("service %p type %d count %d", service, type,
6726                                                 service->online_check_count);
6727
6728         /* currently we only retry IPv6 stuff */
6729         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
6730                         service->online_check_count != 1) {
6731                 connman_warn("Online check failed for %p %s", service,
6732                         service->name);
6733                 return 0;
6734         }
6735
6736         service->online_check_count = 0;
6737
6738         /*
6739          * We set the timeout to 1 sec so that we have a chance to get
6740          * necessary IPv6 router advertisement messages that might have
6741          * DNS data etc.
6742          */
6743         g_timeout_add_seconds(1, redo_wispr, connman_service_ref(service));
6744
6745         return EAGAIN;
6746 }
6747
6748 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
6749                                         enum connman_service_state new_state,
6750                                         enum connman_ipconfig_type type)
6751 {
6752         struct connman_ipconfig *ipconfig = NULL;
6753         enum connman_service_state old_state;
6754         enum connman_ipconfig_method method;
6755
6756         if (!service)
6757                 return -EINVAL;
6758
6759         switch (type) {
6760         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
6761         case CONNMAN_IPCONFIG_TYPE_ALL:
6762                 return -EINVAL;
6763
6764         case CONNMAN_IPCONFIG_TYPE_IPV4:
6765                 old_state = service->state_ipv4;
6766                 ipconfig = service->ipconfig_ipv4;
6767
6768                 break;
6769
6770         case CONNMAN_IPCONFIG_TYPE_IPV6:
6771                 old_state = service->state_ipv6;
6772                 ipconfig = service->ipconfig_ipv6;
6773
6774                 break;
6775         }
6776
6777         if (!ipconfig)
6778                 return -EINVAL;
6779
6780         /* Any change? */
6781         if (old_state == new_state)
6782                 return -EALREADY;
6783
6784 #if defined TIZEN_EXT
6785         __sync_synchronize();
6786         if (service->user_pdn_connection_refcount > 0 &&
6787                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6788                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
6789                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
6790                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
6791                         service->user_pdn_connection_refcount = 0;
6792                         __sync_synchronize();
6793                 }
6794 #endif
6795
6796         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
6797                 service, service ? service->identifier : NULL,
6798                 old_state, state2string(old_state),
6799                 new_state, state2string(new_state),
6800                 type, __connman_ipconfig_type2string(type));
6801
6802         switch (new_state) {
6803         case CONNMAN_SERVICE_STATE_UNKNOWN:
6804         case CONNMAN_SERVICE_STATE_IDLE:
6805         case CONNMAN_SERVICE_STATE_ASSOCIATION:
6806                 break;
6807         case CONNMAN_SERVICE_STATE_CONFIGURATION:
6808                 __connman_ipconfig_enable(ipconfig);
6809                 break;
6810         case CONNMAN_SERVICE_STATE_READY:
6811 #if defined TIZEN_EXT
6812                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
6813                                 __connman_service_is_internet_profile(service) != TRUE) {
6814                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6815                                 service_rp_filter(service, TRUE);
6816
6817                         break;
6818                 }
6819 #endif
6820                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
6821                         check_proxy_setup(service);
6822                         service_rp_filter(service, true);
6823                 } else {
6824                         service->online_check_count = 1;
6825                         __connman_wispr_start(service, type);
6826                 }
6827                 break;
6828         case CONNMAN_SERVICE_STATE_ONLINE:
6829                 break;
6830         case CONNMAN_SERVICE_STATE_DISCONNECT:
6831                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
6832                         return -EINVAL;
6833
6834                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6835                         service_rp_filter(service, false);
6836
6837                 break;
6838         case CONNMAN_SERVICE_STATE_FAILURE:
6839                 break;
6840         }
6841
6842         /* Keep that state, but if the ipconfig method is OFF, then we set
6843            the state to IDLE so that it will not affect the combined state
6844            in the future.
6845          */
6846         method = __connman_ipconfig_get_method(ipconfig);
6847         switch (method) {
6848         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
6849         case CONNMAN_IPCONFIG_METHOD_OFF:
6850                 new_state = CONNMAN_SERVICE_STATE_IDLE;
6851                 break;
6852
6853         case CONNMAN_IPCONFIG_METHOD_FIXED:
6854         case CONNMAN_IPCONFIG_METHOD_MANUAL:
6855         case CONNMAN_IPCONFIG_METHOD_DHCP:
6856         case CONNMAN_IPCONFIG_METHOD_AUTO:
6857                 break;
6858
6859         }
6860
6861         if (is_connected_state(service, old_state) &&
6862                         !is_connected_state(service, new_state))
6863                 nameserver_remove_all(service);
6864
6865         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6866                 service->state_ipv4 = new_state;
6867         else
6868                 service->state_ipv6 = new_state;
6869
6870         if (!is_connected_state(service, old_state) &&
6871                         is_connected_state(service, new_state))
6872                 nameserver_add_all(service);
6873
6874 #if defined TIZEN_EXT
6875         int ret = service_indicate_state(service);
6876         /*Sent the Ready changed signal again in case IPv4 IP set
6877           after IPv6 IP set*/
6878
6879         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
6880                         && new_state == CONNMAN_SERVICE_STATE_READY) {
6881                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
6882                 state_changed(service);
6883         }
6884
6885         return ret;
6886 #endif
6887         return service_indicate_state(service);
6888 }
6889
6890 static bool prepare_network(struct connman_service *service)
6891 {
6892         enum connman_network_type type;
6893         unsigned int ssid_len;
6894
6895         type = connman_network_get_type(service->network);
6896
6897         switch (type) {
6898         case CONNMAN_NETWORK_TYPE_UNKNOWN:
6899         case CONNMAN_NETWORK_TYPE_VENDOR:
6900                 return false;
6901         case CONNMAN_NETWORK_TYPE_WIFI:
6902                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
6903                                                 &ssid_len))
6904                         return false;
6905
6906                 if (service->passphrase)
6907                         connman_network_set_string(service->network,
6908                                 "WiFi.Passphrase", service->passphrase);
6909                 break;
6910         case CONNMAN_NETWORK_TYPE_ETHERNET:
6911         case CONNMAN_NETWORK_TYPE_GADGET:
6912         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
6913         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
6914         case CONNMAN_NETWORK_TYPE_CELLULAR:
6915                 break;
6916         }
6917
6918         return true;
6919 }
6920
6921 static void prepare_8021x(struct connman_service *service)
6922 {
6923         if (service->eap)
6924                 connman_network_set_string(service->network, "WiFi.EAP",
6925                                                                 service->eap);
6926
6927         if (service->identity)
6928                 connman_network_set_string(service->network, "WiFi.Identity",
6929                                                         service->identity);
6930
6931         if (service->ca_cert_file)
6932                 connman_network_set_string(service->network, "WiFi.CACertFile",
6933                                                         service->ca_cert_file);
6934
6935         if (service->client_cert_file)
6936                 connman_network_set_string(service->network,
6937                                                 "WiFi.ClientCertFile",
6938                                                 service->client_cert_file);
6939
6940         if (service->private_key_file)
6941                 connman_network_set_string(service->network,
6942                                                 "WiFi.PrivateKeyFile",
6943                                                 service->private_key_file);
6944
6945         if (service->private_key_passphrase)
6946                 connman_network_set_string(service->network,
6947                                         "WiFi.PrivateKeyPassphrase",
6948                                         service->private_key_passphrase);
6949
6950         if (service->phase2)
6951                 connman_network_set_string(service->network, "WiFi.Phase2",
6952                                                         service->phase2);
6953 }
6954
6955 static int service_connect(struct connman_service *service)
6956 {
6957         int err;
6958
6959         if (service->hidden)
6960                 return -EPERM;
6961
6962         switch (service->type) {
6963         case CONNMAN_SERVICE_TYPE_UNKNOWN:
6964         case CONNMAN_SERVICE_TYPE_SYSTEM:
6965         case CONNMAN_SERVICE_TYPE_GPS:
6966         case CONNMAN_SERVICE_TYPE_P2P:
6967                 return -EINVAL;
6968         case CONNMAN_SERVICE_TYPE_ETHERNET:
6969         case CONNMAN_SERVICE_TYPE_GADGET:
6970         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
6971         case CONNMAN_SERVICE_TYPE_CELLULAR:
6972         case CONNMAN_SERVICE_TYPE_VPN:
6973                 break;
6974         case CONNMAN_SERVICE_TYPE_WIFI:
6975                 switch (service->security) {
6976                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
6977                 case CONNMAN_SERVICE_SECURITY_NONE:
6978                         break;
6979                 case CONNMAN_SERVICE_SECURITY_WEP:
6980                 case CONNMAN_SERVICE_SECURITY_PSK:
6981                 case CONNMAN_SERVICE_SECURITY_WPA:
6982                 case CONNMAN_SERVICE_SECURITY_RSN:
6983                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
6984                                 return -ENOKEY;
6985
6986                         if (service->request_passphrase_input) {
6987                                 DBG("Now try to connect other user's favorite service");
6988                                 service->request_passphrase_input = false;
6989                                 return -ENOKEY;
6990                         } else if (!service->passphrase) {
6991                                 if (!service->network)
6992                                         return -EOPNOTSUPP;
6993
6994                                 if (!service->wps ||
6995                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
6996                                         return -ENOKEY;
6997                         }
6998                         break;
6999
7000                 case CONNMAN_SERVICE_SECURITY_8021X:
7001                         if (!service->eap)
7002                                 return -EINVAL;
7003
7004 #if defined TIZEN_EXT
7005                         /*
7006                          * never request credentials if using EAP-TLS, EAP-SIM
7007                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
7008                          * need to be fully provisioned)
7009                          */
7010                         if (g_str_equal(service->eap, "tls") ||
7011                                 g_str_equal(service->eap, "sim") ||
7012                                 g_str_equal(service->eap, "aka"))
7013                                 break;
7014 #else
7015                         /*
7016                          * never request credentials if using EAP-TLS
7017                          * (EAP-TLS networks need to be fully provisioned)
7018                          */
7019                         if (g_str_equal(service->eap, "tls"))
7020                                 break;
7021 #endif
7022                         /*
7023                          * Return -ENOKEY if either identity or passphrase is
7024                          * missing. Agent provided credentials can be used as
7025                          * fallback if needed.
7026                          */
7027                         if (((!service->identity &&
7028                                         !service->agent_identity) ||
7029                                         !service->passphrase) ||
7030                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7031                                 return -ENOKEY;
7032
7033                         break;
7034                 }
7035                 break;
7036         }
7037
7038         if (service->network) {
7039                 if (!prepare_network(service))
7040                         return -EINVAL;
7041
7042                 switch (service->security) {
7043                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7044                 case CONNMAN_SERVICE_SECURITY_NONE:
7045                 case CONNMAN_SERVICE_SECURITY_WEP:
7046                 case CONNMAN_SERVICE_SECURITY_PSK:
7047                 case CONNMAN_SERVICE_SECURITY_WPA:
7048                 case CONNMAN_SERVICE_SECURITY_RSN:
7049                         break;
7050                 case CONNMAN_SERVICE_SECURITY_8021X:
7051                         prepare_8021x(service);
7052                         break;
7053                 }
7054
7055                 if (__connman_stats_service_register(service) == 0) {
7056                         __connman_stats_get(service, false,
7057                                                 &service->stats.data);
7058                         __connman_stats_get(service, true,
7059                                                 &service->stats_roaming.data);
7060                 }
7061
7062                 if (service->ipconfig_ipv4)
7063                         __connman_ipconfig_enable(service->ipconfig_ipv4);
7064                 if (service->ipconfig_ipv6)
7065                         __connman_ipconfig_enable(service->ipconfig_ipv6);
7066
7067                 err = __connman_network_connect(service->network);
7068         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7069                                         service->provider)
7070                 err = __connman_provider_connect(service->provider);
7071         else
7072                 return -EOPNOTSUPP;
7073
7074         if (err < 0) {
7075                 if (err != -EINPROGRESS) {
7076                         __connman_ipconfig_disable(service->ipconfig_ipv4);
7077                         __connman_ipconfig_disable(service->ipconfig_ipv6);
7078                         __connman_stats_service_unregister(service);
7079                 }
7080         }
7081
7082         return err;
7083 }
7084
7085 int __connman_service_connect(struct connman_service *service,
7086                         enum connman_service_connect_reason reason)
7087 {
7088         int err;
7089
7090         DBG("service %p state %s connect reason %s -> %s",
7091                 service, state2string(service->state),
7092                 reason2string(service->connect_reason),
7093                 reason2string(reason));
7094
7095         if (is_connected(service))
7096                 return -EISCONN;
7097
7098         if (is_connecting(service))
7099                 return -EALREADY;
7100
7101         switch (service->type) {
7102         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7103         case CONNMAN_SERVICE_TYPE_SYSTEM:
7104         case CONNMAN_SERVICE_TYPE_GPS:
7105         case CONNMAN_SERVICE_TYPE_P2P:
7106                 return -EINVAL;
7107
7108         case CONNMAN_SERVICE_TYPE_ETHERNET:
7109         case CONNMAN_SERVICE_TYPE_GADGET:
7110         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7111         case CONNMAN_SERVICE_TYPE_CELLULAR:
7112         case CONNMAN_SERVICE_TYPE_VPN:
7113         case CONNMAN_SERVICE_TYPE_WIFI:
7114                 break;
7115         }
7116
7117         if (!is_ipconfig_usable(service))
7118                 return -ENOLINK;
7119
7120         __connman_service_clear_error(service);
7121
7122         err = service_connect(service);
7123
7124         service->connect_reason = reason;
7125         if (err >= 0)
7126                 return 0;
7127
7128         if (err == -EINPROGRESS) {
7129                 if (service->timeout == 0)
7130                         service->timeout = g_timeout_add_seconds(
7131                                 CONNECT_TIMEOUT, connect_timeout, service);
7132
7133                 return -EINPROGRESS;
7134         }
7135
7136         if (service->network)
7137                 __connman_network_disconnect(service->network);
7138         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7139                                 service->provider)
7140                         connman_provider_disconnect(service->provider);
7141
7142         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
7143                 if (err == -ENOKEY || err == -EPERM) {
7144                         DBusMessage *pending = NULL;
7145
7146                         /*
7147                          * We steal the reply here. The idea is that the
7148                          * connecting client will see the connection status
7149                          * after the real hidden network is connected or
7150                          * connection failed.
7151                          */
7152                         if (service->hidden) {
7153                                 pending = service->pending;
7154                                 service->pending = NULL;
7155                         }
7156
7157                         err = __connman_agent_request_passphrase_input(service,
7158                                         request_input_cb,
7159                                         get_dbus_sender(service),
7160                                         pending);
7161                         if (service->hidden && err != -EINPROGRESS)
7162                                 service->pending = pending;
7163
7164                         return err;
7165                 }
7166                 reply_pending(service, -err);
7167         }
7168
7169         return err;
7170 }
7171
7172 int __connman_service_disconnect(struct connman_service *service)
7173 {
7174         int err;
7175
7176         DBG("service %p", service);
7177
7178         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
7179         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
7180
7181         connman_agent_cancel(service);
7182
7183         reply_pending(service, ECONNABORTED);
7184
7185         if (service->network) {
7186                 err = __connman_network_disconnect(service->network);
7187         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7188                                         service->provider)
7189                 err = connman_provider_disconnect(service->provider);
7190         else
7191                 return -EOPNOTSUPP;
7192
7193         if (err < 0 && err != -EINPROGRESS)
7194                 return err;
7195
7196         __connman_6to4_remove(service->ipconfig_ipv4);
7197
7198         if (service->ipconfig_ipv4)
7199                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
7200                                                         NULL);
7201         else
7202                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
7203                                                         NULL);
7204
7205 #if defined TIZEN_EXT
7206         /**
7207           * Skip the functions If there is any connected profiles
7208           * that use same interface
7209           */
7210         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7211                 __connman_service_get_connected_count_of_iface(service) <= 0) {
7212 #endif
7213         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
7214         settings_changed(service, service->ipconfig_ipv4);
7215
7216         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
7217         settings_changed(service, service->ipconfig_ipv6);
7218
7219         __connman_ipconfig_disable(service->ipconfig_ipv4);
7220         __connman_ipconfig_disable(service->ipconfig_ipv6);
7221 #if defined TIZEN_EXT
7222         }
7223 #endif
7224
7225         __connman_stats_service_unregister(service);
7226
7227         return err;
7228 }
7229
7230 int __connman_service_disconnect_all(void)
7231 {
7232         struct connman_service *service;
7233         GSList *services = NULL, *list;
7234         GList *iter;
7235
7236         DBG("");
7237
7238         for (iter = service_list; iter; iter = iter->next) {
7239                 service = iter->data;
7240
7241                 if (!is_connected(service))
7242                         break;
7243
7244                 services = g_slist_prepend(services, service);
7245         }
7246
7247         for (list = services; list; list = list->next) {
7248                 struct connman_service *service = list->data;
7249
7250                 service->ignore = true;
7251
7252                 __connman_service_disconnect(service);
7253         }
7254
7255         g_slist_free(services);
7256
7257         return 0;
7258 }
7259
7260 /**
7261  * lookup_by_identifier:
7262  * @identifier: service identifier
7263  *
7264  * Look up a service by identifier (reference count will not be increased)
7265  */
7266 static struct connman_service *lookup_by_identifier(const char *identifier)
7267 {
7268         return g_hash_table_lookup(service_hash, identifier);
7269 }
7270
7271 struct provision_user_data {
7272         const char *ident;
7273         int ret;
7274 };
7275
7276 static void provision_changed(gpointer value, gpointer user_data)
7277 {
7278         struct connman_service *service = value;
7279         struct provision_user_data *data = user_data;
7280         const char *path = data->ident;
7281         int ret;
7282
7283         ret = __connman_config_provision_service_ident(service, path,
7284                         service->config_file, service->config_entry);
7285         if (ret > 0)
7286                 data->ret = ret;
7287 }
7288
7289 int __connman_service_provision_changed(const char *ident)
7290 {
7291         struct provision_user_data data = {
7292                 .ident = ident,
7293                 .ret = 0
7294         };
7295
7296         g_list_foreach(service_list, provision_changed, (void *)&data);
7297
7298         /*
7299          * Because the provision_changed() might have set some services
7300          * as favorite, we must sort the sequence now.
7301          */
7302         if (services_dirty) {
7303                 services_dirty = false;
7304
7305                 service_list_sort();
7306
7307                 __connman_connection_update_gateway();
7308         }
7309
7310         return data.ret;
7311 }
7312
7313 void __connman_service_set_config(struct connman_service *service,
7314                                 const char *file_id, const char *entry)
7315 {
7316         if (!service)
7317                 return;
7318
7319         g_free(service->config_file);
7320         service->config_file = g_strdup(file_id);
7321
7322         g_free(service->config_entry);
7323         service->config_entry = g_strdup(entry);
7324 }
7325
7326 /**
7327  * __connman_service_get:
7328  * @identifier: service identifier
7329  *
7330  * Look up a service by identifier or create a new one if not found
7331  */
7332 static struct connman_service *service_get(const char *identifier)
7333 {
7334         struct connman_service *service;
7335
7336         service = g_hash_table_lookup(service_hash, identifier);
7337         if (service) {
7338                 connman_service_ref(service);
7339                 return service;
7340         }
7341
7342         service = connman_service_create();
7343         if (!service)
7344                 return NULL;
7345
7346         DBG("service %p", service);
7347
7348         service->identifier = g_strdup(identifier);
7349
7350         service_list = g_list_insert_sorted(service_list, service,
7351                                                 service_compare);
7352
7353         g_hash_table_insert(service_hash, service->identifier, service);
7354
7355         return service;
7356 }
7357
7358 static int service_register(struct connman_service *service)
7359 {
7360         DBG("service %p", service);
7361
7362         if (service->path)
7363                 return -EALREADY;
7364
7365         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
7366                                                 service->identifier);
7367
7368         DBG("path %s", service->path);
7369
7370         if (__connman_config_provision_service(service) < 0)
7371                 service_load(service);
7372
7373         g_dbus_register_interface(connection, service->path,
7374                                         CONNMAN_SERVICE_INTERFACE,
7375                                         service_methods, service_signals,
7376                                                         NULL, service, NULL);
7377
7378         service_list_sort();
7379
7380         __connman_connection_update_gateway();
7381
7382         return 0;
7383 }
7384
7385 static void service_up(struct connman_ipconfig *ipconfig,
7386                 const char *ifname)
7387 {
7388         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7389
7390         DBG("%s up", ifname);
7391
7392         link_changed(service);
7393
7394         service->stats.valid = false;
7395         service->stats_roaming.valid = false;
7396 }
7397
7398 static void service_down(struct connman_ipconfig *ipconfig,
7399                         const char *ifname)
7400 {
7401         DBG("%s down", ifname);
7402 }
7403
7404 static void service_lower_up(struct connman_ipconfig *ipconfig,
7405                         const char *ifname)
7406 {
7407         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7408
7409         DBG("%s lower up", ifname);
7410
7411         stats_start(service);
7412 }
7413
7414 static void service_lower_down(struct connman_ipconfig *ipconfig,
7415                         const char *ifname)
7416 {
7417         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7418
7419         DBG("%s lower down", ifname);
7420
7421         if (!is_idle_state(service, service->state_ipv4))
7422                 __connman_ipconfig_disable(service->ipconfig_ipv4);
7423
7424         if (!is_idle_state(service, service->state_ipv6))
7425                 __connman_ipconfig_disable(service->ipconfig_ipv6);
7426
7427         stats_stop(service);
7428         service_save(service);
7429 }
7430
7431 static void service_ip_bound(struct connman_ipconfig *ipconfig,
7432                         const char *ifname)
7433 {
7434         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7435         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
7436         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
7437
7438         DBG("%s ip bound", ifname);
7439
7440         type = __connman_ipconfig_get_config_type(ipconfig);
7441         method = __connman_ipconfig_get_method(ipconfig);
7442
7443         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
7444                                                         type, method);
7445
7446         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
7447                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
7448                 __connman_service_ipconfig_indicate_state(service,
7449                                                 CONNMAN_SERVICE_STATE_READY,
7450                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7451
7452         settings_changed(service, ipconfig);
7453 }
7454
7455 static void service_ip_release(struct connman_ipconfig *ipconfig,
7456                         const char *ifname)
7457 {
7458         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7459         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
7460         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
7461
7462         DBG("%s ip release", ifname);
7463
7464         type = __connman_ipconfig_get_config_type(ipconfig);
7465         method = __connman_ipconfig_get_method(ipconfig);
7466
7467         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
7468                                                         type, method);
7469
7470         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
7471                         method == CONNMAN_IPCONFIG_METHOD_OFF)
7472                 __connman_service_ipconfig_indicate_state(service,
7473                                         CONNMAN_SERVICE_STATE_DISCONNECT,
7474                                         CONNMAN_IPCONFIG_TYPE_IPV6);
7475
7476         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
7477                         method == CONNMAN_IPCONFIG_METHOD_OFF)
7478                 __connman_service_ipconfig_indicate_state(service,
7479                                         CONNMAN_SERVICE_STATE_DISCONNECT,
7480                                         CONNMAN_IPCONFIG_TYPE_IPV4);
7481
7482         settings_changed(service, ipconfig);
7483 }
7484
7485 static void service_route_changed(struct connman_ipconfig *ipconfig,
7486                                 const char *ifname)
7487 {
7488         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7489
7490         DBG("%s route changed", ifname);
7491
7492         settings_changed(service, ipconfig);
7493 }
7494
7495 static const struct connman_ipconfig_ops service_ops = {
7496         .up             = service_up,
7497         .down           = service_down,
7498         .lower_up       = service_lower_up,
7499         .lower_down     = service_lower_down,
7500         .ip_bound       = service_ip_bound,
7501         .ip_release     = service_ip_release,
7502         .route_set      = service_route_changed,
7503         .route_unset    = service_route_changed,
7504 };
7505
7506 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
7507                 int index, enum connman_ipconfig_method method)
7508 {
7509         struct connman_ipconfig *ipconfig_ipv4;
7510
7511         ipconfig_ipv4 = __connman_ipconfig_create(index,
7512                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7513         if (!ipconfig_ipv4)
7514                 return NULL;
7515
7516         __connman_ipconfig_set_method(ipconfig_ipv4, method);
7517
7518         __connman_ipconfig_set_data(ipconfig_ipv4, service);
7519
7520         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
7521
7522         return ipconfig_ipv4;
7523 }
7524
7525 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
7526                 int index)
7527 {
7528         struct connman_ipconfig *ipconfig_ipv6;
7529
7530         ipconfig_ipv6 = __connman_ipconfig_create(index,
7531                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7532         if (!ipconfig_ipv6)
7533                 return NULL;
7534
7535         __connman_ipconfig_set_data(ipconfig_ipv6, service);
7536
7537         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
7538
7539         return ipconfig_ipv6;
7540 }
7541
7542 void __connman_service_read_ip4config(struct connman_service *service)
7543 {
7544         GKeyFile *keyfile;
7545
7546         if (!service->ipconfig_ipv4)
7547                 return;
7548
7549         keyfile = connman_storage_load_service(service->identifier);
7550         if (!keyfile)
7551                 return;
7552
7553         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
7554                                 service->identifier, "IPv4.");
7555
7556         g_key_file_free(keyfile);
7557 }
7558
7559 void connman_service_create_ip4config(struct connman_service *service,
7560                                         int index)
7561 {
7562         DBG("ipv4 %p", service->ipconfig_ipv4);
7563
7564         if (service->ipconfig_ipv4)
7565                 return;
7566
7567         service->ipconfig_ipv4 = create_ip4config(service, index,
7568                         CONNMAN_IPCONFIG_METHOD_DHCP);
7569         __connman_service_read_ip4config(service);
7570 }
7571
7572 void __connman_service_read_ip6config(struct connman_service *service)
7573 {
7574         GKeyFile *keyfile;
7575
7576         if (!service->ipconfig_ipv6)
7577                 return;
7578
7579         keyfile = connman_storage_load_service(service->identifier);
7580         if (!keyfile)
7581                 return;
7582
7583         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
7584                                 service->identifier, "IPv6.");
7585
7586         g_key_file_free(keyfile);
7587 }
7588
7589 void connman_service_create_ip6config(struct connman_service *service,
7590                                                                 int index)
7591 {
7592         DBG("ipv6 %p", service->ipconfig_ipv6);
7593
7594         if (service->ipconfig_ipv6)
7595                 return;
7596
7597         service->ipconfig_ipv6 = create_ip6config(service, index);
7598
7599         __connman_service_read_ip6config(service);
7600 }
7601
7602 /**
7603  * connman_service_lookup_from_network:
7604  * @network: network structure
7605  *
7606  * Look up a service by network (reference count will not be increased)
7607  */
7608 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
7609 {
7610         struct connman_service *service;
7611         const char *ident, *group;
7612         char *name;
7613
7614         if (!network)
7615                 return NULL;
7616
7617         ident = __connman_network_get_ident(network);
7618         if (!ident)
7619                 return NULL;
7620
7621         group = connman_network_get_group(network);
7622         if (!group)
7623                 return NULL;
7624
7625         name = g_strdup_printf("%s_%s_%s",
7626                         __connman_network_get_type(network), ident, group);
7627         service = lookup_by_identifier(name);
7628         g_free(name);
7629
7630         return service;
7631 }
7632
7633 struct connman_service *__connman_service_lookup_from_index(int index)
7634 {
7635         struct connman_service *service;
7636         GList *list;
7637
7638         for (list = service_list; list; list = list->next) {
7639                 service = list->data;
7640
7641                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
7642                                                         == index)
7643                         return service;
7644
7645                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
7646                                                         == index)
7647                         return service;
7648         }
7649
7650         return NULL;
7651 }
7652
7653 struct connman_service *__connman_service_lookup_from_ident(const char *identifier)
7654 {
7655         return lookup_by_identifier(identifier);
7656 }
7657
7658 const char *__connman_service_get_ident(struct connman_service *service)
7659 {
7660         return service->identifier;
7661 }
7662
7663 const char *__connman_service_get_path(struct connman_service *service)
7664 {
7665         return service->path;
7666 }
7667
7668 const char *__connman_service_get_name(struct connman_service *service)
7669 {
7670         return service->name;
7671 }
7672
7673 enum connman_service_state __connman_service_get_state(struct connman_service *service)
7674 {
7675         return service->state;
7676 }
7677
7678 unsigned int __connman_service_get_order(struct connman_service *service)
7679 {
7680         unsigned int order = 0;
7681
7682         if (!service)
7683                 return 0;
7684
7685         service->order = 0;
7686
7687         if (!service->favorite)
7688                 return 0;
7689
7690 #if defined TIZEN_EXT
7691         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7692                         service->do_split_routing == FALSE)
7693                 order = 10;
7694         else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
7695                 if (service->order < 5)
7696                         order = 5;
7697         } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
7698                 order = 4;
7699         else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
7700                 order = 3;
7701         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7702                         __connman_service_is_internet_profile(service) == TRUE)
7703                 order = 1;
7704         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7705                         __connman_service_is_tethering_profile(service) == TRUE)
7706                 order = 0;
7707         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7708                 order = 0;
7709         else
7710                 order = 2;
7711 #else
7712         if (service == service_list->data)
7713                 order = 1;
7714
7715         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7716                         !service->do_split_routing) {
7717                 service->order = 10;
7718                 order = 10;
7719         }
7720 #endif
7721         DBG("service %p name %s order %d split %d", service, service->name,
7722                 order, service->do_split_routing);
7723
7724         return order;
7725 }
7726
7727 void __connman_service_update_ordering(void)
7728 {
7729         if (service_list && service_list->next)
7730                 service_list = g_list_sort(service_list, service_compare);
7731 }
7732
7733 static enum connman_service_type convert_network_type(struct connman_network *network)
7734 {
7735         enum connman_network_type type = connman_network_get_type(network);
7736
7737         switch (type) {
7738         case CONNMAN_NETWORK_TYPE_UNKNOWN:
7739         case CONNMAN_NETWORK_TYPE_VENDOR:
7740                 break;
7741         case CONNMAN_NETWORK_TYPE_ETHERNET:
7742                 return CONNMAN_SERVICE_TYPE_ETHERNET;
7743         case CONNMAN_NETWORK_TYPE_WIFI:
7744                 return CONNMAN_SERVICE_TYPE_WIFI;
7745         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
7746         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
7747                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
7748         case CONNMAN_NETWORK_TYPE_CELLULAR:
7749                 return CONNMAN_SERVICE_TYPE_CELLULAR;
7750         case CONNMAN_NETWORK_TYPE_GADGET:
7751                 return CONNMAN_SERVICE_TYPE_GADGET;
7752         }
7753
7754         return CONNMAN_SERVICE_TYPE_UNKNOWN;
7755 }
7756
7757 static enum connman_service_security convert_wifi_security(const char *security)
7758 {
7759         if (!security)
7760                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
7761         else if (g_str_equal(security, "none"))
7762                 return CONNMAN_SERVICE_SECURITY_NONE;
7763         else if (g_str_equal(security, "wep"))
7764                 return CONNMAN_SERVICE_SECURITY_WEP;
7765         else if (g_str_equal(security, "psk"))
7766                 return CONNMAN_SERVICE_SECURITY_PSK;
7767         else if (g_str_equal(security, "ieee8021x"))
7768                 return CONNMAN_SERVICE_SECURITY_8021X;
7769         else if (g_str_equal(security, "wpa"))
7770                 return CONNMAN_SERVICE_SECURITY_WPA;
7771         else if (g_str_equal(security, "rsn"))
7772                 return CONNMAN_SERVICE_SECURITY_RSN;
7773         else
7774                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
7775 }
7776
7777 static void update_from_network(struct connman_service *service,
7778                                         struct connman_network *network)
7779 {
7780         uint8_t strength = service->strength;
7781         const char *str;
7782
7783         DBG("service %p network %p", service, network);
7784
7785         if (is_connected(service))
7786                 return;
7787
7788         if (is_connecting(service))
7789                 return;
7790
7791         str = connman_network_get_string(network, "Name");
7792         if (str) {
7793                 g_free(service->name);
7794                 service->name = g_strdup(str);
7795                 service->hidden = false;
7796         } else {
7797                 g_free(service->name);
7798                 service->name = NULL;
7799                 service->hidden = true;
7800         }
7801
7802         service->strength = connman_network_get_strength(network);
7803         service->roaming = connman_network_get_bool(network, "Roaming");
7804
7805         if (service->strength == 0) {
7806                 /*
7807                  * Filter out 0-values; it's unclear what they mean
7808                  * and they cause anomalous sorting of the priority list.
7809                  */
7810                 service->strength = strength;
7811         }
7812
7813         str = connman_network_get_string(network, "WiFi.Security");
7814         service->security = convert_wifi_security(str);
7815
7816         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7817                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
7818
7819         if (service->strength > strength && service->network) {
7820                 connman_network_unref(service->network);
7821                 service->network = connman_network_ref(network);
7822
7823                 strength_changed(service);
7824         }
7825
7826         if (!service->network)
7827                 service->network = connman_network_ref(network);
7828
7829         service_list_sort();
7830 }
7831
7832 /**
7833  * __connman_service_create_from_network:
7834  * @network: network structure
7835  *
7836  * Look up service by network and if not found, create one
7837  */
7838 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
7839 {
7840         struct connman_service *service;
7841         struct connman_device *device;
7842         const char *ident, *group;
7843         char *name;
7844         unsigned int *auto_connect_types;
7845         int i, index;
7846
7847         DBG("network %p", network);
7848
7849         if (!network)
7850                 return NULL;
7851
7852         ident = __connman_network_get_ident(network);
7853         if (!ident)
7854                 return NULL;
7855
7856         group = connman_network_get_group(network);
7857         if (!group)
7858                 return NULL;
7859
7860         name = g_strdup_printf("%s_%s_%s",
7861                         __connman_network_get_type(network), ident, group);
7862         service = service_get(name);
7863         g_free(name);
7864
7865         if (!service)
7866                 return NULL;
7867
7868         if (__connman_network_get_weakness(network))
7869                 return service;
7870
7871         if (service->path) {
7872                 update_from_network(service, network);
7873                 __connman_connection_update_gateway();
7874                 return service;
7875         }
7876
7877         service->type = convert_network_type(network);
7878
7879         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
7880         service->autoconnect = false;
7881         for (i = 0; auto_connect_types &&
7882                      auto_connect_types[i] != 0; i++) {
7883                 if (service->type == auto_connect_types[i]) {
7884                         service->autoconnect = true;
7885                         break;
7886                 }
7887         }
7888
7889         switch (service->type) {
7890         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7891         case CONNMAN_SERVICE_TYPE_SYSTEM:
7892         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7893         case CONNMAN_SERVICE_TYPE_GPS:
7894         case CONNMAN_SERVICE_TYPE_VPN:
7895         case CONNMAN_SERVICE_TYPE_GADGET:
7896         case CONNMAN_SERVICE_TYPE_WIFI:
7897         case CONNMAN_SERVICE_TYPE_CELLULAR:
7898         case CONNMAN_SERVICE_TYPE_P2P:
7899                 break;
7900         case CONNMAN_SERVICE_TYPE_ETHERNET:
7901                 service->favorite = true;
7902                 break;
7903         }
7904
7905         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
7906         service->state = combine_state(service->state_ipv4, service->state_ipv6);
7907
7908         update_from_network(service, network);
7909
7910         index = connman_network_get_index(network);
7911
7912         if (!service->ipconfig_ipv4)
7913                 service->ipconfig_ipv4 = create_ip4config(service, index,
7914                                 CONNMAN_IPCONFIG_METHOD_DHCP);
7915
7916         if (!service->ipconfig_ipv6)
7917                 service->ipconfig_ipv6 = create_ip6config(service, index);
7918
7919         service_register(service);
7920
7921         if (service->favorite) {
7922                 device = connman_network_get_device(service->network);
7923                 if (device && !connman_device_get_scanning(device)) {
7924
7925                         switch (service->type) {
7926                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7927                         case CONNMAN_SERVICE_TYPE_SYSTEM:
7928                         case CONNMAN_SERVICE_TYPE_P2P:
7929                                 break;
7930
7931                         case CONNMAN_SERVICE_TYPE_GADGET:
7932                         case CONNMAN_SERVICE_TYPE_ETHERNET:
7933                                 if (service->autoconnect) {
7934                                         __connman_service_connect(service,
7935                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7936                                         break;
7937                                 }
7938
7939                                 /* fall through */
7940                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7941                         case CONNMAN_SERVICE_TYPE_GPS:
7942                         case CONNMAN_SERVICE_TYPE_VPN:
7943                         case CONNMAN_SERVICE_TYPE_WIFI:
7944                         case CONNMAN_SERVICE_TYPE_CELLULAR:
7945                                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7946                                 break;
7947                         }
7948                 }
7949
7950 #if defined TIZEN_EXT
7951                 /* TIZEN synchronizes below information when the service creates */
7952                 if (service->eap != NULL)
7953                         connman_network_set_string(service->network, "WiFi.EAP",
7954                                                                 service->eap);
7955                 if (service->identity != NULL)
7956                         connman_network_set_string(service->network, "WiFi.Identity",
7957                                                                 service->identity);
7958                 if (service->phase2 != NULL)
7959                         connman_network_set_string(service->network, "WiFi.Phase2",
7960                                                                 service->phase2);
7961 #endif
7962         }
7963
7964         __connman_notifier_service_add(service, service->name);
7965         service_schedule_added(service);
7966
7967         return service;
7968 }
7969
7970 void __connman_service_update_from_network(struct connman_network *network)
7971 {
7972         bool need_sort = false;
7973         struct connman_service *service;
7974         uint8_t strength;
7975         bool roaming;
7976         const char *name;
7977         bool stats_enable;
7978
7979         service = connman_service_lookup_from_network(network);
7980         if (!service)
7981                 return;
7982
7983         if (!service->network)
7984                 return;
7985
7986         name = connman_network_get_string(service->network, "Name");
7987         if (g_strcmp0(service->name, name) != 0) {
7988                 g_free(service->name);
7989                 service->name = g_strdup(name);
7990
7991                 if (allow_property_changed(service))
7992                         connman_dbus_property_changed_basic(service->path,
7993                                         CONNMAN_SERVICE_INTERFACE, "Name",
7994                                         DBUS_TYPE_STRING, &service->name);
7995         }
7996
7997         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7998                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
7999
8000         strength = connman_network_get_strength(service->network);
8001         if (strength == service->strength)
8002                 goto roaming;
8003
8004         service->strength = strength;
8005         need_sort = true;
8006
8007         strength_changed(service);
8008
8009 roaming:
8010         roaming = connman_network_get_bool(service->network, "Roaming");
8011         if (roaming == service->roaming)
8012                 goto sorting;
8013
8014         stats_enable = stats_enabled(service);
8015         if (stats_enable)
8016                 stats_stop(service);
8017
8018         service->roaming = roaming;
8019         need_sort = true;
8020
8021         if (stats_enable)
8022                 stats_start(service);
8023
8024         roaming_changed(service);
8025
8026 sorting:
8027         if (need_sort) {
8028                 service_list_sort();
8029         }
8030 }
8031
8032 void __connman_service_remove_from_network(struct connman_network *network)
8033 {
8034         struct connman_service *service;
8035
8036         service = connman_service_lookup_from_network(network);
8037
8038         DBG("network %p service %p", network, service);
8039
8040         if (!service)
8041                 return;
8042
8043         service->ignore = true;
8044
8045         __connman_connection_gateway_remove(service,
8046                                         CONNMAN_IPCONFIG_TYPE_ALL);
8047
8048         connman_service_unref(service);
8049 }
8050
8051 /**
8052  * __connman_service_create_from_provider:
8053  * @provider: provider structure
8054  *
8055  * Look up service by provider and if not found, create one
8056  */
8057 struct connman_service *
8058 __connman_service_create_from_provider(struct connman_provider *provider)
8059 {
8060         struct connman_service *service;
8061         const char *ident, *str;
8062         char *name;
8063         int index = connman_provider_get_index(provider);
8064
8065         DBG("provider %p", provider);
8066
8067         ident = __connman_provider_get_ident(provider);
8068         if (!ident)
8069                 return NULL;
8070
8071         name = g_strdup_printf("vpn_%s", ident);
8072         service = service_get(name);
8073         g_free(name);
8074
8075         if (!service)
8076                 return NULL;
8077
8078         service->type = CONNMAN_SERVICE_TYPE_VPN;
8079         service->provider = connman_provider_ref(provider);
8080         service->autoconnect = false;
8081         service->favorite = true;
8082
8083         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8084         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8085
8086         str = connman_provider_get_string(provider, "Name");
8087         if (str) {
8088                 g_free(service->name);
8089                 service->name = g_strdup(str);
8090                 service->hidden = false;
8091         } else {
8092                 g_free(service->name);
8093                 service->name = NULL;
8094                 service->hidden = true;
8095         }
8096
8097         service->strength = 0;
8098
8099         if (!service->ipconfig_ipv4)
8100                 service->ipconfig_ipv4 = create_ip4config(service, index,
8101                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
8102
8103         if (!service->ipconfig_ipv6)
8104                 service->ipconfig_ipv6 = create_ip6config(service, index);
8105
8106         service_register(service);
8107
8108         __connman_notifier_service_add(service, service->name);
8109         service_schedule_added(service);
8110
8111         return service;
8112 }
8113
8114 static void remove_unprovisioned_services(void)
8115 {
8116         gchar **services;
8117         GKeyFile *keyfile, *configkeyfile;
8118         char *file, *section;
8119         int i = 0;
8120
8121         services = connman_storage_get_services();
8122         if (!services)
8123                 return;
8124
8125         for (; services[i]; i++) {
8126                 file = section = NULL;
8127                 keyfile = configkeyfile = NULL;
8128
8129                 keyfile = connman_storage_load_service(services[i]);
8130                 if (!keyfile)
8131                         continue;
8132
8133                 file = g_key_file_get_string(keyfile, services[i],
8134                                         "Config.file", NULL);
8135                 if (!file)
8136                         goto next;
8137
8138                 section = g_key_file_get_string(keyfile, services[i],
8139                                         "Config.ident", NULL);
8140                 if (!section)
8141                         goto next;
8142
8143                 configkeyfile = __connman_storage_load_config(file);
8144                 if (!configkeyfile) {
8145                         /*
8146                          * Config file is missing, remove the provisioned
8147                          * service.
8148                          */
8149                         __connman_storage_remove_service(services[i]);
8150                         goto next;
8151                 }
8152
8153                 if (!g_key_file_has_group(configkeyfile, section))
8154                         /*
8155                          * Config section is missing, remove the provisioned
8156                          * service.
8157                          */
8158                         __connman_storage_remove_service(services[i]);
8159
8160         next:
8161                 if (keyfile)
8162                         g_key_file_free(keyfile);
8163
8164                 if (configkeyfile)
8165                         g_key_file_free(configkeyfile);
8166
8167                 g_free(section);
8168                 g_free(file);
8169         }
8170
8171         g_strfreev(services);
8172 }
8173
8174 static int agent_probe(struct connman_agent *agent)
8175 {
8176         DBG("agent %p", agent);
8177         return 0;
8178 }
8179
8180 static void agent_remove(struct connman_agent *agent)
8181 {
8182         DBG("agent %p", agent);
8183 }
8184
8185 static void *agent_context_ref(void *context)
8186 {
8187         struct connman_service *service = context;
8188
8189         return (void *)connman_service_ref(service);
8190 }
8191
8192 static void agent_context_unref(void *context)
8193 {
8194         struct connman_service *service = context;
8195
8196         connman_service_unref(service);
8197 }
8198
8199 static struct connman_agent_driver agent_driver = {
8200         .name           = "service",
8201         .interface      = CONNMAN_AGENT_INTERFACE,
8202         .probe          = agent_probe,
8203         .remove         = agent_remove,
8204         .context_ref    = agent_context_ref,
8205         .context_unref  = agent_context_unref,
8206 };
8207
8208 int __connman_service_init(void)
8209 {
8210         int err;
8211
8212         DBG("");
8213
8214         err = connman_agent_driver_register(&agent_driver);
8215         if (err < 0) {
8216                 connman_error("Cannot register agent driver for %s",
8217                                                 agent_driver.name);
8218                 return err;
8219         }
8220
8221         connection = connman_dbus_get_connection();
8222
8223         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
8224                                                         NULL, service_free);
8225
8226         services_notify = g_new0(struct _services_notify, 1);
8227         services_notify->remove = g_hash_table_new_full(g_str_hash,
8228                         g_str_equal, g_free, NULL);
8229         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
8230
8231         remove_unprovisioned_services();
8232
8233         return 0;
8234 }
8235
8236 void __connman_service_cleanup(void)
8237 {
8238         DBG("");
8239
8240         if (vpn_autoconnect_timeout) {
8241                 g_source_remove(vpn_autoconnect_timeout);
8242                 vpn_autoconnect_timeout = 0;
8243         }
8244
8245         if (autoconnect_timeout != 0) {
8246                 g_source_remove(autoconnect_timeout);
8247                 autoconnect_timeout = 0;
8248         }
8249
8250         connman_agent_driver_unregister(&agent_driver);
8251
8252         g_list_free(service_list);
8253         service_list = NULL;
8254
8255         g_hash_table_destroy(service_hash);
8256         service_hash = NULL;
8257
8258         g_slist_free(counter_list);
8259         counter_list = NULL;
8260
8261         if (services_notify->id != 0) {
8262                 g_source_remove(services_notify->id);
8263                 service_send_changed(NULL);
8264                 g_hash_table_destroy(services_notify->remove);
8265                 g_hash_table_destroy(services_notify->add);
8266         }
8267         g_free(services_notify);
8268
8269         dbus_connection_unref(connection);
8270 }