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