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