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