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