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