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