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