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