Fix derefrencing of NULL pointer
[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
8559         if (default_connecting_device == NULL)
8560                 return;
8561
8562         default_device = connman_network_get_device(
8563                         __connman_service_get_network(service));
8564
8565         DBG("Disconnecting service %p %s", service, service->path);
8566         DBG("Disconnecting device %p %p %s",
8567                         default_connecting_device,
8568                         default_device,
8569                         connman_device_get_string(default_device, "Name"));
8570
8571         if (default_connecting_device == default_device)
8572                 default_connecting_device = NULL;
8573 }
8574
8575 #if defined TIZEN_MAINTAIN_ONLINE
8576 static void __connman_service_connect_default(struct connman_service *current,
8577                                                                   enum connman_service_state old_state)
8578 #else
8579 static void __connman_service_connect_default(struct connman_service *current)
8580 #endif
8581 {
8582         int err;
8583         GList *list;
8584         bool default_internet;
8585         struct connman_service *service;
8586         struct connman_service *default_service = NULL;
8587         struct connman_device *default_device = NULL;
8588
8589         if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
8590                 switch (current->state) {
8591                 case CONNMAN_SERVICE_STATE_UNKNOWN:
8592                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
8593                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
8594                         return;
8595                 default:
8596                         break;
8597                 }
8598
8599                 if (default_connecting_device &&
8600                                 __connman_service_is_internet_profile(current) == TRUE) {
8601                         if (current->network == NULL)
8602                                 return;
8603
8604                         default_device = connman_network_get_device(current->network);
8605                         if (default_connecting_device == default_device) {
8606                                 DBG("Cellular service[%s]  %p %s",
8607                                                 state2string(current->state), current, current->path);
8608                                 DBG("Cellular device %p %p %s",
8609                                                 default_connecting_device, default_device,
8610                                                 connman_device_get_string(default_device, "Name"));
8611
8612                                 default_connecting_device = NULL;
8613                         }
8614                 }
8615
8616                 return;
8617 #if defined TIZEN_MAINTAIN_ONLINE
8618         } else if (current->state == CONNMAN_SERVICE_STATE_READY &&
8619                            old_state == CONNMAN_SERVICE_STATE_ONLINE) {
8620                 DBG("Device is downgraded: online --> ready");
8621 #endif
8622         } else if (is_connected(current->state) == TRUE || is_connecting(current->state) == TRUE)
8623                 return;
8624
8625         /* Always-on: keep default cellular connection as possible */
8626         for (list = service_list; list; list = list->next) {
8627                 service = list->data;
8628
8629                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
8630                                 __connman_service_is_internet_profile(service) != TRUE ||
8631                                 service->network == NULL) {
8632                         continue;
8633                 }
8634
8635                 default_internet =
8636                                 connman_network_get_bool(service->network, "DefaultInternet");
8637
8638                 DBG("service: %p %s %s %s (default: %d)", service, service->name,
8639                                 __connman_service_type2string(service->type),
8640                                 state2string(service->state), default_internet);
8641
8642                 if (default_internet) {
8643                         default_service = service;
8644                         if (is_connected(default_service->state) == TRUE ||
8645                                         is_connecting(default_service->state) == TRUE)
8646                                 return;
8647
8648                         default_device = connman_network_get_device(default_service->network);
8649                         if (default_connecting_device == default_device) {
8650                                 DBG("Device is connecting (%p)", default_connecting_device);
8651                                 return;
8652                         }
8653
8654                         default_connecting_device = default_device;
8655                         default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
8656
8657                         err = __connman_network_connect(default_service->network);
8658                         DBG("Connecting default service %p %s [%d]",
8659                                         default_service, default_service->path, err);
8660                         DBG("Connecting device %p %s", default_connecting_device,
8661                                         connman_device_get_string(default_connecting_device, "Name"));
8662                         if (err < 0 && err != -EINPROGRESS) {
8663                                 default_connecting_device = NULL;
8664                         } else
8665                                 break;
8666                 }
8667         }
8668 }
8669 #endif
8670
8671 static void single_connected_tech(struct connman_service *allowed)
8672 {
8673         struct connman_service *service;
8674         GSList *services = NULL, *list;
8675         GList *iter;
8676
8677         DBG("keeping %p %s", allowed, allowed->path);
8678
8679 #if defined TIZEN_EXT
8680         if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR)
8681                 return;
8682 #endif
8683
8684         for (iter = service_list; iter; iter = iter->next) {
8685                 service = iter->data;
8686
8687 #if defined TIZEN_EXT
8688                 if (service != allowed && service->type != allowed->type &&
8689                                 __connman_service_can_drop(service) == TRUE)
8690 #else
8691                 if (!is_connected(service->state))
8692                         break;
8693
8694                 if (service == allowed)
8695                         continue;
8696 #endif
8697
8698                 services = g_slist_prepend(services, service);
8699         }
8700
8701         for (list = services; list; list = list->next) {
8702                 service = list->data;
8703
8704                 DBG("disconnecting %p %s", service, service->path);
8705 #if defined TIZEN_EXT
8706                 __connman_service_disconnect_default(service);
8707 #endif
8708                 __connman_service_disconnect(service);
8709         }
8710
8711         g_slist_free(services);
8712 }
8713
8714 #if defined TIZEN_EXT
8715 static void set_priority_connected_service(void)
8716 {
8717         struct connman_service *service;
8718         GList *list;
8719
8720         for (list = service_list; list; list = list->next) {
8721                 service = list->data;
8722
8723                 if (is_connected(service->state) == FALSE)
8724                         service->order = 5;
8725                 else
8726 #if defined TIZEN_MAINTAIN_ONLINE
8727                 {
8728                         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
8729                                 service->state == CONNMAN_SERVICE_STATE_ONLINE)
8730                                 service->order = 6;
8731                         else if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
8732                                 service->order = 6;
8733                         else
8734                                 service->order = 5;
8735                 }
8736 #else
8737                         service->order = 6;
8738 #endif
8739         }
8740 }
8741 #endif
8742
8743 static const char *get_dbus_sender(struct connman_service *service)
8744 {
8745         if (!service->pending)
8746                 return NULL;
8747
8748         return dbus_message_get_sender(service->pending);
8749 }
8750
8751 static int service_indicate_state(struct connman_service *service)
8752 {
8753         enum connman_service_state old_state, new_state;
8754         struct connman_service *def_service;
8755         enum connman_ipconfig_method method;
8756         int result;
8757
8758         if (!service)
8759                 return -EINVAL;
8760
8761         old_state = service->state;
8762         new_state = combine_state(service->state_ipv4, service->state_ipv6);
8763
8764         DBG("service %p old %s - new %s/%s => %s",
8765                                         service,
8766                                         state2string(old_state),
8767                                         state2string(service->state_ipv4),
8768                                         state2string(service->state_ipv6),
8769                                         state2string(new_state));
8770
8771         if (old_state == new_state)
8772                 return -EALREADY;
8773
8774         def_service = connman_service_get_default();
8775
8776         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
8777                 result = service_update_preferred_order(def_service,
8778                                 service, new_state);
8779                 if (result == -EALREADY)
8780                         return result;
8781         }
8782
8783         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
8784                 __connman_notifier_leave_online(service->type);
8785
8786         if (is_connected(old_state) && !is_connected(new_state))
8787                 searchdomain_remove_all(service);
8788
8789         service->state = new_state;
8790 #if defined TIZEN_EXT
8791         if (!is_connected(old_state) && is_connected(new_state))
8792                 connman_device_send_connected_signal(
8793                                 connman_network_get_device(service->network), true);
8794         else if (is_connected(old_state) && !is_connected(new_state))
8795                 connman_device_send_connected_signal(
8796                                 connman_network_get_device(service->network), false);
8797 #endif
8798         state_changed(service);
8799
8800         if (!is_connected(old_state) && is_connected(new_state))
8801                 searchdomain_add_all(service);
8802
8803         switch(new_state) {
8804         case CONNMAN_SERVICE_STATE_UNKNOWN:
8805
8806                 break;
8807
8808         case CONNMAN_SERVICE_STATE_IDLE:
8809                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
8810                         __connman_service_disconnect(service);
8811
8812                 break;
8813
8814         case CONNMAN_SERVICE_STATE_ASSOCIATION:
8815
8816                 break;
8817
8818         case CONNMAN_SERVICE_STATE_CONFIGURATION:
8819                 if (!service->new_service &&
8820                                 __connman_stats_service_register(service) == 0) {
8821                         /*
8822                          * For new services the statistics are updated after
8823                          * we have successfully connected.
8824                          */
8825                         __connman_stats_get(service, false,
8826                                                 &service->stats.data);
8827                         __connman_stats_get(service, true,
8828                                                 &service->stats_roaming.data);
8829                 }
8830
8831                 break;
8832
8833         case CONNMAN_SERVICE_STATE_READY:
8834                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
8835
8836                 if (service->new_service &&
8837                                 __connman_stats_service_register(service) == 0) {
8838                         /*
8839                          * This is normally done after configuring state
8840                          * but for new service do this after we have connected
8841                          * successfully.
8842                          */
8843                         __connman_stats_get(service, false,
8844                                                 &service->stats.data);
8845                         __connman_stats_get(service, true,
8846                                                 &service->stats_roaming.data);
8847                 }
8848
8849                 service->new_service = false;
8850
8851                 default_changed();
8852
8853                 def_service = connman_service_get_default();
8854
8855                 service_update_preferred_order(def_service, service, new_state);
8856
8857                 __connman_service_set_favorite(service, true);
8858
8859                 reply_pending(service, 0);
8860
8861                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
8862                         connman_network_get_bool(service->network,
8863                                                 "WiFi.UseWPS")) {
8864                         const char *pass;
8865
8866                         pass = connman_network_get_string(service->network,
8867                                                         "WiFi.Passphrase");
8868
8869                         __connman_service_set_passphrase(service, pass);
8870
8871                         connman_network_set_bool(service->network,
8872                                                         "WiFi.UseWPS", false);
8873                 }
8874
8875                 g_get_current_time(&service->modified);
8876                 service_save(service);
8877
8878                 domain_changed(service);
8879                 proxy_changed(service);
8880
8881                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
8882                         __connman_notifier_connect(service->type);
8883
8884                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
8885                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
8886                         __connman_ipconfig_disable_ipv6(
8887                                                 service->ipconfig_ipv6);
8888
8889 #if !defined TIZEN_MAINTAIN_ONLINE
8890                 if (connman_setting_get_bool("SingleConnectedTechnology"))
8891                         single_connected_tech(service);
8892                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
8893                         vpn_auto_connect();
8894 #else
8895                 if (service->type != CONNMAN_SERVICE_TYPE_VPN)
8896                         vpn_auto_connect();
8897 #endif
8898
8899 #if defined TIZEN_EXT
8900                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8901                         set_priority_connected_service();
8902 #endif
8903
8904                 break;
8905
8906         case CONNMAN_SERVICE_STATE_ONLINE:
8907 #if defined TIZEN_MAINTAIN_ONLINE
8908 #if defined TIZEN_EXT
8909                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8910                         set_priority_connected_service();
8911 #endif
8912
8913                 if (connman_setting_get_bool("SingleConnectedTechnology"))
8914                         single_connected_tech(service);
8915 #endif
8916
8917 #if defined TIZEN_EXT
8918                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8919                         connman_service_set_internet_connection(service, true);
8920 #endif
8921                 break;
8922
8923         case CONNMAN_SERVICE_STATE_DISCONNECT:
8924                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
8925
8926                 reply_pending(service, ECONNABORTED);
8927
8928                 default_changed();
8929
8930                 __connman_wispr_stop(service);
8931
8932                 __connman_wpad_stop(service);
8933
8934 #if defined TIZEN_EXT
8935                 /**
8936                  * Skip the functions if there is any connected profiles
8937                  * that use same interface
8938                  */
8939                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
8940                         __connman_service_get_connected_count_of_iface(
8941                                                         service) <= 0) {
8942 #endif
8943                 domain_changed(service);
8944                 proxy_changed(service);
8945 #if defined TIZEN_EXT
8946                 }
8947 #endif
8948
8949                 /*
8950                  * Previous services which are connected and which states
8951                  * are set to online should reset relevantly ipconfig_state
8952                  * to ready so wispr/portal will be rerun on those
8953                  */
8954                 downgrade_connected_services();
8955
8956                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8957                 break;
8958
8959         case CONNMAN_SERVICE_STATE_FAILURE:
8960 #if defined TIZEN_EXT
8961                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8962                         service->order = 5;
8963                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8964 #endif
8965                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
8966                         connman_agent_report_error(service, service->path,
8967                                                 error2string(service->error),
8968                                                 report_error_cb,
8969                                                 get_dbus_sender(service),
8970                                                 NULL);
8971                 }
8972                 service_complete(service);
8973                 break;
8974         }
8975
8976         service_list_sort();
8977
8978 #if defined TIZEN_EXT
8979 #if defined TIZEN_MAINTAIN_ONLINE
8980         __connman_service_connect_default(service, old_state);
8981 #else
8982         __connman_service_connect_default(service);
8983 #endif
8984 #endif
8985
8986         __connman_connection_update_gateway();
8987
8988         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
8989                         new_state != CONNMAN_SERVICE_STATE_READY) ||
8990                 (old_state == CONNMAN_SERVICE_STATE_READY &&
8991                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
8992                 __connman_notifier_disconnect(service->type);
8993         }
8994
8995         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
8996                 __connman_notifier_enter_online(service->type);
8997                 default_changed();
8998         }
8999
9000         return 0;
9001 }
9002
9003 int __connman_service_indicate_error(struct connman_service *service,
9004                                         enum connman_service_error error)
9005 {
9006         DBG("service %p error %d", service, error);
9007
9008         if (!service)
9009                 return -EINVAL;
9010
9011         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
9012                 return -EALREADY;
9013
9014         set_error(service, error);
9015
9016 /* default internet service: fix not cleared if pdp activation*/
9017 #if defined TIZEN_EXT
9018                 /*
9019                  * If connection failed for default service(DefaultInternet),
9020                  * default_connecting_device should be cleared.
9021                  */
9022                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
9023                                 service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED)
9024                         __connman_service_disconnect_default(service);
9025
9026                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
9027                                 service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) {
9028                         g_free(service->passphrase);
9029                         service->passphrase = NULL;
9030                 }
9031 #endif
9032
9033         __connman_service_ipconfig_indicate_state(service,
9034                                                 CONNMAN_SERVICE_STATE_FAILURE,
9035                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
9036         __connman_service_ipconfig_indicate_state(service,
9037                                                 CONNMAN_SERVICE_STATE_FAILURE,
9038                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
9039         return 0;
9040 }
9041
9042 int __connman_service_clear_error(struct connman_service *service)
9043 {
9044         DBusMessage *pending, *provider_pending;
9045
9046         DBG("service %p", service);
9047
9048         if (!service)
9049                 return -EINVAL;
9050
9051         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
9052                 return -EINVAL;
9053
9054         pending = service->pending;
9055         service->pending = NULL;
9056         provider_pending = service->provider_pending;
9057         service->provider_pending = NULL;
9058
9059         __connman_service_ipconfig_indicate_state(service,
9060                                                 CONNMAN_SERVICE_STATE_IDLE,
9061                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
9062
9063         __connman_service_ipconfig_indicate_state(service,
9064                                                 CONNMAN_SERVICE_STATE_IDLE,
9065                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
9066
9067         service->pending = pending;
9068         service->provider_pending = provider_pending;
9069
9070         return 0;
9071 }
9072
9073 int __connman_service_indicate_default(struct connman_service *service)
9074 {
9075         DBG("service %p state %s", service, state2string(service->state));
9076
9077         if (!is_connected(service->state)) {
9078                 /*
9079                  * If service is not yet fully connected, then we must not
9080                  * change the default yet. The default gw will be changed
9081                  * after the service state is in ready.
9082                  */
9083                 return -EINPROGRESS;
9084         }
9085
9086         default_changed();
9087
9088         return 0;
9089 }
9090
9091 enum connman_service_state __connman_service_ipconfig_get_state(
9092                                         struct connman_service *service,
9093                                         enum connman_ipconfig_type type)
9094 {
9095         if (!service)
9096                 return CONNMAN_SERVICE_STATE_UNKNOWN;
9097
9098         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9099                 return service->state_ipv4;
9100
9101         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
9102                 return service->state_ipv6;
9103
9104         return CONNMAN_SERVICE_STATE_UNKNOWN;
9105 }
9106
9107 static void check_proxy_setup(struct connman_service *service)
9108 {
9109         /*
9110          * We start WPAD if we haven't got a PAC URL from DHCP and
9111          * if our proxy manual configuration is either empty or set
9112          * to AUTO with an empty URL.
9113          */
9114
9115         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
9116                 goto done;
9117
9118         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
9119                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
9120                         service->pac))
9121                 goto done;
9122
9123         if (__connman_wpad_start(service) < 0) {
9124                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
9125                 __connman_notifier_proxy_changed(service);
9126                 goto done;
9127         }
9128
9129         return;
9130
9131 done:
9132         __connman_service_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
9133 }
9134
9135 #if defined TIZEN_EXT
9136 void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
9137
9138         DBG("check the proxy and start wispr");
9139         check_proxy_setup(service);
9140         return;
9141 }
9142 #endif
9143
9144 /*
9145  * How many networks are connected at the same time. If more than 1,
9146  * then set the rp_filter setting properly (loose mode routing) so that network
9147  * connectivity works ok. This is only done for IPv4 networks as IPv6
9148  * does not have rp_filter knob.
9149  */
9150 static int connected_networks_count;
9151 static int original_rp_filter;
9152
9153 static void service_rp_filter(struct connman_service *service,
9154                                 bool connected)
9155 {
9156         enum connman_ipconfig_method method;
9157
9158         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
9159
9160         switch (method) {
9161         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
9162         case CONNMAN_IPCONFIG_METHOD_OFF:
9163         case CONNMAN_IPCONFIG_METHOD_AUTO:
9164                 return;
9165         case CONNMAN_IPCONFIG_METHOD_FIXED:
9166         case CONNMAN_IPCONFIG_METHOD_MANUAL:
9167         case CONNMAN_IPCONFIG_METHOD_DHCP:
9168                 break;
9169         }
9170
9171         if (connected) {
9172                 if (connected_networks_count == 1) {
9173                         int filter_value;
9174                         filter_value = __connman_ipconfig_set_rp_filter();
9175                         if (filter_value < 0)
9176                                 return;
9177
9178                         original_rp_filter = filter_value;
9179                 }
9180                 connected_networks_count++;
9181
9182         } else {
9183                 if (connected_networks_count == 2)
9184                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
9185
9186                 connected_networks_count--;
9187                 if (connected_networks_count < 0)
9188                         connected_networks_count = 0;
9189         }
9190
9191         DBG("%s %s ipconfig %p method %d count %d filter %d",
9192                 connected ? "connected" : "disconnected", service->identifier,
9193                 service->ipconfig_ipv4, method,
9194                 connected_networks_count, original_rp_filter);
9195 }
9196
9197 static void redo_wispr(struct connman_service *service,
9198                                         enum connman_ipconfig_type type)
9199 {
9200         service->online_timeout = 0;
9201         connman_service_unref(service);
9202
9203         DBG("Retrying %s WISPr for %p %s",
9204                 __connman_ipconfig_type2string(type),
9205                 service, service->name);
9206
9207         __connman_wispr_start(service, type);
9208 }
9209
9210 static gboolean redo_wispr_ipv4(gpointer user_data)
9211 {
9212         struct connman_service *service = user_data;
9213
9214         redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV4);
9215
9216         return FALSE;
9217 }
9218
9219 static gboolean redo_wispr_ipv6(gpointer user_data)
9220 {
9221         struct connman_service *service = user_data;
9222
9223         redo_wispr(service, CONNMAN_IPCONFIG_TYPE_IPV6);
9224
9225         return FALSE;
9226 }
9227
9228 #if defined TIZEN_MAINTAIN_ONLINE
9229 static gboolean redo_wispr_ipv4(gpointer user_data)
9230 {
9231         struct connman_service *service = user_data;
9232
9233         DBG("");
9234
9235         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
9236
9237         return FALSE;
9238 }
9239 #endif
9240
9241 int __connman_service_online_check_failed(struct connman_service *service,
9242                                         enum connman_ipconfig_type type)
9243 {
9244         GSourceFunc redo_func;
9245         int *interval;
9246
9247         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
9248                 interval = &service->online_check_interval_ipv4;
9249                 redo_func = redo_wispr_ipv4;
9250         } else {
9251                 interval = &service->online_check_interval_ipv6;
9252                 redo_func = redo_wispr_ipv6;
9253         }
9254
9255         DBG("service %p type %s interval %d", service,
9256                 __connman_ipconfig_type2string(type), *interval);
9257
9258         service->online_timeout = g_timeout_add_seconds(*interval * *interval,
9259                                 redo_func, connman_service_ref(service));
9260
9261         /* Increment the interval for the next time, set a maximum timeout of
9262          * ONLINE_CHECK_MAX_INTERVAL * ONLINE_CHECK_MAX_INTERVAL seconds.
9263          */
9264         if (*interval < ONLINE_CHECK_MAX_INTERVAL)
9265                 (*interval)++;
9266
9267         return EAGAIN;
9268 }
9269
9270 static void cancel_online_check(struct connman_service *service)
9271 {
9272         if (service->online_timeout == 0)
9273                 return;
9274
9275         g_source_remove(service->online_timeout);
9276         service->online_timeout = 0;
9277         connman_service_unref(service);
9278 }
9279
9280 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
9281                                         enum connman_service_state new_state,
9282                                         enum connman_ipconfig_type type)
9283 {
9284         struct connman_ipconfig *ipconfig = NULL;
9285         enum connman_service_state old_state;
9286         enum connman_ipconfig_method method;
9287
9288         if (!service)
9289                 return -EINVAL;
9290
9291         switch (type) {
9292         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
9293         case CONNMAN_IPCONFIG_TYPE_ALL:
9294                 return -EINVAL;
9295
9296         case CONNMAN_IPCONFIG_TYPE_IPV4:
9297                 old_state = service->state_ipv4;
9298                 ipconfig = service->ipconfig_ipv4;
9299
9300                 break;
9301
9302         case CONNMAN_IPCONFIG_TYPE_IPV6:
9303                 old_state = service->state_ipv6;
9304                 ipconfig = service->ipconfig_ipv6;
9305
9306                 break;
9307         }
9308
9309         if (!ipconfig)
9310                 return -EINVAL;
9311
9312         method = __connman_ipconfig_get_method(ipconfig);
9313
9314         switch (method) {
9315         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
9316         case CONNMAN_IPCONFIG_METHOD_OFF:
9317                 if (new_state != CONNMAN_SERVICE_STATE_IDLE)
9318                         connman_warn("ipconfig state %d ipconfig method %d",
9319                                 new_state, method);
9320
9321 #if defined TIZEN_EXT
9322                 if (old_state != CONNMAN_SERVICE_STATE_READY &&
9323                                 old_state != CONNMAN_SERVICE_STATE_ONLINE)
9324 #endif
9325                 new_state = CONNMAN_SERVICE_STATE_IDLE;
9326                 break;
9327
9328         case CONNMAN_IPCONFIG_METHOD_FIXED:
9329         case CONNMAN_IPCONFIG_METHOD_MANUAL:
9330         case CONNMAN_IPCONFIG_METHOD_DHCP:
9331         case CONNMAN_IPCONFIG_METHOD_AUTO:
9332                 break;
9333
9334         }
9335
9336         /* Any change? */
9337         if (old_state == new_state)
9338                 return -EALREADY;
9339
9340 #if defined TIZEN_EXT
9341         __sync_synchronize();
9342         if (service->user_pdn_connection_refcount > 0 &&
9343                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
9344                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
9345                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
9346                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
9347                         service->user_pdn_connection_refcount = 0;
9348                         __sync_synchronize();
9349                 }
9350 #endif
9351
9352         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
9353                 service, service ? service->identifier : NULL,
9354                 old_state, state2string(old_state),
9355                 new_state, state2string(new_state),
9356                 type, __connman_ipconfig_type2string(type));
9357
9358         switch (new_state) {
9359         case CONNMAN_SERVICE_STATE_UNKNOWN:
9360         case CONNMAN_SERVICE_STATE_ASSOCIATION:
9361                 break;
9362         case CONNMAN_SERVICE_STATE_CONFIGURATION:
9363                 break;
9364         case CONNMAN_SERVICE_STATE_READY:
9365 #if defined TIZEN_EXT
9366                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
9367                                 __connman_service_is_internet_profile(service) != TRUE) {
9368                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9369                                 service_rp_filter(service, TRUE);
9370
9371                         break;
9372                 }
9373 #endif
9374                 if (connman_setting_get_bool("EnableOnlineCheck"))
9375                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
9376 #if !defined TIZEN_EXT
9377                                 check_proxy_setup(service);
9378 #endif
9379 #if defined TIZEN_MAINTAIN_ONLINE
9380 /*                              if (old_state == CONNMAN_SERVICE_STATE_ONLINE) */
9381                                         check_proxy_setup(service);
9382 #endif
9383                         } else {
9384                                 __connman_service_wispr_start(service, type);
9385                         }
9386                 else
9387                         connman_info("Online check disabled. "
9388                                 "Default service remains in READY state.");
9389                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9390                         service_rp_filter(service, true);
9391                 set_mdns(service, service->mdns_config);
9392                 break;
9393         case CONNMAN_SERVICE_STATE_ONLINE:
9394                 break;
9395         case CONNMAN_SERVICE_STATE_DISCONNECT:
9396                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
9397                         return -EINVAL;
9398
9399                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9400                         service_rp_filter(service, false);
9401
9402                 break;
9403
9404         case CONNMAN_SERVICE_STATE_IDLE:
9405         case CONNMAN_SERVICE_STATE_FAILURE:
9406                 __connman_ipconfig_disable(ipconfig);
9407
9408                 break;
9409         }
9410
9411         if (is_connected(old_state) && !is_connected(new_state)) {
9412                 nameserver_remove_all(service, type);
9413                 cancel_online_check(service);
9414         }
9415
9416         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
9417                 service->state_ipv4 = new_state;
9418         else
9419                 service->state_ipv6 = new_state;
9420
9421         if (!is_connected(old_state) && is_connected(new_state))
9422                 nameserver_add_all(service, type);
9423
9424         __connman_timeserver_sync(service);
9425
9426 #if defined TIZEN_EXT
9427         int ret = service_indicate_state(service);
9428         /*Sent the Ready changed signal again in case IPv4 IP set
9429           after IPv6 IP set*/
9430
9431         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
9432                         && new_state == CONNMAN_SERVICE_STATE_READY) {
9433                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
9434                 state_changed(service);
9435         }
9436
9437         return ret;
9438 #endif
9439         return service_indicate_state(service);
9440 }
9441
9442 static bool prepare_network(struct connman_service *service)
9443 {
9444         enum connman_network_type type;
9445         unsigned int ssid_len;
9446
9447         type = connman_network_get_type(service->network);
9448
9449         switch (type) {
9450         case CONNMAN_NETWORK_TYPE_UNKNOWN:
9451         case CONNMAN_NETWORK_TYPE_VENDOR:
9452                 return false;
9453         case CONNMAN_NETWORK_TYPE_WIFI:
9454                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
9455                                                 &ssid_len))
9456                         return false;
9457
9458                 if (service->passphrase)
9459                         connman_network_set_string(service->network,
9460                                 "WiFi.Passphrase", service->passphrase);
9461                 break;
9462         case CONNMAN_NETWORK_TYPE_ETHERNET:
9463         case CONNMAN_NETWORK_TYPE_GADGET:
9464         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
9465         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
9466         case CONNMAN_NETWORK_TYPE_CELLULAR:
9467                 break;
9468         }
9469
9470         return true;
9471 }
9472
9473 static void prepare_8021x(struct connman_service *service)
9474 {
9475         if (service->eap)
9476                 connman_network_set_string(service->network, "WiFi.EAP",
9477                                                                 service->eap);
9478
9479         if (service->identity)
9480                 connman_network_set_string(service->network, "WiFi.Identity",
9481                                                         service->identity);
9482
9483         if (service->anonymous_identity)
9484                 connman_network_set_string(service->network,
9485                                                 "WiFi.AnonymousIdentity",
9486                                                 service->anonymous_identity);
9487
9488         if (service->ca_cert_file)
9489                 connman_network_set_string(service->network, "WiFi.CACertFile",
9490                                                         service->ca_cert_file);
9491
9492         if (service->subject_match)
9493                 connman_network_set_string(service->network, "WiFi.SubjectMatch",
9494                                                         service->subject_match);
9495
9496         if (service->altsubject_match)
9497                 connman_network_set_string(service->network, "WiFi.AltSubjectMatch",
9498                                                         service->altsubject_match);
9499
9500         if (service->domain_suffix_match)
9501                 connman_network_set_string(service->network, "WiFi.DomainSuffixMatch",
9502                                                         service->domain_suffix_match);
9503
9504         if (service->domain_match)
9505                 connman_network_set_string(service->network, "WiFi.DomainMatch",
9506                                                         service->domain_match);
9507
9508         if (service->client_cert_file)
9509                 connman_network_set_string(service->network,
9510                                                 "WiFi.ClientCertFile",
9511                                                 service->client_cert_file);
9512
9513         if (service->private_key_file)
9514                 connman_network_set_string(service->network,
9515                                                 "WiFi.PrivateKeyFile",
9516                                                 service->private_key_file);
9517
9518         if (service->private_key_passphrase)
9519                 connman_network_set_string(service->network,
9520                                         "WiFi.PrivateKeyPassphrase",
9521                                         service->private_key_passphrase);
9522
9523         if (service->phase2)
9524                 connman_network_set_string(service->network, "WiFi.Phase2",
9525                                                         service->phase2);
9526
9527 #if defined TIZEN_EXT
9528         if (service->keymgmt_type)
9529                 connman_network_set_string(service->network, "WiFi.KeymgmtType",
9530                                                         service->keymgmt_type);
9531
9532         DBG("service->phase1 : %s", service->phase1);
9533         if (service->phase1)
9534                 connman_network_set_string(service->network, "WiFi.Phase1",
9535                                                         service->phase1);
9536 #endif
9537 }
9538 #if defined TIZEN_EXT
9539
9540 static bool has_valid_configuration_object(struct connman_service *service)
9541 {
9542         return service->connector && service->c_sign_key && service->net_access_key;
9543 }
9544
9545 static void prepare_dpp(struct connman_service *service)
9546 {
9547         DBG("prepare dpp");
9548         if (service->connector)
9549                 connman_network_set_string(service->network, "WiFi.Connector",
9550                                                                 service->connector);
9551
9552         if (service->c_sign_key)
9553                 connman_network_set_string(service->network, "WiFi.CSignKey",
9554                                                         service->c_sign_key);
9555
9556         if (service->net_access_key)
9557                 connman_network_set_string(service->network, "WiFi.NetAccessKey",
9558                                                         service->net_access_key);
9559 }
9560 #endif
9561
9562 static int service_connect(struct connman_service *service)
9563 {
9564         int err;
9565
9566         if (service->hidden)
9567                 return -EPERM;
9568
9569 #if defined TIZEN_EXT
9570         GList *list;
9571         int index;
9572
9573         index = __connman_service_get_index(service);
9574
9575         for (list = service_list; list; list = list->next) {
9576                 struct connman_service *temp = list->data;
9577
9578                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
9579                         break;
9580
9581                 if (!is_connecting(temp->state) && !is_connected(temp->state))
9582                         break;
9583
9584                 if (service == temp)
9585                         continue;
9586
9587                 if (service->type != temp->type)
9588                         continue;
9589
9590                 if (__connman_service_get_index(temp) == index &&
9591                                 __connman_service_disconnect(temp) == -EINPROGRESS)
9592                         return -EINPROGRESS;
9593         }
9594 #endif
9595
9596         switch (service->type) {
9597         case CONNMAN_SERVICE_TYPE_UNKNOWN:
9598         case CONNMAN_SERVICE_TYPE_SYSTEM:
9599         case CONNMAN_SERVICE_TYPE_GPS:
9600         case CONNMAN_SERVICE_TYPE_P2P:
9601 #if defined TIZEN_EXT_WIFI_MESH
9602         case CONNMAN_SERVICE_TYPE_MESH:
9603 #endif
9604                 return -EINVAL;
9605         case CONNMAN_SERVICE_TYPE_ETHERNET:
9606         case CONNMAN_SERVICE_TYPE_GADGET:
9607         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
9608         case CONNMAN_SERVICE_TYPE_CELLULAR:
9609         case CONNMAN_SERVICE_TYPE_VPN:
9610                 break;
9611         case CONNMAN_SERVICE_TYPE_WIFI:
9612                 switch (service->security) {
9613                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
9614                 case CONNMAN_SERVICE_SECURITY_NONE:
9615 #if defined TIZEN_EXT
9616                 case CONNMAN_SERVICE_SECURITY_OWE:
9617 #endif
9618                         break;
9619                 case CONNMAN_SERVICE_SECURITY_WEP:
9620                 case CONNMAN_SERVICE_SECURITY_PSK:
9621                 case CONNMAN_SERVICE_SECURITY_WPA:
9622                 case CONNMAN_SERVICE_SECURITY_RSN:
9623 #if defined TIZEN_EXT
9624                 case CONNMAN_SERVICE_SECURITY_SAE:
9625 #endif
9626                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
9627                                 return -ENOKEY;
9628
9629                         if (!service->passphrase) {
9630                                 if (!service->network)
9631                                         return -EOPNOTSUPP;
9632
9633                                 if (!service->wps ||
9634                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
9635                                         return -ENOKEY;
9636                         }
9637                         break;
9638
9639 #if defined TIZEN_EXT
9640                 case CONNMAN_SERVICE_SECURITY_DPP:
9641                         if (has_valid_configuration_object(service) &&
9642                                         !service->network)
9643                                 return -EINVAL;
9644                         break;
9645 #endif
9646                 case CONNMAN_SERVICE_SECURITY_8021X:
9647                         if (!service->eap) {
9648                                 connman_warn("EAP type has not been found. "
9649                                         "Most likely ConnMan is not able to "
9650                                         "find a configuration for given "
9651                                         "8021X network. "
9652                                         "Check SSID or Name match with the "
9653                                         "network name.");
9654                                 return -EINVAL;
9655                         }
9656
9657 #if defined TIZEN_EXT
9658                         /*
9659                          * never request credentials if using EAP-TLS, EAP-SIM
9660                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
9661                          * need to be fully provisioned)
9662                          */
9663                         DBG("service eap: %s", service->eap);
9664                         if (g_str_equal(service->eap, "tls") ||
9665                                 g_str_equal(service->eap, "sim") ||
9666                                 g_str_equal(service->eap, "aka") ||
9667                                 g_str_equal(service->eap, "aka'") ||
9668                                 g_str_equal(service->eap, "pwd") ||
9669                                 g_str_equal(service->eap, "fast"))
9670                                 break;
9671 #else
9672                         /*
9673                          * never request credentials if using EAP-TLS
9674                          * (EAP-TLS networks need to be fully provisioned)
9675                          */
9676                         if (g_str_equal(service->eap, "tls"))
9677                                 break;
9678
9679 #endif
9680                         /*
9681                          * Return -ENOKEY if either identity or passphrase is
9682                          * missing. Agent provided credentials can be used as
9683                          * fallback if needed.
9684                          */
9685                         if (((!service->identity &&
9686                                         !service->agent_identity) ||
9687                                         !service->passphrase) ||
9688                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
9689                                 return -ENOKEY;
9690
9691                         break;
9692                 }
9693                 break;
9694         }
9695
9696         if (service->network) {
9697                 if (!prepare_network(service))
9698                         return -EINVAL;
9699
9700                 switch (service->security) {
9701                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
9702                 case CONNMAN_SERVICE_SECURITY_NONE:
9703                 case CONNMAN_SERVICE_SECURITY_WEP:
9704                 case CONNMAN_SERVICE_SECURITY_PSK:
9705                 case CONNMAN_SERVICE_SECURITY_WPA:
9706                 case CONNMAN_SERVICE_SECURITY_RSN:
9707 #if defined TIZEN_EXT
9708                 case CONNMAN_SERVICE_SECURITY_SAE:
9709                 case CONNMAN_SERVICE_SECURITY_OWE:
9710                         break;
9711                 case CONNMAN_SERVICE_SECURITY_DPP:
9712                         prepare_dpp(service);
9713 #endif
9714                         break;
9715                 case CONNMAN_SERVICE_SECURITY_8021X:
9716                         prepare_8021x(service);
9717                         break;
9718                 }
9719
9720                 if (__connman_stats_service_register(service) == 0) {
9721                         __connman_stats_get(service, false,
9722                                                 &service->stats.data);
9723                         __connman_stats_get(service, true,
9724                                                 &service->stats_roaming.data);
9725                 }
9726
9727                 err = __connman_network_connect(service->network);
9728         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
9729                                         service->provider)
9730                 err = __connman_provider_connect(service->provider,
9731                                                 get_dbus_sender(service));
9732         else
9733                 return -EOPNOTSUPP;
9734
9735         if (err < 0) {
9736                 if (err != -EINPROGRESS) {
9737                         __connman_service_ipconfig_indicate_state(service,
9738                                                 CONNMAN_SERVICE_STATE_FAILURE,
9739                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
9740                         __connman_service_ipconfig_indicate_state(service,
9741                                                 CONNMAN_SERVICE_STATE_FAILURE,
9742                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
9743                         __connman_stats_service_unregister(service);
9744                 }
9745         }
9746
9747         return err;
9748 }
9749
9750 int __connman_service_connect(struct connman_service *service,
9751                         enum connman_service_connect_reason reason)
9752 {
9753         int err;
9754
9755         DBG("service %p state %s connect reason %s -> %s",
9756                 service, state2string(service->state),
9757                 reason2string(service->connect_reason),
9758                 reason2string(reason));
9759
9760         if (is_connected(service->state))
9761                 return -EISCONN;
9762
9763         if (is_connecting(service->state))
9764                 return -EALREADY;
9765
9766         switch (service->type) {
9767         case CONNMAN_SERVICE_TYPE_UNKNOWN:
9768         case CONNMAN_SERVICE_TYPE_SYSTEM:
9769         case CONNMAN_SERVICE_TYPE_GPS:
9770         case CONNMAN_SERVICE_TYPE_P2P:
9771 #if defined TIZEN_EXT_WIFI_MESH
9772         case CONNMAN_SERVICE_TYPE_MESH:
9773 #endif
9774                 return -EINVAL;
9775
9776         case CONNMAN_SERVICE_TYPE_ETHERNET:
9777         case CONNMAN_SERVICE_TYPE_GADGET:
9778         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
9779         case CONNMAN_SERVICE_TYPE_CELLULAR:
9780         case CONNMAN_SERVICE_TYPE_VPN:
9781         case CONNMAN_SERVICE_TYPE_WIFI:
9782                 break;
9783         }
9784
9785         if (!is_ipconfig_usable(service))
9786                 return -ENOLINK;
9787
9788         __connman_service_clear_error(service);
9789
9790         err = service_connect(service);
9791
9792         DBG("service %p err %d", service, err);
9793
9794         service->connect_reason = reason;
9795 #if defined TIZEN_EXT
9796         connect_reason_changed(service);
9797 #endif
9798
9799         if (err >= 0)
9800                 return 0;
9801
9802         if (err == -EINPROGRESS) {
9803                 if (service->timeout == 0)
9804                         service->timeout = g_timeout_add_seconds(
9805                                 CONNECT_TIMEOUT, connect_timeout, service);
9806
9807                 return -EINPROGRESS;
9808         }
9809
9810         if (service->network)
9811                 __connman_network_disconnect(service->network);
9812         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
9813                                 service->provider)
9814                         connman_provider_disconnect(service->provider);
9815
9816         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
9817                 if (err == -ENOKEY || err == -EPERM) {
9818                         DBusMessage *pending = NULL;
9819                         const char *dbus_sender = get_dbus_sender(service);
9820
9821                         /*
9822                          * We steal the reply here. The idea is that the
9823                          * connecting client will see the connection status
9824                          * after the real hidden network is connected or
9825                          * connection failed.
9826                          */
9827                         if (service->hidden) {
9828                                 pending = service->pending;
9829                                 service->pending = NULL;
9830                         }
9831
9832                         err = __connman_agent_request_passphrase_input(service,
9833                                         request_input_cb,
9834                                         dbus_sender,
9835                                         pending);
9836                         if (service->hidden && err != -EINPROGRESS)
9837                                 service->pending = pending;
9838
9839                         return err;
9840                 }
9841         }
9842
9843         return err;
9844 }
9845
9846 int __connman_service_disconnect(struct connman_service *service)
9847 {
9848         int err;
9849
9850         DBG("service %p", service);
9851
9852         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
9853         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
9854
9855         connman_agent_cancel(service);
9856
9857         __connman_stats_service_unregister(service);
9858
9859         if (service->network) {
9860                 err = __connman_network_disconnect(service->network);
9861         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
9862                                         service->provider)
9863                 err = connman_provider_disconnect(service->provider);
9864         else
9865                 return -EOPNOTSUPP;
9866
9867         if (err < 0 && err != -EINPROGRESS)
9868                 return err;
9869
9870         __connman_6to4_remove(service->ipconfig_ipv4);
9871
9872         if (service->ipconfig_ipv4)
9873                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
9874                                                         NULL);
9875         else
9876                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
9877                                                         NULL);
9878
9879 #if defined TIZEN_EXT
9880         /**
9881           * Skip the functions If there is any connected profiles
9882           * that use same interface
9883           */
9884         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
9885                 __connman_service_get_connected_count_of_iface(service) <= 0) {
9886 #endif
9887         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
9888         settings_changed(service, service->ipconfig_ipv4);
9889
9890         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
9891         settings_changed(service, service->ipconfig_ipv6);
9892
9893         __connman_ipconfig_disable(service->ipconfig_ipv4);
9894         __connman_ipconfig_disable(service->ipconfig_ipv6);
9895 #if defined TIZEN_EXT
9896         }
9897 #endif
9898
9899         return err;
9900 }
9901
9902 int __connman_service_disconnect_all(void)
9903 {
9904         struct connman_service *service;
9905         GSList *services = NULL, *list;
9906         GList *iter;
9907
9908         DBG("");
9909
9910         for (iter = service_list; iter; iter = iter->next) {
9911                 service = iter->data;
9912
9913                 if (!is_connected(service->state))
9914                         break;
9915
9916                 services = g_slist_prepend(services, service);
9917         }
9918
9919         for (list = services; list; list = list->next) {
9920                 struct connman_service *service = list->data;
9921
9922                 service->ignore = true;
9923
9924                 __connman_service_disconnect(service);
9925         }
9926
9927         g_slist_free(services);
9928
9929         return 0;
9930 }
9931
9932 /**
9933  * lookup_by_identifier:
9934  * @identifier: service identifier
9935  *
9936  * Look up a service by identifier (reference count will not be increased)
9937  */
9938 static struct connman_service *lookup_by_identifier(const char *identifier)
9939 {
9940         return g_hash_table_lookup(service_hash, identifier);
9941 }
9942
9943 struct connman_service *connman_service_lookup_from_identifier(const char* identifier)
9944 {
9945         return identifier ? lookup_by_identifier(identifier) : NULL;
9946 }
9947
9948 struct provision_user_data {
9949         const char *ident;
9950         int ret;
9951 };
9952
9953 static void provision_changed(gpointer value, gpointer user_data)
9954 {
9955         struct connman_service *service = value;
9956         struct provision_user_data *data = user_data;
9957         const char *path = data->ident;
9958         int ret;
9959
9960         ret = __connman_config_provision_service_ident(service, path,
9961                         service->config_file, service->config_entry);
9962         if (ret > 0)
9963                 data->ret = ret;
9964 }
9965
9966 int __connman_service_provision_changed(const char *ident)
9967 {
9968         struct provision_user_data data = {
9969                 .ident = ident,
9970                 .ret = 0
9971         };
9972
9973         g_list_foreach(service_list, provision_changed, (void *)&data);
9974
9975         /*
9976          * Because the provision_changed() might have set some services
9977          * as favorite, we must sort the sequence now.
9978          */
9979         if (services_dirty) {
9980                 services_dirty = false;
9981
9982                 service_list_sort();
9983
9984                 __connman_connection_update_gateway();
9985         }
9986
9987         return data.ret;
9988 }
9989
9990 void __connman_service_set_config(struct connman_service *service,
9991                                 const char *file_id, const char *entry)
9992 {
9993         if (!service)
9994                 return;
9995
9996         g_free(service->config_file);
9997         service->config_file = g_strdup(file_id);
9998
9999         g_free(service->config_entry);
10000         service->config_entry = g_strdup(entry);
10001 }
10002
10003 /**
10004  * __connman_service_get:
10005  * @identifier: service identifier
10006  *
10007  * Look up a service by identifier or create a new one if not found
10008  */
10009 static struct connman_service *service_get(const char *identifier)
10010 {
10011         struct connman_service *service;
10012
10013         service = g_hash_table_lookup(service_hash, identifier);
10014         if (service) {
10015                 connman_service_ref(service);
10016                 return service;
10017         }
10018
10019         service = connman_service_create();
10020         if (!service)
10021                 return NULL;
10022 #if defined TIZEN_EXT
10023         if (!simplified_log)
10024 #endif
10025         DBG("service %p", service);
10026
10027         service->identifier = g_strdup(identifier);
10028
10029         service_list = g_list_insert_sorted(service_list, service,
10030                                                 service_compare);
10031
10032         g_hash_table_insert(service_hash, service->identifier, service);
10033
10034         return service;
10035 }
10036
10037 static int service_register(struct connman_service *service)
10038 {
10039 #if defined TIZEN_EXT
10040         if (!simplified_log)
10041 #endif
10042         DBG("service %p", service);
10043
10044         if (service->path)
10045                 return -EALREADY;
10046
10047         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
10048                                                 service->identifier);
10049
10050         DBG("path %s", service->path);
10051
10052 #if defined TIZEN_EXT
10053         int ret;
10054         service_load(service);
10055         ret = service_ext_load(service);
10056         if (ret == -ERANGE)
10057                 service_ext_save(service);
10058         ret = __connman_config_provision_service(service);
10059         if (ret < 0 && !simplified_log)
10060                 DBG("Failed to provision service");
10061 #else
10062         if (__connman_config_provision_service(service) < 0)
10063                 service_load(service);
10064 #endif
10065
10066         g_dbus_register_interface(connection, service->path,
10067                                         CONNMAN_SERVICE_INTERFACE,
10068                                         service_methods, service_signals,
10069                                                         NULL, service, NULL);
10070
10071         service_list_sort();
10072
10073         __connman_connection_update_gateway();
10074
10075         return 0;
10076 }
10077
10078 static void service_up(struct connman_ipconfig *ipconfig,
10079                 const char *ifname)
10080 {
10081         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10082
10083         DBG("%s up", ifname);
10084
10085         link_changed(service);
10086
10087         service->stats.valid = false;
10088         service->stats_roaming.valid = false;
10089 }
10090
10091 static void service_down(struct connman_ipconfig *ipconfig,
10092                         const char *ifname)
10093 {
10094         DBG("%s down", ifname);
10095 }
10096
10097 static void service_lower_up(struct connman_ipconfig *ipconfig,
10098                         const char *ifname)
10099 {
10100         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10101
10102         DBG("%s lower up", ifname);
10103
10104         stats_start(service);
10105 }
10106
10107 static void service_lower_down(struct connman_ipconfig *ipconfig,
10108                         const char *ifname)
10109 {
10110         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10111
10112         DBG("%s lower down", ifname);
10113
10114         stats_stop(service);
10115         service_save(service);
10116 }
10117
10118 static void service_ip_bound(struct connman_ipconfig *ipconfig,
10119                         const char *ifname)
10120 {
10121         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10122         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
10123         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
10124 #if defined TIZEN_EXT
10125         int err;
10126 #endif
10127
10128         DBG("%s ip bound", ifname);
10129
10130         type = __connman_ipconfig_get_config_type(ipconfig);
10131         method = __connman_ipconfig_get_method(ipconfig);
10132
10133         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
10134                                                         type, method);
10135
10136         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
10137                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
10138 #if defined TIZEN_EXT
10139         {
10140                 err = __connman_ipconfig_gateway_add(ipconfig, service);
10141
10142                 if(err < 0)
10143                         DBG("Failed to add gateway");
10144         }
10145 #else
10146                 __connman_service_ipconfig_indicate_state(service,
10147                                                 CONNMAN_SERVICE_STATE_READY,
10148                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
10149 #endif
10150
10151         settings_changed(service, ipconfig);
10152         address_updated(service, type);
10153 }
10154
10155 static void service_ip_release(struct connman_ipconfig *ipconfig,
10156                         const char *ifname)
10157 {
10158         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10159         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
10160         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
10161
10162         DBG("%s ip release", ifname);
10163
10164         type = __connman_ipconfig_get_config_type(ipconfig);
10165         method = __connman_ipconfig_get_method(ipconfig);
10166
10167         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
10168                                                         type, method);
10169
10170         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
10171                         method == CONNMAN_IPCONFIG_METHOD_OFF)
10172                 __connman_service_ipconfig_indicate_state(service,
10173                                         CONNMAN_SERVICE_STATE_DISCONNECT,
10174                                         CONNMAN_IPCONFIG_TYPE_IPV6);
10175
10176         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
10177                         method == CONNMAN_IPCONFIG_METHOD_OFF)
10178                 __connman_service_ipconfig_indicate_state(service,
10179                                         CONNMAN_SERVICE_STATE_DISCONNECT,
10180                                         CONNMAN_IPCONFIG_TYPE_IPV4);
10181
10182         settings_changed(service, ipconfig);
10183 }
10184
10185 static void service_route_changed(struct connman_ipconfig *ipconfig,
10186                                 const char *ifname)
10187 {
10188         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
10189
10190         DBG("%s route changed", ifname);
10191
10192         settings_changed(service, ipconfig);
10193 }
10194
10195 static const struct connman_ipconfig_ops service_ops = {
10196         .up             = service_up,
10197         .down           = service_down,
10198         .lower_up       = service_lower_up,
10199         .lower_down     = service_lower_down,
10200         .ip_bound       = service_ip_bound,
10201         .ip_release     = service_ip_release,
10202         .route_set      = service_route_changed,
10203         .route_unset    = service_route_changed,
10204 };
10205
10206 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
10207                 int index, enum connman_ipconfig_method method)
10208 {
10209         struct connman_ipconfig *ipconfig_ipv4;
10210
10211         ipconfig_ipv4 = __connman_ipconfig_create(index,
10212                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
10213         if (!ipconfig_ipv4)
10214                 return NULL;
10215
10216         __connman_ipconfig_set_method(ipconfig_ipv4, method);
10217
10218         __connman_ipconfig_set_data(ipconfig_ipv4, service);
10219
10220         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
10221
10222         return ipconfig_ipv4;
10223 }
10224
10225 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
10226                 int index)
10227 {
10228         struct connman_ipconfig *ipconfig_ipv6;
10229
10230         ipconfig_ipv6 = __connman_ipconfig_create(index,
10231                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
10232         if (!ipconfig_ipv6)
10233                 return NULL;
10234
10235         __connman_ipconfig_set_data(ipconfig_ipv6, service);
10236
10237         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
10238
10239         return ipconfig_ipv6;
10240 }
10241
10242 void __connman_service_read_ip4config(struct connman_service *service)
10243 {
10244         GKeyFile *keyfile;
10245
10246         if (!service->ipconfig_ipv4)
10247                 return;
10248
10249         keyfile = connman_storage_load_service(service->identifier);
10250         if (!keyfile)
10251                 return;
10252
10253         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
10254                                 service->identifier, "IPv4.");
10255
10256         g_key_file_free(keyfile);
10257 }
10258
10259 void connman_service_create_ip4config(struct connman_service *service,
10260                                         int index)
10261 {
10262         DBG("ipv4 %p", service->ipconfig_ipv4);
10263
10264         if (service->ipconfig_ipv4)
10265                 return;
10266
10267         service->ipconfig_ipv4 = create_ip4config(service, index,
10268                         CONNMAN_IPCONFIG_METHOD_DHCP);
10269         __connman_service_read_ip4config(service);
10270 }
10271
10272 void __connman_service_read_ip6config(struct connman_service *service)
10273 {
10274         GKeyFile *keyfile;
10275
10276         if (!service->ipconfig_ipv6)
10277                 return;
10278
10279         keyfile = connman_storage_load_service(service->identifier);
10280         if (!keyfile)
10281                 return;
10282
10283         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
10284                                 service->identifier, "IPv6.");
10285
10286         g_key_file_free(keyfile);
10287 }
10288
10289 void connman_service_create_ip6config(struct connman_service *service,
10290                                                                 int index)
10291 {
10292         DBG("ipv6 %p", service->ipconfig_ipv6);
10293
10294         if (service->ipconfig_ipv6)
10295                 return;
10296
10297         service->ipconfig_ipv6 = create_ip6config(service, index);
10298
10299         __connman_service_read_ip6config(service);
10300 }
10301
10302 /**
10303  * connman_service_lookup_from_network:
10304  * @network: network structure
10305  *
10306  * Look up a service by network (reference count will not be increased)
10307  */
10308 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
10309 {
10310         struct connman_service *service;
10311         const char *ident, *group;
10312         char *name;
10313
10314         if (!network)
10315                 return NULL;
10316
10317         ident = __connman_network_get_ident(network);
10318         if (!ident)
10319                 return NULL;
10320
10321         group = connman_network_get_group(network);
10322         if (!group)
10323                 return NULL;
10324
10325         name = g_strdup_printf("%s_%s_%s",
10326                         __connman_network_get_type(network), ident, group);
10327         service = lookup_by_identifier(name);
10328         g_free(name);
10329
10330         return service;
10331 }
10332
10333 struct connman_service *__connman_service_lookup_from_index(int index)
10334 {
10335         struct connman_service *service;
10336         GList *list;
10337
10338         for (list = service_list; list; list = list->next) {
10339                 service = list->data;
10340
10341                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
10342                                                         == index)
10343                         return service;
10344
10345                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
10346                                                         == index)
10347                         return service;
10348         }
10349
10350         return NULL;
10351 }
10352
10353 const char *connman_service_get_identifier(struct connman_service *service)
10354 {
10355         return service ? service->identifier : NULL;
10356 }
10357
10358 const char *__connman_service_get_path(struct connman_service *service)
10359 {
10360         return service->path;
10361 }
10362
10363 const char *__connman_service_get_name(struct connman_service *service)
10364 {
10365         return service->name;
10366 }
10367
10368 enum connman_service_state connman_service_get_state(struct connman_service *service)
10369 {
10370         return service ? service->state : CONNMAN_SERVICE_STATE_UNKNOWN;
10371 }
10372
10373 static enum connman_service_type convert_network_type(struct connman_network *network)
10374 {
10375         enum connman_network_type type = connman_network_get_type(network);
10376
10377         switch (type) {
10378         case CONNMAN_NETWORK_TYPE_UNKNOWN:
10379         case CONNMAN_NETWORK_TYPE_VENDOR:
10380                 break;
10381         case CONNMAN_NETWORK_TYPE_ETHERNET:
10382                 return CONNMAN_SERVICE_TYPE_ETHERNET;
10383         case CONNMAN_NETWORK_TYPE_WIFI:
10384                 return CONNMAN_SERVICE_TYPE_WIFI;
10385         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
10386         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
10387                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
10388         case CONNMAN_NETWORK_TYPE_CELLULAR:
10389                 return CONNMAN_SERVICE_TYPE_CELLULAR;
10390         case CONNMAN_NETWORK_TYPE_GADGET:
10391                 return CONNMAN_SERVICE_TYPE_GADGET;
10392         }
10393
10394         return CONNMAN_SERVICE_TYPE_UNKNOWN;
10395 }
10396
10397 static enum connman_service_security convert_wifi_security(const char *security)
10398 {
10399         if (!security)
10400                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
10401         else if (g_str_equal(security, "none"))
10402                 return CONNMAN_SERVICE_SECURITY_NONE;
10403         else if (g_str_equal(security, "wep"))
10404                 return CONNMAN_SERVICE_SECURITY_WEP;
10405         else if (g_str_equal(security, "psk"))
10406                 return CONNMAN_SERVICE_SECURITY_PSK;
10407         else if (g_str_equal(security, "ieee8021x"))
10408                 return CONNMAN_SERVICE_SECURITY_8021X;
10409         else if (g_str_equal(security, "wpa"))
10410                 return CONNMAN_SERVICE_SECURITY_WPA;
10411         else if (g_str_equal(security, "rsn"))
10412                 return CONNMAN_SERVICE_SECURITY_RSN;
10413 #if defined TIZEN_EXT
10414         else if (g_str_equal(security, "sae"))
10415                 return CONNMAN_SERVICE_SECURITY_SAE;
10416         else if (g_str_equal(security, "owe"))
10417                 return CONNMAN_SERVICE_SECURITY_OWE;
10418         else if (g_str_equal(security, "dpp"))
10419                 return CONNMAN_SERVICE_SECURITY_DPP;
10420         else if (g_str_equal(security, "ft_psk") == TRUE)
10421                 return CONNMAN_SERVICE_SECURITY_PSK;
10422         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
10423                 return CONNMAN_SERVICE_SECURITY_8021X;
10424 #endif
10425         else
10426                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
10427 }
10428
10429 #if defined TIZEN_EXT
10430 int check_passphrase_ext(struct connman_network *network,
10431                                         const char *passphrase)
10432 {
10433         const char *str;
10434         enum connman_service_security security;
10435
10436         str = connman_network_get_string(network, "WiFi.Security");
10437         security = convert_wifi_security(str);
10438
10439         return __connman_service_check_passphrase(security, passphrase);
10440 }
10441 #endif
10442
10443 static void update_wps_values(struct connman_service *service,
10444                                 struct connman_network *network)
10445 {
10446         bool wps = connman_network_get_bool(network, "WiFi.WPS");
10447         bool wps_advertising = connman_network_get_bool(network,
10448                                                         "WiFi.WPSAdvertising");
10449
10450         if (service->wps != wps ||
10451                         service->wps_advertizing != wps_advertising) {
10452                 service->wps = wps;
10453                 service->wps_advertizing = wps_advertising;
10454                 security_changed(service);
10455         }
10456 }
10457
10458 static void update_from_network(struct connman_service *service,
10459                                         struct connman_network *network)
10460 {
10461         uint8_t strength = service->strength;
10462         const char *str;
10463
10464         DBG("service %p network %p", service, network);
10465
10466         if (is_connected(service->state))
10467                 return;
10468
10469         if (is_connecting(service->state))
10470                 return;
10471
10472         str = connman_network_get_string(network, "Name");
10473         if (str) {
10474                 g_free(service->name);
10475                 service->name = g_strdup(str);
10476                 service->hidden = false;
10477         } else {
10478                 g_free(service->name);
10479                 service->name = NULL;
10480                 service->hidden = true;
10481         }
10482
10483         service->strength = connman_network_get_strength(network);
10484         service->roaming = connman_network_get_bool(network, "Roaming");
10485
10486         if (service->strength == 0) {
10487                 /*
10488                  * Filter out 0-values; it's unclear what they mean
10489                  * and they cause anomalous sorting of the priority list.
10490                  */
10491                 service->strength = strength;
10492         }
10493
10494         str = connman_network_get_string(network, "WiFi.Security");
10495         service->security = convert_wifi_security(str);
10496
10497         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
10498                 update_wps_values(service, network);
10499
10500         if (service->strength > strength && service->network) {
10501                 connman_network_unref(service->network);
10502                 service->network = connman_network_ref(network);
10503
10504                 strength_changed(service);
10505         }
10506
10507         if (!service->network)
10508                 service->network = connman_network_ref(network);
10509
10510         service_list_sort();
10511 }
10512
10513 /**
10514  * __connman_service_create_from_network:
10515  * @network: network structure
10516  *
10517  * Look up service by network and if not found, create one
10518  */
10519 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
10520 {
10521         struct connman_service *service;
10522         struct connman_device *device;
10523         const char *ident, *group;
10524         char *name;
10525         unsigned int *auto_connect_types, *favorite_types;
10526         int i, index;
10527
10528         DBG("network %p", network);
10529
10530         if (!network)
10531                 return NULL;
10532
10533         ident = __connman_network_get_ident(network);
10534         if (!ident)
10535                 return NULL;
10536
10537         group = connman_network_get_group(network);
10538         if (!group)
10539                 return NULL;
10540
10541         name = g_strdup_printf("%s_%s_%s",
10542                         __connman_network_get_type(network), ident, group);
10543         service = service_get(name);
10544         g_free(name);
10545
10546         if (!service)
10547                 return NULL;
10548
10549         if (__connman_network_get_weakness(network))
10550                 return service;
10551
10552         if (service->path) {
10553                 update_from_network(service, network);
10554                 __connman_connection_update_gateway();
10555                 return service;
10556         }
10557
10558         service->type = convert_network_type(network);
10559
10560         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
10561         service->autoconnect = false;
10562         for (i = 0; auto_connect_types &&
10563                      auto_connect_types[i] != 0; i++) {
10564                 if (service->type == auto_connect_types[i]) {
10565                         service->autoconnect = true;
10566                         break;
10567                 }
10568         }
10569
10570         favorite_types = connman_setting_get_uint_list("DefaultFavoriteTechnologies");
10571         service->favorite = false;
10572         for (i = 0; favorite_types && favorite_types[i] != 0; i++) {
10573                 if (service->type == favorite_types[i]) {
10574                         service->favorite = true;
10575                         break;
10576                 }
10577         }
10578
10579         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
10580         service->state = combine_state(service->state_ipv4, service->state_ipv6);
10581
10582         update_from_network(service, network);
10583
10584         index = connman_network_get_index(network);
10585
10586         if (!service->ipconfig_ipv4)
10587                 service->ipconfig_ipv4 = create_ip4config(service, index,
10588                                 CONNMAN_IPCONFIG_METHOD_DHCP);
10589
10590         if (!service->ipconfig_ipv6)
10591                 service->ipconfig_ipv6 = create_ip6config(service, index);
10592
10593         service_register(service);
10594         service_schedule_added(service);
10595
10596         if (service->favorite) {
10597                 device = connman_network_get_device(service->network);
10598                 if (device && !connman_device_get_scanning(device,
10599                                                 CONNMAN_SERVICE_TYPE_UNKNOWN)) {
10600
10601                         switch (service->type) {
10602                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
10603                         case CONNMAN_SERVICE_TYPE_SYSTEM:
10604                         case CONNMAN_SERVICE_TYPE_P2P:
10605 #if defined TIZEN_EXT_WIFI_MESH
10606                         case CONNMAN_SERVICE_TYPE_MESH:
10607 #endif
10608                                 break;
10609
10610                         case CONNMAN_SERVICE_TYPE_GADGET:
10611                         case CONNMAN_SERVICE_TYPE_ETHERNET:
10612                                 if (service->autoconnect) {
10613                                         __connman_service_connect(service,
10614                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
10615                                         break;
10616                                 }
10617
10618                                 /* fall through */
10619                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
10620                         case CONNMAN_SERVICE_TYPE_GPS:
10621                         case CONNMAN_SERVICE_TYPE_VPN:
10622                         case CONNMAN_SERVICE_TYPE_WIFI:
10623                         case CONNMAN_SERVICE_TYPE_CELLULAR:
10624                                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
10625                                 break;
10626                         }
10627                 }
10628
10629 #if defined TIZEN_EXT
10630                 /* TIZEN synchronizes below information when the service creates */
10631                 if (service->eap != NULL)
10632                         connman_network_set_string(service->network, "WiFi.EAP",
10633                                                                 service->eap);
10634                 if (service->identity != NULL)
10635                         connman_network_set_string(service->network, "WiFi.Identity",
10636                                                                 service->identity);
10637                 if (service->phase2 != NULL)
10638                         connman_network_set_string(service->network, "WiFi.Phase2",
10639                                                                 service->phase2);
10640                 if (service->eap != NULL)
10641                         connman_network_set_string(service->network, "WiFi.Connector",
10642                                                                 service->connector);
10643                 if (service->identity != NULL)
10644                         connman_network_set_string(service->network, "WiFi.CSignKey",
10645                                                                 service->c_sign_key);
10646                 if (service->phase2 != NULL)
10647                         connman_network_set_string(service->network, "WiFi.NetAccessKey",
10648                                                                 service->net_access_key);
10649 #endif
10650         }
10651
10652         __connman_notifier_service_add(service, service->name);
10653
10654         return service;
10655 }
10656
10657 #if defined TIZEN_EXT
10658 void __connman_service_notify_strength_changed(struct connman_network *network)
10659 {
10660         struct connman_service *service;
10661         uint8_t strength = 0;
10662
10663         service = connman_service_lookup_from_network(network);
10664         if (!service)
10665                 return;
10666
10667         if (!service->network)
10668                 return;
10669
10670         strength = connman_network_get_strength(service->network);
10671         if (strength == service->strength)
10672                 return;
10673
10674         service->strength = strength;
10675         if (!simplified_log)
10676                 DBG("Strength %d", strength);
10677         strength_changed(service);
10678         service_list_sort();
10679 }
10680 #endif
10681
10682 void __connman_service_update_from_network(struct connman_network *network)
10683 {
10684         bool need_sort = false;
10685         struct connman_service *service;
10686         uint8_t strength;
10687         bool roaming;
10688         const char *name;
10689         bool stats_enable;
10690 #if defined TIZEN_EXT
10691         bool need_save = false;
10692 #endif
10693
10694         service = connman_service_lookup_from_network(network);
10695         if (!service)
10696                 return;
10697
10698         if (!service->network)
10699                 return;
10700
10701 #if defined TIZEN_EXT
10702         if (service->storage_reload) {
10703                 service_load(service);
10704                 __connman_service_set_storage_reload(service, false);
10705         }
10706 #endif
10707
10708         name = connman_network_get_string(service->network, "Name");
10709         if (g_strcmp0(service->name, name) != 0) {
10710                 g_free(service->name);
10711                 service->name = g_strdup(name);
10712
10713                 if (allow_property_changed(service))
10714                         connman_dbus_property_changed_basic(service->path,
10715                                         CONNMAN_SERVICE_INTERFACE, "Name",
10716                                         DBUS_TYPE_STRING, &service->name);
10717         }
10718
10719         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
10720                 update_wps_values(service, network);
10721
10722         strength = connman_network_get_strength(service->network);
10723         if (strength == service->strength)
10724                 goto roaming;
10725
10726         service->strength = strength;
10727         need_sort = true;
10728
10729         strength_changed(service);
10730
10731 roaming:
10732         roaming = connman_network_get_bool(service->network, "Roaming");
10733         if (roaming == service->roaming)
10734                 goto sorting;
10735
10736         stats_enable = stats_enabled(service);
10737         if (stats_enable)
10738                 stats_stop(service);
10739
10740         service->roaming = roaming;
10741         need_sort = true;
10742
10743         if (stats_enable)
10744                 stats_start(service);
10745
10746         roaming_changed(service);
10747
10748 sorting:
10749 #if defined TIZEN_EXT
10750         need_save |= update_last_connected_bssid(service);
10751         need_save |= update_assoc_reject(service);
10752         if (need_save) {
10753                 g_get_current_time(&service->modified);
10754                 service_ext_save(service);
10755                 need_sort = true;
10756         }
10757 #endif
10758
10759         if (need_sort) {
10760                 service_list_sort();
10761         }
10762 }
10763
10764 void __connman_service_remove_from_network(struct connman_network *network)
10765 {
10766         struct connman_service *service;
10767
10768         service = connman_service_lookup_from_network(network);
10769
10770         DBG("network %p service %p", network, service);
10771
10772         if (!service)
10773                 return;
10774
10775         service->ignore = true;
10776
10777         __connman_connection_gateway_remove(service,
10778                                         CONNMAN_IPCONFIG_TYPE_ALL);
10779
10780         connman_service_unref(service);
10781 }
10782
10783 /**
10784  * __connman_service_create_from_provider:
10785  * @provider: provider structure
10786  *
10787  * Look up service by provider and if not found, create one
10788  */
10789 struct connman_service *
10790 __connman_service_create_from_provider(struct connman_provider *provider)
10791 {
10792         struct connman_service *service;
10793         const char *ident, *str;
10794         char *name;
10795         int index = connman_provider_get_index(provider);
10796
10797         DBG("provider %p", provider);
10798
10799         ident = __connman_provider_get_ident(provider);
10800         if (!ident)
10801                 return NULL;
10802
10803         name = g_strdup_printf("vpn_%s", ident);
10804         service = service_get(name);
10805         g_free(name);
10806
10807         if (!service)
10808                 return NULL;
10809
10810         service->type = CONNMAN_SERVICE_TYPE_VPN;
10811         service->order = service->do_split_routing ? 0 : 10;
10812         service->provider = connman_provider_ref(provider);
10813         service->autoconnect = false;
10814         service->favorite = true;
10815
10816         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
10817         service->state = combine_state(service->state_ipv4, service->state_ipv6);
10818
10819         str = connman_provider_get_string(provider, "Name");
10820         if (str) {
10821                 g_free(service->name);
10822                 service->name = g_strdup(str);
10823                 service->hidden = false;
10824         } else {
10825                 g_free(service->name);
10826                 service->name = NULL;
10827                 service->hidden = true;
10828         }
10829
10830         service->strength = 0;
10831
10832         if (!service->ipconfig_ipv4)
10833                 service->ipconfig_ipv4 = create_ip4config(service, index,
10834                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
10835
10836         if (!service->ipconfig_ipv6)
10837                 service->ipconfig_ipv6 = create_ip6config(service, index);
10838
10839         service_register(service);
10840
10841         __connman_notifier_service_add(service, service->name);
10842         service_schedule_added(service);
10843
10844         return service;
10845 }
10846
10847 static void remove_unprovisioned_services(void)
10848 {
10849         gchar **services;
10850         GKeyFile *keyfile, *configkeyfile;
10851         char *file, *section;
10852         int i = 0;
10853
10854         services = connman_storage_get_services();
10855         if (!services)
10856                 return;
10857
10858         for (; services[i]; i++) {
10859                 file = section = NULL;
10860                 keyfile = configkeyfile = NULL;
10861
10862                 keyfile = connman_storage_load_service(services[i]);
10863                 if (!keyfile)
10864                         continue;
10865
10866                 file = g_key_file_get_string(keyfile, services[i],
10867                                         "Config.file", NULL);
10868                 if (!file)
10869                         goto next;
10870
10871                 section = g_key_file_get_string(keyfile, services[i],
10872                                         "Config.ident", NULL);
10873                 if (!section)
10874                         goto next;
10875
10876                 configkeyfile = __connman_storage_load_config(file);
10877                 if (!configkeyfile) {
10878                         /*
10879                          * Config file is missing, remove the provisioned
10880                          * service.
10881                          */
10882                         __connman_storage_remove_service(services[i]);
10883                         goto next;
10884                 }
10885
10886                 if (!g_key_file_has_group(configkeyfile, section))
10887                         /*
10888                          * Config section is missing, remove the provisioned
10889                          * service.
10890                          */
10891                         __connman_storage_remove_service(services[i]);
10892
10893         next:
10894                 if (keyfile)
10895                         g_key_file_free(keyfile);
10896
10897                 if (configkeyfile)
10898                         g_key_file_free(configkeyfile);
10899
10900                 g_free(section);
10901                 g_free(file);
10902         }
10903
10904         g_strfreev(services);
10905 }
10906
10907 static int agent_probe(struct connman_agent *agent)
10908 {
10909         DBG("agent %p", agent);
10910         return 0;
10911 }
10912
10913 static void agent_remove(struct connman_agent *agent)
10914 {
10915         DBG("agent %p", agent);
10916 }
10917
10918 static void *agent_context_ref(void *context)
10919 {
10920         struct connman_service *service = context;
10921
10922         return (void *)connman_service_ref(service);
10923 }
10924
10925 static void agent_context_unref(void *context)
10926 {
10927         struct connman_service *service = context;
10928
10929         connman_service_unref(service);
10930 }
10931
10932 static struct connman_agent_driver agent_driver = {
10933         .name           = "service",
10934         .interface      = CONNMAN_AGENT_INTERFACE,
10935         .probe          = agent_probe,
10936         .remove         = agent_remove,
10937         .context_ref    = agent_context_ref,
10938         .context_unref  = agent_context_unref,
10939 };
10940
10941 #if defined TIZEN_EXT
10942 static void ins_setting_init(void)
10943 {
10944         int i;
10945         const char *string;
10946         char **string_list;
10947         unsigned int string_count;
10948
10949         ins_settings.last_user_selection = connman_setting_get_bool("INSLastUserSelection");
10950         ins_settings.last_user_selection_time = connman_setting_get_uint("INSLastUserSelectionTime");
10951         ins_settings.last_connected = connman_setting_get_bool("INSLastConnected");
10952
10953         string = connman_option_get_string("INSPreferredFreq");
10954         if (g_strcmp0(string, "5GHz") == 0)
10955                 ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_5GHZ;
10956         else if (g_strcmp0(string, "2.4GHz") == 0)
10957                 ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_24GHZ;
10958         else
10959                 ins_settings.preferred_freq = CONNMAN_INS_PREFERRED_FREQ_UNKNOWN;
10960
10961         ins_settings.security_priority_count = connman_setting_get_uint("INSSecurityPriorityCount");
10962         ins_settings.security_priority_score = connman_setting_get_uint("INSSecurityPriorityScore");
10963         string_count = ins_settings.security_priority_count;
10964
10965         memset(ins_settings.security_priority, 0, sizeof(ins_settings.security_priority));
10966         string_list = connman_setting_get_string_list("INSSecurityPriority");
10967         for (i = 0; string_list && string_list[i]; i++) {
10968                 unsigned int security_score = string_count * ins_settings.security_priority_score;
10969
10970                 if (g_strcmp0(string_list[i], "WEP") == 0)
10971                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_WEP] = security_score;
10972                 else if (g_strcmp0(string_list[i], "PSK") == 0)
10973                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_PSK] = security_score;
10974                 else if (g_strcmp0(string_list[i], "8021X") == 0)
10975                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_8021X] = security_score;
10976                 else if (g_strcmp0(string_list[i], "WPA") == 0)
10977                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_WPA] = security_score;
10978                 else if (g_strcmp0(string_list[i], "RSN") == 0)
10979                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_RSN] = security_score;
10980                 else if (g_strcmp0(string_list[i], "SAE") == 0)
10981                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_SAE] = security_score;
10982                 else if (g_strcmp0(string_list[i], "OWE") == 0)
10983                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_OWE] = security_score;
10984                 else if (g_strcmp0(string_list[i], "DPP") == 0)
10985                         ins_settings.security_priority[CONNMAN_SERVICE_SECURITY_DPP] = security_score;
10986
10987                 string_count--;
10988         }
10989
10990         ins_settings.signal = connman_setting_get_bool("INSSignal");
10991         ins_settings.internet = connman_setting_get_bool("INSInternet");
10992
10993         ins_settings.last_user_selection_score = connman_setting_get_uint("INSLastUserSelectionScore");
10994         ins_settings.last_connected_score = connman_setting_get_uint("INSLastConnectedScore");
10995         ins_settings.preferred_freq_score = connman_setting_get_uint("INSPreferredFreqScore");
10996         ins_settings.internet_score = connman_setting_get_uint("INSInternetScore");
10997
10998         ins_settings.signal_level3_5ghz = connman_setting_get_int("INSSignalLevel3_5GHz");
10999         ins_settings.signal_level3_24ghz = connman_setting_get_int("INSSignalLevel3_24GHz");
11000
11001         DBG("last_user_selection [%s]", ins_settings.last_user_selection ? "true" : "false");
11002         DBG("last_user_selection_time [%d]", ins_settings.last_user_selection_time);
11003         DBG("last_user_selection_score [%d]", ins_settings.last_user_selection_score);
11004
11005         DBG("last_connected [%s]", ins_settings.last_connected ? "true" : "false");
11006         DBG("last_connected_score [%d]", ins_settings.last_connected_score);
11007
11008         DBG("preferred_freq [%s]", ins_settings.preferred_freq ? "true" : "false");
11009         DBG("preferred_freq_score [%d]", ins_settings.preferred_freq_score);
11010
11011         DBG("security_priority_count [%d]", ins_settings.security_priority_count);
11012         for (i = 0; i < CONNMAN_SERVICE_SECURITY_MAX; i++) {
11013                 if (ins_settings.security_priority[i])
11014                         DBG("security_priority %s [%d]", security2string(i),
11015                                         ins_settings.security_priority[i]);
11016         }
11017         DBG("security_priority_score [%d]", ins_settings.security_priority_score);
11018
11019         DBG("signal [%s]", ins_settings.signal ? "true" : "false");
11020
11021         DBG("internet [%s]", ins_settings.internet ? "true" : "false");
11022         DBG("internet_score [%d]", ins_settings.internet_score);
11023
11024         DBG("signal_level3_5ghz [%d]", ins_settings.signal_level3_5ghz);
11025         DBG("signal_level3_24ghz [%d]", ins_settings.signal_level3_24ghz);
11026 }
11027 #endif
11028
11029 int __connman_service_init(void)
11030 {
11031         int err;
11032
11033         DBG("");
11034
11035         err = connman_agent_driver_register(&agent_driver);
11036         if (err < 0) {
11037                 connman_error("Cannot register agent driver for %s",
11038                                                 agent_driver.name);
11039                 return err;
11040         }
11041
11042         set_always_connecting_technologies();
11043
11044         connection = connman_dbus_get_connection();
11045
11046         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
11047                                                         NULL, service_free);
11048
11049         services_notify = g_new0(struct _services_notify, 1);
11050         services_notify->remove = g_hash_table_new_full(g_str_hash,
11051                         g_str_equal, g_free, NULL);
11052         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
11053
11054         remove_unprovisioned_services();
11055
11056 #if defined TIZEN_EXT
11057         ins_setting_init();
11058 #endif
11059
11060         return 0;
11061 }
11062
11063 void __connman_service_cleanup(void)
11064 {
11065         DBG("");
11066
11067         if (vpn_autoconnect_id) {
11068                 g_source_remove(vpn_autoconnect_id);
11069                 vpn_autoconnect_id = 0;
11070         }
11071
11072         if (autoconnect_id != 0) {
11073                 g_source_remove(autoconnect_id);
11074                 autoconnect_id = 0;
11075         }
11076
11077         connman_agent_driver_unregister(&agent_driver);
11078
11079         g_list_free(service_list);
11080         service_list = NULL;
11081
11082         g_hash_table_destroy(service_hash);
11083         service_hash = NULL;
11084
11085         g_slist_free(counter_list);
11086         counter_list = NULL;
11087
11088         if (services_notify->id != 0) {
11089                 g_source_remove(services_notify->id);
11090                 service_send_changed(NULL);
11091         }
11092
11093         g_hash_table_destroy(services_notify->remove);
11094         g_hash_table_destroy(services_notify->add);
11095         g_free(services_notify);
11096
11097         dbus_connection_unref(connection);
11098 }