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