Added vsie information of AP in append_properties function.
[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         const char *str;
3170         gboolean passpoint;
3171
3172         ssid = connman_network_get_blob(network, "WiFi.SSID", &ssid_len);
3173         bssid = connman_network_get_bssid(network);
3174         maxrate = connman_network_get_maxrate(network);
3175         frequency = connman_network_get_frequency(network);
3176         enc_mode = connman_network_get_enc_mode(network);
3177         passpoint = connman_network_get_is_hs20AP(network);
3178         keymgmt = connman_network_get_keymgmt(network);
3179
3180         snprintf(bssid_str, WIFI_BSSID_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
3181                                 bssid[0], bssid[1], bssid[2],
3182                                 bssid[3], bssid[4], bssid[5]);
3183
3184         connman_dbus_dict_append_fixed_array(dict, "SSID",
3185                                         DBUS_TYPE_BYTE, &ssid, ssid_len);
3186         connman_dbus_dict_append_basic(dict, "BSSID",
3187                                         DBUS_TYPE_STRING, &bssid_str);
3188         connman_dbus_dict_append_basic(dict, "MaxRate",
3189                                         DBUS_TYPE_UINT32, &maxrate);
3190         connman_dbus_dict_append_basic(dict, "Frequency",
3191                                         DBUS_TYPE_UINT16, &frequency);
3192         connman_dbus_dict_append_basic(dict, "EncryptionMode",
3193                                         DBUS_TYPE_STRING, &enc_mode);
3194         connman_dbus_dict_append_basic(dict, "Passpoint",
3195                                         DBUS_TYPE_BOOLEAN, &passpoint);
3196         connman_dbus_dict_append_basic(dict, "Keymgmt",
3197                                         DBUS_TYPE_UINT32, &keymgmt);
3198
3199         str = connman_network_get_string(network, "WiFi.Security");
3200         if (str != NULL && g_str_equal(str, "ieee8021x") == TRUE) {
3201                 str = connman_network_get_string(network, "WiFi.EAP");
3202                 if (str != NULL)
3203                         connman_dbus_dict_append_basic(dict, "EAP",
3204                                         DBUS_TYPE_STRING, &str);
3205
3206                 str = connman_network_get_string(network, "WiFi.Phase2");
3207                 if (str != NULL)
3208                         connman_dbus_dict_append_basic(dict, "Phase2",
3209                                         DBUS_TYPE_STRING, &str);
3210
3211                 str = connman_network_get_string(network, "WiFi.Identity");
3212                 if (str != NULL)
3213                         connman_dbus_dict_append_basic(dict, "Identity",
3214                                         DBUS_TYPE_STRING, &str);
3215
3216                 str = connman_network_get_string(network, "WiFi.CACertFile");
3217                 if (str != NULL)
3218                         connman_dbus_dict_append_basic(dict, "CACertFile",
3219                                         DBUS_TYPE_STRING, &str);
3220
3221                 str = connman_network_get_string(network,
3222                                 "WiFi.ClientCertFile");
3223                 if (str != NULL)
3224                         connman_dbus_dict_append_basic(dict, "ClientCertFile",
3225                                         DBUS_TYPE_STRING, &str);
3226
3227                 str = connman_network_get_string(network,
3228                                 "WiFi.PrivateKeyFile");
3229                 if (str != NULL)
3230                         connman_dbus_dict_append_basic(dict, "PrivateKeyFile",
3231                                         DBUS_TYPE_STRING, &str);
3232         }
3233 }
3234 #endif
3235
3236 static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
3237                                         struct connman_service *service)
3238 {
3239         dbus_bool_t val;
3240         const char *str;
3241         GSList *list;
3242
3243 #if defined TIZEN_EXT
3244         unsigned int frequency = 0U;
3245         if (service && service->network) {
3246                 frequency = connman_network_get_frequency(service->network);
3247                 connman_dbus_dict_append_basic(dict, "Frequency",
3248                                 DBUS_TYPE_UINT16, &frequency);
3249         }
3250         const void *wifi_vsie;
3251         unsigned int wifi_vsie_len;
3252         wifi_vsie = connman_network_get_blob(service->network, "WiFi.Vsie", &wifi_vsie_len);
3253         if(wifi_vsie_len > 0) {
3254                 DBG("ConnMan, service->path=%s vsie length=%d", service->path, wifi_vsie_len);
3255         }
3256         connman_dbus_dict_append_fixed_array(dict, "Vsie", DBUS_TYPE_BYTE,
3257                         &wifi_vsie, wifi_vsie_len);
3258 #endif
3259
3260         str = __connman_service_type2string(service->type);
3261         if (str)
3262                 connman_dbus_dict_append_basic(dict, "Type",
3263                                                 DBUS_TYPE_STRING, &str);
3264
3265         connman_dbus_dict_append_array(dict, "Security",
3266                                 DBUS_TYPE_STRING, append_security, service);
3267
3268         str = state2string(service->state);
3269         if (str)
3270                 connman_dbus_dict_append_basic(dict, "State",
3271                                                 DBUS_TYPE_STRING, &str);
3272
3273 #ifdef TIZEN_EXT
3274         str = state2string(service->state_ipv6);
3275         if (str != NULL)
3276                 connman_dbus_dict_append_basic(dict, "StateIPv6",
3277                                 DBUS_TYPE_STRING, &str);
3278 #endif
3279
3280         str = error2string(service->error);
3281         if (str)
3282                 connman_dbus_dict_append_basic(dict, "Error",
3283                                                 DBUS_TYPE_STRING, &str);
3284
3285         if (service->strength > 0)
3286                 connman_dbus_dict_append_basic(dict, "Strength",
3287                                         DBUS_TYPE_BYTE, &service->strength);
3288
3289         val = service->favorite;
3290         connman_dbus_dict_append_basic(dict, "Favorite",
3291                                         DBUS_TYPE_BOOLEAN, &val);
3292
3293         val = service->immutable;
3294         connman_dbus_dict_append_basic(dict, "Immutable",
3295                                         DBUS_TYPE_BOOLEAN, &val);
3296
3297         if (service->favorite)
3298                 val = service->autoconnect;
3299         else
3300                 val = service->favorite;
3301
3302         connman_dbus_dict_append_basic(dict, "AutoConnect",
3303                                 DBUS_TYPE_BOOLEAN, &val);
3304
3305         if (service->name)
3306                 connman_dbus_dict_append_basic(dict, "Name",
3307                                         DBUS_TYPE_STRING, &service->name);
3308
3309         switch (service->type) {
3310         case CONNMAN_SERVICE_TYPE_UNKNOWN:
3311         case CONNMAN_SERVICE_TYPE_SYSTEM:
3312         case CONNMAN_SERVICE_TYPE_GPS:
3313         case CONNMAN_SERVICE_TYPE_VPN:
3314         case CONNMAN_SERVICE_TYPE_P2P:
3315                 break;
3316         case CONNMAN_SERVICE_TYPE_CELLULAR:
3317                 val = service->roaming;
3318                 connman_dbus_dict_append_basic(dict, "Roaming",
3319                                         DBUS_TYPE_BOOLEAN, &val);
3320
3321                 connman_dbus_dict_append_dict(dict, "Ethernet",
3322                                                 append_ethernet, service);
3323                 break;
3324         case CONNMAN_SERVICE_TYPE_WIFI:
3325 #if defined TIZEN_EXT
3326                 if (service->network != NULL)
3327                         append_wifi_ext_info(dict, service->network);
3328
3329                 connman_dbus_dict_append_dict(dict, "Ethernet",
3330                                                 append_ethernet, service);
3331
3332                 connman_dbus_dict_append_basic(dict, "DisconnectReason",
3333                                 DBUS_TYPE_INT32, &service->disconnect_reason);
3334
3335                 break;
3336 #endif
3337         case CONNMAN_SERVICE_TYPE_ETHERNET:
3338         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
3339         case CONNMAN_SERVICE_TYPE_GADGET:
3340                 connman_dbus_dict_append_dict(dict, "Ethernet",
3341                                                 append_ethernet, service);
3342                 break;
3343         }
3344
3345         connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service);
3346
3347         connman_dbus_dict_append_dict(dict, "IPv4.Configuration",
3348                                                 append_ipv4config, service);
3349
3350         connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service);
3351
3352         connman_dbus_dict_append_dict(dict, "IPv6.Configuration",
3353                                                 append_ipv6config, service);
3354
3355         connman_dbus_dict_append_array(dict, "Nameservers",
3356                                 DBUS_TYPE_STRING, append_dns, service);
3357
3358         connman_dbus_dict_append_array(dict, "Nameservers.Configuration",
3359                                 DBUS_TYPE_STRING, append_dnsconfig, service);
3360
3361         if (service->state == CONNMAN_SERVICE_STATE_READY ||
3362                         service->state == CONNMAN_SERVICE_STATE_ONLINE)
3363                 list = __connman_timeserver_get_all(service);
3364         else
3365                 list = NULL;
3366
3367         connman_dbus_dict_append_array(dict, "Timeservers",
3368                                 DBUS_TYPE_STRING, append_ts, list);
3369
3370         g_slist_free_full(list, g_free);
3371
3372         connman_dbus_dict_append_array(dict, "Timeservers.Configuration",
3373                                 DBUS_TYPE_STRING, append_tsconfig, service);
3374
3375         connman_dbus_dict_append_array(dict, "Domains",
3376                                 DBUS_TYPE_STRING, append_domain, service);
3377
3378         connman_dbus_dict_append_array(dict, "Domains.Configuration",
3379                                 DBUS_TYPE_STRING, append_domainconfig, service);
3380
3381         connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service);
3382
3383         connman_dbus_dict_append_dict(dict, "Proxy.Configuration",
3384                                                 append_proxyconfig, service);
3385
3386         connman_dbus_dict_append_dict(dict, "Provider",
3387                                                 append_provider, service);
3388 }
3389
3390 static void append_struct_service(DBusMessageIter *iter,
3391                 connman_dbus_append_cb_t function,
3392                 struct connman_service *service)
3393 {
3394         DBusMessageIter entry, dict;
3395
3396         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
3397
3398         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
3399                                                         &service->path);
3400
3401         connman_dbus_dict_open(&entry, &dict);
3402         if (function)
3403                 function(&dict, service);
3404         connman_dbus_dict_close(&entry, &dict);
3405
3406         dbus_message_iter_close_container(iter, &entry);
3407 }
3408
3409 static void append_dict_properties(DBusMessageIter *dict, void *user_data)
3410 {
3411         struct connman_service *service = user_data;
3412
3413         append_properties(dict, TRUE, service);
3414 }
3415
3416 static void append_struct(gpointer value, gpointer user_data)
3417 {
3418         struct connman_service *service = value;
3419         DBusMessageIter *iter = user_data;
3420
3421         if (!service->path)
3422                 return;
3423
3424         append_struct_service(iter, append_dict_properties, service);
3425 }
3426
3427 void __connman_service_list_struct(DBusMessageIter *iter)
3428 {
3429         g_list_foreach(service_list, append_struct, iter);
3430 }
3431
3432 #if defined TIZEN_EXT
3433 static void append_wifi_vsie_properties(DBusMessageIter *iter,
3434                                         struct connman_service *service)
3435 {
3436         DBusMessageIter dict;
3437         const void *wifi_vsie;
3438         unsigned int wifi_vsie_len;
3439
3440         connman_dbus_dict_open(iter, &dict);
3441
3442         wifi_vsie = connman_network_get_blob(service->network, "WiFi.Vsie", &wifi_vsie_len);
3443
3444         if(wifi_vsie_len > 0) {
3445                 DBG("ConnMan, service->path=%s vsie length=%d", service->path, wifi_vsie_len);
3446         }
3447
3448         connman_dbus_dict_append_fixed_array(&dict, "Vsie", DBUS_TYPE_BYTE,
3449                         &wifi_vsie, wifi_vsie_len);
3450
3451         connman_dbus_dict_close(iter, &dict);
3452 }
3453
3454 void __connman_wifi_vsie_list_struct(DBusMessageIter *iter)
3455 {
3456         GList *list;
3457         DBusMessageIter entry;
3458
3459         DBG("ConnMan, __connman_wifi_vsie_list_struct API called");
3460
3461         for (list = service_list; list; list = list->next) {
3462                 struct connman_service *service = list->data;
3463
3464                 if (!service->path ||
3465                                 service->type !=  CONNMAN_SERVICE_TYPE_WIFI ||
3466                                 service->network == NULL)
3467                         continue;
3468
3469                 dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
3470                                 NULL, &entry);
3471                 dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
3472                                 &service->path);
3473                 append_wifi_vsie_properties(&entry, service);
3474                 dbus_message_iter_close_container(iter, &entry);
3475         }
3476 }
3477 #endif
3478
3479 bool __connman_service_is_hidden(struct connman_service *service)
3480 {
3481         return service->hidden;
3482 }
3483
3484 bool
3485 __connman_service_is_split_routing(struct connman_service *service)
3486 {
3487         return service->do_split_routing;
3488 }
3489
3490 bool __connman_service_index_is_split_routing(int index)
3491 {
3492         struct connman_service *service;
3493
3494         if (index < 0)
3495                 return false;
3496
3497         service = __connman_service_lookup_from_index(index);
3498         if (!service)
3499                 return false;
3500
3501         return __connman_service_is_split_routing(service);
3502 }
3503
3504 int __connman_service_get_index(struct connman_service *service)
3505 {
3506         if (!service)
3507                 return -1;
3508
3509         if (service->network)
3510                 return connman_network_get_index(service->network);
3511         else if (service->provider)
3512                 return connman_provider_get_index(service->provider);
3513
3514         return -1;
3515 }
3516
3517 void __connman_service_set_hidden(struct connman_service *service)
3518 {
3519         if (!service || service->hidden)
3520                 return;
3521
3522         service->hidden_service = true;
3523 }
3524
3525 void __connman_service_set_hostname(struct connman_service *service,
3526                                                 const char *hostname)
3527 {
3528         if (!service || service->hidden)
3529                 return;
3530
3531         g_free(service->hostname);
3532         service->hostname = g_strdup(hostname);
3533 }
3534
3535 const char *__connman_service_get_hostname(struct connman_service *service)
3536 {
3537         if (!service)
3538                 return NULL;
3539
3540         return service->hostname;
3541 }
3542
3543 void __connman_service_set_domainname(struct connman_service *service,
3544                                                 const char *domainname)
3545 {
3546         if (!service || service->hidden)
3547                 return;
3548
3549         g_free(service->domainname);
3550         service->domainname = g_strdup(domainname);
3551
3552         domain_changed(service);
3553 }
3554
3555 const char *connman_service_get_domainname(struct connman_service *service)
3556 {
3557         if (!service)
3558                 return NULL;
3559
3560         if (service->domains)
3561                 return service->domains[0];
3562         else
3563                 return service->domainname;
3564 }
3565
3566 char **connman_service_get_nameservers(struct connman_service *service)
3567 {
3568         if (!service)
3569                 return NULL;
3570
3571         if (service->nameservers_config)
3572                 return g_strdupv(service->nameservers_config);
3573         else if (service->nameservers ||
3574                                         service->nameservers_auto) {
3575                 int len = 0, len_auto = 0, i;
3576                 char **nameservers;
3577
3578                 if (service->nameservers)
3579                         len = g_strv_length(service->nameservers);
3580                 if (service->nameservers_auto)
3581                         len_auto = g_strv_length(service->nameservers_auto);
3582
3583                 nameservers = g_try_new0(char *, len + len_auto + 1);
3584                 if (!nameservers)
3585                         return NULL;
3586
3587                 for (i = 0; i < len; i++)
3588                         nameservers[i] = g_strdup(service->nameservers[i]);
3589
3590                 for (i = 0; i < len_auto; i++)
3591                         nameservers[i + len] =
3592                                 g_strdup(service->nameservers_auto[i]);
3593
3594                 return nameservers;
3595         }
3596
3597         return g_strdupv(connman_setting_get_string_list("FallbackNameservers"));
3598 }
3599
3600 char **connman_service_get_timeservers_config(struct connman_service *service)
3601 {
3602         if (!service)
3603                 return NULL;
3604
3605         return service->timeservers_config;
3606 }
3607
3608 char **connman_service_get_timeservers(struct connman_service *service)
3609 {
3610         if (!service)
3611                 return NULL;
3612
3613         return service->timeservers;
3614 }
3615
3616 #if defined TIZEN_EXT
3617 /*
3618  * Description: Telephony plug-in requires manual PROXY setting function
3619  */
3620 int connman_service_set_proxy(struct connman_service *service,
3621                                         const char *proxy, gboolean active)
3622 {
3623         char **proxies_array = NULL;
3624
3625         if (service == NULL)
3626                 return -EINVAL;
3627
3628         switch (service->type) {
3629         case CONNMAN_SERVICE_TYPE_CELLULAR:
3630         case CONNMAN_SERVICE_TYPE_ETHERNET:
3631         case CONNMAN_SERVICE_TYPE_WIFI:
3632                 break;
3633
3634         default:
3635                 return -EINVAL;
3636         }
3637
3638         g_strfreev(service->proxies);
3639         service->proxies = NULL;
3640
3641         if (proxy != NULL)
3642                 proxies_array = g_strsplit(proxy, " ", 0);
3643
3644         service->proxies = proxies_array;
3645
3646         if (proxy == NULL) {
3647                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
3648                 DBG("proxy changed (%d)", active);
3649         } else {
3650                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_MANUAL;
3651                 DBG("proxy chagned %s (%d)", proxy, active);
3652         }
3653
3654         if (active == TRUE) {
3655                 proxy_changed(service);
3656
3657                 __connman_notifier_proxy_changed(service);
3658         }
3659
3660         return 0;
3661 }
3662 #endif
3663
3664 void connman_service_set_proxy_method(struct connman_service *service,
3665                                         enum connman_service_proxy_method method)
3666 {
3667         if (!service || service->hidden)
3668                 return;
3669
3670         service->proxy = method;
3671
3672         proxy_changed(service);
3673
3674         if (method != CONNMAN_SERVICE_PROXY_METHOD_AUTO)
3675                 __connman_notifier_proxy_changed(service);
3676 }
3677
3678 enum connman_service_proxy_method connman_service_get_proxy_method(
3679                                         struct connman_service *service)
3680 {
3681         if (!service)
3682                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
3683
3684         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) {
3685                 if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_AUTO &&
3686                                 !service->pac)
3687                         return service->proxy;
3688
3689                 return service->proxy_config;
3690         }
3691
3692         return service->proxy;
3693 }
3694
3695 char **connman_service_get_proxy_servers(struct connman_service *service)
3696 {
3697         return g_strdupv(service->proxies);
3698 }
3699
3700 char **connman_service_get_proxy_excludes(struct connman_service *service)
3701 {
3702         return g_strdupv(service->excludes);
3703 }
3704
3705 const char *connman_service_get_proxy_url(struct connman_service *service)
3706 {
3707         if (!service)
3708                 return NULL;
3709
3710         return service->pac;
3711 }
3712
3713 void __connman_service_set_proxy_autoconfig(struct connman_service *service,
3714                                                         const char *url)
3715 {
3716         if (!service || service->hidden)
3717                 return;
3718
3719         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_AUTO;
3720
3721         if (service->ipconfig_ipv4) {
3722                 if (__connman_ipconfig_set_proxy_autoconfig(
3723                             service->ipconfig_ipv4, url) < 0)
3724                         return;
3725         } else if (service->ipconfig_ipv6) {
3726                 if (__connman_ipconfig_set_proxy_autoconfig(
3727                             service->ipconfig_ipv6, url) < 0)
3728                         return;
3729         } else
3730                 return;
3731
3732         proxy_changed(service);
3733
3734         __connman_notifier_proxy_changed(service);
3735 }
3736
3737 const char *connman_service_get_proxy_autoconfig(struct connman_service *service)
3738 {
3739         if (!service)
3740                 return NULL;
3741
3742         if (service->ipconfig_ipv4)
3743                 return __connman_ipconfig_get_proxy_autoconfig(
3744                                                 service->ipconfig_ipv4);
3745         else if (service->ipconfig_ipv6)
3746                 return __connman_ipconfig_get_proxy_autoconfig(
3747                                                 service->ipconfig_ipv6);
3748         return NULL;
3749 }
3750
3751 #if defined TIZEN_EXT
3752 int connman_service_get_ipv6_dns_method(struct connman_service *service)
3753 {
3754         if (!service) {
3755                 DBG("Service is NULL");
3756                 return -1;
3757         }
3758
3759         return service->dns_config_method_ipv6;
3760 }
3761 #endif
3762
3763 void __connman_service_set_timeservers(struct connman_service *service,
3764                                 char **timeservers)
3765 {
3766         int i;
3767
3768         if (!service)
3769                 return;
3770
3771         g_strfreev(service->timeservers);
3772         service->timeservers = NULL;
3773
3774         for (i = 0; timeservers && timeservers[i]; i++)
3775                 __connman_service_timeserver_append(service, timeservers[i]);
3776 }
3777
3778 int __connman_service_timeserver_append(struct connman_service *service,
3779                                                 const char *timeserver)
3780 {
3781         int len;
3782
3783         DBG("service %p timeserver %s", service, timeserver);
3784
3785         if (!timeserver)
3786                 return -EINVAL;
3787
3788         if (service->timeservers) {
3789                 int i;
3790
3791                 for (i = 0; service->timeservers[i]; i++)
3792                         if (g_strcmp0(service->timeservers[i], timeserver) == 0)
3793                                 return -EEXIST;
3794
3795                 len = g_strv_length(service->timeservers);
3796                 service->timeservers = g_try_renew(char *, service->timeservers,
3797                                                         len + 2);
3798         } else {
3799                 len = 0;
3800                 service->timeservers = g_try_new0(char *, len + 2);
3801         }
3802
3803         if (!service->timeservers)
3804                 return -ENOMEM;
3805
3806         service->timeservers[len] = g_strdup(timeserver);
3807         service->timeservers[len + 1] = NULL;
3808
3809         return 0;
3810 }
3811
3812 int __connman_service_timeserver_remove(struct connman_service *service,
3813                                                 const char *timeserver)
3814 {
3815         char **servers;
3816         int len, i, j, found = 0;
3817
3818         DBG("service %p timeserver %s", service, timeserver);
3819
3820         if (!timeserver)
3821                 return -EINVAL;
3822
3823         if (!service->timeservers)
3824                 return 0;
3825
3826         for (i = 0; service->timeservers &&
3827                                         service->timeservers[i]; i++)
3828                 if (g_strcmp0(service->timeservers[i], timeserver) == 0) {
3829                         found = 1;
3830                         break;
3831                 }
3832
3833         if (found == 0)
3834                 return 0;
3835
3836         len = g_strv_length(service->timeservers);
3837
3838         if (len == 1) {
3839                 g_strfreev(service->timeservers);
3840                 service->timeservers = NULL;
3841
3842                 return 0;
3843         }
3844
3845         servers = g_try_new0(char *, len);
3846         if (!servers)
3847                 return -ENOMEM;
3848
3849         for (i = 0, j = 0; i < len; i++) {
3850                 if (g_strcmp0(service->timeservers[i], timeserver) != 0) {
3851                         servers[j] = g_strdup(service->timeservers[i]);
3852                         if (!servers[j])
3853                                 return -ENOMEM;
3854                         j++;
3855                 }
3856         }
3857         servers[len - 1] = NULL;
3858
3859         g_strfreev(service->timeservers);
3860         service->timeservers = servers;
3861
3862         return 0;
3863 }
3864
3865 void __connman_service_timeserver_changed(struct connman_service *service,
3866                 GSList *ts_list)
3867 {
3868         if (!service)
3869                 return;
3870
3871         if (!allow_property_changed(service))
3872                 return;
3873
3874         connman_dbus_property_changed_array(service->path,
3875                         CONNMAN_SERVICE_INTERFACE, "Timeservers",
3876                         DBUS_TYPE_STRING, append_ts, ts_list);
3877 }
3878
3879 void __connman_service_set_pac(struct connman_service *service,
3880                                         const char *pac)
3881 {
3882         if (service->hidden)
3883                 return;
3884         g_free(service->pac);
3885         service->pac = g_strdup(pac);
3886
3887         proxy_changed(service);
3888 }
3889
3890 #if defined TIZEN_EXT
3891 void __connman_service_set_proxy(struct connman_service *service,
3892                                        const char *proxies)
3893 {
3894        char **proxies_array = NULL;
3895
3896        g_strfreev(service->proxies);
3897        service->proxies = NULL;
3898
3899        if (proxies != NULL)
3900                proxies_array = g_strsplit(proxies, " ", 0);
3901
3902        service->proxies = proxies_array;
3903 }
3904 #endif
3905
3906 void __connman_service_set_identity(struct connman_service *service,
3907                                         const char *identity)
3908 {
3909         if (service->immutable || service->hidden)
3910                 return;
3911
3912         g_free(service->identity);
3913         service->identity = g_strdup(identity);
3914
3915         if (service->network)
3916                 connman_network_set_string(service->network,
3917                                         "WiFi.Identity",
3918                                         service->identity);
3919 }
3920
3921 void __connman_service_set_agent_identity(struct connman_service *service,
3922                                                 const char *agent_identity)
3923 {
3924         if (service->hidden)
3925                 return;
3926         g_free(service->agent_identity);
3927         service->agent_identity = g_strdup(agent_identity);
3928
3929         if (service->network)
3930                 connman_network_set_string(service->network,
3931                                         "WiFi.AgentIdentity",
3932                                         service->agent_identity);
3933 }
3934
3935 static int check_passphrase(enum connman_service_security security,
3936                 const char *passphrase)
3937 {
3938         guint i;
3939         gsize length;
3940
3941         if (!passphrase)
3942                 return 0;
3943
3944         length = strlen(passphrase);
3945
3946         switch (security) {
3947         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
3948         case CONNMAN_SERVICE_SECURITY_NONE:
3949         case CONNMAN_SERVICE_SECURITY_WPA:
3950 #if !defined TIZEN_EXT
3951         case CONNMAN_SERVICE_SECURITY_RSN:
3952 #endif
3953
3954                 DBG("service security '%s' (%d) not handled",
3955                                 security2string(security), security);
3956
3957                 return -EOPNOTSUPP;
3958
3959         case CONNMAN_SERVICE_SECURITY_PSK:
3960 #if defined TIZEN_EXT
3961         case CONNMAN_SERVICE_SECURITY_RSN:
3962 #endif
3963                 /* A raw key is always 64 bytes length,
3964                  * its content is in hex representation.
3965                  * A PSK key must be between [8..63].
3966                  */
3967                 if (length == 64) {
3968                         for (i = 0; i < 64; i++)
3969                                 if (!isxdigit((unsigned char)
3970                                               passphrase[i]))
3971                                         return -ENOKEY;
3972                 } else if (length < 8 || length > 63)
3973                         return -ENOKEY;
3974                 break;
3975         case CONNMAN_SERVICE_SECURITY_WEP:
3976                 /* length of WEP key is 10 or 26
3977                  * length of WEP passphrase is 5 or 13
3978                  */
3979                 if (length == 10 || length == 26) {
3980                         for (i = 0; i < length; i++)
3981                                 if (!isxdigit((unsigned char)
3982                                               passphrase[i]))
3983                                         return -ENOKEY;
3984                 } else if (length != 5 && length != 13)
3985                         return -ENOKEY;
3986                 break;
3987
3988         case CONNMAN_SERVICE_SECURITY_8021X:
3989                 break;
3990         }
3991
3992         return 0;
3993 }
3994
3995 int __connman_service_set_passphrase(struct connman_service *service,
3996                                         const char *passphrase)
3997 {
3998         int err;
3999
4000         if (service->hidden)
4001                 return -EINVAL;
4002
4003         if (service->immutable &&
4004                         service->security != CONNMAN_SERVICE_SECURITY_8021X)
4005                 return -EINVAL;
4006
4007         err = check_passphrase(service->security, passphrase);
4008
4009         if (err < 0)
4010                 return err;
4011
4012         g_free(service->passphrase);
4013         service->passphrase = g_strdup(passphrase);
4014
4015         if (service->network)
4016                 connman_network_set_string(service->network, "WiFi.Passphrase",
4017                                 service->passphrase);
4018
4019         return 0;
4020 }
4021
4022 const char *__connman_service_get_passphrase(struct connman_service *service)
4023 {
4024         if (!service)
4025                 return NULL;
4026
4027         return service->passphrase;
4028 }
4029
4030 static DBusMessage *get_properties(DBusConnection *conn,
4031                                         DBusMessage *msg, void *user_data)
4032 {
4033         struct connman_service *service = user_data;
4034         DBusMessage *reply;
4035         DBusMessageIter array, dict;
4036
4037         DBG("service %p", service);
4038
4039         reply = dbus_message_new_method_return(msg);
4040         if (!reply)
4041                 return NULL;
4042
4043         dbus_message_iter_init_append(reply, &array);
4044
4045         connman_dbus_dict_open(&array, &dict);
4046         append_properties(&dict, FALSE, service);
4047         connman_dbus_dict_close(&array, &dict);
4048
4049         return reply;
4050 }
4051
4052 static int update_proxy_configuration(struct connman_service *service,
4053                                 DBusMessageIter *array)
4054 {
4055         DBusMessageIter dict;
4056         enum connman_service_proxy_method method;
4057         GString *servers_str = NULL;
4058         GString *excludes_str = NULL;
4059         const char *url = NULL;
4060
4061         method = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
4062
4063         dbus_message_iter_recurse(array, &dict);
4064
4065         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
4066                 DBusMessageIter entry, variant;
4067                 const char *key;
4068                 int type;
4069
4070                 dbus_message_iter_recurse(&dict, &entry);
4071
4072                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
4073                         goto error;
4074
4075                 dbus_message_iter_get_basic(&entry, &key);
4076                 dbus_message_iter_next(&entry);
4077
4078                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
4079                         goto error;
4080
4081                 dbus_message_iter_recurse(&entry, &variant);
4082
4083                 type = dbus_message_iter_get_arg_type(&variant);
4084
4085                 if (g_str_equal(key, "Method")) {
4086                         const char *val;
4087
4088                         if (type != DBUS_TYPE_STRING)
4089                                 goto error;
4090
4091                         dbus_message_iter_get_basic(&variant, &val);
4092                         method = string2proxymethod(val);
4093                 } else if (g_str_equal(key, "URL")) {
4094                         if (type != DBUS_TYPE_STRING)
4095                                 goto error;
4096
4097                         dbus_message_iter_get_basic(&variant, &url);
4098                 } else if (g_str_equal(key, "Servers")) {
4099                         DBusMessageIter str_array;
4100
4101                         if (type != DBUS_TYPE_ARRAY)
4102                                 goto error;
4103
4104                         servers_str = g_string_new(NULL);
4105                         if (!servers_str)
4106                                 goto error;
4107
4108                         dbus_message_iter_recurse(&variant, &str_array);
4109
4110                         while (dbus_message_iter_get_arg_type(&str_array) ==
4111                                                         DBUS_TYPE_STRING) {
4112                                 char *val = NULL;
4113
4114                                 dbus_message_iter_get_basic(&str_array, &val);
4115
4116                                 if (servers_str->len > 0)
4117                                         g_string_append_printf(servers_str,
4118                                                         " %s", val);
4119                                 else
4120                                         g_string_append(servers_str, val);
4121
4122                                 dbus_message_iter_next(&str_array);
4123                         }
4124                 } else if (g_str_equal(key, "Excludes")) {
4125                         DBusMessageIter str_array;
4126
4127                         if (type != DBUS_TYPE_ARRAY)
4128                                 goto error;
4129
4130                         excludes_str = g_string_new(NULL);
4131                         if (!excludes_str)
4132                                 goto error;
4133
4134                         dbus_message_iter_recurse(&variant, &str_array);
4135
4136                         while (dbus_message_iter_get_arg_type(&str_array) ==
4137                                                         DBUS_TYPE_STRING) {
4138                                 char *val = NULL;
4139
4140                                 dbus_message_iter_get_basic(&str_array, &val);
4141
4142                                 if (excludes_str->len > 0)
4143                                         g_string_append_printf(excludes_str,
4144                                                         " %s", val);
4145                                 else
4146                                         g_string_append(excludes_str, val);
4147
4148                                 dbus_message_iter_next(&str_array);
4149                         }
4150                 }
4151
4152                 dbus_message_iter_next(&dict);
4153         }
4154
4155         switch (method) {
4156         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
4157                 break;
4158         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
4159                 if (!servers_str && !service->proxies)
4160                         goto error;
4161
4162                 if (servers_str) {
4163                         g_strfreev(service->proxies);
4164
4165                         if (servers_str->len > 0)
4166                                 service->proxies = g_strsplit_set(
4167                                         servers_str->str, " ", 0);
4168                         else
4169                                 service->proxies = NULL;
4170                 }
4171
4172                 if (excludes_str) {
4173                         g_strfreev(service->excludes);
4174
4175                         if (excludes_str->len > 0)
4176                                 service->excludes = g_strsplit_set(
4177                                         excludes_str->str, " ", 0);
4178                         else
4179                                 service->excludes = NULL;
4180                 }
4181
4182                 if (!service->proxies)
4183                         method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
4184
4185                 break;
4186         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
4187                 g_free(service->pac);
4188
4189                 if (url && strlen(url) > 0)
4190                         service->pac = g_strdup(url);
4191                 else
4192                         service->pac = NULL;
4193
4194                 /* if we are connected:
4195                    - if service->pac == NULL
4196                    - if __connman_ipconfig_get_proxy_autoconfig(
4197                    service->ipconfig) == NULL
4198                    --> We should start WPAD */
4199
4200                 break;
4201         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
4202                 goto error;
4203         }
4204
4205         if (servers_str)
4206                 g_string_free(servers_str, TRUE);
4207
4208         if (excludes_str)
4209                 g_string_free(excludes_str, TRUE);
4210
4211         service->proxy_config = method;
4212
4213         return 0;
4214
4215 error:
4216         if (servers_str)
4217                 g_string_free(servers_str, TRUE);
4218
4219         if (excludes_str)
4220                 g_string_free(excludes_str, TRUE);
4221
4222         return -EINVAL;
4223 }
4224
4225 int __connman_service_reset_ipconfig(struct connman_service *service,
4226                 enum connman_ipconfig_type type, DBusMessageIter *array,
4227                 enum connman_service_state *new_state)
4228 {
4229         struct connman_ipconfig *ipconfig, *new_ipconfig;
4230         enum connman_ipconfig_method old_method, new_method;
4231         enum connman_service_state state;
4232         int err = 0, index;
4233
4234         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
4235                 ipconfig = service->ipconfig_ipv4;
4236                 state = service->state_ipv4;
4237                 new_method = CONNMAN_IPCONFIG_METHOD_DHCP;
4238         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
4239                 ipconfig = service->ipconfig_ipv6;
4240                 state = service->state_ipv6;
4241                 new_method = CONNMAN_IPCONFIG_METHOD_AUTO;
4242         } else
4243                 return -EINVAL;
4244
4245         if (!ipconfig)
4246                 return -ENXIO;
4247
4248         old_method = __connman_ipconfig_get_method(ipconfig);
4249         index = __connman_ipconfig_get_index(ipconfig);
4250
4251         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4252                 new_ipconfig = create_ip4config(service, index,
4253                                 CONNMAN_IPCONFIG_METHOD_UNKNOWN);
4254         else
4255                 new_ipconfig = create_ip6config(service, index);
4256
4257         if (array) {
4258                 err = __connman_ipconfig_set_config(new_ipconfig, array);
4259                 if (err < 0) {
4260                         __connman_ipconfig_unref(new_ipconfig);
4261                         return err;
4262                 }
4263
4264                 new_method = __connman_ipconfig_get_method(new_ipconfig);
4265         }
4266
4267         if (is_connecting_state(service, state) ||
4268                                         is_connected_state(service, state))
4269                 __connman_network_clear_ipconfig(service->network, ipconfig);
4270
4271         __connman_ipconfig_unref(ipconfig);
4272
4273         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4274                 service->ipconfig_ipv4 = new_ipconfig;
4275         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
4276                 service->ipconfig_ipv6 = new_ipconfig;
4277
4278         if (is_connecting_state(service, state) ||
4279                                         is_connected_state(service, state))
4280                 __connman_ipconfig_enable(new_ipconfig);
4281
4282         if (new_state && new_method != old_method) {
4283                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4284                         *new_state = service->state_ipv4;
4285                 else
4286                         *new_state = service->state_ipv6;
4287
4288                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4289         }
4290
4291         DBG("err %d ipconfig %p type %d method %d state %s", err,
4292                 new_ipconfig, type, new_method,
4293                 !new_state  ? "-" : state2string(*new_state));
4294
4295         return err;
4296 }
4297
4298 static DBusMessage *set_property(DBusConnection *conn,
4299                                         DBusMessage *msg, void *user_data)
4300 {
4301         struct connman_service *service = user_data;
4302         DBusMessageIter iter, value;
4303         const char *name;
4304         int type;
4305
4306         DBG("service %p", service);
4307
4308         if (!dbus_message_iter_init(msg, &iter))
4309                 return __connman_error_invalid_arguments(msg);
4310
4311         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
4312                 return __connman_error_invalid_arguments(msg);
4313
4314         if (service->type == CONNMAN_SERVICE_TYPE_WIFI && is_connected(service)) {
4315                 uid_t uid;
4316                 if (connman_dbus_get_connection_unix_user_sync(conn,
4317                                                 dbus_message_get_sender(msg),
4318                                                 &uid) < 0) {
4319                         DBG("Can not get unix user id!");
4320                         return __connman_error_permission_denied(msg);
4321                 }
4322
4323                 if (!connman_service_is_user_allowed(service, uid)) {
4324                         DBG("Not allow this user to operate this wifi service now!");
4325                         return __connman_error_permission_denied(msg);
4326                 }
4327         }
4328
4329         dbus_message_iter_get_basic(&iter, &name);
4330         dbus_message_iter_next(&iter);
4331
4332         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
4333                 return __connman_error_invalid_arguments(msg);
4334
4335         dbus_message_iter_recurse(&iter, &value);
4336
4337         type = dbus_message_iter_get_arg_type(&value);
4338
4339         if (g_str_equal(name, "AutoConnect")) {
4340                 dbus_bool_t autoconnect;
4341
4342                 if (type != DBUS_TYPE_BOOLEAN)
4343                         return __connman_error_invalid_arguments(msg);
4344
4345                 if (!service->favorite)
4346                         return __connman_error_invalid_service(msg);
4347
4348                 dbus_message_iter_get_basic(&value, &autoconnect);
4349
4350                 if (service->autoconnect == autoconnect)
4351                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4352
4353                 service->autoconnect = autoconnect;
4354
4355                 autoconnect_changed(service);
4356
4357                 if (autoconnect)
4358                         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4359
4360                 service_save(service);
4361         } else if (g_str_equal(name, "Nameservers.Configuration")) {
4362                 DBusMessageIter entry;
4363                 GString *str;
4364                 int index;
4365                 const char *gw;
4366 #if defined TIZEN_EXT
4367                 enum connman_ipconfig_type ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4368                 DBG("%s", name);
4369 #endif
4370
4371                 if (__connman_provider_is_immutable(service->provider) ||
4372                                 service->immutable)
4373                         return __connman_error_not_supported(msg);
4374
4375                 if (type != DBUS_TYPE_ARRAY)
4376                         return __connman_error_invalid_arguments(msg);
4377
4378                 str = g_string_new(NULL);
4379                 if (!str)
4380                         return __connman_error_invalid_arguments(msg);
4381
4382                 index = __connman_service_get_index(service);
4383                 gw = __connman_ipconfig_get_gateway_from_index(index,
4384                         CONNMAN_IPCONFIG_TYPE_ALL);
4385
4386                 if (gw && strlen(gw))
4387                         __connman_service_nameserver_del_routes(service,
4388                                                 CONNMAN_IPCONFIG_TYPE_ALL);
4389
4390                 dbus_message_iter_recurse(&value, &entry);
4391
4392 #if defined TIZEN_EXT
4393                 /* IPv4/IPv6 Last DNS config method */
4394                 int last_dns_ipv4 = service->dns_config_method_ipv4;
4395                 int last_dns_ipv6 = service->dns_config_method_ipv6;
4396                 DBG("Last DNS Config Method IPv4: %d IPv6: %d", last_dns_ipv4, last_dns_ipv6);
4397 #endif
4398
4399                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
4400                         const char *val;
4401                         dbus_message_iter_get_basic(&entry, &val);
4402                         dbus_message_iter_next(&entry);
4403 #ifdef TIZEN_EXT
4404                         /* First unpack the DNS Config Method */
4405                         DBG("DNS Config Method: %s", val);
4406                         if((g_strcmp0(val, "ipv4.manual") == 0)) {
4407                                 service->dns_config_method_ipv4 =
4408                                         CONNMAN_DNSCONFIG_METHOD_MANUAL;
4409
4410                                 if(last_dns_ipv4 != CONNMAN_DNSCONFIG_METHOD_MANUAL) {
4411                                         if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN)
4412                                                 ip_type = CONNMAN_IPCONFIG_TYPE_IPV4;
4413                                         else
4414                                                 ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4415                                 }
4416                                 continue;
4417                         } else if(g_strcmp0(val, "ipv4.dhcp") == 0) {
4418                                 service->dns_config_method_ipv4 =
4419                                         CONNMAN_DNSCONFIG_METHOD_DHCP;
4420                                 if(last_dns_ipv4 == CONNMAN_DNSCONFIG_METHOD_MANUAL)
4421                                         ip_type = CONNMAN_IPCONFIG_TYPE_IPV4;
4422
4423                                 continue;
4424                         } else if(g_strcmp0(val, "ipv6.manual") == 0) {
4425                                 service->dns_config_method_ipv6 =
4426                                         CONNMAN_DNSCONFIG_METHOD_MANUAL;
4427                                 if(last_dns_ipv6 != CONNMAN_DNSCONFIG_METHOD_MANUAL) {
4428                                         if(ip_type == CONNMAN_IPCONFIG_TYPE_UNKNOWN)
4429                                                 ip_type = CONNMAN_IPCONFIG_TYPE_IPV6;
4430                                         else
4431                                                 ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4432                                 }
4433                                 continue;
4434                         } else if(g_strcmp0(val, "ipv6.dhcp") == 0) {
4435                                 service->dns_config_method_ipv6 =
4436                                         CONNMAN_DNSCONFIG_METHOD_DHCP;
4437                                 if(last_dns_ipv6 == CONNMAN_DNSCONFIG_METHOD_MANUAL)
4438                                         ip_type = CONNMAN_IPCONFIG_TYPE_IPV6;
4439
4440                                 continue;
4441                         }
4442 #endif
4443                         if (connman_inet_check_ipaddress(val) > 0) {
4444                                 if (str->len > 0)
4445                                         g_string_append_printf(str, " %s", val);
4446                                 else
4447                                         g_string_append(str, val);
4448                         }
4449                 }
4450
4451 #if defined TIZEN_EXT
4452                 if (service->dns_config_method_ipv4 == CONNMAN_DNSCONFIG_METHOD_DHCP &&
4453                         service->dns_config_method_ipv6 == CONNMAN_DNSCONFIG_METHOD_DHCP) {
4454                                         DBG("Both IPv4 and IPv6 DNS Method DHCP");
4455                                         ip_type = CONNMAN_IPCONFIG_TYPE_ALL;
4456                 }
4457                 if (gw && strlen(gw))
4458                         __connman_service_nameserver_del_routes(service,
4459                                                 ip_type);
4460
4461                 DBG("%s ip_type: %d nameserver remove all", name, ip_type);
4462                 nameserver_remove_all(service, ip_type);
4463 #else
4464                 nameserver_remove_all(service);
4465 #endif
4466                 g_strfreev(service->nameservers_config);
4467
4468                 if (str->len > 0) {
4469                         service->nameservers_config =
4470                                 g_strsplit_set(str->str, " ", 0);
4471                 } else {
4472                         service->nameservers_config = NULL;
4473                 }
4474
4475                 g_string_free(str, TRUE);
4476
4477                 if (gw && strlen(gw))
4478                         __connman_service_nameserver_add_routes(service, gw);
4479
4480 #if defined TIZEN_EXT
4481                 DBG("%s ip_type: %d nameserver add all", name, ip_type);
4482                 nameserver_add_all(service, ip_type);
4483 #else
4484                 nameserver_add_all(service);
4485 #endif
4486                 dns_configuration_changed(service);
4487
4488                 if (__connman_service_is_connected_state(service,
4489                                                 CONNMAN_IPCONFIG_TYPE_IPV4))
4490                         __connman_wispr_start(service,
4491                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4492
4493                 if (__connman_service_is_connected_state(service,
4494                                                 CONNMAN_IPCONFIG_TYPE_IPV6))
4495                         __connman_wispr_start(service,
4496                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
4497
4498                 service_save(service);
4499         } else if (g_str_equal(name, "Timeservers.Configuration")) {
4500                 DBusMessageIter entry;
4501                 GSList *list = NULL;
4502                 int count = 0;
4503
4504                 if (service->immutable)
4505                         return __connman_error_not_supported(msg);
4506
4507                 if (type != DBUS_TYPE_ARRAY)
4508                         return __connman_error_invalid_arguments(msg);
4509
4510                 dbus_message_iter_recurse(&value, &entry);
4511
4512                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
4513                         const char *val;
4514                         GSList *new_head;
4515
4516                         dbus_message_iter_get_basic(&entry, &val);
4517
4518                         new_head = __connman_timeserver_add_list(list, val);
4519                         if (list != new_head) {
4520                                 count++;
4521                                 list = new_head;
4522                         }
4523
4524                         dbus_message_iter_next(&entry);
4525                 }
4526
4527                 g_strfreev(service->timeservers_config);
4528                 service->timeservers_config = NULL;
4529
4530                 if (list) {
4531                         service->timeservers_config = g_new0(char *, count+1);
4532
4533                         while (list) {
4534                                 count--;
4535                                 service->timeservers_config[count] = list->data;
4536                                 list = g_slist_delete_link(list, list);
4537                         };
4538                 }
4539
4540                 service_save(service);
4541                 timeservers_configuration_changed(service);
4542
4543                 if (service == __connman_service_get_default())
4544                         __connman_timeserver_sync(service);
4545
4546         } else if (g_str_equal(name, "Domains.Configuration")) {
4547                 DBusMessageIter entry;
4548                 GString *str;
4549
4550                 if (service->immutable)
4551                         return __connman_error_not_supported(msg);
4552
4553                 if (type != DBUS_TYPE_ARRAY)
4554                         return __connman_error_invalid_arguments(msg);
4555
4556                 str = g_string_new(NULL);
4557                 if (!str)
4558                         return __connman_error_invalid_arguments(msg);
4559
4560                 dbus_message_iter_recurse(&value, &entry);
4561
4562                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
4563                         const char *val;
4564                         dbus_message_iter_get_basic(&entry, &val);
4565                         dbus_message_iter_next(&entry);
4566                         if (str->len > 0)
4567                                 g_string_append_printf(str, " %s", val);
4568                         else
4569                                 g_string_append(str, val);
4570                 }
4571
4572                 searchdomain_remove_all(service);
4573                 g_strfreev(service->domains);
4574
4575                 if (str->len > 0)
4576                         service->domains = g_strsplit_set(str->str, " ", 0);
4577                 else
4578                         service->domains = NULL;
4579
4580                 g_string_free(str, TRUE);
4581
4582                 searchdomain_add_all(service);
4583                 domain_configuration_changed(service);
4584                 domain_changed(service);
4585
4586                 service_save(service);
4587         } else if (g_str_equal(name, "Proxy.Configuration")) {
4588                 int err;
4589
4590                 if (service->immutable)
4591                         return __connman_error_not_supported(msg);
4592
4593                 if (type != DBUS_TYPE_ARRAY)
4594                         return __connman_error_invalid_arguments(msg);
4595
4596                 err = update_proxy_configuration(service, &value);
4597
4598                 if (err < 0)
4599                         return __connman_error_failed(msg, -err);
4600
4601                 proxy_configuration_changed(service);
4602
4603                 __connman_notifier_proxy_changed(service);
4604
4605                 service_save(service);
4606         } else if (g_str_equal(name, "IPv4.Configuration") ||
4607                         g_str_equal(name, "IPv6.Configuration")) {
4608
4609                 enum connman_service_state state =
4610                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
4611                 enum connman_ipconfig_type type =
4612                         CONNMAN_IPCONFIG_TYPE_UNKNOWN;
4613                 int err = 0;
4614
4615                 if (service->type == CONNMAN_SERVICE_TYPE_VPN ||
4616                                 service->immutable)
4617                         return __connman_error_not_supported(msg);
4618
4619                 DBG("%s", name);
4620
4621                 if (!service->ipconfig_ipv4 &&
4622                                         !service->ipconfig_ipv6)
4623                         return __connman_error_invalid_property(msg);
4624
4625                 if (g_str_equal(name, "IPv4.Configuration"))
4626                         type = CONNMAN_IPCONFIG_TYPE_IPV4;
4627                 else
4628                         type = CONNMAN_IPCONFIG_TYPE_IPV6;
4629
4630                 err = __connman_service_reset_ipconfig(service, type, &value,
4631                                                                 &state);
4632
4633                 if (err < 0) {
4634                         if (is_connected_state(service, state) ||
4635                                         is_connecting_state(service, state)) {
4636                                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4637                                         __connman_network_enable_ipconfig(service->network,
4638                                                         service->ipconfig_ipv4);
4639                                 else
4640                                         __connman_network_enable_ipconfig(service->network,
4641                                                         service->ipconfig_ipv6);
4642                         }
4643
4644                         return __connman_error_failed(msg, -err);
4645                 }
4646
4647                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4648                         ipv4_configuration_changed(service);
4649                 else
4650                         ipv6_configuration_changed(service);
4651
4652                 if (is_connecting(service) || is_connected(service)) {
4653                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4654                                 __connman_network_enable_ipconfig(service->network,
4655                                                                 service->ipconfig_ipv4);
4656                         else
4657                                 __connman_network_enable_ipconfig(service->network,
4658                                                                 service->ipconfig_ipv6);
4659                 }
4660
4661                 service_save(service);
4662         } else
4663                 return __connman_error_invalid_property(msg);
4664
4665         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4666 }
4667
4668 static void set_error(struct connman_service *service,
4669                                         enum connman_service_error error)
4670 {
4671         const char *str;
4672
4673         if (service->error == error)
4674                 return;
4675
4676         service->error = error;
4677
4678         if (!service->path)
4679                 return;
4680
4681 #if !defined TIZEN_EXT
4682         if (!allow_property_changed(service))
4683                 return;
4684 #endif
4685
4686         str = error2string(service->error);
4687
4688         if (!str)
4689                 str = "";
4690
4691         connman_dbus_property_changed_basic(service->path,
4692                                 CONNMAN_SERVICE_INTERFACE, "Error",
4693                                 DBUS_TYPE_STRING, &str);
4694 }
4695
4696 static void set_idle(struct connman_service *service)
4697 {
4698         service->state = service->state_ipv4 = service->state_ipv6 =
4699                                                 CONNMAN_SERVICE_STATE_IDLE;
4700         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
4701         state_changed(service);
4702 }
4703
4704 static DBusMessage *clear_property(DBusConnection *conn,
4705                                         DBusMessage *msg, void *user_data)
4706 {
4707         struct connman_service *service = user_data;
4708         const char *name;
4709
4710         DBG("service %p", service);
4711
4712         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
4713                                                         DBUS_TYPE_INVALID);
4714
4715         if (g_str_equal(name, "Error")) {
4716                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
4717
4718                 g_get_current_time(&service->modified);
4719                 service_save(service);
4720         } else
4721                 return __connman_error_invalid_property(msg);
4722
4723         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4724 }
4725
4726 static bool is_ipconfig_usable(struct connman_service *service)
4727 {
4728         if (!__connman_ipconfig_is_usable(service->ipconfig_ipv4) &&
4729                         !__connman_ipconfig_is_usable(service->ipconfig_ipv6))
4730                 return false;
4731
4732         return true;
4733 }
4734
4735 static bool is_ignore(struct connman_service *service)
4736 {
4737         if (!service->autoconnect)
4738                 return true;
4739
4740         if (service->roaming)
4741                 return true;
4742
4743         if (service->ignore)
4744                 return true;
4745
4746         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
4747                 return true;
4748
4749         if (!is_ipconfig_usable(service))
4750                 return true;
4751
4752         return false;
4753 }
4754
4755 static void disconnect_on_last_session(enum connman_service_type type)
4756 {
4757         GList *list;
4758
4759         for (list = service_list; list; list = list->next) {
4760                 struct connman_service *service = list->data;
4761
4762                 if (service->type != type)
4763                         continue;
4764
4765                 if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_SESSION)
4766                          continue;
4767
4768                 __connman_service_disconnect(service);
4769                 return;
4770         }
4771 }
4772
4773 static int active_sessions[MAX_CONNMAN_SERVICE_TYPES] = {};
4774 static int active_count = 0;
4775
4776 void __connman_service_set_active_session(bool enable, GSList *list)
4777 {
4778         if (!list)
4779                 return;
4780
4781         if (enable)
4782                 active_count++;
4783         else
4784                 active_count--;
4785
4786         while (list != NULL) {
4787                 enum connman_service_type type = GPOINTER_TO_INT(list->data);
4788
4789                 switch (type) {
4790                 case CONNMAN_SERVICE_TYPE_ETHERNET:
4791                 case CONNMAN_SERVICE_TYPE_WIFI:
4792                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
4793                 case CONNMAN_SERVICE_TYPE_CELLULAR:
4794                 case CONNMAN_SERVICE_TYPE_GADGET:
4795                         if (enable)
4796                                 active_sessions[type]++;
4797                         else
4798                                 active_sessions[type]--;
4799                         break;
4800
4801                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
4802                 case CONNMAN_SERVICE_TYPE_SYSTEM:
4803                 case CONNMAN_SERVICE_TYPE_GPS:
4804                 case CONNMAN_SERVICE_TYPE_VPN:
4805                 case CONNMAN_SERVICE_TYPE_P2P:
4806                         break;
4807                 }
4808
4809                 if (active_sessions[type] == 0)
4810                         disconnect_on_last_session(type);
4811
4812                 list = g_slist_next(list);
4813         }
4814
4815         DBG("eth %d wifi %d bt %d cellular %d gadget %d sessions %d",
4816                         active_sessions[CONNMAN_SERVICE_TYPE_ETHERNET],
4817                         active_sessions[CONNMAN_SERVICE_TYPE_WIFI],
4818                         active_sessions[CONNMAN_SERVICE_TYPE_BLUETOOTH],
4819                         active_sessions[CONNMAN_SERVICE_TYPE_CELLULAR],
4820                         active_sessions[CONNMAN_SERVICE_TYPE_GADGET],
4821                         active_count);
4822 }
4823
4824 struct preferred_tech_data {
4825         GList *preferred_list;
4826         enum connman_service_type type;
4827 };
4828
4829 static void preferred_tech_add_by_type(gpointer data, gpointer user_data)
4830 {
4831         struct connman_service *service = data;
4832         struct preferred_tech_data *tech_data = user_data;
4833
4834         if (service->type == tech_data->type) {
4835                 tech_data->preferred_list =
4836                         g_list_append(tech_data->preferred_list, service);
4837
4838                 DBG("type %d service %p %s", tech_data->type, service,
4839                                 service->name);
4840         }
4841 }
4842
4843 static GList *preferred_tech_list_get(void)
4844 {
4845         unsigned int *tech_array;
4846         struct preferred_tech_data tech_data = { 0, };
4847         int i;
4848
4849         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
4850         if (!tech_array)
4851                 return NULL;
4852
4853         if (connman_setting_get_bool("SingleConnectedTechnology")) {
4854                 GList *list;
4855                 for (list = service_list; list; list = list->next) {
4856                         struct connman_service *service = list->data;
4857
4858                         if (!is_connected(service))
4859                                 break;
4860
4861                         if (service->connect_reason ==
4862                                         CONNMAN_SERVICE_CONNECT_REASON_USER) {
4863                                 DBG("service %p name %s is user connected",
4864                                                 service, service->name);
4865 #if defined TIZEN_EXT
4866                                 /* We can connect to a favorite service like
4867                                  * wifi even we have a userconnect for cellular
4868                                  * because we have refount for cellular service
4869                                  */
4870                                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
4871                                         break;
4872
4873                                 if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
4874                                         break;
4875 #endif
4876                                 return NULL;
4877                         }
4878                 }
4879         }
4880
4881         for (i = 0; tech_array[i] != 0; i += 1) {
4882                 tech_data.type = tech_array[i];
4883                 g_list_foreach(service_list, preferred_tech_add_by_type,
4884                                 &tech_data);
4885         }
4886
4887         return tech_data.preferred_list;
4888 }
4889
4890 static bool auto_connect_service(GList *services,
4891                                 enum connman_service_connect_reason reason,
4892                                 bool preferred)
4893 {
4894         struct connman_service *service = NULL;
4895         bool ignore[MAX_CONNMAN_SERVICE_TYPES] = { };
4896         bool autoconnecting = false;
4897         GList *list;
4898
4899         DBG("preferred %d sessions %d reason %s", preferred, active_count,
4900                 reason2string(reason));
4901
4902         ignore[CONNMAN_SERVICE_TYPE_VPN] = true;
4903
4904         for (list = services; list; list = list->next) {
4905                 service = list->data;
4906
4907                 if (ignore[service->type]) {
4908                         DBG("service %p type %s ignore", service,
4909                                 __connman_service_type2string(service->type));
4910                         continue;
4911                 }
4912
4913 #if defined TIZEN_EXT
4914                 DBG("service %p %s %s %s, favorite(%d), ignore(%d), hidden(%d, %d)",
4915                                 service, service->name,
4916                                 state2string(service->state),
4917                                 __connman_service_type2string(service->type),
4918                                 service->favorite, is_ignore(service),
4919                                 service->hidden, service->hidden_service);
4920
4921                 /* Tizen takes Wi-Fi as the highest priority into consideration. */
4922                 if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
4923                         if (is_connecting(service) == TRUE || is_connected(service) == TRUE)
4924                                 continue;
4925 #endif
4926
4927                 if (service->pending ||
4928                                 is_connecting(service) ||
4929                                 is_connected(service)) {
4930                         if (!active_count)
4931                                 return true;
4932
4933                         ignore[service->type] = true;
4934                         autoconnecting = true;
4935
4936                         DBG("service %p type %s busy", service,
4937                                 __connman_service_type2string(service->type));
4938
4939                         continue;
4940                 }
4941
4942                 if (!service->favorite) {
4943                         if (preferred)
4944                                continue;
4945
4946 #if defined TIZEN_EXT
4947                         DBG("Service is not favorite, autoconnecting %d",
4948                                         autoconnecting);
4949 #endif
4950                         return autoconnecting;
4951                 }
4952
4953 #if defined TIZEN_EXT
4954                 DBG("service %p identifier %s roaming %d ignore %d "
4955                                 "ipconfig_usable %d autoconnect %d state %d",
4956                                 service,
4957                                 service->identifier, service->roaming,
4958                                 service->ignore, is_ipconfig_usable(service),
4959                                 service->autoconnect, service->state);
4960 #endif
4961                 if (is_ignore(service) || service->state !=
4962                                 CONNMAN_SERVICE_STATE_IDLE)
4963                         continue;
4964
4965                 if (autoconnecting && !active_sessions[service->type]) {
4966                         DBG("service %p type %s has no users", service,
4967                                 __connman_service_type2string(service->type));
4968                         continue;
4969                 }
4970
4971                 if (!is_service_owner_user_login(service)) {
4972                         DBG("favorite user not login, wifi auto connect denied");
4973                         continue;
4974                 }
4975
4976                 DBG("service %p %s %s", service, service->name,
4977                         (preferred) ? "preferred" : reason2string(reason));
4978
4979                 __connman_service_connect(service, reason);
4980
4981                 if (!active_count)
4982                         return true;
4983
4984                 ignore[service->type] = true;
4985         }
4986
4987         return autoconnecting;
4988 }
4989
4990 static gboolean run_auto_connect(gpointer data)
4991 {
4992         enum connman_service_connect_reason reason = GPOINTER_TO_UINT(data);
4993         bool autoconnecting = false;
4994         GList *preferred_tech;
4995
4996         autoconnect_timeout = 0;
4997
4998         DBG("");
4999
5000         preferred_tech = preferred_tech_list_get();
5001         if (preferred_tech) {
5002                 autoconnecting = auto_connect_service(preferred_tech, reason,
5003                                                         true);
5004                 g_list_free(preferred_tech);
5005         }
5006
5007         if (!autoconnecting || active_count)
5008                 auto_connect_service(service_list, reason, false);
5009
5010         return FALSE;
5011 }
5012
5013 #if defined TIZEN_EXT
5014 bool __connman_service_get_auto_connect_mode(void)
5015 {
5016         return auto_connect_mode;
5017 }
5018
5019 void __connman_service_set_auto_connect_mode(bool enable)
5020 {
5021         DBG("set auto_connect_mode = %d", enable);
5022
5023         if (auto_connect_mode != enable)
5024                 auto_connect_mode = enable;
5025 }
5026 #endif
5027
5028 void __connman_service_auto_connect(enum connman_service_connect_reason reason)
5029 {
5030         DBG("");
5031
5032         if (autoconnect_timeout != 0)
5033                 return;
5034
5035 #if defined TIZEN_EXT
5036         if (auto_connect_mode == FALSE) {
5037                 DBG("Currently, not auto connection mode");
5038                 return;
5039         }
5040 #endif
5041
5042         if (!__connman_session_policy_autoconnect(reason))
5043                 return;
5044
5045 #if defined TIZEN_EXT
5046         /* Adding Timeout of 500ms before trying to auto connect.
5047          * This is done because of below scenario
5048          * 1. Device is connected to AP1
5049          * 2. WPS Connection request is initiated for AP2
5050          * 3. Immediately WPS Connection is Cancelled
5051          * When WPS Connection Connection is initiated for AP2 then
5052          * sometimes there is a scenario where connman gets in ASSOCIATED
5053          * state with AP1 due to autoconnect and subsequently the connection
5054          * initiated by AP1 fails and connman service for AP1 comes in
5055          * FAILURE state due to this when connection with AP2 is cancelled
5056          * then autoconnect with AP1 doesn't works because its autoconnection
5057          * is ignored as its last state was FAILURE rather than IDLE */
5058         autoconnect_timeout = g_timeout_add(500, run_auto_connect,
5059 #else
5060         autoconnect_timeout = g_timeout_add_seconds(0, run_auto_connect,
5061 #endif
5062                                                 GUINT_TO_POINTER(reason));
5063 }
5064
5065 static gboolean run_vpn_auto_connect(gpointer data) {
5066         GList *list;
5067         bool need_split = false;
5068
5069         vpn_autoconnect_timeout = 0;
5070
5071         for (list = service_list; list; list = list->next) {
5072                 struct connman_service *service = list->data;
5073                 int res;
5074
5075                 if (service->type != CONNMAN_SERVICE_TYPE_VPN)
5076                         continue;
5077
5078                 if (is_connected(service) || is_connecting(service)) {
5079                         if (!service->do_split_routing)
5080                                 need_split = true;
5081                         continue;
5082                 }
5083
5084                 if (is_ignore(service) || !service->favorite)
5085                         continue;
5086
5087                 if (need_split && !service->do_split_routing) {
5088                         DBG("service %p no split routing", service);
5089                         continue;
5090                 }
5091
5092                 DBG("service %p %s %s", service, service->name,
5093                                 service->do_split_routing ?
5094                                 "split routing" : "");
5095
5096                 res = __connman_service_connect(service,
5097                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
5098                 if (res < 0 && res != -EINPROGRESS)
5099                         continue;
5100
5101                 if (!service->do_split_routing)
5102                         need_split = true;
5103         }
5104
5105         return FALSE;
5106 }
5107
5108 static void vpn_auto_connect(void)
5109 {
5110         if (vpn_autoconnect_timeout)
5111                 return;
5112
5113         vpn_autoconnect_timeout =
5114                 g_timeout_add_seconds(0, run_vpn_auto_connect, NULL);
5115 }
5116
5117 static void remove_timeout(struct connman_service *service)
5118 {
5119         if (service->timeout > 0) {
5120                 g_source_remove(service->timeout);
5121                 service->timeout = 0;
5122         }
5123 }
5124
5125 static void reply_pending(struct connman_service *service, int error)
5126 {
5127         remove_timeout(service);
5128
5129         if (service->pending) {
5130                 connman_dbus_reply_pending(service->pending, error, NULL);
5131                 service->pending = NULL;
5132         }
5133
5134         if (service->provider_pending) {
5135                 connman_dbus_reply_pending(service->provider_pending,
5136                                                 error, service->path);
5137                 service->provider_pending = NULL;
5138         }
5139 }
5140
5141 bool
5142 __connman_service_is_provider_pending(struct connman_service *service)
5143 {
5144         if (!service)
5145                 return false;
5146
5147         if (service->provider_pending)
5148                 return true;
5149
5150         return false;
5151 }
5152
5153 void __connman_service_set_provider_pending(struct connman_service *service,
5154                                                         DBusMessage *msg)
5155 {
5156         if (service->provider_pending) {
5157                 DBG("service %p provider pending msg %p already exists",
5158                         service, service->provider_pending);
5159                 return;
5160         }
5161
5162         service->provider_pending = msg;
5163         return;
5164 }
5165
5166 static void check_pending_msg(struct connman_service *service)
5167 {
5168         if (!service->pending)
5169                 return;
5170
5171         DBG("service %p pending msg %p already exists", service,
5172                                                 service->pending);
5173         dbus_message_unref(service->pending);
5174 }
5175
5176 void __connman_service_set_hidden_data(struct connman_service *service,
5177                                                         gpointer user_data)
5178 {
5179         DBusMessage *pending = user_data;
5180
5181         DBG("service %p pending %p", service, pending);
5182
5183         if (!pending)
5184                 return;
5185
5186         check_pending_msg(service);
5187
5188         service->pending = pending;
5189 }
5190
5191 void __connman_service_return_error(struct connman_service *service,
5192                                 int error, gpointer user_data)
5193 {
5194         DBG("service %p error %d user_data %p", service, error, user_data);
5195
5196         __connman_service_set_hidden_data(service, user_data);
5197
5198         reply_pending(service, error);
5199 }
5200
5201 static gboolean connect_timeout(gpointer user_data)
5202 {
5203         struct connman_service *service = user_data;
5204         bool autoconnect = false;
5205
5206         DBG("service %p", service);
5207
5208         service->timeout = 0;
5209
5210         if (service->network)
5211                 __connman_network_disconnect(service->network);
5212         else if (service->provider)
5213                 connman_provider_disconnect(service->provider);
5214
5215         __connman_ipconfig_disable(service->ipconfig_ipv4);
5216         __connman_ipconfig_disable(service->ipconfig_ipv6);
5217
5218         __connman_stats_service_unregister(service);
5219
5220         if (service->pending) {
5221                 DBusMessage *reply;
5222
5223                 reply = __connman_error_operation_timeout(service->pending);
5224                 if (reply)
5225                         g_dbus_send_message(connection, reply);
5226
5227                 dbus_message_unref(service->pending);
5228                 service->pending = NULL;
5229         } else
5230                 autoconnect = true;
5231
5232         __connman_service_ipconfig_indicate_state(service,
5233                                         CONNMAN_SERVICE_STATE_FAILURE,
5234                                         CONNMAN_IPCONFIG_TYPE_IPV4);
5235         __connman_service_ipconfig_indicate_state(service,
5236                                         CONNMAN_SERVICE_STATE_FAILURE,
5237                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5238
5239         if (autoconnect &&
5240                         service->connect_reason !=
5241                                 CONNMAN_SERVICE_CONNECT_REASON_USER)
5242                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
5243
5244         return FALSE;
5245 }
5246
5247 static DBusMessage *connect_service(DBusConnection *conn,
5248                                         DBusMessage *msg, void *user_data)
5249 {
5250         struct connman_service *service = user_data;
5251 #if defined TIZEN_EXT
5252         int err = 0;
5253 #else
5254         int index, err = 0;
5255         GList *list;
5256 #endif
5257
5258         DBG("service %p", service);
5259
5260 #if defined TIZEN_EXT
5261         /*
5262          * Description: TIZEN implements system global connection management.
5263          */
5264         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5265                 connman_service_user_pdn_connection_ref(service);
5266
5267         /*Reset the Disconnect Reason while issue connect request*/
5268         service->disconnect_reason = 0;
5269 #endif
5270
5271         if (service->pending)
5272                 return __connman_error_in_progress(msg);
5273
5274         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
5275                 uid_t uid;
5276                 if (connman_dbus_get_connection_unix_user_sync(conn,
5277                                                 dbus_message_get_sender(msg),
5278                                                 &uid) < 0) {
5279                         DBG("Can not get unix user id!");
5280                         return __connman_error_permission_denied(msg);
5281                 }
5282
5283                 if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
5284                         DBG("Not allow this user to connect this wifi service now!");
5285                         return __connman_error_permission_denied(msg);
5286                 }
5287
5288                 if (uid != USER_ROOT && uid != service->user.favorite_user)
5289                         service->request_passphrase_input = true;
5290
5291                 service->user.current_user = uid;
5292
5293                 if (!service->passphrase && uid == service->user.favorite_user) {
5294                         DBG("Now load this favorite user's passphrase.");
5295                         service_load_passphrase(service);
5296                 }
5297         }
5298
5299 #if !defined TIZEN_EXT
5300         index = __connman_service_get_index(service);
5301
5302         for (list = service_list; list; list = list->next) {
5303                 struct connman_service *temp = list->data;
5304
5305 #if defined TIZEN_EXT
5306                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5307                         break;
5308 #endif
5309                 if (!is_connecting(temp) && !is_connected(temp))
5310                         break;
5311
5312                 if (service == temp)
5313                         continue;
5314
5315                 if (service->type != temp->type)
5316                         continue;
5317
5318                 if (__connman_service_get_index(temp) == index &&
5319                                 __connman_service_disconnect(temp) == -EINPROGRESS)
5320                         err = -EINPROGRESS;
5321
5322         }
5323         if (err == -EINPROGRESS)
5324                 return __connman_error_operation_timeout(msg);
5325 #endif
5326
5327         service->ignore = false;
5328
5329         service->pending = dbus_message_ref(msg);
5330
5331         err = __connman_service_connect(service,
5332                         CONNMAN_SERVICE_CONNECT_REASON_USER);
5333
5334         if (err == -EINPROGRESS)
5335                 return NULL;
5336
5337         if (service->pending) {
5338                 dbus_message_unref(service->pending);
5339                 service->pending = NULL;
5340         }
5341
5342         if (err < 0)
5343                 return __connman_error_failed(msg, -err);
5344
5345         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5346 }
5347
5348 static DBusMessage *disconnect_service(DBusConnection *conn,
5349                                         DBusMessage *msg, void *user_data)
5350 {
5351         struct connman_service *service = user_data;
5352         int err;
5353
5354         DBG("service %p", service);
5355
5356 #if defined TIZEN_EXT
5357         /*
5358          * Description: TIZEN implements system global connection management.
5359          */
5360         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
5361                 if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE)
5362                         return __connman_error_failed(msg, EISCONN);
5363
5364                 if (is_connected(service) == TRUE &&
5365                                 service == connman_service_get_default_connection())
5366                         return __connman_error_failed(msg, EISCONN);
5367         }
5368 #endif
5369
5370         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
5371                 uid_t uid;
5372                 if (connman_dbus_get_connection_unix_user_sync(conn,
5373                                                 dbus_message_get_sender(msg),
5374                                                 &uid) < 0) {
5375                         DBG("Can not get unix user id!");
5376                         return __connman_error_permission_denied(msg);
5377                 }
5378
5379                 if (!connman_service_is_user_allowed(service, uid)) {
5380                         DBG("Not allow this user to disconnect this wifi service now!");
5381                         return __connman_error_permission_denied(msg);
5382                 }
5383         }
5384
5385         service->ignore = true;
5386
5387         err = __connman_service_disconnect(service);
5388         if (err < 0 && err != -EINPROGRESS)
5389                 return __connman_error_failed(msg, -err);
5390
5391         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5392 }
5393
5394 #if defined TIZEN_EXT
5395 static void __connman_service_cleanup_network_8021x(struct connman_service *service)
5396 {
5397         if (service == NULL)
5398                 return;
5399
5400         DBG("service %p ", service);
5401
5402         connman_network_set_string(service->network, "WiFi.EAP", NULL);
5403         connman_network_set_string(service->network, "WiFi.Identity", NULL);
5404         connman_network_set_string(service->network, "WiFi.CACertFile", NULL);
5405         connman_network_set_string(service->network, "WiFi.ClientCertFile", NULL);
5406         connman_network_set_string(service->network, "WiFi.PrivateKeyFile", NULL);
5407         connman_network_set_string(service->network, "WiFi.PrivateKeyPassphrase", NULL);
5408         connman_network_set_string(service->network, "WiFi.Phase2", NULL);
5409 }
5410 #endif
5411
5412 bool __connman_service_remove(struct connman_service *service)
5413 {
5414         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET ||
5415                         service->type == CONNMAN_SERVICE_TYPE_GADGET)
5416                 return false;
5417
5418         if (service->immutable || service->hidden ||
5419                         __connman_provider_is_immutable(service->provider))
5420                 return false;
5421
5422 #if !defined TIZEN_EXT
5423         if (!service->favorite && service->state !=
5424                                                 CONNMAN_SERVICE_STATE_FAILURE)
5425                 return false;
5426 #endif
5427
5428         __connman_service_disconnect(service);
5429
5430         g_free(service->passphrase);
5431         service->passphrase = NULL;
5432
5433         g_free(service->identity);
5434         service->identity = NULL;
5435
5436         g_free(service->agent_identity);
5437         service->agent_identity = NULL;
5438
5439         g_free(service->eap);
5440         service->eap = NULL;
5441
5442 #if defined TIZEN_EXT
5443         g_free(service->ca_cert_file);
5444         service->ca_cert_file = NULL;
5445
5446         g_free(service->client_cert_file);
5447         service->client_cert_file = NULL;
5448
5449         g_free(service->private_key_file);
5450         service->private_key_file = NULL;
5451
5452         g_free(service->private_key_passphrase);
5453         service->private_key_passphrase = NULL;
5454
5455         g_free(service->phase2);
5456         service->phase2 = NULL;
5457
5458         __connman_service_cleanup_network_8021x(service);
5459
5460         __connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP);
5461         __connman_ipconfig_set_method(service->ipconfig_ipv6, CONNMAN_IPCONFIG_METHOD_AUTO);
5462         connman_service_set_proxy(service, NULL, false);
5463
5464         __connman_service_nameserver_clear(service);
5465
5466         g_strfreev(service->nameservers_config);
5467         service->nameservers_config = NULL;
5468
5469 #endif
5470
5471 #if defined TIZEN_EXT
5472         if (service->security != CONNMAN_SERVICE_SECURITY_8021X)
5473 #endif
5474         set_idle(service);
5475
5476         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
5477
5478         service->user.favorite_user = USER_NONE;
5479
5480         __connman_service_set_favorite(service, false);
5481
5482         __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
5483
5484 #if defined TIZEN_EXT
5485         /* Reset IP Method and DNS Method to DHCP */
5486         __connman_ipconfig_set_method(service->ipconfig_ipv4,
5487                         CONNMAN_IPCONFIG_METHOD_DHCP);
5488         service->dns_config_method_ipv4 = CONNMAN_DNSCONFIG_METHOD_DHCP;
5489         g_strfreev(service->nameservers_config);
5490         service->nameservers_config = NULL;
5491 #endif
5492
5493 #if defined TIZEN_EXT
5494         __connman_storage_remove_service(service->identifier);
5495 #else
5496         service_save(service);
5497 #endif
5498
5499         return true;
5500 }
5501
5502 static DBusMessage *remove_service(DBusConnection *conn,
5503                                         DBusMessage *msg, void *user_data)
5504 {
5505         struct connman_service *service = user_data;
5506
5507         DBG("service %p", service);
5508
5509         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
5510                 uid_t uid;
5511                 if (connman_dbus_get_connection_unix_user_sync(conn,
5512                                                 dbus_message_get_sender(msg),
5513                                                 &uid) < 0) {
5514                         DBG("Can not get unix user id!");
5515                         return __connman_error_permission_denied(msg);
5516                 }
5517
5518 #if !defined TIZEN_EXT
5519                 if (!connman_service_is_user_allowed(service, uid)) {
5520                         DBG("Not allow this user to remove this wifi service now!");
5521                         return __connman_error_permission_denied(msg);
5522                 }
5523 #endif
5524         }
5525
5526         if (!__connman_service_remove(service))
5527                 return __connman_error_not_supported(msg);
5528
5529         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5530 }
5531
5532 static bool check_suitable_state(enum connman_service_state a,
5533                                         enum connman_service_state b)
5534 {
5535         /*
5536          * Special check so that "ready" service can be moved before
5537          * "online" one.
5538          */
5539         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
5540                         b == CONNMAN_SERVICE_STATE_READY) ||
5541                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
5542                         a == CONNMAN_SERVICE_STATE_READY))
5543                 return true;
5544
5545         return a == b;
5546 }
5547
5548 static void downgrade_state(struct connman_service *service)
5549 {
5550         if (!service)
5551                 return;
5552
5553         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
5554                                                 service->state_ipv6);
5555
5556         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
5557                 __connman_service_ipconfig_indicate_state(service,
5558                                                 CONNMAN_SERVICE_STATE_READY,
5559                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
5560
5561         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
5562                 __connman_service_ipconfig_indicate_state(service,
5563                                                 CONNMAN_SERVICE_STATE_READY,
5564                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5565 }
5566
5567 static void apply_relevant_default_downgrade(struct connman_service *service)
5568 {
5569         struct connman_service *def_service;
5570
5571         def_service = __connman_service_get_default();
5572         if (!def_service)
5573                 return;
5574
5575         if (def_service == service &&
5576                         def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
5577                 def_service->state = CONNMAN_SERVICE_STATE_READY;
5578                 __connman_notifier_leave_online(def_service->type);
5579                 state_changed(def_service);
5580         }
5581 }
5582
5583 static void switch_default_service(struct connman_service *default_service,
5584                 struct connman_service *downgrade_service)
5585 {
5586         struct connman_service *service;
5587         GList *src, *dst;
5588
5589         apply_relevant_default_downgrade(default_service);
5590         src = g_list_find(service_list, downgrade_service);
5591         dst = g_list_find(service_list, default_service);
5592
5593         /* Nothing to do */
5594         if (src == dst || src->next == dst)
5595                 return;
5596
5597         service = src->data;
5598         service_list = g_list_delete_link(service_list, src);
5599         service_list = g_list_insert_before(service_list, dst, service);
5600
5601         downgrade_state(downgrade_service);
5602 }
5603
5604 static DBusMessage *move_service(DBusConnection *conn,
5605                                         DBusMessage *msg, void *user_data,
5606                                                                 bool before)
5607 {
5608         struct connman_service *service = user_data;
5609         struct connman_service *target;
5610         const char *path;
5611         enum connman_ipconfig_method target4, target6;
5612         enum connman_ipconfig_method service4, service6;
5613
5614         DBG("service %p", service);
5615
5616         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
5617                                                         DBUS_TYPE_INVALID);
5618
5619         if (!service->favorite)
5620                 return __connman_error_not_supported(msg);
5621
5622         target = find_service(path);
5623         if (!target || !target->favorite || target == service)
5624                 return __connman_error_invalid_service(msg);
5625
5626         if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
5627                 /*
5628                  * We only allow VPN route splitting if there are
5629                  * routes defined for a given VPN.
5630                  */
5631                 if (!__connman_provider_check_routes(target->provider)) {
5632                         connman_info("Cannot move service. "
5633                                 "No routes defined for provider %s",
5634                                 __connman_provider_get_ident(target->provider));
5635                         return __connman_error_invalid_service(msg);
5636                 }
5637
5638                 target->do_split_routing = true;
5639         } else
5640                 target->do_split_routing = false;
5641
5642         service->do_split_routing = false;
5643
5644         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
5645         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
5646         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
5647         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
5648
5649         DBG("target %s method %d/%d state %d/%d split %d", target->identifier,
5650                 target4, target6, target->state_ipv4, target->state_ipv6,
5651                 target->do_split_routing);
5652
5653         DBG("service %s method %d/%d state %d/%d", service->identifier,
5654                                 service4, service6,
5655                                 service->state_ipv4, service->state_ipv6);
5656
5657         /*
5658          * If method is OFF, then we do not need to check the corresponding
5659          * ipconfig state.
5660          */
5661         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5662                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5663                         if (!check_suitable_state(target->state_ipv6,
5664                                                         service->state_ipv6))
5665                                 return __connman_error_invalid_service(msg);
5666                 }
5667         }
5668
5669         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5670                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5671                         if (!check_suitable_state(target->state_ipv4,
5672                                                         service->state_ipv4))
5673                                 return __connman_error_invalid_service(msg);
5674                 }
5675         }
5676
5677         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5678                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5679                         if (!check_suitable_state(target->state_ipv6,
5680                                                         service->state_ipv6))
5681                                 return __connman_error_invalid_service(msg);
5682                 }
5683         }
5684
5685         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5686                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5687                         if (!check_suitable_state(target->state_ipv4,
5688                                                         service->state_ipv4))
5689                                 return __connman_error_invalid_service(msg);
5690                 }
5691         }
5692
5693         g_get_current_time(&service->modified);
5694         service_save(service);
5695         service_save(target);
5696
5697         /*
5698          * If the service which goes down is the default service and is
5699          * online, we downgrade directly its state to ready so:
5700          * the service which goes up, needs to recompute its state which
5701          * is triggered via downgrading it - if relevant - to state ready.
5702          */
5703         if (before)
5704                 switch_default_service(target, service);
5705         else
5706                 switch_default_service(service, target);
5707
5708         __connman_connection_update_gateway();
5709
5710         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5711 }
5712
5713 static DBusMessage *move_before(DBusConnection *conn,
5714                                         DBusMessage *msg, void *user_data)
5715 {
5716         return move_service(conn, msg, user_data, true);
5717 }
5718
5719 static DBusMessage *move_after(DBusConnection *conn,
5720                                         DBusMessage *msg, void *user_data)
5721 {
5722         return move_service(conn, msg, user_data, false);
5723 }
5724
5725 static DBusMessage *reset_counters(DBusConnection *conn,
5726                                         DBusMessage *msg, void *user_data)
5727 {
5728         struct connman_service *service = user_data;
5729
5730         reset_stats(service);
5731
5732         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5733 }
5734
5735 static DBusMessage *get_user_favorite(DBusConnection *conn,
5736                                         DBusMessage *msg, void *user_data)
5737 {
5738         DBusMessage *reply;
5739         uid_t uid = USER_NONE;
5740         dbus_bool_t user_favorite = false;
5741         struct connman_service *service = user_data;
5742
5743         connman_dbus_get_connection_unix_user_sync(conn,
5744                                         dbus_message_get_sender(msg),
5745                                         &uid);
5746         if (uid == USER_ROOT)
5747                 user_favorite = service->favorite;
5748         else if (uid != USER_NONE && uid == service->user.favorite_user) {
5749                 DBG("The service is favorite to this user!");
5750                 user_favorite = true;
5751         }
5752
5753         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5754         dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,
5755                                 &user_favorite, DBUS_TYPE_INVALID);
5756         return reply;
5757 }
5758
5759 static struct _services_notify {
5760         int id;
5761         GHashTable *add;
5762         GHashTable *remove;
5763 } *services_notify;
5764
5765 static void service_append_added_foreach(gpointer data, gpointer user_data)
5766 {
5767         struct connman_service *service = data;
5768         DBusMessageIter *iter = user_data;
5769
5770         if (!service || !service->path) {
5771 #if !defined TIZEN_EXT
5772                 DBG("service %p or path is NULL", service);
5773 #endif
5774                 return;
5775         }
5776
5777         if (g_hash_table_lookup(services_notify->add, service->path)) {
5778 #if !defined TIZEN_EXT
5779                 DBG("new %s", service->path);
5780 #endif
5781
5782                 append_struct(service, iter);
5783                 g_hash_table_remove(services_notify->add, service->path);
5784         } else {
5785 #if !defined TIZEN_EXT
5786                 DBG("changed %s", service->path);
5787 #endif
5788
5789                 append_struct_service(iter, NULL, service);
5790         }
5791 }
5792
5793 static void service_append_ordered(DBusMessageIter *iter, void *user_data)
5794 {
5795         g_list_foreach(service_list, service_append_added_foreach, iter);
5796 }
5797
5798 static void append_removed(gpointer key, gpointer value, gpointer user_data)
5799 {
5800         char *objpath = key;
5801         DBusMessageIter *iter = user_data;
5802
5803         DBG("removed %s", objpath);
5804         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
5805 }
5806
5807 static void service_append_removed(DBusMessageIter *iter, void *user_data)
5808 {
5809         g_hash_table_foreach(services_notify->remove, append_removed, iter);
5810 }
5811
5812 static gboolean service_send_changed(gpointer data)
5813 {
5814         DBusMessage *signal;
5815
5816         DBG("");
5817
5818         services_notify->id = 0;
5819
5820         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
5821                         CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
5822         if (!signal)
5823                 return FALSE;
5824
5825         __connman_dbus_append_objpath_dict_array(signal,
5826                                         service_append_ordered, NULL);
5827         __connman_dbus_append_objpath_array(signal,
5828                                         service_append_removed, NULL);
5829
5830         dbus_connection_send(connection, signal, NULL);
5831         dbus_message_unref(signal);
5832
5833         g_hash_table_remove_all(services_notify->remove);
5834         g_hash_table_remove_all(services_notify->add);
5835
5836         return FALSE;
5837 }
5838
5839 static void service_schedule_changed(void)
5840 {
5841         if (services_notify->id != 0)
5842                 return;
5843
5844         services_notify->id = g_timeout_add(100, service_send_changed, NULL);
5845 }
5846
5847 static void service_schedule_added(struct connman_service *service)
5848 {
5849         DBG("service %p", service);
5850
5851         g_hash_table_remove(services_notify->remove, service->path);
5852         g_hash_table_replace(services_notify->add, service->path, service);
5853
5854         service_schedule_changed();
5855 }
5856
5857 static void service_schedule_removed(struct connman_service *service)
5858 {
5859         if (!service || !service->path) {
5860                 DBG("service %p or path is NULL", service);
5861                 return;
5862         }
5863
5864         DBG("service %p %s", service, service->path);
5865
5866         g_hash_table_remove(services_notify->add, service->path);
5867         g_hash_table_replace(services_notify->remove, g_strdup(service->path),
5868                         NULL);
5869
5870         service_schedule_changed();
5871 }
5872
5873 static bool allow_property_changed(struct connman_service *service)
5874 {
5875 #if defined TIZEN_EXT
5876         if (service->path == NULL)
5877                 return FALSE;
5878 #endif
5879         if (g_hash_table_lookup_extended(services_notify->add, service->path,
5880                                         NULL, NULL)) {
5881                 DBG("no property updates for service %p", service);
5882                 return false;
5883         }
5884
5885         return true;
5886 }
5887
5888 static const GDBusMethodTable service_methods[] = {
5889         { GDBUS_DEPRECATED_METHOD("GetProperties",
5890                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
5891                         get_properties) },
5892         { GDBUS_METHOD("SetProperty",
5893                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
5894                         NULL, set_property) },
5895         { GDBUS_METHOD("ClearProperty",
5896                         GDBUS_ARGS({ "name", "s" }), NULL,
5897                         clear_property) },
5898         { GDBUS_ASYNC_METHOD("Connect", NULL, NULL,
5899                               connect_service) },
5900         { GDBUS_METHOD("Disconnect", NULL, NULL,
5901                         disconnect_service) },
5902         { GDBUS_METHOD("Remove", NULL, NULL, remove_service) },
5903         { GDBUS_METHOD("MoveBefore",
5904                         GDBUS_ARGS({ "service", "o" }), NULL,
5905                         move_before) },
5906         { GDBUS_METHOD("MoveAfter",
5907                         GDBUS_ARGS({ "service", "o" }), NULL,
5908                         move_after) },
5909         { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
5910         { GDBUS_METHOD("GetUserFavorite",
5911                         NULL, GDBUS_ARGS({ "value", "v" }),
5912                         get_user_favorite) },
5913         { },
5914 };
5915
5916 static const GDBusSignalTable service_signals[] = {
5917         { GDBUS_SIGNAL("PropertyChanged",
5918                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
5919         { },
5920 };
5921
5922 static void service_free(gpointer user_data)
5923 {
5924         struct connman_service *service = user_data;
5925         char *path = service->path;
5926
5927         DBG("service %p", service);
5928
5929         reply_pending(service, ENOENT);
5930
5931         __connman_notifier_service_remove(service);
5932         service_schedule_removed(service);
5933
5934         __connman_wispr_stop(service);
5935         stats_stop(service);
5936
5937         service->path = NULL;
5938
5939         if (path) {
5940                 __connman_connection_update_gateway();
5941
5942                 g_dbus_unregister_interface(connection, path,
5943                                                 CONNMAN_SERVICE_INTERFACE);
5944                 g_free(path);
5945         }
5946
5947         g_hash_table_destroy(service->counter_table);
5948
5949         if (service->network) {
5950                 __connman_network_disconnect(service->network);
5951                 connman_network_unref(service->network);
5952                 service->network = NULL;
5953         }
5954
5955         if (service->provider)
5956                 connman_provider_unref(service->provider);
5957
5958         if (service->ipconfig_ipv4) {
5959                 __connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
5960                 __connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
5961                 __connman_ipconfig_unref(service->ipconfig_ipv4);
5962                 service->ipconfig_ipv4 = NULL;
5963         }
5964
5965         if (service->ipconfig_ipv6) {
5966                 __connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
5967                 __connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
5968                 __connman_ipconfig_unref(service->ipconfig_ipv6);
5969                 service->ipconfig_ipv6 = NULL;
5970         }
5971
5972         g_strfreev(service->timeservers);
5973         g_strfreev(service->timeservers_config);
5974         g_strfreev(service->nameservers);
5975         g_strfreev(service->nameservers_config);
5976         g_strfreev(service->nameservers_auto);
5977         g_strfreev(service->domains);
5978         g_strfreev(service->proxies);
5979         g_strfreev(service->excludes);
5980
5981         g_free(service->hostname);
5982         g_free(service->domainname);
5983         g_free(service->pac);
5984         g_free(service->name);
5985         g_free(service->passphrase);
5986         g_free(service->identifier);
5987         g_free(service->eap);
5988         g_free(service->identity);
5989         g_free(service->agent_identity);
5990         g_free(service->ca_cert_file);
5991         g_free(service->client_cert_file);
5992         g_free(service->private_key_file);
5993         g_free(service->private_key_passphrase);
5994         g_free(service->phase2);
5995         g_free(service->config_file);
5996         g_free(service->config_entry);
5997
5998         if (service->stats.timer)
5999                 g_timer_destroy(service->stats.timer);
6000         if (service->stats_roaming.timer)
6001                 g_timer_destroy(service->stats_roaming.timer);
6002
6003         if (current_default == service)
6004                 current_default = NULL;
6005
6006         g_free(service);
6007 }
6008
6009 static void stats_init(struct connman_service *service)
6010 {
6011         /* home */
6012         service->stats.valid = false;
6013         service->stats.enabled = false;
6014         service->stats.timer = g_timer_new();
6015
6016         /* roaming */
6017         service->stats_roaming.valid = false;
6018         service->stats_roaming.enabled = false;
6019         service->stats_roaming.timer = g_timer_new();
6020 }
6021
6022 static void service_initialize(struct connman_service *service)
6023 {
6024         DBG("service %p", service);
6025
6026         service->refcount = 1;
6027
6028         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
6029
6030         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
6031         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
6032
6033         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
6034         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
6035         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
6036
6037         service->favorite  = false;
6038         service->immutable = false;
6039         service->hidden = false;
6040
6041         service->ignore = false;
6042
6043         service->user.favorite_user = USER_NONE;
6044         service->user.current_user = USER_NONE;
6045
6046         service->request_passphrase_input = false;
6047
6048         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
6049
6050         service->order = 0;
6051
6052         stats_init(service);
6053
6054         service->provider = NULL;
6055
6056         service->wps = false;
6057 #if defined TIZEN_EXT
6058         service->storage_reload = false;
6059         /*
6060          * Description: TIZEN implements system global connection management.
6061          */
6062         service->user_pdn_connection_refcount = 0;
6063         __sync_synchronize();
6064 #endif
6065 }
6066
6067 /**
6068  * connman_service_create:
6069  *
6070  * Allocate a new service.
6071  *
6072  * Returns: a newly-allocated #connman_service structure
6073  */
6074 struct connman_service *connman_service_create(void)
6075 {
6076         GSList *list;
6077         struct connman_stats_counter *counters;
6078         const char *counter;
6079
6080         struct connman_service *service;
6081
6082         service = g_try_new0(struct connman_service, 1);
6083         if (!service)
6084                 return NULL;
6085
6086         DBG("service %p", service);
6087
6088         service->counter_table = g_hash_table_new_full(g_str_hash,
6089                                                 g_str_equal, NULL, g_free);
6090
6091         for (list = counter_list; list; list = list->next) {
6092                 counter = list->data;
6093
6094                 counters = g_try_new0(struct connman_stats_counter, 1);
6095                 if (!counters) {
6096                         g_hash_table_destroy(service->counter_table);
6097                         g_free(service);
6098                         return NULL;
6099                 }
6100
6101                 counters->append_all = true;
6102
6103                 g_hash_table_replace(service->counter_table, (gpointer)counter,
6104                                 counters);
6105         }
6106
6107         service_initialize(service);
6108
6109         return service;
6110 }
6111
6112 /**
6113  * connman_service_ref:
6114  * @service: service structure
6115  *
6116  * Increase reference counter of service
6117  */
6118 struct connman_service *
6119 connman_service_ref_debug(struct connman_service *service,
6120                         const char *file, int line, const char *caller)
6121 {
6122         DBG("%p ref %d by %s:%d:%s()", service, service->refcount + 1,
6123                 file, line, caller);
6124
6125         __sync_fetch_and_add(&service->refcount, 1);
6126
6127         return service;
6128 }
6129
6130 /**
6131  * connman_service_unref:
6132  * @service: service structure
6133  *
6134  * Decrease reference counter of service and release service if no
6135  * longer needed.
6136  */
6137 void connman_service_unref_debug(struct connman_service *service,
6138                         const char *file, int line, const char *caller)
6139 {
6140         DBG("%p ref %d by %s:%d:%s()", service, service->refcount - 1,
6141                 file, line, caller);
6142
6143         if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
6144                 return;
6145
6146         service_list = g_list_remove(service_list, service);
6147
6148         __connman_service_disconnect(service);
6149
6150         g_hash_table_remove(service_hash, service->identifier);
6151 }
6152
6153 static gint service_compare(gconstpointer a, gconstpointer b)
6154 {
6155         struct connman_service *service_a = (void *) a;
6156         struct connman_service *service_b = (void *) b;
6157         enum connman_service_state state_a, state_b;
6158         bool a_connected, b_connected;
6159         gint strength;
6160
6161         state_a = service_a->state;
6162         state_b = service_b->state;
6163         a_connected = is_connected(service_a);
6164         b_connected = is_connected(service_b);
6165
6166         if (a_connected && b_connected) {
6167                 if (service_a->order > service_b->order)
6168                         return -1;
6169
6170                 if (service_a->order < service_b->order)
6171                         return 1;
6172         }
6173
6174         if (state_a != state_b) {
6175                 if (a_connected && b_connected) {
6176                         /* We prefer online over ready state */
6177                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
6178                                 return -1;
6179
6180                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
6181                                 return 1;
6182                 }
6183
6184                 if (a_connected)
6185                         return -1;
6186                 if (b_connected)
6187                         return 1;
6188
6189                 if (is_connecting(service_a))
6190                         return -1;
6191                 if (is_connecting(service_b))
6192                         return 1;
6193         }
6194
6195         if (service_a->favorite && !service_b->favorite)
6196                 return -1;
6197
6198         if (!service_a->favorite && service_b->favorite)
6199                 return 1;
6200
6201         if (service_a->type != service_b->type) {
6202
6203                 if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
6204                         return -1;
6205                 if (service_b->type == CONNMAN_SERVICE_TYPE_ETHERNET)
6206                         return 1;
6207
6208                 if (service_a->type == CONNMAN_SERVICE_TYPE_WIFI)
6209                         return -1;
6210                 if (service_b->type == CONNMAN_SERVICE_TYPE_WIFI)
6211                         return 1;
6212
6213                 if (service_a->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6214                         return -1;
6215                 if (service_b->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6216                         return 1;
6217
6218                 if (service_a->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
6219                         return -1;
6220                 if (service_b->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
6221                         return 1;
6222
6223                 if (service_a->type == CONNMAN_SERVICE_TYPE_VPN)
6224                         return -1;
6225                 if (service_b->type == CONNMAN_SERVICE_TYPE_VPN)
6226                         return 1;
6227
6228                 if (service_a->type == CONNMAN_SERVICE_TYPE_GADGET)
6229                         return -1;
6230                 if (service_b->type == CONNMAN_SERVICE_TYPE_GADGET)
6231                         return 1;
6232         }
6233
6234         strength = (gint) service_b->strength - (gint) service_a->strength;
6235         if (strength)
6236                 return strength;
6237
6238         return g_strcmp0(service_a->name, service_b->name);
6239 }
6240
6241 static void service_list_sort(void)
6242 {
6243         if (service_list && service_list->next) {
6244                 service_list = g_list_sort(service_list, service_compare);
6245                 service_schedule_changed();
6246         }
6247 }
6248
6249 /**
6250  * connman_service_get_type:
6251  * @service: service structure
6252  *
6253  * Get the type of service
6254  */
6255 enum connman_service_type connman_service_get_type(struct connman_service *service)
6256 {
6257         if (!service)
6258                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
6259
6260         return service->type;
6261 }
6262
6263 /**
6264  * connman_service_get_interface:
6265  * @service: service structure
6266  *
6267  * Get network interface of service
6268  */
6269 char *connman_service_get_interface(struct connman_service *service)
6270 {
6271         int index;
6272
6273         if (!service)
6274                 return NULL;
6275
6276         index = __connman_service_get_index(service);
6277
6278         return connman_inet_ifname(index);
6279 }
6280
6281 /**
6282  * __connman_service_is_user_allowed:
6283  * @type: service type
6284  * @uid: user id
6285  *
6286  * Check a user is allowed to operate a type of service
6287  */
6288 bool __connman_service_is_user_allowed(enum connman_service_type type,
6289                                         uid_t uid)
6290 {
6291         GList *list;
6292         uid_t owner_user = USER_NONE;
6293
6294         for (list = service_list; list; list = list->next) {
6295                 struct connman_service *service = list->data;
6296
6297                 if (service->type != type)
6298                         continue;
6299
6300                 if (is_connected(service)) {
6301                         owner_user = service->user.favorite_user;
6302                         break;
6303                 }
6304         }
6305
6306         if (uid == USER_NONE ||
6307                         (uid != USER_ROOT &&
6308                         owner_user != USER_NONE &&
6309                         owner_user != uid))
6310                 return false;
6311
6312         return true;
6313 }
6314
6315 /**
6316  * connman_service_get_network:
6317  * @service: service structure
6318  *
6319  * Get the service network
6320  */
6321 struct connman_network *
6322 __connman_service_get_network(struct connman_service *service)
6323 {
6324         if (!service)
6325                 return NULL;
6326
6327         return service->network;
6328 }
6329
6330 struct connman_ipconfig *
6331 __connman_service_get_ip4config(struct connman_service *service)
6332 {
6333         if (!service)
6334                 return NULL;
6335
6336         return service->ipconfig_ipv4;
6337 }
6338
6339 struct connman_ipconfig *
6340 __connman_service_get_ip6config(struct connman_service *service)
6341 {
6342         if (!service)
6343                 return NULL;
6344
6345         return service->ipconfig_ipv6;
6346 }
6347
6348 struct connman_ipconfig *
6349 __connman_service_get_ipconfig(struct connman_service *service, int family)
6350 {
6351         if (family == AF_INET)
6352                 return __connman_service_get_ip4config(service);
6353         else if (family == AF_INET6)
6354                 return __connman_service_get_ip6config(service);
6355         else
6356                 return NULL;
6357
6358 }
6359
6360 bool __connman_service_is_connected_state(struct connman_service *service,
6361                                         enum connman_ipconfig_type type)
6362 {
6363         if (!service)
6364                 return false;
6365
6366         switch (type) {
6367         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
6368                 break;
6369         case CONNMAN_IPCONFIG_TYPE_IPV4:
6370                 return is_connected_state(service, service->state_ipv4);
6371         case CONNMAN_IPCONFIG_TYPE_IPV6:
6372                 return is_connected_state(service, service->state_ipv6);
6373         case CONNMAN_IPCONFIG_TYPE_ALL:
6374                 return is_connected_state(service,
6375                                         CONNMAN_IPCONFIG_TYPE_IPV4) &&
6376                         is_connected_state(service,
6377                                         CONNMAN_IPCONFIG_TYPE_IPV6);
6378         }
6379
6380         return false;
6381 }
6382 enum connman_service_security __connman_service_get_security(
6383                                 struct connman_service *service)
6384 {
6385         if (!service)
6386                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
6387
6388         return service->security;
6389 }
6390
6391 const char *__connman_service_get_phase2(struct connman_service *service)
6392 {
6393         if (!service)
6394                 return NULL;
6395
6396         return service->phase2;
6397 }
6398
6399 bool __connman_service_wps_enabled(struct connman_service *service)
6400 {
6401         if (!service)
6402                 return false;
6403
6404         return service->wps;
6405 }
6406
6407 void __connman_service_mark_dirty(void)
6408 {
6409         services_dirty = true;
6410 }
6411
6412 #if defined TIZEN_EXT
6413 /**
6414   * Returns profile count if there is any connected profiles
6415   * that use same interface
6416   */
6417 int __connman_service_get_connected_count_of_iface(
6418                                         struct connman_service *service)
6419 {
6420         GList *list;
6421         int count = 0;
6422         int index1 = 0;
6423         int index2 = 0;
6424
6425         DBG("");
6426
6427         index1 = __connman_service_get_index(service);
6428
6429         if (index1 <= 0)
6430                 return 0;
6431
6432         for (list = service_list; list; list = list->next) {
6433                 struct connman_service *service2 = list->data;
6434
6435                 if (service == service2)
6436                         continue;
6437
6438                 index2 = __connman_service_get_index(service2);
6439
6440                 if (is_connected(service2) && index2 > 0 && index1 == index2)
6441                         count++;
6442
6443                 index2 = 0;
6444         }
6445
6446         DBG("Interface index %d, count %d", index1, count);
6447
6448         return count;
6449 }
6450
6451 void __connman_service_set_storage_reload(struct connman_service *service,
6452                                         bool storage_reload)
6453 {
6454         if (service != NULL)
6455                 service->storage_reload = storage_reload;
6456 }
6457 #endif
6458
6459 /**
6460  * __connman_service_set_favorite_delayed:
6461  * @service: service structure
6462  * @favorite: favorite value
6463  * @delay_ordering: do not order service sequence
6464  *
6465  * Change the favorite setting of service
6466  */
6467 int __connman_service_set_favorite_delayed(struct connman_service *service,
6468                                         bool favorite,
6469                                         bool delay_ordering)
6470 {
6471 #if defined TIZEN_EXT
6472         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6473                 return -EIO;
6474 #endif
6475         if (service->hidden)
6476                 return -EOPNOTSUPP;
6477
6478         if (service->favorite == favorite)
6479                 return -EALREADY;
6480
6481         service->favorite = favorite;
6482
6483         if (!delay_ordering)
6484                 __connman_service_get_order(service);
6485
6486         favorite_changed(service);
6487
6488         if (!delay_ordering) {
6489
6490                 service_list_sort();
6491
6492                 __connman_connection_update_gateway();
6493         }
6494
6495         return 0;
6496 }
6497
6498 /**
6499  * __connman_service_set_favorite:
6500  * @service: service structure
6501  * @favorite: favorite value
6502  *
6503  * Change the favorite setting of service
6504  */
6505 int __connman_service_set_favorite(struct connman_service *service,
6506                                                 bool favorite)
6507 {
6508         return __connman_service_set_favorite_delayed(service, favorite,
6509                                                         false);
6510 }
6511
6512 bool connman_service_get_favorite(struct connman_service *service)
6513 {
6514         return service->favorite;
6515 }
6516
6517 bool connman_service_get_autoconnect(struct connman_service *service)
6518 {
6519         return service->autoconnect;
6520 }
6521
6522 int __connman_service_set_immutable(struct connman_service *service,
6523                                                 bool immutable)
6524 {
6525         if (service->hidden)
6526                 return -EOPNOTSUPP;
6527
6528         if (service->immutable == immutable)
6529                 return 0;
6530
6531         service->immutable = immutable;
6532
6533         immutable_changed(service);
6534
6535         return 0;
6536 }
6537
6538 int __connman_service_set_ignore(struct connman_service *service,
6539                                                 bool ignore)
6540 {
6541         if (!service)
6542                 return -EINVAL;
6543
6544         service->ignore = ignore;
6545
6546         return 0;
6547 }
6548
6549 void __connman_service_set_string(struct connman_service *service,
6550                                   const char *key, const char *value)
6551 {
6552         if (service->hidden)
6553                 return;
6554         if (g_str_equal(key, "EAP")) {
6555                 g_free(service->eap);
6556                 service->eap = g_strdup(value);
6557         } else if (g_str_equal(key, "Identity")) {
6558                 g_free(service->identity);
6559                 service->identity = g_strdup(value);
6560         } else if (g_str_equal(key, "CACertFile")) {
6561                 g_free(service->ca_cert_file);
6562                 service->ca_cert_file = g_strdup(value);
6563         } else if (g_str_equal(key, "ClientCertFile")) {
6564                 g_free(service->client_cert_file);
6565                 service->client_cert_file = g_strdup(value);
6566         } else if (g_str_equal(key, "PrivateKeyFile")) {
6567                 g_free(service->private_key_file);
6568                 service->private_key_file = g_strdup(value);
6569         } else if (g_str_equal(key, "PrivateKeyPassphrase")) {
6570                 g_free(service->private_key_passphrase);
6571                 service->private_key_passphrase = g_strdup(value);
6572         } else if (g_str_equal(key, "Phase2")) {
6573                 g_free(service->phase2);
6574                 service->phase2 = g_strdup(value);
6575         } else if (g_str_equal(key, "Passphrase"))
6576                 __connman_service_set_passphrase(service, value);
6577 }
6578
6579 void __connman_service_set_search_domains(struct connman_service *service,
6580                                         char **domains)
6581 {
6582         searchdomain_remove_all(service);
6583
6584         if (service->domains)
6585                 g_strfreev(service->domains);
6586
6587         service->domains = g_strdupv(domains);
6588
6589         searchdomain_add_all(service);
6590 }
6591
6592 static void service_complete(struct connman_service *service)
6593 {
6594         reply_pending(service, EIO);
6595
6596         if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
6597                 __connman_service_auto_connect(service->connect_reason);
6598
6599         g_get_current_time(&service->modified);
6600         service_save(service);
6601 }
6602
6603 static void report_error_cb(void *user_context, bool retry,
6604                                                         void *user_data)
6605 {
6606         struct connman_service *service = user_context;
6607
6608         if (retry)
6609                 __connman_service_connect(service,
6610                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6611         else {
6612                 /* It is not relevant to stay on Failure state
6613                  * when failing is due to wrong user input */
6614                 __connman_service_clear_error(service);
6615 #if defined TIZEN_EXT
6616                 /* Reseting the state back in case of failure state */
6617                 service->state_ipv4 = service->state_ipv6 =
6618                                 CONNMAN_SERVICE_STATE_IDLE;
6619
6620                 if (service->error != CONNMAN_SERVICE_ERROR_AUTH_FAILED)
6621                         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6622 #endif
6623                 service_complete(service);
6624                 __connman_connection_update_gateway();
6625         }
6626 }
6627
6628 static int check_wpspin(struct connman_service *service, const char *wpspin)
6629 {
6630         int length;
6631         guint i;
6632
6633         if (!wpspin)
6634                 return 0;
6635
6636         length = strlen(wpspin);
6637
6638         /* If 0, it will mean user wants to use PBC method */
6639         if (length == 0) {
6640                 connman_network_set_string(service->network,
6641                                                         "WiFi.PinWPS", NULL);
6642                 return 0;
6643         }
6644
6645         /* A WPS PIN is always 8 chars length,
6646          * its content is in digit representation.
6647          */
6648         if (length != 8)
6649                 return -ENOKEY;
6650
6651         for (i = 0; i < 8; i++)
6652                 if (!isdigit((unsigned char) wpspin[i]))
6653                         return -ENOKEY;
6654
6655         connman_network_set_string(service->network, "WiFi.PinWPS", wpspin);
6656
6657         return 0;
6658 }
6659
6660 static void request_input_cb(struct connman_service *service,
6661                         bool values_received,
6662                         const char *name, int name_len,
6663                         const char *identity, const char *passphrase,
6664                         bool wps, const char *wpspin,
6665                         const char *error, void *user_data)
6666 {
6667         struct connman_device *device;
6668         const char *security;
6669         int err = 0;
6670
6671         DBG("RequestInput return, %p", service);
6672
6673         if (error) {
6674                 DBG("error: %s", error);
6675
6676                 if (g_strcmp0(error,
6677                                 "net.connman.Agent.Error.Canceled") == 0) {
6678                         err = -EINVAL;
6679
6680                         if (service->hidden)
6681                                 __connman_service_return_error(service,
6682                                                         ECANCELED, user_data);
6683                         goto done;
6684                 } else {
6685                         if (service->hidden)
6686                                 __connman_service_return_error(service,
6687                                                         ETIMEDOUT, user_data);
6688                 }
6689         }
6690
6691         if (service->hidden && name_len > 0 && name_len <= 32) {
6692                 device = connman_network_get_device(service->network);
6693                 security = connman_network_get_string(service->network,
6694                                                         "WiFi.Security");
6695                 err = __connman_device_request_hidden_scan(device,
6696                                                 name, name_len,
6697                                                 identity, passphrase,
6698                                                 security, user_data);
6699                 if (err < 0)
6700                         __connman_service_return_error(service, -err,
6701                                                         user_data);
6702         }
6703
6704         if (!values_received || service->hidden) {
6705                 err = -EINVAL;
6706                 goto done;
6707         }
6708
6709         if (wps && service->network) {
6710                 err = check_wpspin(service, wpspin);
6711                 if (err < 0)
6712                         goto done;
6713
6714                 connman_network_set_bool(service->network, "WiFi.UseWPS", wps);
6715         }
6716
6717         if (identity)
6718                 __connman_service_set_agent_identity(service, identity);
6719
6720         if (passphrase)
6721                 err = __connman_service_set_passphrase(service, passphrase);
6722
6723  done:
6724         if (err >= 0) {
6725                 /* We forget any previous error. */
6726                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6727
6728                 __connman_service_connect(service,
6729                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6730
6731         } else if (err == -ENOKEY) {
6732                 __connman_service_indicate_error(service,
6733                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
6734         } else {
6735                 /* It is not relevant to stay on Failure state
6736                  * when failing is due to wrong user input */
6737                 service->state = CONNMAN_SERVICE_STATE_IDLE;
6738
6739                 if (!service->hidden) {
6740                         /*
6741                          * If there was a real error when requesting
6742                          * hidden scan, then that error is returned already
6743                          * to the user somewhere above so do not try to
6744                          * do this again.
6745                          */
6746                         __connman_service_return_error(service, -err,
6747                                                         user_data);
6748                 }
6749
6750                 service_complete(service);
6751                 __connman_connection_update_gateway();
6752         }
6753 }
6754
6755 static void downgrade_connected_services(void)
6756 {
6757         struct connman_service *up_service;
6758         GList *list;
6759
6760         for (list = service_list; list; list = list->next) {
6761                 up_service = list->data;
6762
6763                 if (!is_connected(up_service))
6764                         continue;
6765
6766                 if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
6767                         return;
6768
6769                 downgrade_state(up_service);
6770         }
6771 }
6772
6773 static int service_update_preferred_order(struct connman_service *default_service,
6774                 struct connman_service *new_service,
6775                 enum connman_service_state new_state)
6776 {
6777         unsigned int *tech_array;
6778         int i;
6779
6780         if (!default_service || default_service == new_service ||
6781                         default_service->state != new_state)
6782                 return 0;
6783
6784         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
6785         if (tech_array) {
6786
6787                 for (i = 0; tech_array[i] != 0; i += 1) {
6788                         if (default_service->type == tech_array[i])
6789                                 return -EALREADY;
6790
6791                         if (new_service->type == tech_array[i]) {
6792                                 switch_default_service(default_service,
6793                                                 new_service);
6794                                 __connman_connection_update_gateway();
6795                                 return 0;
6796                         }
6797                 }
6798         }
6799
6800         return -EALREADY;
6801 }
6802
6803 #if defined TIZEN_EXT
6804 static gboolean __connman_service_can_drop(struct connman_service *service)
6805 {
6806         if (is_connected(service) == TRUE || is_connecting(service) == TRUE) {
6807                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
6808                         return TRUE;
6809                 else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE)
6810                         return TRUE;
6811         }
6812         return FALSE;
6813 }
6814
6815 static struct connman_device *default_connecting_device = NULL;
6816
6817 static void __connman_service_disconnect_default(struct connman_service *service)
6818 {
6819         struct connman_device *default_device = NULL;
6820
6821         if (default_connecting_device == NULL)
6822                 return;
6823
6824         default_device = connman_network_get_device(
6825                         __connman_service_get_network(service));
6826
6827         DBG("Disconnecting service %p %s", service, service->path);
6828         DBG("Disconnecting device %p %p %s",
6829                         default_connecting_device,
6830                         default_device,
6831                         connman_device_get_string(default_device, "Name"));
6832
6833         if (default_connecting_device == default_device)
6834                 default_connecting_device = NULL;
6835 }
6836
6837 static void __connman_service_connect_default(struct connman_service *current)
6838 {
6839         int err;
6840         GList *list;
6841         bool default_internet;
6842         struct connman_service *service;
6843         struct connman_service *default_service = NULL;
6844         struct connman_device *default_device = NULL;
6845
6846         if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
6847                 switch (current->state) {
6848                 case CONNMAN_SERVICE_STATE_UNKNOWN:
6849                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
6850                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
6851                         return;
6852                 default:
6853                         break;
6854                 }
6855
6856                 if (default_connecting_device &&
6857                                 __connman_service_is_internet_profile(current) == TRUE) {
6858                         if (current->network == NULL)
6859                                 return;
6860
6861                         default_device = connman_network_get_device(current->network);
6862                         if (default_connecting_device == default_device) {
6863                                 DBG("Cellular service[%s]  %p %s",
6864                                                 state2string(current->state), current, current->path);
6865                                 DBG("Cellular device %p %p %s",
6866                                                 default_connecting_device, default_device,
6867                                                 connman_device_get_string(default_device, "Name"));
6868
6869                                 default_connecting_device = NULL;
6870                         }
6871                 }
6872
6873                 return;
6874         } else if (is_connected(current) == TRUE || is_connecting(current) == TRUE)
6875                 return;
6876
6877         /* Always-on: keep default cellular connection as possible */
6878         for (list = service_list; list; list = list->next) {
6879                 service = list->data;
6880
6881                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6882                                 __connman_service_is_internet_profile(service) != TRUE ||
6883                                 service->network == NULL) {
6884                         continue;
6885                 }
6886
6887                 default_internet =
6888                                 connman_network_get_bool(service->network, "DefaultInternet");
6889
6890                 DBG("service: %p %s %s %s (default: %d)", service, service->name,
6891                                 __connman_service_type2string(service->type),
6892                                 state2string(service->state), default_internet);
6893
6894                 if (default_internet) {
6895                         default_service = service;
6896                         if (is_connected(default_service) == TRUE ||
6897                                         is_connecting(default_service) == TRUE)
6898                                 return;
6899
6900                         default_device = connman_network_get_device(default_service->network);
6901                         if (default_connecting_device == default_device) {
6902                                 DBG("Device is connecting (%p)", default_connecting_device);
6903                                 return;
6904                         }
6905
6906                         default_connecting_device = default_device;
6907                         default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
6908
6909                         err = __connman_network_connect(default_service->network);
6910                         DBG("Connecting default service %p %s [%d]",
6911                                         default_service, default_service->path, err);
6912                         DBG("Connecting device %p %s", default_connecting_device,
6913                                         connman_device_get_string(default_connecting_device, "Name"));
6914                         if (err < 0 && err != -EINPROGRESS) {
6915                                 default_connecting_device = NULL;
6916                         } else
6917                                 break;
6918                 }
6919         }
6920 }
6921 #endif
6922
6923 static void single_connected_tech(struct connman_service *allowed)
6924 {
6925         struct connman_service *service;
6926         GSList *services = NULL, *list;
6927         GList *iter;
6928
6929         DBG("keeping %p %s", allowed, allowed->path);
6930
6931 #if defined TIZEN_EXT
6932         if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6933                 return;
6934 #endif
6935
6936         for (iter = service_list; iter; iter = iter->next) {
6937                 service = iter->data;
6938
6939 #if defined TIZEN_EXT
6940                 if (service != allowed && service->type != allowed->type &&
6941                                 __connman_service_can_drop(service) == TRUE)
6942 #else
6943                 if (!is_connected(service))
6944                         break;
6945
6946                 if (service == allowed)
6947                         continue;
6948 #endif
6949                 services = g_slist_prepend(services, service);
6950         }
6951
6952         for (list = services; list; list = list->next) {
6953                 service = list->data;
6954
6955                 DBG("disconnecting %p %s", service, service->path);
6956 #if defined TIZEN_EXT
6957                 __connman_service_disconnect_default(service);
6958 #endif
6959                 __connman_service_disconnect(service);
6960         }
6961
6962         g_slist_free(services);
6963 }
6964
6965 #if defined TIZEN_EXT
6966 static void set_priority_connected_service(void)
6967 {
6968         struct connman_service *service;
6969         GList *list;
6970
6971         for (list = service_list; list; list = list->next) {
6972                 service = list->data;
6973
6974                 if (is_connected(service) == FALSE)
6975                         service->order = 5;
6976                 else
6977                         service->order = 6;
6978         }
6979 }
6980 #endif
6981
6982 static const char *get_dbus_sender(struct connman_service *service)
6983 {
6984         if (!service->pending)
6985                 return NULL;
6986
6987         return dbus_message_get_sender(service->pending);
6988 }
6989
6990 static int service_indicate_state(struct connman_service *service)
6991 {
6992         enum connman_service_state old_state, new_state;
6993         struct connman_service *def_service;
6994         enum connman_ipconfig_method method;
6995         int result;
6996
6997         if (!service)
6998                 return -EINVAL;
6999
7000         old_state = service->state;
7001         new_state = combine_state(service->state_ipv4, service->state_ipv6);
7002
7003         DBG("service %p old %s - new %s/%s => %s",
7004                                         service,
7005                                         state2string(old_state),
7006                                         state2string(service->state_ipv4),
7007                                         state2string(service->state_ipv6),
7008                                         state2string(new_state));
7009
7010         if (old_state == new_state)
7011                 return -EALREADY;
7012
7013         def_service = __connman_service_get_default();
7014
7015         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
7016                 result = service_update_preferred_order(def_service,
7017                                 service, new_state);
7018                 if (result == -EALREADY)
7019                         return result;
7020         }
7021
7022         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
7023                 __connman_notifier_leave_online(service->type);
7024
7025         if (is_connected_state(service, old_state) &&
7026                         !is_connected_state(service, new_state))
7027                 searchdomain_remove_all(service);
7028
7029         service->state = new_state;
7030         state_changed(service);
7031
7032         switch(new_state) {
7033         case CONNMAN_SERVICE_STATE_UNKNOWN:
7034
7035                 break;
7036
7037         case CONNMAN_SERVICE_STATE_IDLE:
7038                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
7039                         __connman_service_disconnect(service);
7040
7041                 break;
7042
7043         case CONNMAN_SERVICE_STATE_ASSOCIATION:
7044
7045                 break;
7046
7047         case CONNMAN_SERVICE_STATE_CONFIGURATION:
7048                 if (!service->new_service &&
7049                                 __connman_stats_service_register(service) == 0) {
7050                         /*
7051                          * For new services the statistics are updated after
7052                          * we have successfully connected.
7053                          */
7054                         __connman_stats_get(service, false,
7055                                                 &service->stats.data);
7056                         __connman_stats_get(service, true,
7057                                                 &service->stats_roaming.data);
7058                 }
7059
7060                 break;
7061
7062         case CONNMAN_SERVICE_STATE_READY:
7063                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7064
7065                 if (service->new_service &&
7066                                 __connman_stats_service_register(service) == 0) {
7067                         /*
7068                          * This is normally done after configuring state
7069                          * but for new service do this after we have connected
7070                          * successfully.
7071                          */
7072                         __connman_stats_get(service, false,
7073                                                 &service->stats.data);
7074                         __connman_stats_get(service, true,
7075                                                 &service->stats_roaming.data);
7076                 }
7077
7078                 service->new_service = false;
7079
7080                 default_changed();
7081
7082                 def_service = __connman_service_get_default();
7083
7084                 service_update_preferred_order(def_service, service, new_state);
7085
7086                 __connman_service_set_favorite(service, true);
7087
7088                 reply_pending(service, 0);
7089
7090                 g_get_current_time(&service->modified);
7091                 service_save(service);
7092
7093                 searchdomain_add_all(service);
7094                 dns_changed(service);
7095                 domain_changed(service);
7096                 proxy_changed(service);
7097
7098                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
7099                         __connman_notifier_connect(service->type);
7100
7101                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7102                         connman_network_get_bool(service->network,
7103                                                 "WiFi.UseWPS")) {
7104                         const char *pass;
7105
7106                         pass = connman_network_get_string(service->network,
7107                                                         "WiFi.Passphrase");
7108
7109                         __connman_service_set_passphrase(service, pass);
7110
7111                         connman_network_set_bool(service->network,
7112                                                         "WiFi.UseWPS", false);
7113                 }
7114
7115                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
7116                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
7117                         __connman_ipconfig_disable_ipv6(
7118                                                 service->ipconfig_ipv6);
7119
7120                 if (connman_setting_get_bool("SingleConnectedTechnology"))
7121                         single_connected_tech(service);
7122                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
7123                         vpn_auto_connect();
7124
7125 #if defined TIZEN_EXT
7126                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7127                         set_priority_connected_service();
7128 #endif
7129
7130                 break;
7131
7132         case CONNMAN_SERVICE_STATE_ONLINE:
7133
7134                 break;
7135
7136         case CONNMAN_SERVICE_STATE_DISCONNECT:
7137                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
7138
7139                 reply_pending(service, ECONNABORTED);
7140
7141                 def_service = __connman_service_get_default();
7142                 service->disconnect_reason = connman_network_get_disconnect_reason(service->network);
7143
7144                 if (!__connman_notifier_is_connected() &&
7145                         def_service &&
7146                                 def_service->provider)
7147                         connman_provider_disconnect(def_service->provider);
7148
7149                 default_changed();
7150
7151                 __connman_wispr_stop(service);
7152
7153                 __connman_wpad_stop(service);
7154
7155 #if defined TIZEN_EXT
7156                 /**
7157                   * Skip the functions if there is any connected profiles
7158                   * that use same interface
7159                   */
7160                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7161                         __connman_service_get_connected_count_of_iface(
7162                                                         service) <= 0) {
7163 #endif
7164                 dns_changed(service);
7165                 domain_changed(service);
7166                 proxy_changed(service);
7167 #if defined TIZEN_EXT
7168                 }
7169 #endif
7170
7171                 /*
7172                  * Previous services which are connected and which states
7173                  * are set to online should reset relevantly ipconfig_state
7174                  * to ready so wispr/portal will be rerun on those
7175                  */
7176                 downgrade_connected_services();
7177
7178                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7179                 break;
7180
7181         case CONNMAN_SERVICE_STATE_FAILURE:
7182 #if defined TIZEN_EXT
7183                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7184                         service->order = 5;
7185                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
7186 #endif
7187                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
7188                         connman_agent_report_error(service, service->path,
7189                                         error2string(service->error),
7190                                         report_error_cb,
7191                                         get_dbus_sender(service),
7192                                         NULL) == -EINPROGRESS)
7193                         return 0;
7194                 service_complete(service);
7195
7196                 break;
7197         }
7198
7199         service_list_sort();
7200
7201 #if defined TIZEN_EXT
7202         __connman_service_connect_default(service);
7203 #endif
7204
7205         __connman_connection_update_gateway();
7206
7207         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
7208                         new_state != CONNMAN_SERVICE_STATE_READY) ||
7209                 (old_state == CONNMAN_SERVICE_STATE_READY &&
7210                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
7211                 __connman_notifier_disconnect(service->type);
7212         }
7213
7214         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
7215                 __connman_notifier_enter_online(service->type);
7216                 default_changed();
7217         }
7218
7219         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7220                 service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
7221                 (new_state == CONNMAN_SERVICE_STATE_READY ||
7222                 new_state == CONNMAN_SERVICE_STATE_ONLINE)) {
7223                 if (service->user.favorite_user != service->user.current_user) {
7224                         DBG("Now set service favorite user id from %d to %d",
7225                         service->user.favorite_user, service->user.current_user);
7226
7227                         service->user.favorite_user = service->user.current_user;
7228
7229                         service_save(service);
7230                 }
7231         }
7232
7233         return 0;
7234 }
7235
7236 int __connman_service_indicate_error(struct connman_service *service,
7237                                         enum connman_service_error error)
7238 {
7239         DBG("service %p error %d", service, error);
7240
7241         if (!service)
7242                 return -EINVAL;
7243
7244         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
7245                 return -EALREADY;
7246
7247         set_error(service, error);
7248
7249 /* default internet service: fix not cleared if pdp activation*/
7250 #if defined TIZEN_EXT
7251                 /*
7252                  * If connection failed for default service(DefaultInternet),
7253                  * default_connecting_device should be cleared.
7254                  */
7255                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7256                                 service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED)
7257                         __connman_service_disconnect_default(service);
7258
7259                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
7260                                 service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) {
7261                         g_free(service->passphrase);
7262                         service->passphrase = NULL;
7263                 }
7264 #endif
7265
7266         __connman_service_ipconfig_indicate_state(service,
7267                                                 CONNMAN_SERVICE_STATE_FAILURE,
7268                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7269         __connman_service_ipconfig_indicate_state(service,
7270                                                 CONNMAN_SERVICE_STATE_FAILURE,
7271                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7272         return 0;
7273 }
7274
7275 int __connman_service_clear_error(struct connman_service *service)
7276 {
7277         DBusMessage *pending, *provider_pending;
7278
7279         DBG("service %p", service);
7280
7281         if (!service)
7282                 return -EINVAL;
7283
7284         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
7285                 return -EINVAL;
7286
7287         pending = service->pending;
7288         service->pending = NULL;
7289         provider_pending = service->provider_pending;
7290         service->provider_pending = NULL;
7291
7292         __connman_service_ipconfig_indicate_state(service,
7293                                                 CONNMAN_SERVICE_STATE_IDLE,
7294                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7295
7296         __connman_service_ipconfig_indicate_state(service,
7297                                                 CONNMAN_SERVICE_STATE_IDLE,
7298                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7299
7300         service->pending = pending;
7301         service->provider_pending = provider_pending;
7302
7303         return 0;
7304 }
7305
7306 int __connman_service_indicate_default(struct connman_service *service)
7307 {
7308         DBG("service %p state %s", service, state2string(service->state));
7309
7310         if (!is_connected(service)) {
7311                 /*
7312                  * If service is not yet fully connected, then we must not
7313                  * change the default yet. The default gw will be changed
7314                  * after the service state is in ready.
7315                  */
7316                 return -EINPROGRESS;
7317         }
7318
7319         default_changed();
7320
7321         return 0;
7322 }
7323
7324 enum connman_service_state __connman_service_ipconfig_get_state(
7325                                         struct connman_service *service,
7326                                         enum connman_ipconfig_type type)
7327 {
7328         if (!service)
7329                 return CONNMAN_SERVICE_STATE_UNKNOWN;
7330
7331         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7332                 return service->state_ipv4;
7333
7334         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
7335                 return service->state_ipv6;
7336
7337         return CONNMAN_SERVICE_STATE_UNKNOWN;
7338 }
7339
7340 static void check_proxy_setup(struct connman_service *service)
7341 {
7342         /*
7343          * We start WPAD if we haven't got a PAC URL from DHCP and
7344          * if our proxy manual configuration is either empty or set
7345          * to AUTO with an empty URL.
7346          */
7347
7348         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
7349                 goto done;
7350
7351         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
7352                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
7353                         service->pac))
7354                 goto done;
7355
7356         if (__connman_wpad_start(service) < 0) {
7357                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
7358                 __connman_notifier_proxy_changed(service);
7359                 goto done;
7360         }
7361
7362         return;
7363
7364 done:
7365         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
7366 }
7367
7368 #if defined TIZEN_EXT
7369 void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
7370
7371         DBG("check the proxy and start wispr");
7372         check_proxy_setup(service);
7373         return;
7374 }
7375 #endif
7376
7377 /*
7378  * How many networks are connected at the same time. If more than 1,
7379  * then set the rp_filter setting properly (loose mode routing) so that network
7380  * connectivity works ok. This is only done for IPv4 networks as IPv6
7381  * does not have rp_filter knob.
7382  */
7383 static int connected_networks_count;
7384 static int original_rp_filter;
7385
7386 static void service_rp_filter(struct connman_service *service,
7387                                 bool connected)
7388 {
7389         enum connman_ipconfig_method method;
7390
7391         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
7392
7393         switch (method) {
7394         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
7395         case CONNMAN_IPCONFIG_METHOD_OFF:
7396         case CONNMAN_IPCONFIG_METHOD_AUTO:
7397                 return;
7398         case CONNMAN_IPCONFIG_METHOD_FIXED:
7399         case CONNMAN_IPCONFIG_METHOD_MANUAL:
7400         case CONNMAN_IPCONFIG_METHOD_DHCP:
7401                 break;
7402         }
7403
7404         if (connected) {
7405                 if (connected_networks_count == 1) {
7406                         int filter_value;
7407                         filter_value = __connman_ipconfig_set_rp_filter();
7408                         if (filter_value < 0)
7409                                 return;
7410
7411                         original_rp_filter = filter_value;
7412                 }
7413                 connected_networks_count++;
7414
7415         } else {
7416                 if (connected_networks_count == 2)
7417                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
7418
7419                 connected_networks_count--;
7420                 if (connected_networks_count < 0)
7421                         connected_networks_count = 0;
7422         }
7423
7424         DBG("%s %s ipconfig %p method %d count %d filter %d",
7425                 connected ? "connected" : "disconnected", service->identifier,
7426                 service->ipconfig_ipv4, method,
7427                 connected_networks_count, original_rp_filter);
7428 }
7429
7430 static gboolean redo_wispr(gpointer user_data)
7431 {
7432         struct connman_service *service = user_data;
7433         int refcount = service->refcount - 1;
7434
7435         connman_service_unref(service);
7436         if (refcount == 0) {
7437                 DBG("Service %p already removed", service);
7438                 return FALSE;
7439         }
7440
7441         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
7442
7443         return FALSE;
7444 }
7445
7446 int __connman_service_online_check_failed(struct connman_service *service,
7447                                         enum connman_ipconfig_type type)
7448 {
7449         DBG("service %p type %d count %d", service, type,
7450                                                 service->online_check_count);
7451
7452         /* currently we only retry IPv6 stuff */
7453         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
7454                         service->online_check_count != 1) {
7455                 connman_warn("Online check failed for %p %s", service,
7456                         service->name);
7457                 return 0;
7458         }
7459
7460         service->online_check_count = 0;
7461
7462         /*
7463          * We set the timeout to 1 sec so that we have a chance to get
7464          * necessary IPv6 router advertisement messages that might have
7465          * DNS data etc.
7466          */
7467         g_timeout_add_seconds(1, redo_wispr, connman_service_ref(service));
7468
7469         return EAGAIN;
7470 }
7471
7472 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
7473                                         enum connman_service_state new_state,
7474                                         enum connman_ipconfig_type type)
7475 {
7476         struct connman_ipconfig *ipconfig = NULL;
7477         enum connman_service_state old_state;
7478         enum connman_ipconfig_method method;
7479
7480         if (!service)
7481                 return -EINVAL;
7482
7483         switch (type) {
7484         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
7485         case CONNMAN_IPCONFIG_TYPE_ALL:
7486                 return -EINVAL;
7487
7488         case CONNMAN_IPCONFIG_TYPE_IPV4:
7489                 old_state = service->state_ipv4;
7490                 ipconfig = service->ipconfig_ipv4;
7491
7492                 break;
7493
7494         case CONNMAN_IPCONFIG_TYPE_IPV6:
7495                 old_state = service->state_ipv6;
7496                 ipconfig = service->ipconfig_ipv6;
7497
7498                 break;
7499         }
7500
7501         if (!ipconfig)
7502                 return -EINVAL;
7503
7504         /* Any change? */
7505         if (old_state == new_state)
7506                 return -EALREADY;
7507
7508 #if defined TIZEN_EXT
7509         __sync_synchronize();
7510         if (service->user_pdn_connection_refcount > 0 &&
7511                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7512                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
7513                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
7514                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
7515                         service->user_pdn_connection_refcount = 0;
7516                         __sync_synchronize();
7517                 }
7518 #endif
7519
7520         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
7521                 service, service ? service->identifier : NULL,
7522                 old_state, state2string(old_state),
7523                 new_state, state2string(new_state),
7524                 type, __connman_ipconfig_type2string(type));
7525
7526         switch (new_state) {
7527         case CONNMAN_SERVICE_STATE_UNKNOWN:
7528         case CONNMAN_SERVICE_STATE_IDLE:
7529         case CONNMAN_SERVICE_STATE_ASSOCIATION:
7530                 break;
7531         case CONNMAN_SERVICE_STATE_CONFIGURATION:
7532                 __connman_ipconfig_enable(ipconfig);
7533                 break;
7534         case CONNMAN_SERVICE_STATE_READY:
7535 #if defined TIZEN_EXT
7536                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7537                                 __connman_service_is_internet_profile(service) != TRUE) {
7538                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7539                                 service_rp_filter(service, TRUE);
7540
7541                         break;
7542                 }
7543 #endif
7544                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
7545 #if !defined TIZEN_EXT
7546                         check_proxy_setup(service);
7547 #endif
7548                         service_rp_filter(service, true);
7549                 } else {
7550                         service->online_check_count = 1;
7551                         __connman_wispr_start(service, type);
7552                 }
7553                 break;
7554         case CONNMAN_SERVICE_STATE_ONLINE:
7555                 break;
7556         case CONNMAN_SERVICE_STATE_DISCONNECT:
7557                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
7558                         return -EINVAL;
7559
7560                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7561                         service_rp_filter(service, false);
7562
7563                 break;
7564         case CONNMAN_SERVICE_STATE_FAILURE:
7565                 break;
7566         }
7567
7568         /* Keep that state, but if the ipconfig method is OFF, then we set
7569            the state to IDLE so that it will not affect the combined state
7570            in the future.
7571          */
7572         method = __connman_ipconfig_get_method(ipconfig);
7573         switch (method) {
7574         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
7575         case CONNMAN_IPCONFIG_METHOD_OFF:
7576                 new_state = CONNMAN_SERVICE_STATE_IDLE;
7577                 break;
7578
7579         case CONNMAN_IPCONFIG_METHOD_FIXED:
7580         case CONNMAN_IPCONFIG_METHOD_MANUAL:
7581         case CONNMAN_IPCONFIG_METHOD_DHCP:
7582         case CONNMAN_IPCONFIG_METHOD_AUTO:
7583                 break;
7584
7585         }
7586
7587         if (is_connected_state(service, old_state) &&
7588                         !is_connected_state(service, new_state))
7589 #if defined TIZEN_EXT
7590         {
7591                 DBG("nameserver remove all, type: %d", type);
7592                 nameserver_remove_all(service, type);
7593 #else
7594                 nameserver_remove_all(service);
7595 #endif
7596 #if defined TIZEN_EXT
7597         }
7598 #endif
7599
7600         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
7601                 service->state_ipv4 = new_state;
7602         else
7603                 service->state_ipv6 = new_state;
7604
7605         if (!is_connected_state(service, old_state) &&
7606                         is_connected_state(service, new_state))
7607 #if defined TIZEN_EXT
7608         {
7609                 DBG("nameserver add all, type: %d", type);
7610                 nameserver_add_all(service, type);
7611 #else
7612                 nameserver_add_all(service);
7613 #endif
7614 #if defined TIZEN_EXT
7615         }
7616 #endif
7617
7618 #if defined TIZEN_EXT
7619         int ret = service_indicate_state(service);
7620         /*Sent the Ready changed signal again in case IPv4 IP set
7621           after IPv6 IP set*/
7622
7623         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
7624                         && new_state == CONNMAN_SERVICE_STATE_READY) {
7625                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
7626                 state_changed(service);
7627         }
7628
7629         return ret;
7630 #endif
7631         return service_indicate_state(service);
7632 }
7633
7634 static bool prepare_network(struct connman_service *service)
7635 {
7636         enum connman_network_type type;
7637         unsigned int ssid_len;
7638
7639         type = connman_network_get_type(service->network);
7640
7641         switch (type) {
7642         case CONNMAN_NETWORK_TYPE_UNKNOWN:
7643         case CONNMAN_NETWORK_TYPE_VENDOR:
7644                 return false;
7645         case CONNMAN_NETWORK_TYPE_WIFI:
7646                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
7647                                                 &ssid_len))
7648                         return false;
7649
7650                 if (service->passphrase)
7651                         connman_network_set_string(service->network,
7652                                 "WiFi.Passphrase", service->passphrase);
7653                 break;
7654         case CONNMAN_NETWORK_TYPE_ETHERNET:
7655         case CONNMAN_NETWORK_TYPE_GADGET:
7656         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
7657         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
7658         case CONNMAN_NETWORK_TYPE_CELLULAR:
7659                 break;
7660         }
7661
7662         return true;
7663 }
7664
7665 static void prepare_8021x(struct connman_service *service)
7666 {
7667         if (service->eap)
7668                 connman_network_set_string(service->network, "WiFi.EAP",
7669                                                                 service->eap);
7670
7671         if (service->identity)
7672                 connman_network_set_string(service->network, "WiFi.Identity",
7673                                                         service->identity);
7674
7675         if (service->ca_cert_file)
7676                 connman_network_set_string(service->network, "WiFi.CACertFile",
7677                                                         service->ca_cert_file);
7678
7679         if (service->client_cert_file)
7680                 connman_network_set_string(service->network,
7681                                                 "WiFi.ClientCertFile",
7682                                                 service->client_cert_file);
7683
7684         if (service->private_key_file)
7685                 connman_network_set_string(service->network,
7686                                                 "WiFi.PrivateKeyFile",
7687                                                 service->private_key_file);
7688
7689         if (service->private_key_passphrase)
7690                 connman_network_set_string(service->network,
7691                                         "WiFi.PrivateKeyPassphrase",
7692                                         service->private_key_passphrase);
7693
7694         if (service->phase2)
7695                 connman_network_set_string(service->network, "WiFi.Phase2",
7696                                                         service->phase2);
7697 }
7698
7699 static int service_connect(struct connman_service *service)
7700 {
7701         int err;
7702
7703         if (service->hidden)
7704                 return -EPERM;
7705
7706 #if defined TIZEN_EXT
7707         GList *list;
7708         int index;
7709
7710         index = __connman_service_get_index(service);
7711
7712         for (list = service_list; list; list = list->next) {
7713                 struct connman_service *temp = list->data;
7714
7715                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7716                         break;
7717
7718                 if (!is_connecting(temp) && !is_connected(temp))
7719                         break;
7720
7721                 if (service == temp)
7722                         continue;
7723
7724                 if (service->type != temp->type)
7725                         continue;
7726
7727                 if (__connman_service_get_index(temp) == index &&
7728                                 __connman_service_disconnect(temp) == -EINPROGRESS)
7729                         return -EINPROGRESS;
7730         }
7731 #endif
7732
7733         switch (service->type) {
7734         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7735         case CONNMAN_SERVICE_TYPE_SYSTEM:
7736         case CONNMAN_SERVICE_TYPE_GPS:
7737         case CONNMAN_SERVICE_TYPE_P2P:
7738                 return -EINVAL;
7739         case CONNMAN_SERVICE_TYPE_ETHERNET:
7740         case CONNMAN_SERVICE_TYPE_GADGET:
7741         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7742         case CONNMAN_SERVICE_TYPE_CELLULAR:
7743         case CONNMAN_SERVICE_TYPE_VPN:
7744                 break;
7745         case CONNMAN_SERVICE_TYPE_WIFI:
7746                 switch (service->security) {
7747                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7748                 case CONNMAN_SERVICE_SECURITY_NONE:
7749                         break;
7750                 case CONNMAN_SERVICE_SECURITY_WEP:
7751                 case CONNMAN_SERVICE_SECURITY_PSK:
7752                 case CONNMAN_SERVICE_SECURITY_WPA:
7753                 case CONNMAN_SERVICE_SECURITY_RSN:
7754                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7755                                 return -ENOKEY;
7756
7757                         if (service->request_passphrase_input) {
7758                                 DBG("Now try to connect other user's favorite service");
7759                                 service->request_passphrase_input = false;
7760                                 return -ENOKEY;
7761                         } else if (!service->passphrase) {
7762                                 if (!service->network)
7763                                         return -EOPNOTSUPP;
7764
7765                                 if (!service->wps ||
7766                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
7767                                         return -ENOKEY;
7768                         }
7769                         break;
7770
7771                 case CONNMAN_SERVICE_SECURITY_8021X:
7772                         if (!service->eap)
7773                                 return -EINVAL;
7774
7775 #if defined TIZEN_EXT
7776                         /*
7777                          * never request credentials if using EAP-TLS, EAP-SIM
7778                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
7779                          * need to be fully provisioned)
7780                          */
7781                         DBG("service eap: %s", service->eap);
7782                         if (g_str_equal(service->eap, "tls") ||
7783                                 g_str_equal(service->eap, "sim") ||
7784                                 g_str_equal(service->eap, "aka"))
7785                                 break;
7786 #else
7787                         /*
7788                          * never request credentials if using EAP-TLS
7789                          * (EAP-TLS networks need to be fully provisioned)
7790                          */
7791                         if (g_str_equal(service->eap, "tls"))
7792                                 break;
7793 #endif
7794                         /*
7795                          * Return -ENOKEY if either identity or passphrase is
7796                          * missing. Agent provided credentials can be used as
7797                          * fallback if needed.
7798                          */
7799                         if (((!service->identity &&
7800                                         !service->agent_identity) ||
7801                                         !service->passphrase) ||
7802                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7803                                 return -ENOKEY;
7804
7805                         break;
7806                 }
7807                 break;
7808         }
7809
7810         if (service->network) {
7811                 if (!prepare_network(service))
7812                         return -EINVAL;
7813
7814                 switch (service->security) {
7815                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7816                 case CONNMAN_SERVICE_SECURITY_NONE:
7817                 case CONNMAN_SERVICE_SECURITY_WEP:
7818                 case CONNMAN_SERVICE_SECURITY_PSK:
7819                 case CONNMAN_SERVICE_SECURITY_WPA:
7820                 case CONNMAN_SERVICE_SECURITY_RSN:
7821                         break;
7822                 case CONNMAN_SERVICE_SECURITY_8021X:
7823                         prepare_8021x(service);
7824                         break;
7825                 }
7826
7827                 if (__connman_stats_service_register(service) == 0) {
7828                         __connman_stats_get(service, false,
7829                                                 &service->stats.data);
7830                         __connman_stats_get(service, true,
7831                                                 &service->stats_roaming.data);
7832                 }
7833
7834                 if (service->ipconfig_ipv4)
7835                         __connman_ipconfig_enable(service->ipconfig_ipv4);
7836                 if (service->ipconfig_ipv6)
7837                         __connman_ipconfig_enable(service->ipconfig_ipv6);
7838
7839                 err = __connman_network_connect(service->network);
7840         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7841                                         service->provider)
7842                 err = __connman_provider_connect(service->provider);
7843         else
7844                 return -EOPNOTSUPP;
7845
7846         if (err < 0) {
7847                 if (err != -EINPROGRESS) {
7848                         __connman_ipconfig_disable(service->ipconfig_ipv4);
7849                         __connman_ipconfig_disable(service->ipconfig_ipv6);
7850                         __connman_stats_service_unregister(service);
7851                 }
7852         }
7853
7854         return err;
7855 }
7856
7857 int __connman_service_connect(struct connman_service *service,
7858                         enum connman_service_connect_reason reason)
7859 {
7860         int err;
7861
7862         DBG("service %p state %s connect reason %s -> %s",
7863                 service, state2string(service->state),
7864                 reason2string(service->connect_reason),
7865                 reason2string(reason));
7866
7867         if (is_connected(service))
7868                 return -EISCONN;
7869
7870         if (is_connecting(service))
7871                 return -EALREADY;
7872
7873         switch (service->type) {
7874         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7875         case CONNMAN_SERVICE_TYPE_SYSTEM:
7876         case CONNMAN_SERVICE_TYPE_GPS:
7877         case CONNMAN_SERVICE_TYPE_P2P:
7878                 return -EINVAL;
7879
7880         case CONNMAN_SERVICE_TYPE_ETHERNET:
7881         case CONNMAN_SERVICE_TYPE_GADGET:
7882         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7883         case CONNMAN_SERVICE_TYPE_CELLULAR:
7884         case CONNMAN_SERVICE_TYPE_VPN:
7885         case CONNMAN_SERVICE_TYPE_WIFI:
7886                 break;
7887         }
7888
7889         if (!is_ipconfig_usable(service))
7890                 return -ENOLINK;
7891
7892         __connman_service_clear_error(service);
7893
7894         err = service_connect(service);
7895
7896         service->connect_reason = reason;
7897         if (err >= 0)
7898                 return 0;
7899
7900         if (err == -EINPROGRESS) {
7901                 if (service->timeout == 0)
7902                         service->timeout = g_timeout_add_seconds(
7903                                 CONNECT_TIMEOUT, connect_timeout, service);
7904
7905                 return -EINPROGRESS;
7906         }
7907
7908         if (service->network)
7909                 __connman_network_disconnect(service->network);
7910         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7911                                 service->provider)
7912                         connman_provider_disconnect(service->provider);
7913
7914         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
7915                 if (err == -ENOKEY || err == -EPERM) {
7916                         DBusMessage *pending = NULL;
7917
7918                         /*
7919                          * We steal the reply here. The idea is that the
7920                          * connecting client will see the connection status
7921                          * after the real hidden network is connected or
7922                          * connection failed.
7923                          */
7924                         if (service->hidden) {
7925                                 pending = service->pending;
7926                                 service->pending = NULL;
7927                         }
7928
7929                         err = __connman_agent_request_passphrase_input(service,
7930                                         request_input_cb,
7931                                         get_dbus_sender(service),
7932                                         pending);
7933                         if (service->hidden && err != -EINPROGRESS)
7934                                 service->pending = pending;
7935
7936                         return err;
7937                 }
7938                 reply_pending(service, -err);
7939         }
7940
7941         return err;
7942 }
7943
7944 int __connman_service_disconnect(struct connman_service *service)
7945 {
7946         int err;
7947
7948         DBG("service %p", service);
7949
7950         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
7951         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
7952
7953         connman_agent_cancel(service);
7954
7955         reply_pending(service, ECONNABORTED);
7956
7957         if (service->network) {
7958                 err = __connman_network_disconnect(service->network);
7959         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7960                                         service->provider)
7961                 err = connman_provider_disconnect(service->provider);
7962         else
7963                 return -EOPNOTSUPP;
7964
7965         if (err < 0 && err != -EINPROGRESS)
7966                 return err;
7967
7968         __connman_6to4_remove(service->ipconfig_ipv4);
7969
7970         if (service->ipconfig_ipv4)
7971                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
7972                                                         NULL);
7973         else
7974                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
7975                                                         NULL);
7976
7977 #if defined TIZEN_EXT
7978         /**
7979           * Skip the functions If there is any connected profiles
7980           * that use same interface
7981           */
7982         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7983                 __connman_service_get_connected_count_of_iface(service) <= 0) {
7984 #endif
7985         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
7986         settings_changed(service, service->ipconfig_ipv4);
7987
7988         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
7989         settings_changed(service, service->ipconfig_ipv6);
7990
7991         __connman_ipconfig_disable(service->ipconfig_ipv4);
7992         __connman_ipconfig_disable(service->ipconfig_ipv6);
7993 #if defined TIZEN_EXT
7994         }
7995 #endif
7996
7997         __connman_stats_service_unregister(service);
7998
7999         return err;
8000 }
8001
8002 int __connman_service_disconnect_all(void)
8003 {
8004         struct connman_service *service;
8005         GSList *services = NULL, *list;
8006         GList *iter;
8007
8008         DBG("");
8009
8010         for (iter = service_list; iter; iter = iter->next) {
8011                 service = iter->data;
8012
8013                 if (!is_connected(service))
8014                         break;
8015
8016                 services = g_slist_prepend(services, service);
8017         }
8018
8019         for (list = services; list; list = list->next) {
8020                 struct connman_service *service = list->data;
8021
8022                 service->ignore = true;
8023
8024                 __connman_service_disconnect(service);
8025         }
8026
8027         g_slist_free(services);
8028
8029         return 0;
8030 }
8031
8032 /**
8033  * lookup_by_identifier:
8034  * @identifier: service identifier
8035  *
8036  * Look up a service by identifier (reference count will not be increased)
8037  */
8038 static struct connman_service *lookup_by_identifier(const char *identifier)
8039 {
8040         return g_hash_table_lookup(service_hash, identifier);
8041 }
8042
8043 struct provision_user_data {
8044         const char *ident;
8045         int ret;
8046 };
8047
8048 static void provision_changed(gpointer value, gpointer user_data)
8049 {
8050         struct connman_service *service = value;
8051         struct provision_user_data *data = user_data;
8052         const char *path = data->ident;
8053         int ret;
8054
8055         ret = __connman_config_provision_service_ident(service, path,
8056                         service->config_file, service->config_entry);
8057         if (ret > 0)
8058                 data->ret = ret;
8059 }
8060
8061 int __connman_service_provision_changed(const char *ident)
8062 {
8063         struct provision_user_data data = {
8064                 .ident = ident,
8065                 .ret = 0
8066         };
8067
8068         g_list_foreach(service_list, provision_changed, (void *)&data);
8069
8070         /*
8071          * Because the provision_changed() might have set some services
8072          * as favorite, we must sort the sequence now.
8073          */
8074         if (services_dirty) {
8075                 services_dirty = false;
8076
8077                 service_list_sort();
8078
8079                 __connman_connection_update_gateway();
8080         }
8081
8082         return data.ret;
8083 }
8084
8085 void __connman_service_set_config(struct connman_service *service,
8086                                 const char *file_id, const char *entry)
8087 {
8088         if (!service)
8089                 return;
8090
8091         g_free(service->config_file);
8092         service->config_file = g_strdup(file_id);
8093
8094         g_free(service->config_entry);
8095         service->config_entry = g_strdup(entry);
8096 }
8097
8098 /**
8099  * __connman_service_get:
8100  * @identifier: service identifier
8101  *
8102  * Look up a service by identifier or create a new one if not found
8103  */
8104 static struct connman_service *service_get(const char *identifier)
8105 {
8106         struct connman_service *service;
8107
8108         service = g_hash_table_lookup(service_hash, identifier);
8109         if (service) {
8110                 connman_service_ref(service);
8111                 return service;
8112         }
8113
8114         service = connman_service_create();
8115         if (!service)
8116                 return NULL;
8117
8118         DBG("service %p", service);
8119
8120         service->identifier = g_strdup(identifier);
8121
8122         service_list = g_list_insert_sorted(service_list, service,
8123                                                 service_compare);
8124
8125         g_hash_table_insert(service_hash, service->identifier, service);
8126
8127         return service;
8128 }
8129
8130 static int service_register(struct connman_service *service)
8131 {
8132         DBG("service %p", service);
8133
8134         if (service->path)
8135                 return -EALREADY;
8136
8137         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
8138                                                 service->identifier);
8139
8140         DBG("path %s", service->path);
8141
8142         if (__connman_config_provision_service(service) < 0)
8143                 service_load(service);
8144
8145         g_dbus_register_interface(connection, service->path,
8146                                         CONNMAN_SERVICE_INTERFACE,
8147                                         service_methods, service_signals,
8148                                                         NULL, service, NULL);
8149
8150         service_list_sort();
8151
8152         __connman_connection_update_gateway();
8153
8154         return 0;
8155 }
8156
8157 static void service_up(struct connman_ipconfig *ipconfig,
8158                 const char *ifname)
8159 {
8160         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8161
8162         DBG("%s up", ifname);
8163
8164         link_changed(service);
8165
8166         service->stats.valid = false;
8167         service->stats_roaming.valid = false;
8168 }
8169
8170 static void service_down(struct connman_ipconfig *ipconfig,
8171                         const char *ifname)
8172 {
8173         DBG("%s down", ifname);
8174 }
8175
8176 static void service_lower_up(struct connman_ipconfig *ipconfig,
8177                         const char *ifname)
8178 {
8179         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8180
8181         DBG("%s lower up", ifname);
8182
8183         stats_start(service);
8184 }
8185
8186 static void service_lower_down(struct connman_ipconfig *ipconfig,
8187                         const char *ifname)
8188 {
8189         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8190
8191         DBG("%s lower down", ifname);
8192
8193         if (!is_idle_state(service, service->state_ipv4))
8194                 __connman_ipconfig_disable(service->ipconfig_ipv4);
8195
8196         if (!is_idle_state(service, service->state_ipv6))
8197                 __connman_ipconfig_disable(service->ipconfig_ipv6);
8198
8199         stats_stop(service);
8200         service_save(service);
8201 }
8202
8203 static void service_ip_bound(struct connman_ipconfig *ipconfig,
8204                         const char *ifname)
8205 {
8206         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8207         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
8208         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
8209 #if defined TIZEN_EXT
8210         int err;
8211 #endif
8212
8213         DBG("%s ip bound", ifname);
8214
8215         type = __connman_ipconfig_get_config_type(ipconfig);
8216         method = __connman_ipconfig_get_method(ipconfig);
8217
8218         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
8219                                                         type, method);
8220
8221         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
8222                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
8223 #if defined TIZEN_EXT
8224         {
8225                 err = __connman_ipconfig_gateway_add(ipconfig, service);
8226
8227                 if(err == 0)
8228                         __connman_connection_gateway_activate(service,
8229                                         CONNMAN_IPCONFIG_TYPE_IPV6);
8230         }
8231 #else
8232                 __connman_service_ipconfig_indicate_state(service,
8233                                                 CONNMAN_SERVICE_STATE_READY,
8234                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
8235 #endif
8236
8237         settings_changed(service, ipconfig);
8238 }
8239
8240 static void service_ip_release(struct connman_ipconfig *ipconfig,
8241                         const char *ifname)
8242 {
8243         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8244         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
8245         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
8246
8247         DBG("%s ip release", ifname);
8248
8249         type = __connman_ipconfig_get_config_type(ipconfig);
8250         method = __connman_ipconfig_get_method(ipconfig);
8251
8252         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
8253                                                         type, method);
8254
8255         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
8256                         method == CONNMAN_IPCONFIG_METHOD_OFF)
8257                 __connman_service_ipconfig_indicate_state(service,
8258                                         CONNMAN_SERVICE_STATE_DISCONNECT,
8259                                         CONNMAN_IPCONFIG_TYPE_IPV6);
8260
8261         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
8262                         method == CONNMAN_IPCONFIG_METHOD_OFF)
8263                 __connman_service_ipconfig_indicate_state(service,
8264                                         CONNMAN_SERVICE_STATE_DISCONNECT,
8265                                         CONNMAN_IPCONFIG_TYPE_IPV4);
8266
8267         settings_changed(service, ipconfig);
8268 }
8269
8270 static void service_route_changed(struct connman_ipconfig *ipconfig,
8271                                 const char *ifname)
8272 {
8273         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
8274
8275         DBG("%s route changed", ifname);
8276
8277         settings_changed(service, ipconfig);
8278 }
8279
8280 static const struct connman_ipconfig_ops service_ops = {
8281         .up             = service_up,
8282         .down           = service_down,
8283         .lower_up       = service_lower_up,
8284         .lower_down     = service_lower_down,
8285         .ip_bound       = service_ip_bound,
8286         .ip_release     = service_ip_release,
8287         .route_set      = service_route_changed,
8288         .route_unset    = service_route_changed,
8289 };
8290
8291 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
8292                 int index, enum connman_ipconfig_method method)
8293 {
8294         struct connman_ipconfig *ipconfig_ipv4;
8295
8296         ipconfig_ipv4 = __connman_ipconfig_create(index,
8297                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
8298         if (!ipconfig_ipv4)
8299                 return NULL;
8300
8301         __connman_ipconfig_set_method(ipconfig_ipv4, method);
8302
8303         __connman_ipconfig_set_data(ipconfig_ipv4, service);
8304
8305         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
8306
8307         return ipconfig_ipv4;
8308 }
8309
8310 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
8311                 int index)
8312 {
8313         struct connman_ipconfig *ipconfig_ipv6;
8314
8315         ipconfig_ipv6 = __connman_ipconfig_create(index,
8316                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
8317         if (!ipconfig_ipv6)
8318                 return NULL;
8319
8320         __connman_ipconfig_set_data(ipconfig_ipv6, service);
8321
8322         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
8323
8324         return ipconfig_ipv6;
8325 }
8326
8327 void __connman_service_read_ip4config(struct connman_service *service)
8328 {
8329         GKeyFile *keyfile;
8330
8331         if (!service->ipconfig_ipv4)
8332                 return;
8333
8334         keyfile = connman_storage_load_service(service->identifier);
8335         if (!keyfile)
8336                 return;
8337
8338         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
8339                                 service->identifier, "IPv4.");
8340
8341         g_key_file_free(keyfile);
8342 }
8343
8344 void connman_service_create_ip4config(struct connman_service *service,
8345                                         int index)
8346 {
8347         DBG("ipv4 %p", service->ipconfig_ipv4);
8348
8349         if (service->ipconfig_ipv4)
8350                 return;
8351
8352         service->ipconfig_ipv4 = create_ip4config(service, index,
8353                         CONNMAN_IPCONFIG_METHOD_DHCP);
8354         __connman_service_read_ip4config(service);
8355 }
8356
8357 void __connman_service_read_ip6config(struct connman_service *service)
8358 {
8359         GKeyFile *keyfile;
8360
8361         if (!service->ipconfig_ipv6)
8362                 return;
8363
8364         keyfile = connman_storage_load_service(service->identifier);
8365         if (!keyfile)
8366                 return;
8367
8368         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
8369                                 service->identifier, "IPv6.");
8370
8371         g_key_file_free(keyfile);
8372 }
8373
8374 void connman_service_create_ip6config(struct connman_service *service,
8375                                                                 int index)
8376 {
8377         DBG("ipv6 %p", service->ipconfig_ipv6);
8378
8379         if (service->ipconfig_ipv6)
8380                 return;
8381
8382         service->ipconfig_ipv6 = create_ip6config(service, index);
8383
8384         __connman_service_read_ip6config(service);
8385 }
8386
8387 /**
8388  * connman_service_lookup_from_network:
8389  * @network: network structure
8390  *
8391  * Look up a service by network (reference count will not be increased)
8392  */
8393 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
8394 {
8395         struct connman_service *service;
8396         const char *ident, *group;
8397         char *name;
8398
8399         if (!network)
8400                 return NULL;
8401
8402         ident = __connman_network_get_ident(network);
8403         if (!ident)
8404                 return NULL;
8405
8406         group = connman_network_get_group(network);
8407         if (!group)
8408                 return NULL;
8409
8410         name = g_strdup_printf("%s_%s_%s",
8411                         __connman_network_get_type(network), ident, group);
8412         service = lookup_by_identifier(name);
8413         g_free(name);
8414
8415         return service;
8416 }
8417
8418 struct connman_service *__connman_service_lookup_from_index(int index)
8419 {
8420         struct connman_service *service;
8421         GList *list;
8422
8423         for (list = service_list; list; list = list->next) {
8424                 service = list->data;
8425
8426                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
8427                                                         == index)
8428                         return service;
8429
8430                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
8431                                                         == index)
8432                         return service;
8433         }
8434
8435         return NULL;
8436 }
8437
8438 struct connman_service *__connman_service_lookup_from_ident(const char *identifier)
8439 {
8440         return lookup_by_identifier(identifier);
8441 }
8442
8443 const char *__connman_service_get_ident(struct connman_service *service)
8444 {
8445         return service->identifier;
8446 }
8447
8448 const char *__connman_service_get_path(struct connman_service *service)
8449 {
8450         return service->path;
8451 }
8452
8453 const char *__connman_service_get_name(struct connman_service *service)
8454 {
8455         return service->name;
8456 }
8457
8458 enum connman_service_state __connman_service_get_state(struct connman_service *service)
8459 {
8460         return service->state;
8461 }
8462
8463 unsigned int __connman_service_get_order(struct connman_service *service)
8464 {
8465         unsigned int order = 0;
8466
8467         if (!service)
8468                 return 0;
8469
8470         service->order = 0;
8471
8472         if (!service->favorite)
8473                 return 0;
8474
8475 #if defined TIZEN_EXT
8476         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
8477                         service->do_split_routing == FALSE)
8478                 order = 10;
8479         else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
8480                 if (service->order < 5)
8481                         order = 5;
8482         } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
8483                 order = 4;
8484         else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
8485                 order = 3;
8486         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
8487                         __connman_service_is_internet_profile(service) == TRUE)
8488                 order = 1;
8489         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
8490                         __connman_service_is_tethering_profile(service) == TRUE)
8491                 order = 0;
8492         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
8493                 order = 0;
8494         else
8495                 order = 2;
8496 #else
8497         if (service == service_list->data)
8498                 order = 1;
8499
8500         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
8501                         !service->do_split_routing) {
8502                 service->order = 10;
8503                 order = 10;
8504         }
8505 #endif
8506         DBG("service %p name %s order %d split %d", service, service->name,
8507                 order, service->do_split_routing);
8508
8509         return order;
8510 }
8511
8512 void __connman_service_update_ordering(void)
8513 {
8514         if (service_list && service_list->next)
8515                 service_list = g_list_sort(service_list, service_compare);
8516 }
8517
8518 static enum connman_service_type convert_network_type(struct connman_network *network)
8519 {
8520         enum connman_network_type type = connman_network_get_type(network);
8521
8522         switch (type) {
8523         case CONNMAN_NETWORK_TYPE_UNKNOWN:
8524         case CONNMAN_NETWORK_TYPE_VENDOR:
8525                 break;
8526         case CONNMAN_NETWORK_TYPE_ETHERNET:
8527                 return CONNMAN_SERVICE_TYPE_ETHERNET;
8528         case CONNMAN_NETWORK_TYPE_WIFI:
8529                 return CONNMAN_SERVICE_TYPE_WIFI;
8530         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
8531         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
8532                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
8533         case CONNMAN_NETWORK_TYPE_CELLULAR:
8534                 return CONNMAN_SERVICE_TYPE_CELLULAR;
8535         case CONNMAN_NETWORK_TYPE_GADGET:
8536                 return CONNMAN_SERVICE_TYPE_GADGET;
8537         }
8538
8539         return CONNMAN_SERVICE_TYPE_UNKNOWN;
8540 }
8541
8542 static enum connman_service_security convert_wifi_security(const char *security)
8543 {
8544         if (!security)
8545                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
8546         else if (g_str_equal(security, "none"))
8547                 return CONNMAN_SERVICE_SECURITY_NONE;
8548         else if (g_str_equal(security, "wep"))
8549                 return CONNMAN_SERVICE_SECURITY_WEP;
8550         else if (g_str_equal(security, "psk"))
8551                 return CONNMAN_SERVICE_SECURITY_PSK;
8552         else if (g_str_equal(security, "ieee8021x"))
8553                 return CONNMAN_SERVICE_SECURITY_8021X;
8554         else if (g_str_equal(security, "wpa"))
8555                 return CONNMAN_SERVICE_SECURITY_WPA;
8556         else if (g_str_equal(security, "rsn"))
8557                 return CONNMAN_SERVICE_SECURITY_RSN;
8558 #if defined TIZEN_EXT
8559         else if (g_str_equal(security, "ft_psk") == TRUE)
8560                 return CONNMAN_SERVICE_SECURITY_PSK;
8561         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
8562                 return CONNMAN_SERVICE_SECURITY_8021X;
8563 #endif
8564         else
8565                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
8566 }
8567
8568 static void update_from_network(struct connman_service *service,
8569                                         struct connman_network *network)
8570 {
8571         uint8_t strength = service->strength;
8572         const char *str;
8573
8574         DBG("service %p network %p", service, network);
8575
8576         if (is_connected(service))
8577                 return;
8578
8579         if (is_connecting(service))
8580                 return;
8581
8582         str = connman_network_get_string(network, "Name");
8583         if (str) {
8584                 g_free(service->name);
8585                 service->name = g_strdup(str);
8586                 service->hidden = false;
8587         } else {
8588                 g_free(service->name);
8589                 service->name = NULL;
8590                 service->hidden = true;
8591         }
8592
8593         service->strength = connman_network_get_strength(network);
8594         service->roaming = connman_network_get_bool(network, "Roaming");
8595
8596         if (service->strength == 0) {
8597                 /*
8598                  * Filter out 0-values; it's unclear what they mean
8599                  * and they cause anomalous sorting of the priority list.
8600                  */
8601                 service->strength = strength;
8602         }
8603
8604         str = connman_network_get_string(network, "WiFi.Security");
8605         service->security = convert_wifi_security(str);
8606
8607         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8608                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
8609
8610         if (service->strength > strength && service->network) {
8611                 connman_network_unref(service->network);
8612                 service->network = connman_network_ref(network);
8613
8614                 strength_changed(service);
8615         }
8616
8617         if (!service->network)
8618                 service->network = connman_network_ref(network);
8619
8620         service_list_sort();
8621 }
8622
8623 /**
8624  * __connman_service_create_from_network:
8625  * @network: network structure
8626  *
8627  * Look up service by network and if not found, create one
8628  */
8629 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
8630 {
8631         struct connman_service *service;
8632         struct connman_device *device;
8633         const char *ident, *group;
8634         char *name;
8635         unsigned int *auto_connect_types;
8636         int i, index;
8637
8638         DBG("network %p", network);
8639
8640         if (!network)
8641                 return NULL;
8642
8643         ident = __connman_network_get_ident(network);
8644         if (!ident)
8645                 return NULL;
8646
8647         group = connman_network_get_group(network);
8648         if (!group)
8649                 return NULL;
8650
8651         name = g_strdup_printf("%s_%s_%s",
8652                         __connman_network_get_type(network), ident, group);
8653         service = service_get(name);
8654         g_free(name);
8655
8656         if (!service)
8657                 return NULL;
8658
8659         if (__connman_network_get_weakness(network))
8660                 return service;
8661
8662         if (service->path) {
8663                 update_from_network(service, network);
8664                 __connman_connection_update_gateway();
8665                 return service;
8666         }
8667
8668         service->type = convert_network_type(network);
8669
8670         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
8671         service->autoconnect = false;
8672         for (i = 0; auto_connect_types &&
8673                      auto_connect_types[i] != 0; i++) {
8674                 if (service->type == auto_connect_types[i]) {
8675                         service->autoconnect = true;
8676                         break;
8677                 }
8678         }
8679
8680         switch (service->type) {
8681         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8682         case CONNMAN_SERVICE_TYPE_SYSTEM:
8683         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8684         case CONNMAN_SERVICE_TYPE_GPS:
8685         case CONNMAN_SERVICE_TYPE_VPN:
8686         case CONNMAN_SERVICE_TYPE_GADGET:
8687         case CONNMAN_SERVICE_TYPE_WIFI:
8688         case CONNMAN_SERVICE_TYPE_CELLULAR:
8689         case CONNMAN_SERVICE_TYPE_P2P:
8690                 break;
8691         case CONNMAN_SERVICE_TYPE_ETHERNET:
8692                 service->favorite = true;
8693                 break;
8694         }
8695
8696         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8697         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8698
8699         update_from_network(service, network);
8700
8701         index = connman_network_get_index(network);
8702
8703         if (!service->ipconfig_ipv4)
8704                 service->ipconfig_ipv4 = create_ip4config(service, index,
8705                                 CONNMAN_IPCONFIG_METHOD_DHCP);
8706
8707         if (!service->ipconfig_ipv6)
8708                 service->ipconfig_ipv6 = create_ip6config(service, index);
8709
8710         service_register(service);
8711
8712         if (service->favorite) {
8713                 device = connman_network_get_device(service->network);
8714                 if (device && !connman_device_get_scanning(device)) {
8715
8716                         switch (service->type) {
8717                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8718                         case CONNMAN_SERVICE_TYPE_SYSTEM:
8719                         case CONNMAN_SERVICE_TYPE_P2P:
8720                                 break;
8721
8722                         case CONNMAN_SERVICE_TYPE_GADGET:
8723                         case CONNMAN_SERVICE_TYPE_ETHERNET:
8724                                 if (service->autoconnect) {
8725                                         __connman_service_connect(service,
8726                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8727                                         break;
8728                                 }
8729
8730                                 /* fall through */
8731                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8732                         case CONNMAN_SERVICE_TYPE_GPS:
8733                         case CONNMAN_SERVICE_TYPE_VPN:
8734                         case CONNMAN_SERVICE_TYPE_WIFI:
8735                         case CONNMAN_SERVICE_TYPE_CELLULAR:
8736                                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8737                                 break;
8738                         }
8739                 }
8740
8741 #if defined TIZEN_EXT
8742                 /* TIZEN synchronizes below information when the service creates */
8743                 if (service->eap != NULL)
8744                         connman_network_set_string(service->network, "WiFi.EAP",
8745                                                                 service->eap);
8746                 if (service->identity != NULL)
8747                         connman_network_set_string(service->network, "WiFi.Identity",
8748                                                                 service->identity);
8749                 if (service->phase2 != NULL)
8750                         connman_network_set_string(service->network, "WiFi.Phase2",
8751                                                                 service->phase2);
8752 #endif
8753         }
8754
8755         __connman_notifier_service_add(service, service->name);
8756         service_schedule_added(service);
8757
8758         return service;
8759 }
8760
8761 void __connman_service_update_from_network(struct connman_network *network)
8762 {
8763         bool need_sort = false;
8764         struct connman_service *service;
8765         uint8_t strength;
8766         bool roaming;
8767         const char *name;
8768         bool stats_enable;
8769
8770         service = connman_service_lookup_from_network(network);
8771         if (!service)
8772                 return;
8773
8774         if (!service->network)
8775                 return;
8776
8777 #if defined TIZEN_EXT
8778         if (service->storage_reload) {
8779                 service_load(service);
8780                 __connman_service_set_storage_reload(service, false);
8781         }
8782 #endif
8783
8784         name = connman_network_get_string(service->network, "Name");
8785         if (g_strcmp0(service->name, name) != 0) {
8786                 g_free(service->name);
8787                 service->name = g_strdup(name);
8788
8789                 if (allow_property_changed(service))
8790                         connman_dbus_property_changed_basic(service->path,
8791                                         CONNMAN_SERVICE_INTERFACE, "Name",
8792                                         DBUS_TYPE_STRING, &service->name);
8793         }
8794
8795         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8796                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
8797
8798         strength = connman_network_get_strength(service->network);
8799         if (strength == service->strength)
8800                 goto roaming;
8801
8802         service->strength = strength;
8803         need_sort = true;
8804
8805         strength_changed(service);
8806
8807 roaming:
8808         roaming = connman_network_get_bool(service->network, "Roaming");
8809         if (roaming == service->roaming)
8810                 goto sorting;
8811
8812         stats_enable = stats_enabled(service);
8813         if (stats_enable)
8814                 stats_stop(service);
8815
8816         service->roaming = roaming;
8817         need_sort = true;
8818
8819         if (stats_enable)
8820                 stats_start(service);
8821
8822         roaming_changed(service);
8823
8824 sorting:
8825         if (need_sort) {
8826                 service_list_sort();
8827         }
8828 }
8829
8830 void __connman_service_remove_from_network(struct connman_network *network)
8831 {
8832         struct connman_service *service;
8833
8834         service = connman_service_lookup_from_network(network);
8835
8836         DBG("network %p service %p", network, service);
8837
8838         if (!service)
8839                 return;
8840
8841         service->ignore = true;
8842
8843         __connman_connection_gateway_remove(service,
8844                                         CONNMAN_IPCONFIG_TYPE_ALL);
8845
8846         connman_service_unref(service);
8847 }
8848
8849 /**
8850  * __connman_service_create_from_provider:
8851  * @provider: provider structure
8852  *
8853  * Look up service by provider and if not found, create one
8854  */
8855 struct connman_service *
8856 __connman_service_create_from_provider(struct connman_provider *provider)
8857 {
8858         struct connman_service *service;
8859         const char *ident, *str;
8860         char *name;
8861         int index = connman_provider_get_index(provider);
8862
8863         DBG("provider %p", provider);
8864
8865         ident = __connman_provider_get_ident(provider);
8866         if (!ident)
8867                 return NULL;
8868
8869         name = g_strdup_printf("vpn_%s", ident);
8870         service = service_get(name);
8871         g_free(name);
8872
8873         if (!service)
8874                 return NULL;
8875
8876         service->type = CONNMAN_SERVICE_TYPE_VPN;
8877         service->provider = connman_provider_ref(provider);
8878         service->autoconnect = false;
8879         service->favorite = true;
8880
8881         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8882         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8883
8884         str = connman_provider_get_string(provider, "Name");
8885         if (str) {
8886                 g_free(service->name);
8887                 service->name = g_strdup(str);
8888                 service->hidden = false;
8889         } else {
8890                 g_free(service->name);
8891                 service->name = NULL;
8892                 service->hidden = true;
8893         }
8894
8895         service->strength = 0;
8896
8897         if (!service->ipconfig_ipv4)
8898                 service->ipconfig_ipv4 = create_ip4config(service, index,
8899                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
8900
8901         if (!service->ipconfig_ipv6)
8902                 service->ipconfig_ipv6 = create_ip6config(service, index);
8903
8904         service_register(service);
8905
8906         __connman_notifier_service_add(service, service->name);
8907         service_schedule_added(service);
8908
8909         return service;
8910 }
8911
8912 static void remove_unprovisioned_services(void)
8913 {
8914         gchar **services;
8915         GKeyFile *keyfile, *configkeyfile;
8916         char *file, *section;
8917         int i = 0;
8918
8919         services = connman_storage_get_services();
8920         if (!services)
8921                 return;
8922
8923         for (; services[i]; i++) {
8924                 file = section = NULL;
8925                 keyfile = configkeyfile = NULL;
8926
8927                 keyfile = connman_storage_load_service(services[i]);
8928                 if (!keyfile)
8929                         continue;
8930
8931                 file = g_key_file_get_string(keyfile, services[i],
8932                                         "Config.file", NULL);
8933                 if (!file)
8934                         goto next;
8935
8936                 section = g_key_file_get_string(keyfile, services[i],
8937                                         "Config.ident", NULL);
8938                 if (!section)
8939                         goto next;
8940
8941                 configkeyfile = __connman_storage_load_config(file);
8942                 if (!configkeyfile) {
8943                         /*
8944                          * Config file is missing, remove the provisioned
8945                          * service.
8946                          */
8947                         __connman_storage_remove_service(services[i]);
8948                         goto next;
8949                 }
8950
8951                 if (!g_key_file_has_group(configkeyfile, section))
8952                         /*
8953                          * Config section is missing, remove the provisioned
8954                          * service.
8955                          */
8956                         __connman_storage_remove_service(services[i]);
8957
8958         next:
8959                 if (keyfile)
8960                         g_key_file_free(keyfile);
8961
8962                 if (configkeyfile)
8963                         g_key_file_free(configkeyfile);
8964
8965                 g_free(section);
8966                 g_free(file);
8967         }
8968
8969         g_strfreev(services);
8970 }
8971
8972 static int agent_probe(struct connman_agent *agent)
8973 {
8974         DBG("agent %p", agent);
8975         return 0;
8976 }
8977
8978 static void agent_remove(struct connman_agent *agent)
8979 {
8980         DBG("agent %p", agent);
8981 }
8982
8983 static void *agent_context_ref(void *context)
8984 {
8985         struct connman_service *service = context;
8986
8987         return (void *)connman_service_ref(service);
8988 }
8989
8990 static void agent_context_unref(void *context)
8991 {
8992         struct connman_service *service = context;
8993
8994         connman_service_unref(service);
8995 }
8996
8997 static struct connman_agent_driver agent_driver = {
8998         .name           = "service",
8999         .interface      = CONNMAN_AGENT_INTERFACE,
9000         .probe          = agent_probe,
9001         .remove         = agent_remove,
9002         .context_ref    = agent_context_ref,
9003         .context_unref  = agent_context_unref,
9004 };
9005
9006 int __connman_service_init(void)
9007 {
9008         int err;
9009
9010         DBG("");
9011
9012         err = connman_agent_driver_register(&agent_driver);
9013         if (err < 0) {
9014                 connman_error("Cannot register agent driver for %s",
9015                                                 agent_driver.name);
9016                 return err;
9017         }
9018
9019         connection = connman_dbus_get_connection();
9020
9021         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
9022                                                         NULL, service_free);
9023
9024         services_notify = g_new0(struct _services_notify, 1);
9025         services_notify->remove = g_hash_table_new_full(g_str_hash,
9026                         g_str_equal, g_free, NULL);
9027         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
9028
9029         remove_unprovisioned_services();
9030
9031         return 0;
9032 }
9033
9034 void __connman_service_cleanup(void)
9035 {
9036         DBG("");
9037
9038         if (vpn_autoconnect_timeout) {
9039                 g_source_remove(vpn_autoconnect_timeout);
9040                 vpn_autoconnect_timeout = 0;
9041         }
9042
9043         if (autoconnect_timeout != 0) {
9044                 g_source_remove(autoconnect_timeout);
9045                 autoconnect_timeout = 0;
9046         }
9047
9048         connman_agent_driver_unregister(&agent_driver);
9049
9050         g_list_free(service_list);
9051         service_list = NULL;
9052
9053         g_hash_table_destroy(service_hash);
9054         service_hash = NULL;
9055
9056         g_slist_free(counter_list);
9057         counter_list = NULL;
9058
9059         if (services_notify->id != 0) {
9060                 g_source_remove(services_notify->id);
9061                 service_send_changed(NULL);
9062                 g_hash_table_destroy(services_notify->remove);
9063                 g_hash_table_destroy(services_notify->add);
9064         }
9065         g_free(services_notify);
9066
9067         dbus_connection_unref(connection);
9068 }