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