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