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