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