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