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