Merge "Fix for single channel scan in SelectNetwork" into tizen
[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 #include <pwd.h>
34 #include <utmpx.h>
35
36 #include <connman/storage.h>
37 #include <connman/setting.h>
38 #include <connman/agent.h>
39
40 #include "connman.h"
41
42 #define CONNECT_TIMEOUT         120
43
44 #define USER_ROOT               0
45 #define USER_NONE               (uid_t)-1
46
47 #if defined TIZEN_EXT
48 #define WIFI_BSSID_STR_LEN      18
49 #endif
50
51 static DBusConnection *connection = NULL;
52
53 static GList *service_list = NULL;
54 static GHashTable *service_hash = NULL;
55 static GSList *counter_list = NULL;
56 static unsigned int autoconnect_timeout = 0;
57 static unsigned int vpn_autoconnect_timeout = 0;
58 static struct connman_service *current_default = NULL;
59 static bool services_dirty = false;
60
61 struct connman_stats {
62         bool valid;
63         bool enabled;
64         struct connman_stats_data data_last;
65         struct connman_stats_data data;
66         GTimer *timer;
67 };
68
69 struct connman_stats_counter {
70         bool append_all;
71         struct connman_stats stats;
72         struct connman_stats stats_roaming;
73 };
74
75 struct connman_service_user {
76         uid_t favorite_user;
77         uid_t current_user;
78 };
79
80 #ifdef TIZEN_EXT
81 enum connman_dnsconfig_method {
82         CONNMAN_DNSCONFIG_METHOD_UNKNOWN = 0,
83         CONNMAN_DNSCONFIG_METHOD_MANUAL  = 1,
84         CONNMAN_DNSCONFIG_METHOD_DHCP    = 2,
85 };
86 #endif
87
88 struct connman_service {
89         int refcount;
90         char *identifier;
91         char *path;
92         enum connman_service_type type;
93         enum connman_service_security security;
94         enum connman_service_state state;
95         enum connman_service_state state_ipv4;
96         enum connman_service_state state_ipv6;
97         enum connman_service_error error;
98         enum connman_service_connect_reason connect_reason;
99         uint8_t strength;
100         bool favorite;
101         bool immutable;
102         bool hidden;
103         bool ignore;
104         bool autoconnect;
105         GTimeVal modified;
106         unsigned int order;
107         char *name;
108         char *passphrase;
109         bool roaming;
110         bool request_passphrase_input;
111         struct connman_service_user user;
112         struct connman_ipconfig *ipconfig_ipv4;
113         struct connman_ipconfig *ipconfig_ipv6;
114         struct connman_network *network;
115         struct connman_provider *provider;
116         char **nameservers;
117         char **nameservers_config;
118         char **nameservers_auto;
119         char **domains;
120         char *hostname;
121         char *domainname;
122         char **timeservers;
123         char **timeservers_config;
124         /* 802.1x settings from the config files */
125         char *eap;
126         char *identity;
127         char *agent_identity;
128         char *ca_cert_file;
129         char *client_cert_file;
130         char *private_key_file;
131         char *private_key_passphrase;
132         char *phase2;
133         DBusMessage *pending;
134         DBusMessage *provider_pending;
135         guint timeout;
136         struct connman_stats stats;
137         struct connman_stats stats_roaming;
138         GHashTable *counter_table;
139         enum connman_service_proxy_method proxy;
140         enum connman_service_proxy_method proxy_config;
141         char **proxies;
142         char **excludes;
143         char *pac;
144         bool wps;
145         int online_check_count;
146         bool do_split_routing;
147         bool new_service;
148         bool hidden_service;
149         char *config_file;
150         char *config_entry;
151 #if defined TIZEN_EXT
152         /*
153          * Description: TIZEN implements system global connection management.
154          *              It's only for PDP (cellular) bearer. Wi-Fi is managed
155          *              by ConnMan automatically. Reference count can help to
156          *              manage open/close connection requests by each application.
157          */
158         int user_pdn_connection_refcount;
159         bool storage_reload;
160         /*
161          * Description: In case of EAP security type,
162          *                                user can select the keymgmt type for roaming(802.11r).
163          *                                - FT, CCKM, OKC, ...
164          */
165         char *keymgmt_type;
166         int disconnect_reason;
167 #endif
168 #ifdef TIZEN_EXT
169         enum connman_dnsconfig_method dns_config_method;
170 #endif
171 };
172
173 static bool allow_property_changed(struct connman_service *service);
174
175 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
176                 int index, enum connman_ipconfig_method method);
177 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
178                 int index);
179
180
181 struct find_data {
182         const char *path;
183         struct connman_service *service;
184 };
185
186 #if defined TIZEN_EXT
187 /*
188  * Public APIs to use user_pdn_connection_refcount
189  */
190 void connman_service_user_pdn_connection_ref(struct connman_service *service)
191 {
192         __sync_fetch_and_add(&service->user_pdn_connection_refcount, 1);
193
194         DBG("User made PDN connection referenced: %d",
195                                 service->user_pdn_connection_refcount);
196 }
197
198 gboolean connman_service_user_pdn_connection_unref_and_test(
199                                         struct connman_service *service)
200 {
201         __sync_synchronize();
202
203         DBG("User made PDN connection referenced: %d, which will be decreased",
204                                 service->user_pdn_connection_refcount);
205
206         if (service->user_pdn_connection_refcount < 1)
207                 return TRUE;
208
209         if (__sync_sub_and_fetch(&service->user_pdn_connection_refcount, 1) == 0)
210                 return TRUE;
211
212         return FALSE;
213 }
214
215 gboolean connman_service_is_no_ref_user_pdn_connection(
216                                         struct connman_service *cellular)
217 {
218         if (cellular == NULL)
219                 return TRUE;
220
221         __sync_synchronize();
222         if (cellular->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
223                         cellular->user_pdn_connection_refcount == 0)
224                 return TRUE;
225
226         return FALSE;
227 }
228 #endif
229
230 static void compare_path(gpointer value, gpointer user_data)
231 {
232         struct connman_service *service = value;
233         struct find_data *data = user_data;
234
235         if (data->service)
236                 return;
237
238         if (g_strcmp0(service->path, data->path) == 0)
239                 data->service = service;
240 }
241
242 static struct connman_service *find_service(const char *path)
243 {
244         struct find_data data = { .path = path, .service = NULL };
245
246         DBG("path %s", path);
247
248         g_list_foreach(service_list, compare_path, &data);
249
250         return data.service;
251 }
252
253 static const char *reason2string(enum connman_service_connect_reason reason)
254 {
255
256         switch (reason) {
257         case CONNMAN_SERVICE_CONNECT_REASON_NONE:
258                 return "none";
259         case CONNMAN_SERVICE_CONNECT_REASON_USER:
260                 return "user";
261         case CONNMAN_SERVICE_CONNECT_REASON_AUTO:
262                 return "auto";
263         case CONNMAN_SERVICE_CONNECT_REASON_SESSION:
264                 return "session";
265         }
266
267         return "unknown";
268 }
269
270 const char *__connman_service_type2string(enum connman_service_type type)
271 {
272         switch (type) {
273         case CONNMAN_SERVICE_TYPE_UNKNOWN:
274                 break;
275         case CONNMAN_SERVICE_TYPE_SYSTEM:
276                 return "system";
277         case CONNMAN_SERVICE_TYPE_ETHERNET:
278                 return "ethernet";
279         case CONNMAN_SERVICE_TYPE_WIFI:
280                 return "wifi";
281         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
282                 return "bluetooth";
283         case CONNMAN_SERVICE_TYPE_CELLULAR:
284                 return "cellular";
285         case CONNMAN_SERVICE_TYPE_GPS:
286                 return "gps";
287         case CONNMAN_SERVICE_TYPE_VPN:
288                 return "vpn";
289         case CONNMAN_SERVICE_TYPE_GADGET:
290                 return "gadget";
291         case CONNMAN_SERVICE_TYPE_P2P:
292                 return "p2p";
293         }
294
295         return NULL;
296 }
297
298 enum connman_service_type __connman_service_string2type(const char *str)
299 {
300         if (!str)
301                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
302
303         if (strcmp(str, "ethernet") == 0)
304                 return CONNMAN_SERVICE_TYPE_ETHERNET;
305         if (strcmp(str, "gadget") == 0)
306                 return CONNMAN_SERVICE_TYPE_GADGET;
307         if (strcmp(str, "wifi") == 0)
308                 return CONNMAN_SERVICE_TYPE_WIFI;
309         if (strcmp(str, "cellular") == 0)
310                 return CONNMAN_SERVICE_TYPE_CELLULAR;
311         if (strcmp(str, "bluetooth") == 0)
312                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
313         if (strcmp(str, "vpn") == 0)
314                 return CONNMAN_SERVICE_TYPE_VPN;
315         if (strcmp(str, "gps") == 0)
316                 return CONNMAN_SERVICE_TYPE_GPS;
317         if (strcmp(str, "system") == 0)
318                 return CONNMAN_SERVICE_TYPE_SYSTEM;
319         if (strcmp(str, "p2p") == 0)
320                 return CONNMAN_SERVICE_TYPE_P2P;
321
322         return CONNMAN_SERVICE_TYPE_UNKNOWN;
323 }
324
325 enum connman_service_security __connman_service_string2security(const char *str)
326 {
327         if (!str)
328                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
329
330         if (!strcmp(str, "psk"))
331                 return CONNMAN_SERVICE_SECURITY_PSK;
332         if (!strcmp(str, "ieee8021x"))
333                 return CONNMAN_SERVICE_SECURITY_8021X;
334         if (!strcmp(str, "none"))
335                 return CONNMAN_SERVICE_SECURITY_NONE;
336         if (!strcmp(str, "wep"))
337                 return CONNMAN_SERVICE_SECURITY_WEP;
338 #if defined TIZEN_EXT
339         if (!strcmp(str, "rsn"))
340                 return CONNMAN_SERVICE_SECURITY_RSN;
341 #endif
342
343         return CONNMAN_SERVICE_SECURITY_UNKNOWN;
344 }
345
346 static const char *security2string(enum connman_service_security security)
347 {
348         switch (security) {
349         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
350                 break;
351         case CONNMAN_SERVICE_SECURITY_NONE:
352                 return "none";
353         case CONNMAN_SERVICE_SECURITY_WEP:
354                 return "wep";
355         case CONNMAN_SERVICE_SECURITY_PSK:
356         case CONNMAN_SERVICE_SECURITY_WPA:
357 #if defined TIZEN_EXT
358                 return "psk";
359         case CONNMAN_SERVICE_SECURITY_RSN:
360                 return "rsn";
361 #else
362         case CONNMAN_SERVICE_SECURITY_RSN:
363                 return "psk";
364 #endif
365         case CONNMAN_SERVICE_SECURITY_8021X:
366                 return "ieee8021x";
367         }
368
369         return NULL;
370 }
371
372 static const char *state2string(enum connman_service_state state)
373 {
374         switch (state) {
375         case CONNMAN_SERVICE_STATE_UNKNOWN:
376                 break;
377         case CONNMAN_SERVICE_STATE_IDLE:
378                 return "idle";
379         case CONNMAN_SERVICE_STATE_ASSOCIATION:
380                 return "association";
381         case CONNMAN_SERVICE_STATE_CONFIGURATION:
382                 return "configuration";
383         case CONNMAN_SERVICE_STATE_READY:
384                 return "ready";
385         case CONNMAN_SERVICE_STATE_ONLINE:
386                 return "online";
387         case CONNMAN_SERVICE_STATE_DISCONNECT:
388                 return "disconnect";
389         case CONNMAN_SERVICE_STATE_FAILURE:
390                 return "failure";
391         }
392
393         return NULL;
394 }
395
396 static const char *error2string(enum connman_service_error error)
397 {
398         switch (error) {
399         case CONNMAN_SERVICE_ERROR_UNKNOWN:
400                 break;
401         case CONNMAN_SERVICE_ERROR_OUT_OF_RANGE:
402                 return "out-of-range";
403         case CONNMAN_SERVICE_ERROR_PIN_MISSING:
404                 return "pin-missing";
405         case CONNMAN_SERVICE_ERROR_DHCP_FAILED:
406                 return "dhcp-failed";
407         case CONNMAN_SERVICE_ERROR_CONNECT_FAILED:
408                 return "connect-failed";
409         case CONNMAN_SERVICE_ERROR_LOGIN_FAILED:
410                 return "login-failed";
411         case CONNMAN_SERVICE_ERROR_AUTH_FAILED:
412                 return "auth-failed";
413         case CONNMAN_SERVICE_ERROR_INVALID_KEY:
414                 return "invalid-key";
415         }
416
417         return NULL;
418 }
419
420 static const char *proxymethod2string(enum connman_service_proxy_method method)
421 {
422         switch (method) {
423         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
424                 return "direct";
425         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
426                 return "manual";
427         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
428                 return "auto";
429         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
430                 break;
431         }
432
433         return NULL;
434 }
435
436 static enum connman_service_proxy_method string2proxymethod(const char *method)
437 {
438         if (g_strcmp0(method, "direct") == 0)
439                 return CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
440         else if (g_strcmp0(method, "auto") == 0)
441                 return CONNMAN_SERVICE_PROXY_METHOD_AUTO;
442         else if (g_strcmp0(method, "manual") == 0)
443                 return CONNMAN_SERVICE_PROXY_METHOD_MANUAL;
444         else
445                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
446 }
447
448 #ifdef TIZEN_EXT
449 static const char *__connman_dnsconfig_method2string(enum connman_dnsconfig_method method)
450 {
451         switch (method) {
452         case CONNMAN_DNSCONFIG_METHOD_UNKNOWN:
453                 return "unknown";
454         case CONNMAN_DNSCONFIG_METHOD_MANUAL:
455                 return "manual";
456         case CONNMAN_DNSCONFIG_METHOD_DHCP:
457                 return "dhcp";
458         }
459
460         return NULL;
461 }
462
463 static enum connman_dnsconfig_method __connman_dnsconfig_string2method(
464                 const char *method)
465 {
466         if (g_strcmp0(method, "manual") == 0)
467                 return CONNMAN_DNSCONFIG_METHOD_MANUAL;
468         else if (g_strcmp0(method, "dhcp") == 0)
469                 return CONNMAN_DNSCONFIG_METHOD_DHCP;
470         else
471                 return CONNMAN_DNSCONFIG_METHOD_UNKNOWN;
472 }
473 #endif
474
475 static bool
476 connman_service_is_user_allowed(struct connman_service *service, uid_t uid)
477 {
478         uid_t favorite_user = service->user.favorite_user;
479         uid_t current_user = uid;
480
481         DBG("Service favorite UID: %d, current UID: %d", favorite_user, current_user);
482         if (favorite_user == USER_NONE || current_user == USER_ROOT)
483                 return true;
484
485         if (favorite_user != current_user || current_user == USER_NONE) {
486                 DBG("Current user is not a favorite user to this service!");
487                 return false;
488         }
489
490         return true;
491 }
492
493 #if !defined TIZEN_EXT
494 static GList *connman_service_get_login_users()
495 {
496         struct utmpx *utmp;
497         struct passwd *pwd;
498         GList *user_list = NULL;
499
500         setutxent();
501
502         while ((utmp = getutxent()) != NULL) {
503                 DBG("User Name: %s", utmp->ut_user);
504
505                 pwd = getpwnam(utmp->ut_user);
506                 if (pwd) {
507                         if (!g_list_find(user_list, GUINT_TO_POINTER(pwd->pw_uid)))
508                                 user_list = g_list_append(user_list,
509                                                 GUINT_TO_POINTER(pwd->pw_uid));
510
511                         DBG("User Name: %s, UID: %d", utmp->ut_user, pwd->pw_uid);
512                 }
513         }
514
515         endutxent();
516
517         return user_list;
518 }
519 #endif
520
521 static bool is_service_owner_user_login(struct connman_service *service)
522 {
523 #if defined TIZEN_EXT
524         return true;
525 #else
526         GList *list, *user_list;
527         bool ret = false;
528
529         /* Here we only care about wifi service */
530         if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
531                 return true;
532
533         DBG("service favorite user id is: %d", service->user.favorite_user);
534
535         user_list = connman_service_get_login_users();
536         if (user_list == NULL) {
537                 DBG("Can not get any logged in user info.");
538                 return true;
539         }
540
541         for (list = user_list; list; list = list->next) {
542                 uid_t uid = GPOINTER_TO_UINT(list->data);
543
544                 DBG("login user id is %d", uid);
545
546                 if (service->user.favorite_user == uid) {
547                         ret = true;
548                         break;
549                 }
550         }
551
552         g_list_free(user_list);
553
554         return ret;
555 #endif
556 }
557
558 int __connman_service_load_modifiable(struct connman_service *service)
559 {
560         GKeyFile *keyfile;
561         GError *error = NULL;
562         gchar *str;
563         bool autoconnect;
564
565         DBG("service %p", service);
566
567         keyfile = connman_storage_load_service(service->identifier);
568         if (!keyfile)
569                 return -EIO;
570
571         switch (service->type) {
572         case CONNMAN_SERVICE_TYPE_UNKNOWN:
573         case CONNMAN_SERVICE_TYPE_SYSTEM:
574         case CONNMAN_SERVICE_TYPE_GPS:
575         case CONNMAN_SERVICE_TYPE_P2P:
576                 break;
577         case CONNMAN_SERVICE_TYPE_VPN:
578                 service->do_split_routing = g_key_file_get_boolean(keyfile,
579                                 service->identifier, "SplitRouting", NULL);
580                 /* fall through */
581         case CONNMAN_SERVICE_TYPE_WIFI:
582         case CONNMAN_SERVICE_TYPE_GADGET:
583         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
584         case CONNMAN_SERVICE_TYPE_CELLULAR:
585         case CONNMAN_SERVICE_TYPE_ETHERNET:
586                 autoconnect = g_key_file_get_boolean(keyfile,
587                                 service->identifier, "AutoConnect", &error);
588                 if (!error)
589                         service->autoconnect = autoconnect;
590                 g_clear_error(&error);
591                 break;
592         }
593
594         str = g_key_file_get_string(keyfile,
595                                 service->identifier, "Modified", NULL);
596         if (str) {
597                 g_time_val_from_iso8601(str, &service->modified);
598                 g_free(str);
599         }
600
601         g_key_file_free(keyfile);
602
603         return 0;
604 }
605
606 static int service_load_passphrase(struct connman_service *service)
607 {
608         GKeyFile *keyfile;
609         gchar *str;
610
611         keyfile = connman_storage_load_service(service->identifier);
612         if (!keyfile)
613                 return -EIO;
614
615         str = g_key_file_get_string(keyfile,
616                                 service->identifier, "Passphrase", NULL);
617         if (str)
618                 service->passphrase = str;
619
620         return 0;
621 }
622
623 static int service_load(struct connman_service *service)
624 {
625         GKeyFile *keyfile;
626         GError *error = NULL;
627         gsize length;
628         gchar *str;
629         bool autoconnect;
630         unsigned int ssid_len;
631         int err = 0;
632
633         DBG("service %p", service);
634
635         keyfile = connman_storage_load_service(service->identifier);
636         if (!keyfile) {
637                 service->new_service = true;
638                 return -EIO;
639         } else
640                 service->new_service = false;
641
642         switch (service->type) {
643         case CONNMAN_SERVICE_TYPE_UNKNOWN:
644         case CONNMAN_SERVICE_TYPE_SYSTEM:
645         case CONNMAN_SERVICE_TYPE_GPS:
646         case CONNMAN_SERVICE_TYPE_P2P:
647                 break;
648         case CONNMAN_SERVICE_TYPE_VPN:
649                 service->do_split_routing = g_key_file_get_boolean(keyfile,
650                                 service->identifier, "SplitRouting", NULL);
651                 autoconnect = g_key_file_get_boolean(keyfile,
652                                 service->identifier, "AutoConnect", &error);
653                 if (!error)
654                         service->autoconnect = autoconnect;
655                 g_clear_error(&error);
656                 break;
657         case CONNMAN_SERVICE_TYPE_WIFI:
658                 if (!service->name) {
659                         gchar *name;
660
661                         name = g_key_file_get_string(keyfile,
662                                         service->identifier, "Name", NULL);
663                         if (name) {
664                                 g_free(service->name);
665                                 service->name = name;
666                         }
667
668                         if (service->network)
669                                 connman_network_set_name(service->network,
670                                                                         name);
671                 }
672
673                 if (service->network &&
674                                 !connman_network_get_blob(service->network,
675                                                 "WiFi.SSID", &ssid_len)) {
676                         gchar *hex_ssid;
677
678                         hex_ssid = g_key_file_get_string(keyfile,
679                                                         service->identifier,
680                                                                 "SSID", NULL);
681
682                         if (hex_ssid) {
683                                 gchar *ssid;
684                                 unsigned int i, j = 0, hex;
685                                 size_t hex_ssid_len = strlen(hex_ssid);
686
687                                 ssid = g_try_malloc0(hex_ssid_len / 2);
688                                 if (!ssid) {
689                                         g_free(hex_ssid);
690                                         err = -ENOMEM;
691                                         goto done;
692                                 }
693
694                                 for (i = 0; i < hex_ssid_len; i += 2) {
695                                         sscanf(hex_ssid + i, "%02x", &hex);
696                                         ssid[j++] = hex;
697                                 }
698
699                                 connman_network_set_blob(service->network,
700                                         "WiFi.SSID", ssid, hex_ssid_len / 2);
701
702                                 g_free(ssid);
703                         }
704
705                         g_free(hex_ssid);
706                 }
707                 /* fall through */
708
709         case CONNMAN_SERVICE_TYPE_GADGET:
710         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
711         case CONNMAN_SERVICE_TYPE_CELLULAR:
712                 service->favorite = g_key_file_get_boolean(keyfile,
713                                 service->identifier, "Favorite", NULL);
714
715                 /* fall through */
716
717         case CONNMAN_SERVICE_TYPE_ETHERNET:
718                 autoconnect = g_key_file_get_boolean(keyfile,
719                                 service->identifier, "AutoConnect", &error);
720                 if (!error)
721                         service->autoconnect = autoconnect;
722                 g_clear_error(&error);
723                 break;
724         }
725
726         str = g_key_file_get_string(keyfile,
727                                 service->identifier, "Modified", NULL);
728         if (str) {
729                 g_time_val_from_iso8601(str, &service->modified);
730                 g_free(str);
731         }
732
733         str = g_key_file_get_string(keyfile,
734                                 service->identifier, "Passphrase", NULL);
735         if (str) {
736                 g_free(service->passphrase);
737                 service->passphrase = str;
738         }
739
740         if (service->ipconfig_ipv4)
741                 __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
742                                         service->identifier, "IPv4.");
743
744         if (service->ipconfig_ipv6)
745                 __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
746                                         service->identifier, "IPv6.");
747
748         service->nameservers_config = g_key_file_get_string_list(keyfile,
749                         service->identifier, "Nameservers", &length, NULL);
750         if (service->nameservers_config && length == 0) {
751                 g_strfreev(service->nameservers_config);
752                 service->nameservers_config = NULL;
753         }
754
755 #ifdef TIZEN_EXT
756         char *dns_method;
757         if (TIZEN_TV_EXT) {
758                 dns_method = g_key_file_get_string(keyfile, service->identifier,
759                                 "Nameservers.method", NULL);
760                 service->dns_config_method = __connman_dnsconfig_string2method(dns_method);
761         }
762 #endif
763
764         service->timeservers_config = g_key_file_get_string_list(keyfile,
765                         service->identifier, "Timeservers", &length, NULL);
766         if (service->timeservers_config && length == 0) {
767                 g_strfreev(service->timeservers_config);
768                 service->timeservers_config = NULL;
769         }
770
771         service->domains = g_key_file_get_string_list(keyfile,
772                         service->identifier, "Domains", &length, NULL);
773         if (service->domains && length == 0) {
774                 g_strfreev(service->domains);
775                 service->domains = NULL;
776         }
777
778         str = g_key_file_get_string(keyfile,
779                                 service->identifier, "Proxy.Method", NULL);
780         if (str)
781                 service->proxy_config = string2proxymethod(str);
782
783         g_free(str);
784
785         service->proxies = g_key_file_get_string_list(keyfile,
786                         service->identifier, "Proxy.Servers", &length, NULL);
787         if (service->proxies && length == 0) {
788                 g_strfreev(service->proxies);
789                 service->proxies = NULL;
790         }
791
792         service->excludes = g_key_file_get_string_list(keyfile,
793                         service->identifier, "Proxy.Excludes", &length, NULL);
794         if (service->excludes && length == 0) {
795                 g_strfreev(service->excludes);
796                 service->excludes = NULL;
797         }
798
799         str = g_key_file_get_string(keyfile,
800                                 service->identifier, "Proxy.URL", NULL);
801         if (str) {
802                 g_free(service->pac);
803                 service->pac = str;
804         }
805
806         service->hidden_service = g_key_file_get_boolean(keyfile,
807                                         service->identifier, "Hidden", NULL);
808
809 #if defined TIZEN_EXT
810         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
811                         service->security == CONNMAN_SERVICE_SECURITY_8021X) {
812                 str = g_key_file_get_string(keyfile,
813                                 service->identifier, "EAP", NULL);
814                 if (str != NULL) {
815                         g_free(service->eap);
816                         service->eap = str;
817                 }
818
819                 str = g_key_file_get_string(keyfile,
820                                 service->identifier, "Phase2", NULL);
821                 if (str != NULL) {
822                         g_free(service->phase2);
823                         service->phase2 = str;
824                 }
825
826                 str = g_key_file_get_string(keyfile,
827                                 service->identifier, "Identity", NULL);
828                 if (str != NULL) {
829                         g_free(service->identity);
830                         service->identity = str;
831                 }
832
833                 str = g_key_file_get_string(keyfile,
834                                 service->identifier, "CACertFile", NULL);
835                 if (str != NULL) {
836                         g_free(service->ca_cert_file);
837                         service->ca_cert_file = str;
838                 }
839
840                 str = g_key_file_get_string(keyfile,
841                                 service->identifier, "ClientCertFile", NULL);
842                 if (str != NULL) {
843                         g_free(service->client_cert_file);
844                         service->client_cert_file = str;
845                 }
846
847                 str = g_key_file_get_string(keyfile,
848                                 service->identifier, "PrivateKeyFile", NULL);
849                 if (str != NULL) {
850                         g_free(service->private_key_file);
851                         service->private_key_file = str;
852                 }
853
854                 str = g_key_file_get_string(keyfile,
855                                 service->identifier, "PrivateKeyPassphrase", NULL);
856                 if (str != NULL) {
857                         g_free(service->private_key_passphrase);
858                         service->private_key_passphrase = str;
859                 }
860         }
861 #endif
862
863         if (g_key_file_has_key(keyfile, service->identifier, "UID", NULL))
864                 service->user.favorite_user = g_key_file_get_integer(keyfile,
865                                         service->identifier, "UID", NULL);
866 done:
867         g_key_file_free(keyfile);
868
869         return err;
870 }
871
872 static int service_save(struct connman_service *service)
873 {
874         GKeyFile *keyfile;
875         gchar *str;
876         guint freq;
877         const char *cst_str = NULL;
878         int err = 0;
879
880         DBG("service %p new %d", service, service->new_service);
881
882         if (service->new_service)
883                 return -ESRCH;
884
885         keyfile = __connman_storage_open_service(service->identifier);
886         if (!keyfile)
887                 return -EIO;
888
889         if (service->name)
890                 g_key_file_set_string(keyfile, service->identifier,
891                                                 "Name", service->name);
892
893         switch (service->type) {
894         case CONNMAN_SERVICE_TYPE_UNKNOWN:
895         case CONNMAN_SERVICE_TYPE_SYSTEM:
896         case CONNMAN_SERVICE_TYPE_GPS:
897         case CONNMAN_SERVICE_TYPE_P2P:
898                 break;
899         case CONNMAN_SERVICE_TYPE_VPN:
900                 g_key_file_set_boolean(keyfile, service->identifier,
901                                 "SplitRouting", service->do_split_routing);
902                 if (service->favorite)
903                         g_key_file_set_boolean(keyfile, service->identifier,
904                                         "AutoConnect", service->autoconnect);
905                 break;
906         case CONNMAN_SERVICE_TYPE_WIFI:
907                 if (service->network) {
908                         const unsigned char *ssid;
909                         unsigned int ssid_len = 0;
910
911                         if (service->user.favorite_user == USER_NONE)
912                                 g_key_file_remove_key(keyfile, service->identifier,
913                                                         "UID", NULL);
914                         else
915                                 g_key_file_set_integer(keyfile, service->identifier,
916                                                         "UID", service->user.favorite_user);
917
918                         ssid = connman_network_get_blob(service->network,
919                                                         "WiFi.SSID", &ssid_len);
920
921                         if (ssid && ssid_len > 0 && ssid[0] != '\0') {
922                                 char *identifier = service->identifier;
923                                 GString *ssid_str;
924                                 unsigned int i;
925
926                                 ssid_str = g_string_sized_new(ssid_len * 2);
927                                 if (!ssid_str) {
928                                         err = -ENOMEM;
929                                         goto done;
930                                 }
931
932                                 for (i = 0; i < ssid_len; i++)
933                                         g_string_append_printf(ssid_str,
934                                                         "%02x", ssid[i]);
935
936                                 g_key_file_set_string(keyfile, identifier,
937                                                         "SSID", ssid_str->str);
938
939                                 g_string_free(ssid_str, TRUE);
940                         }
941
942                         freq = connman_network_get_frequency(service->network);
943                         g_key_file_set_integer(keyfile, service->identifier,
944                                                 "Frequency", freq);
945                 }
946                 /* fall through */
947
948         case CONNMAN_SERVICE_TYPE_GADGET:
949         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
950         case CONNMAN_SERVICE_TYPE_CELLULAR:
951                 g_key_file_set_boolean(keyfile, service->identifier,
952                                         "Favorite", service->favorite);
953
954                 g_key_file_remove_key(keyfile, service->identifier,
955                                 "Failure", NULL);
956
957                 /* fall through */
958
959         case CONNMAN_SERVICE_TYPE_ETHERNET:
960                 if (service->favorite)
961                         g_key_file_set_boolean(keyfile, service->identifier,
962                                         "AutoConnect", service->autoconnect);
963                 break;
964         }
965
966         str = g_time_val_to_iso8601(&service->modified);
967         if (str) {
968                 g_key_file_set_string(keyfile, service->identifier,
969                                                         "Modified", str);
970                 g_free(str);
971         }
972
973         if (service->user.current_user == service->user.favorite_user) {
974                 if (service->passphrase && strlen(service->passphrase) > 0)
975                         g_key_file_set_string(keyfile, service->identifier,
976                                         "Passphrase", service->passphrase);
977                 else
978                         g_key_file_remove_key(keyfile, service->identifier,
979                                         "Passphrase", NULL);
980         }
981
982         if (service->ipconfig_ipv4)
983                 __connman_ipconfig_save(service->ipconfig_ipv4, keyfile,
984                                         service->identifier, "IPv4.");
985
986         if (service->ipconfig_ipv6)
987                 __connman_ipconfig_save(service->ipconfig_ipv6, keyfile,
988                                                 service->identifier, "IPv6.");
989
990         if (service->nameservers_config) {
991                 guint len = g_strv_length(service->nameservers_config);
992
993                 g_key_file_set_string_list(keyfile, service->identifier,
994                                                                 "Nameservers",
995                                 (const gchar **) service->nameservers_config, len);
996         } else
997         g_key_file_remove_key(keyfile, service->identifier,
998                                                         "Nameservers", NULL);
999
1000 #ifdef TIZEN_EXT
1001         if (TIZEN_TV_EXT) {
1002                 if(service->dns_config_method != 0) {
1003                         const char *method;
1004                         method = __connman_dnsconfig_method2string(
1005                                         service->dns_config_method);
1006                         g_key_file_set_string(keyfile, service->identifier,
1007                                         "Nameservers.method", method);
1008                 } else
1009                 g_key_file_remove_key(keyfile, service->identifier,
1010                                                         "Nameservers.method", NULL);
1011         }
1012 #endif
1013
1014         if (service->timeservers_config) {
1015                 guint len = g_strv_length(service->timeservers_config);
1016
1017                 g_key_file_set_string_list(keyfile, service->identifier,
1018                                                                 "Timeservers",
1019                                 (const gchar **) service->timeservers_config, len);
1020         } else
1021                 g_key_file_remove_key(keyfile, service->identifier,
1022                                                         "Timeservers", NULL);
1023
1024         if (service->domains) {
1025                 guint len = g_strv_length(service->domains);
1026
1027                 g_key_file_set_string_list(keyfile, service->identifier,
1028                                                                 "Domains",
1029                                 (const gchar **) service->domains, len);
1030         } else
1031                 g_key_file_remove_key(keyfile, service->identifier,
1032                                                         "Domains", NULL);
1033
1034         cst_str = proxymethod2string(service->proxy_config);
1035         if (cst_str)
1036                 g_key_file_set_string(keyfile, service->identifier,
1037                                 "Proxy.Method", cst_str);
1038
1039         if (service->proxies) {
1040                 guint len = g_strv_length(service->proxies);
1041
1042                 g_key_file_set_string_list(keyfile, service->identifier,
1043                                 "Proxy.Servers",
1044                                 (const gchar **) service->proxies, len);
1045         } else
1046                 g_key_file_remove_key(keyfile, service->identifier,
1047                                                 "Proxy.Servers", NULL);
1048
1049         if (service->excludes) {
1050                 guint len = g_strv_length(service->excludes);
1051
1052                 g_key_file_set_string_list(keyfile, service->identifier,
1053                                 "Proxy.Excludes",
1054                                 (const gchar **) service->excludes, len);
1055         } else
1056                 g_key_file_remove_key(keyfile, service->identifier,
1057                                                 "Proxy.Excludes", NULL);
1058
1059         if (service->pac && strlen(service->pac) > 0)
1060                 g_key_file_set_string(keyfile, service->identifier,
1061                                         "Proxy.URL", service->pac);
1062         else
1063                 g_key_file_remove_key(keyfile, service->identifier,
1064                                                         "Proxy.URL", NULL);
1065
1066         if (service->hidden_service)
1067                 g_key_file_set_boolean(keyfile, service->identifier, "Hidden",
1068                                                                         TRUE);
1069
1070         if (service->config_file && strlen(service->config_file) > 0)
1071                 g_key_file_set_string(keyfile, service->identifier,
1072                                 "Config.file", service->config_file);
1073
1074         if (service->config_entry &&
1075                                         strlen(service->config_entry) > 0)
1076                 g_key_file_set_string(keyfile, service->identifier,
1077                                 "Config.ident", service->config_entry);
1078
1079 #if defined TIZEN_EXT
1080         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
1081                         service->security == CONNMAN_SERVICE_SECURITY_8021X) {
1082                 if (service->eap != NULL && strlen(service->eap) > 0)
1083                         g_key_file_set_string(keyfile, service->identifier,
1084                                         "EAP", service->eap);
1085                 else
1086                         g_key_file_remove_key(keyfile, service->identifier,
1087                                         "EAP", NULL);
1088
1089                 if (service->phase2 != NULL && strlen(service->phase2) > 0)
1090                         g_key_file_set_string(keyfile, service->identifier,
1091                                         "Phase2", service->phase2);
1092                 else
1093                         g_key_file_remove_key(keyfile, service->identifier,
1094                                         "Phase2", NULL);
1095
1096                 if (service->identity != NULL && strlen(service->identity) > 0)
1097                         g_key_file_set_string(keyfile, service->identifier,
1098                                         "Identity", service->identity);
1099                 else
1100                         g_key_file_remove_key(keyfile, service->identifier,
1101                                         "Identity", NULL);
1102
1103                 if (service->ca_cert_file != NULL && strlen(service->ca_cert_file) > 0)
1104                         g_key_file_set_string(keyfile, service->identifier,
1105                                         "CACertFile", service->ca_cert_file);
1106                 else
1107                         g_key_file_remove_key(keyfile, service->identifier,
1108                                         "CACertFile", NULL);
1109
1110                 if (service->client_cert_file != NULL && strlen(service->client_cert_file) > 0)
1111                         g_key_file_set_string(keyfile, service->identifier,
1112                                         "ClientCertFile", service->client_cert_file);
1113                 else
1114                         g_key_file_remove_key(keyfile, service->identifier,
1115                                         "ClientCertFile", NULL);
1116
1117                 if (service->private_key_file != NULL && strlen(service->private_key_file) > 0)
1118                         g_key_file_set_string(keyfile, service->identifier,
1119                                         "PrivateKeyFile", service->private_key_file);
1120                 else
1121                         g_key_file_remove_key(keyfile, service->identifier,
1122                                         "PrivateKeyFile", NULL);
1123
1124                 if (service->private_key_passphrase != NULL && strlen(service->private_key_passphrase) > 0)
1125                         g_key_file_set_string(keyfile, service->identifier,
1126                                         "PrivateKeyPassphrase", service->private_key_passphrase);
1127                 else
1128                         g_key_file_remove_key(keyfile, service->identifier,
1129                                         "PrivateKeyPassphrase", NULL);
1130         }
1131 #endif
1132
1133 done:
1134         __connman_storage_save_service(keyfile, service->identifier);
1135
1136         g_key_file_free(keyfile);
1137
1138         return err;
1139 }
1140
1141 void __connman_service_save(struct connman_service *service)
1142 {
1143         if (!service)
1144                 return;
1145
1146         service_save(service);
1147 }
1148
1149 static enum connman_service_state combine_state(
1150                                         enum connman_service_state state_a,
1151                                         enum connman_service_state state_b)
1152 {
1153         enum connman_service_state result;
1154
1155         if (state_a == state_b) {
1156                 result = state_a;
1157                 goto done;
1158         }
1159
1160         if (state_a == CONNMAN_SERVICE_STATE_UNKNOWN) {
1161                 result = state_b;
1162                 goto done;
1163         }
1164
1165         if (state_b == CONNMAN_SERVICE_STATE_UNKNOWN) {
1166                 result = state_a;
1167                 goto done;
1168         }
1169
1170         if (state_a == CONNMAN_SERVICE_STATE_IDLE) {
1171                 result = state_b;
1172                 goto done;
1173         }
1174
1175         if (state_b == CONNMAN_SERVICE_STATE_IDLE) {
1176                 result = state_a;
1177                 goto done;
1178         }
1179
1180         if (state_a == CONNMAN_SERVICE_STATE_ONLINE) {
1181                 result = state_a;
1182                 goto done;
1183         }
1184
1185         if (state_b == CONNMAN_SERVICE_STATE_ONLINE) {
1186                 result = state_b;
1187                 goto done;
1188         }
1189
1190         if (state_a == CONNMAN_SERVICE_STATE_READY) {
1191                 result = state_a;
1192                 goto done;
1193         }
1194
1195         if (state_b == CONNMAN_SERVICE_STATE_READY) {
1196                 result = state_b;
1197                 goto done;
1198         }
1199
1200         if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION) {
1201                 result = state_a;
1202                 goto done;
1203         }
1204
1205         if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION) {
1206                 result = state_b;
1207                 goto done;
1208         }
1209
1210         if (state_a == CONNMAN_SERVICE_STATE_ASSOCIATION) {
1211                 result = state_a;
1212                 goto done;
1213         }
1214
1215         if (state_b == CONNMAN_SERVICE_STATE_ASSOCIATION) {
1216                 result = state_b;
1217                 goto done;
1218         }
1219
1220         if (state_a == CONNMAN_SERVICE_STATE_DISCONNECT) {
1221                 result = state_a;
1222                 goto done;
1223         }
1224
1225         if (state_b == CONNMAN_SERVICE_STATE_DISCONNECT) {
1226                 result = state_b;
1227                 goto done;
1228         }
1229
1230         result = CONNMAN_SERVICE_STATE_FAILURE;
1231
1232 done:
1233         return result;
1234 }
1235
1236 static bool is_connecting_state(struct connman_service *service,
1237                                         enum connman_service_state state)
1238 {
1239         switch (state) {
1240         case CONNMAN_SERVICE_STATE_UNKNOWN:
1241         case CONNMAN_SERVICE_STATE_IDLE:
1242         case CONNMAN_SERVICE_STATE_FAILURE:
1243                 if (service->network)
1244                         return connman_network_get_connecting(service->network);
1245         case CONNMAN_SERVICE_STATE_DISCONNECT:
1246         case CONNMAN_SERVICE_STATE_READY:
1247         case CONNMAN_SERVICE_STATE_ONLINE:
1248                 break;
1249         case CONNMAN_SERVICE_STATE_ASSOCIATION:
1250         case CONNMAN_SERVICE_STATE_CONFIGURATION:
1251                 return true;
1252         }
1253
1254         return false;
1255 }
1256
1257 static bool is_connected_state(const struct connman_service *service,
1258                                         enum connman_service_state state)
1259 {
1260         switch (state) {
1261         case CONNMAN_SERVICE_STATE_UNKNOWN:
1262         case CONNMAN_SERVICE_STATE_IDLE:
1263         case CONNMAN_SERVICE_STATE_ASSOCIATION:
1264         case CONNMAN_SERVICE_STATE_CONFIGURATION:
1265         case CONNMAN_SERVICE_STATE_DISCONNECT:
1266         case CONNMAN_SERVICE_STATE_FAILURE:
1267                 break;
1268         case CONNMAN_SERVICE_STATE_READY:
1269         case CONNMAN_SERVICE_STATE_ONLINE:
1270                 return true;
1271         }
1272
1273         return false;
1274 }
1275
1276 static bool is_idle_state(const struct connman_service *service,
1277                                 enum connman_service_state state)
1278 {
1279         switch (state) {
1280         case CONNMAN_SERVICE_STATE_UNKNOWN:
1281         case CONNMAN_SERVICE_STATE_ASSOCIATION:
1282         case CONNMAN_SERVICE_STATE_CONFIGURATION:
1283         case CONNMAN_SERVICE_STATE_READY:
1284         case CONNMAN_SERVICE_STATE_ONLINE:
1285         case CONNMAN_SERVICE_STATE_DISCONNECT:
1286         case CONNMAN_SERVICE_STATE_FAILURE:
1287                 break;
1288         case CONNMAN_SERVICE_STATE_IDLE:
1289                 return true;
1290         }
1291
1292         return false;
1293 }
1294
1295 static bool is_connecting(struct connman_service *service)
1296 {
1297         return is_connecting_state(service, service->state);
1298 }
1299
1300 static bool is_connected(struct connman_service *service)
1301 {
1302         return is_connected_state(service, service->state);
1303 }
1304
1305 static bool nameserver_available(struct connman_service *service,
1306                                 const char *ns)
1307 {
1308         int family;
1309
1310         family = connman_inet_check_ipaddress(ns);
1311
1312         if (family == AF_INET)
1313                 return is_connected_state(service, service->state_ipv4);
1314
1315         if (family == AF_INET6)
1316                 return is_connected_state(service, service->state_ipv6);
1317
1318         return false;
1319 }
1320
1321 static int nameserver_add(struct connman_service *service,
1322                         const char *nameserver)
1323 {
1324         int index;
1325
1326         if (!nameserver_available(service, nameserver))
1327                 return 0;
1328
1329         index = __connman_service_get_index(service);
1330         if (index < 0)
1331                 return -ENXIO;
1332
1333         return connman_resolver_append(index, NULL, nameserver);
1334 }
1335
1336 static int nameserver_add_all(struct connman_service *service)
1337 {
1338         int i = 0;
1339
1340         if (service->nameservers_config) {
1341                 while (service->nameservers_config[i]) {
1342                         nameserver_add(service, service->nameservers_config[i]);
1343                         i++;
1344                 }
1345
1346                 return 0;
1347         }
1348
1349         if (service->nameservers) {
1350                 while (service->nameservers[i]) {
1351                         nameserver_add(service, service->nameservers[i]);
1352                         i++;
1353                 }
1354         }
1355
1356         return 0;
1357 }
1358
1359 static int nameserver_remove(struct connman_service *service,
1360                         const char *nameserver)
1361 {
1362         int index;
1363
1364         if (!nameserver_available(service, nameserver))
1365                 return 0;
1366
1367         index = __connman_service_get_index(service);
1368         if (index < 0)
1369                 return -ENXIO;
1370
1371         return connman_resolver_remove(index, NULL, nameserver);
1372 }
1373
1374 static int nameserver_remove_all(struct connman_service *service)
1375 {
1376 #if defined TIZEN_EXT
1377         /**
1378           * Skip this function if there is any connected profiles
1379           * that use same interface
1380           */
1381         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
1382                         __connman_service_get_connected_count_of_iface(service) > 0)
1383                 return 0;
1384 #endif
1385         int index, i = 0;
1386
1387         index = __connman_service_get_index(service);
1388         if (index < 0)
1389                 return -ENXIO;
1390
1391         while (service->nameservers_config && service->nameservers_config[i]) {
1392
1393                 nameserver_remove(service, service->nameservers_config[i]);
1394                 i++;
1395         }
1396
1397         i = 0;
1398         while (service->nameservers && service->nameservers[i]) {
1399                 nameserver_remove(service, service->nameservers[i]);
1400                 i++;
1401         }
1402
1403         return 0;
1404 }
1405
1406 static int searchdomain_add_all(struct connman_service *service)
1407 {
1408         int index, i = 0;
1409
1410         if (!is_connected(service))
1411                 return -ENOTCONN;
1412
1413         index = __connman_service_get_index(service);
1414         if (index < 0)
1415                 return -ENXIO;
1416
1417         if (service->domains) {
1418                 while (service->domains[i]) {
1419                         connman_resolver_append(index, service->domains[i],
1420                                                 NULL);
1421                         i++;
1422                 }
1423
1424                 return 0;
1425         }
1426
1427         if (service->domainname)
1428                 connman_resolver_append(index, service->domainname, NULL);
1429
1430         return 0;
1431
1432 }
1433
1434 static int searchdomain_remove_all(struct connman_service *service)
1435 {
1436         int index, i = 0;
1437
1438         if (!is_connected(service))
1439                 return -ENOTCONN;
1440
1441         index = __connman_service_get_index(service);
1442         if (index < 0)
1443                 return -ENXIO;
1444
1445         while (service->domains && service->domains[i]) {
1446                 connman_resolver_remove(index, service->domains[i], NULL);
1447                 i++;
1448         }
1449
1450         if (service->domainname)
1451                 connman_resolver_remove(index, service->domainname, NULL);
1452
1453         return 0;
1454 }
1455
1456 /*
1457  * The is_auto variable is set to true when IPv6 autoconf nameservers are
1458  * inserted to resolver via netlink message (see rtnl.c:rtnl_newnduseropt()
1459  * for details) and not through service.c
1460  */
1461 int __connman_service_nameserver_append(struct connman_service *service,
1462                                 const char *nameserver, bool is_auto)
1463 {
1464         char **nameservers;
1465         int len, i;
1466
1467         DBG("service %p nameserver %s auto %d", service, nameserver, is_auto);
1468
1469         if (!nameserver)
1470                 return -EINVAL;
1471
1472         if (is_auto)
1473                 nameservers = service->nameservers_auto;
1474         else
1475                 nameservers = service->nameservers;
1476
1477         for (i = 0; nameservers && nameservers[i]; i++)
1478                 if (g_strcmp0(nameservers[i], nameserver) == 0)
1479                         return -EEXIST;
1480
1481         if (nameservers) {
1482                 len = g_strv_length(nameservers);
1483                 nameservers = g_try_renew(char *, nameservers, len + 2);
1484         } else {
1485                 len = 0;
1486                 nameservers = g_try_new0(char *, len + 2);
1487         }
1488
1489         if (!nameservers)
1490                 return -ENOMEM;
1491
1492         nameservers[len] = g_strdup(nameserver);
1493         if (!nameservers[len])
1494                 return -ENOMEM;
1495
1496         nameservers[len + 1] = NULL;
1497
1498 #ifdef TIZEN_EXT
1499         if(TIZEN_TV_EXT &&
1500            service->dns_config_method == CONNMAN_DNSCONFIG_METHOD_UNKNOWN)
1501                 service->dns_config_method = CONNMAN_DNSCONFIG_METHOD_DHCP;
1502 #endif
1503
1504         if (is_auto) {
1505                 service->nameservers_auto = nameservers;
1506         } else {
1507                 service->nameservers = nameservers;
1508                 nameserver_add(service, nameserver);
1509         }
1510
1511         return 0;
1512 }
1513
1514 int __connman_service_nameserver_remove(struct connman_service *service,
1515                                 const char *nameserver, bool is_auto)
1516 {
1517         char **servers, **nameservers;
1518         bool found = false;
1519         int len, i, j;
1520
1521         DBG("service %p nameserver %s auto %d", service, nameserver, is_auto);
1522
1523         if (!nameserver)
1524                 return -EINVAL;
1525
1526         if (is_auto)
1527                 nameservers = service->nameservers_auto;
1528         else
1529                 nameservers = service->nameservers;
1530
1531         if (!nameservers)
1532                 return 0;
1533
1534         for (i = 0; nameservers && nameservers[i]; i++)
1535                 if (g_strcmp0(nameservers[i], nameserver) == 0) {
1536                         found = true;
1537                         break;
1538                 }
1539
1540         if (!found)
1541                 return 0;
1542
1543         len = g_strv_length(nameservers);
1544
1545         if (len == 1) {
1546                 servers = NULL;
1547                 goto set_servers;
1548         }
1549
1550         servers = g_try_new0(char *, len);
1551         if (!servers)
1552                 return -ENOMEM;
1553
1554         for (i = 0, j = 0; i < len; i++) {
1555                 if (g_strcmp0(nameservers[i], nameserver)) {
1556                         servers[j] = nameservers[i];
1557                         j++;
1558                 } else
1559                         g_free(nameservers[i]);
1560
1561                 nameservers[i] = NULL;
1562         }
1563         servers[len - 1] = NULL;
1564
1565 set_servers:
1566         g_strfreev(nameservers);
1567         nameservers = servers;
1568
1569         if (is_auto) {
1570                 service->nameservers_auto = nameservers;
1571         } else {
1572                 service->nameservers = nameservers;
1573                 nameserver_remove(service, nameserver);
1574         }
1575
1576         return 0;
1577 }
1578
1579 void __connman_service_nameserver_clear(struct connman_service *service)
1580 {
1581         nameserver_remove_all(service);
1582
1583         g_strfreev(service->nameservers);
1584         service->nameservers = NULL;
1585
1586         nameserver_add_all(service);
1587 }
1588
1589 static void add_nameserver_route(int family, int index, char *nameserver,
1590                                 const char *gw)
1591 {
1592         switch (family) {
1593         case AF_INET:
1594                 if (connman_inet_compare_subnet(index, nameserver))
1595                         break;
1596
1597                 if (connman_inet_add_host_route(index, nameserver, gw) < 0)
1598                         /* For P-t-P link the above route add will fail */
1599                         connman_inet_add_host_route(index, nameserver, NULL);
1600                 break;
1601
1602         case AF_INET6:
1603                 if (connman_inet_add_ipv6_host_route(index, nameserver,
1604                                                                 gw) < 0)
1605                         connman_inet_add_ipv6_host_route(index, nameserver,
1606                                                         NULL);
1607                 break;
1608         }
1609 }
1610
1611 static void nameserver_add_routes(int index, char **nameservers,
1612                                         const char *gw)
1613 {
1614         int i, ns_family, gw_family;
1615
1616         gw_family = connman_inet_check_ipaddress(gw);
1617         if (gw_family < 0)
1618                 return;
1619
1620         for (i = 0; nameservers[i]; i++) {
1621                 ns_family = connman_inet_check_ipaddress(nameservers[i]);
1622                 if (ns_family < 0 || ns_family != gw_family)
1623                         continue;
1624
1625                 add_nameserver_route(ns_family, index, nameservers[i], gw);
1626         }
1627 }
1628
1629 static void nameserver_del_routes(int index, char **nameservers,
1630                                 enum connman_ipconfig_type type)
1631 {
1632         int i, family;
1633
1634         for (i = 0; nameservers[i]; i++) {
1635                 family = connman_inet_check_ipaddress(nameservers[i]);
1636                 if (family < 0)
1637                         continue;
1638
1639                 switch (family) {
1640                 case AF_INET:
1641                         if (type != CONNMAN_IPCONFIG_TYPE_IPV6)
1642                                 connman_inet_del_host_route(index,
1643                                                         nameservers[i]);
1644                         break;
1645                 case AF_INET6:
1646                         if (type != CONNMAN_IPCONFIG_TYPE_IPV4)
1647                                 connman_inet_del_ipv6_host_route(index,
1648                                                         nameservers[i]);
1649                         break;
1650                 }
1651         }
1652 }
1653
1654 void __connman_service_nameserver_add_routes(struct connman_service *service,
1655                                                 const char *gw)
1656 {
1657         int index;
1658
1659         if (!service)
1660                 return;
1661
1662         index = __connman_service_get_index(service);
1663
1664         if (service->nameservers_config) {
1665                 /*
1666                  * Configured nameserver takes preference over the
1667                  * discoverd nameserver gathered from DHCP, VPN, etc.
1668                  */
1669                 nameserver_add_routes(index, service->nameservers_config, gw);
1670         } else if (service->nameservers) {
1671                 /*
1672                  * We add nameservers host routes for nameservers that
1673                  * are not on our subnet. For those who are, the subnet
1674                  * route will be installed by the time the dns proxy code
1675                  * tries to reach them. The subnet route is installed
1676                  * when setting the interface IP address.
1677                  */
1678                 nameserver_add_routes(index, service->nameservers, gw);
1679         }
1680 }
1681
1682 void __connman_service_nameserver_del_routes(struct connman_service *service,
1683                                         enum connman_ipconfig_type type)
1684 {
1685         int index;
1686
1687         if (!service)
1688                 return;
1689
1690         index = __connman_service_get_index(service);
1691
1692         if (service->nameservers_config)
1693                 nameserver_del_routes(index, service->nameservers_config,
1694                                         type);
1695         else if (service->nameservers)
1696                 nameserver_del_routes(index, service->nameservers, type);
1697 }
1698
1699 static struct connman_stats *stats_get(struct connman_service *service)
1700 {
1701         if (service->roaming)
1702                 return &service->stats_roaming;
1703         else
1704                 return &service->stats;
1705 }
1706
1707 static bool stats_enabled(struct connman_service *service)
1708 {
1709         struct connman_stats *stats = stats_get(service);
1710
1711         return stats->enabled;
1712 }
1713
1714 static void stats_start(struct connman_service *service)
1715 {
1716         struct connman_stats *stats = stats_get(service);
1717
1718         DBG("service %p", service);
1719
1720         if (!stats->timer)
1721                 return;
1722
1723         stats->enabled = true;
1724         stats->data_last.time = stats->data.time;
1725
1726         g_timer_start(stats->timer);
1727 }
1728
1729 static void stats_stop(struct connman_service *service)
1730 {
1731         struct connman_stats *stats = stats_get(service);
1732         unsigned int seconds;
1733
1734         DBG("service %p", service);
1735
1736         if (!stats->timer)
1737                 return;
1738
1739         if (!stats->enabled)
1740                 return;
1741
1742         g_timer_stop(stats->timer);
1743
1744         seconds = g_timer_elapsed(stats->timer, NULL);
1745         stats->data.time = stats->data_last.time + seconds;
1746
1747         stats->enabled = false;
1748 }
1749
1750 static void reset_stats(struct connman_service *service)
1751 {
1752         DBG("service %p", service);
1753
1754         /* home */
1755         service->stats.valid = false;
1756
1757         service->stats.data.rx_packets = 0;
1758         service->stats.data.tx_packets = 0;
1759         service->stats.data.rx_bytes = 0;
1760         service->stats.data.tx_bytes = 0;
1761         service->stats.data.rx_errors = 0;
1762         service->stats.data.tx_errors = 0;
1763         service->stats.data.rx_dropped = 0;
1764         service->stats.data.tx_dropped = 0;
1765         service->stats.data.time = 0;
1766         service->stats.data_last.time = 0;
1767
1768         g_timer_reset(service->stats.timer);
1769
1770         /* roaming */
1771         service->stats_roaming.valid = false;
1772
1773         service->stats_roaming.data.rx_packets = 0;
1774         service->stats_roaming.data.tx_packets = 0;
1775         service->stats_roaming.data.rx_bytes = 0;
1776         service->stats_roaming.data.tx_bytes = 0;
1777         service->stats_roaming.data.rx_errors = 0;
1778         service->stats_roaming.data.tx_errors = 0;
1779         service->stats_roaming.data.rx_dropped = 0;
1780         service->stats_roaming.data.tx_dropped = 0;
1781         service->stats_roaming.data.time = 0;
1782         service->stats_roaming.data_last.time = 0;
1783
1784         g_timer_reset(service->stats_roaming.timer);
1785 }
1786
1787 #if defined TIZEN_EXT
1788 static gboolean __connman_service_is_internet_profile(
1789                 struct connman_service *cellular)
1790 {
1791         const char internet_suffix[] = "_1";
1792
1793         DBG("Service path: %s", cellular->path);
1794
1795         if (g_str_has_suffix(cellular->path, internet_suffix) == TRUE)
1796                 return TRUE;
1797
1798         return FALSE;
1799 }
1800
1801 static gboolean __connman_service_is_tethering_profile(
1802                 struct connman_service *cellular)
1803 {
1804         const char tethering_suffix[] = "_5";
1805
1806         DBG("Service path: %s", cellular->path);
1807
1808         if (g_str_has_suffix(cellular->path, tethering_suffix) == TRUE)
1809                 return TRUE;
1810
1811         return FALSE;
1812 }
1813
1814 struct connman_service *connman_service_get_default_connection(void)
1815 {
1816         GList *list;
1817         struct connman_service *service;
1818         struct connman_service *default_service = NULL;
1819
1820         for (list = service_list; list; list = list->next) {
1821                 service = list->data;
1822
1823                 DBG("service: %p %s %s %s", service, service->name,
1824                                 state2string(service->state),
1825                                 __connman_service_type2string(service->type));
1826
1827                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
1828                                 is_connected(service) == TRUE) {
1829                         return service;
1830                 } else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
1831                                 __connman_service_is_internet_profile(service) == TRUE) {
1832                         if (default_service == NULL)
1833                                 default_service = service;
1834                         else if (is_connected(service) == TRUE &&
1835                                         is_connected(default_service) == FALSE)
1836                                 default_service = service;
1837                 } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET &&
1838                                 is_connected(service) == TRUE) {
1839                         if (default_service == NULL)
1840                                 default_service = service;
1841                 } else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH &&
1842                                 is_connected(service) == TRUE) {
1843                         if (default_service == NULL)
1844                                 default_service = service;
1845                 }
1846         }
1847
1848         return default_service;
1849 }
1850 #endif
1851
1852 struct connman_service *__connman_service_get_default(void)
1853 {
1854         struct connman_service *service;
1855
1856         if (!service_list)
1857                 return NULL;
1858
1859         service = service_list->data;
1860
1861         if (!is_connected(service))
1862                 return NULL;
1863
1864         return service;
1865 }
1866
1867 bool __connman_service_index_is_default(int index)
1868 {
1869         struct connman_service *service;
1870
1871         if (index < 0)
1872                 return false;
1873
1874         service = __connman_service_get_default();
1875
1876         return __connman_service_get_index(service) == index;
1877 }
1878
1879 static void default_changed(void)
1880 {
1881         struct connman_service *service = __connman_service_get_default();
1882
1883         if (service == current_default)
1884                 return;
1885
1886         DBG("current default %p %s", current_default,
1887                 current_default ? current_default->identifier : "");
1888         DBG("new default %p %s", service, service ? service->identifier : "");
1889
1890 #if defined TIZEN_EXT
1891         current_default = service;
1892
1893         __connman_service_timeserver_changed(service, NULL);
1894 #else
1895         __connman_service_timeserver_changed(current_default, NULL);
1896
1897         current_default = service;
1898 #endif
1899
1900         if (service) {
1901                 if (service->hostname &&
1902                                 connman_setting_get_bool("AllowHostnameUpdates"))
1903                         __connman_utsname_set_hostname(service->hostname);
1904
1905                 if (service->domainname)
1906                         __connman_utsname_set_domainname(service->domainname);
1907         }
1908
1909         __connman_notifier_default_changed(service);
1910 }
1911
1912 static void state_changed(struct connman_service *service)
1913 {
1914         const char *str;
1915
1916         __connman_notifier_service_state_changed(service, service->state);
1917
1918         str = state2string(service->state);
1919         if (!str)
1920                 return;
1921
1922 #if !defined TIZEN_EXT
1923         if (!allow_property_changed(service))
1924                 return;
1925 #endif
1926
1927         connman_dbus_property_changed_basic(service->path,
1928                                 CONNMAN_SERVICE_INTERFACE, "State",
1929                                                 DBUS_TYPE_STRING, &str);
1930 }
1931
1932 static void strength_changed(struct connman_service *service)
1933 {
1934         if (service->strength == 0)
1935                 return;
1936
1937         if (!allow_property_changed(service))
1938                 return;
1939
1940         connman_dbus_property_changed_basic(service->path,
1941                                 CONNMAN_SERVICE_INTERFACE, "Strength",
1942                                         DBUS_TYPE_BYTE, &service->strength);
1943 }
1944
1945 static void favorite_changed(struct connman_service *service)
1946 {
1947         dbus_bool_t favorite;
1948
1949         if (!service->path)
1950                 return;
1951
1952         if (!allow_property_changed(service))
1953                 return;
1954
1955         favorite = service->favorite;
1956         connman_dbus_property_changed_basic(service->path,
1957                                 CONNMAN_SERVICE_INTERFACE, "Favorite",
1958                                         DBUS_TYPE_BOOLEAN, &favorite);
1959 }
1960
1961 static void immutable_changed(struct connman_service *service)
1962 {
1963         dbus_bool_t immutable;
1964
1965         if (!service->path)
1966                 return;
1967
1968         if (!allow_property_changed(service))
1969                 return;
1970
1971         immutable = service->immutable;
1972         connman_dbus_property_changed_basic(service->path,
1973                                 CONNMAN_SERVICE_INTERFACE, "Immutable",
1974                                         DBUS_TYPE_BOOLEAN, &immutable);
1975 }
1976
1977 static void roaming_changed(struct connman_service *service)
1978 {
1979         dbus_bool_t roaming;
1980
1981         if (!service->path)
1982                 return;
1983
1984         if (!allow_property_changed(service))
1985                 return;
1986
1987         roaming = service->roaming;
1988         connman_dbus_property_changed_basic(service->path,
1989                                 CONNMAN_SERVICE_INTERFACE, "Roaming",
1990                                         DBUS_TYPE_BOOLEAN, &roaming);
1991 }
1992
1993 static void autoconnect_changed(struct connman_service *service)
1994 {
1995         dbus_bool_t autoconnect;
1996
1997         if (!service->path)
1998                 return;
1999
2000         if (!allow_property_changed(service))
2001                 return;
2002
2003         autoconnect = service->autoconnect;
2004         connman_dbus_property_changed_basic(service->path,
2005                                 CONNMAN_SERVICE_INTERFACE, "AutoConnect",
2006                                 DBUS_TYPE_BOOLEAN, &autoconnect);
2007 }
2008
2009 static void append_security(DBusMessageIter *iter, void *user_data)
2010 {
2011         struct connman_service *service = user_data;
2012         const char *str;
2013
2014         str = security2string(service->security);
2015         if (str)
2016                 dbus_message_iter_append_basic(iter,
2017                                 DBUS_TYPE_STRING, &str);
2018
2019         /*
2020          * Some access points incorrectly advertise WPS even when they
2021          * are configured as open or no security, so filter
2022          * appropriately.
2023          */
2024         if (service->wps) {
2025                 switch (service->security) {
2026                 case CONNMAN_SERVICE_SECURITY_PSK:
2027                 case CONNMAN_SERVICE_SECURITY_WPA:
2028                 case CONNMAN_SERVICE_SECURITY_RSN:
2029                         str = "wps";
2030                         dbus_message_iter_append_basic(iter,
2031                                                 DBUS_TYPE_STRING, &str);
2032                         break;
2033                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
2034                 case CONNMAN_SERVICE_SECURITY_NONE:
2035                 case CONNMAN_SERVICE_SECURITY_WEP:
2036                 case CONNMAN_SERVICE_SECURITY_8021X:
2037                         break;
2038                 }
2039         }
2040 }
2041
2042 static void append_ethernet(DBusMessageIter *iter, void *user_data)
2043 {
2044         struct connman_service *service = user_data;
2045
2046         if (service->ipconfig_ipv4)
2047                 __connman_ipconfig_append_ethernet(service->ipconfig_ipv4,
2048                                                                         iter);
2049         else if (service->ipconfig_ipv6)
2050                 __connman_ipconfig_append_ethernet(service->ipconfig_ipv6,
2051                                                                         iter);
2052 }
2053
2054 static void append_ipv4(DBusMessageIter *iter, void *user_data)
2055 {
2056         struct connman_service *service = user_data;
2057
2058         if (!is_connected_state(service, service->state_ipv4))
2059                 return;
2060
2061         if (service->ipconfig_ipv4)
2062                 __connman_ipconfig_append_ipv4(service->ipconfig_ipv4, iter);
2063 }
2064
2065 static void append_ipv6(DBusMessageIter *iter, void *user_data)
2066 {
2067         struct connman_service *service = user_data;
2068
2069         if (!is_connected_state(service, service->state_ipv6))
2070                 return;
2071
2072         if (service->ipconfig_ipv6)
2073                 __connman_ipconfig_append_ipv6(service->ipconfig_ipv6, iter,
2074                                                 service->ipconfig_ipv4);
2075 }
2076
2077 static void append_ipv4config(DBusMessageIter *iter, void *user_data)
2078 {
2079         struct connman_service *service = user_data;
2080
2081         if (service->ipconfig_ipv4)
2082                 __connman_ipconfig_append_ipv4config(service->ipconfig_ipv4,
2083                                                         iter);
2084 }
2085
2086 static void append_ipv6config(DBusMessageIter *iter, void *user_data)
2087 {
2088         struct connman_service *service = user_data;
2089
2090         if (service->ipconfig_ipv6)
2091                 __connman_ipconfig_append_ipv6config(service->ipconfig_ipv6,
2092                                                         iter);
2093 }
2094
2095 static void append_nameservers(DBusMessageIter *iter,
2096                 struct connman_service *service, char **servers)
2097 {
2098         int i;
2099         bool available = true;
2100
2101         for (i = 0; servers[i]; i++) {
2102                 if (service)
2103                         available = nameserver_available(service, servers[i]);
2104
2105                 DBG("servers[%d] %s available %d", i, servers[i], available);
2106
2107                 if (available)
2108                         dbus_message_iter_append_basic(iter,
2109                                         DBUS_TYPE_STRING, &servers[i]);
2110         }
2111 }
2112
2113 static void append_dns(DBusMessageIter *iter, void *user_data)
2114 {
2115         struct connman_service *service = user_data;
2116
2117         if (!is_connected(service))
2118                 return;
2119
2120 #ifdef TIZEN_EXT
2121         const char *str;
2122         if (TIZEN_TV_EXT) {
2123                 /* Append DNS Config Type */
2124                 str = __connman_dnsconfig_method2string(service->dns_config_method);
2125                 if(str != NULL)
2126                         dbus_message_iter_append_basic(iter,
2127                                 DBUS_TYPE_STRING, &str);
2128         }
2129 #endif
2130
2131         if (service->nameservers_config) {
2132                 append_nameservers(iter, service, service->nameservers_config);
2133                 return;
2134         } else {
2135                 if (service->nameservers)
2136                         append_nameservers(iter, service,
2137                                         service->nameservers);
2138
2139                 if (service->nameservers_auto)
2140                         append_nameservers(iter, service,
2141                                         service->nameservers_auto);
2142
2143                 if (!service->nameservers && !service->nameservers_auto) {
2144                         char **ns;
2145
2146                         DBG("append fallback nameservers");
2147
2148                         ns = connman_setting_get_string_list("FallbackNameservers");
2149                         if (ns)
2150                                 append_nameservers(iter, service, ns);
2151                 }
2152         }
2153 }
2154
2155 static void append_dnsconfig(DBusMessageIter *iter, void *user_data)
2156 {
2157         struct connman_service *service = user_data;
2158
2159 #ifdef TIZEN_EXT
2160         /* Append DNS Config Type */
2161         const char *str;
2162         if (TIZEN_TV_EXT) {
2163                 str = __connman_dnsconfig_method2string(service->dns_config_method);
2164                 if(str != NULL)
2165                         dbus_message_iter_append_basic(iter,
2166                                 DBUS_TYPE_STRING, &str);
2167         }
2168 #endif
2169
2170         if (!service->nameservers_config)
2171                 return;
2172
2173         append_nameservers(iter, NULL, service->nameservers_config);
2174 }
2175
2176 static void append_ts(DBusMessageIter *iter, void *user_data)
2177 {
2178         GSList *list = user_data;
2179
2180         while (list) {
2181                 char *timeserver = list->data;
2182
2183                 if (timeserver)
2184                         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
2185                                         &timeserver);
2186
2187                 list = g_slist_next(list);
2188         }
2189 }
2190
2191 static void append_tsconfig(DBusMessageIter *iter, void *user_data)
2192 {
2193         struct connman_service *service = user_data;
2194         int i;
2195
2196         if (!service->timeservers_config)
2197                 return;
2198
2199         for (i = 0; service->timeservers_config[i]; i++) {
2200                 dbus_message_iter_append_basic(iter,
2201                                 DBUS_TYPE_STRING,
2202                                 &service->timeservers_config[i]);
2203         }
2204 }
2205
2206 static void append_domainconfig(DBusMessageIter *iter, void *user_data)
2207 {
2208         struct connman_service *service = user_data;
2209         int i;
2210
2211         if (!service->domains)
2212                 return;
2213
2214         for (i = 0; service->domains[i]; i++)
2215                 dbus_message_iter_append_basic(iter,
2216                                 DBUS_TYPE_STRING, &service->domains[i]);
2217 }
2218
2219 static void append_domain(DBusMessageIter *iter, void *user_data)
2220 {
2221         struct connman_service *service = user_data;
2222
2223         if (!is_connected(service) &&
2224                                 !is_connecting(service))
2225                 return;
2226
2227         if (service->domains)
2228                 append_domainconfig(iter, user_data);
2229         else if (service->domainname)
2230                 dbus_message_iter_append_basic(iter,
2231                                 DBUS_TYPE_STRING, &service->domainname);
2232 }
2233
2234 static void append_proxies(DBusMessageIter *iter, void *user_data)
2235 {
2236         struct connman_service *service = user_data;
2237         int i;
2238
2239         if (!service->proxies)
2240                 return;
2241
2242         for (i = 0; service->proxies[i]; i++)
2243                 dbus_message_iter_append_basic(iter,
2244                                 DBUS_TYPE_STRING, &service->proxies[i]);
2245 }
2246
2247 static void append_excludes(DBusMessageIter *iter, void *user_data)
2248 {
2249         struct connman_service *service = user_data;
2250         int i;
2251
2252         if (!service->excludes)
2253                 return;
2254
2255         for (i = 0; service->excludes[i]; i++)
2256                 dbus_message_iter_append_basic(iter,
2257                                 DBUS_TYPE_STRING, &service->excludes[i]);
2258 }
2259
2260 static void append_proxy(DBusMessageIter *iter, void *user_data)
2261 {
2262         struct connman_service *service = user_data;
2263         enum connman_service_proxy_method proxy;
2264         const char *pac = NULL;
2265         const char *method = proxymethod2string(
2266                 CONNMAN_SERVICE_PROXY_METHOD_DIRECT);
2267
2268         if (!is_connected(service))
2269                 return;
2270
2271         proxy = connman_service_get_proxy_method(service);
2272
2273         switch (proxy) {
2274         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
2275                 return;
2276         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
2277                 goto done;
2278         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
2279                 connman_dbus_dict_append_array(iter, "Servers",
2280                                         DBUS_TYPE_STRING, append_proxies,
2281                                         service);
2282
2283                 connman_dbus_dict_append_array(iter, "Excludes",
2284                                         DBUS_TYPE_STRING, append_excludes,
2285                                         service);
2286                 break;
2287         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
2288                 /* Maybe DHCP, or WPAD,  has provided an url for a pac file */
2289                 if (service->ipconfig_ipv4)
2290                         pac = __connman_ipconfig_get_proxy_autoconfig(
2291                                 service->ipconfig_ipv4);
2292                 else if (service->ipconfig_ipv6)
2293                         pac = __connman_ipconfig_get_proxy_autoconfig(
2294                                 service->ipconfig_ipv6);
2295
2296                 if (!service->pac && !pac)
2297                         goto done;
2298
2299                 if (service->pac)
2300                         pac = service->pac;
2301
2302                 connman_dbus_dict_append_basic(iter, "URL",
2303                                         DBUS_TYPE_STRING, &pac);
2304                 break;
2305         }
2306
2307         method = proxymethod2string(proxy);
2308
2309 done:
2310         connman_dbus_dict_append_basic(iter, "Method",
2311                                         DBUS_TYPE_STRING, &method);
2312 }
2313
2314 static void append_proxyconfig(DBusMessageIter *iter, void *user_data)
2315 {
2316         struct connman_service *service = user_data;
2317         const char *method;
2318
2319         if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
2320                 return;
2321
2322         switch (service->proxy_config) {
2323         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
2324                 return;
2325         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
2326                 break;
2327         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
2328                 if (service->proxies)
2329                         connman_dbus_dict_append_array(iter, "Servers",
2330                                                 DBUS_TYPE_STRING,
2331                                                 append_proxies, service);
2332
2333                 if (service->excludes)
2334                         connman_dbus_dict_append_array(iter, "Excludes",
2335                                                 DBUS_TYPE_STRING,
2336                                                 append_excludes, service);
2337                 break;
2338         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
2339                 if (service->pac)
2340                         connman_dbus_dict_append_basic(iter, "URL",
2341                                         DBUS_TYPE_STRING, &service->pac);
2342                 break;
2343         }
2344
2345         method = proxymethod2string(service->proxy_config);
2346
2347         connman_dbus_dict_append_basic(iter, "Method",
2348                                 DBUS_TYPE_STRING, &method);
2349 }
2350
2351 static void append_provider(DBusMessageIter *iter, void *user_data)
2352 {
2353         struct connman_service *service = user_data;
2354
2355         if (!is_connected(service))
2356                 return;
2357
2358         if (service->provider)
2359                 __connman_provider_append_properties(service->provider, iter);
2360 }
2361
2362
2363 static void settings_changed(struct connman_service *service,
2364                                 struct connman_ipconfig *ipconfig)
2365 {
2366         enum connman_ipconfig_type type;
2367
2368         if (!allow_property_changed(service))
2369                 return;
2370
2371         type = __connman_ipconfig_get_config_type(ipconfig);
2372
2373         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
2374                 connman_dbus_property_changed_dict(service->path,
2375                                         CONNMAN_SERVICE_INTERFACE, "IPv4",
2376                                         append_ipv4, service);
2377         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
2378                 connman_dbus_property_changed_dict(service->path,
2379                                         CONNMAN_SERVICE_INTERFACE, "IPv6",
2380                                         append_ipv6, service);
2381
2382         __connman_notifier_ipconfig_changed(service, ipconfig);
2383 }
2384
2385 static void ipv4_configuration_changed(struct connman_service *service)
2386 {
2387         if (!allow_property_changed(service))
2388                 return;
2389
2390         connman_dbus_property_changed_dict(service->path,
2391                                         CONNMAN_SERVICE_INTERFACE,
2392                                                         "IPv4.Configuration",
2393                                                         append_ipv4config,
2394                                                         service);
2395 }
2396
2397 static void ipv6_configuration_changed(struct connman_service *service)
2398 {
2399         if (!allow_property_changed(service))
2400                 return;
2401
2402         connman_dbus_property_changed_dict(service->path,
2403                                         CONNMAN_SERVICE_INTERFACE,
2404                                                         "IPv6.Configuration",
2405                                                         append_ipv6config,
2406                                                         service);
2407 }
2408
2409 static void dns_changed(struct connman_service *service)
2410 {
2411         if (!allow_property_changed(service))
2412                 return;
2413
2414         connman_dbus_property_changed_array(service->path,
2415                                 CONNMAN_SERVICE_INTERFACE, "Nameservers",
2416                                         DBUS_TYPE_STRING, append_dns, service);
2417 }
2418
2419 static void dns_configuration_changed(struct connman_service *service)
2420 {
2421         if (!allow_property_changed(service))
2422                 return;
2423
2424         connman_dbus_property_changed_array(service->path,
2425                                 CONNMAN_SERVICE_INTERFACE,
2426                                 "Nameservers.Configuration",
2427                                 DBUS_TYPE_STRING, append_dnsconfig, service);
2428
2429         dns_changed(service);
2430 }
2431
2432 static void domain_changed(struct connman_service *service)
2433 {
2434         if (!allow_property_changed(service))
2435                 return;
2436
2437         connman_dbus_property_changed_array(service->path,
2438                                 CONNMAN_SERVICE_INTERFACE, "Domains",
2439                                 DBUS_TYPE_STRING, append_domain, service);
2440 }
2441
2442 static void domain_configuration_changed(struct connman_service *service)
2443 {
2444         if (!allow_property_changed(service))
2445                 return;
2446
2447         connman_dbus_property_changed_array(service->path,
2448                                 CONNMAN_SERVICE_INTERFACE,
2449                                 "Domains.Configuration",
2450                                 DBUS_TYPE_STRING, append_domainconfig, service);
2451 }
2452
2453 static void proxy_changed(struct connman_service *service)
2454 {
2455         if (!allow_property_changed(service))
2456                 return;
2457
2458         connman_dbus_property_changed_dict(service->path,
2459                                         CONNMAN_SERVICE_INTERFACE, "Proxy",
2460                                                         append_proxy, service);
2461 }
2462
2463 static void proxy_configuration_changed(struct connman_service *service)
2464 {
2465         if (!allow_property_changed(service))
2466                 return;
2467
2468         connman_dbus_property_changed_dict(service->path,
2469                         CONNMAN_SERVICE_INTERFACE, "Proxy.Configuration",
2470                                                 append_proxyconfig, service);
2471
2472         proxy_changed(service);
2473 }
2474
2475 static void timeservers_configuration_changed(struct connman_service *service)
2476 {
2477         if (!allow_property_changed(service))
2478                 return;
2479
2480         connman_dbus_property_changed_array(service->path,
2481                         CONNMAN_SERVICE_INTERFACE,
2482                         "Timeservers.Configuration",
2483                         DBUS_TYPE_STRING,
2484                         append_tsconfig, service);
2485 }
2486
2487 static void link_changed(struct connman_service *service)
2488 {
2489         if (!allow_property_changed(service))
2490                 return;
2491
2492         connman_dbus_property_changed_dict(service->path,
2493                                         CONNMAN_SERVICE_INTERFACE, "Ethernet",
2494                                                 append_ethernet, service);
2495 }
2496
2497 static void stats_append_counters(DBusMessageIter *dict,
2498                         struct connman_stats_data *stats,
2499                         struct connman_stats_data *counters,
2500                         bool append_all)
2501 {
2502         if (counters->rx_packets != stats->rx_packets || append_all) {
2503                 counters->rx_packets = stats->rx_packets;
2504                 connman_dbus_dict_append_basic(dict, "RX.Packets",
2505                                         DBUS_TYPE_UINT32, &stats->rx_packets);
2506         }
2507
2508         if (counters->tx_packets != stats->tx_packets || append_all) {
2509                 counters->tx_packets = stats->tx_packets;
2510                 connman_dbus_dict_append_basic(dict, "TX.Packets",
2511                                         DBUS_TYPE_UINT32, &stats->tx_packets);
2512         }
2513
2514         if (counters->rx_bytes != stats->rx_bytes || append_all) {
2515                 counters->rx_bytes = stats->rx_bytes;
2516                 connman_dbus_dict_append_basic(dict, "RX.Bytes",
2517                                         DBUS_TYPE_UINT32, &stats->rx_bytes);
2518         }
2519
2520         if (counters->tx_bytes != stats->tx_bytes || append_all) {
2521                 counters->tx_bytes = stats->tx_bytes;
2522                 connman_dbus_dict_append_basic(dict, "TX.Bytes",
2523                                         DBUS_TYPE_UINT32, &stats->tx_bytes);
2524         }
2525
2526         if (counters->rx_errors != stats->rx_errors || append_all) {
2527                 counters->rx_errors = stats->rx_errors;
2528                 connman_dbus_dict_append_basic(dict, "RX.Errors",
2529                                         DBUS_TYPE_UINT32, &stats->rx_errors);
2530         }
2531
2532         if (counters->tx_errors != stats->tx_errors || append_all) {
2533                 counters->tx_errors = stats->tx_errors;
2534                 connman_dbus_dict_append_basic(dict, "TX.Errors",
2535                                         DBUS_TYPE_UINT32, &stats->tx_errors);
2536         }
2537
2538         if (counters->rx_dropped != stats->rx_dropped || append_all) {
2539                 counters->rx_dropped = stats->rx_dropped;
2540                 connman_dbus_dict_append_basic(dict, "RX.Dropped",
2541                                         DBUS_TYPE_UINT32, &stats->rx_dropped);
2542         }
2543
2544         if (counters->tx_dropped != stats->tx_dropped || append_all) {
2545                 counters->tx_dropped = stats->tx_dropped;
2546                 connman_dbus_dict_append_basic(dict, "TX.Dropped",
2547                                         DBUS_TYPE_UINT32, &stats->tx_dropped);
2548         }
2549
2550         if (counters->time != stats->time || append_all) {
2551                 counters->time = stats->time;
2552                 connman_dbus_dict_append_basic(dict, "Time",
2553                                         DBUS_TYPE_UINT32, &stats->time);
2554         }
2555 }
2556
2557 static void stats_append(struct connman_service *service,
2558                                 const char *counter,
2559                                 struct connman_stats_counter *counters,
2560                                 bool append_all)
2561 {
2562         DBusMessageIter array, dict;
2563         DBusMessage *msg;
2564
2565         DBG("service %p counter %s", service, counter);
2566
2567         msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
2568         if (!msg)
2569                 return;
2570
2571         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH,
2572                                 &service->path, DBUS_TYPE_INVALID);
2573
2574         dbus_message_iter_init_append(msg, &array);
2575
2576         /* home counter */
2577         connman_dbus_dict_open(&array, &dict);
2578
2579         stats_append_counters(&dict, &service->stats.data,
2580                                 &counters->stats.data, append_all);
2581
2582         connman_dbus_dict_close(&array, &dict);
2583
2584         /* roaming counter */
2585         connman_dbus_dict_open(&array, &dict);
2586
2587         stats_append_counters(&dict, &service->stats_roaming.data,
2588                                 &counters->stats_roaming.data, append_all);
2589
2590         connman_dbus_dict_close(&array, &dict);
2591
2592         __connman_counter_send_usage(counter, msg);
2593 }
2594
2595 static void stats_update(struct connman_service *service,
2596                                 unsigned int rx_packets, unsigned int tx_packets,
2597                                 unsigned int rx_bytes, unsigned int tx_bytes,
2598                                 unsigned int rx_errors, unsigned int tx_errors,
2599                                 unsigned int rx_dropped, unsigned int tx_dropped)
2600 {
2601         struct connman_stats *stats = stats_get(service);
2602         struct connman_stats_data *data_last = &stats->data_last;
2603         struct connman_stats_data *data = &stats->data;
2604         unsigned int seconds;
2605
2606         DBG("service %p", service);
2607
2608         if (stats->valid) {
2609                 data->rx_packets +=
2610                         rx_packets - data_last->rx_packets;
2611                 data->tx_packets +=
2612                         tx_packets - data_last->tx_packets;
2613                 data->rx_bytes +=
2614                         rx_bytes - data_last->rx_bytes;
2615                 data->tx_bytes +=
2616                         tx_bytes - data_last->tx_bytes;
2617                 data->rx_errors +=
2618                         rx_errors - data_last->rx_errors;
2619                 data->tx_errors +=
2620                         tx_errors - data_last->tx_errors;
2621                 data->rx_dropped +=
2622                         rx_dropped - data_last->rx_dropped;
2623                 data->tx_dropped +=
2624                         tx_dropped - data_last->tx_dropped;
2625         } else {
2626                 stats->valid = true;
2627         }
2628
2629         data_last->rx_packets = rx_packets;
2630         data_last->tx_packets = tx_packets;
2631         data_last->rx_bytes = rx_bytes;
2632         data_last->tx_bytes = tx_bytes;
2633         data_last->rx_errors = rx_errors;
2634         data_last->tx_errors = tx_errors;
2635         data_last->rx_dropped = rx_dropped;
2636         data_last->tx_dropped = tx_dropped;
2637
2638         seconds = g_timer_elapsed(stats->timer, NULL);
2639         stats->data.time = stats->data_last.time + seconds;
2640 }
2641
2642 void __connman_service_notify(struct connman_service *service,
2643                         unsigned int rx_packets, unsigned int tx_packets,
2644                         unsigned int rx_bytes, unsigned int tx_bytes,
2645                         unsigned int rx_errors, unsigned int tx_errors,
2646                         unsigned int rx_dropped, unsigned int tx_dropped)
2647 {
2648         GHashTableIter iter;
2649         gpointer key, value;
2650         const char *counter;
2651         struct connman_stats_counter *counters;
2652         struct connman_stats_data *data;
2653         int err;
2654
2655         if (!service)
2656                 return;
2657
2658         if (!is_connected(service))
2659                 return;
2660
2661         stats_update(service,
2662                 rx_packets, tx_packets,
2663                 rx_bytes, tx_bytes,
2664                 rx_errors, tx_errors,
2665                 rx_dropped, tx_dropped);
2666
2667         data = &stats_get(service)->data;
2668         err = __connman_stats_update(service, service->roaming, data);
2669         if (err < 0)
2670                 connman_error("Failed to store statistics for %s",
2671                                 service->identifier);
2672
2673         g_hash_table_iter_init(&iter, service->counter_table);
2674         while (g_hash_table_iter_next(&iter, &key, &value)) {
2675                 counter = key;
2676                 counters = value;
2677
2678                 stats_append(service, counter, counters, counters->append_all);
2679                 counters->append_all = false;
2680         }
2681 }
2682
2683 int __connman_service_counter_register(const char *counter)
2684 {
2685         struct connman_service *service;
2686         GList *list;
2687         struct connman_stats_counter *counters;
2688
2689         DBG("counter %s", counter);
2690
2691         counter_list = g_slist_prepend(counter_list, (gpointer)counter);
2692
2693         for (list = service_list; list; list = list->next) {
2694                 service = list->data;
2695
2696                 counters = g_try_new0(struct connman_stats_counter, 1);
2697                 if (!counters)
2698                         return -ENOMEM;
2699
2700                 counters->append_all = true;
2701
2702                 g_hash_table_replace(service->counter_table, (gpointer)counter,
2703                                         counters);
2704         }
2705
2706         return 0;
2707 }
2708
2709 void __connman_service_counter_unregister(const char *counter)
2710 {
2711         struct connman_service *service;
2712         GList *list;
2713
2714         DBG("counter %s", counter);
2715
2716         for (list = service_list; list; list = list->next) {
2717                 service = list->data;
2718
2719                 g_hash_table_remove(service->counter_table, counter);
2720         }
2721
2722         counter_list = g_slist_remove(counter_list, counter);
2723 }
2724
2725 int __connman_service_iterate_services(service_iterate_cb cb, void *user_data)
2726 {
2727         GList *list;
2728
2729         for (list = service_list; list; list = list->next) {
2730                 struct connman_service *service = list->data;
2731
2732                 cb(service, user_data);
2733         }
2734
2735         return 0;
2736 }
2737
2738 #if defined TIZEN_EXT
2739 static void append_wifi_ext_info(DBusMessageIter *dict,
2740                                         struct connman_network *network)
2741 {
2742         char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
2743         char *bssid_str = bssid_buff;
2744         unsigned char *bssid;
2745         unsigned int maxrate;
2746         unsigned int keymgmt;
2747         uint16_t frequency;
2748         const char *enc_mode;
2749         gboolean passpoint;
2750
2751         bssid = connman_network_get_bssid(network);
2752         maxrate = connman_network_get_maxrate(network);
2753         frequency = connman_network_get_frequency(network);
2754         enc_mode = connman_network_get_enc_mode(network);
2755         passpoint = connman_network_get_is_hs20AP(network);
2756         keymgmt = connman_network_get_keymgmt(network);
2757
2758         snprintf(bssid_str, WIFI_BSSID_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
2759                                 bssid[0], bssid[1], bssid[2],
2760                                 bssid[3], bssid[4], bssid[5]);
2761
2762         connman_dbus_dict_append_basic(dict, "BSSID",
2763                                         DBUS_TYPE_STRING, &bssid_str);
2764         connman_dbus_dict_append_basic(dict, "MaxRate",
2765                                         DBUS_TYPE_UINT32, &maxrate);
2766         connman_dbus_dict_append_basic(dict, "Frequency",
2767                                         DBUS_TYPE_UINT16, &frequency);
2768         connman_dbus_dict_append_basic(dict, "EncryptionMode",
2769                                         DBUS_TYPE_STRING, &enc_mode);
2770         connman_dbus_dict_append_basic(dict, "Passpoint",
2771                                         DBUS_TYPE_BOOLEAN, &passpoint);
2772         connman_dbus_dict_append_basic(dict, "Keymgmt",
2773                                         DBUS_TYPE_UINT32, &keymgmt);
2774 }
2775 #endif
2776
2777 static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
2778                                         struct connman_service *service)
2779 {
2780         dbus_bool_t val;
2781         const char *str;
2782         GSList *list;
2783
2784 #if defined TIZEN_EXT
2785         unsigned int frequency = 0U;
2786         if (service && service->network) {
2787                 frequency = connman_network_get_frequency(service->network);
2788                 connman_dbus_dict_append_basic(dict, "Frequency",
2789                                 DBUS_TYPE_UINT16, &frequency);
2790         }
2791 #endif
2792
2793         str = __connman_service_type2string(service->type);
2794         if (str)
2795                 connman_dbus_dict_append_basic(dict, "Type",
2796                                                 DBUS_TYPE_STRING, &str);
2797
2798         connman_dbus_dict_append_array(dict, "Security",
2799                                 DBUS_TYPE_STRING, append_security, service);
2800
2801         str = state2string(service->state);
2802         if (str)
2803                 connman_dbus_dict_append_basic(dict, "State",
2804                                                 DBUS_TYPE_STRING, &str);
2805
2806 #ifdef TIZEN_EXT
2807         if (TIZEN_TV_EXT) {
2808                 str = state2string(service->state_ipv6);
2809                 if (str != NULL)
2810                         connman_dbus_dict_append_basic(dict, "StateIPv6",
2811                                                         DBUS_TYPE_STRING, &str);
2812         }
2813 #endif
2814
2815         str = error2string(service->error);
2816         if (str)
2817                 connman_dbus_dict_append_basic(dict, "Error",
2818                                                 DBUS_TYPE_STRING, &str);
2819
2820         if (service->strength > 0)
2821                 connman_dbus_dict_append_basic(dict, "Strength",
2822                                         DBUS_TYPE_BYTE, &service->strength);
2823
2824         val = service->favorite;
2825         connman_dbus_dict_append_basic(dict, "Favorite",
2826                                         DBUS_TYPE_BOOLEAN, &val);
2827
2828         val = service->immutable;
2829         connman_dbus_dict_append_basic(dict, "Immutable",
2830                                         DBUS_TYPE_BOOLEAN, &val);
2831
2832         if (service->favorite)
2833                 val = service->autoconnect;
2834         else
2835                 val = service->favorite;
2836
2837         connman_dbus_dict_append_basic(dict, "AutoConnect",
2838                                 DBUS_TYPE_BOOLEAN, &val);
2839
2840         if (service->name)
2841                 connman_dbus_dict_append_basic(dict, "Name",
2842                                         DBUS_TYPE_STRING, &service->name);
2843
2844         switch (service->type) {
2845         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2846         case CONNMAN_SERVICE_TYPE_SYSTEM:
2847         case CONNMAN_SERVICE_TYPE_GPS:
2848         case CONNMAN_SERVICE_TYPE_VPN:
2849         case CONNMAN_SERVICE_TYPE_P2P:
2850                 break;
2851         case CONNMAN_SERVICE_TYPE_CELLULAR:
2852                 val = service->roaming;
2853                 connman_dbus_dict_append_basic(dict, "Roaming",
2854                                         DBUS_TYPE_BOOLEAN, &val);
2855
2856                 connman_dbus_dict_append_dict(dict, "Ethernet",
2857                                                 append_ethernet, service);
2858                 break;
2859         case CONNMAN_SERVICE_TYPE_WIFI:
2860 #if defined TIZEN_EXT
2861                 if (service->network != NULL)
2862                         append_wifi_ext_info(dict, service->network);
2863
2864                 connman_dbus_dict_append_dict(dict, "Ethernet",
2865                                                 append_ethernet, service);
2866
2867                 connman_dbus_dict_append_basic(dict, "DisconnectReason",
2868                                 DBUS_TYPE_INT32, &service->disconnect_reason);
2869
2870                 break;
2871 #endif
2872         case CONNMAN_SERVICE_TYPE_ETHERNET:
2873         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2874         case CONNMAN_SERVICE_TYPE_GADGET:
2875                 connman_dbus_dict_append_dict(dict, "Ethernet",
2876                                                 append_ethernet, service);
2877                 break;
2878         }
2879
2880         connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service);
2881
2882         connman_dbus_dict_append_dict(dict, "IPv4.Configuration",
2883                                                 append_ipv4config, service);
2884
2885         connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service);
2886
2887         connman_dbus_dict_append_dict(dict, "IPv6.Configuration",
2888                                                 append_ipv6config, service);
2889
2890         connman_dbus_dict_append_array(dict, "Nameservers",
2891                                 DBUS_TYPE_STRING, append_dns, service);
2892
2893         connman_dbus_dict_append_array(dict, "Nameservers.Configuration",
2894                                 DBUS_TYPE_STRING, append_dnsconfig, service);
2895
2896         if (service->state == CONNMAN_SERVICE_STATE_READY ||
2897                         service->state == CONNMAN_SERVICE_STATE_ONLINE)
2898                 list = __connman_timeserver_get_all(service);
2899         else
2900                 list = NULL;
2901
2902         connman_dbus_dict_append_array(dict, "Timeservers",
2903                                 DBUS_TYPE_STRING, append_ts, list);
2904
2905         g_slist_free_full(list, g_free);
2906
2907         connman_dbus_dict_append_array(dict, "Timeservers.Configuration",
2908                                 DBUS_TYPE_STRING, append_tsconfig, service);
2909
2910         connman_dbus_dict_append_array(dict, "Domains",
2911                                 DBUS_TYPE_STRING, append_domain, service);
2912
2913         connman_dbus_dict_append_array(dict, "Domains.Configuration",
2914                                 DBUS_TYPE_STRING, append_domainconfig, service);
2915
2916         connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service);
2917
2918         connman_dbus_dict_append_dict(dict, "Proxy.Configuration",
2919                                                 append_proxyconfig, service);
2920
2921         connman_dbus_dict_append_dict(dict, "Provider",
2922                                                 append_provider, service);
2923 }
2924
2925 static void append_struct_service(DBusMessageIter *iter,
2926                 connman_dbus_append_cb_t function,
2927                 struct connman_service *service)
2928 {
2929         DBusMessageIter entry, dict;
2930
2931         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
2932
2933         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
2934                                                         &service->path);
2935
2936         connman_dbus_dict_open(&entry, &dict);
2937         if (function)
2938                 function(&dict, service);
2939         connman_dbus_dict_close(&entry, &dict);
2940
2941         dbus_message_iter_close_container(iter, &entry);
2942 }
2943
2944 static void append_dict_properties(DBusMessageIter *dict, void *user_data)
2945 {
2946         struct connman_service *service = user_data;
2947
2948         append_properties(dict, TRUE, service);
2949 }
2950
2951 static void append_struct(gpointer value, gpointer user_data)
2952 {
2953         struct connman_service *service = value;
2954         DBusMessageIter *iter = user_data;
2955
2956         if (!service->path)
2957                 return;
2958
2959         append_struct_service(iter, append_dict_properties, service);
2960 }
2961
2962 void __connman_service_list_struct(DBusMessageIter *iter)
2963 {
2964         g_list_foreach(service_list, append_struct, iter);
2965 }
2966
2967 bool __connman_service_is_hidden(struct connman_service *service)
2968 {
2969         return service->hidden;
2970 }
2971
2972 bool
2973 __connman_service_is_split_routing(struct connman_service *service)
2974 {
2975         return service->do_split_routing;
2976 }
2977
2978 bool __connman_service_index_is_split_routing(int index)
2979 {
2980         struct connman_service *service;
2981
2982         if (index < 0)
2983                 return false;
2984
2985         service = __connman_service_lookup_from_index(index);
2986         if (!service)
2987                 return false;
2988
2989         return __connman_service_is_split_routing(service);
2990 }
2991
2992 int __connman_service_get_index(struct connman_service *service)
2993 {
2994         if (!service)
2995                 return -1;
2996
2997         if (service->network)
2998                 return connman_network_get_index(service->network);
2999         else if (service->provider)
3000                 return connman_provider_get_index(service->provider);
3001
3002         return -1;
3003 }
3004
3005 void __connman_service_set_hidden(struct connman_service *service)
3006 {
3007         if (!service || service->hidden)
3008                 return;
3009
3010         service->hidden_service = true;
3011 }
3012
3013 void __connman_service_set_hostname(struct connman_service *service,
3014                                                 const char *hostname)
3015 {
3016         if (!service || service->hidden)
3017                 return;
3018
3019         g_free(service->hostname);
3020         service->hostname = g_strdup(hostname);
3021 }
3022
3023 const char *__connman_service_get_hostname(struct connman_service *service)
3024 {
3025         if (!service)
3026                 return NULL;
3027
3028         return service->hostname;
3029 }
3030
3031 void __connman_service_set_domainname(struct connman_service *service,
3032                                                 const char *domainname)
3033 {
3034         if (!service || service->hidden)
3035                 return;
3036
3037         g_free(service->domainname);
3038         service->domainname = g_strdup(domainname);
3039
3040         domain_changed(service);
3041 }
3042
3043 const char *connman_service_get_domainname(struct connman_service *service)
3044 {
3045         if (!service)
3046                 return NULL;
3047
3048         if (service->domains)
3049                 return service->domains[0];
3050         else
3051                 return service->domainname;
3052 }
3053
3054 char **connman_service_get_nameservers(struct connman_service *service)
3055 {
3056         if (!service)
3057                 return NULL;
3058
3059         if (service->nameservers_config)
3060                 return g_strdupv(service->nameservers_config);
3061         else if (service->nameservers ||
3062                                         service->nameservers_auto) {
3063                 int len = 0, len_auto = 0, i;
3064                 char **nameservers;
3065
3066                 if (service->nameservers)
3067                         len = g_strv_length(service->nameservers);
3068                 if (service->nameservers_auto)
3069                         len_auto = g_strv_length(service->nameservers_auto);
3070
3071                 nameservers = g_try_new0(char *, len + len_auto + 1);
3072                 if (!nameservers)
3073                         return NULL;
3074
3075                 for (i = 0; i < len; i++)
3076                         nameservers[i] = g_strdup(service->nameservers[i]);
3077
3078                 for (i = 0; i < len_auto; i++)
3079                         nameservers[i + len] =
3080                                 g_strdup(service->nameservers_auto[i]);
3081
3082                 return nameservers;
3083         }
3084
3085         return g_strdupv(connman_setting_get_string_list("FallbackNameservers"));
3086 }
3087
3088 char **connman_service_get_timeservers_config(struct connman_service *service)
3089 {
3090         if (!service)
3091                 return NULL;
3092
3093         return service->timeservers_config;
3094 }
3095
3096 char **connman_service_get_timeservers(struct connman_service *service)
3097 {
3098         if (!service)
3099                 return NULL;
3100
3101         return service->timeservers;
3102 }
3103
3104 #if defined TIZEN_EXT
3105 /*
3106  * Description: Telephony plug-in requires manual PROXY setting function
3107  */
3108 int connman_service_set_proxy(struct connman_service *service,
3109                                         const char *proxy, gboolean active)
3110 {
3111         char **proxies_array = NULL;
3112
3113         if (service == NULL)
3114                 return -EINVAL;
3115
3116         switch (service->type) {
3117         case CONNMAN_SERVICE_TYPE_CELLULAR:
3118         case CONNMAN_SERVICE_TYPE_ETHERNET:
3119         case CONNMAN_SERVICE_TYPE_WIFI:
3120                 break;
3121
3122         default:
3123                 return -EINVAL;
3124         }
3125
3126         g_strfreev(service->proxies);
3127         service->proxies = NULL;
3128
3129         if (proxy != NULL)
3130                 proxies_array = g_strsplit(proxy, " ", 0);
3131
3132         service->proxies = proxies_array;
3133
3134         if (proxy == NULL) {
3135                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
3136                 DBG("proxy changed (%d)", active);
3137         } else {
3138                 service->proxy_config = CONNMAN_SERVICE_PROXY_METHOD_MANUAL;
3139                 DBG("proxy chagned %s (%d)", proxy, active);
3140         }
3141
3142         if (active == TRUE) {
3143                 proxy_changed(service);
3144
3145                 __connman_notifier_proxy_changed(service);
3146         }
3147
3148         return 0;
3149 }
3150 #endif
3151
3152 void connman_service_set_proxy_method(struct connman_service *service,
3153                                         enum connman_service_proxy_method method)
3154 {
3155         if (!service || service->hidden)
3156                 return;
3157
3158         service->proxy = method;
3159
3160         proxy_changed(service);
3161
3162         if (method != CONNMAN_SERVICE_PROXY_METHOD_AUTO)
3163                 __connman_notifier_proxy_changed(service);
3164 }
3165
3166 enum connman_service_proxy_method connman_service_get_proxy_method(
3167                                         struct connman_service *service)
3168 {
3169         if (!service)
3170                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
3171
3172         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) {
3173                 if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_AUTO &&
3174                                 !service->pac)
3175                         return service->proxy;
3176
3177                 return service->proxy_config;
3178         }
3179
3180         return service->proxy;
3181 }
3182
3183 char **connman_service_get_proxy_servers(struct connman_service *service)
3184 {
3185         return g_strdupv(service->proxies);
3186 }
3187
3188 char **connman_service_get_proxy_excludes(struct connman_service *service)
3189 {
3190         return g_strdupv(service->excludes);
3191 }
3192
3193 const char *connman_service_get_proxy_url(struct connman_service *service)
3194 {
3195         if (!service)
3196                 return NULL;
3197
3198         return service->pac;
3199 }
3200
3201 void __connman_service_set_proxy_autoconfig(struct connman_service *service,
3202                                                         const char *url)
3203 {
3204         if (!service || service->hidden)
3205                 return;
3206
3207         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_AUTO;
3208
3209         if (service->ipconfig_ipv4) {
3210                 if (__connman_ipconfig_set_proxy_autoconfig(
3211                             service->ipconfig_ipv4, url) < 0)
3212                         return;
3213         } else if (service->ipconfig_ipv6) {
3214                 if (__connman_ipconfig_set_proxy_autoconfig(
3215                             service->ipconfig_ipv6, url) < 0)
3216                         return;
3217         } else
3218                 return;
3219
3220         proxy_changed(service);
3221
3222         __connman_notifier_proxy_changed(service);
3223 }
3224
3225 const char *connman_service_get_proxy_autoconfig(struct connman_service *service)
3226 {
3227         if (!service)
3228                 return NULL;
3229
3230         if (service->ipconfig_ipv4)
3231                 return __connman_ipconfig_get_proxy_autoconfig(
3232                                                 service->ipconfig_ipv4);
3233         else if (service->ipconfig_ipv6)
3234                 return __connman_ipconfig_get_proxy_autoconfig(
3235                                                 service->ipconfig_ipv6);
3236         return NULL;
3237 }
3238
3239 void __connman_service_set_timeservers(struct connman_service *service,
3240                                 char **timeservers)
3241 {
3242         int i;
3243
3244         if (!service)
3245                 return;
3246
3247         g_strfreev(service->timeservers);
3248         service->timeservers = NULL;
3249
3250         for (i = 0; timeservers && timeservers[i]; i++)
3251                 __connman_service_timeserver_append(service, timeservers[i]);
3252 }
3253
3254 int __connman_service_timeserver_append(struct connman_service *service,
3255                                                 const char *timeserver)
3256 {
3257         int len;
3258
3259         DBG("service %p timeserver %s", service, timeserver);
3260
3261         if (!timeserver)
3262                 return -EINVAL;
3263
3264         if (service->timeservers) {
3265                 int i;
3266
3267                 for (i = 0; service->timeservers[i]; i++)
3268                         if (g_strcmp0(service->timeservers[i], timeserver) == 0)
3269                                 return -EEXIST;
3270
3271                 len = g_strv_length(service->timeservers);
3272                 service->timeservers = g_try_renew(char *, service->timeservers,
3273                                                         len + 2);
3274         } else {
3275                 len = 0;
3276                 service->timeservers = g_try_new0(char *, len + 2);
3277         }
3278
3279         if (!service->timeservers)
3280                 return -ENOMEM;
3281
3282         service->timeservers[len] = g_strdup(timeserver);
3283         service->timeservers[len + 1] = NULL;
3284
3285         return 0;
3286 }
3287
3288 int __connman_service_timeserver_remove(struct connman_service *service,
3289                                                 const char *timeserver)
3290 {
3291         char **servers;
3292         int len, i, j, found = 0;
3293
3294         DBG("service %p timeserver %s", service, timeserver);
3295
3296         if (!timeserver)
3297                 return -EINVAL;
3298
3299         if (!service->timeservers)
3300                 return 0;
3301
3302         for (i = 0; service->timeservers &&
3303                                         service->timeservers[i]; i++)
3304                 if (g_strcmp0(service->timeservers[i], timeserver) == 0) {
3305                         found = 1;
3306                         break;
3307                 }
3308
3309         if (found == 0)
3310                 return 0;
3311
3312         len = g_strv_length(service->timeservers);
3313
3314         if (len == 1) {
3315                 g_strfreev(service->timeservers);
3316                 service->timeservers = NULL;
3317
3318                 return 0;
3319         }
3320
3321         servers = g_try_new0(char *, len);
3322         if (!servers)
3323                 return -ENOMEM;
3324
3325         for (i = 0, j = 0; i < len; i++) {
3326                 if (g_strcmp0(service->timeservers[i], timeserver) != 0) {
3327                         servers[j] = g_strdup(service->timeservers[i]);
3328                         if (!servers[j])
3329                                 return -ENOMEM;
3330                         j++;
3331                 }
3332         }
3333         servers[len - 1] = NULL;
3334
3335         g_strfreev(service->timeservers);
3336         service->timeservers = servers;
3337
3338         return 0;
3339 }
3340
3341 void __connman_service_timeserver_changed(struct connman_service *service,
3342                 GSList *ts_list)
3343 {
3344         if (!service)
3345                 return;
3346
3347         if (!allow_property_changed(service))
3348                 return;
3349
3350         connman_dbus_property_changed_array(service->path,
3351                         CONNMAN_SERVICE_INTERFACE, "Timeservers",
3352                         DBUS_TYPE_STRING, append_ts, ts_list);
3353 }
3354
3355 void __connman_service_set_pac(struct connman_service *service,
3356                                         const char *pac)
3357 {
3358         if (service->hidden)
3359                 return;
3360         g_free(service->pac);
3361         service->pac = g_strdup(pac);
3362
3363         proxy_changed(service);
3364 }
3365
3366 #if defined TIZEN_EXT
3367 void __connman_service_set_proxy(struct connman_service *service,
3368                                        const char *proxies)
3369 {
3370        char **proxies_array = NULL;
3371
3372        g_strfreev(service->proxies);
3373        service->proxies = NULL;
3374
3375        if (proxies != NULL)
3376                proxies_array = g_strsplit(proxies, " ", 0);
3377
3378        service->proxies = proxies_array;
3379 }
3380 #endif
3381
3382 void __connman_service_set_identity(struct connman_service *service,
3383                                         const char *identity)
3384 {
3385         if (service->immutable || service->hidden)
3386                 return;
3387
3388         g_free(service->identity);
3389         service->identity = g_strdup(identity);
3390
3391         if (service->network)
3392                 connman_network_set_string(service->network,
3393                                         "WiFi.Identity",
3394                                         service->identity);
3395 }
3396
3397 void __connman_service_set_agent_identity(struct connman_service *service,
3398                                                 const char *agent_identity)
3399 {
3400         if (service->hidden)
3401                 return;
3402         g_free(service->agent_identity);
3403         service->agent_identity = g_strdup(agent_identity);
3404
3405         if (service->network)
3406                 connman_network_set_string(service->network,
3407                                         "WiFi.AgentIdentity",
3408                                         service->agent_identity);
3409 }
3410
3411 static int check_passphrase(enum connman_service_security security,
3412                 const char *passphrase)
3413 {
3414         guint i;
3415         gsize length;
3416
3417         if (!passphrase)
3418                 return 0;
3419
3420         length = strlen(passphrase);
3421
3422         switch (security) {
3423         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
3424         case CONNMAN_SERVICE_SECURITY_NONE:
3425         case CONNMAN_SERVICE_SECURITY_WPA:
3426 #if !defined TIZEN_EXT
3427         case CONNMAN_SERVICE_SECURITY_RSN:
3428 #endif
3429
3430                 DBG("service security '%s' (%d) not handled",
3431                                 security2string(security), security);
3432
3433                 return -EOPNOTSUPP;
3434
3435         case CONNMAN_SERVICE_SECURITY_PSK:
3436 #if defined TIZEN_EXT
3437         case CONNMAN_SERVICE_SECURITY_RSN:
3438 #endif
3439                 /* A raw key is always 64 bytes length,
3440                  * its content is in hex representation.
3441                  * A PSK key must be between [8..63].
3442                  */
3443                 if (length == 64) {
3444                         for (i = 0; i < 64; i++)
3445                                 if (!isxdigit((unsigned char)
3446                                               passphrase[i]))
3447                                         return -ENOKEY;
3448                 } else if (length < 8 || length > 63)
3449                         return -ENOKEY;
3450                 break;
3451         case CONNMAN_SERVICE_SECURITY_WEP:
3452                 /* length of WEP key is 10 or 26
3453                  * length of WEP passphrase is 5 or 13
3454                  */
3455                 if (length == 10 || length == 26) {
3456                         for (i = 0; i < length; i++)
3457                                 if (!isxdigit((unsigned char)
3458                                               passphrase[i]))
3459                                         return -ENOKEY;
3460                 } else if (length != 5 && length != 13)
3461                         return -ENOKEY;
3462                 break;
3463
3464         case CONNMAN_SERVICE_SECURITY_8021X:
3465                 break;
3466         }
3467
3468         return 0;
3469 }
3470
3471 int __connman_service_set_passphrase(struct connman_service *service,
3472                                         const char *passphrase)
3473 {
3474         int err;
3475
3476         if (service->hidden)
3477                 return -EINVAL;
3478
3479         if (service->immutable &&
3480                         service->security != CONNMAN_SERVICE_SECURITY_8021X)
3481                 return -EINVAL;
3482
3483         err = check_passphrase(service->security, passphrase);
3484
3485         if (err < 0)
3486                 return err;
3487
3488         g_free(service->passphrase);
3489         service->passphrase = g_strdup(passphrase);
3490
3491         if (service->network)
3492                 connman_network_set_string(service->network, "WiFi.Passphrase",
3493                                 service->passphrase);
3494
3495         return 0;
3496 }
3497
3498 const char *__connman_service_get_passphrase(struct connman_service *service)
3499 {
3500         if (!service)
3501                 return NULL;
3502
3503         return service->passphrase;
3504 }
3505
3506 static DBusMessage *get_properties(DBusConnection *conn,
3507                                         DBusMessage *msg, void *user_data)
3508 {
3509         struct connman_service *service = user_data;
3510         DBusMessage *reply;
3511         DBusMessageIter array, dict;
3512
3513         DBG("service %p", service);
3514
3515         reply = dbus_message_new_method_return(msg);
3516         if (!reply)
3517                 return NULL;
3518
3519         dbus_message_iter_init_append(reply, &array);
3520
3521         connman_dbus_dict_open(&array, &dict);
3522         append_properties(&dict, FALSE, service);
3523         connman_dbus_dict_close(&array, &dict);
3524
3525         return reply;
3526 }
3527
3528 static int update_proxy_configuration(struct connman_service *service,
3529                                 DBusMessageIter *array)
3530 {
3531         DBusMessageIter dict;
3532         enum connman_service_proxy_method method;
3533         GString *servers_str = NULL;
3534         GString *excludes_str = NULL;
3535         const char *url = NULL;
3536
3537         method = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
3538
3539         dbus_message_iter_recurse(array, &dict);
3540
3541         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
3542                 DBusMessageIter entry, variant;
3543                 const char *key;
3544                 int type;
3545
3546                 dbus_message_iter_recurse(&dict, &entry);
3547
3548                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
3549                         goto error;
3550
3551                 dbus_message_iter_get_basic(&entry, &key);
3552                 dbus_message_iter_next(&entry);
3553
3554                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
3555                         goto error;
3556
3557                 dbus_message_iter_recurse(&entry, &variant);
3558
3559                 type = dbus_message_iter_get_arg_type(&variant);
3560
3561                 if (g_str_equal(key, "Method")) {
3562                         const char *val;
3563
3564                         if (type != DBUS_TYPE_STRING)
3565                                 goto error;
3566
3567                         dbus_message_iter_get_basic(&variant, &val);
3568                         method = string2proxymethod(val);
3569                 } else if (g_str_equal(key, "URL")) {
3570                         if (type != DBUS_TYPE_STRING)
3571                                 goto error;
3572
3573                         dbus_message_iter_get_basic(&variant, &url);
3574                 } else if (g_str_equal(key, "Servers")) {
3575                         DBusMessageIter str_array;
3576
3577                         if (type != DBUS_TYPE_ARRAY)
3578                                 goto error;
3579
3580                         servers_str = g_string_new(NULL);
3581                         if (!servers_str)
3582                                 goto error;
3583
3584                         dbus_message_iter_recurse(&variant, &str_array);
3585
3586                         while (dbus_message_iter_get_arg_type(&str_array) ==
3587                                                         DBUS_TYPE_STRING) {
3588                                 char *val = NULL;
3589
3590                                 dbus_message_iter_get_basic(&str_array, &val);
3591
3592                                 if (servers_str->len > 0)
3593                                         g_string_append_printf(servers_str,
3594                                                         " %s", val);
3595                                 else
3596                                         g_string_append(servers_str, val);
3597
3598                                 dbus_message_iter_next(&str_array);
3599                         }
3600                 } else if (g_str_equal(key, "Excludes")) {
3601                         DBusMessageIter str_array;
3602
3603                         if (type != DBUS_TYPE_ARRAY)
3604                                 goto error;
3605
3606                         excludes_str = g_string_new(NULL);
3607                         if (!excludes_str)
3608                                 goto error;
3609
3610                         dbus_message_iter_recurse(&variant, &str_array);
3611
3612                         while (dbus_message_iter_get_arg_type(&str_array) ==
3613                                                         DBUS_TYPE_STRING) {
3614                                 char *val = NULL;
3615
3616                                 dbus_message_iter_get_basic(&str_array, &val);
3617
3618                                 if (excludes_str->len > 0)
3619                                         g_string_append_printf(excludes_str,
3620                                                         " %s", val);
3621                                 else
3622                                         g_string_append(excludes_str, val);
3623
3624                                 dbus_message_iter_next(&str_array);
3625                         }
3626                 }
3627
3628                 dbus_message_iter_next(&dict);
3629         }
3630
3631         switch (method) {
3632         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
3633                 break;
3634         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
3635                 if (!servers_str && !service->proxies)
3636                         goto error;
3637
3638                 if (servers_str) {
3639                         g_strfreev(service->proxies);
3640
3641                         if (servers_str->len > 0)
3642                                 service->proxies = g_strsplit_set(
3643                                         servers_str->str, " ", 0);
3644                         else
3645                                 service->proxies = NULL;
3646                 }
3647
3648                 if (excludes_str) {
3649                         g_strfreev(service->excludes);
3650
3651                         if (excludes_str->len > 0)
3652                                 service->excludes = g_strsplit_set(
3653                                         excludes_str->str, " ", 0);
3654                         else
3655                                 service->excludes = NULL;
3656                 }
3657
3658                 if (!service->proxies)
3659                         method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
3660
3661                 break;
3662         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
3663                 g_free(service->pac);
3664
3665                 if (url && strlen(url) > 0)
3666                         service->pac = g_strdup(url);
3667                 else
3668                         service->pac = NULL;
3669
3670                 /* if we are connected:
3671                    - if service->pac == NULL
3672                    - if __connman_ipconfig_get_proxy_autoconfig(
3673                    service->ipconfig) == NULL
3674                    --> We should start WPAD */
3675
3676                 break;
3677         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
3678                 goto error;
3679         }
3680
3681         if (servers_str)
3682                 g_string_free(servers_str, TRUE);
3683
3684         if (excludes_str)
3685                 g_string_free(excludes_str, TRUE);
3686
3687         service->proxy_config = method;
3688
3689         return 0;
3690
3691 error:
3692         if (servers_str)
3693                 g_string_free(servers_str, TRUE);
3694
3695         if (excludes_str)
3696                 g_string_free(excludes_str, TRUE);
3697
3698         return -EINVAL;
3699 }
3700
3701 int __connman_service_reset_ipconfig(struct connman_service *service,
3702                 enum connman_ipconfig_type type, DBusMessageIter *array,
3703                 enum connman_service_state *new_state)
3704 {
3705         struct connman_ipconfig *ipconfig, *new_ipconfig;
3706         enum connman_ipconfig_method old_method, new_method;
3707         enum connman_service_state state;
3708         int err = 0, index;
3709
3710         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
3711                 ipconfig = service->ipconfig_ipv4;
3712                 state = service->state_ipv4;
3713                 new_method = CONNMAN_IPCONFIG_METHOD_DHCP;
3714         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
3715                 ipconfig = service->ipconfig_ipv6;
3716                 state = service->state_ipv6;
3717                 new_method = CONNMAN_IPCONFIG_METHOD_AUTO;
3718         } else
3719                 return -EINVAL;
3720
3721         if (!ipconfig)
3722                 return -ENXIO;
3723
3724         old_method = __connman_ipconfig_get_method(ipconfig);
3725         index = __connman_ipconfig_get_index(ipconfig);
3726
3727         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
3728                 new_ipconfig = create_ip4config(service, index,
3729                                 CONNMAN_IPCONFIG_METHOD_UNKNOWN);
3730         else
3731                 new_ipconfig = create_ip6config(service, index);
3732
3733         if (array) {
3734                 err = __connman_ipconfig_set_config(new_ipconfig, array);
3735                 if (err < 0) {
3736                         __connman_ipconfig_unref(new_ipconfig);
3737                         return err;
3738                 }
3739
3740                 new_method = __connman_ipconfig_get_method(new_ipconfig);
3741         }
3742
3743         if (is_connecting_state(service, state) ||
3744                                         is_connected_state(service, state))
3745                 __connman_network_clear_ipconfig(service->network, ipconfig);
3746
3747         __connman_ipconfig_unref(ipconfig);
3748
3749         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
3750                 service->ipconfig_ipv4 = new_ipconfig;
3751         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
3752                 service->ipconfig_ipv6 = new_ipconfig;
3753
3754         if (is_connecting_state(service, state) ||
3755                                         is_connected_state(service, state))
3756                 __connman_ipconfig_enable(new_ipconfig);
3757
3758         if (new_state && new_method != old_method) {
3759                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
3760                         *new_state = service->state_ipv4;
3761                 else
3762                         *new_state = service->state_ipv6;
3763
3764                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
3765         }
3766
3767         DBG("err %d ipconfig %p type %d method %d state %s", err,
3768                 new_ipconfig, type, new_method,
3769                 !new_state  ? "-" : state2string(*new_state));
3770
3771         return err;
3772 }
3773
3774 static DBusMessage *set_property(DBusConnection *conn,
3775                                         DBusMessage *msg, void *user_data)
3776 {
3777         struct connman_service *service = user_data;
3778         DBusMessageIter iter, value;
3779         const char *name;
3780         int type;
3781
3782         DBG("service %p", service);
3783
3784         if (!dbus_message_iter_init(msg, &iter))
3785                 return __connman_error_invalid_arguments(msg);
3786
3787         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
3788                 return __connman_error_invalid_arguments(msg);
3789
3790         if (service->type == CONNMAN_SERVICE_TYPE_WIFI && is_connected(service)) {
3791                 uid_t uid;
3792                 if (connman_dbus_get_connection_unix_user_sync(conn,
3793                                                 dbus_message_get_sender(msg),
3794                                                 &uid) < 0) {
3795                         DBG("Can not get unix user id!");
3796                         return __connman_error_permission_denied(msg);
3797                 }
3798
3799                 if (!connman_service_is_user_allowed(service, uid)) {
3800                         DBG("Not allow this user to operate this wifi service now!");
3801                         return __connman_error_permission_denied(msg);
3802                 }
3803         }
3804
3805         dbus_message_iter_get_basic(&iter, &name);
3806         dbus_message_iter_next(&iter);
3807
3808         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
3809                 return __connman_error_invalid_arguments(msg);
3810
3811         dbus_message_iter_recurse(&iter, &value);
3812
3813         type = dbus_message_iter_get_arg_type(&value);
3814
3815         if (g_str_equal(name, "AutoConnect")) {
3816                 dbus_bool_t autoconnect;
3817
3818                 if (type != DBUS_TYPE_BOOLEAN)
3819                         return __connman_error_invalid_arguments(msg);
3820
3821                 if (!service->favorite)
3822                         return __connman_error_invalid_service(msg);
3823
3824                 dbus_message_iter_get_basic(&value, &autoconnect);
3825
3826                 if (service->autoconnect == autoconnect)
3827                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3828
3829                 service->autoconnect = autoconnect;
3830
3831                 autoconnect_changed(service);
3832
3833                 if (autoconnect)
3834                         __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
3835
3836                 service_save(service);
3837         } else if (g_str_equal(name, "Nameservers.Configuration")) {
3838                 DBusMessageIter entry;
3839                 GString *str;
3840                 int index;
3841                 const char *gw;
3842
3843                 if (__connman_provider_is_immutable(service->provider) ||
3844                                 service->immutable)
3845                         return __connman_error_not_supported(msg);
3846
3847                 if (type != DBUS_TYPE_ARRAY)
3848                         return __connman_error_invalid_arguments(msg);
3849
3850                 str = g_string_new(NULL);
3851                 if (!str)
3852                         return __connman_error_invalid_arguments(msg);
3853
3854                 index = __connman_service_get_index(service);
3855                 gw = __connman_ipconfig_get_gateway_from_index(index,
3856                         CONNMAN_IPCONFIG_TYPE_ALL);
3857
3858                 if (gw && strlen(gw))
3859                         __connman_service_nameserver_del_routes(service,
3860                                                 CONNMAN_IPCONFIG_TYPE_ALL);
3861
3862                 dbus_message_iter_recurse(&value, &entry);
3863
3864                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
3865                         const char *val;
3866                         dbus_message_iter_get_basic(&entry, &val);
3867                         dbus_message_iter_next(&entry);
3868 #ifdef TIZEN_EXT
3869                         if (TIZEN_TV_EXT) {
3870                                 /* First unpack the DNS Config Method */
3871                                 if(g_strcmp0(val, "manual") == 0) {
3872                                         service->dns_config_method =
3873                                                 CONNMAN_DNSCONFIG_METHOD_MANUAL;
3874                                         continue;
3875                                 } else if(g_strcmp0(val, "dhcp") == 0) {
3876                                         service->dns_config_method =
3877                                                 CONNMAN_DNSCONFIG_METHOD_DHCP;
3878                                         continue;
3879                                 }
3880                         }
3881 #endif
3882                         if (connman_inet_check_ipaddress(val) > 0) {
3883                                 if (str->len > 0)
3884                                         g_string_append_printf(str, " %s", val);
3885                                 else
3886                                         g_string_append(str, val);
3887                         }
3888                 }
3889
3890                 nameserver_remove_all(service);
3891                 g_strfreev(service->nameservers_config);
3892
3893                 if (str->len > 0) {
3894                         service->nameservers_config =
3895                                 g_strsplit_set(str->str, " ", 0);
3896                 } else {
3897                         service->nameservers_config = NULL;
3898                 }
3899
3900                 g_string_free(str, TRUE);
3901
3902                 if (gw && strlen(gw))
3903                         __connman_service_nameserver_add_routes(service, gw);
3904
3905                 nameserver_add_all(service);
3906                 dns_configuration_changed(service);
3907
3908                 if (__connman_service_is_connected_state(service,
3909                                                 CONNMAN_IPCONFIG_TYPE_IPV4))
3910                         __connman_wispr_start(service,
3911                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
3912
3913                 if (__connman_service_is_connected_state(service,
3914                                                 CONNMAN_IPCONFIG_TYPE_IPV6))
3915                         __connman_wispr_start(service,
3916                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
3917
3918                 service_save(service);
3919         } else if (g_str_equal(name, "Timeservers.Configuration")) {
3920                 DBusMessageIter entry;
3921                 GSList *list = NULL;
3922                 int count = 0;
3923
3924                 if (service->immutable)
3925                         return __connman_error_not_supported(msg);
3926
3927                 if (type != DBUS_TYPE_ARRAY)
3928                         return __connman_error_invalid_arguments(msg);
3929
3930                 dbus_message_iter_recurse(&value, &entry);
3931
3932                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
3933                         const char *val;
3934                         GSList *new_head;
3935
3936                         dbus_message_iter_get_basic(&entry, &val);
3937
3938                         new_head = __connman_timeserver_add_list(list, val);
3939                         if (list != new_head) {
3940                                 count++;
3941                                 list = new_head;
3942                         }
3943
3944                         dbus_message_iter_next(&entry);
3945                 }
3946
3947                 g_strfreev(service->timeservers_config);
3948                 service->timeservers_config = NULL;
3949
3950                 if (list) {
3951                         service->timeservers_config = g_new0(char *, count+1);
3952
3953                         while (list) {
3954                                 count--;
3955                                 service->timeservers_config[count] = list->data;
3956                                 list = g_slist_delete_link(list, list);
3957                         };
3958                 }
3959
3960                 service_save(service);
3961                 timeservers_configuration_changed(service);
3962
3963                 if (service == __connman_service_get_default())
3964                         __connman_timeserver_sync(service);
3965
3966         } else if (g_str_equal(name, "Domains.Configuration")) {
3967                 DBusMessageIter entry;
3968                 GString *str;
3969
3970                 if (service->immutable)
3971                         return __connman_error_not_supported(msg);
3972
3973                 if (type != DBUS_TYPE_ARRAY)
3974                         return __connman_error_invalid_arguments(msg);
3975
3976                 str = g_string_new(NULL);
3977                 if (!str)
3978                         return __connman_error_invalid_arguments(msg);
3979
3980                 dbus_message_iter_recurse(&value, &entry);
3981
3982                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
3983                         const char *val;
3984                         dbus_message_iter_get_basic(&entry, &val);
3985                         dbus_message_iter_next(&entry);
3986                         if (str->len > 0)
3987                                 g_string_append_printf(str, " %s", val);
3988                         else
3989                                 g_string_append(str, val);
3990                 }
3991
3992                 searchdomain_remove_all(service);
3993                 g_strfreev(service->domains);
3994
3995                 if (str->len > 0)
3996                         service->domains = g_strsplit_set(str->str, " ", 0);
3997                 else
3998                         service->domains = NULL;
3999
4000                 g_string_free(str, TRUE);
4001
4002                 searchdomain_add_all(service);
4003                 domain_configuration_changed(service);
4004                 domain_changed(service);
4005
4006                 service_save(service);
4007         } else if (g_str_equal(name, "Proxy.Configuration")) {
4008                 int err;
4009
4010                 if (service->immutable)
4011                         return __connman_error_not_supported(msg);
4012
4013                 if (type != DBUS_TYPE_ARRAY)
4014                         return __connman_error_invalid_arguments(msg);
4015
4016                 err = update_proxy_configuration(service, &value);
4017
4018                 if (err < 0)
4019                         return __connman_error_failed(msg, -err);
4020
4021                 proxy_configuration_changed(service);
4022
4023                 __connman_notifier_proxy_changed(service);
4024
4025                 service_save(service);
4026         } else if (g_str_equal(name, "IPv4.Configuration") ||
4027                         g_str_equal(name, "IPv6.Configuration")) {
4028
4029                 enum connman_service_state state =
4030                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
4031                 enum connman_ipconfig_type type =
4032                         CONNMAN_IPCONFIG_TYPE_UNKNOWN;
4033                 int err = 0;
4034
4035                 if (service->type == CONNMAN_SERVICE_TYPE_VPN ||
4036                                 service->immutable)
4037                         return __connman_error_not_supported(msg);
4038
4039                 DBG("%s", name);
4040
4041                 if (!service->ipconfig_ipv4 &&
4042                                         !service->ipconfig_ipv6)
4043                         return __connman_error_invalid_property(msg);
4044
4045                 if (g_str_equal(name, "IPv4.Configuration"))
4046                         type = CONNMAN_IPCONFIG_TYPE_IPV4;
4047                 else
4048                         type = CONNMAN_IPCONFIG_TYPE_IPV6;
4049
4050                 err = __connman_service_reset_ipconfig(service, type, &value,
4051                                                                 &state);
4052
4053                 if (err < 0) {
4054                         if (is_connected_state(service, state) ||
4055                                         is_connecting_state(service, state)) {
4056                                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4057                                         __connman_network_enable_ipconfig(service->network,
4058                                                         service->ipconfig_ipv4);
4059                                 else
4060                                         __connman_network_enable_ipconfig(service->network,
4061                                                         service->ipconfig_ipv6);
4062                         }
4063
4064                         return __connman_error_failed(msg, -err);
4065                 }
4066
4067                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4068                         ipv4_configuration_changed(service);
4069                 else
4070                         ipv6_configuration_changed(service);
4071
4072                 if (is_connecting(service) || is_connected(service)) {
4073                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4074                                 __connman_network_enable_ipconfig(service->network,
4075                                                                 service->ipconfig_ipv4);
4076                         else
4077                                 __connman_network_enable_ipconfig(service->network,
4078                                                                 service->ipconfig_ipv6);
4079                 }
4080
4081                 service_save(service);
4082         } else
4083                 return __connman_error_invalid_property(msg);
4084
4085         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4086 }
4087
4088 static void set_error(struct connman_service *service,
4089                                         enum connman_service_error error)
4090 {
4091         const char *str;
4092
4093         if (service->error == error)
4094                 return;
4095
4096         service->error = error;
4097
4098         if (!service->path)
4099                 return;
4100
4101 #if !defined TIZEN_EXT
4102         if (!allow_property_changed(service))
4103                 return;
4104 #endif
4105
4106         str = error2string(service->error);
4107
4108         if (!str)
4109                 str = "";
4110
4111         connman_dbus_property_changed_basic(service->path,
4112                                 CONNMAN_SERVICE_INTERFACE, "Error",
4113                                 DBUS_TYPE_STRING, &str);
4114 }
4115
4116 static void set_idle(struct connman_service *service)
4117 {
4118         service->state = service->state_ipv4 = service->state_ipv6 =
4119                                                 CONNMAN_SERVICE_STATE_IDLE;
4120         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
4121         state_changed(service);
4122 }
4123
4124 static DBusMessage *clear_property(DBusConnection *conn,
4125                                         DBusMessage *msg, void *user_data)
4126 {
4127         struct connman_service *service = user_data;
4128         const char *name;
4129
4130         DBG("service %p", service);
4131
4132         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
4133                                                         DBUS_TYPE_INVALID);
4134
4135         if (g_str_equal(name, "Error")) {
4136                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
4137
4138                 g_get_current_time(&service->modified);
4139                 service_save(service);
4140         } else
4141                 return __connman_error_invalid_property(msg);
4142
4143         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4144 }
4145
4146 static bool is_ipconfig_usable(struct connman_service *service)
4147 {
4148         if (!__connman_ipconfig_is_usable(service->ipconfig_ipv4) &&
4149                         !__connman_ipconfig_is_usable(service->ipconfig_ipv6))
4150                 return false;
4151
4152         return true;
4153 }
4154
4155 static bool is_ignore(struct connman_service *service)
4156 {
4157         if (!service->autoconnect)
4158                 return true;
4159
4160         if (service->roaming)
4161                 return true;
4162
4163         if (service->ignore)
4164                 return true;
4165
4166         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
4167                 return true;
4168
4169         if (!is_ipconfig_usable(service))
4170                 return true;
4171
4172         return false;
4173 }
4174
4175 static void disconnect_on_last_session(enum connman_service_type type)
4176 {
4177         GList *list;
4178
4179         for (list = service_list; list; list = list->next) {
4180                 struct connman_service *service = list->data;
4181
4182                 if (service->type != type)
4183                         continue;
4184
4185                 if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_SESSION)
4186                          continue;
4187
4188                 __connman_service_disconnect(service);
4189                 return;
4190         }
4191 }
4192
4193 static int active_sessions[MAX_CONNMAN_SERVICE_TYPES] = {};
4194 static int active_count = 0;
4195
4196 void __connman_service_set_active_session(bool enable, GSList *list)
4197 {
4198         if (!list)
4199                 return;
4200
4201         if (enable)
4202                 active_count++;
4203         else
4204                 active_count--;
4205
4206         while (list != NULL) {
4207                 enum connman_service_type type = GPOINTER_TO_INT(list->data);
4208
4209                 switch (type) {
4210                 case CONNMAN_SERVICE_TYPE_ETHERNET:
4211                 case CONNMAN_SERVICE_TYPE_WIFI:
4212                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
4213                 case CONNMAN_SERVICE_TYPE_CELLULAR:
4214                 case CONNMAN_SERVICE_TYPE_GADGET:
4215                         if (enable)
4216                                 active_sessions[type]++;
4217                         else
4218                                 active_sessions[type]--;
4219                         break;
4220
4221                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
4222                 case CONNMAN_SERVICE_TYPE_SYSTEM:
4223                 case CONNMAN_SERVICE_TYPE_GPS:
4224                 case CONNMAN_SERVICE_TYPE_VPN:
4225                 case CONNMAN_SERVICE_TYPE_P2P:
4226                         break;
4227                 }
4228
4229                 if (active_sessions[type] == 0)
4230                         disconnect_on_last_session(type);
4231
4232                 list = g_slist_next(list);
4233         }
4234
4235         DBG("eth %d wifi %d bt %d cellular %d gadget %d sessions %d",
4236                         active_sessions[CONNMAN_SERVICE_TYPE_ETHERNET],
4237                         active_sessions[CONNMAN_SERVICE_TYPE_WIFI],
4238                         active_sessions[CONNMAN_SERVICE_TYPE_BLUETOOTH],
4239                         active_sessions[CONNMAN_SERVICE_TYPE_CELLULAR],
4240                         active_sessions[CONNMAN_SERVICE_TYPE_GADGET],
4241                         active_count);
4242 }
4243
4244 struct preferred_tech_data {
4245         GList *preferred_list;
4246         enum connman_service_type type;
4247 };
4248
4249 static void preferred_tech_add_by_type(gpointer data, gpointer user_data)
4250 {
4251         struct connman_service *service = data;
4252         struct preferred_tech_data *tech_data = user_data;
4253
4254         if (service->type == tech_data->type) {
4255                 tech_data->preferred_list =
4256                         g_list_append(tech_data->preferred_list, service);
4257
4258                 DBG("type %d service %p %s", tech_data->type, service,
4259                                 service->name);
4260         }
4261 }
4262
4263 static GList *preferred_tech_list_get(void)
4264 {
4265         unsigned int *tech_array;
4266         struct preferred_tech_data tech_data = { 0, };
4267         int i;
4268
4269         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
4270         if (!tech_array)
4271                 return NULL;
4272
4273         if (connman_setting_get_bool("SingleConnectedTechnology")) {
4274                 GList *list;
4275                 for (list = service_list; list; list = list->next) {
4276                         struct connman_service *service = list->data;
4277
4278                         if (!is_connected(service))
4279                                 break;
4280
4281                         if (service->connect_reason ==
4282                                         CONNMAN_SERVICE_CONNECT_REASON_USER) {
4283                                 DBG("service %p name %s is user connected",
4284                                                 service, service->name);
4285 #if defined TIZEN_EXT
4286                                 /* We can connect to a favorite service like
4287                                  * wifi even we have a userconnect for cellular
4288                                  * because we have refount for cellular service
4289                                  */
4290                                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
4291                                         break;
4292
4293                                 if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
4294                                         break;
4295 #endif
4296                                 return NULL;
4297                         }
4298                 }
4299         }
4300
4301         for (i = 0; tech_array[i] != 0; i += 1) {
4302                 tech_data.type = tech_array[i];
4303                 g_list_foreach(service_list, preferred_tech_add_by_type,
4304                                 &tech_data);
4305         }
4306
4307         return tech_data.preferred_list;
4308 }
4309
4310 static bool auto_connect_service(GList *services,
4311                                 enum connman_service_connect_reason reason,
4312                                 bool preferred)
4313 {
4314         struct connman_service *service = NULL;
4315         bool ignore[MAX_CONNMAN_SERVICE_TYPES] = { };
4316         bool autoconnecting = false;
4317         GList *list;
4318
4319         DBG("preferred %d sessions %d reason %s", preferred, active_count,
4320                 reason2string(reason));
4321
4322         ignore[CONNMAN_SERVICE_TYPE_VPN] = true;
4323
4324         for (list = services; list; list = list->next) {
4325                 service = list->data;
4326
4327                 if (ignore[service->type]) {
4328                         DBG("service %p type %s ignore", service,
4329                                 __connman_service_type2string(service->type));
4330                         continue;
4331                 }
4332
4333 #if defined TIZEN_EXT
4334                 DBG("service %p %s %s %s, favorite(%d), ignore(%d), hidden(%d, %d)",
4335                                 service, service->name,
4336                                 state2string(service->state),
4337                                 __connman_service_type2string(service->type),
4338                                 service->favorite, is_ignore(service),
4339                                 service->hidden, service->hidden_service);
4340
4341                 /* Tizen takes Wi-Fi as the highest priority into consideration. */
4342                 if (service->type != CONNMAN_SERVICE_TYPE_WIFI)
4343                         if (is_connecting(service) == TRUE || is_connected(service) == TRUE)
4344                                 continue;
4345 #endif
4346
4347                 if (service->pending ||
4348                                 is_connecting(service) ||
4349                                 is_connected(service)) {
4350                         if (!active_count)
4351                                 return true;
4352
4353                         ignore[service->type] = true;
4354                         autoconnecting = true;
4355
4356                         DBG("service %p type %s busy", service,
4357                                 __connman_service_type2string(service->type));
4358
4359                         continue;
4360                 }
4361
4362                 if (!service->favorite) {
4363                         if (preferred)
4364                                continue;
4365
4366                         return autoconnecting;
4367                 }
4368
4369                 if (is_ignore(service) || service->state !=
4370                                 CONNMAN_SERVICE_STATE_IDLE)
4371                         continue;
4372
4373                 if (autoconnecting && !active_sessions[service->type]) {
4374                         DBG("service %p type %s has no users", service,
4375                                 __connman_service_type2string(service->type));
4376                         continue;
4377                 }
4378
4379                 if (!is_service_owner_user_login(service)) {
4380                         DBG("favorite user not login, wifi auto connect denied");
4381                         continue;
4382                 }
4383
4384                 DBG("service %p %s %s", service, service->name,
4385                         (preferred) ? "preferred" : reason2string(reason));
4386
4387                 __connman_service_connect(service, reason);
4388
4389                 if (!active_count)
4390                         return true;
4391
4392                 ignore[service->type] = true;
4393         }
4394
4395         return autoconnecting;
4396 }
4397
4398 static gboolean run_auto_connect(gpointer data)
4399 {
4400         enum connman_service_connect_reason reason = GPOINTER_TO_UINT(data);
4401         bool autoconnecting = false;
4402         GList *preferred_tech;
4403
4404         autoconnect_timeout = 0;
4405
4406         DBG("");
4407
4408         preferred_tech = preferred_tech_list_get();
4409         if (preferred_tech) {
4410                 autoconnecting = auto_connect_service(preferred_tech, reason,
4411                                                         true);
4412                 g_list_free(preferred_tech);
4413         }
4414
4415         if (!autoconnecting || active_count)
4416                 auto_connect_service(service_list, reason, false);
4417
4418         return FALSE;
4419 }
4420
4421 void __connman_service_auto_connect(enum connman_service_connect_reason reason)
4422 {
4423         DBG("");
4424
4425         if (autoconnect_timeout != 0)
4426                 return;
4427
4428         if (!__connman_session_policy_autoconnect(reason))
4429                 return;
4430
4431 #if defined TIZEN_EXT
4432         /* Adding Timeout of 500ms before trying to auto connect.
4433          * This is done because of below scenario
4434          * 1. Device is connected to AP1
4435          * 2. WPS Connection request is initiated for AP2
4436          * 3. Immediately WPS Connection is Cancelled
4437          * When WPS Connection Connection is initiated for AP2 then
4438          * sometimes there is a scenario where connman gets in ASSOCIATED
4439          * state with AP1 due to autoconnect and subsequently the connection
4440          * initiated by AP1 fails and connman service for AP1 comes in
4441          * FAILURE state due to this when connection with AP2 is cancelled
4442          * then autoconnect with AP1 doesn't works because its autoconnection
4443          * is ignored as its last state was FAILURE rather than IDLE */
4444         autoconnect_timeout = g_timeout_add(500, run_auto_connect,
4445 #else
4446         autoconnect_timeout = g_timeout_add_seconds(0, run_auto_connect,
4447 #endif
4448                                                 GUINT_TO_POINTER(reason));
4449 }
4450
4451 static gboolean run_vpn_auto_connect(gpointer data) {
4452         GList *list;
4453         bool need_split = false;
4454
4455         vpn_autoconnect_timeout = 0;
4456
4457         for (list = service_list; list; list = list->next) {
4458                 struct connman_service *service = list->data;
4459                 int res;
4460
4461                 if (service->type != CONNMAN_SERVICE_TYPE_VPN)
4462                         continue;
4463
4464                 if (is_connected(service) || is_connecting(service)) {
4465                         if (!service->do_split_routing)
4466                                 need_split = true;
4467                         continue;
4468                 }
4469
4470                 if (is_ignore(service) || !service->favorite)
4471                         continue;
4472
4473                 if (need_split && !service->do_split_routing) {
4474                         DBG("service %p no split routing", service);
4475                         continue;
4476                 }
4477
4478                 DBG("service %p %s %s", service, service->name,
4479                                 service->do_split_routing ?
4480                                 "split routing" : "");
4481
4482                 res = __connman_service_connect(service,
4483                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4484                 if (res < 0 && res != -EINPROGRESS)
4485                         continue;
4486
4487                 if (!service->do_split_routing)
4488                         need_split = true;
4489         }
4490
4491         return FALSE;
4492 }
4493
4494 static void vpn_auto_connect(void)
4495 {
4496         if (vpn_autoconnect_timeout)
4497                 return;
4498
4499         vpn_autoconnect_timeout =
4500                 g_timeout_add_seconds(0, run_vpn_auto_connect, NULL);
4501 }
4502
4503 static void remove_timeout(struct connman_service *service)
4504 {
4505         if (service->timeout > 0) {
4506                 g_source_remove(service->timeout);
4507                 service->timeout = 0;
4508         }
4509 }
4510
4511 static void reply_pending(struct connman_service *service, int error)
4512 {
4513         remove_timeout(service);
4514
4515         if (service->pending) {
4516                 connman_dbus_reply_pending(service->pending, error, NULL);
4517                 service->pending = NULL;
4518         }
4519
4520         if (service->provider_pending) {
4521                 connman_dbus_reply_pending(service->provider_pending,
4522                                                 error, service->path);
4523                 service->provider_pending = NULL;
4524         }
4525 }
4526
4527 bool
4528 __connman_service_is_provider_pending(struct connman_service *service)
4529 {
4530         if (!service)
4531                 return false;
4532
4533         if (service->provider_pending)
4534                 return true;
4535
4536         return false;
4537 }
4538
4539 void __connman_service_set_provider_pending(struct connman_service *service,
4540                                                         DBusMessage *msg)
4541 {
4542         if (service->provider_pending) {
4543                 DBG("service %p provider pending msg %p already exists",
4544                         service, service->provider_pending);
4545                 return;
4546         }
4547
4548         service->provider_pending = msg;
4549         return;
4550 }
4551
4552 static void check_pending_msg(struct connman_service *service)
4553 {
4554         if (!service->pending)
4555                 return;
4556
4557         DBG("service %p pending msg %p already exists", service,
4558                                                 service->pending);
4559         dbus_message_unref(service->pending);
4560 }
4561
4562 void __connman_service_set_hidden_data(struct connman_service *service,
4563                                                         gpointer user_data)
4564 {
4565         DBusMessage *pending = user_data;
4566
4567         DBG("service %p pending %p", service, pending);
4568
4569         if (!pending)
4570                 return;
4571
4572         check_pending_msg(service);
4573
4574         service->pending = pending;
4575 }
4576
4577 void __connman_service_return_error(struct connman_service *service,
4578                                 int error, gpointer user_data)
4579 {
4580         DBG("service %p error %d user_data %p", service, error, user_data);
4581
4582         __connman_service_set_hidden_data(service, user_data);
4583
4584         reply_pending(service, error);
4585 }
4586
4587 static gboolean connect_timeout(gpointer user_data)
4588 {
4589         struct connman_service *service = user_data;
4590         bool autoconnect = false;
4591
4592         DBG("service %p", service);
4593
4594         service->timeout = 0;
4595
4596         if (service->network)
4597                 __connman_network_disconnect(service->network);
4598         else if (service->provider)
4599                 connman_provider_disconnect(service->provider);
4600
4601         __connman_ipconfig_disable(service->ipconfig_ipv4);
4602         __connman_ipconfig_disable(service->ipconfig_ipv6);
4603
4604         __connman_stats_service_unregister(service);
4605
4606         if (service->pending) {
4607                 DBusMessage *reply;
4608
4609                 reply = __connman_error_operation_timeout(service->pending);
4610                 if (reply)
4611                         g_dbus_send_message(connection, reply);
4612
4613                 dbus_message_unref(service->pending);
4614                 service->pending = NULL;
4615         } else
4616                 autoconnect = true;
4617
4618         __connman_service_ipconfig_indicate_state(service,
4619                                         CONNMAN_SERVICE_STATE_FAILURE,
4620                                         CONNMAN_IPCONFIG_TYPE_IPV4);
4621         __connman_service_ipconfig_indicate_state(service,
4622                                         CONNMAN_SERVICE_STATE_FAILURE,
4623                                         CONNMAN_IPCONFIG_TYPE_IPV6);
4624
4625         if (autoconnect &&
4626                         service->connect_reason !=
4627                                 CONNMAN_SERVICE_CONNECT_REASON_USER)
4628                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
4629
4630         return FALSE;
4631 }
4632
4633 static DBusMessage *connect_service(DBusConnection *conn,
4634                                         DBusMessage *msg, void *user_data)
4635 {
4636         struct connman_service *service = user_data;
4637 #if defined TIZEN_EXT
4638         int err = 0;
4639 #else
4640         int index, err = 0;
4641         GList *list;
4642 #endif
4643
4644         DBG("service %p", service);
4645
4646 #if defined TIZEN_EXT
4647         /*
4648          * Description: TIZEN implements system global connection management.
4649          */
4650         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
4651                 connman_service_user_pdn_connection_ref(service);
4652 #endif
4653
4654         if (service->pending)
4655                 return __connman_error_in_progress(msg);
4656
4657         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
4658                 uid_t uid;
4659                 if (connman_dbus_get_connection_unix_user_sync(conn,
4660                                                 dbus_message_get_sender(msg),
4661                                                 &uid) < 0) {
4662                         DBG("Can not get unix user id!");
4663                         return __connman_error_permission_denied(msg);
4664                 }
4665
4666                 if (!__connman_service_is_user_allowed(CONNMAN_SERVICE_TYPE_WIFI, uid)) {
4667                         DBG("Not allow this user to connect this wifi service now!");
4668                         return __connman_error_permission_denied(msg);
4669                 }
4670
4671                 if (uid != USER_ROOT && uid != service->user.favorite_user)
4672                         service->request_passphrase_input = true;
4673
4674                 service->user.current_user = uid;
4675
4676                 if (!service->passphrase && uid == service->user.favorite_user) {
4677                         DBG("Now load this favorite user's passphrase.");
4678                         service_load_passphrase(service);
4679                 }
4680         }
4681
4682 #if !defined TIZEN_EXT
4683         index = __connman_service_get_index(service);
4684
4685         for (list = service_list; list; list = list->next) {
4686                 struct connman_service *temp = list->data;
4687
4688 #if defined TIZEN_EXT
4689                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
4690                         break;
4691 #endif
4692                 if (!is_connecting(temp) && !is_connected(temp))
4693                         break;
4694
4695                 if (service == temp)
4696                         continue;
4697
4698                 if (service->type != temp->type)
4699                         continue;
4700
4701                 if (__connman_service_get_index(temp) == index &&
4702                                 __connman_service_disconnect(temp) == -EINPROGRESS)
4703                         err = -EINPROGRESS;
4704
4705         }
4706         if (err == -EINPROGRESS)
4707                 return __connman_error_operation_timeout(msg);
4708 #endif
4709
4710         service->ignore = false;
4711
4712         service->pending = dbus_message_ref(msg);
4713
4714         err = __connman_service_connect(service,
4715                         CONNMAN_SERVICE_CONNECT_REASON_USER);
4716
4717         if (err == -EINPROGRESS)
4718                 return NULL;
4719
4720         if (service->pending) {
4721                 dbus_message_unref(service->pending);
4722                 service->pending = NULL;
4723         }
4724
4725         if (err < 0)
4726                 return __connman_error_failed(msg, -err);
4727
4728         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4729 }
4730
4731 static DBusMessage *disconnect_service(DBusConnection *conn,
4732                                         DBusMessage *msg, void *user_data)
4733 {
4734         struct connman_service *service = user_data;
4735         int err;
4736
4737         DBG("service %p", service);
4738
4739 #if defined TIZEN_EXT
4740         /*
4741          * Description: TIZEN implements system global connection management.
4742          */
4743         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
4744                 if (connman_service_user_pdn_connection_unref_and_test(service) != TRUE)
4745                         return __connman_error_failed(msg, EISCONN);
4746
4747                 if (is_connected(service) == TRUE &&
4748                                 service == connman_service_get_default_connection())
4749                         return __connman_error_failed(msg, EISCONN);
4750         }
4751 #endif
4752
4753         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
4754                 uid_t uid;
4755                 if (connman_dbus_get_connection_unix_user_sync(conn,
4756                                                 dbus_message_get_sender(msg),
4757                                                 &uid) < 0) {
4758                         DBG("Can not get unix user id!");
4759                         return __connman_error_permission_denied(msg);
4760                 }
4761
4762                 if (!connman_service_is_user_allowed(service, uid)) {
4763                         DBG("Not allow this user to disconnect this wifi service now!");
4764                         return __connman_error_permission_denied(msg);
4765                 }
4766         }
4767
4768         service->ignore = true;
4769
4770         err = __connman_service_disconnect(service);
4771         if (err < 0 && err != -EINPROGRESS)
4772                 return __connman_error_failed(msg, -err);
4773
4774         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4775 }
4776
4777 #if defined TIZEN_EXT
4778 static void __connman_service_cleanup_network_8021x(struct connman_service *service)
4779 {
4780         if (service == NULL)
4781                 return;
4782
4783         DBG("service %p ", service);
4784
4785         connman_network_set_string(service->network, "WiFi.EAP", NULL);
4786         connman_network_set_string(service->network, "WiFi.Identity", NULL);
4787         connman_network_set_string(service->network, "WiFi.CACertFile", NULL);
4788         connman_network_set_string(service->network, "WiFi.ClientCertFile", NULL);
4789         connman_network_set_string(service->network, "WiFi.PrivateKeyFile", NULL);
4790         connman_network_set_string(service->network, "WiFi.PrivateKeyPassphrase", NULL);
4791         connman_network_set_string(service->network, "WiFi.Phase2", NULL);
4792 }
4793 #endif
4794
4795 bool __connman_service_remove(struct connman_service *service)
4796 {
4797         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET ||
4798                         service->type == CONNMAN_SERVICE_TYPE_GADGET)
4799                 return false;
4800
4801         if (service->immutable || service->hidden ||
4802                         __connman_provider_is_immutable(service->provider))
4803                 return false;
4804
4805 #if !defined TIZEN_EXT
4806         if (!service->favorite && service->state !=
4807                                                 CONNMAN_SERVICE_STATE_FAILURE)
4808                 return false;
4809 #endif
4810
4811         __connman_service_disconnect(service);
4812
4813         g_free(service->passphrase);
4814         service->passphrase = NULL;
4815
4816         g_free(service->identity);
4817         service->identity = NULL;
4818
4819         g_free(service->agent_identity);
4820         service->agent_identity = NULL;
4821
4822         g_free(service->eap);
4823         service->eap = NULL;
4824
4825 #if defined TIZEN_EXT
4826         g_free(service->ca_cert_file);
4827         service->ca_cert_file = NULL;
4828
4829         g_free(service->client_cert_file);
4830         service->client_cert_file = NULL;
4831
4832         g_free(service->private_key_file);
4833         service->private_key_file = NULL;
4834
4835         g_free(service->private_key_passphrase);
4836         service->private_key_passphrase = NULL;
4837
4838         g_free(service->phase2);
4839         service->phase2 = NULL;
4840
4841         __connman_service_cleanup_network_8021x(service);
4842
4843         __connman_ipconfig_set_method(service->ipconfig_ipv4, CONNMAN_IPCONFIG_METHOD_DHCP);
4844         __connman_ipconfig_set_method(service->ipconfig_ipv6, CONNMAN_IPCONFIG_METHOD_AUTO);
4845         connman_service_set_proxy(service, NULL, false);
4846
4847         __connman_service_nameserver_clear(service);
4848
4849         g_strfreev(service->nameservers_config);
4850         service->nameservers_config = NULL;
4851
4852 #endif
4853
4854 #if defined TIZEN_EXT
4855         if (service->security != CONNMAN_SERVICE_SECURITY_8021X)
4856 #endif
4857         set_idle(service);
4858
4859         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
4860
4861         service->user.favorite_user = USER_NONE;
4862
4863         __connman_service_set_favorite(service, false);
4864
4865         __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
4866
4867 #if defined TIZEN_EXT
4868         __connman_storage_remove_service(service->identifier);
4869 #else
4870         service_save(service);
4871 #endif
4872
4873         return true;
4874 }
4875
4876 static DBusMessage *remove_service(DBusConnection *conn,
4877                                         DBusMessage *msg, void *user_data)
4878 {
4879         struct connman_service *service = user_data;
4880
4881         DBG("service %p", service);
4882
4883         if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
4884                 uid_t uid;
4885                 if (connman_dbus_get_connection_unix_user_sync(conn,
4886                                                 dbus_message_get_sender(msg),
4887                                                 &uid) < 0) {
4888                         DBG("Can not get unix user id!");
4889                         return __connman_error_permission_denied(msg);
4890                 }
4891
4892 #if !defined TIZEN_EXT
4893                 if (!connman_service_is_user_allowed(service, uid)) {
4894                         DBG("Not allow this user to remove this wifi service now!");
4895                         return __connman_error_permission_denied(msg);
4896                 }
4897 #endif
4898         }
4899
4900         if (!__connman_service_remove(service))
4901                 return __connman_error_not_supported(msg);
4902
4903         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
4904 }
4905
4906 static bool check_suitable_state(enum connman_service_state a,
4907                                         enum connman_service_state b)
4908 {
4909         /*
4910          * Special check so that "ready" service can be moved before
4911          * "online" one.
4912          */
4913         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
4914                         b == CONNMAN_SERVICE_STATE_READY) ||
4915                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
4916                         a == CONNMAN_SERVICE_STATE_READY))
4917                 return true;
4918
4919         return a == b;
4920 }
4921
4922 static void downgrade_state(struct connman_service *service)
4923 {
4924         if (!service)
4925                 return;
4926
4927         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
4928                                                 service->state_ipv6);
4929
4930         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
4931                 __connman_service_ipconfig_indicate_state(service,
4932                                                 CONNMAN_SERVICE_STATE_READY,
4933                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4934
4935         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
4936                 __connman_service_ipconfig_indicate_state(service,
4937                                                 CONNMAN_SERVICE_STATE_READY,
4938                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
4939 }
4940
4941 static void apply_relevant_default_downgrade(struct connman_service *service)
4942 {
4943         struct connman_service *def_service;
4944
4945         def_service = __connman_service_get_default();
4946         if (!def_service)
4947                 return;
4948
4949         if (def_service == service &&
4950                         def_service->state == CONNMAN_SERVICE_STATE_ONLINE) {
4951                 def_service->state = CONNMAN_SERVICE_STATE_READY;
4952                 __connman_notifier_leave_online(def_service->type);
4953                 state_changed(def_service);
4954         }
4955 }
4956
4957 static void switch_default_service(struct connman_service *default_service,
4958                 struct connman_service *downgrade_service)
4959 {
4960         struct connman_service *service;
4961         GList *src, *dst;
4962
4963         apply_relevant_default_downgrade(default_service);
4964         src = g_list_find(service_list, downgrade_service);
4965         dst = g_list_find(service_list, default_service);
4966
4967         /* Nothing to do */
4968         if (src == dst || src->next == dst)
4969                 return;
4970
4971         service = src->data;
4972         service_list = g_list_delete_link(service_list, src);
4973         service_list = g_list_insert_before(service_list, dst, service);
4974
4975         downgrade_state(downgrade_service);
4976 }
4977
4978 static DBusMessage *move_service(DBusConnection *conn,
4979                                         DBusMessage *msg, void *user_data,
4980                                                                 bool before)
4981 {
4982         struct connman_service *service = user_data;
4983         struct connman_service *target;
4984         const char *path;
4985         enum connman_ipconfig_method target4, target6;
4986         enum connman_ipconfig_method service4, service6;
4987
4988         DBG("service %p", service);
4989
4990         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
4991                                                         DBUS_TYPE_INVALID);
4992
4993         if (!service->favorite)
4994                 return __connman_error_not_supported(msg);
4995
4996         target = find_service(path);
4997         if (!target || !target->favorite || target == service)
4998                 return __connman_error_invalid_service(msg);
4999
5000         if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
5001                 /*
5002                  * We only allow VPN route splitting if there are
5003                  * routes defined for a given VPN.
5004                  */
5005                 if (!__connman_provider_check_routes(target->provider)) {
5006                         connman_info("Cannot move service. "
5007                                 "No routes defined for provider %s",
5008                                 __connman_provider_get_ident(target->provider));
5009                         return __connman_error_invalid_service(msg);
5010                 }
5011
5012                 target->do_split_routing = true;
5013         } else
5014                 target->do_split_routing = false;
5015
5016         service->do_split_routing = false;
5017
5018         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
5019         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
5020         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
5021         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
5022
5023         DBG("target %s method %d/%d state %d/%d split %d", target->identifier,
5024                 target4, target6, target->state_ipv4, target->state_ipv6,
5025                 target->do_split_routing);
5026
5027         DBG("service %s method %d/%d state %d/%d", service->identifier,
5028                                 service4, service6,
5029                                 service->state_ipv4, service->state_ipv6);
5030
5031         /*
5032          * If method is OFF, then we do not need to check the corresponding
5033          * ipconfig state.
5034          */
5035         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5036                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5037                         if (!check_suitable_state(target->state_ipv6,
5038                                                         service->state_ipv6))
5039                                 return __connman_error_invalid_service(msg);
5040                 }
5041         }
5042
5043         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5044                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5045                         if (!check_suitable_state(target->state_ipv4,
5046                                                         service->state_ipv4))
5047                                 return __connman_error_invalid_service(msg);
5048                 }
5049         }
5050
5051         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
5052                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
5053                         if (!check_suitable_state(target->state_ipv6,
5054                                                         service->state_ipv6))
5055                                 return __connman_error_invalid_service(msg);
5056                 }
5057         }
5058
5059         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
5060                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
5061                         if (!check_suitable_state(target->state_ipv4,
5062                                                         service->state_ipv4))
5063                                 return __connman_error_invalid_service(msg);
5064                 }
5065         }
5066
5067         g_get_current_time(&service->modified);
5068         service_save(service);
5069         service_save(target);
5070
5071         /*
5072          * If the service which goes down is the default service and is
5073          * online, we downgrade directly its state to ready so:
5074          * the service which goes up, needs to recompute its state which
5075          * is triggered via downgrading it - if relevant - to state ready.
5076          */
5077         if (before)
5078                 switch_default_service(target, service);
5079         else
5080                 switch_default_service(service, target);
5081
5082         __connman_connection_update_gateway();
5083
5084         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5085 }
5086
5087 static DBusMessage *move_before(DBusConnection *conn,
5088                                         DBusMessage *msg, void *user_data)
5089 {
5090         return move_service(conn, msg, user_data, true);
5091 }
5092
5093 static DBusMessage *move_after(DBusConnection *conn,
5094                                         DBusMessage *msg, void *user_data)
5095 {
5096         return move_service(conn, msg, user_data, false);
5097 }
5098
5099 static DBusMessage *reset_counters(DBusConnection *conn,
5100                                         DBusMessage *msg, void *user_data)
5101 {
5102         struct connman_service *service = user_data;
5103
5104         reset_stats(service);
5105
5106         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5107 }
5108
5109 static DBusMessage *get_user_favorite(DBusConnection *conn,
5110                                         DBusMessage *msg, void *user_data)
5111 {
5112         DBusMessage *reply;
5113         uid_t uid = USER_NONE;
5114         dbus_bool_t user_favorite = false;
5115         struct connman_service *service = user_data;
5116
5117         connman_dbus_get_connection_unix_user_sync(conn,
5118                                         dbus_message_get_sender(msg),
5119                                         &uid);
5120         if (uid == USER_ROOT)
5121                 user_favorite = service->favorite;
5122         else if (uid != USER_NONE && uid == service->user.favorite_user) {
5123                 DBG("The service is favorite to this user!");
5124                 user_favorite = true;
5125         }
5126
5127         reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
5128         dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN,
5129                                 &user_favorite, DBUS_TYPE_INVALID);
5130         return reply;
5131 }
5132
5133 static struct _services_notify {
5134         int id;
5135         GHashTable *add;
5136         GHashTable *remove;
5137 } *services_notify;
5138
5139 static void service_append_added_foreach(gpointer data, gpointer user_data)
5140 {
5141         struct connman_service *service = data;
5142         DBusMessageIter *iter = user_data;
5143
5144         if (!service || !service->path) {
5145                 DBG("service %p or path is NULL", service);
5146                 return;
5147         }
5148
5149         if (g_hash_table_lookup(services_notify->add, service->path)) {
5150                 DBG("new %s", service->path);
5151
5152                 append_struct(service, iter);
5153                 g_hash_table_remove(services_notify->add, service->path);
5154         } else {
5155                 DBG("changed %s", service->path);
5156
5157                 append_struct_service(iter, NULL, service);
5158         }
5159 }
5160
5161 static void service_append_ordered(DBusMessageIter *iter, void *user_data)
5162 {
5163         g_list_foreach(service_list, service_append_added_foreach, iter);
5164 }
5165
5166 static void append_removed(gpointer key, gpointer value, gpointer user_data)
5167 {
5168         char *objpath = key;
5169         DBusMessageIter *iter = user_data;
5170
5171         DBG("removed %s", objpath);
5172         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
5173 }
5174
5175 static void service_append_removed(DBusMessageIter *iter, void *user_data)
5176 {
5177         g_hash_table_foreach(services_notify->remove, append_removed, iter);
5178 }
5179
5180 static gboolean service_send_changed(gpointer data)
5181 {
5182         DBusMessage *signal;
5183
5184         DBG("");
5185
5186         services_notify->id = 0;
5187
5188         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
5189                         CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
5190         if (!signal)
5191                 return FALSE;
5192
5193         __connman_dbus_append_objpath_dict_array(signal,
5194                                         service_append_ordered, NULL);
5195         __connman_dbus_append_objpath_array(signal,
5196                                         service_append_removed, NULL);
5197
5198         dbus_connection_send(connection, signal, NULL);
5199         dbus_message_unref(signal);
5200
5201         g_hash_table_remove_all(services_notify->remove);
5202         g_hash_table_remove_all(services_notify->add);
5203
5204         return FALSE;
5205 }
5206
5207 static void service_schedule_changed(void)
5208 {
5209         if (services_notify->id != 0)
5210                 return;
5211
5212         services_notify->id = g_timeout_add(100, service_send_changed, NULL);
5213 }
5214
5215 static void service_schedule_added(struct connman_service *service)
5216 {
5217         DBG("service %p", service);
5218
5219         g_hash_table_remove(services_notify->remove, service->path);
5220         g_hash_table_replace(services_notify->add, service->path, service);
5221
5222         service_schedule_changed();
5223 }
5224
5225 static void service_schedule_removed(struct connman_service *service)
5226 {
5227         if (!service || !service->path) {
5228                 DBG("service %p or path is NULL", service);
5229                 return;
5230         }
5231
5232         DBG("service %p %s", service, service->path);
5233
5234         g_hash_table_remove(services_notify->add, service->path);
5235         g_hash_table_replace(services_notify->remove, g_strdup(service->path),
5236                         NULL);
5237
5238         service_schedule_changed();
5239 }
5240
5241 static bool allow_property_changed(struct connman_service *service)
5242 {
5243 #if defined TIZEN_EXT
5244         if (service->path == NULL)
5245                 return FALSE;
5246 #endif
5247         if (g_hash_table_lookup_extended(services_notify->add, service->path,
5248                                         NULL, NULL)) {
5249                 DBG("no property updates for service %p", service);
5250                 return false;
5251         }
5252
5253         return true;
5254 }
5255
5256 static const GDBusMethodTable service_methods[] = {
5257         { GDBUS_DEPRECATED_METHOD("GetProperties",
5258                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
5259                         get_properties) },
5260         { GDBUS_METHOD("SetProperty",
5261                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }),
5262                         NULL, set_property) },
5263         { GDBUS_METHOD("ClearProperty",
5264                         GDBUS_ARGS({ "name", "s" }), NULL,
5265                         clear_property) },
5266         { GDBUS_ASYNC_METHOD("Connect", NULL, NULL,
5267                               connect_service) },
5268         { GDBUS_METHOD("Disconnect", NULL, NULL,
5269                         disconnect_service) },
5270         { GDBUS_METHOD("Remove", NULL, NULL, remove_service) },
5271         { GDBUS_METHOD("MoveBefore",
5272                         GDBUS_ARGS({ "service", "o" }), NULL,
5273                         move_before) },
5274         { GDBUS_METHOD("MoveAfter",
5275                         GDBUS_ARGS({ "service", "o" }), NULL,
5276                         move_after) },
5277         { GDBUS_METHOD("ResetCounters", NULL, NULL, reset_counters) },
5278         { GDBUS_METHOD("GetUserFavorite",
5279                         NULL, GDBUS_ARGS({ "value", "v" }),
5280                         get_user_favorite) },
5281         { },
5282 };
5283
5284 static const GDBusSignalTable service_signals[] = {
5285         { GDBUS_SIGNAL("PropertyChanged",
5286                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
5287         { },
5288 };
5289
5290 static void service_free(gpointer user_data)
5291 {
5292         struct connman_service *service = user_data;
5293         char *path = service->path;
5294
5295         DBG("service %p", service);
5296
5297         reply_pending(service, ENOENT);
5298
5299         __connman_notifier_service_remove(service);
5300         service_schedule_removed(service);
5301
5302         __connman_wispr_stop(service);
5303         stats_stop(service);
5304
5305         service->path = NULL;
5306
5307         if (path) {
5308                 __connman_connection_update_gateway();
5309
5310                 g_dbus_unregister_interface(connection, path,
5311                                                 CONNMAN_SERVICE_INTERFACE);
5312                 g_free(path);
5313         }
5314
5315         g_hash_table_destroy(service->counter_table);
5316
5317         if (service->network) {
5318                 __connman_network_disconnect(service->network);
5319                 connman_network_unref(service->network);
5320                 service->network = NULL;
5321         }
5322
5323         if (service->provider)
5324                 connman_provider_unref(service->provider);
5325
5326         if (service->ipconfig_ipv4) {
5327                 __connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
5328                 __connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
5329                 __connman_ipconfig_unref(service->ipconfig_ipv4);
5330                 service->ipconfig_ipv4 = NULL;
5331         }
5332
5333         if (service->ipconfig_ipv6) {
5334                 __connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
5335                 __connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
5336                 __connman_ipconfig_unref(service->ipconfig_ipv6);
5337                 service->ipconfig_ipv6 = NULL;
5338         }
5339
5340         g_strfreev(service->timeservers);
5341         g_strfreev(service->timeservers_config);
5342         g_strfreev(service->nameservers);
5343         g_strfreev(service->nameservers_config);
5344         g_strfreev(service->nameservers_auto);
5345         g_strfreev(service->domains);
5346         g_strfreev(service->proxies);
5347         g_strfreev(service->excludes);
5348
5349         g_free(service->hostname);
5350         g_free(service->domainname);
5351         g_free(service->pac);
5352         g_free(service->name);
5353         g_free(service->passphrase);
5354         g_free(service->identifier);
5355         g_free(service->eap);
5356         g_free(service->identity);
5357         g_free(service->agent_identity);
5358         g_free(service->ca_cert_file);
5359         g_free(service->client_cert_file);
5360         g_free(service->private_key_file);
5361         g_free(service->private_key_passphrase);
5362         g_free(service->phase2);
5363         g_free(service->config_file);
5364         g_free(service->config_entry);
5365
5366         if (service->stats.timer)
5367                 g_timer_destroy(service->stats.timer);
5368         if (service->stats_roaming.timer)
5369                 g_timer_destroy(service->stats_roaming.timer);
5370
5371         if (current_default == service)
5372                 current_default = NULL;
5373
5374         g_free(service);
5375 }
5376
5377 static void stats_init(struct connman_service *service)
5378 {
5379         /* home */
5380         service->stats.valid = false;
5381         service->stats.enabled = false;
5382         service->stats.timer = g_timer_new();
5383
5384         /* roaming */
5385         service->stats_roaming.valid = false;
5386         service->stats_roaming.enabled = false;
5387         service->stats_roaming.timer = g_timer_new();
5388 }
5389
5390 static void service_initialize(struct connman_service *service)
5391 {
5392         DBG("service %p", service);
5393
5394         service->refcount = 1;
5395
5396         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
5397
5398         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
5399         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
5400
5401         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
5402         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
5403         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
5404
5405         service->favorite  = false;
5406         service->immutable = false;
5407         service->hidden = false;
5408
5409         service->ignore = false;
5410
5411         service->user.favorite_user = USER_NONE;
5412         service->user.current_user = USER_NONE;
5413
5414         service->request_passphrase_input = false;
5415
5416         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
5417
5418         service->order = 0;
5419
5420         stats_init(service);
5421
5422         service->provider = NULL;
5423
5424         service->wps = false;
5425 #if defined TIZEN_EXT
5426         service->storage_reload = false;
5427         /*
5428          * Description: TIZEN implements system global connection management.
5429          */
5430         service->user_pdn_connection_refcount = 0;
5431         __sync_synchronize();
5432 #endif
5433 }
5434
5435 /**
5436  * connman_service_create:
5437  *
5438  * Allocate a new service.
5439  *
5440  * Returns: a newly-allocated #connman_service structure
5441  */
5442 struct connman_service *connman_service_create(void)
5443 {
5444         GSList *list;
5445         struct connman_stats_counter *counters;
5446         const char *counter;
5447
5448         struct connman_service *service;
5449
5450         service = g_try_new0(struct connman_service, 1);
5451         if (!service)
5452                 return NULL;
5453
5454         DBG("service %p", service);
5455
5456         service->counter_table = g_hash_table_new_full(g_str_hash,
5457                                                 g_str_equal, NULL, g_free);
5458
5459         for (list = counter_list; list; list = list->next) {
5460                 counter = list->data;
5461
5462                 counters = g_try_new0(struct connman_stats_counter, 1);
5463                 if (!counters) {
5464                         g_hash_table_destroy(service->counter_table);
5465                         g_free(service);
5466                         return NULL;
5467                 }
5468
5469                 counters->append_all = true;
5470
5471                 g_hash_table_replace(service->counter_table, (gpointer)counter,
5472                                 counters);
5473         }
5474
5475         service_initialize(service);
5476
5477         return service;
5478 }
5479
5480 /**
5481  * connman_service_ref:
5482  * @service: service structure
5483  *
5484  * Increase reference counter of service
5485  */
5486 struct connman_service *
5487 connman_service_ref_debug(struct connman_service *service,
5488                         const char *file, int line, const char *caller)
5489 {
5490         DBG("%p ref %d by %s:%d:%s()", service, service->refcount + 1,
5491                 file, line, caller);
5492
5493         __sync_fetch_and_add(&service->refcount, 1);
5494
5495         return service;
5496 }
5497
5498 /**
5499  * connman_service_unref:
5500  * @service: service structure
5501  *
5502  * Decrease reference counter of service and release service if no
5503  * longer needed.
5504  */
5505 void connman_service_unref_debug(struct connman_service *service,
5506                         const char *file, int line, const char *caller)
5507 {
5508         DBG("%p ref %d by %s:%d:%s()", service, service->refcount - 1,
5509                 file, line, caller);
5510
5511         if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
5512                 return;
5513
5514         service_list = g_list_remove(service_list, service);
5515
5516         __connman_service_disconnect(service);
5517
5518         g_hash_table_remove(service_hash, service->identifier);
5519 }
5520
5521 static gint service_compare(gconstpointer a, gconstpointer b)
5522 {
5523         struct connman_service *service_a = (void *) a;
5524         struct connman_service *service_b = (void *) b;
5525         enum connman_service_state state_a, state_b;
5526         bool a_connected, b_connected;
5527         gint strength;
5528
5529         state_a = service_a->state;
5530         state_b = service_b->state;
5531         a_connected = is_connected(service_a);
5532         b_connected = is_connected(service_b);
5533
5534         if (a_connected && b_connected) {
5535                 if (service_a->order > service_b->order)
5536                         return -1;
5537
5538                 if (service_a->order < service_b->order)
5539                         return 1;
5540         }
5541
5542         if (state_a != state_b) {
5543                 if (a_connected && b_connected) {
5544                         /* We prefer online over ready state */
5545                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
5546                                 return -1;
5547
5548                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
5549                                 return 1;
5550                 }
5551
5552                 if (a_connected)
5553                         return -1;
5554                 if (b_connected)
5555                         return 1;
5556
5557                 if (is_connecting(service_a))
5558                         return -1;
5559                 if (is_connecting(service_b))
5560                         return 1;
5561         }
5562
5563         if (service_a->favorite && !service_b->favorite)
5564                 return -1;
5565
5566         if (!service_a->favorite && service_b->favorite)
5567                 return 1;
5568
5569         if (service_a->type != service_b->type) {
5570
5571                 if (service_a->type == CONNMAN_SERVICE_TYPE_ETHERNET)
5572                         return -1;
5573                 if (service_b->type == CONNMAN_SERVICE_TYPE_ETHERNET)
5574                         return 1;
5575
5576                 if (service_a->type == CONNMAN_SERVICE_TYPE_WIFI)
5577                         return -1;
5578                 if (service_b->type == CONNMAN_SERVICE_TYPE_WIFI)
5579                         return 1;
5580
5581                 if (service_a->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5582                         return -1;
5583                 if (service_b->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5584                         return 1;
5585
5586                 if (service_a->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
5587                         return -1;
5588                 if (service_b->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
5589                         return 1;
5590
5591                 if (service_a->type == CONNMAN_SERVICE_TYPE_VPN)
5592                         return -1;
5593                 if (service_b->type == CONNMAN_SERVICE_TYPE_VPN)
5594                         return 1;
5595
5596                 if (service_a->type == CONNMAN_SERVICE_TYPE_GADGET)
5597                         return -1;
5598                 if (service_b->type == CONNMAN_SERVICE_TYPE_GADGET)
5599                         return 1;
5600         }
5601
5602         strength = (gint) service_b->strength - (gint) service_a->strength;
5603         if (strength)
5604                 return strength;
5605
5606         return g_strcmp0(service_a->name, service_b->name);
5607 }
5608
5609 static void service_list_sort(void)
5610 {
5611         if (service_list && service_list->next) {
5612                 service_list = g_list_sort(service_list, service_compare);
5613                 service_schedule_changed();
5614         }
5615 }
5616
5617 /**
5618  * connman_service_get_type:
5619  * @service: service structure
5620  *
5621  * Get the type of service
5622  */
5623 enum connman_service_type connman_service_get_type(struct connman_service *service)
5624 {
5625         if (!service)
5626                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
5627
5628         return service->type;
5629 }
5630
5631 /**
5632  * connman_service_get_interface:
5633  * @service: service structure
5634  *
5635  * Get network interface of service
5636  */
5637 char *connman_service_get_interface(struct connman_service *service)
5638 {
5639         int index;
5640
5641         if (!service)
5642                 return NULL;
5643
5644         index = __connman_service_get_index(service);
5645
5646         return connman_inet_ifname(index);
5647 }
5648
5649 /**
5650  * __connman_service_is_user_allowed:
5651  * @type: service type
5652  * @uid: user id
5653  *
5654  * Check a user is allowed to operate a type of service
5655  */
5656 bool __connman_service_is_user_allowed(enum connman_service_type type,
5657                                         uid_t uid)
5658 {
5659         GList *list;
5660         uid_t owner_user = USER_NONE;
5661
5662         for (list = service_list; list; list = list->next) {
5663                 struct connman_service *service = list->data;
5664
5665                 if (service->type != type)
5666                         continue;
5667
5668                 if (is_connected(service)) {
5669                         owner_user = service->user.favorite_user;
5670                         break;
5671                 }
5672         }
5673
5674         if (uid == USER_NONE ||
5675                         (uid != USER_ROOT &&
5676                         owner_user != USER_NONE &&
5677                         owner_user != uid))
5678                 return false;
5679
5680         return true;
5681 }
5682
5683 /**
5684  * connman_service_get_network:
5685  * @service: service structure
5686  *
5687  * Get the service network
5688  */
5689 struct connman_network *
5690 __connman_service_get_network(struct connman_service *service)
5691 {
5692         if (!service)
5693                 return NULL;
5694
5695         return service->network;
5696 }
5697
5698 struct connman_ipconfig *
5699 __connman_service_get_ip4config(struct connman_service *service)
5700 {
5701         if (!service)
5702                 return NULL;
5703
5704         return service->ipconfig_ipv4;
5705 }
5706
5707 struct connman_ipconfig *
5708 __connman_service_get_ip6config(struct connman_service *service)
5709 {
5710         if (!service)
5711                 return NULL;
5712
5713         return service->ipconfig_ipv6;
5714 }
5715
5716 struct connman_ipconfig *
5717 __connman_service_get_ipconfig(struct connman_service *service, int family)
5718 {
5719         if (family == AF_INET)
5720                 return __connman_service_get_ip4config(service);
5721         else if (family == AF_INET6)
5722                 return __connman_service_get_ip6config(service);
5723         else
5724                 return NULL;
5725
5726 }
5727
5728 bool __connman_service_is_connected_state(struct connman_service *service,
5729                                         enum connman_ipconfig_type type)
5730 {
5731         if (!service)
5732                 return false;
5733
5734         switch (type) {
5735         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
5736                 break;
5737         case CONNMAN_IPCONFIG_TYPE_IPV4:
5738                 return is_connected_state(service, service->state_ipv4);
5739         case CONNMAN_IPCONFIG_TYPE_IPV6:
5740                 return is_connected_state(service, service->state_ipv6);
5741         case CONNMAN_IPCONFIG_TYPE_ALL:
5742                 return is_connected_state(service,
5743                                         CONNMAN_IPCONFIG_TYPE_IPV4) &&
5744                         is_connected_state(service,
5745                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5746         }
5747
5748         return false;
5749 }
5750 enum connman_service_security __connman_service_get_security(
5751                                 struct connman_service *service)
5752 {
5753         if (!service)
5754                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
5755
5756         return service->security;
5757 }
5758
5759 const char *__connman_service_get_phase2(struct connman_service *service)
5760 {
5761         if (!service)
5762                 return NULL;
5763
5764         return service->phase2;
5765 }
5766
5767 bool __connman_service_wps_enabled(struct connman_service *service)
5768 {
5769         if (!service)
5770                 return false;
5771
5772         return service->wps;
5773 }
5774
5775 void __connman_service_mark_dirty(void)
5776 {
5777         services_dirty = true;
5778 }
5779
5780 #if defined TIZEN_EXT
5781 /**
5782   * Returns profile count if there is any connected profiles
5783   * that use same interface
5784   */
5785 int __connman_service_get_connected_count_of_iface(
5786                                         struct connman_service *service)
5787 {
5788         GList *list;
5789         int count = 0;
5790         int index1 = 0;
5791         int index2 = 0;
5792
5793         DBG("");
5794
5795         index1 = __connman_service_get_index(service);
5796
5797         if (index1 <= 0)
5798                 return 0;
5799
5800         for (list = service_list; list; list = list->next) {
5801                 struct connman_service *service2 = list->data;
5802
5803                 if (service == service2)
5804                         continue;
5805
5806                 index2 = __connman_service_get_index(service2);
5807
5808                 if (is_connected(service2) && index2 > 0 && index1 == index2)
5809                         count++;
5810
5811                 index2 = 0;
5812         }
5813
5814         DBG("Interface index %d, count %d", index1, count);
5815
5816         return count;
5817 }
5818
5819 void __connman_service_set_storage_reload(struct connman_service *service,
5820                                         bool storage_reload)
5821 {
5822         if (service != NULL)
5823                 service->storage_reload = storage_reload;
5824 }
5825 #endif
5826
5827 /**
5828  * __connman_service_set_favorite_delayed:
5829  * @service: service structure
5830  * @favorite: favorite value
5831  * @delay_ordering: do not order service sequence
5832  *
5833  * Change the favorite setting of service
5834  */
5835 int __connman_service_set_favorite_delayed(struct connman_service *service,
5836                                         bool favorite,
5837                                         bool delay_ordering)
5838 {
5839 #if defined TIZEN_EXT
5840         if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
5841                 return -EIO;
5842 #endif
5843         if (service->hidden)
5844                 return -EOPNOTSUPP;
5845
5846         if (service->favorite == favorite)
5847                 return -EALREADY;
5848
5849         service->favorite = favorite;
5850
5851         if (!delay_ordering)
5852                 __connman_service_get_order(service);
5853
5854         favorite_changed(service);
5855
5856         if (!delay_ordering) {
5857
5858                 service_list_sort();
5859
5860                 __connman_connection_update_gateway();
5861         }
5862
5863         return 0;
5864 }
5865
5866 /**
5867  * __connman_service_set_favorite:
5868  * @service: service structure
5869  * @favorite: favorite value
5870  *
5871  * Change the favorite setting of service
5872  */
5873 int __connman_service_set_favorite(struct connman_service *service,
5874                                                 bool favorite)
5875 {
5876         return __connman_service_set_favorite_delayed(service, favorite,
5877                                                         false);
5878 }
5879
5880 bool connman_service_get_favorite(struct connman_service *service)
5881 {
5882         return service->favorite;
5883 }
5884
5885 bool connman_service_get_autoconnect(struct connman_service *service)
5886 {
5887         return service->autoconnect;
5888 }
5889
5890 int __connman_service_set_immutable(struct connman_service *service,
5891                                                 bool immutable)
5892 {
5893         if (service->hidden)
5894                 return -EOPNOTSUPP;
5895
5896         if (service->immutable == immutable)
5897                 return 0;
5898
5899         service->immutable = immutable;
5900
5901         immutable_changed(service);
5902
5903         return 0;
5904 }
5905
5906 int __connman_service_set_ignore(struct connman_service *service,
5907                                                 bool ignore)
5908 {
5909         if (!service)
5910                 return -EINVAL;
5911
5912         service->ignore = ignore;
5913
5914         return 0;
5915 }
5916
5917 void __connman_service_set_string(struct connman_service *service,
5918                                   const char *key, const char *value)
5919 {
5920         if (service->hidden)
5921                 return;
5922         if (g_str_equal(key, "EAP")) {
5923                 g_free(service->eap);
5924                 service->eap = g_strdup(value);
5925         } else if (g_str_equal(key, "Identity")) {
5926                 g_free(service->identity);
5927                 service->identity = g_strdup(value);
5928         } else if (g_str_equal(key, "CACertFile")) {
5929                 g_free(service->ca_cert_file);
5930                 service->ca_cert_file = g_strdup(value);
5931         } else if (g_str_equal(key, "ClientCertFile")) {
5932                 g_free(service->client_cert_file);
5933                 service->client_cert_file = g_strdup(value);
5934         } else if (g_str_equal(key, "PrivateKeyFile")) {
5935                 g_free(service->private_key_file);
5936                 service->private_key_file = g_strdup(value);
5937         } else if (g_str_equal(key, "PrivateKeyPassphrase")) {
5938                 g_free(service->private_key_passphrase);
5939                 service->private_key_passphrase = g_strdup(value);
5940         } else if (g_str_equal(key, "Phase2")) {
5941                 g_free(service->phase2);
5942                 service->phase2 = g_strdup(value);
5943         } else if (g_str_equal(key, "Passphrase"))
5944                 __connman_service_set_passphrase(service, value);
5945 }
5946
5947 void __connman_service_set_search_domains(struct connman_service *service,
5948                                         char **domains)
5949 {
5950         searchdomain_remove_all(service);
5951
5952         if (service->domains)
5953                 g_strfreev(service->domains);
5954
5955         service->domains = g_strdupv(domains);
5956
5957         searchdomain_add_all(service);
5958 }
5959
5960 static void service_complete(struct connman_service *service)
5961 {
5962         reply_pending(service, EIO);
5963
5964         if (service->connect_reason != CONNMAN_SERVICE_CONNECT_REASON_USER)
5965                 __connman_service_auto_connect(service->connect_reason);
5966
5967         g_get_current_time(&service->modified);
5968         service_save(service);
5969 }
5970
5971 static void report_error_cb(void *user_context, bool retry,
5972                                                         void *user_data)
5973 {
5974         struct connman_service *service = user_context;
5975
5976         if (retry)
5977                 __connman_service_connect(service,
5978                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
5979         else {
5980                 /* It is not relevant to stay on Failure state
5981                  * when failing is due to wrong user input */
5982                 __connman_service_clear_error(service);
5983 #if defined TIZEN_EXT
5984                 /* Reseting the state back in case of failure state */
5985                 service->state_ipv4 = service->state_ipv6 =
5986                                 CONNMAN_SERVICE_STATE_IDLE;
5987
5988                 if (service->error != CONNMAN_SERVICE_ERROR_AUTH_FAILED)
5989                         set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
5990 #endif
5991                 service_complete(service);
5992                 __connman_connection_update_gateway();
5993         }
5994 }
5995
5996 static int check_wpspin(struct connman_service *service, const char *wpspin)
5997 {
5998         int length;
5999         guint i;
6000
6001         if (!wpspin)
6002                 return 0;
6003
6004         length = strlen(wpspin);
6005
6006         /* If 0, it will mean user wants to use PBC method */
6007         if (length == 0) {
6008                 connman_network_set_string(service->network,
6009                                                         "WiFi.PinWPS", NULL);
6010                 return 0;
6011         }
6012
6013         /* A WPS PIN is always 8 chars length,
6014          * its content is in digit representation.
6015          */
6016         if (length != 8)
6017                 return -ENOKEY;
6018
6019         for (i = 0; i < 8; i++)
6020                 if (!isdigit((unsigned char) wpspin[i]))
6021                         return -ENOKEY;
6022
6023         connman_network_set_string(service->network, "WiFi.PinWPS", wpspin);
6024
6025         return 0;
6026 }
6027
6028 static void request_input_cb(struct connman_service *service,
6029                         bool values_received,
6030                         const char *name, int name_len,
6031                         const char *identity, const char *passphrase,
6032                         bool wps, const char *wpspin,
6033                         const char *error, void *user_data)
6034 {
6035         struct connman_device *device;
6036         const char *security;
6037         int err = 0;
6038
6039         DBG("RequestInput return, %p", service);
6040
6041         if (error) {
6042                 DBG("error: %s", error);
6043
6044                 if (g_strcmp0(error,
6045                                 "net.connman.Agent.Error.Canceled") == 0) {
6046                         err = -EINVAL;
6047
6048                         if (service->hidden)
6049                                 __connman_service_return_error(service,
6050                                                         ECANCELED, user_data);
6051                         goto done;
6052                 } else {
6053                         if (service->hidden)
6054                                 __connman_service_return_error(service,
6055                                                         ETIMEDOUT, user_data);
6056                 }
6057         }
6058
6059         if (service->hidden && name_len > 0 && name_len <= 32) {
6060                 device = connman_network_get_device(service->network);
6061                 security = connman_network_get_string(service->network,
6062                                                         "WiFi.Security");
6063                 err = __connman_device_request_hidden_scan(device,
6064                                                 name, name_len,
6065                                                 identity, passphrase,
6066                                                 security, user_data);
6067                 if (err < 0)
6068                         __connman_service_return_error(service, -err,
6069                                                         user_data);
6070         }
6071
6072         if (!values_received || service->hidden) {
6073                 err = -EINVAL;
6074                 goto done;
6075         }
6076
6077         if (wps && service->network) {
6078                 err = check_wpspin(service, wpspin);
6079                 if (err < 0)
6080                         goto done;
6081
6082                 connman_network_set_bool(service->network, "WiFi.UseWPS", wps);
6083         }
6084
6085         if (identity)
6086                 __connman_service_set_agent_identity(service, identity);
6087
6088         if (passphrase)
6089                 err = __connman_service_set_passphrase(service, passphrase);
6090
6091  done:
6092         if (err >= 0) {
6093                 /* We forget any previous error. */
6094                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6095
6096                 __connman_service_connect(service,
6097                                         CONNMAN_SERVICE_CONNECT_REASON_USER);
6098
6099         } else if (err == -ENOKEY) {
6100                 __connman_service_indicate_error(service,
6101                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
6102         } else {
6103                 /* It is not relevant to stay on Failure state
6104                  * when failing is due to wrong user input */
6105                 service->state = CONNMAN_SERVICE_STATE_IDLE;
6106
6107                 if (!service->hidden) {
6108                         /*
6109                          * If there was a real error when requesting
6110                          * hidden scan, then that error is returned already
6111                          * to the user somewhere above so do not try to
6112                          * do this again.
6113                          */
6114                         __connman_service_return_error(service, -err,
6115                                                         user_data);
6116                 }
6117
6118                 service_complete(service);
6119                 __connman_connection_update_gateway();
6120         }
6121 }
6122
6123 static void downgrade_connected_services(void)
6124 {
6125         struct connman_service *up_service;
6126         GList *list;
6127
6128         for (list = service_list; list; list = list->next) {
6129                 up_service = list->data;
6130
6131                 if (!is_connected(up_service))
6132                         continue;
6133
6134                 if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
6135                         return;
6136
6137                 downgrade_state(up_service);
6138         }
6139 }
6140
6141 static int service_update_preferred_order(struct connman_service *default_service,
6142                 struct connman_service *new_service,
6143                 enum connman_service_state new_state)
6144 {
6145         unsigned int *tech_array;
6146         int i;
6147
6148         if (!default_service || default_service == new_service ||
6149                         default_service->state != new_state)
6150                 return 0;
6151
6152         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
6153         if (tech_array) {
6154
6155                 for (i = 0; tech_array[i] != 0; i += 1) {
6156                         if (default_service->type == tech_array[i])
6157                                 return -EALREADY;
6158
6159                         if (new_service->type == tech_array[i]) {
6160                                 switch_default_service(default_service,
6161                                                 new_service);
6162                                 __connman_connection_update_gateway();
6163                                 return 0;
6164                         }
6165                 }
6166         }
6167
6168         return -EALREADY;
6169 }
6170
6171 #if defined TIZEN_EXT
6172 static gboolean __connman_service_can_drop(struct connman_service *service)
6173 {
6174         if (is_connected(service) == TRUE || is_connecting(service) == TRUE) {
6175                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR)
6176                         return TRUE;
6177                 else if (connman_service_is_no_ref_user_pdn_connection(service) == TRUE)
6178                         return TRUE;
6179         }
6180         return FALSE;
6181 }
6182
6183 static struct connman_device *default_connecting_device = NULL;
6184
6185 static void __connman_service_disconnect_default(struct connman_service *service)
6186 {
6187         struct connman_device *default_device = NULL;
6188
6189         if (default_connecting_device == NULL)
6190                 return;
6191
6192         default_device = connman_network_get_device(
6193                         __connman_service_get_network(service));
6194
6195         DBG("Disconnecting service %p %s", service, service->path);
6196         DBG("Disconnecting device %p %p %s",
6197                         default_connecting_device,
6198                         default_device,
6199                         connman_device_get_string(default_device, "Name"));
6200
6201         if (default_connecting_device == default_device)
6202                 default_connecting_device = NULL;
6203 }
6204
6205 static void __connman_service_connect_default(struct connman_service *current)
6206 {
6207         int err;
6208         GList *list;
6209         bool default_internet;
6210         struct connman_service *service;
6211         struct connman_service *default_service = NULL;
6212         struct connman_device *default_device = NULL;
6213
6214         if (current->type == CONNMAN_SERVICE_TYPE_CELLULAR) {
6215                 switch (current->state) {
6216                 case CONNMAN_SERVICE_STATE_UNKNOWN:
6217                 case CONNMAN_SERVICE_STATE_ASSOCIATION:
6218                 case CONNMAN_SERVICE_STATE_CONFIGURATION:
6219                         return;
6220                 default:
6221                         break;
6222                 }
6223
6224                 if (default_connecting_device &&
6225                                 __connman_service_is_internet_profile(current) == TRUE) {
6226                         if (current->network == NULL)
6227                                 return;
6228
6229                         default_device = connman_network_get_device(current->network);
6230                         if (default_connecting_device == default_device) {
6231                                 DBG("Cellular service[%s]  %p %s",
6232                                                 state2string(current->state), current, current->path);
6233                                 DBG("Cellular device %p %p %s",
6234                                                 default_connecting_device, default_device,
6235                                                 connman_device_get_string(default_device, "Name"));
6236
6237                                 default_connecting_device = NULL;
6238                         }
6239                 }
6240
6241                 return;
6242         } else if (is_connected(current) == TRUE || is_connecting(current) == TRUE)
6243                 return;
6244
6245         /* Always-on: keep default cellular connection as possible */
6246         for (list = service_list; list; list = list->next) {
6247                 service = list->data;
6248
6249                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6250                                 __connman_service_is_internet_profile(service) != TRUE ||
6251                                 service->network == NULL) {
6252                         continue;
6253                 }
6254
6255                 default_internet =
6256                                 connman_network_get_bool(service->network, "DefaultInternet");
6257
6258                 DBG("service: %p %s %s %s (default: %d)", service, service->name,
6259                                 __connman_service_type2string(service->type),
6260                                 state2string(service->state), default_internet);
6261
6262                 if (default_internet) {
6263                         default_service = service;
6264                         if (is_connected(default_service) == TRUE ||
6265                                         is_connecting(default_service) == TRUE)
6266                                 return;
6267
6268                         default_device = connman_network_get_device(default_service->network);
6269                         if (default_connecting_device == default_device) {
6270                                 DBG("Device is connecting (%p)", default_connecting_device);
6271                                 return;
6272                         }
6273
6274                         default_connecting_device = default_device;
6275                         default_service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_USER;
6276
6277                         err = __connman_network_connect(default_service->network);
6278                         DBG("Connecting default service %p %s [%d]",
6279                                         default_service, default_service->path, err);
6280                         DBG("Connecting device %p %s", default_connecting_device,
6281                                         connman_device_get_string(default_connecting_device, "Name"));
6282                         if (err < 0 && err != -EINPROGRESS) {
6283                                 default_connecting_device = NULL;
6284                         } else
6285                                 break;
6286                 }
6287         }
6288 }
6289 #endif
6290
6291 static void single_connected_tech(struct connman_service *allowed)
6292 {
6293         struct connman_service *service;
6294         GSList *services = NULL, *list;
6295         GList *iter;
6296
6297         DBG("keeping %p %s", allowed, allowed->path);
6298
6299 #if defined TIZEN_EXT
6300         if (!allowed || allowed->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6301                 return;
6302 #endif
6303
6304         for (iter = service_list; iter; iter = iter->next) {
6305                 service = iter->data;
6306
6307 #if defined TIZEN_EXT
6308                 if (service != allowed && service->type != allowed->type &&
6309                                 __connman_service_can_drop(service) == TRUE)
6310 #else
6311                 if (!is_connected(service))
6312                         break;
6313
6314                 if (service == allowed)
6315                         continue;
6316 #endif
6317                 services = g_slist_prepend(services, service);
6318         }
6319
6320         for (list = services; list; list = list->next) {
6321                 service = list->data;
6322
6323                 DBG("disconnecting %p %s", service, service->path);
6324 #if defined TIZEN_EXT
6325                 __connman_service_disconnect_default(service);
6326 #endif
6327                 __connman_service_disconnect(service);
6328         }
6329
6330         g_slist_free(services);
6331 }
6332
6333 #if defined TIZEN_EXT
6334 static void set_priority_connected_service(void)
6335 {
6336         struct connman_service *service;
6337         GList *list;
6338
6339         for (list = service_list; list; list = list->next) {
6340                 service = list->data;
6341
6342                 if (is_connected(service) == FALSE)
6343                         service->order = 5;
6344                 else
6345                         service->order = 6;
6346         }
6347 }
6348 #endif
6349
6350 static const char *get_dbus_sender(struct connman_service *service)
6351 {
6352         if (!service->pending)
6353                 return NULL;
6354
6355         return dbus_message_get_sender(service->pending);
6356 }
6357
6358 static int service_indicate_state(struct connman_service *service)
6359 {
6360         enum connman_service_state old_state, new_state;
6361         struct connman_service *def_service;
6362         enum connman_ipconfig_method method;
6363         int result;
6364
6365         if (!service)
6366                 return -EINVAL;
6367
6368         old_state = service->state;
6369         new_state = combine_state(service->state_ipv4, service->state_ipv6);
6370
6371         DBG("service %p old %s - new %s/%s => %s",
6372                                         service,
6373                                         state2string(old_state),
6374                                         state2string(service->state_ipv4),
6375                                         state2string(service->state_ipv6),
6376                                         state2string(new_state));
6377
6378         if (old_state == new_state)
6379                 return -EALREADY;
6380
6381         def_service = __connman_service_get_default();
6382
6383         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
6384                 result = service_update_preferred_order(def_service,
6385                                 service, new_state);
6386                 if (result == -EALREADY)
6387                         return result;
6388         }
6389
6390         if (old_state == CONNMAN_SERVICE_STATE_ONLINE)
6391                 __connman_notifier_leave_online(service->type);
6392
6393         if (is_connected_state(service, old_state) &&
6394                         !is_connected_state(service, new_state))
6395                 searchdomain_remove_all(service);
6396
6397         service->state = new_state;
6398         state_changed(service);
6399
6400         switch(new_state) {
6401         case CONNMAN_SERVICE_STATE_UNKNOWN:
6402
6403                 break;
6404
6405         case CONNMAN_SERVICE_STATE_IDLE:
6406                 if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
6407                         __connman_service_disconnect(service);
6408
6409                 break;
6410
6411         case CONNMAN_SERVICE_STATE_ASSOCIATION:
6412
6413                 break;
6414
6415         case CONNMAN_SERVICE_STATE_CONFIGURATION:
6416                 if (!service->new_service &&
6417                                 __connman_stats_service_register(service) == 0) {
6418                         /*
6419                          * For new services the statistics are updated after
6420                          * we have successfully connected.
6421                          */
6422                         __connman_stats_get(service, false,
6423                                                 &service->stats.data);
6424                         __connman_stats_get(service, true,
6425                                                 &service->stats_roaming.data);
6426                 }
6427
6428                 break;
6429
6430         case CONNMAN_SERVICE_STATE_READY:
6431                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6432
6433                 if (service->new_service &&
6434                                 __connman_stats_service_register(service) == 0) {
6435                         /*
6436                          * This is normally done after configuring state
6437                          * but for new service do this after we have connected
6438                          * successfully.
6439                          */
6440                         __connman_stats_get(service, false,
6441                                                 &service->stats.data);
6442                         __connman_stats_get(service, true,
6443                                                 &service->stats_roaming.data);
6444                 }
6445
6446                 service->new_service = false;
6447
6448                 default_changed();
6449
6450                 def_service = __connman_service_get_default();
6451
6452                 service_update_preferred_order(def_service, service, new_state);
6453
6454                 __connman_service_set_favorite(service, true);
6455
6456                 reply_pending(service, 0);
6457
6458                 g_get_current_time(&service->modified);
6459                 service_save(service);
6460
6461                 searchdomain_add_all(service);
6462                 dns_changed(service);
6463                 domain_changed(service);
6464                 proxy_changed(service);
6465
6466                 if (old_state != CONNMAN_SERVICE_STATE_ONLINE)
6467                         __connman_notifier_connect(service->type);
6468
6469                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
6470                         connman_network_get_bool(service->network,
6471                                                 "WiFi.UseWPS")) {
6472                         const char *pass;
6473
6474                         pass = connman_network_get_string(service->network,
6475                                                         "WiFi.Passphrase");
6476
6477                         __connman_service_set_passphrase(service, pass);
6478
6479                         connman_network_set_bool(service->network,
6480                                                         "WiFi.UseWPS", false);
6481                 }
6482
6483                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
6484                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
6485                         __connman_ipconfig_disable_ipv6(
6486                                                 service->ipconfig_ipv6);
6487
6488                 if (connman_setting_get_bool("SingleConnectedTechnology"))
6489                         single_connected_tech(service);
6490                 else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
6491                         vpn_auto_connect();
6492
6493 #if defined TIZEN_EXT
6494                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
6495                         set_priority_connected_service();
6496 #endif
6497
6498                 break;
6499
6500         case CONNMAN_SERVICE_STATE_ONLINE:
6501
6502                 break;
6503
6504         case CONNMAN_SERVICE_STATE_DISCONNECT:
6505                 set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
6506
6507                 reply_pending(service, ECONNABORTED);
6508
6509                 def_service = __connman_service_get_default();
6510                 service->disconnect_reason = connman_network_get_disconnect_reason(service->network);
6511
6512                 if (!__connman_notifier_is_connected() &&
6513                         def_service &&
6514                                 def_service->provider)
6515                         connman_provider_disconnect(def_service->provider);
6516
6517                 default_changed();
6518
6519                 __connman_wispr_stop(service);
6520
6521                 __connman_wpad_stop(service);
6522
6523 #if defined TIZEN_EXT
6524                 /**
6525                   * Skip the functions if there is any connected profiles
6526                   * that use same interface
6527                   */
6528                 if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
6529                         __connman_service_get_connected_count_of_iface(
6530                                                         service) <= 0) {
6531 #endif
6532                 dns_changed(service);
6533                 domain_changed(service);
6534                 proxy_changed(service);
6535 #if defined TIZEN_EXT
6536                 }
6537 #endif
6538
6539                 /*
6540                  * Previous services which are connected and which states
6541                  * are set to online should reset relevantly ipconfig_state
6542                  * to ready so wispr/portal will be rerun on those
6543                  */
6544                 downgrade_connected_services();
6545
6546                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
6547                 break;
6548
6549         case CONNMAN_SERVICE_STATE_FAILURE:
6550 #if defined TIZEN_EXT
6551                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
6552                         service->order = 5;
6553                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
6554 #endif
6555                 if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
6556                         connman_agent_report_error(service, service->path,
6557                                         error2string(service->error),
6558                                         report_error_cb,
6559                                         get_dbus_sender(service),
6560                                         NULL) == -EINPROGRESS)
6561                         return 0;
6562                 service_complete(service);
6563
6564                 break;
6565         }
6566
6567         service_list_sort();
6568
6569 #if defined TIZEN_EXT
6570         __connman_service_connect_default(service);
6571 #endif
6572
6573         __connman_connection_update_gateway();
6574
6575         if ((old_state == CONNMAN_SERVICE_STATE_ONLINE &&
6576                         new_state != CONNMAN_SERVICE_STATE_READY) ||
6577                 (old_state == CONNMAN_SERVICE_STATE_READY &&
6578                         new_state != CONNMAN_SERVICE_STATE_ONLINE)) {
6579                 __connman_notifier_disconnect(service->type);
6580         }
6581
6582         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
6583                 __connman_notifier_enter_online(service->type);
6584                 default_changed();
6585         }
6586
6587         if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
6588                 service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
6589                 (new_state == CONNMAN_SERVICE_STATE_READY ||
6590                 new_state == CONNMAN_SERVICE_STATE_ONLINE)) {
6591                 if (service->user.favorite_user != service->user.current_user) {
6592                         DBG("Now set service favorite user id from %d to %d",
6593                         service->user.favorite_user, service->user.current_user);
6594
6595                         service->user.favorite_user = service->user.current_user;
6596
6597                         service_save(service);
6598                 }
6599         }
6600
6601         return 0;
6602 }
6603
6604 int __connman_service_indicate_error(struct connman_service *service,
6605                                         enum connman_service_error error)
6606 {
6607         DBG("service %p error %d", service, error);
6608
6609         if (!service)
6610                 return -EINVAL;
6611
6612         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
6613                 return -EALREADY;
6614
6615         set_error(service, error);
6616
6617 /* default internet service: fix not cleared if pdp activation*/
6618 #if defined TIZEN_EXT
6619                 /*
6620                  * If connection failed for default service(DefaultInternet),
6621                  * default_connecting_device should be cleared.
6622                  */
6623                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
6624                                 service->error == CONNMAN_SERVICE_ERROR_CONNECT_FAILED)
6625                         __connman_service_disconnect_default(service);
6626
6627                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
6628                                 service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY) {
6629                         g_free(service->passphrase);
6630                         service->passphrase = NULL;
6631                 }
6632 #endif
6633
6634         __connman_service_ipconfig_indicate_state(service,
6635                                                 CONNMAN_SERVICE_STATE_FAILURE,
6636                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
6637         __connman_service_ipconfig_indicate_state(service,
6638                                                 CONNMAN_SERVICE_STATE_FAILURE,
6639                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
6640         return 0;
6641 }
6642
6643 int __connman_service_clear_error(struct connman_service *service)
6644 {
6645         DBusMessage *pending, *provider_pending;
6646
6647         DBG("service %p", service);
6648
6649         if (!service)
6650                 return -EINVAL;
6651
6652         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
6653                 return -EINVAL;
6654
6655         pending = service->pending;
6656         service->pending = NULL;
6657         provider_pending = service->provider_pending;
6658         service->provider_pending = NULL;
6659
6660         __connman_service_ipconfig_indicate_state(service,
6661                                                 CONNMAN_SERVICE_STATE_IDLE,
6662                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
6663
6664         __connman_service_ipconfig_indicate_state(service,
6665                                                 CONNMAN_SERVICE_STATE_IDLE,
6666                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
6667
6668         service->pending = pending;
6669         service->provider_pending = provider_pending;
6670
6671         return 0;
6672 }
6673
6674 int __connman_service_indicate_default(struct connman_service *service)
6675 {
6676         DBG("service %p state %s", service, state2string(service->state));
6677
6678         if (!is_connected(service)) {
6679                 /*
6680                  * If service is not yet fully connected, then we must not
6681                  * change the default yet. The default gw will be changed
6682                  * after the service state is in ready.
6683                  */
6684                 return -EINPROGRESS;
6685         }
6686
6687         default_changed();
6688
6689         return 0;
6690 }
6691
6692 enum connman_service_state __connman_service_ipconfig_get_state(
6693                                         struct connman_service *service,
6694                                         enum connman_ipconfig_type type)
6695 {
6696         if (!service)
6697                 return CONNMAN_SERVICE_STATE_UNKNOWN;
6698
6699         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6700                 return service->state_ipv4;
6701
6702         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
6703                 return service->state_ipv6;
6704
6705         return CONNMAN_SERVICE_STATE_UNKNOWN;
6706 }
6707
6708 static void check_proxy_setup(struct connman_service *service)
6709 {
6710         /*
6711          * We start WPAD if we haven't got a PAC URL from DHCP and
6712          * if our proxy manual configuration is either empty or set
6713          * to AUTO with an empty URL.
6714          */
6715
6716         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
6717                 goto done;
6718
6719         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
6720                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
6721                         service->pac))
6722                 goto done;
6723
6724         if (__connman_wpad_start(service) < 0) {
6725                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
6726                 __connman_notifier_proxy_changed(service);
6727                 goto done;
6728         }
6729
6730         return;
6731
6732 done:
6733         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
6734 }
6735
6736 #if defined TIZEN_EXT
6737 void connman_check_proxy_setup_and_wispr_start(struct connman_service *service){
6738
6739         DBG("check the proxy and start wispr");
6740         check_proxy_setup(service);
6741         return;
6742 }
6743 #endif
6744
6745 /*
6746  * How many networks are connected at the same time. If more than 1,
6747  * then set the rp_filter setting properly (loose mode routing) so that network
6748  * connectivity works ok. This is only done for IPv4 networks as IPv6
6749  * does not have rp_filter knob.
6750  */
6751 static int connected_networks_count;
6752 static int original_rp_filter;
6753
6754 static void service_rp_filter(struct connman_service *service,
6755                                 bool connected)
6756 {
6757         enum connman_ipconfig_method method;
6758
6759         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
6760
6761         switch (method) {
6762         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
6763         case CONNMAN_IPCONFIG_METHOD_OFF:
6764         case CONNMAN_IPCONFIG_METHOD_AUTO:
6765                 return;
6766         case CONNMAN_IPCONFIG_METHOD_FIXED:
6767         case CONNMAN_IPCONFIG_METHOD_MANUAL:
6768         case CONNMAN_IPCONFIG_METHOD_DHCP:
6769                 break;
6770         }
6771
6772         if (connected) {
6773                 if (connected_networks_count == 1) {
6774                         int filter_value;
6775                         filter_value = __connman_ipconfig_set_rp_filter();
6776                         if (filter_value < 0)
6777                                 return;
6778
6779                         original_rp_filter = filter_value;
6780                 }
6781                 connected_networks_count++;
6782
6783         } else {
6784                 if (connected_networks_count == 2)
6785                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
6786
6787                 connected_networks_count--;
6788                 if (connected_networks_count < 0)
6789                         connected_networks_count = 0;
6790         }
6791
6792         DBG("%s %s ipconfig %p method %d count %d filter %d",
6793                 connected ? "connected" : "disconnected", service->identifier,
6794                 service->ipconfig_ipv4, method,
6795                 connected_networks_count, original_rp_filter);
6796 }
6797
6798 static gboolean redo_wispr(gpointer user_data)
6799 {
6800         struct connman_service *service = user_data;
6801         int refcount = service->refcount - 1;
6802
6803         connman_service_unref(service);
6804         if (refcount == 0) {
6805                 DBG("Service %p already removed", service);
6806                 return FALSE;
6807         }
6808
6809         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
6810
6811         return FALSE;
6812 }
6813
6814 int __connman_service_online_check_failed(struct connman_service *service,
6815                                         enum connman_ipconfig_type type)
6816 {
6817         DBG("service %p type %d count %d", service, type,
6818                                                 service->online_check_count);
6819
6820         /* currently we only retry IPv6 stuff */
6821         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
6822                         service->online_check_count != 1) {
6823                 connman_warn("Online check failed for %p %s", service,
6824                         service->name);
6825                 return 0;
6826         }
6827
6828         service->online_check_count = 0;
6829
6830         /*
6831          * We set the timeout to 1 sec so that we have a chance to get
6832          * necessary IPv6 router advertisement messages that might have
6833          * DNS data etc.
6834          */
6835         g_timeout_add_seconds(1, redo_wispr, connman_service_ref(service));
6836
6837         return EAGAIN;
6838 }
6839
6840 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
6841                                         enum connman_service_state new_state,
6842                                         enum connman_ipconfig_type type)
6843 {
6844         struct connman_ipconfig *ipconfig = NULL;
6845         enum connman_service_state old_state;
6846         enum connman_ipconfig_method method;
6847
6848         if (!service)
6849                 return -EINVAL;
6850
6851         switch (type) {
6852         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
6853         case CONNMAN_IPCONFIG_TYPE_ALL:
6854                 return -EINVAL;
6855
6856         case CONNMAN_IPCONFIG_TYPE_IPV4:
6857                 old_state = service->state_ipv4;
6858                 ipconfig = service->ipconfig_ipv4;
6859
6860                 break;
6861
6862         case CONNMAN_IPCONFIG_TYPE_IPV6:
6863                 old_state = service->state_ipv6;
6864                 ipconfig = service->ipconfig_ipv6;
6865
6866                 break;
6867         }
6868
6869         if (!ipconfig)
6870                 return -EINVAL;
6871
6872         /* Any change? */
6873         if (old_state == new_state)
6874                 return -EALREADY;
6875
6876 #if defined TIZEN_EXT
6877         __sync_synchronize();
6878         if (service->user_pdn_connection_refcount > 0 &&
6879                         service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
6880                 if (new_state == CONNMAN_SERVICE_STATE_FAILURE ||
6881                                 new_state == CONNMAN_SERVICE_STATE_DISCONNECT ||
6882                                 new_state == CONNMAN_SERVICE_STATE_IDLE) {
6883                         service->user_pdn_connection_refcount = 0;
6884                         __sync_synchronize();
6885                 }
6886 #endif
6887
6888         DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
6889                 service, service ? service->identifier : NULL,
6890                 old_state, state2string(old_state),
6891                 new_state, state2string(new_state),
6892                 type, __connman_ipconfig_type2string(type));
6893
6894         switch (new_state) {
6895         case CONNMAN_SERVICE_STATE_UNKNOWN:
6896         case CONNMAN_SERVICE_STATE_IDLE:
6897         case CONNMAN_SERVICE_STATE_ASSOCIATION:
6898                 break;
6899         case CONNMAN_SERVICE_STATE_CONFIGURATION:
6900                 __connman_ipconfig_enable(ipconfig);
6901                 break;
6902         case CONNMAN_SERVICE_STATE_READY:
6903 #if defined TIZEN_EXT
6904                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
6905                                 __connman_service_is_internet_profile(service) != TRUE) {
6906                         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6907                                 service_rp_filter(service, TRUE);
6908
6909                         break;
6910                 }
6911 #endif
6912                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
6913 #if !defined TIZEN_EXT
6914                         check_proxy_setup(service);
6915 #endif
6916                         service_rp_filter(service, true);
6917                 } else {
6918                         service->online_check_count = 1;
6919                         __connman_wispr_start(service, type);
6920                 }
6921                 break;
6922         case CONNMAN_SERVICE_STATE_ONLINE:
6923                 break;
6924         case CONNMAN_SERVICE_STATE_DISCONNECT:
6925                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
6926                         return -EINVAL;
6927
6928                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6929                         service_rp_filter(service, false);
6930
6931                 break;
6932         case CONNMAN_SERVICE_STATE_FAILURE:
6933                 break;
6934         }
6935
6936         /* Keep that state, but if the ipconfig method is OFF, then we set
6937            the state to IDLE so that it will not affect the combined state
6938            in the future.
6939          */
6940         method = __connman_ipconfig_get_method(ipconfig);
6941         switch (method) {
6942         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
6943         case CONNMAN_IPCONFIG_METHOD_OFF:
6944                 new_state = CONNMAN_SERVICE_STATE_IDLE;
6945                 break;
6946
6947         case CONNMAN_IPCONFIG_METHOD_FIXED:
6948         case CONNMAN_IPCONFIG_METHOD_MANUAL:
6949         case CONNMAN_IPCONFIG_METHOD_DHCP:
6950         case CONNMAN_IPCONFIG_METHOD_AUTO:
6951                 break;
6952
6953         }
6954
6955         if (is_connected_state(service, old_state) &&
6956                         !is_connected_state(service, new_state))
6957                 nameserver_remove_all(service);
6958
6959         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
6960                 service->state_ipv4 = new_state;
6961         else
6962                 service->state_ipv6 = new_state;
6963
6964         if (!is_connected_state(service, old_state) &&
6965                         is_connected_state(service, new_state))
6966                 nameserver_add_all(service);
6967
6968 #if defined TIZEN_EXT
6969         int ret = service_indicate_state(service);
6970         /*Sent the Ready changed signal again in case IPv4 IP set
6971           after IPv6 IP set*/
6972
6973         if(ret == -EALREADY && type == CONNMAN_IPCONFIG_TYPE_IPV4
6974                         && new_state == CONNMAN_SERVICE_STATE_READY) {
6975                 DBG("Notify IPv4 state new/old %d/%d", new_state,old_state);
6976                 state_changed(service);
6977         }
6978
6979         return ret;
6980 #endif
6981         return service_indicate_state(service);
6982 }
6983
6984 static bool prepare_network(struct connman_service *service)
6985 {
6986         enum connman_network_type type;
6987         unsigned int ssid_len;
6988
6989         type = connman_network_get_type(service->network);
6990
6991         switch (type) {
6992         case CONNMAN_NETWORK_TYPE_UNKNOWN:
6993         case CONNMAN_NETWORK_TYPE_VENDOR:
6994                 return false;
6995         case CONNMAN_NETWORK_TYPE_WIFI:
6996                 if (!connman_network_get_blob(service->network, "WiFi.SSID",
6997                                                 &ssid_len))
6998                         return false;
6999
7000                 if (service->passphrase)
7001                         connman_network_set_string(service->network,
7002                                 "WiFi.Passphrase", service->passphrase);
7003                 break;
7004         case CONNMAN_NETWORK_TYPE_ETHERNET:
7005         case CONNMAN_NETWORK_TYPE_GADGET:
7006         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
7007         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
7008         case CONNMAN_NETWORK_TYPE_CELLULAR:
7009                 break;
7010         }
7011
7012         return true;
7013 }
7014
7015 static void prepare_8021x(struct connman_service *service)
7016 {
7017         if (service->eap)
7018                 connman_network_set_string(service->network, "WiFi.EAP",
7019                                                                 service->eap);
7020
7021         if (service->identity)
7022                 connman_network_set_string(service->network, "WiFi.Identity",
7023                                                         service->identity);
7024
7025         if (service->ca_cert_file)
7026                 connman_network_set_string(service->network, "WiFi.CACertFile",
7027                                                         service->ca_cert_file);
7028
7029         if (service->client_cert_file)
7030                 connman_network_set_string(service->network,
7031                                                 "WiFi.ClientCertFile",
7032                                                 service->client_cert_file);
7033
7034         if (service->private_key_file)
7035                 connman_network_set_string(service->network,
7036                                                 "WiFi.PrivateKeyFile",
7037                                                 service->private_key_file);
7038
7039         if (service->private_key_passphrase)
7040                 connman_network_set_string(service->network,
7041                                         "WiFi.PrivateKeyPassphrase",
7042                                         service->private_key_passphrase);
7043
7044         if (service->phase2)
7045                 connman_network_set_string(service->network, "WiFi.Phase2",
7046                                                         service->phase2);
7047 }
7048
7049 static int service_connect(struct connman_service *service)
7050 {
7051         int err;
7052
7053         if (service->hidden)
7054                 return -EPERM;
7055
7056 #if defined TIZEN_EXT
7057         GList *list;
7058         int index;
7059
7060         index = __connman_service_get_index(service);
7061
7062         for (list = service_list; list; list = list->next) {
7063                 struct connman_service *temp = list->data;
7064
7065                 if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7066                         break;
7067
7068                 if (!is_connecting(temp) && !is_connected(temp))
7069                         break;
7070
7071                 if (service == temp)
7072                         continue;
7073
7074                 if (service->type != temp->type)
7075                         continue;
7076
7077                 if (__connman_service_get_index(temp) == index &&
7078                                 __connman_service_disconnect(temp) == -EINPROGRESS)
7079                         return -EINPROGRESS;
7080         }
7081 #endif
7082
7083         switch (service->type) {
7084         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7085         case CONNMAN_SERVICE_TYPE_SYSTEM:
7086         case CONNMAN_SERVICE_TYPE_GPS:
7087         case CONNMAN_SERVICE_TYPE_P2P:
7088                 return -EINVAL;
7089         case CONNMAN_SERVICE_TYPE_ETHERNET:
7090         case CONNMAN_SERVICE_TYPE_GADGET:
7091         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7092         case CONNMAN_SERVICE_TYPE_CELLULAR:
7093         case CONNMAN_SERVICE_TYPE_VPN:
7094                 break;
7095         case CONNMAN_SERVICE_TYPE_WIFI:
7096                 switch (service->security) {
7097                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7098                 case CONNMAN_SERVICE_SECURITY_NONE:
7099                         break;
7100                 case CONNMAN_SERVICE_SECURITY_WEP:
7101                 case CONNMAN_SERVICE_SECURITY_PSK:
7102                 case CONNMAN_SERVICE_SECURITY_WPA:
7103                 case CONNMAN_SERVICE_SECURITY_RSN:
7104                         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7105                                 return -ENOKEY;
7106
7107                         if (service->request_passphrase_input) {
7108                                 DBG("Now try to connect other user's favorite service");
7109                                 service->request_passphrase_input = false;
7110                                 return -ENOKEY;
7111                         } else if (!service->passphrase) {
7112                                 if (!service->network)
7113                                         return -EOPNOTSUPP;
7114
7115                                 if (!service->wps ||
7116                                         !connman_network_get_bool(service->network, "WiFi.UseWPS"))
7117                                         return -ENOKEY;
7118                         }
7119                         break;
7120
7121                 case CONNMAN_SERVICE_SECURITY_8021X:
7122                         if (!service->eap)
7123                                 return -EINVAL;
7124
7125 #if defined TIZEN_EXT
7126                         /*
7127                          * never request credentials if using EAP-TLS, EAP-SIM
7128                          * or EAP-AKA (EAP-TLS, EAP-SIM and EAP-AKA networks
7129                          * need to be fully provisioned)
7130                          */
7131                         if (g_str_equal(service->eap, "tls") ||
7132                                 g_str_equal(service->eap, "sim") ||
7133                                 g_str_equal(service->eap, "aka"))
7134                                 break;
7135 #else
7136                         /*
7137                          * never request credentials if using EAP-TLS
7138                          * (EAP-TLS networks need to be fully provisioned)
7139                          */
7140                         if (g_str_equal(service->eap, "tls"))
7141                                 break;
7142 #endif
7143                         /*
7144                          * Return -ENOKEY if either identity or passphrase is
7145                          * missing. Agent provided credentials can be used as
7146                          * fallback if needed.
7147                          */
7148                         if (((!service->identity &&
7149                                         !service->agent_identity) ||
7150                                         !service->passphrase) ||
7151                                         service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
7152                                 return -ENOKEY;
7153
7154                         break;
7155                 }
7156                 break;
7157         }
7158
7159         if (service->network) {
7160                 if (!prepare_network(service))
7161                         return -EINVAL;
7162
7163                 switch (service->security) {
7164                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
7165                 case CONNMAN_SERVICE_SECURITY_NONE:
7166                 case CONNMAN_SERVICE_SECURITY_WEP:
7167                 case CONNMAN_SERVICE_SECURITY_PSK:
7168                 case CONNMAN_SERVICE_SECURITY_WPA:
7169                 case CONNMAN_SERVICE_SECURITY_RSN:
7170                         break;
7171                 case CONNMAN_SERVICE_SECURITY_8021X:
7172                         prepare_8021x(service);
7173                         break;
7174                 }
7175
7176                 if (__connman_stats_service_register(service) == 0) {
7177                         __connman_stats_get(service, false,
7178                                                 &service->stats.data);
7179                         __connman_stats_get(service, true,
7180                                                 &service->stats_roaming.data);
7181                 }
7182
7183                 if (service->ipconfig_ipv4)
7184                         __connman_ipconfig_enable(service->ipconfig_ipv4);
7185                 if (service->ipconfig_ipv6)
7186                         __connman_ipconfig_enable(service->ipconfig_ipv6);
7187
7188                 err = __connman_network_connect(service->network);
7189         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7190                                         service->provider)
7191                 err = __connman_provider_connect(service->provider);
7192         else
7193                 return -EOPNOTSUPP;
7194
7195         if (err < 0) {
7196                 if (err != -EINPROGRESS) {
7197                         __connman_ipconfig_disable(service->ipconfig_ipv4);
7198                         __connman_ipconfig_disable(service->ipconfig_ipv6);
7199                         __connman_stats_service_unregister(service);
7200                 }
7201         }
7202
7203         return err;
7204 }
7205
7206 int __connman_service_connect(struct connman_service *service,
7207                         enum connman_service_connect_reason reason)
7208 {
7209         int err;
7210
7211         DBG("service %p state %s connect reason %s -> %s",
7212                 service, state2string(service->state),
7213                 reason2string(service->connect_reason),
7214                 reason2string(reason));
7215
7216         if (is_connected(service))
7217                 return -EISCONN;
7218
7219         if (is_connecting(service))
7220                 return -EALREADY;
7221
7222         switch (service->type) {
7223         case CONNMAN_SERVICE_TYPE_UNKNOWN:
7224         case CONNMAN_SERVICE_TYPE_SYSTEM:
7225         case CONNMAN_SERVICE_TYPE_GPS:
7226         case CONNMAN_SERVICE_TYPE_P2P:
7227                 return -EINVAL;
7228
7229         case CONNMAN_SERVICE_TYPE_ETHERNET:
7230         case CONNMAN_SERVICE_TYPE_GADGET:
7231         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
7232         case CONNMAN_SERVICE_TYPE_CELLULAR:
7233         case CONNMAN_SERVICE_TYPE_VPN:
7234         case CONNMAN_SERVICE_TYPE_WIFI:
7235                 break;
7236         }
7237
7238         if (!is_ipconfig_usable(service))
7239                 return -ENOLINK;
7240
7241         __connman_service_clear_error(service);
7242
7243         err = service_connect(service);
7244
7245         service->connect_reason = reason;
7246         if (err >= 0)
7247                 return 0;
7248
7249         if (err == -EINPROGRESS) {
7250                 if (service->timeout == 0)
7251                         service->timeout = g_timeout_add_seconds(
7252                                 CONNECT_TIMEOUT, connect_timeout, service);
7253
7254                 return -EINPROGRESS;
7255         }
7256
7257         if (service->network)
7258                 __connman_network_disconnect(service->network);
7259         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7260                                 service->provider)
7261                         connman_provider_disconnect(service->provider);
7262
7263         if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER) {
7264                 if (err == -ENOKEY || err == -EPERM) {
7265                         DBusMessage *pending = NULL;
7266
7267                         /*
7268                          * We steal the reply here. The idea is that the
7269                          * connecting client will see the connection status
7270                          * after the real hidden network is connected or
7271                          * connection failed.
7272                          */
7273                         if (service->hidden) {
7274                                 pending = service->pending;
7275                                 service->pending = NULL;
7276                         }
7277
7278                         err = __connman_agent_request_passphrase_input(service,
7279                                         request_input_cb,
7280                                         get_dbus_sender(service),
7281                                         pending);
7282                         if (service->hidden && err != -EINPROGRESS)
7283                                 service->pending = pending;
7284
7285                         return err;
7286                 }
7287                 reply_pending(service, -err);
7288         }
7289
7290         return err;
7291 }
7292
7293 int __connman_service_disconnect(struct connman_service *service)
7294 {
7295         int err;
7296
7297         DBG("service %p", service);
7298
7299         service->connect_reason = CONNMAN_SERVICE_CONNECT_REASON_NONE;
7300         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
7301
7302         connman_agent_cancel(service);
7303
7304         reply_pending(service, ECONNABORTED);
7305
7306         if (service->network) {
7307                 err = __connman_network_disconnect(service->network);
7308         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7309                                         service->provider)
7310                 err = connman_provider_disconnect(service->provider);
7311         else
7312                 return -EOPNOTSUPP;
7313
7314         if (err < 0 && err != -EINPROGRESS)
7315                 return err;
7316
7317         __connman_6to4_remove(service->ipconfig_ipv4);
7318
7319         if (service->ipconfig_ipv4)
7320                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
7321                                                         NULL);
7322         else
7323                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
7324                                                         NULL);
7325
7326 #if defined TIZEN_EXT
7327         /**
7328           * Skip the functions If there is any connected profiles
7329           * that use same interface
7330           */
7331         if (service->type != CONNMAN_SERVICE_TYPE_CELLULAR ||
7332                 __connman_service_get_connected_count_of_iface(service) <= 0) {
7333 #endif
7334         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
7335         settings_changed(service, service->ipconfig_ipv4);
7336
7337         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
7338         settings_changed(service, service->ipconfig_ipv6);
7339
7340         __connman_ipconfig_disable(service->ipconfig_ipv4);
7341         __connman_ipconfig_disable(service->ipconfig_ipv6);
7342 #if defined TIZEN_EXT
7343         }
7344 #endif
7345
7346         __connman_stats_service_unregister(service);
7347
7348         return err;
7349 }
7350
7351 int __connman_service_disconnect_all(void)
7352 {
7353         struct connman_service *service;
7354         GSList *services = NULL, *list;
7355         GList *iter;
7356
7357         DBG("");
7358
7359         for (iter = service_list; iter; iter = iter->next) {
7360                 service = iter->data;
7361
7362                 if (!is_connected(service))
7363                         break;
7364
7365                 services = g_slist_prepend(services, service);
7366         }
7367
7368         for (list = services; list; list = list->next) {
7369                 struct connman_service *service = list->data;
7370
7371                 service->ignore = true;
7372
7373                 __connman_service_disconnect(service);
7374         }
7375
7376         g_slist_free(services);
7377
7378         return 0;
7379 }
7380
7381 /**
7382  * lookup_by_identifier:
7383  * @identifier: service identifier
7384  *
7385  * Look up a service by identifier (reference count will not be increased)
7386  */
7387 static struct connman_service *lookup_by_identifier(const char *identifier)
7388 {
7389         return g_hash_table_lookup(service_hash, identifier);
7390 }
7391
7392 struct provision_user_data {
7393         const char *ident;
7394         int ret;
7395 };
7396
7397 static void provision_changed(gpointer value, gpointer user_data)
7398 {
7399         struct connman_service *service = value;
7400         struct provision_user_data *data = user_data;
7401         const char *path = data->ident;
7402         int ret;
7403
7404         ret = __connman_config_provision_service_ident(service, path,
7405                         service->config_file, service->config_entry);
7406         if (ret > 0)
7407                 data->ret = ret;
7408 }
7409
7410 int __connman_service_provision_changed(const char *ident)
7411 {
7412         struct provision_user_data data = {
7413                 .ident = ident,
7414                 .ret = 0
7415         };
7416
7417         g_list_foreach(service_list, provision_changed, (void *)&data);
7418
7419         /*
7420          * Because the provision_changed() might have set some services
7421          * as favorite, we must sort the sequence now.
7422          */
7423         if (services_dirty) {
7424                 services_dirty = false;
7425
7426                 service_list_sort();
7427
7428                 __connman_connection_update_gateway();
7429         }
7430
7431         return data.ret;
7432 }
7433
7434 void __connman_service_set_config(struct connman_service *service,
7435                                 const char *file_id, const char *entry)
7436 {
7437         if (!service)
7438                 return;
7439
7440         g_free(service->config_file);
7441         service->config_file = g_strdup(file_id);
7442
7443         g_free(service->config_entry);
7444         service->config_entry = g_strdup(entry);
7445 }
7446
7447 /**
7448  * __connman_service_get:
7449  * @identifier: service identifier
7450  *
7451  * Look up a service by identifier or create a new one if not found
7452  */
7453 static struct connman_service *service_get(const char *identifier)
7454 {
7455         struct connman_service *service;
7456
7457         service = g_hash_table_lookup(service_hash, identifier);
7458         if (service) {
7459                 connman_service_ref(service);
7460                 return service;
7461         }
7462
7463         service = connman_service_create();
7464         if (!service)
7465                 return NULL;
7466
7467         DBG("service %p", service);
7468
7469         service->identifier = g_strdup(identifier);
7470
7471         service_list = g_list_insert_sorted(service_list, service,
7472                                                 service_compare);
7473
7474         g_hash_table_insert(service_hash, service->identifier, service);
7475
7476         return service;
7477 }
7478
7479 static int service_register(struct connman_service *service)
7480 {
7481         DBG("service %p", service);
7482
7483         if (service->path)
7484                 return -EALREADY;
7485
7486         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
7487                                                 service->identifier);
7488
7489         DBG("path %s", service->path);
7490
7491         if (__connman_config_provision_service(service) < 0)
7492                 service_load(service);
7493
7494         g_dbus_register_interface(connection, service->path,
7495                                         CONNMAN_SERVICE_INTERFACE,
7496                                         service_methods, service_signals,
7497                                                         NULL, service, NULL);
7498
7499         service_list_sort();
7500
7501         __connman_connection_update_gateway();
7502
7503         return 0;
7504 }
7505
7506 static void service_up(struct connman_ipconfig *ipconfig,
7507                 const char *ifname)
7508 {
7509         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7510
7511         DBG("%s up", ifname);
7512
7513         link_changed(service);
7514
7515         service->stats.valid = false;
7516         service->stats_roaming.valid = false;
7517 }
7518
7519 static void service_down(struct connman_ipconfig *ipconfig,
7520                         const char *ifname)
7521 {
7522         DBG("%s down", ifname);
7523 }
7524
7525 static void service_lower_up(struct connman_ipconfig *ipconfig,
7526                         const char *ifname)
7527 {
7528         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7529
7530         DBG("%s lower up", ifname);
7531
7532         stats_start(service);
7533 }
7534
7535 static void service_lower_down(struct connman_ipconfig *ipconfig,
7536                         const char *ifname)
7537 {
7538         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7539
7540         DBG("%s lower down", ifname);
7541
7542         if (!is_idle_state(service, service->state_ipv4))
7543                 __connman_ipconfig_disable(service->ipconfig_ipv4);
7544
7545         if (!is_idle_state(service, service->state_ipv6))
7546                 __connman_ipconfig_disable(service->ipconfig_ipv6);
7547
7548         stats_stop(service);
7549         service_save(service);
7550 }
7551
7552 static void service_ip_bound(struct connman_ipconfig *ipconfig,
7553                         const char *ifname)
7554 {
7555         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7556         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
7557         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
7558
7559         DBG("%s ip bound", ifname);
7560
7561         type = __connman_ipconfig_get_config_type(ipconfig);
7562         method = __connman_ipconfig_get_method(ipconfig);
7563
7564         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
7565                                                         type, method);
7566
7567         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
7568                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
7569                 __connman_service_ipconfig_indicate_state(service,
7570                                                 CONNMAN_SERVICE_STATE_READY,
7571                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7572
7573         settings_changed(service, ipconfig);
7574 }
7575
7576 static void service_ip_release(struct connman_ipconfig *ipconfig,
7577                         const char *ifname)
7578 {
7579         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7580         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
7581         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
7582
7583         DBG("%s ip release", ifname);
7584
7585         type = __connman_ipconfig_get_config_type(ipconfig);
7586         method = __connman_ipconfig_get_method(ipconfig);
7587
7588         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
7589                                                         type, method);
7590
7591         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
7592                         method == CONNMAN_IPCONFIG_METHOD_OFF)
7593                 __connman_service_ipconfig_indicate_state(service,
7594                                         CONNMAN_SERVICE_STATE_DISCONNECT,
7595                                         CONNMAN_IPCONFIG_TYPE_IPV6);
7596
7597         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
7598                         method == CONNMAN_IPCONFIG_METHOD_OFF)
7599                 __connman_service_ipconfig_indicate_state(service,
7600                                         CONNMAN_SERVICE_STATE_DISCONNECT,
7601                                         CONNMAN_IPCONFIG_TYPE_IPV4);
7602
7603         settings_changed(service, ipconfig);
7604 }
7605
7606 static void service_route_changed(struct connman_ipconfig *ipconfig,
7607                                 const char *ifname)
7608 {
7609         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
7610
7611         DBG("%s route changed", ifname);
7612
7613         settings_changed(service, ipconfig);
7614 }
7615
7616 static const struct connman_ipconfig_ops service_ops = {
7617         .up             = service_up,
7618         .down           = service_down,
7619         .lower_up       = service_lower_up,
7620         .lower_down     = service_lower_down,
7621         .ip_bound       = service_ip_bound,
7622         .ip_release     = service_ip_release,
7623         .route_set      = service_route_changed,
7624         .route_unset    = service_route_changed,
7625 };
7626
7627 static struct connman_ipconfig *create_ip4config(struct connman_service *service,
7628                 int index, enum connman_ipconfig_method method)
7629 {
7630         struct connman_ipconfig *ipconfig_ipv4;
7631
7632         ipconfig_ipv4 = __connman_ipconfig_create(index,
7633                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
7634         if (!ipconfig_ipv4)
7635                 return NULL;
7636
7637         __connman_ipconfig_set_method(ipconfig_ipv4, method);
7638
7639         __connman_ipconfig_set_data(ipconfig_ipv4, service);
7640
7641         __connman_ipconfig_set_ops(ipconfig_ipv4, &service_ops);
7642
7643         return ipconfig_ipv4;
7644 }
7645
7646 static struct connman_ipconfig *create_ip6config(struct connman_service *service,
7647                 int index)
7648 {
7649         struct connman_ipconfig *ipconfig_ipv6;
7650
7651         ipconfig_ipv6 = __connman_ipconfig_create(index,
7652                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
7653         if (!ipconfig_ipv6)
7654                 return NULL;
7655
7656         __connman_ipconfig_set_data(ipconfig_ipv6, service);
7657
7658         __connman_ipconfig_set_ops(ipconfig_ipv6, &service_ops);
7659
7660         return ipconfig_ipv6;
7661 }
7662
7663 void __connman_service_read_ip4config(struct connman_service *service)
7664 {
7665         GKeyFile *keyfile;
7666
7667         if (!service->ipconfig_ipv4)
7668                 return;
7669
7670         keyfile = connman_storage_load_service(service->identifier);
7671         if (!keyfile)
7672                 return;
7673
7674         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
7675                                 service->identifier, "IPv4.");
7676
7677         g_key_file_free(keyfile);
7678 }
7679
7680 void connman_service_create_ip4config(struct connman_service *service,
7681                                         int index)
7682 {
7683         DBG("ipv4 %p", service->ipconfig_ipv4);
7684
7685         if (service->ipconfig_ipv4)
7686                 return;
7687
7688         service->ipconfig_ipv4 = create_ip4config(service, index,
7689                         CONNMAN_IPCONFIG_METHOD_DHCP);
7690         __connman_service_read_ip4config(service);
7691 }
7692
7693 void __connman_service_read_ip6config(struct connman_service *service)
7694 {
7695         GKeyFile *keyfile;
7696
7697         if (!service->ipconfig_ipv6)
7698                 return;
7699
7700         keyfile = connman_storage_load_service(service->identifier);
7701         if (!keyfile)
7702                 return;
7703
7704         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
7705                                 service->identifier, "IPv6.");
7706
7707         g_key_file_free(keyfile);
7708 }
7709
7710 void connman_service_create_ip6config(struct connman_service *service,
7711                                                                 int index)
7712 {
7713         DBG("ipv6 %p", service->ipconfig_ipv6);
7714
7715         if (service->ipconfig_ipv6)
7716                 return;
7717
7718         service->ipconfig_ipv6 = create_ip6config(service, index);
7719
7720         __connman_service_read_ip6config(service);
7721 }
7722
7723 /**
7724  * connman_service_lookup_from_network:
7725  * @network: network structure
7726  *
7727  * Look up a service by network (reference count will not be increased)
7728  */
7729 struct connman_service *connman_service_lookup_from_network(struct connman_network *network)
7730 {
7731         struct connman_service *service;
7732         const char *ident, *group;
7733         char *name;
7734
7735         if (!network)
7736                 return NULL;
7737
7738         ident = __connman_network_get_ident(network);
7739         if (!ident)
7740                 return NULL;
7741
7742         group = connman_network_get_group(network);
7743         if (!group)
7744                 return NULL;
7745
7746         name = g_strdup_printf("%s_%s_%s",
7747                         __connman_network_get_type(network), ident, group);
7748         service = lookup_by_identifier(name);
7749         g_free(name);
7750
7751         return service;
7752 }
7753
7754 struct connman_service *__connman_service_lookup_from_index(int index)
7755 {
7756         struct connman_service *service;
7757         GList *list;
7758
7759         for (list = service_list; list; list = list->next) {
7760                 service = list->data;
7761
7762                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
7763                                                         == index)
7764                         return service;
7765
7766                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
7767                                                         == index)
7768                         return service;
7769         }
7770
7771         return NULL;
7772 }
7773
7774 struct connman_service *__connman_service_lookup_from_ident(const char *identifier)
7775 {
7776         return lookup_by_identifier(identifier);
7777 }
7778
7779 const char *__connman_service_get_ident(struct connman_service *service)
7780 {
7781         return service->identifier;
7782 }
7783
7784 const char *__connman_service_get_path(struct connman_service *service)
7785 {
7786         return service->path;
7787 }
7788
7789 const char *__connman_service_get_name(struct connman_service *service)
7790 {
7791         return service->name;
7792 }
7793
7794 enum connman_service_state __connman_service_get_state(struct connman_service *service)
7795 {
7796         return service->state;
7797 }
7798
7799 unsigned int __connman_service_get_order(struct connman_service *service)
7800 {
7801         unsigned int order = 0;
7802
7803         if (!service)
7804                 return 0;
7805
7806         service->order = 0;
7807
7808         if (!service->favorite)
7809                 return 0;
7810
7811 #if defined TIZEN_EXT
7812         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7813                         service->do_split_routing == FALSE)
7814                 order = 10;
7815         else if (service->type == CONNMAN_SERVICE_TYPE_WIFI) {
7816                 if (service->order < 5)
7817                         order = 5;
7818         } else if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
7819                 order = 4;
7820         else if (service->type == CONNMAN_SERVICE_TYPE_BLUETOOTH)
7821                 order = 3;
7822         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7823                         __connman_service_is_internet_profile(service) == TRUE)
7824                 order = 1;
7825         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR &&
7826                         __connman_service_is_tethering_profile(service) == TRUE)
7827                 order = 0;
7828         else if (service->type == CONNMAN_SERVICE_TYPE_CELLULAR)
7829                 order = 0;
7830         else
7831                 order = 2;
7832 #else
7833         if (service == service_list->data)
7834                 order = 1;
7835
7836         if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
7837                         !service->do_split_routing) {
7838                 service->order = 10;
7839                 order = 10;
7840         }
7841 #endif
7842         DBG("service %p name %s order %d split %d", service, service->name,
7843                 order, service->do_split_routing);
7844
7845         return order;
7846 }
7847
7848 void __connman_service_update_ordering(void)
7849 {
7850         if (service_list && service_list->next)
7851                 service_list = g_list_sort(service_list, service_compare);
7852 }
7853
7854 static enum connman_service_type convert_network_type(struct connman_network *network)
7855 {
7856         enum connman_network_type type = connman_network_get_type(network);
7857
7858         switch (type) {
7859         case CONNMAN_NETWORK_TYPE_UNKNOWN:
7860         case CONNMAN_NETWORK_TYPE_VENDOR:
7861                 break;
7862         case CONNMAN_NETWORK_TYPE_ETHERNET:
7863                 return CONNMAN_SERVICE_TYPE_ETHERNET;
7864         case CONNMAN_NETWORK_TYPE_WIFI:
7865                 return CONNMAN_SERVICE_TYPE_WIFI;
7866         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
7867         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
7868                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
7869         case CONNMAN_NETWORK_TYPE_CELLULAR:
7870                 return CONNMAN_SERVICE_TYPE_CELLULAR;
7871         case CONNMAN_NETWORK_TYPE_GADGET:
7872                 return CONNMAN_SERVICE_TYPE_GADGET;
7873         }
7874
7875         return CONNMAN_SERVICE_TYPE_UNKNOWN;
7876 }
7877
7878 static enum connman_service_security convert_wifi_security(const char *security)
7879 {
7880         if (!security)
7881                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
7882         else if (g_str_equal(security, "none"))
7883                 return CONNMAN_SERVICE_SECURITY_NONE;
7884         else if (g_str_equal(security, "wep"))
7885                 return CONNMAN_SERVICE_SECURITY_WEP;
7886         else if (g_str_equal(security, "psk"))
7887                 return CONNMAN_SERVICE_SECURITY_PSK;
7888         else if (g_str_equal(security, "ieee8021x"))
7889                 return CONNMAN_SERVICE_SECURITY_8021X;
7890         else if (g_str_equal(security, "wpa"))
7891                 return CONNMAN_SERVICE_SECURITY_WPA;
7892         else if (g_str_equal(security, "rsn"))
7893                 return CONNMAN_SERVICE_SECURITY_RSN;
7894 #if defined TIZEN_EXT
7895         else if (g_str_equal(security, "ft_psk") == TRUE)
7896                 return CONNMAN_SERVICE_SECURITY_PSK;
7897         else if (g_str_equal(security, "ft_ieee8021x") == TRUE)
7898                 return CONNMAN_SERVICE_SECURITY_8021X;
7899 #endif
7900         else
7901                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
7902 }
7903
7904 static void update_from_network(struct connman_service *service,
7905                                         struct connman_network *network)
7906 {
7907         uint8_t strength = service->strength;
7908         const char *str;
7909
7910         DBG("service %p network %p", service, network);
7911
7912         if (is_connected(service))
7913                 return;
7914
7915         if (is_connecting(service))
7916                 return;
7917
7918         str = connman_network_get_string(network, "Name");
7919         if (str) {
7920                 g_free(service->name);
7921                 service->name = g_strdup(str);
7922                 service->hidden = false;
7923         } else {
7924                 g_free(service->name);
7925                 service->name = NULL;
7926                 service->hidden = true;
7927         }
7928
7929         service->strength = connman_network_get_strength(network);
7930         service->roaming = connman_network_get_bool(network, "Roaming");
7931
7932         if (service->strength == 0) {
7933                 /*
7934                  * Filter out 0-values; it's unclear what they mean
7935                  * and they cause anomalous sorting of the priority list.
7936                  */
7937                 service->strength = strength;
7938         }
7939
7940         str = connman_network_get_string(network, "WiFi.Security");
7941         service->security = convert_wifi_security(str);
7942
7943         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
7944                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
7945
7946         if (service->strength > strength && service->network) {
7947                 connman_network_unref(service->network);
7948                 service->network = connman_network_ref(network);
7949
7950                 strength_changed(service);
7951         }
7952
7953         if (!service->network)
7954                 service->network = connman_network_ref(network);
7955
7956         service_list_sort();
7957 }
7958
7959 /**
7960  * __connman_service_create_from_network:
7961  * @network: network structure
7962  *
7963  * Look up service by network and if not found, create one
7964  */
7965 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
7966 {
7967         struct connman_service *service;
7968         struct connman_device *device;
7969         const char *ident, *group;
7970         char *name;
7971         unsigned int *auto_connect_types;
7972         int i, index;
7973
7974         DBG("network %p", network);
7975
7976         if (!network)
7977                 return NULL;
7978
7979         ident = __connman_network_get_ident(network);
7980         if (!ident)
7981                 return NULL;
7982
7983         group = connman_network_get_group(network);
7984         if (!group)
7985                 return NULL;
7986
7987         name = g_strdup_printf("%s_%s_%s",
7988                         __connman_network_get_type(network), ident, group);
7989         service = service_get(name);
7990         g_free(name);
7991
7992         if (!service)
7993                 return NULL;
7994
7995         if (__connman_network_get_weakness(network))
7996                 return service;
7997
7998         if (service->path) {
7999                 update_from_network(service, network);
8000                 __connman_connection_update_gateway();
8001                 return service;
8002         }
8003
8004         service->type = convert_network_type(network);
8005
8006         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
8007         service->autoconnect = false;
8008         for (i = 0; auto_connect_types &&
8009                      auto_connect_types[i] != 0; i++) {
8010                 if (service->type == auto_connect_types[i]) {
8011                         service->autoconnect = true;
8012                         break;
8013                 }
8014         }
8015
8016         switch (service->type) {
8017         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8018         case CONNMAN_SERVICE_TYPE_SYSTEM:
8019         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8020         case CONNMAN_SERVICE_TYPE_GPS:
8021         case CONNMAN_SERVICE_TYPE_VPN:
8022         case CONNMAN_SERVICE_TYPE_GADGET:
8023         case CONNMAN_SERVICE_TYPE_WIFI:
8024         case CONNMAN_SERVICE_TYPE_CELLULAR:
8025         case CONNMAN_SERVICE_TYPE_P2P:
8026                 break;
8027         case CONNMAN_SERVICE_TYPE_ETHERNET:
8028                 service->favorite = true;
8029                 break;
8030         }
8031
8032         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8033         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8034
8035         update_from_network(service, network);
8036
8037         index = connman_network_get_index(network);
8038
8039         if (!service->ipconfig_ipv4)
8040                 service->ipconfig_ipv4 = create_ip4config(service, index,
8041                                 CONNMAN_IPCONFIG_METHOD_DHCP);
8042
8043         if (!service->ipconfig_ipv6)
8044                 service->ipconfig_ipv6 = create_ip6config(service, index);
8045
8046         service_register(service);
8047
8048         if (service->favorite) {
8049                 device = connman_network_get_device(service->network);
8050                 if (device && !connman_device_get_scanning(device)) {
8051
8052                         switch (service->type) {
8053                         case CONNMAN_SERVICE_TYPE_UNKNOWN:
8054                         case CONNMAN_SERVICE_TYPE_SYSTEM:
8055                         case CONNMAN_SERVICE_TYPE_P2P:
8056                                 break;
8057
8058                         case CONNMAN_SERVICE_TYPE_GADGET:
8059                         case CONNMAN_SERVICE_TYPE_ETHERNET:
8060                                 if (service->autoconnect) {
8061                                         __connman_service_connect(service,
8062                                                 CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8063                                         break;
8064                                 }
8065
8066                                 /* fall through */
8067                         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
8068                         case CONNMAN_SERVICE_TYPE_GPS:
8069                         case CONNMAN_SERVICE_TYPE_VPN:
8070                         case CONNMAN_SERVICE_TYPE_WIFI:
8071                         case CONNMAN_SERVICE_TYPE_CELLULAR:
8072                                 __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
8073                                 break;
8074                         }
8075                 }
8076
8077 #if defined TIZEN_EXT
8078                 /* TIZEN synchronizes below information when the service creates */
8079                 if (service->eap != NULL)
8080                         connman_network_set_string(service->network, "WiFi.EAP",
8081                                                                 service->eap);
8082                 if (service->identity != NULL)
8083                         connman_network_set_string(service->network, "WiFi.Identity",
8084                                                                 service->identity);
8085                 if (service->phase2 != NULL)
8086                         connman_network_set_string(service->network, "WiFi.Phase2",
8087                                                                 service->phase2);
8088 #endif
8089         }
8090
8091         __connman_notifier_service_add(service, service->name);
8092         service_schedule_added(service);
8093
8094         return service;
8095 }
8096
8097 void __connman_service_update_from_network(struct connman_network *network)
8098 {
8099         bool need_sort = false;
8100         struct connman_service *service;
8101         uint8_t strength;
8102         bool roaming;
8103         const char *name;
8104         bool stats_enable;
8105
8106         service = connman_service_lookup_from_network(network);
8107         if (!service)
8108                 return;
8109
8110         if (!service->network)
8111                 return;
8112
8113 #if defined TIZEN_EXT
8114         if (service->storage_reload) {
8115                 service_load(service);
8116                 __connman_service_set_storage_reload(service, false);
8117         }
8118 #endif
8119
8120         name = connman_network_get_string(service->network, "Name");
8121         if (g_strcmp0(service->name, name) != 0) {
8122                 g_free(service->name);
8123                 service->name = g_strdup(name);
8124
8125                 if (allow_property_changed(service))
8126                         connman_dbus_property_changed_basic(service->path,
8127                                         CONNMAN_SERVICE_INTERFACE, "Name",
8128                                         DBUS_TYPE_STRING, &service->name);
8129         }
8130
8131         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
8132                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
8133
8134         strength = connman_network_get_strength(service->network);
8135         if (strength == service->strength)
8136                 goto roaming;
8137
8138         service->strength = strength;
8139         need_sort = true;
8140
8141         strength_changed(service);
8142
8143 roaming:
8144         roaming = connman_network_get_bool(service->network, "Roaming");
8145         if (roaming == service->roaming)
8146                 goto sorting;
8147
8148         stats_enable = stats_enabled(service);
8149         if (stats_enable)
8150                 stats_stop(service);
8151
8152         service->roaming = roaming;
8153         need_sort = true;
8154
8155         if (stats_enable)
8156                 stats_start(service);
8157
8158         roaming_changed(service);
8159
8160 sorting:
8161         if (need_sort) {
8162                 service_list_sort();
8163         }
8164 }
8165
8166 void __connman_service_remove_from_network(struct connman_network *network)
8167 {
8168         struct connman_service *service;
8169
8170         service = connman_service_lookup_from_network(network);
8171
8172         DBG("network %p service %p", network, service);
8173
8174         if (!service)
8175                 return;
8176
8177         service->ignore = true;
8178
8179         __connman_connection_gateway_remove(service,
8180                                         CONNMAN_IPCONFIG_TYPE_ALL);
8181
8182         connman_service_unref(service);
8183 }
8184
8185 /**
8186  * __connman_service_create_from_provider:
8187  * @provider: provider structure
8188  *
8189  * Look up service by provider and if not found, create one
8190  */
8191 struct connman_service *
8192 __connman_service_create_from_provider(struct connman_provider *provider)
8193 {
8194         struct connman_service *service;
8195         const char *ident, *str;
8196         char *name;
8197         int index = connman_provider_get_index(provider);
8198
8199         DBG("provider %p", provider);
8200
8201         ident = __connman_provider_get_ident(provider);
8202         if (!ident)
8203                 return NULL;
8204
8205         name = g_strdup_printf("vpn_%s", ident);
8206         service = service_get(name);
8207         g_free(name);
8208
8209         if (!service)
8210                 return NULL;
8211
8212         service->type = CONNMAN_SERVICE_TYPE_VPN;
8213         service->provider = connman_provider_ref(provider);
8214         service->autoconnect = false;
8215         service->favorite = true;
8216
8217         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
8218         service->state = combine_state(service->state_ipv4, service->state_ipv6);
8219
8220         str = connman_provider_get_string(provider, "Name");
8221         if (str) {
8222                 g_free(service->name);
8223                 service->name = g_strdup(str);
8224                 service->hidden = false;
8225         } else {
8226                 g_free(service->name);
8227                 service->name = NULL;
8228                 service->hidden = true;
8229         }
8230
8231         service->strength = 0;
8232
8233         if (!service->ipconfig_ipv4)
8234                 service->ipconfig_ipv4 = create_ip4config(service, index,
8235                                 CONNMAN_IPCONFIG_METHOD_MANUAL);
8236
8237         if (!service->ipconfig_ipv6)
8238                 service->ipconfig_ipv6 = create_ip6config(service, index);
8239
8240         service_register(service);
8241
8242         __connman_notifier_service_add(service, service->name);
8243         service_schedule_added(service);
8244
8245         return service;
8246 }
8247
8248 static void remove_unprovisioned_services(void)
8249 {
8250         gchar **services;
8251         GKeyFile *keyfile, *configkeyfile;
8252         char *file, *section;
8253         int i = 0;
8254
8255         services = connman_storage_get_services();
8256         if (!services)
8257                 return;
8258
8259         for (; services[i]; i++) {
8260                 file = section = NULL;
8261                 keyfile = configkeyfile = NULL;
8262
8263                 keyfile = connman_storage_load_service(services[i]);
8264                 if (!keyfile)
8265                         continue;
8266
8267                 file = g_key_file_get_string(keyfile, services[i],
8268                                         "Config.file", NULL);
8269                 if (!file)
8270                         goto next;
8271
8272                 section = g_key_file_get_string(keyfile, services[i],
8273                                         "Config.ident", NULL);
8274                 if (!section)
8275                         goto next;
8276
8277                 configkeyfile = __connman_storage_load_config(file);
8278                 if (!configkeyfile) {
8279                         /*
8280                          * Config file is missing, remove the provisioned
8281                          * service.
8282                          */
8283                         __connman_storage_remove_service(services[i]);
8284                         goto next;
8285                 }
8286
8287                 if (!g_key_file_has_group(configkeyfile, section))
8288                         /*
8289                          * Config section is missing, remove the provisioned
8290                          * service.
8291                          */
8292                         __connman_storage_remove_service(services[i]);
8293
8294         next:
8295                 if (keyfile)
8296                         g_key_file_free(keyfile);
8297
8298                 if (configkeyfile)
8299                         g_key_file_free(configkeyfile);
8300
8301                 g_free(section);
8302                 g_free(file);
8303         }
8304
8305         g_strfreev(services);
8306 }
8307
8308 static int agent_probe(struct connman_agent *agent)
8309 {
8310         DBG("agent %p", agent);
8311         return 0;
8312 }
8313
8314 static void agent_remove(struct connman_agent *agent)
8315 {
8316         DBG("agent %p", agent);
8317 }
8318
8319 static void *agent_context_ref(void *context)
8320 {
8321         struct connman_service *service = context;
8322
8323         return (void *)connman_service_ref(service);
8324 }
8325
8326 static void agent_context_unref(void *context)
8327 {
8328         struct connman_service *service = context;
8329
8330         connman_service_unref(service);
8331 }
8332
8333 static struct connman_agent_driver agent_driver = {
8334         .name           = "service",
8335         .interface      = CONNMAN_AGENT_INTERFACE,
8336         .probe          = agent_probe,
8337         .remove         = agent_remove,
8338         .context_ref    = agent_context_ref,
8339         .context_unref  = agent_context_unref,
8340 };
8341
8342 int __connman_service_init(void)
8343 {
8344         int err;
8345
8346         DBG("");
8347
8348         err = connman_agent_driver_register(&agent_driver);
8349         if (err < 0) {
8350                 connman_error("Cannot register agent driver for %s",
8351                                                 agent_driver.name);
8352                 return err;
8353         }
8354
8355         connection = connman_dbus_get_connection();
8356
8357         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
8358                                                         NULL, service_free);
8359
8360         services_notify = g_new0(struct _services_notify, 1);
8361         services_notify->remove = g_hash_table_new_full(g_str_hash,
8362                         g_str_equal, g_free, NULL);
8363         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
8364
8365         remove_unprovisioned_services();
8366
8367         return 0;
8368 }
8369
8370 void __connman_service_cleanup(void)
8371 {
8372         DBG("");
8373
8374         if (vpn_autoconnect_timeout) {
8375                 g_source_remove(vpn_autoconnect_timeout);
8376                 vpn_autoconnect_timeout = 0;
8377         }
8378
8379         if (autoconnect_timeout != 0) {
8380                 g_source_remove(autoconnect_timeout);
8381                 autoconnect_timeout = 0;
8382         }
8383
8384         connman_agent_driver_unregister(&agent_driver);
8385
8386         g_list_free(service_list);
8387         service_list = NULL;
8388
8389         g_hash_table_destroy(service_hash);
8390         service_hash = NULL;
8391
8392         g_slist_free(counter_list);
8393         counter_list = NULL;
8394
8395         if (services_notify->id != 0) {
8396                 g_source_remove(services_notify->id);
8397                 service_send_changed(NULL);
8398                 g_hash_table_destroy(services_notify->remove);
8399                 g_hash_table_destroy(services_notify->add);
8400         }
8401         g_free(services_notify);
8402
8403         dbus_connection_unref(connection);
8404 }