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