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