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