service: Set the user connect status correctly for VPN
[framework/connectivity/connman.git] / src / service.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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
32 #include "connman.h"
33
34 #define CONNECT_TIMEOUT         120
35
36 static DBusConnection *connection = NULL;
37
38 static GSequence *service_list = NULL;
39 static GHashTable *service_hash = NULL;
40 static GSList *counter_list = NULL;
41
42 struct connman_stats {
43         connman_bool_t valid;
44         connman_bool_t enabled;
45         struct connman_stats_data data_last;
46         struct connman_stats_data data;
47         GTimer *timer;
48 };
49
50 struct connman_stats_counter {
51         connman_bool_t append_all;
52         struct connman_stats stats;
53         struct connman_stats stats_roaming;
54 };
55
56 struct connman_service {
57         gint refcount;
58         gint session_usage_count;
59         char *identifier;
60         char *path;
61         enum connman_service_type type;
62         enum connman_service_security security;
63         enum connman_service_state state;
64         enum connman_service_state state_ipv4;
65         enum connman_service_state state_ipv6;
66         enum connman_service_error error;
67         connman_uint8_t strength;
68         connman_bool_t favorite;
69         connman_bool_t immutable;
70         connman_bool_t hidden;
71         connman_bool_t ignore;
72         connman_bool_t autoconnect;
73         connman_bool_t userconnect;
74         GTimeVal modified;
75         unsigned int order;
76         char *name;
77         char *passphrase;
78         char *agent_passphrase;
79         connman_bool_t roaming;
80         connman_bool_t login_required;
81         connman_bool_t network_created;
82         struct connman_ipconfig *ipconfig_ipv4;
83         struct connman_ipconfig *ipconfig_ipv6;
84         struct connman_network *network;
85         struct connman_provider *provider;
86         char **nameservers;
87         char **nameservers_config;
88         char **domains;
89         char *domainname;
90         char **timeservers;
91         /* 802.1x settings from the config files */
92         char *eap;
93         char *identity;
94         char *agent_identity;
95         char *ca_cert_file;
96         char *client_cert_file;
97         char *private_key_file;
98         char *private_key_passphrase;
99         char *phase2;
100         DBusMessage *pending;
101         guint timeout;
102         struct connman_location *location;
103         struct connman_stats stats;
104         struct connman_stats stats_roaming;
105         GHashTable *counter_table;
106         enum connman_service_proxy_method proxy;
107         enum connman_service_proxy_method proxy_config;
108         char **proxies;
109         char **excludes;
110         char *pac;
111         connman_bool_t wps;
112 };
113
114 static void append_path(gpointer value, gpointer user_data)
115 {
116         struct connman_service *service = value;
117         DBusMessageIter *iter = user_data;
118
119         if (service->path == NULL || service->hidden == TRUE)
120                 return;
121
122         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
123                                                         &service->path);
124 }
125
126 void __connman_service_list(DBusMessageIter *iter, void *user_data)
127 {
128         if (service_list == NULL)
129                 return;
130
131         g_sequence_foreach(service_list, append_path, iter);
132 }
133
134 struct find_data {
135         const char *path;
136         struct connman_service *service;
137 };
138
139 static void compare_path(gpointer value, gpointer user_data)
140 {
141         struct connman_service *service = value;
142         struct find_data *data = user_data;
143
144         if (data->service != NULL)
145                 return;
146
147         if (g_strcmp0(service->path, data->path) == 0)
148                 data->service = service;
149 }
150
151 static struct connman_service *find_service(const char *path)
152 {
153         struct find_data data = { .path = path, .service = NULL };
154
155         DBG("path %s", path);
156
157         g_sequence_foreach(service_list, compare_path, &data);
158
159         return data.service;
160 }
161
162 const char *__connman_service_type2string(enum connman_service_type type)
163 {
164         switch (type) {
165         case CONNMAN_SERVICE_TYPE_UNKNOWN:
166                 break;
167         case CONNMAN_SERVICE_TYPE_SYSTEM:
168                 return "system";
169         case CONNMAN_SERVICE_TYPE_ETHERNET:
170                 return "ethernet";
171         case CONNMAN_SERVICE_TYPE_WIFI:
172                 return "wifi";
173         case CONNMAN_SERVICE_TYPE_WIMAX:
174                 return "wimax";
175         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
176                 return "bluetooth";
177         case CONNMAN_SERVICE_TYPE_CELLULAR:
178                 return "cellular";
179         case CONNMAN_SERVICE_TYPE_GPS:
180                 return "gps";
181         case CONNMAN_SERVICE_TYPE_VPN:
182                 return "vpn";
183         case CONNMAN_SERVICE_TYPE_GADGET:
184                 return "gadget";
185         }
186
187         return NULL;
188 }
189
190 static const char *security2string(enum connman_service_security security)
191 {
192         switch (security) {
193         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
194                 break;
195         case CONNMAN_SERVICE_SECURITY_NONE:
196                 return "none";
197         case CONNMAN_SERVICE_SECURITY_WEP:
198                 return "wep";
199         case CONNMAN_SERVICE_SECURITY_PSK:
200                 return "psk";
201         case CONNMAN_SERVICE_SECURITY_8021X:
202                 return "ieee8021x";
203         case CONNMAN_SERVICE_SECURITY_WPA:
204                 return "wpa";
205         case CONNMAN_SERVICE_SECURITY_RSN:
206                 return "rsn";
207         }
208
209         return NULL;
210 }
211
212 static const char *state2string(enum connman_service_state state)
213 {
214         switch (state) {
215         case CONNMAN_SERVICE_STATE_UNKNOWN:
216                 break;
217         case CONNMAN_SERVICE_STATE_IDLE:
218                 return "idle";
219         case CONNMAN_SERVICE_STATE_ASSOCIATION:
220                 return "association";
221         case CONNMAN_SERVICE_STATE_CONFIGURATION:
222                 return "configuration";
223         case CONNMAN_SERVICE_STATE_READY:
224                 return "ready";
225         case CONNMAN_SERVICE_STATE_ONLINE:
226                 return "online";
227         case CONNMAN_SERVICE_STATE_DISCONNECT:
228                 return "disconnect";
229         case CONNMAN_SERVICE_STATE_FAILURE:
230                 return "failure";
231         }
232
233         return NULL;
234 }
235
236 static const char *error2string(enum connman_service_error error)
237 {
238         switch (error) {
239         case CONNMAN_SERVICE_ERROR_UNKNOWN:
240                 break;
241         case CONNMAN_SERVICE_ERROR_OUT_OF_RANGE:
242                 return "out-of-range";
243         case CONNMAN_SERVICE_ERROR_PIN_MISSING:
244                 return "pin-missing";
245         case CONNMAN_SERVICE_ERROR_DHCP_FAILED:
246                 return "dhcp-failed";
247         case CONNMAN_SERVICE_ERROR_CONNECT_FAILED:
248                 return "connect-failed";
249         case CONNMAN_SERVICE_ERROR_LOGIN_FAILED:
250                 return "login-failed";
251         case CONNMAN_SERVICE_ERROR_AUTH_FAILED:
252                 return "auth-failed";
253         case CONNMAN_SERVICE_ERROR_INVALID_KEY:
254                 return "invalid-key";
255         }
256
257         return NULL;
258 }
259
260 static enum connman_service_error string2error(const char *error)
261 {
262         if (g_strcmp0(error, "dhcp-failed") == 0)
263                 return CONNMAN_SERVICE_ERROR_DHCP_FAILED;
264         else if (g_strcmp0(error, "pin-missing") == 0)
265                 return CONNMAN_SERVICE_ERROR_PIN_MISSING;
266         else if (g_strcmp0(error, "invalid-key") == 0)
267                 return CONNMAN_SERVICE_ERROR_INVALID_KEY;
268
269         return CONNMAN_SERVICE_ERROR_UNKNOWN;
270 }
271
272 static const char *proxymethod2string(enum connman_service_proxy_method method)
273 {
274         switch (method) {
275         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
276                 return "direct";
277         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
278                 return "manual";
279         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
280                 return "auto";
281         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
282                 break;
283         }
284
285         return NULL;
286 }
287
288 static enum connman_service_proxy_method string2proxymethod(const char *method)
289 {
290         if (g_strcmp0(method, "direct") == 0)
291                 return CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
292         else if (g_strcmp0(method, "auto") == 0)
293                 return CONNMAN_SERVICE_PROXY_METHOD_AUTO;
294         else if (g_strcmp0(method, "manual") == 0)
295                 return CONNMAN_SERVICE_PROXY_METHOD_MANUAL;
296         else
297                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
298 }
299
300 static int service_load(struct connman_service *service)
301 {
302         const char *ident = "default";
303         GKeyFile *keyfile;
304         GError *error = NULL;
305         gchar *pathname, *data = NULL;
306         gsize length;
307         gchar *str;
308         connman_bool_t autoconnect;
309         unsigned int ssid_len;
310         int err = 0;
311
312         DBG("service %p", service);
313
314         if (ident == NULL)
315                 return -EINVAL;
316
317         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
318         if (pathname == NULL)
319                 return -ENOMEM;
320
321         keyfile = g_key_file_new();
322
323         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
324                 g_free(pathname);
325                 return -ENOENT;
326         }
327
328         g_free(pathname);
329
330         if (g_key_file_load_from_data(keyfile, data, length,
331                                                         0, NULL) == FALSE) {
332                 g_free(data);
333                 return -EILSEQ;
334         }
335
336         g_free(data);
337
338         switch (service->type) {
339         case CONNMAN_SERVICE_TYPE_UNKNOWN:
340         case CONNMAN_SERVICE_TYPE_SYSTEM:
341         case CONNMAN_SERVICE_TYPE_ETHERNET:
342         case CONNMAN_SERVICE_TYPE_GPS:
343         case CONNMAN_SERVICE_TYPE_VPN:
344         case CONNMAN_SERVICE_TYPE_GADGET:
345                 break;
346         case CONNMAN_SERVICE_TYPE_WIFI:
347                 if (service->name == NULL) {
348                         gchar *name;
349
350                         name = g_key_file_get_string(keyfile,
351                                         service->identifier, "Name", NULL);
352                         if (name != NULL) {
353                                 g_free(service->name);
354                                 service->name = name;
355                         }
356
357                         if (service->network != NULL)
358                                 connman_network_set_name(service->network,
359                                                                         name);
360                 }
361
362                 if (service->network &&
363                                 connman_network_get_blob(service->network,
364                                         "WiFi.SSID", &ssid_len) == NULL) {
365                         gchar *hex_ssid;
366
367                         hex_ssid = g_key_file_get_string(keyfile,
368                                                         service->identifier,
369                                                                 "SSID", NULL);
370
371                         if (hex_ssid != NULL) {
372                                 gchar *ssid;
373                                 unsigned int i, j = 0, hex;
374                                 size_t hex_ssid_len = strlen(hex_ssid);
375
376                                 ssid = g_try_malloc0(hex_ssid_len / 2);
377                                 if (ssid == NULL) {
378                                         g_free(hex_ssid);
379                                         err = -ENOMEM;
380                                         goto done;
381                                 }
382
383                                 for (i = 0; i < hex_ssid_len; i += 2) {
384                                         sscanf(hex_ssid + i, "%02x", &hex);
385                                         ssid[j++] = hex;
386                                 }
387
388                                 connman_network_set_blob(service->network,
389                                         "WiFi.SSID", ssid, hex_ssid_len / 2);
390                         }
391
392                         g_free(hex_ssid);
393                 }
394                 /* fall through */
395
396         case CONNMAN_SERVICE_TYPE_WIMAX:
397         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
398         case CONNMAN_SERVICE_TYPE_CELLULAR:
399                 service->favorite = g_key_file_get_boolean(keyfile,
400                                 service->identifier, "Favorite", NULL);
401
402                 autoconnect = g_key_file_get_boolean(keyfile,
403                                 service->identifier, "AutoConnect", &error);
404                 if (error == NULL)
405                         service->autoconnect = autoconnect;
406                 g_clear_error(&error);
407
408                 str = g_key_file_get_string(keyfile,
409                                 service->identifier, "Failure", NULL);
410                 if (str != NULL) {
411                         if (service->favorite == FALSE)
412                                 service->state_ipv4 = service->state_ipv6 =
413                                         CONNMAN_SERVICE_STATE_FAILURE;
414                         service->error = string2error(str);
415                 }
416                 break;
417         }
418
419         str = g_key_file_get_string(keyfile,
420                                 service->identifier, "Modified", NULL);
421         if (str != NULL) {
422                 g_time_val_from_iso8601(str, &service->modified);
423                 g_free(str);
424         }
425
426         str = g_key_file_get_string(keyfile,
427                                 service->identifier, "Passphrase", NULL);
428         if (str != NULL) {
429                 g_free(service->passphrase);
430                 service->passphrase = str;
431         }
432
433         if (service->ipconfig_ipv4 != NULL)
434                 __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
435                                         service->identifier, "IPv4.");
436
437         if (service->ipconfig_ipv6 != NULL)
438                 __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
439                                         service->identifier, "IPv6.");
440
441         service->nameservers_config = g_key_file_get_string_list(keyfile,
442                         service->identifier, "Nameservers", &length, NULL);
443         if (service->nameservers_config != NULL && length == 0) {
444                 g_strfreev(service->nameservers_config);
445                 service->nameservers_config = NULL;
446         }
447
448         service->domains = g_key_file_get_string_list(keyfile,
449                         service->identifier, "Domains", &length, NULL);
450         if (service->domains != NULL && length == 0) {
451                 g_strfreev(service->domains);
452                 service->domains = NULL;
453         }
454
455         str = g_key_file_get_string(keyfile,
456                                 service->identifier, "Proxy.Method", NULL);
457         if (str != NULL)
458                 service->proxy_config = string2proxymethod(str);
459
460         g_free(str);
461
462         service->proxies = g_key_file_get_string_list(keyfile,
463                         service->identifier, "Proxy.Servers", &length, NULL);
464         if (service->proxies != NULL && length == 0) {
465                 g_strfreev(service->proxies);
466                 service->proxies = NULL;
467         }
468
469         service->excludes = g_key_file_get_string_list(keyfile,
470                         service->identifier, "Proxy.Excludes", &length, NULL);
471         if (service->excludes != NULL && length == 0) {
472                 g_strfreev(service->excludes);
473                 service->excludes = NULL;
474         }
475
476         str = g_key_file_get_string(keyfile,
477                                 service->identifier, "Proxy.URL", NULL);
478         if (str != NULL) {
479                 g_free(service->pac);
480                 service->pac = str;
481         }
482
483 done:
484         g_key_file_free(keyfile);
485
486         return err;
487 }
488
489 static int service_save(struct connman_service *service)
490 {
491         const char *ident = "default";
492         GKeyFile *keyfile;
493         gchar *pathname, *data = NULL;
494         gsize length;
495         gchar *str;
496         const char *cst_str = NULL;
497         int err = 0;
498
499         DBG("service %p", service);
500
501         if (ident == NULL)
502                 return -EINVAL;
503
504         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
505         if (pathname == NULL)
506                 return -ENOMEM;
507
508         keyfile = g_key_file_new();
509
510         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
511                 goto update;
512
513         if (length > 0) {
514                 if (g_key_file_load_from_data(keyfile, data, length,
515                                                         0, NULL) == FALSE)
516                         goto done;
517         }
518
519         g_free(data);
520
521 update:
522         if (service->name != NULL)
523                 g_key_file_set_string(keyfile, service->identifier,
524                                                 "Name", service->name);
525
526         switch (service->type) {
527         case CONNMAN_SERVICE_TYPE_UNKNOWN:
528         case CONNMAN_SERVICE_TYPE_SYSTEM:
529         case CONNMAN_SERVICE_TYPE_ETHERNET:
530         case CONNMAN_SERVICE_TYPE_GPS:
531         case CONNMAN_SERVICE_TYPE_VPN:
532         case CONNMAN_SERVICE_TYPE_GADGET:
533                 break;
534         case CONNMAN_SERVICE_TYPE_WIFI:
535                 if (service->network) {
536                         const unsigned char *ssid;
537                         unsigned int ssid_len = 0;
538
539                         ssid = connman_network_get_blob(service->network,
540                                                         "WiFi.SSID", &ssid_len);
541
542                         if (ssid != NULL && ssid_len > 0 && ssid[0] != '\0') {
543                                 char *identifier = service->identifier;
544                                 GString *str;
545                                 unsigned int i;
546
547                                 str = g_string_sized_new(ssid_len * 2);
548                                 if (str == NULL) {
549                                         err = -ENOMEM;
550                                         goto done;
551                                 }
552
553                                 for (i = 0; i < ssid_len; i++)
554                                         g_string_append_printf(str,
555                                                         "%02x", ssid[i]);
556
557                                 g_key_file_set_string(keyfile, identifier,
558                                                         "SSID", str->str);
559
560                                 g_string_free(str, TRUE);
561                         }
562                 }
563                 /* fall through */
564
565         case CONNMAN_SERVICE_TYPE_WIMAX:
566         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
567         case CONNMAN_SERVICE_TYPE_CELLULAR:
568                 g_key_file_set_boolean(keyfile, service->identifier,
569                                         "Favorite", service->favorite);
570
571                 if (service->favorite == TRUE)
572                         g_key_file_set_boolean(keyfile, service->identifier,
573                                         "AutoConnect", service->autoconnect);
574
575                 if (service->state_ipv4 == CONNMAN_SERVICE_STATE_FAILURE ||
576                         service->state_ipv6 == CONNMAN_SERVICE_STATE_FAILURE) {
577                         const char *failure = error2string(service->error);
578                         if (failure != NULL)
579                                 g_key_file_set_string(keyfile,
580                                                         service->identifier,
581                                                         "Failure", failure);
582                 } else {
583                         g_key_file_remove_key(keyfile, service->identifier,
584                                                         "Failure", NULL);
585                 }
586                 break;
587         }
588
589         str = g_time_val_to_iso8601(&service->modified);
590         if (str != NULL) {
591                 g_key_file_set_string(keyfile, service->identifier,
592                                                         "Modified", str);
593                 g_free(str);
594         }
595
596         if (service->passphrase != NULL && strlen(service->passphrase) > 0)
597                 g_key_file_set_string(keyfile, service->identifier,
598                                         "Passphrase", service->passphrase);
599         else
600                 g_key_file_remove_key(keyfile, service->identifier,
601                                                         "Passphrase", NULL);
602
603         if (service->ipconfig_ipv4 != NULL)
604                 __connman_ipconfig_save(service->ipconfig_ipv4, keyfile,
605                                         service->identifier, "IPv4.");
606
607         if (service->ipconfig_ipv6 != NULL)
608                 __connman_ipconfig_save(service->ipconfig_ipv6, keyfile,
609                                                 service->identifier, "IPv6.");
610
611         if (service->nameservers_config != NULL) {
612                 guint len = g_strv_length(service->nameservers_config);
613
614                 g_key_file_set_string_list(keyfile, service->identifier,
615                                                                 "Nameservers",
616                                 (const gchar **) service->nameservers_config, len);
617         } else
618         g_key_file_remove_key(keyfile, service->identifier,
619                                                         "Nameservers", NULL);
620
621         if (service->domains != NULL) {
622                 guint len = g_strv_length(service->domains);
623
624                 g_key_file_set_string_list(keyfile, service->identifier,
625                                                                 "Domains",
626                                 (const gchar **) service->domains, len);
627         } else
628                 g_key_file_remove_key(keyfile, service->identifier,
629                                                         "Domains", NULL);
630
631         cst_str = proxymethod2string(service->proxy_config);
632         if (cst_str != NULL)
633                 g_key_file_set_string(keyfile, service->identifier,
634                                 "Proxy.Method", cst_str);
635
636         if (service->proxies != NULL) {
637                 guint len = g_strv_length(service->proxies);
638
639                 g_key_file_set_string_list(keyfile, service->identifier,
640                                 "Proxy.Servers",
641                                 (const gchar **) service->proxies, len);
642         } else
643                 g_key_file_remove_key(keyfile, service->identifier,
644                                                 "Proxy.Servers", NULL);
645
646         if (service->excludes != NULL) {
647                 guint len = g_strv_length(service->excludes);
648
649                 g_key_file_set_string_list(keyfile, service->identifier,
650                                 "Proxy.Excludes",
651                                 (const gchar **) service->excludes, len);
652         } else
653                 g_key_file_remove_key(keyfile, service->identifier,
654                                                 "Proxy.Excludes", NULL);
655
656         if (service->pac != NULL && strlen(service->pac) > 0)
657                 g_key_file_set_string(keyfile, service->identifier,
658                                         "Proxy.URL", service->pac);
659         else
660                 g_key_file_remove_key(keyfile, service->identifier,
661                                                         "Proxy.URL", NULL);
662
663         data = g_key_file_to_data(keyfile, &length, NULL);
664
665         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
666                 connman_error("Failed to store service information");
667
668 done:
669         g_free(data);
670
671         g_key_file_free(keyfile);
672
673         g_free(pathname);
674
675         return err;
676 }
677
678 static guint changed_timeout = 0;
679
680 static gboolean notify_services_changed(gpointer user_data)
681 {
682         changed_timeout = 0;
683
684         connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
685                                 CONNMAN_MANAGER_INTERFACE, "Services",
686                                 DBUS_TYPE_OBJECT_PATH, __connman_service_list,
687                                 NULL);
688
689         return FALSE;
690 }
691
692 static void services_changed(gboolean delayed)
693 {
694         DBG("");
695
696         if (changed_timeout > 0) {
697                 g_source_remove(changed_timeout);
698                 changed_timeout = 0;
699         }
700
701         if (__connman_connection_update_gateway() == TRUE) {
702                 notify_services_changed(NULL);
703                 return;
704         }
705
706         if (delayed == FALSE) {
707                 notify_services_changed(NULL);
708                 return;
709         }
710
711         changed_timeout = g_timeout_add_seconds(1, notify_services_changed,
712                                                                  NULL);
713 }
714
715 static enum connman_service_state combine_state(
716                                         enum connman_service_state state_a,
717                                         enum connman_service_state state_b)
718 {
719         enum connman_service_state result;
720
721         if (state_a == state_b) {
722                 result = state_a;
723                 goto done;
724         }
725
726         if (state_a == CONNMAN_SERVICE_STATE_UNKNOWN) {
727                 result = state_b;
728                 goto done;
729         }
730
731         if (state_b == CONNMAN_SERVICE_STATE_UNKNOWN) {
732                 result = state_a;
733                 goto done;
734         }
735
736         if (state_a == CONNMAN_SERVICE_STATE_IDLE) {
737                 result = state_b;
738                 goto done;
739         }
740
741         if (state_b == CONNMAN_SERVICE_STATE_IDLE) {
742                 result = state_a;
743                 goto done;
744         }
745
746         if (state_a == CONNMAN_SERVICE_STATE_ASSOCIATION) {
747                 if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION ||
748                                 state_b == CONNMAN_SERVICE_STATE_ONLINE ||
749                                 state_b == CONNMAN_SERVICE_STATE_READY)
750                         result = state_b;
751                 else
752                         result = state_a;
753                 goto done;
754         }
755
756         if (state_b == CONNMAN_SERVICE_STATE_ASSOCIATION) {
757                 if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION ||
758                                 state_a == CONNMAN_SERVICE_STATE_ONLINE ||
759                                 state_a == CONNMAN_SERVICE_STATE_READY)
760                         result = state_a;
761                 else
762                         result = state_b;
763                 goto done;
764         }
765
766         if (state_a == CONNMAN_SERVICE_STATE_CONFIGURATION) {
767                 if (state_b == CONNMAN_SERVICE_STATE_ONLINE ||
768                                 state_b == CONNMAN_SERVICE_STATE_READY)
769                         result = state_b;
770                 else
771                         result = state_a;
772                 goto done;
773         }
774
775         if (state_b == CONNMAN_SERVICE_STATE_CONFIGURATION) {
776                 if (state_a == CONNMAN_SERVICE_STATE_ONLINE ||
777                                 state_a == CONNMAN_SERVICE_STATE_READY)
778                         result = state_a;
779                 else
780                         result = state_b;
781                 goto done;
782         }
783
784         if (state_a == CONNMAN_SERVICE_STATE_READY) {
785                 if (state_b == CONNMAN_SERVICE_STATE_ONLINE ||
786                                 state_b == CONNMAN_SERVICE_STATE_DISCONNECT)
787                         result = state_b;
788                 else
789                         result = state_a;
790                 goto done;
791         }
792
793         if (state_b == CONNMAN_SERVICE_STATE_READY) {
794                 if (state_a == CONNMAN_SERVICE_STATE_ONLINE ||
795                                 state_a == CONNMAN_SERVICE_STATE_DISCONNECT)
796                         result = state_a;
797                 else
798                         result = state_b;
799                 goto done;
800         }
801
802         if (state_a == CONNMAN_SERVICE_STATE_ONLINE) {
803                 if (state_b == CONNMAN_SERVICE_STATE_DISCONNECT)
804                         result = state_b;
805                 else
806                         result = state_a;
807                 goto done;
808         }
809
810         if (state_b == CONNMAN_SERVICE_STATE_ONLINE) {
811                 if (state_a == CONNMAN_SERVICE_STATE_DISCONNECT)
812                         result = state_a;
813                 else
814                         result = state_b;
815                 goto done;
816         }
817
818         if (state_a == CONNMAN_SERVICE_STATE_DISCONNECT) {
819                 result = state_a;
820                 goto done;
821         }
822
823         if (state_b == CONNMAN_SERVICE_STATE_DISCONNECT) {
824                 result = state_b;
825                 goto done;
826         }
827
828         result = CONNMAN_SERVICE_STATE_FAILURE;
829
830 done:
831         return result;
832 }
833
834 static connman_bool_t is_connecting_state(struct connman_service *service,
835                                         enum connman_service_state state)
836 {
837         switch (state) {
838         case CONNMAN_SERVICE_STATE_UNKNOWN:
839         case CONNMAN_SERVICE_STATE_IDLE:
840         case CONNMAN_SERVICE_STATE_FAILURE:
841                 if (service->network != NULL)
842                         return connman_network_get_connecting(service->network);
843         case CONNMAN_SERVICE_STATE_DISCONNECT:
844         case CONNMAN_SERVICE_STATE_READY:
845         case CONNMAN_SERVICE_STATE_ONLINE:
846                 break;
847         case CONNMAN_SERVICE_STATE_ASSOCIATION:
848         case CONNMAN_SERVICE_STATE_CONFIGURATION:
849                 return TRUE;
850         }
851
852         return FALSE;
853 }
854
855 static connman_bool_t is_connected_state(const struct connman_service *service,
856                                         enum connman_service_state state)
857 {
858         switch (state) {
859         case CONNMAN_SERVICE_STATE_UNKNOWN:
860         case CONNMAN_SERVICE_STATE_IDLE:
861         case CONNMAN_SERVICE_STATE_ASSOCIATION:
862         case CONNMAN_SERVICE_STATE_CONFIGURATION:
863         case CONNMAN_SERVICE_STATE_DISCONNECT:
864         case CONNMAN_SERVICE_STATE_FAILURE:
865                 break;
866         case CONNMAN_SERVICE_STATE_READY:
867         case CONNMAN_SERVICE_STATE_ONLINE:
868                 return TRUE;
869         }
870
871         return FALSE;
872 }
873
874 static connman_bool_t is_connecting(struct connman_service *service)
875 {
876         return is_connecting_state(service, service->state);
877 }
878
879 static connman_bool_t is_connected(struct connman_service *service)
880 {
881         return is_connected_state(service, service->state);
882 }
883
884 static void update_nameservers(struct connman_service *service)
885 {
886         const char *ifname;
887
888         if (service->ipconfig_ipv4)
889                 ifname = connman_ipconfig_get_ifname(service->ipconfig_ipv4);
890         else if (service->ipconfig_ipv6)
891                 ifname = connman_ipconfig_get_ifname(service->ipconfig_ipv6);
892         else
893                 ifname = NULL;
894
895         if (ifname == NULL)
896                 return;
897
898         switch (combine_state(service->state_ipv4, service->state_ipv6)) {
899         case CONNMAN_SERVICE_STATE_UNKNOWN:
900         case CONNMAN_SERVICE_STATE_IDLE:
901         case CONNMAN_SERVICE_STATE_ASSOCIATION:
902         case CONNMAN_SERVICE_STATE_CONFIGURATION:
903                 return;
904         case CONNMAN_SERVICE_STATE_FAILURE:
905         case CONNMAN_SERVICE_STATE_DISCONNECT:
906                 connman_resolver_remove_all(ifname);
907                 return;
908         case CONNMAN_SERVICE_STATE_READY:
909         case CONNMAN_SERVICE_STATE_ONLINE:
910                 break;
911         }
912
913         connman_resolver_remove_all(ifname);
914
915         if (service->nameservers_config != NULL) {
916                 int i;
917
918                 for (i = 0; service->nameservers_config[i] != NULL; i++) {
919                         connman_resolver_append(ifname, NULL,
920                                                 service->nameservers_config[i]);
921                 }
922         } else if (service->nameservers != NULL) {
923                 int i;
924
925                 for (i = 0; service->nameservers[i] != NULL; i++) {
926                         connman_resolver_append(ifname, NULL,
927                                                 service->nameservers[i]);
928                 }
929         }
930
931         if (service->domains != NULL) {
932                 int i;
933
934                 for (i = 0; service->domains[i]; i++)
935                         connman_resolver_append(ifname, service->domains[i],
936                                                 NULL);
937         } else if (service->domainname != NULL)
938                 connman_resolver_append(ifname, service->domainname, NULL);
939
940         connman_resolver_flush();
941 }
942
943 int __connman_service_nameserver_append(struct connman_service *service,
944                                                 const char *nameserver)
945 {
946         int len;
947
948         DBG("service %p nameserver %s", service, nameserver);
949
950         if (nameserver == NULL)
951                 return -EINVAL;
952
953         if (service->nameservers != NULL) {
954                 int i;
955
956                 for (i = 0; service->nameservers[i] != NULL; i++)
957                         if (g_strcmp0(service->nameservers[i], nameserver) == 0)
958                                 return -EEXIST;
959
960                 len = g_strv_length(service->nameservers);
961                 service->nameservers = g_try_renew(char *, service->nameservers,
962                                                         len + 2);
963         } else {
964                 len = 0;
965                 service->nameservers = g_try_new0(char *, len + 2);
966         }
967
968         if (service->nameservers == NULL)
969                 return -ENOMEM;
970
971         service->nameservers[len] = g_strdup(nameserver);
972         service->nameservers[len + 1] = NULL;
973
974         update_nameservers(service);
975
976         return 0;
977 }
978
979 int __connman_service_nameserver_remove(struct connman_service *service,
980                                                 const char *nameserver)
981 {
982         char **servers;
983         int len, i, j;
984
985         DBG("service %p nameserver %s", service, nameserver);
986
987         if (nameserver == NULL)
988                 return -EINVAL;
989
990         if (service->nameservers == NULL)
991                 return 0;
992
993         len = g_strv_length(service->nameservers);
994         if (len == 1) {
995                 if (g_strcmp0(service->nameservers[0], nameserver) != 0)
996                         return 0;
997
998                 g_strfreev(service->nameservers);
999                 service->nameservers = NULL;
1000
1001                 return 0;
1002         }
1003
1004         servers = g_try_new0(char *, len);
1005         if (servers == NULL)
1006                 return -ENOMEM;
1007
1008         for (i = 0, j = 0; i < len; i++) {
1009                 if (g_strcmp0(service->nameservers[i], nameserver) != 0) {
1010                         servers[j] = g_strdup(service->nameservers[i]);
1011                         j++;
1012                 }
1013         }
1014         servers[len - 1] = NULL;
1015
1016         g_strfreev(service->nameservers);
1017         service->nameservers = servers;
1018
1019         update_nameservers(service);
1020
1021         return 0;
1022 }
1023
1024 void __connman_service_nameserver_clear(struct connman_service *service)
1025 {
1026         g_strfreev(service->nameservers);
1027         service->nameservers = NULL;
1028
1029         update_nameservers(service);
1030 }
1031
1032 static void nameserver_add_routes(int index, char **nameservers,
1033                                         const char *gw)
1034 {
1035         int i, ret, family;
1036         struct addrinfo hints;
1037         struct addrinfo *addr;
1038
1039         for (i = 0; nameservers[i] != NULL; i++) {
1040                 memset(&hints, 0, sizeof(struct addrinfo));
1041                 hints.ai_flags = AI_NUMERICHOST;
1042                 addr = NULL;
1043
1044                 ret = getaddrinfo(nameservers[i], NULL, &hints, &addr);
1045                 if (ret == EAI_NONAME)
1046                         family = AF_INET; /* use the IPv4 as a default */
1047                 else if (ret != 0)
1048                         continue;
1049                 else
1050                         family = addr->ai_family;
1051
1052                 if (family == AF_INET) {
1053                         if (connman_inet_compare_subnet(index,
1054                                                 nameservers[i]) != TRUE)
1055                                 connman_inet_add_host_route(index,
1056                                                         nameservers[i], gw);
1057                 } else if (family == AF_INET6)
1058                         connman_inet_add_ipv6_host_route(index,
1059                                                         nameservers[i], gw);
1060
1061                 freeaddrinfo(addr);
1062         }
1063 }
1064
1065 static void nameserver_del_routes(int index, char **nameservers)
1066 {
1067         int i, ret, family;
1068         struct addrinfo hints;
1069         struct addrinfo *addr;
1070
1071         for (i = 0; nameservers[i] != NULL; i++) {
1072                 memset(&hints, 0, sizeof(struct addrinfo));
1073                 hints.ai_flags = AI_NUMERICHOST;
1074                 addr = NULL;
1075
1076                 ret = getaddrinfo(nameservers[i], NULL, &hints, &addr);
1077                 if (ret == EAI_NONAME)
1078                         family = AF_INET; /* use the IPv4 as a default */
1079                 else if (ret != 0)
1080                         continue;
1081                 else
1082                         family = addr->ai_family;
1083
1084                 if (family == AF_INET)
1085                         connman_inet_del_host_route(index, nameservers[i]);
1086                 else if (family == AF_INET6)
1087                         connman_inet_del_ipv6_host_route(index,
1088                                                         nameservers[i]);
1089
1090                 freeaddrinfo(addr);
1091         }
1092 }
1093
1094 void __connman_service_nameserver_add_routes(struct connman_service *service,
1095                                                 const char *gw)
1096 {
1097         int index = -1;
1098
1099         if (service == NULL)
1100                 return;
1101
1102         if (service->network != NULL)
1103                 index = connman_network_get_index(service->network);
1104         else if (service->provider != NULL)
1105                 index = connman_provider_get_index(service->provider);
1106
1107         if (service->nameservers_config != NULL) {
1108                 /*
1109                  * Configured nameserver takes preference over the
1110                  * discoverd nameserver gathered from DHCP, VPN, etc.
1111                  */
1112                 nameserver_add_routes(index, service->nameservers_config, gw);
1113         } else if (service->nameservers != NULL) {
1114                 /*
1115                  * We add nameservers host routes for nameservers that
1116                  * are not on our subnet. For those who are, the subnet
1117                  * route will be installed by the time the dns proxy code
1118                  * tries to reach them. The subnet route is installed
1119                  * when setting the interface IP address.
1120                  */
1121                 nameserver_add_routes(index, service->nameservers, gw);
1122         }
1123 }
1124
1125 void __connman_service_nameserver_del_routes(struct connman_service *service)
1126 {
1127         int index = -1;
1128
1129         if (service == NULL)
1130                 return;
1131
1132         if (service->network != NULL)
1133                 index = connman_network_get_index(service->network);
1134         else if (service->provider != NULL)
1135                 index = connman_provider_get_index(service->provider);
1136
1137         if (service->nameservers_config != NULL)
1138                 nameserver_del_routes(index, service->nameservers_config);
1139         else if (service->nameservers != NULL)
1140                 nameserver_del_routes(index, service->nameservers);
1141 }
1142
1143 static struct connman_stats *stats_get(struct connman_service *service)
1144 {
1145         if (service->roaming == TRUE)
1146                 return &service->stats_roaming;
1147         else
1148                 return &service->stats;
1149 }
1150
1151 static connman_bool_t stats_enabled(struct connman_service *service)
1152 {
1153         struct connman_stats *stats = stats_get(service);
1154
1155         return stats->enabled;
1156 }
1157
1158 static void stats_start(struct connman_service *service)
1159 {
1160         struct connman_stats *stats = stats_get(service);
1161
1162         DBG("service %p", service);
1163
1164         if (stats->timer == NULL)
1165                 return;
1166
1167         stats->enabled = TRUE;
1168         stats->data_last.time = stats->data.time;
1169
1170         g_timer_start(stats->timer);
1171 }
1172
1173 static void stats_stop(struct connman_service *service)
1174 {
1175         struct connman_stats *stats = stats_get(service);
1176         unsigned int seconds;
1177
1178         DBG("service %p", service);
1179
1180         if (stats->timer == NULL)
1181                 return;
1182
1183         if (stats->enabled == FALSE)
1184                 return;
1185
1186         g_timer_stop(stats->timer);
1187
1188         seconds = g_timer_elapsed(stats->timer, NULL);
1189         stats->data.time = stats->data_last.time + seconds;
1190
1191         stats->enabled = FALSE;
1192 }
1193
1194 static void reset_stats(struct connman_service *service)
1195 {
1196         DBG("service %p", service);
1197
1198         /* home */
1199         service->stats.valid = FALSE;
1200
1201         service->stats.data.rx_packets = 0;
1202         service->stats.data.tx_packets = 0;
1203         service->stats.data.rx_bytes = 0;
1204         service->stats.data.tx_bytes = 0;
1205         service->stats.data.rx_errors = 0;
1206         service->stats.data.tx_errors = 0;
1207         service->stats.data.rx_dropped = 0;
1208         service->stats.data.tx_dropped = 0;
1209         service->stats.data.time = 0;
1210         service->stats.data_last.time = 0;
1211
1212         g_timer_reset(service->stats.timer);
1213
1214         /* roaming */
1215         service->stats_roaming.valid = FALSE;
1216
1217         service->stats_roaming.data.rx_packets = 0;
1218         service->stats_roaming.data.tx_packets = 0;
1219         service->stats_roaming.data.rx_bytes = 0;
1220         service->stats_roaming.data.tx_bytes = 0;
1221         service->stats_roaming.data.rx_errors = 0;
1222         service->stats_roaming.data.tx_errors = 0;
1223         service->stats_roaming.data.rx_dropped = 0;
1224         service->stats_roaming.data.tx_dropped = 0;
1225         service->stats_roaming.data.time = 0;
1226         service->stats_roaming.data_last.time = 0;
1227
1228         g_timer_reset(service->stats_roaming.timer);
1229 }
1230
1231 static struct connman_service *get_default(void)
1232 {
1233         struct connman_service *service;
1234         GSequenceIter *iter;
1235
1236         iter = g_sequence_get_begin_iter(service_list);
1237
1238         if (g_sequence_iter_is_end(iter) == TRUE)
1239                 return NULL;
1240
1241         service = g_sequence_get(iter);
1242
1243         if (is_connected(service) == FALSE)
1244                 return NULL;
1245
1246         return service;
1247 }
1248
1249 static void default_changed(void)
1250 {
1251         struct connman_service *service = get_default();
1252
1253         __connman_notifier_default_changed(service);
1254 }
1255
1256 const char *__connman_service_default(void)
1257 {
1258         struct connman_service *service;
1259
1260         service = get_default();
1261         if (service == NULL)
1262                 return "";
1263
1264         return __connman_service_type2string(service->type);
1265 }
1266
1267 static void state_changed(struct connman_service *service)
1268 {
1269         const char *str;
1270
1271         __connman_notifier_service_state_changed(service, service->state);
1272
1273         str = state2string(service->state);
1274         if (str == NULL)
1275                 return;
1276
1277         connman_dbus_property_changed_basic(service->path,
1278                                 CONNMAN_SERVICE_INTERFACE, "State",
1279                                                 DBUS_TYPE_STRING, &str);
1280 }
1281
1282 static void strength_changed(struct connman_service *service)
1283 {
1284         if (service->strength == 0)
1285                 return;
1286
1287         connman_dbus_property_changed_basic(service->path,
1288                                 CONNMAN_SERVICE_INTERFACE, "Strength",
1289                                         DBUS_TYPE_BYTE, &service->strength);
1290 }
1291
1292 static void favorite_changed(struct connman_service *service)
1293 {
1294         if (service->path == NULL)
1295                 return;
1296
1297         connman_dbus_property_changed_basic(service->path,
1298                                 CONNMAN_SERVICE_INTERFACE, "Favorite",
1299                                         DBUS_TYPE_BOOLEAN, &service->favorite);
1300 }
1301
1302 static void immutable_changed(struct connman_service *service)
1303 {
1304         if (service->path == NULL)
1305                 return;
1306
1307         connman_dbus_property_changed_basic(service->path,
1308                                 CONNMAN_SERVICE_INTERFACE, "Immutable",
1309                                         DBUS_TYPE_BOOLEAN, &service->immutable);
1310 }
1311
1312 static void roaming_changed(struct connman_service *service)
1313 {
1314         if (service->path == NULL)
1315                 return;
1316
1317         connman_dbus_property_changed_basic(service->path,
1318                                 CONNMAN_SERVICE_INTERFACE, "Roaming",
1319                                         DBUS_TYPE_BOOLEAN, &service->roaming);
1320 }
1321
1322 static void autoconnect_changed(struct connman_service *service)
1323 {
1324         if (service->path == NULL)
1325                 return;
1326
1327         connman_dbus_property_changed_basic(service->path,
1328                                 CONNMAN_SERVICE_INTERFACE, "AutoConnect",
1329                                 DBUS_TYPE_BOOLEAN, &service->autoconnect);
1330 }
1331
1332 static void passphrase_changed(struct connman_service *service)
1333 {
1334         dbus_bool_t required;
1335
1336         switch (service->type) {
1337         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1338         case CONNMAN_SERVICE_TYPE_SYSTEM:
1339         case CONNMAN_SERVICE_TYPE_ETHERNET:
1340         case CONNMAN_SERVICE_TYPE_WIMAX:
1341         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1342         case CONNMAN_SERVICE_TYPE_CELLULAR:
1343         case CONNMAN_SERVICE_TYPE_GPS:
1344         case CONNMAN_SERVICE_TYPE_VPN:
1345         case CONNMAN_SERVICE_TYPE_GADGET:
1346                 return;
1347         case CONNMAN_SERVICE_TYPE_WIFI:
1348                 required = FALSE;
1349
1350                 switch (service->security) {
1351                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
1352                 case CONNMAN_SERVICE_SECURITY_NONE:
1353                         break;
1354                 case CONNMAN_SERVICE_SECURITY_WEP:
1355                 case CONNMAN_SERVICE_SECURITY_PSK:
1356                 case CONNMAN_SERVICE_SECURITY_WPA:
1357                 case CONNMAN_SERVICE_SECURITY_RSN:
1358                         if (service->passphrase == NULL)
1359                                 required = TRUE;
1360                         break;
1361                 case CONNMAN_SERVICE_SECURITY_8021X:
1362                         break;
1363                 }
1364                 break;
1365         }
1366
1367         connman_dbus_property_changed_basic(service->path,
1368                                 CONNMAN_SERVICE_INTERFACE, "PassphraseRequired",
1369                                                 DBUS_TYPE_BOOLEAN, &required);
1370 }
1371
1372 static void login_changed(struct connman_service *service)
1373 {
1374         dbus_bool_t required = service->login_required;
1375
1376         if (service->path == NULL)
1377                 return;
1378
1379         connman_dbus_property_changed_basic(service->path,
1380                                 CONNMAN_SERVICE_INTERFACE, "LoginRequired",
1381                                                 DBUS_TYPE_BOOLEAN, &required);
1382 }
1383
1384 static void append_security(DBusMessageIter *iter, void *user_data)
1385 {
1386         struct connman_service *service = user_data;
1387         const char *str;
1388
1389         str = security2string(service->security);
1390         if (str != NULL)
1391                 dbus_message_iter_append_basic(iter,
1392                                 DBUS_TYPE_STRING, &str);
1393
1394         str = "wps";
1395         if (service->wps == TRUE)
1396                 dbus_message_iter_append_basic(iter,
1397                                 DBUS_TYPE_STRING, &str);
1398 }
1399
1400 static void append_ethernet(DBusMessageIter *iter, void *user_data)
1401 {
1402         struct connman_service *service = user_data;
1403
1404         if (service->ipconfig_ipv4 != NULL)
1405                 __connman_ipconfig_append_ethernet(service->ipconfig_ipv4,
1406                                                                         iter);
1407         else if (service->ipconfig_ipv6 != NULL)
1408                 __connman_ipconfig_append_ethernet(service->ipconfig_ipv6,
1409                                                                         iter);
1410 }
1411
1412 static void append_ipv4(DBusMessageIter *iter, void *user_data)
1413 {
1414         struct connman_service *service = user_data;
1415
1416         DBG("ipv4 %p state %s", service->ipconfig_ipv4,
1417                                 state2string(service->state_ipv4));
1418
1419         if (is_connected_state(service, service->state_ipv4) == FALSE)
1420                 return;
1421
1422         if (service->ipconfig_ipv4 != NULL)
1423                 __connman_ipconfig_append_ipv4(service->ipconfig_ipv4, iter);
1424 }
1425
1426 static void append_ipv6(DBusMessageIter *iter, void *user_data)
1427 {
1428         struct connman_service *service = user_data;
1429
1430         DBG("ipv6 %p state %s", service->ipconfig_ipv6,
1431                                 state2string(service->state_ipv6));
1432
1433         if (is_connected_state(service, service->state_ipv6) == FALSE)
1434                 return;
1435
1436         if (service->ipconfig_ipv6 != NULL)
1437                 __connman_ipconfig_append_ipv6(service->ipconfig_ipv6, iter,
1438                                                 service->ipconfig_ipv4);
1439 }
1440
1441 static void append_ipv4config(DBusMessageIter *iter, void *user_data)
1442 {
1443         struct connman_service *service = user_data;
1444
1445         if (service->ipconfig_ipv4 != NULL)
1446                 __connman_ipconfig_append_ipv4config(service->ipconfig_ipv4,
1447                                                         iter);
1448 }
1449
1450 static void append_ipv6config(DBusMessageIter *iter, void *user_data)
1451 {
1452         struct connman_service *service = user_data;
1453
1454         if (service->ipconfig_ipv6 != NULL)
1455                 __connman_ipconfig_append_ipv6config(service->ipconfig_ipv6,
1456                                                         iter);
1457 }
1458
1459 static void append_nameserver(DBusMessageIter *iter, char ***nameservers)
1460 {
1461         char **servers;
1462         int i;
1463
1464         servers = *nameservers;
1465
1466         for (i = 0; servers[i] != NULL; i++) {
1467                 dbus_message_iter_append_basic(iter,
1468                                         DBUS_TYPE_STRING, &servers[i]);
1469         }
1470 }
1471
1472 static void append_dns(DBusMessageIter *iter, void *user_data)
1473 {
1474         struct connman_service *service = user_data;
1475
1476         if (is_connected(service) == FALSE)
1477                 return;
1478
1479         if (service->nameservers_config != NULL) {
1480                 append_nameserver(iter, &service->nameservers_config);
1481                 return;
1482         } else if (service->nameservers != NULL) {
1483                 append_nameserver(iter, &service->nameservers);
1484                 return;
1485         }
1486 }
1487
1488 static void append_dnsconfig(DBusMessageIter *iter, void *user_data)
1489 {
1490         struct connman_service *service = user_data;
1491         int i;
1492
1493         if (service->nameservers_config == NULL)
1494                 return;
1495
1496         for (i = 0; service->nameservers_config[i]; i++) {
1497                 dbus_message_iter_append_basic(iter,
1498                                 DBUS_TYPE_STRING,
1499                                 &service->nameservers_config[i]);
1500         }
1501 }
1502
1503 static void append_domain(DBusMessageIter *iter, void *user_data)
1504 {
1505         struct connman_service *service = user_data;
1506
1507         if (is_connected(service) == FALSE &&
1508                                 is_connecting(service) == FALSE)
1509                 return;
1510
1511         if (service->domainname == NULL)
1512                 return;
1513
1514         dbus_message_iter_append_basic(iter,
1515                                 DBUS_TYPE_STRING, &service->domainname);
1516 }
1517
1518 static void append_domainconfig(DBusMessageIter *iter, void *user_data)
1519 {
1520         struct connman_service *service = user_data;
1521         int i;
1522
1523         if (service->domains == NULL)
1524                 return;
1525
1526         for (i = 0; service->domains[i]; i++)
1527                 dbus_message_iter_append_basic(iter,
1528                                 DBUS_TYPE_STRING, &service->domains[i]);
1529 }
1530
1531 static void append_proxies(DBusMessageIter *iter, void *user_data)
1532 {
1533         struct connman_service *service = user_data;
1534         int i;
1535
1536         if (service->proxies == NULL)
1537                 return;
1538
1539         for (i = 0; service->proxies[i]; i++)
1540                 dbus_message_iter_append_basic(iter,
1541                                 DBUS_TYPE_STRING, &service->proxies[i]);
1542 }
1543
1544 static void append_excludes(DBusMessageIter *iter, void *user_data)
1545 {
1546         struct connman_service *service = user_data;
1547         int i;
1548
1549         if (service->excludes == NULL)
1550                 return;
1551
1552         for (i = 0; service->excludes[i]; i++)
1553                 dbus_message_iter_append_basic(iter,
1554                                 DBUS_TYPE_STRING, &service->excludes[i]);
1555 }
1556
1557 static void append_proxy(DBusMessageIter *iter, void *user_data)
1558 {
1559         struct connman_service *service = user_data;
1560         enum connman_service_proxy_method proxy;
1561         const char *pac = NULL;
1562         const char *method = proxymethod2string(
1563                 CONNMAN_SERVICE_PROXY_METHOD_DIRECT);
1564
1565         DBG("");
1566
1567         if (is_connected(service) == FALSE)
1568                 return;
1569
1570         proxy = connman_service_get_proxy_method(service);
1571
1572         switch (proxy) {
1573         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
1574                 return;
1575         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
1576                 goto done;
1577         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
1578                 connman_dbus_dict_append_array(iter, "Servers",
1579                                         DBUS_TYPE_STRING, append_proxies,
1580                                         service);
1581
1582                 connman_dbus_dict_append_array(iter, "Excludes",
1583                                         DBUS_TYPE_STRING, append_excludes,
1584                                         service);
1585                 break;
1586         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
1587                 /* Maybe DHCP, or WPAD,  has provided an url for a pac file */
1588                 if (service->ipconfig_ipv4 != NULL)
1589                         pac = __connman_ipconfig_get_proxy_autoconfig(
1590                                 service->ipconfig_ipv4);
1591                 else if (service->ipconfig_ipv6 != NULL)
1592                         pac = __connman_ipconfig_get_proxy_autoconfig(
1593                                 service->ipconfig_ipv6);
1594
1595                 if (service->pac == NULL && pac == NULL)
1596                         goto done;
1597
1598                 if (service->pac != NULL)
1599                         pac = service->pac;
1600
1601                 connman_dbus_dict_append_basic(iter, "URL",
1602                                         DBUS_TYPE_STRING, &pac);
1603                 break;
1604         }
1605
1606         method = proxymethod2string(proxy);
1607
1608 done:
1609         connman_dbus_dict_append_basic(iter, "Method",
1610                                         DBUS_TYPE_STRING, &method);
1611 }
1612
1613 static void append_proxyconfig(DBusMessageIter *iter, void *user_data)
1614 {
1615         struct connman_service *service = user_data;
1616         const char *method;
1617
1618         if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
1619                 return;
1620
1621         switch (service->proxy_config) {
1622         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
1623                 return;
1624         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
1625                 break;
1626         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
1627                 if (service->proxies != NULL)
1628                         connman_dbus_dict_append_array(iter, "Servers",
1629                                                 DBUS_TYPE_STRING,
1630                                                 append_proxies, service);
1631
1632                 if (service->excludes != NULL)
1633                         connman_dbus_dict_append_array(iter, "Excludes",
1634                                                 DBUS_TYPE_STRING,
1635                                                 append_excludes, service);
1636                 break;
1637         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
1638                 if (service->pac != NULL)
1639                         connman_dbus_dict_append_basic(iter, "URL",
1640                                         DBUS_TYPE_STRING, &service->pac);
1641                 break;
1642         }
1643
1644         method = proxymethod2string(service->proxy_config);
1645
1646         connman_dbus_dict_append_basic(iter, "Method",
1647                                 DBUS_TYPE_STRING, &method);
1648 }
1649
1650 static void append_provider(DBusMessageIter *iter, void *user_data)
1651 {
1652         struct connman_service *service = user_data;
1653
1654         DBG("%p %p", service, service->provider);
1655
1656         if (is_connected(service) == FALSE)
1657                 return;
1658
1659         if (service->provider != NULL)
1660                 __connman_provider_append_properties(service->provider, iter);
1661 }
1662
1663
1664 static void settings_changed(struct connman_service *service,
1665                                 struct connman_ipconfig *ipconfig)
1666 {
1667         connman_dbus_property_changed_dict(service->path,
1668                                         CONNMAN_SERVICE_INTERFACE, "IPv4",
1669                                                         append_ipv4, service);
1670
1671         connman_dbus_property_changed_dict(service->path,
1672                                         CONNMAN_SERVICE_INTERFACE, "IPv6",
1673                                                         append_ipv6, service);
1674
1675         __connman_notifier_ipconfig_changed(service, ipconfig);
1676 }
1677
1678 static void ipv4_configuration_changed(struct connman_service *service)
1679 {
1680         connman_dbus_property_changed_dict(service->path,
1681                                         CONNMAN_SERVICE_INTERFACE,
1682                                                         "IPv4.Configuration",
1683                                                         append_ipv4config,
1684                                                         service);
1685 }
1686
1687 static void ipv6_configuration_changed(struct connman_service *service)
1688 {
1689         connman_dbus_property_changed_dict(service->path,
1690                                         CONNMAN_SERVICE_INTERFACE,
1691                                                         "IPv6.Configuration",
1692                                                         append_ipv6config,
1693                                                         service);
1694 }
1695
1696 static void dns_changed(struct connman_service *service)
1697 {
1698         connman_dbus_property_changed_array(service->path,
1699                                 CONNMAN_SERVICE_INTERFACE, "Nameservers",
1700                                         DBUS_TYPE_STRING, append_dns, service);
1701 }
1702
1703 static void dns_configuration_changed(struct connman_service *service)
1704 {
1705         connman_dbus_property_changed_array(service->path,
1706                                 CONNMAN_SERVICE_INTERFACE,
1707                                 "Nameservers.Configuration",
1708                                 DBUS_TYPE_STRING, append_dnsconfig, service);
1709
1710         dns_changed(service);
1711 }
1712
1713 static void domain_changed(struct connman_service *service)
1714 {
1715         connman_dbus_property_changed_array(service->path,
1716                                 CONNMAN_SERVICE_INTERFACE, "Domains",
1717                                 DBUS_TYPE_STRING, append_domain, service);
1718 }
1719
1720 static void domain_configuration_changed(struct connman_service *service)
1721 {
1722         connman_dbus_property_changed_array(service->path,
1723                                 CONNMAN_SERVICE_INTERFACE,
1724                                 "Domains.Configuration",
1725                                 DBUS_TYPE_STRING, append_domainconfig, service);
1726 }
1727
1728 static void proxy_changed(struct connman_service *service)
1729 {
1730         connman_dbus_property_changed_dict(service->path,
1731                                         CONNMAN_SERVICE_INTERFACE, "Proxy",
1732                                                         append_proxy, service);
1733 }
1734
1735 static void proxy_configuration_changed(struct connman_service *service)
1736 {
1737         connman_dbus_property_changed_dict(service->path,
1738                         CONNMAN_SERVICE_INTERFACE, "Proxy.Configuration",
1739                                                 append_proxyconfig, service);
1740
1741         proxy_changed(service);
1742 }
1743
1744 static void link_changed(struct connman_service *service)
1745 {
1746         connman_dbus_property_changed_dict(service->path,
1747                                         CONNMAN_SERVICE_INTERFACE, "Ethernet",
1748                                                 append_ethernet, service);
1749 }
1750
1751 static void stats_append_counters(DBusMessageIter *dict,
1752                         struct connman_stats_data *stats,
1753                         struct connman_stats_data *counters,
1754                         connman_bool_t append_all)
1755 {
1756         if (counters->rx_packets != stats->rx_packets || append_all) {
1757                 counters->rx_packets = stats->rx_packets;
1758                 connman_dbus_dict_append_basic(dict, "RX.Packets",
1759                                         DBUS_TYPE_UINT32, &stats->rx_packets);
1760         }
1761
1762         if (counters->tx_packets != stats->tx_packets || append_all) {
1763                 counters->tx_packets = stats->tx_packets;
1764                 connman_dbus_dict_append_basic(dict, "TX.Packets",
1765                                         DBUS_TYPE_UINT32, &stats->tx_packets);
1766         }
1767
1768         if (counters->rx_bytes != stats->rx_bytes || append_all) {
1769                 counters->rx_bytes = stats->rx_bytes;
1770                 connman_dbus_dict_append_basic(dict, "RX.Bytes",
1771                                         DBUS_TYPE_UINT32, &stats->rx_bytes);
1772         }
1773
1774         if (counters->tx_bytes != stats->tx_bytes || append_all) {
1775                 counters->tx_bytes = stats->tx_bytes;
1776                 connman_dbus_dict_append_basic(dict, "TX.Bytes",
1777                                         DBUS_TYPE_UINT32, &stats->tx_bytes);
1778         }
1779
1780         if (counters->rx_errors != stats->rx_errors || append_all) {
1781                 counters->rx_errors = stats->rx_errors;
1782                 connman_dbus_dict_append_basic(dict, "RX.Errors",
1783                                         DBUS_TYPE_UINT32, &stats->rx_errors);
1784         }
1785
1786         if (counters->tx_errors != stats->tx_errors || append_all) {
1787                 counters->tx_errors = stats->tx_errors;
1788                 connman_dbus_dict_append_basic(dict, "TX.Errors",
1789                                         DBUS_TYPE_UINT32, &stats->tx_errors);
1790         }
1791
1792         if (counters->rx_dropped != stats->rx_dropped || append_all) {
1793                 counters->rx_dropped = stats->rx_dropped;
1794                 connman_dbus_dict_append_basic(dict, "RX.Dropped",
1795                                         DBUS_TYPE_UINT32, &stats->rx_dropped);
1796         }
1797
1798         if (counters->tx_dropped != stats->tx_dropped || append_all) {
1799                 counters->tx_dropped = stats->tx_dropped;
1800                 connman_dbus_dict_append_basic(dict, "TX.Dropped",
1801                                         DBUS_TYPE_UINT32, &stats->tx_dropped);
1802         }
1803
1804         if (counters->time != stats->time || append_all) {
1805                 counters->time = stats->time;
1806                 connman_dbus_dict_append_basic(dict, "Time",
1807                                         DBUS_TYPE_UINT32, &stats->time);
1808         }
1809 }
1810
1811 static void stats_append(struct connman_service *service,
1812                                 const char *counter,
1813                                 struct connman_stats_counter *counters,
1814                                 connman_bool_t append_all)
1815 {
1816         DBusMessageIter array, dict;
1817         DBusMessage *msg;
1818
1819         DBG("service %p counter %s", service, counter);
1820
1821         msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
1822         if (msg == NULL)
1823                 return;
1824
1825         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH,
1826                                 &service->path, DBUS_TYPE_INVALID);
1827
1828         dbus_message_iter_init_append(msg, &array);
1829
1830         /* home counter */
1831         connman_dbus_dict_open(&array, &dict);
1832
1833         stats_append_counters(&dict, &service->stats.data,
1834                                 &counters->stats.data, append_all);
1835
1836         connman_dbus_dict_close(&array, &dict);
1837
1838         /* roaming counter */
1839         connman_dbus_dict_open(&array, &dict);
1840
1841         stats_append_counters(&dict, &service->stats_roaming.data,
1842                                 &counters->stats_roaming.data, append_all);
1843
1844         connman_dbus_dict_close(&array, &dict);
1845
1846         __connman_counter_send_usage(counter, msg);
1847 }
1848
1849 static void stats_update(struct connman_service *service,
1850                                 unsigned int rx_packets, unsigned int tx_packets,
1851                                 unsigned int rx_bytes, unsigned int tx_bytes,
1852                                 unsigned int rx_errors, unsigned int tx_errors,
1853                                 unsigned int rx_dropped, unsigned int tx_dropped)
1854 {
1855         struct connman_stats *stats = stats_get(service);
1856         struct connman_stats_data *data_last = &stats->data_last;
1857         struct connman_stats_data *data = &stats->data;
1858         unsigned int seconds;
1859
1860         DBG("service %p", service);
1861
1862         if (stats->valid == TRUE) {
1863                 data->rx_packets +=
1864                         rx_packets - data_last->rx_packets;
1865                 data->tx_packets +=
1866                         tx_packets - data_last->tx_packets;
1867                 data->rx_bytes +=
1868                         rx_bytes - data_last->rx_bytes;
1869                 data->tx_bytes +=
1870                         tx_bytes - data_last->tx_bytes;
1871                 data->rx_errors +=
1872                         rx_errors - data_last->rx_errors;
1873                 data->tx_errors +=
1874                         tx_errors - data_last->tx_errors;
1875                 data->rx_dropped +=
1876                         rx_dropped - data_last->rx_dropped;
1877                 data->tx_dropped +=
1878                         tx_dropped - data_last->tx_dropped;
1879         } else {
1880                 stats->valid = TRUE;
1881         }
1882
1883         data_last->rx_packets = rx_packets;
1884         data_last->tx_packets = tx_packets;
1885         data_last->rx_bytes = rx_bytes;
1886         data_last->tx_bytes = tx_bytes;
1887         data_last->rx_errors = rx_errors;
1888         data_last->tx_errors = tx_errors;
1889         data_last->rx_dropped = rx_dropped;
1890         data_last->tx_dropped = tx_dropped;
1891
1892         seconds = g_timer_elapsed(stats->timer, NULL);
1893         stats->data.time = stats->data_last.time + seconds;
1894 }
1895
1896 static char *wifi_build_group_name(const unsigned char *ssid,
1897                                                 unsigned int ssid_len,
1898                                                         const char *mode,
1899                                                         const char *security)
1900 {
1901         GString *str;
1902         unsigned int i;
1903
1904         /* the last 3 is for the 2 '_' and '\0' */
1905         str = g_string_sized_new((ssid_len * 2) + strlen(mode)
1906                                         + strlen(security) + 3);
1907         if (str == NULL)
1908                 return NULL;
1909
1910         for (i = 0; i < ssid_len; i++)
1911                 g_string_append_printf(str, "%02x", ssid[i]);
1912
1913         g_string_append_printf(str, "_%s_%s", mode, security);
1914
1915         return g_string_free(str, FALSE);
1916 }
1917
1918 void __connman_service_notify(struct connman_service *service,
1919                         unsigned int rx_packets, unsigned int tx_packets,
1920                         unsigned int rx_bytes, unsigned int tx_bytes,
1921                         unsigned int rx_errors, unsigned int tx_errors,
1922                         unsigned int rx_dropped, unsigned int tx_dropped)
1923 {
1924         GHashTableIter iter;
1925         gpointer key, value;
1926         const char *counter;
1927         struct connman_stats_counter *counters;
1928         struct connman_stats_data *data;
1929         int err;
1930
1931         if (service == NULL)
1932                 return;
1933
1934         if (is_connected(service) == FALSE)
1935                 return;
1936
1937         stats_update(service,
1938                 rx_packets, tx_packets,
1939                 rx_bytes, tx_bytes,
1940                 rx_errors, tx_errors,
1941                 rx_dropped, tx_dropped);
1942
1943         data = &stats_get(service)->data;
1944         err = __connman_stats_update(service, service->roaming, data);
1945         if (err < 0)
1946                 connman_error("Failed to store statistics for %s",
1947                                 service->identifier);
1948
1949         g_hash_table_iter_init(&iter, service->counter_table);
1950         while (g_hash_table_iter_next(&iter, &key, &value)) {
1951                 counter = key;
1952                 counters = value;
1953
1954                 stats_append(service, counter, counters, counters->append_all);
1955                 counters->append_all = FALSE;
1956         }
1957 }
1958
1959 int __connman_service_counter_register(const char *counter)
1960 {
1961         struct connman_service *service;
1962         GSequenceIter *iter;
1963         struct connman_stats_counter *counters;
1964
1965         DBG("counter %s", counter);
1966
1967         counter_list = g_slist_append(counter_list, (gpointer)counter);
1968
1969         iter = g_sequence_get_begin_iter(service_list);
1970
1971         while (g_sequence_iter_is_end(iter) == FALSE) {
1972                 service = g_sequence_get(iter);
1973
1974                 counters = g_try_new0(struct connman_stats_counter, 1);
1975                 if (counters == NULL)
1976                         return -ENOMEM;
1977
1978                 counters->append_all = TRUE;
1979
1980                 g_hash_table_replace(service->counter_table, (gpointer)counter,
1981                                         counters);
1982
1983                 iter = g_sequence_iter_next(iter);
1984         }
1985
1986         return 0;
1987 }
1988
1989 void __connman_service_counter_unregister(const char *counter)
1990 {
1991         struct connman_service *service;
1992         GSequenceIter *iter;
1993
1994         DBG("counter %s", counter);
1995
1996         iter = g_sequence_get_begin_iter(service_list);
1997
1998         while (g_sequence_iter_is_end(iter) == FALSE) {
1999                 service = g_sequence_get(iter);
2000
2001                 g_hash_table_remove(service->counter_table, counter);
2002
2003                 iter = g_sequence_iter_next(iter);
2004         }
2005
2006         counter_list = g_slist_remove(counter_list, counter);
2007 }
2008
2009 GSequence *__connman_service_get_list(struct connman_session *session,
2010                                 service_match_cb service_match,
2011                                 create_service_entry_cb create_service_entry,
2012                                 GDestroyNotify destroy_service_entry)
2013 {
2014         GSequence *list;
2015         GSequenceIter *iter;
2016         struct connman_service *service;
2017         struct service_entry *entry;
2018
2019         list = g_sequence_new(destroy_service_entry);
2020         if (list == NULL)
2021                 return NULL;
2022
2023         iter = g_sequence_get_begin_iter(service_list);
2024
2025         while (g_sequence_iter_is_end(iter) == FALSE) {
2026                 service = g_sequence_get(iter);
2027
2028                 if (service_match(session, service) == TRUE) {
2029                         entry = create_service_entry(service, service->name,
2030                                                         service->state);
2031                         if (entry == NULL)
2032                                 return list;
2033
2034                         g_sequence_append(list, entry);
2035                 }
2036
2037                 iter = g_sequence_iter_next(iter);
2038         }
2039
2040         return list;
2041 }
2042
2043 void __connman_service_session_inc(struct connman_service *service)
2044 {
2045         DBG("service %p ref count %d", service,
2046                 g_atomic_int_get(&service->session_usage_count) + 1);
2047
2048         g_atomic_int_inc(&service->session_usage_count);
2049 }
2050
2051 connman_bool_t __connman_service_session_dec(struct connman_service *service)
2052 {
2053         DBG("service %p ref count %d", service,
2054                 g_atomic_int_get(&service->session_usage_count) - 1);
2055
2056         if (g_atomic_int_dec_and_test(&service->session_usage_count) == FALSE)
2057                 return FALSE;
2058
2059         return TRUE;
2060 }
2061
2062 static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
2063                                         struct connman_service *service)
2064 {
2065         dbus_bool_t required;
2066         const char *str;
2067
2068         str = __connman_service_type2string(service->type);
2069         if (str != NULL)
2070                 connman_dbus_dict_append_basic(dict, "Type",
2071                                                 DBUS_TYPE_STRING, &str);
2072
2073         connman_dbus_dict_append_array(dict, "Security",
2074                                 DBUS_TYPE_STRING, append_security, service);
2075
2076         str = state2string(service->state);
2077         if (str != NULL)
2078                 connman_dbus_dict_append_basic(dict, "State",
2079                                                 DBUS_TYPE_STRING, &str);
2080
2081         str = error2string(service->error);
2082         if (str != NULL)
2083                 connman_dbus_dict_append_basic(dict, "Error",
2084                                                 DBUS_TYPE_STRING, &str);
2085
2086         if (service->strength > 0)
2087                 connman_dbus_dict_append_basic(dict, "Strength",
2088                                         DBUS_TYPE_BYTE, &service->strength);
2089
2090         connman_dbus_dict_append_basic(dict, "Favorite",
2091                                         DBUS_TYPE_BOOLEAN, &service->favorite);
2092
2093         connman_dbus_dict_append_basic(dict, "Immutable",
2094                                         DBUS_TYPE_BOOLEAN, &service->immutable);
2095
2096         if (service->favorite == TRUE)
2097                 connman_dbus_dict_append_basic(dict, "AutoConnect",
2098                                 DBUS_TYPE_BOOLEAN, &service->autoconnect);
2099         else
2100                 connman_dbus_dict_append_basic(dict, "AutoConnect",
2101                                         DBUS_TYPE_BOOLEAN, &service->favorite);
2102
2103         if (service->name != NULL)
2104                 connman_dbus_dict_append_basic(dict, "Name",
2105                                         DBUS_TYPE_STRING, &service->name);
2106
2107         connman_dbus_dict_append_basic(dict, "LoginRequired",
2108                                 DBUS_TYPE_BOOLEAN, &service->login_required);
2109
2110         switch (service->type) {
2111         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2112         case CONNMAN_SERVICE_TYPE_SYSTEM:
2113         case CONNMAN_SERVICE_TYPE_GPS:
2114         case CONNMAN_SERVICE_TYPE_VPN:
2115         case CONNMAN_SERVICE_TYPE_GADGET:
2116                 break;
2117         case CONNMAN_SERVICE_TYPE_CELLULAR:
2118                 connman_dbus_dict_append_basic(dict, "Roaming",
2119                                         DBUS_TYPE_BOOLEAN, &service->roaming);
2120
2121                 required = FALSE;
2122                 connman_dbus_dict_append_basic(dict, "SetupRequired",
2123                                                 DBUS_TYPE_BOOLEAN, &required);
2124                 connman_dbus_dict_append_dict(dict, "Ethernet",
2125                                                 append_ethernet, service);
2126                 break;
2127         case CONNMAN_SERVICE_TYPE_WIFI:
2128                 if (service->passphrase != NULL && limited == FALSE)
2129                         connman_dbus_dict_append_basic(dict, "Passphrase",
2130                                 DBUS_TYPE_STRING, &service->passphrase);
2131
2132                 required = FALSE;
2133
2134                 switch (service->security) {
2135                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
2136                 case CONNMAN_SERVICE_SECURITY_NONE:
2137                         break;
2138                 case CONNMAN_SERVICE_SECURITY_WEP:
2139                 case CONNMAN_SERVICE_SECURITY_PSK:
2140                 case CONNMAN_SERVICE_SECURITY_WPA:
2141                 case CONNMAN_SERVICE_SECURITY_RSN:
2142                         if (service->passphrase == NULL)
2143                                 required = TRUE;
2144                         break;
2145                 case CONNMAN_SERVICE_SECURITY_8021X:
2146                         break;
2147                 }
2148
2149                 connman_dbus_dict_append_basic(dict, "PassphraseRequired",
2150                                                 DBUS_TYPE_BOOLEAN, &required);
2151
2152                 /* fall through */
2153         case CONNMAN_SERVICE_TYPE_ETHERNET:
2154         case CONNMAN_SERVICE_TYPE_WIMAX:
2155         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2156                 connman_dbus_dict_append_dict(dict, "Ethernet",
2157                                                 append_ethernet, service);
2158                 break;
2159         }
2160
2161         connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service);
2162
2163         connman_dbus_dict_append_dict(dict, "IPv4.Configuration",
2164                                                 append_ipv4config, service);
2165
2166         connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service);
2167
2168         connman_dbus_dict_append_dict(dict, "IPv6.Configuration",
2169                                                 append_ipv6config, service);
2170
2171         connman_dbus_dict_append_array(dict, "Nameservers",
2172                                 DBUS_TYPE_STRING, append_dns, service);
2173
2174         connman_dbus_dict_append_array(dict, "Nameservers.Configuration",
2175                                 DBUS_TYPE_STRING, append_dnsconfig, service);
2176
2177         connman_dbus_dict_append_array(dict, "Domains",
2178                                 DBUS_TYPE_STRING, append_domain, service);
2179
2180         connman_dbus_dict_append_array(dict, "Domains.Configuration",
2181                                 DBUS_TYPE_STRING, append_domainconfig, service);
2182
2183         connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service);
2184
2185         connman_dbus_dict_append_dict(dict, "Proxy.Configuration",
2186                                                 append_proxyconfig, service);
2187
2188         connman_dbus_dict_append_dict(dict, "Provider",
2189                                                 append_provider, service);
2190 }
2191
2192 static void append_struct(gpointer value, gpointer user_data)
2193 {
2194         struct connman_service *service = value;
2195         DBusMessageIter *iter = user_data;
2196         DBusMessageIter entry, dict;
2197
2198         if (service->path == NULL || service->hidden == TRUE)
2199                 return;
2200
2201         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
2202
2203         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
2204                                                         &service->path);
2205
2206         connman_dbus_dict_open(&entry, &dict);
2207         append_properties(&dict, TRUE, service);
2208         connman_dbus_dict_close(&entry, &dict);
2209
2210         dbus_message_iter_close_container(iter, &entry);
2211 }
2212
2213 void __connman_service_list_struct(DBusMessageIter *iter)
2214 {
2215         g_sequence_foreach(service_list, append_struct, iter);
2216 }
2217
2218 int __connman_service_get_index(struct connman_service *service)
2219 {
2220         if (service == NULL)
2221                 return -1;
2222
2223         if (service->network != NULL)
2224                 return connman_network_get_index(service->network);
2225         else if (service->provider != NULL)
2226                 return connman_provider_get_index(service->provider);
2227
2228         return -1;
2229 }
2230
2231 void __connman_service_set_domainname(struct connman_service *service,
2232                                                 const char *domainname)
2233 {
2234         if (service == NULL)
2235                 return;
2236
2237         g_free(service->domainname);
2238         service->domainname = g_strdup(domainname);
2239
2240         domain_changed(service);
2241 }
2242
2243 const char *connman_service_get_domainname(struct connman_service *service)
2244 {
2245         if (service == NULL)
2246                 return NULL;
2247
2248         if (service->domains != NULL)
2249                 return service->domains[0];
2250         else
2251                 return service->domainname;
2252 }
2253
2254 char **connman_service_get_nameservers(struct connman_service *service)
2255 {
2256         if (service == NULL)
2257                 return NULL;
2258
2259         if (service->nameservers_config != NULL)
2260                 return service->nameservers_config;
2261         else if (service->nameservers != NULL)
2262                 return service->nameservers;
2263
2264         return NULL;
2265 }
2266
2267 void connman_service_set_proxy_method(struct connman_service *service,
2268                                         enum connman_service_proxy_method method)
2269 {
2270         if (service == NULL)
2271                 return;
2272
2273         service->proxy = method;
2274
2275         proxy_changed(service);
2276
2277         if (method != CONNMAN_SERVICE_PROXY_METHOD_AUTO)
2278                 __connman_notifier_proxy_changed(service);
2279 }
2280
2281 enum connman_service_proxy_method connman_service_get_proxy_method(
2282                                         struct connman_service *service)
2283 {
2284         if (service == NULL)
2285                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
2286
2287         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) {
2288                 if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_AUTO &&
2289                                 service->pac == NULL)
2290                         return service->proxy;
2291
2292                 return service->proxy_config;
2293         }
2294
2295         return service->proxy;
2296 }
2297
2298 char **connman_service_get_proxy_servers(struct connman_service *service)
2299 {
2300         return g_strdupv(service->proxies);
2301 }
2302
2303 char **connman_service_get_proxy_excludes(struct connman_service *service)
2304 {
2305         return g_strdupv(service->excludes);
2306 }
2307
2308 const char *connman_service_get_proxy_url(struct connman_service *service)
2309 {
2310         if (service == NULL)
2311                 return NULL;
2312
2313         return service->pac;
2314 }
2315
2316 void __connman_service_set_proxy_autoconfig(struct connman_service *service,
2317                                                         const char *url)
2318 {
2319         if (service == NULL)
2320                 return;
2321
2322         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_AUTO;
2323
2324         if (service->ipconfig_ipv4) {
2325                 if (__connman_ipconfig_set_proxy_autoconfig(
2326                             service->ipconfig_ipv4, url) < 0)
2327                         return;
2328         } else if (service->ipconfig_ipv6) {
2329                 if (__connman_ipconfig_set_proxy_autoconfig(
2330                             service->ipconfig_ipv6, url) < 0)
2331                         return;
2332         } else
2333                 return;
2334
2335         proxy_changed(service);
2336
2337         __connman_notifier_proxy_changed(service);
2338 }
2339
2340 const char *connman_service_get_proxy_autoconfig(struct connman_service *service)
2341 {
2342         if (service == NULL)
2343                 return NULL;
2344
2345         if (service->ipconfig_ipv4)
2346                 return __connman_ipconfig_get_proxy_autoconfig(
2347                                                 service->ipconfig_ipv4);
2348         else if (service->ipconfig_ipv6)
2349                 return __connman_ipconfig_get_proxy_autoconfig(
2350                                                 service->ipconfig_ipv6);
2351         return NULL;
2352 }
2353
2354 static void update_timeservers(struct connman_service *service)
2355 {
2356         int i;
2357
2358         if (service->timeservers == NULL)
2359                 return;
2360
2361         switch (service->state) {
2362         case CONNMAN_SERVICE_STATE_UNKNOWN:
2363         case CONNMAN_SERVICE_STATE_IDLE:
2364         case CONNMAN_SERVICE_STATE_ASSOCIATION:
2365         case CONNMAN_SERVICE_STATE_CONFIGURATION:
2366                 return;
2367         case CONNMAN_SERVICE_STATE_FAILURE:
2368         case CONNMAN_SERVICE_STATE_DISCONNECT:
2369                 for (i = 0; service->timeservers[i] != NULL; i++)
2370                         connman_timeserver_remove(service->timeservers[i]);
2371                 return;
2372         case CONNMAN_SERVICE_STATE_READY:
2373         case CONNMAN_SERVICE_STATE_ONLINE:
2374                 break;
2375         }
2376
2377         for (i = 0; service->timeservers[i] != NULL; i++)
2378                 connman_timeserver_append(service->timeservers[i]);
2379 }
2380
2381 int __connman_service_timeserver_append(struct connman_service *service,
2382                                                 const char *timeserver)
2383 {
2384         int len;
2385
2386         DBG("service %p timeserver %s", service, timeserver);
2387
2388         if (timeserver == NULL)
2389                 return -EINVAL;
2390
2391         if (service->timeservers != NULL) {
2392                 int i;
2393
2394                 for (i = 0; service->timeservers[i] != NULL; i++)
2395                         if (g_strcmp0(service->timeservers[i], timeserver) == 0)
2396                                 return -EEXIST;
2397
2398                 len = g_strv_length(service->timeservers);
2399                 service->timeservers = g_try_renew(char *, service->timeservers,
2400                                                         len + 2);
2401         } else {
2402                 len = 0;
2403                 service->timeservers = g_try_new0(char *, len + 2);
2404         }
2405
2406         if (service->timeservers == NULL)
2407                 return -ENOMEM;
2408
2409         service->timeservers[len] = g_strdup(timeserver);
2410         service->timeservers[len + 1] = NULL;
2411
2412         update_timeservers(service);
2413
2414         return 0;
2415 }
2416
2417 int __connman_service_timeserver_remove(struct connman_service *service,
2418                                                 const char *timeserver)
2419 {
2420         char **servers;
2421         int len, i, j;
2422
2423         DBG("service %p timeserver %s", service, timeserver);
2424
2425         if (timeserver == NULL)
2426                 return -EINVAL;
2427
2428         if (service->timeservers == NULL)
2429                 return 0;
2430
2431         len = g_strv_length(service->timeservers);
2432         if (len == 1) {
2433                 if (g_strcmp0(service->timeservers[0], timeserver) != 0)
2434                         return 0;
2435
2436                 g_strfreev(service->timeservers);
2437                 service->timeservers = NULL;
2438
2439                 return 0;
2440         }
2441
2442         servers = g_try_new0(char *, len - 1);
2443         if (servers == NULL)
2444                 return -ENOMEM;
2445
2446         for (i = 0, j = 0; i < len; i++) {
2447                 if (g_strcmp0(service->timeservers[i], timeserver) != 0) {
2448                         servers[j] = g_strdup(service->timeservers[i]);
2449                         j++;
2450                 }
2451         }
2452         servers[len - 2] = NULL;
2453
2454         g_strfreev(service->timeservers);
2455         service->timeservers = servers;
2456
2457         update_timeservers(service);
2458
2459         return 0;
2460 }
2461
2462 void __connman_service_set_pac(struct connman_service *service,
2463                                         const char *pac)
2464 {
2465         g_free(service->pac);
2466         service->pac = g_strdup(pac);
2467
2468         proxy_changed(service);
2469 }
2470
2471 void __connman_service_set_identity(struct connman_service *service,
2472                                         const char *identity)
2473 {
2474         if (service->immutable)
2475                 return;
2476
2477         g_free(service->identity);
2478         service->identity = g_strdup(identity);
2479
2480         if (service->network != NULL)
2481                 connman_network_set_string(service->network,
2482                                         "WiFi.Identity",
2483                                         service->identity);
2484 }
2485
2486 void __connman_service_set_agent_identity(struct connman_service *service,
2487                                                 const char *agent_identity)
2488 {
2489         g_free(service->agent_identity);
2490         service->agent_identity = g_strdup(agent_identity);
2491
2492         if (service->network != NULL)
2493                 connman_network_set_string(service->network,
2494                                         "WiFi.AgentIdentity",
2495                                         service->agent_identity);
2496 }
2497
2498 void __connman_service_set_passphrase(struct connman_service *service,
2499                                         const char* passphrase)
2500 {
2501         if (service->immutable == TRUE)
2502                 return;
2503
2504         g_free(service->passphrase);
2505         service->passphrase = g_strdup(passphrase);
2506
2507         passphrase_changed(service);
2508
2509         if (service->network != NULL)
2510                 connman_network_set_string(service->network,
2511                                         "WiFi.Passphrase",
2512                                         service->passphrase);
2513
2514         service_save(service);
2515 }
2516
2517 void __connman_service_set_agent_passphrase(struct connman_service *service,
2518                                                 const char *agent_passphrase)
2519 {
2520         g_free(service->agent_passphrase);
2521         service->agent_passphrase = g_strdup(agent_passphrase);
2522
2523         if (service->network != NULL)
2524                 connman_network_set_string(service->network,
2525                                         "WiFi.AgentPassphrase",
2526                                         service->agent_passphrase);
2527 }
2528
2529 static DBusMessage *get_properties(DBusConnection *conn,
2530                                         DBusMessage *msg, void *user_data)
2531 {
2532         struct connman_service *service = user_data;
2533         DBusMessage *reply;
2534         DBusMessageIter array, dict;
2535
2536         DBG("service %p", service);
2537
2538         reply = dbus_message_new_method_return(msg);
2539         if (reply == NULL)
2540                 return NULL;
2541
2542         dbus_message_iter_init_append(reply, &array);
2543
2544         connman_dbus_dict_open(&array, &dict);
2545         append_properties(&dict, FALSE, service);
2546         connman_dbus_dict_close(&array, &dict);
2547
2548         return reply;
2549 }
2550
2551 static int update_proxy_configuration(struct connman_service *service,
2552                                 DBusMessageIter *array)
2553 {
2554         DBusMessageIter dict;
2555         enum connman_service_proxy_method method;
2556         GString *servers_str = NULL;
2557         GString *excludes_str = NULL;
2558         const char *url = NULL;
2559
2560         method = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
2561
2562         dbus_message_iter_recurse(array, &dict);
2563
2564         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2565                 DBusMessageIter entry, variant;
2566                 const char *key;
2567                 int type;
2568
2569                 dbus_message_iter_recurse(&dict, &entry);
2570
2571                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2572                         goto error;
2573
2574                 dbus_message_iter_get_basic(&entry, &key);
2575                 dbus_message_iter_next(&entry);
2576
2577                 if (dbus_message_iter_get_arg_type(&entry) !=
2578                                                         DBUS_TYPE_VARIANT)
2579                         goto error;
2580
2581                 dbus_message_iter_recurse(&entry, &variant);
2582                 type = dbus_message_iter_get_arg_type(&variant);
2583
2584                 if (g_str_equal(key, "Method") == TRUE) {
2585                         const char *val;
2586
2587                         if (type != DBUS_TYPE_STRING)
2588                                 goto error;
2589
2590                         dbus_message_iter_get_basic(&variant, &val);
2591                         method = string2proxymethod(val);
2592                 } else if (g_str_equal(key, "URL") == TRUE) {
2593                         if (type != DBUS_TYPE_STRING)
2594                                 goto error;
2595
2596                         dbus_message_iter_get_basic(&variant, &url);
2597                 } else if (g_str_equal(key, "Servers") == TRUE) {
2598                         DBusMessageIter str_array;
2599
2600                         if (type != DBUS_TYPE_ARRAY)
2601                                 goto error;
2602
2603                         servers_str = g_string_new(NULL);
2604                         if (servers_str == NULL)
2605                                 goto error;
2606
2607                         dbus_message_iter_recurse(&variant, &str_array);
2608
2609                         while (dbus_message_iter_get_arg_type(&str_array) ==
2610                                                         DBUS_TYPE_STRING) {
2611                                 char *val = NULL;
2612
2613                                 dbus_message_iter_get_basic(&str_array, &val);
2614
2615                                 if (servers_str->len > 0)
2616                                         g_string_append_printf(servers_str,
2617                                                         " %s", val);
2618                                 else
2619                                         g_string_append(servers_str, val);
2620
2621                                 dbus_message_iter_next(&str_array);
2622                         }
2623                 } else if (g_str_equal(key, "Excludes") == TRUE) {
2624                         DBusMessageIter str_array;
2625
2626                         if (type != DBUS_TYPE_ARRAY)
2627                                 goto error;
2628
2629                         excludes_str = g_string_new(NULL);
2630                         if (excludes_str == NULL)
2631                                 goto error;
2632
2633                         dbus_message_iter_recurse(&variant, &str_array);
2634
2635                         while (dbus_message_iter_get_arg_type(&str_array) ==
2636                                                         DBUS_TYPE_STRING) {
2637                                 char *val = NULL;
2638
2639                                 dbus_message_iter_get_basic(&str_array, &val);
2640
2641                                 if (excludes_str->len > 0)
2642                                         g_string_append_printf(excludes_str,
2643                                                         " %s", val);
2644                                 else
2645                                         g_string_append(excludes_str, val);
2646
2647                                 dbus_message_iter_next(&str_array);
2648                         }
2649                 }
2650
2651                 dbus_message_iter_next(&dict);
2652         }
2653
2654         switch (method) {
2655         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
2656                 break;
2657         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
2658                 if (servers_str == NULL && service->proxies == NULL)
2659                         goto error;
2660
2661                 if (servers_str != NULL) {
2662                         g_strfreev(service->proxies);
2663
2664                         if (servers_str->len > 0)
2665                                 service->proxies = g_strsplit_set(
2666                                         servers_str->str, " ", 0);
2667                         else
2668                                 service->proxies = NULL;
2669                 }
2670
2671                 if (excludes_str != NULL) {
2672                         g_strfreev(service->excludes);
2673
2674                         if (excludes_str->len > 0)
2675                                 service->excludes = g_strsplit_set(
2676                                         excludes_str->str, " ", 0);
2677                         else
2678                                 service->excludes = NULL;
2679                 }
2680
2681                 if (service->proxies == NULL)
2682                         method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
2683
2684                 break;
2685         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
2686                 g_free(service->pac);
2687
2688                 if (url != NULL && strlen(url) > 0)
2689                         service->pac = g_strdup(url);
2690                 else
2691                         service->pac = NULL;
2692
2693                 /* if we are connected:
2694                    - if service->pac == NULL
2695                    - if __connman_ipconfig_get_proxy_autoconfig(
2696                    service->ipconfig) == NULL
2697                    --> We should start WPAD */
2698
2699                 break;
2700         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
2701                 goto error;
2702         }
2703
2704         if (servers_str != NULL)
2705                 g_string_free(servers_str, TRUE);
2706
2707         if (excludes_str != NULL)
2708                 g_string_free(excludes_str, TRUE);
2709
2710         service->proxy_config = method;
2711
2712         return 0;
2713
2714 error:
2715         if (servers_str != NULL)
2716                 g_string_free(servers_str, TRUE);
2717
2718         if (excludes_str != NULL)
2719                 g_string_free(excludes_str, TRUE);
2720
2721         return -EINVAL;
2722 }
2723
2724 static int set_ipconfig(struct connman_service *service,
2725                         struct connman_ipconfig *ipconfig,
2726                         DBusMessageIter *array,
2727                         enum connman_service_state state,
2728                         enum connman_service_state *new_state)
2729 {
2730         enum connman_ipconfig_method old_method;
2731         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
2732         enum connman_ipconfig_type type;
2733         int err;
2734
2735         if (ipconfig == NULL)
2736                 return -EINVAL;
2737
2738         old_method = __connman_ipconfig_get_method(ipconfig);
2739
2740         if (is_connecting_state(service, state) ||
2741                                         is_connected_state(service, state))
2742                 __connman_network_clear_ipconfig(service->network, ipconfig);
2743
2744         err = __connman_ipconfig_set_config(ipconfig, array);
2745         method = __connman_ipconfig_get_method(ipconfig);
2746         type = __connman_ipconfig_get_config_type(ipconfig);
2747
2748         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
2749                 if (err == 0 && old_method == CONNMAN_IPCONFIG_METHOD_OFF &&
2750                                 method == CONNMAN_IPCONFIG_METHOD_DHCP) {
2751                         *new_state = service->state_ipv4 =
2752                                 CONNMAN_SERVICE_STATE_CONFIGURATION;
2753                         __connman_ipconfig_enable(ipconfig);
2754                 }
2755
2756         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
2757                 if (err == 0 && old_method == CONNMAN_IPCONFIG_METHOD_OFF &&
2758                                 method == CONNMAN_IPCONFIG_METHOD_AUTO) {
2759                         *new_state = service->state_ipv6;
2760                         __connman_ipconfig_enable(ipconfig);
2761                 }
2762         }
2763
2764         DBG("err %d ipconfig %p type %d method %d state %s", err, ipconfig,
2765                 type, method, state2string(*new_state));
2766
2767         return err;
2768 }
2769
2770 static DBusMessage *set_property(DBusConnection *conn,
2771                                         DBusMessage *msg, void *user_data)
2772 {
2773         struct connman_service *service = user_data;
2774         DBusMessageIter iter, value;
2775         const char *name;
2776         int type;
2777
2778         DBG("service %p", service);
2779
2780         if (dbus_message_iter_init(msg, &iter) == FALSE)
2781                 return __connman_error_invalid_arguments(msg);
2782
2783         dbus_message_iter_get_basic(&iter, &name);
2784         dbus_message_iter_next(&iter);
2785         dbus_message_iter_recurse(&iter, &value);
2786
2787         type = dbus_message_iter_get_arg_type(&value);
2788
2789         if (g_str_equal(name, "AutoConnect") == TRUE) {
2790                 connman_bool_t autoconnect;
2791
2792                 if (type != DBUS_TYPE_BOOLEAN)
2793                         return __connman_error_invalid_arguments(msg);
2794
2795                 if (service->favorite == FALSE)
2796                         return __connman_error_invalid_service(msg);
2797
2798                 dbus_message_iter_get_basic(&value, &autoconnect);
2799
2800                 if (service->autoconnect == autoconnect)
2801                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2802
2803                 service->autoconnect = autoconnect;
2804
2805                 autoconnect_changed(service);
2806
2807                 service_save(service);
2808         } else if (g_str_equal(name, "Passphrase") == TRUE) {
2809                 const char *passphrase;
2810
2811                 if (type != DBUS_TYPE_STRING)
2812                         return __connman_error_invalid_arguments(msg);
2813
2814                 if (service->immutable == TRUE)
2815                         return __connman_error_not_supported(msg);
2816
2817                 dbus_message_iter_get_basic(&value, &passphrase);
2818
2819                 __connman_service_set_passphrase(service, passphrase);
2820         } else if (g_str_equal(name, "Nameservers.Configuration") == TRUE) {
2821                 DBusMessageIter entry;
2822                 GString *str;
2823                 int index;
2824                 const char *gw;
2825
2826                 if (type != DBUS_TYPE_ARRAY)
2827                         return __connman_error_invalid_arguments(msg);
2828
2829                 str = g_string_new(NULL);
2830                 if (str == NULL)
2831                         return __connman_error_invalid_arguments(msg);
2832
2833                 index = connman_network_get_index(service->network);
2834                 gw = __connman_ipconfig_get_gateway_from_index(index);
2835
2836                 if (gw && strlen(gw))
2837                         __connman_service_nameserver_del_routes(service);
2838
2839                 dbus_message_iter_recurse(&value, &entry);
2840
2841                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
2842                         const char *val;
2843                         dbus_message_iter_get_basic(&entry, &val);
2844                         dbus_message_iter_next(&entry);
2845                         if (str->len > 0)
2846                                 g_string_append_printf(str, " %s", val);
2847                         else
2848                                 g_string_append(str, val);
2849                 }
2850
2851                 g_strfreev(service->nameservers_config);
2852
2853                 if (str->len > 0) {
2854                         service->nameservers_config =
2855                                 g_strsplit_set(str->str, " ", 0);
2856                 } else {
2857                         service->nameservers_config = NULL;
2858                 }
2859
2860                 g_string_free(str, TRUE);
2861
2862                 if (gw && strlen(gw))
2863                         __connman_service_nameserver_add_routes(service, gw);
2864
2865                 update_nameservers(service);
2866                 dns_configuration_changed(service);
2867
2868                 service_save(service);
2869         } else if (g_str_equal(name, "Domains.Configuration") == TRUE) {
2870                 DBusMessageIter entry;
2871                 GString *str;
2872
2873                 if (type != DBUS_TYPE_ARRAY)
2874                         return __connman_error_invalid_arguments(msg);
2875
2876                 str = g_string_new(NULL);
2877                 if (str == NULL)
2878                         return __connman_error_invalid_arguments(msg);
2879
2880                 dbus_message_iter_recurse(&value, &entry);
2881
2882                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
2883                         const char *val;
2884                         dbus_message_iter_get_basic(&entry, &val);
2885                         dbus_message_iter_next(&entry);
2886                         if (str->len > 0)
2887                                 g_string_append_printf(str, " %s", val);
2888                         else
2889                                 g_string_append(str, val);
2890                 }
2891
2892                 g_strfreev(service->domains);
2893
2894                 if (str->len > 0)
2895                         service->domains = g_strsplit_set(str->str, " ", 0);
2896                 else
2897                         service->domains = NULL;
2898
2899                 g_string_free(str, TRUE);
2900
2901                 update_nameservers(service);
2902                 domain_configuration_changed(service);
2903
2904                 service_save(service);
2905         } else if (g_str_equal(name, "Proxy.Configuration") == TRUE) {
2906                 int err;
2907
2908                 if (type != DBUS_TYPE_ARRAY)
2909                         return __connman_error_invalid_arguments(msg);
2910
2911                 err = update_proxy_configuration(service, &value);
2912
2913                 if (err < 0)
2914                         return __connman_error_failed(msg, -err);
2915
2916                 proxy_configuration_changed(service);
2917
2918                 __connman_notifier_proxy_changed(service);
2919
2920                 service_save(service);
2921         } else if (g_str_equal(name, "IPv4.Configuration") == TRUE ||
2922                         g_str_equal(name, "IPv6.Configuration")) {
2923
2924                 struct connman_ipconfig *ipv4 = NULL, *ipv6 = NULL;
2925                 enum connman_service_state state =
2926                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
2927                 int err = 0;
2928
2929                 DBG("%s", name);
2930
2931                 if (service->ipconfig_ipv4 == NULL &&
2932                                         service->ipconfig_ipv6 == NULL)
2933                         return __connman_error_invalid_property(msg);
2934
2935                 if (g_str_equal(name, "IPv4.Configuration") == TRUE) {
2936                         ipv4 = service->ipconfig_ipv4;
2937                         err = set_ipconfig(service, ipv4, &value,
2938                                         service->state_ipv4, &state);
2939
2940                 } else if (g_str_equal(name, "IPv6.Configuration") == TRUE) {
2941                         ipv6 = service->ipconfig_ipv6;
2942                         err = set_ipconfig(service, ipv6, &value,
2943                                         service->state_ipv6, &state);
2944                 }
2945
2946                 if (err < 0) {
2947                         if (is_connected_state(service, state) ||
2948                                         is_connecting_state(service, state))
2949                                 __connman_network_set_ipconfig(service->network,
2950                                                                 ipv4, ipv6);
2951                         return __connman_error_failed(msg, -err);
2952                 }
2953
2954                 if (ipv4)
2955                         ipv4_configuration_changed(service);
2956                 else if (ipv6)
2957                         ipv6_configuration_changed(service);
2958
2959                 if (is_connecting(service) || is_connected(service))
2960                         __connman_network_set_ipconfig(service->network,
2961                                                         ipv4, ipv6);
2962
2963                 service_save(service);
2964         } else
2965                 return __connman_error_invalid_property(msg);
2966
2967         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2968 }
2969
2970 static void set_idle(struct connman_service *service)
2971 {
2972         service->state = service->state_ipv4 = service->state_ipv6 =
2973                                                 CONNMAN_SERVICE_STATE_IDLE;
2974         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
2975         state_changed(service);
2976 }
2977
2978 static DBusMessage *clear_property(DBusConnection *conn,
2979                                         DBusMessage *msg, void *user_data)
2980 {
2981         struct connman_service *service = user_data;
2982         const char *name;
2983
2984         DBG("service %p", service);
2985
2986         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
2987                                                         DBUS_TYPE_INVALID);
2988
2989         if (g_str_equal(name, "Error") == TRUE) {
2990                 set_idle(service);
2991
2992                 g_get_current_time(&service->modified);
2993                 service_save(service);
2994         } else if (g_str_equal(name, "Passphrase") == TRUE) {
2995                 if (service->immutable == TRUE)
2996                         return __connman_error_not_supported(msg);
2997
2998                 g_free(service->passphrase);
2999                 service->passphrase = NULL;
3000
3001                 passphrase_changed(service);
3002
3003                 service_save(service);
3004         } else
3005                 return __connman_error_invalid_property(msg);
3006
3007         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3008 }
3009
3010 static connman_bool_t is_ignore(struct connman_service *service)
3011 {
3012         if (service->autoconnect == FALSE)
3013                 return TRUE;
3014
3015         if (service->roaming == TRUE)
3016                 return TRUE;
3017
3018         if (service->ignore == TRUE)
3019                 return TRUE;
3020
3021         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
3022                 return TRUE;
3023
3024         return FALSE;
3025 }
3026
3027 void __connman_service_auto_connect(void)
3028 {
3029         struct connman_service *service = NULL;
3030         GSequenceIter *iter;
3031
3032         DBG("");
3033
3034         if (__connman_session_mode() == TRUE) {
3035                 DBG("Session mode enabled: auto connect disabled");
3036                 return;
3037         }
3038
3039         iter = g_sequence_get_begin_iter(service_list);
3040
3041         while (g_sequence_iter_is_end(iter) == FALSE) {
3042                 service = g_sequence_get(iter);
3043
3044                 if (service->pending != NULL)
3045                         return;
3046
3047                 if (is_connecting(service) == TRUE)
3048                         return;
3049
3050                 if (service->favorite == FALSE)
3051                         return;
3052
3053                 if (is_connected(service) == TRUE)
3054                         return;
3055
3056                 if (is_ignore(service) == FALSE && service->state ==
3057                                                 CONNMAN_SERVICE_STATE_IDLE)
3058                         break;
3059
3060                 service = NULL;
3061
3062                 iter = g_sequence_iter_next(iter);
3063         }
3064
3065         if (service != NULL) {
3066                 service->userconnect = FALSE;
3067                 __connman_service_connect(service);
3068         }
3069 }
3070
3071 static void remove_timeout(struct connman_service *service)
3072 {
3073         if (service->timeout > 0) {
3074                 g_source_remove(service->timeout);
3075                 service->timeout = 0;
3076         }
3077 }
3078
3079 static void reply_pending(struct connman_service *service, int error)
3080 {
3081         remove_timeout(service);
3082
3083         if (service->pending != NULL) {
3084                 if (error > 0) {
3085                         DBusMessage *reply;
3086
3087                         reply = __connman_error_failed(service->pending,
3088                                                                 error);
3089                         if (reply != NULL)
3090                                 g_dbus_send_message(connection, reply);
3091                 } else {
3092                         const char *sender;
3093
3094                         sender = dbus_message_get_interface(service->pending);
3095
3096                         DBG("sender %s", sender);
3097
3098                         if (g_strcmp0(sender, CONNMAN_MANAGER_INTERFACE) == 0)
3099                                 g_dbus_send_reply(connection, service->pending,
3100                                         DBUS_TYPE_OBJECT_PATH, &service->path,
3101                                                         DBUS_TYPE_INVALID);
3102                         else
3103                                 g_dbus_send_reply(connection, service->pending,
3104                                                         DBUS_TYPE_INVALID);
3105                 }
3106
3107                 dbus_message_unref(service->pending);
3108                 service->pending = NULL;
3109         }
3110 }
3111
3112 static gboolean connect_timeout(gpointer user_data)
3113 {
3114         struct connman_service *service = user_data;
3115         connman_bool_t autoconnect = FALSE;
3116
3117         DBG("service %p", service);
3118
3119         service->timeout = 0;
3120
3121         if (service->network != NULL)
3122                 __connman_network_disconnect(service->network);
3123
3124         __connman_ipconfig_disable(service->ipconfig_ipv4);
3125         __connman_ipconfig_disable(service->ipconfig_ipv6);
3126
3127         __connman_stats_service_unregister(service);
3128
3129         if (service->pending != NULL) {
3130                 DBusMessage *reply;
3131
3132                 reply = __connman_error_operation_timeout(service->pending);
3133                 if (reply != NULL)
3134                         g_dbus_send_message(connection, reply);
3135
3136                 dbus_message_unref(service->pending);
3137                 service->pending = NULL;
3138         } else
3139                 autoconnect = TRUE;
3140
3141         __connman_service_ipconfig_indicate_state(service,
3142                                         CONNMAN_SERVICE_STATE_FAILURE,
3143                                         CONNMAN_IPCONFIG_TYPE_IPV4);
3144         __connman_service_ipconfig_indicate_state(service,
3145                                         CONNMAN_SERVICE_STATE_FAILURE,
3146                                         CONNMAN_IPCONFIG_TYPE_IPV6);
3147
3148         if (autoconnect == TRUE && service->userconnect == FALSE)
3149                 __connman_service_auto_connect();
3150
3151         return FALSE;
3152 }
3153
3154 static void set_reconnect_state(struct connman_service *service,
3155                                                 connman_bool_t reconnect)
3156 {
3157         struct connman_device *device;
3158
3159         if (service->network == NULL)
3160                 return;
3161
3162         device = connman_network_get_device(service->network);
3163         if (device == NULL)
3164                 return;
3165
3166         __connman_device_set_reconnect(device, reconnect);
3167 }
3168
3169 static connman_bool_t get_reconnect_state(struct connman_service *service)
3170 {
3171         struct connman_device *device;
3172
3173         if (service->network == NULL)
3174                 return FALSE;
3175
3176         device = connman_network_get_device(service->network);
3177         if (device == NULL)
3178                 return FALSE;
3179
3180         return __connman_device_get_reconnect(device);
3181 }
3182
3183 static void request_input_cb (struct connman_service *service,
3184                         const char *identity, const char *passphrase,
3185                         void *user_data)
3186 {
3187         DBG ("RequestInput return, %p", service);
3188
3189         if (identity == NULL && passphrase == NULL && service->wps == FALSE)
3190                 return;
3191
3192         if (identity != NULL)
3193                 __connman_service_set_agent_identity(service, identity);
3194
3195         if (passphrase != NULL) {
3196                 switch (service->security) {
3197                 case CONNMAN_SERVICE_SECURITY_WEP:
3198                 case CONNMAN_SERVICE_SECURITY_PSK:
3199                         __connman_service_set_passphrase(service, passphrase);
3200                         break;
3201                 case CONNMAN_SERVICE_SECURITY_8021X:
3202                         __connman_service_set_agent_passphrase(service,
3203                                                         passphrase);
3204                         break;
3205                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
3206                 case CONNMAN_SERVICE_SECURITY_NONE:
3207                 case CONNMAN_SERVICE_SECURITY_WPA:
3208                 case CONNMAN_SERVICE_SECURITY_RSN:
3209                         DBG("service security '%s' not handled",
3210                                 security2string(service->security));
3211                         break;
3212                 }
3213         }
3214
3215         __connman_service_connect(service);
3216
3217         /* Never cache agent provided credentials */
3218         __connman_service_set_agent_identity(service, NULL);
3219         __connman_service_set_agent_passphrase(service, NULL);
3220 }
3221
3222 static DBusMessage *connect_service(DBusConnection *conn,
3223                                         DBusMessage *msg, void *user_data)
3224 {
3225         struct connman_service *service = user_data;
3226         GSequenceIter *iter;
3227         int err;
3228
3229         DBG("service %p", service);
3230
3231         if (service->pending != NULL)
3232                 return __connman_error_in_progress(msg);
3233
3234         iter = g_sequence_get_begin_iter(service_list);
3235
3236         while (g_sequence_iter_is_end(iter) == FALSE) {
3237                 struct connman_service *temp = g_sequence_get(iter);
3238
3239                 if (service->type == temp->type && is_connecting(temp) == TRUE)
3240                         return __connman_error_in_progress(msg);
3241
3242                 iter = g_sequence_iter_next(iter);
3243         }
3244
3245         service->ignore = FALSE;
3246
3247         service->userconnect = TRUE;
3248
3249         service->pending = dbus_message_ref(msg);
3250
3251         set_reconnect_state(service, FALSE);
3252
3253         err = __connman_service_connect(service);
3254         if (err < 0) {
3255                 if (service->pending == NULL)
3256                         return NULL;
3257
3258                 if (err != -EINPROGRESS) {
3259                         dbus_message_unref(service->pending);
3260                         service->pending = NULL;
3261
3262                         return __connman_error_failed(msg, -err);
3263                 }
3264
3265                 return NULL;
3266         }
3267
3268         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3269 }
3270
3271 static DBusMessage *disconnect_service(DBusConnection *conn,
3272                                         DBusMessage *msg, void *user_data)
3273 {
3274         struct connman_service *service = user_data;
3275         int err;
3276
3277         DBG("service %p", service);
3278
3279         reply_pending(service, ECONNABORTED);
3280
3281         service->ignore = TRUE;
3282
3283         set_reconnect_state(service, FALSE);
3284
3285         err = __connman_service_disconnect(service);
3286         if (err < 0) {
3287                 if (err != -EINPROGRESS)
3288                         return __connman_error_failed(msg, -err);
3289
3290                 return NULL;
3291         }
3292
3293         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3294 }
3295
3296 static DBusMessage *remove_service(DBusConnection *conn,
3297                                         DBusMessage *msg, void *user_data)
3298 {
3299         struct connman_service *service = user_data;
3300
3301         DBG("service %p", service);
3302
3303         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
3304                 return __connman_error_not_supported(msg);
3305
3306         if (service->immutable == TRUE)
3307                 return __connman_error_not_supported(msg);
3308
3309         if (service->favorite == FALSE && service->state !=
3310                                                 CONNMAN_SERVICE_STATE_FAILURE)
3311                 return __connman_error_not_supported(msg);
3312
3313         if (service->network != NULL) {
3314                 set_reconnect_state(service, FALSE);
3315
3316                 __connman_network_disconnect(service->network);
3317         }
3318
3319         g_free(service->passphrase);
3320         service->passphrase = NULL;
3321
3322         passphrase_changed(service);
3323
3324         set_idle(service);
3325
3326         __connman_service_set_favorite(service, FALSE);
3327         service_save(service);
3328
3329         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3330 }
3331
3332 static gboolean check_suitable_state(enum connman_service_state a,
3333                                         enum connman_service_state b)
3334 {
3335         /*
3336          * Special check so that "ready" service can be moved before
3337          * "online" one.
3338          */
3339         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
3340                         b == CONNMAN_SERVICE_STATE_READY) ||
3341                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
3342                         a == CONNMAN_SERVICE_STATE_READY))
3343                 return TRUE;
3344
3345         return a == b;
3346 }
3347
3348 static DBusMessage *move_service(DBusConnection *conn,
3349                                         DBusMessage *msg, void *user_data,
3350                                                                 gboolean before)
3351 {
3352         struct connman_service *service = user_data;
3353         struct connman_service *target;
3354         const char *path;
3355         GSequenceIter *src, *dst;
3356         enum connman_ipconfig_method target4, target6;
3357         enum connman_ipconfig_method service4, service6;
3358
3359         DBG("service %p", service);
3360
3361         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
3362                                                         DBUS_TYPE_INVALID);
3363
3364         if (service->favorite == FALSE)
3365                 return __connman_error_not_supported(msg);
3366
3367         target = find_service(path);
3368         if (target == NULL || target->favorite == FALSE || target == service)
3369                 return __connman_error_invalid_service(msg);
3370
3371         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
3372         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
3373         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
3374         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
3375
3376         DBG("target %s method %d/%d state %d/%d", target->identifier,
3377                                 target4, target6,
3378                                 target->state_ipv4, target->state_ipv6);
3379
3380         DBG("service %s method %d/%d state %d/%d", service->identifier,
3381                                 service4, service6,
3382                                 service->state_ipv4, service->state_ipv6);
3383
3384         /*
3385          * If method is OFF, then we do not need to check the corresponding
3386          * ipconfig state.
3387          */
3388         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
3389                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
3390                         if (check_suitable_state(target->state_ipv6,
3391                                                 service->state_ipv6) == FALSE)
3392                                 return __connman_error_invalid_service(msg);
3393                 }
3394         }
3395
3396         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
3397                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
3398                         if (check_suitable_state(target->state_ipv4,
3399                                                 service->state_ipv4) == FALSE)
3400                                 return __connman_error_invalid_service(msg);
3401                 }
3402         }
3403
3404         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
3405                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
3406                         if (check_suitable_state(target->state_ipv6,
3407                                                 service->state_ipv6) == FALSE)
3408                                 return __connman_error_invalid_service(msg);
3409                 }
3410         }
3411
3412         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
3413                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
3414                         if (check_suitable_state(target->state_ipv4,
3415                                                 service->state_ipv4) == FALSE)
3416                                 return __connman_error_invalid_service(msg);
3417                 }
3418         }
3419
3420         g_get_current_time(&service->modified);
3421         service_save(service);
3422
3423         src = g_hash_table_lookup(service_hash, service->identifier);
3424         dst = g_hash_table_lookup(service_hash, target->identifier);
3425
3426         before ? g_sequence_move(src, dst) : g_sequence_move(dst, src);
3427
3428         services_changed(FALSE);
3429
3430         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3431 }
3432
3433 static DBusMessage *move_before(DBusConnection *conn,
3434                                         DBusMessage *msg, void *user_data)
3435 {
3436         return move_service(conn, msg, user_data, TRUE);
3437 }
3438
3439 static DBusMessage *move_after(DBusConnection *conn,
3440                                         DBusMessage *msg, void *user_data)
3441 {
3442         return move_service(conn, msg, user_data, FALSE);
3443 }
3444
3445 static DBusMessage *reset_counters(DBusConnection *conn,
3446                                         DBusMessage *msg, void *user_data)
3447 {
3448         struct connman_service *service = user_data;
3449
3450         reset_stats(service);
3451
3452         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3453 }
3454
3455 static GDBusMethodTable service_methods[] = {
3456         { "GetProperties", "",   "a{sv}", get_properties     },
3457         { "SetProperty",   "sv", "",      set_property       },
3458         { "ClearProperty", "s",  "",      clear_property     },
3459         { "Connect",       "",   "",      connect_service,
3460                                                 G_DBUS_METHOD_FLAG_ASYNC },
3461         { "Disconnect",    "",   "",      disconnect_service },
3462         { "Remove",        "",   "",      remove_service     },
3463         { "MoveBefore",    "o",  "",      move_before        },
3464         { "MoveAfter",     "o",  "",      move_after         },
3465         { "ResetCounters", "",   "",      reset_counters     },
3466         { },
3467 };
3468
3469 static GDBusSignalTable service_signals[] = {
3470         { "PropertyChanged", "sv" },
3471         { },
3472 };
3473
3474 static void service_free(gpointer user_data)
3475 {
3476         struct connman_service *service = user_data;
3477         char *path = service->path;
3478
3479         DBG("service %p", service);
3480
3481         reply_pending(service, ENOENT);
3482
3483         g_hash_table_remove(service_hash, service->identifier);
3484
3485         __connman_notifier_service_remove(service);
3486
3487         stats_stop(service);
3488         service_save(service);
3489
3490         service->path = NULL;
3491
3492         if (path != NULL) {
3493                 services_changed(FALSE);
3494
3495                 g_dbus_unregister_interface(connection, path,
3496                                                 CONNMAN_SERVICE_INTERFACE);
3497                 g_free(path);
3498         }
3499
3500         g_hash_table_destroy(service->counter_table);
3501
3502         if (service->network != NULL) {
3503                 if (service->network_created == TRUE)
3504                         connman_network_unref(service->network);
3505         }
3506
3507         if (service->provider != NULL)
3508                 connman_provider_unref(service->provider);
3509
3510         if (service->ipconfig_ipv4 != NULL) {
3511                 connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
3512                 connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
3513                 connman_ipconfig_unref(service->ipconfig_ipv4);
3514                 service->ipconfig_ipv4 = NULL;
3515         }
3516
3517         if (service->ipconfig_ipv6 != NULL) {
3518                 connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
3519                 connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
3520                 connman_ipconfig_unref(service->ipconfig_ipv6);
3521                 service->ipconfig_ipv6 = NULL;
3522         }
3523
3524         if (service->location != NULL)
3525                 connman_location_unref(service->location);
3526
3527         g_strfreev(service->nameservers);
3528         g_strfreev(service->nameservers_config);
3529         g_strfreev(service->domains);
3530         g_strfreev(service->proxies);
3531         g_strfreev(service->excludes);
3532
3533         g_free(service->domainname);
3534         g_free(service->pac);
3535         g_free(service->name);
3536         g_free(service->passphrase);
3537         g_free(service->agent_passphrase);
3538         g_free(service->identifier);
3539         g_free(service->eap);
3540         g_free(service->identity);
3541         g_free(service->agent_identity);
3542         g_free(service->ca_cert_file);
3543         g_free(service->client_cert_file);
3544         g_free(service->private_key_file);
3545         g_free(service->private_key_passphrase);
3546         g_free(service->phase2);
3547
3548         if (service->stats.timer != NULL)
3549                 g_timer_destroy(service->stats.timer);
3550         if (service->stats_roaming.timer != NULL)
3551                 g_timer_destroy(service->stats_roaming.timer);
3552
3553         g_free(service);
3554 }
3555
3556 /**
3557  * __connman_service_put:
3558  * @service: service structure
3559  *
3560  * Release service if no longer needed
3561  */
3562 void __connman_service_put(struct connman_service *service)
3563 {
3564         DBG("service %p", service);
3565
3566         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
3567                 GSequenceIter *iter;
3568
3569                 iter = g_hash_table_lookup(service_hash, service->identifier);
3570                 if (iter != NULL) {
3571                         reply_pending(service, ECONNABORTED);
3572
3573                         __connman_service_disconnect(service);
3574
3575                         g_sequence_remove(iter);
3576                 } else
3577                         service_free(service);
3578         }
3579 }
3580
3581 static void stats_init(struct connman_service *service)
3582 {
3583         /* home */
3584         service->stats.valid = FALSE;
3585         service->stats.enabled = FALSE;
3586         service->stats.timer = g_timer_new();
3587
3588         /* roaming */
3589         service->stats_roaming.valid = FALSE;
3590         service->stats_roaming.enabled = FALSE;
3591         service->stats_roaming.timer = g_timer_new();
3592 }
3593
3594 static void service_initialize(struct connman_service *service)
3595 {
3596         DBG("service %p", service);
3597
3598         service->refcount = 1;
3599         service->session_usage_count = 0;
3600
3601         service->network_created = FALSE;
3602
3603         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
3604         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
3605
3606         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
3607         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
3608         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
3609
3610         service->favorite  = FALSE;
3611         service->immutable = FALSE;
3612         service->hidden = FALSE;
3613
3614         service->ignore = FALSE;
3615
3616         service->userconnect = FALSE;
3617
3618         service->order = 0;
3619
3620         stats_init(service);
3621
3622         service->provider = NULL;
3623
3624         service->wps = FALSE;
3625 }
3626
3627 /**
3628  * connman_service_create:
3629  *
3630  * Allocate a new service.
3631  *
3632  * Returns: a newly-allocated #connman_service structure
3633  */
3634 struct connman_service *connman_service_create(void)
3635 {
3636         GSList *list;
3637         struct connman_stats_counter *counters;
3638         const char *counter;
3639
3640         struct connman_service *service;
3641
3642         service = g_try_new0(struct connman_service, 1);
3643         if (service == NULL)
3644                 return NULL;
3645
3646         DBG("service %p", service);
3647
3648         service->counter_table = g_hash_table_new_full(g_str_hash,
3649                                                 g_str_equal, NULL, g_free);
3650
3651         for (list = counter_list; list; list = list->next) {
3652                 counter = list->data;
3653
3654                 counters = g_try_new0(struct connman_stats_counter, 1);
3655                 if (counters == NULL) {
3656                         g_hash_table_destroy(service->counter_table);
3657                         g_free(service);
3658                         return NULL;
3659                 }
3660
3661                 counters->append_all = TRUE;
3662
3663                 g_hash_table_replace(service->counter_table, (gpointer)counter,
3664                                 counters);
3665         }
3666
3667         service_initialize(service);
3668
3669         service->location = __connman_location_create(service);
3670
3671         return service;
3672 }
3673
3674 struct connman_location *__connman_service_get_location(struct connman_service *service)
3675 {
3676         return service->location;
3677 }
3678
3679 /**
3680  * connman_service_ref:
3681  * @service: service structure
3682  *
3683  * Increase reference counter of service
3684  */
3685 struct connman_service *connman_service_ref(struct connman_service *service)
3686 {
3687         DBG("%p", service);
3688
3689         g_atomic_int_inc(&service->refcount);
3690
3691         return service;
3692 }
3693
3694 /**
3695  * connman_service_unref:
3696  * @service: service structure
3697  *
3698  * Decrease reference counter of service
3699  */
3700 void connman_service_unref(struct connman_service *service)
3701 {
3702         __connman_service_put(service);
3703 }
3704
3705 static gint service_compare(gconstpointer a, gconstpointer b,
3706                                                         gpointer user_data)
3707 {
3708         struct connman_service *service_a = (void *) a;
3709         struct connman_service *service_b = (void *) b;
3710         enum connman_service_state state_a, state_b;
3711
3712         state_a = service_a->state;
3713         state_b = service_b->state;
3714
3715         if (state_a != state_b) {
3716                 gboolean a_connected = is_connected(service_a);
3717                 gboolean b_connected = is_connected(service_b);
3718
3719                 if (a_connected == TRUE && b_connected == TRUE) {
3720                         /* We prefer online over ready state */
3721                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
3722                                 return -1;
3723
3724                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
3725                                 return 1;
3726                 }
3727
3728                 if (a_connected == TRUE)
3729                         return -1;
3730                 if (b_connected == TRUE)
3731                         return 1;
3732
3733                 if (is_connecting(service_a) == TRUE)
3734                         return -1;
3735                 if (is_connecting(service_b) == TRUE)
3736                         return 1;
3737         }
3738
3739         if (service_a->order > service_b->order)
3740                 return -1;
3741
3742         if (service_a->order < service_b->order)
3743                 return 1;
3744
3745         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
3746                 return -1;
3747
3748         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
3749                 return 1;
3750
3751         if (service_a->type != service_b->type) {
3752                 switch (service_a->type) {
3753                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
3754                 case CONNMAN_SERVICE_TYPE_SYSTEM:
3755                 case CONNMAN_SERVICE_TYPE_ETHERNET:
3756                 case CONNMAN_SERVICE_TYPE_GPS:
3757                 case CONNMAN_SERVICE_TYPE_VPN:
3758                 case CONNMAN_SERVICE_TYPE_GADGET:
3759                         break;
3760                 case CONNMAN_SERVICE_TYPE_WIFI:
3761                         return 1;
3762                 case CONNMAN_SERVICE_TYPE_WIMAX:
3763                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
3764                 case CONNMAN_SERVICE_TYPE_CELLULAR:
3765                         return -1;
3766                 }
3767         }
3768
3769         return (gint) service_b->strength - (gint) service_a->strength;
3770 }
3771
3772 /**
3773  * connman_service_get_type:
3774  * @service: service structure
3775  *
3776  * Get the type of service
3777  */
3778 enum connman_service_type connman_service_get_type(struct connman_service *service)
3779 {
3780         if (service == NULL)
3781                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
3782
3783         return service->type;
3784 }
3785
3786 /**
3787  * connman_service_get_interface:
3788  * @service: service structure
3789  *
3790  * Get network interface of service
3791  */
3792 char *connman_service_get_interface(struct connman_service *service)
3793 {
3794         int index;
3795
3796         if (service == NULL)
3797                 return NULL;
3798
3799         if (service->type == CONNMAN_SERVICE_TYPE_VPN) {
3800                 if (service->ipconfig_ipv4)
3801                         index = connman_ipconfig_get_index(
3802                                                 service->ipconfig_ipv4);
3803                 else if (service->ipconfig_ipv6)
3804                         index = connman_ipconfig_get_index(
3805                                                 service->ipconfig_ipv6);
3806                 else
3807                         return NULL;
3808
3809                 return connman_inet_ifname(index);
3810         }
3811
3812         if (service->network == NULL)
3813                 return NULL;
3814
3815         index = connman_network_get_index(service->network);
3816
3817         return connman_inet_ifname(index);
3818 }
3819
3820 /**
3821  * connman_service_get_network:
3822  * @service: service structure
3823  *
3824  * Get the service network
3825  */
3826 struct connman_network *
3827 __connman_service_get_network(struct connman_service *service)
3828 {
3829         if (service == NULL)
3830                 return NULL;
3831
3832         return service->network;
3833 }
3834
3835 struct connman_ipconfig *
3836 __connman_service_get_ip4config(struct connman_service *service)
3837 {
3838         if (service == NULL)
3839                 return NULL;
3840
3841         return service->ipconfig_ipv4;
3842 }
3843
3844 struct connman_ipconfig *
3845 __connman_service_get_ip6config(struct connman_service *service)
3846 {
3847         if (service == NULL)
3848                 return NULL;
3849
3850         return service->ipconfig_ipv6;
3851 }
3852
3853 struct connman_ipconfig *
3854 __connman_service_get_ipconfig(struct connman_service *service, int family)
3855 {
3856         if (family == AF_INET)
3857                 return __connman_service_get_ip4config(service);
3858         else if (family == AF_INET6)
3859                 return __connman_service_get_ip6config(service);
3860         else
3861                 return NULL;
3862
3863 }
3864
3865 enum connman_service_security __connman_service_get_security(struct connman_service *service)
3866 {
3867         if (service == NULL)
3868                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
3869
3870         return service->security;
3871 }
3872
3873 const char *__connman_service_get_phase2(struct connman_service *service)
3874 {
3875         if (service == NULL)
3876                 return NULL;
3877
3878         return service->phase2;
3879 }
3880
3881 connman_bool_t __connman_service_wps_enabled(struct connman_service *service)
3882 {
3883         if (service == NULL)
3884                 return FALSE;
3885
3886         return service->wps;
3887 }
3888
3889 /**
3890  * __connman_service_set_favorite:
3891  * @service: service structure
3892  * @favorite: favorite value
3893  *
3894  * Change the favorite setting of service
3895  */
3896 int __connman_service_set_favorite(struct connman_service *service,
3897                                                 connman_bool_t favorite)
3898 {
3899         GSequenceIter *iter;
3900
3901         iter = g_hash_table_lookup(service_hash, service->identifier);
3902         if (iter == NULL)
3903                 return -ENOENT;
3904
3905         if (service->favorite == favorite)
3906                 return -EALREADY;
3907
3908         service->favorite = favorite;
3909
3910         favorite_changed(service);
3911
3912         g_sequence_sort_changed(iter, service_compare, NULL);
3913
3914         services_changed(FALSE);
3915
3916         return 0;
3917 }
3918
3919 int __connman_service_set_immutable(struct connman_service *service,
3920                                                 connman_bool_t immutable)
3921 {
3922         service->immutable = immutable;
3923
3924         immutable_changed(service);
3925
3926         return 0;
3927 }
3928
3929 void __connman_service_set_string(struct connman_service *service,
3930                                   const char *key, const char *value)
3931 {
3932         if (g_str_equal(key, "EAP") == TRUE) {
3933                 g_free(service->eap);
3934                 service->eap = g_strdup(value);
3935         } else if (g_str_equal(key, "Identity") == TRUE) {
3936                 g_free(service->identity);
3937                 service->identity = g_strdup(value);
3938         } else if (g_str_equal(key, "CACertFile") == TRUE) {
3939                 g_free(service->ca_cert_file);
3940                 service->ca_cert_file = g_strdup(value);
3941         } else if (g_str_equal(key, "ClientCertFile") == TRUE) {
3942                 g_free(service->client_cert_file);
3943                 service->client_cert_file = g_strdup(value);
3944         } else if (g_str_equal(key, "PrivateKeyFile") == TRUE) {
3945                 g_free(service->private_key_file);
3946                 service->private_key_file = g_strdup(value);
3947         } else if (g_str_equal(key, "PrivateKeyPassphrase") == TRUE) {
3948                 g_free(service->private_key_passphrase);
3949                 service->private_key_passphrase = g_strdup(value);
3950         } else if (g_str_equal(key, "Phase2") == TRUE) {
3951                 g_free(service->phase2);
3952                 service->phase2 = g_strdup(value);
3953         } else if (g_str_equal(key, "Passphrase") == TRUE) {
3954                 g_free(service->passphrase);
3955                 service->passphrase = g_strdup(value);
3956         }
3957 }
3958
3959 static void service_complete(struct connman_service *service)
3960 {
3961         reply_pending(service, EIO);
3962
3963         if (service->userconnect == FALSE)
3964                 __connman_service_auto_connect();
3965
3966         g_get_current_time(&service->modified);
3967         service_save(service);
3968 }
3969
3970 static void report_error_cb(struct connman_service *service,
3971                         gboolean retry, void *user_data)
3972 {
3973         if (retry == TRUE)
3974                 __connman_service_connect(service);
3975         else {
3976                 service_complete(service);
3977                 services_changed(FALSE);
3978                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
3979         }
3980 }
3981
3982 static int __connman_service_indicate_state(struct connman_service *service)
3983 {
3984         enum connman_service_state old_state, new_state;
3985         GSequenceIter *iter;
3986
3987         if (service == NULL)
3988                 return -EINVAL;
3989
3990         old_state = service->state;
3991         new_state = combine_state(service->state_ipv4, service->state_ipv6);
3992
3993         if (old_state == new_state)
3994                 return -EALREADY;
3995
3996         DBG("service %p old %s - new %s/%s => %s",
3997                                         service,
3998                                         state2string(old_state),
3999                                         state2string(service->state_ipv4),
4000                                         state2string(service->state_ipv6),
4001                                         state2string(new_state));
4002
4003         service->state = new_state;
4004         state_changed(service);
4005
4006         if (new_state == CONNMAN_SERVICE_STATE_IDLE &&
4007                         old_state != CONNMAN_SERVICE_STATE_DISCONNECT) {
4008                 reply_pending(service, ECONNABORTED);
4009
4010                 __connman_service_disconnect(service);
4011         }
4012
4013         if (new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) {
4014                 if (__connman_stats_service_register(service) == 0) {
4015                         __connman_stats_get(service, FALSE,
4016                                                 &service->stats.data);
4017                         __connman_stats_get(service, TRUE,
4018                                                 &service->stats_roaming.data);
4019                 }
4020         }
4021
4022         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
4023                 if (service->login_required == TRUE) {
4024                         service->login_required = FALSE;
4025                         login_changed(service);
4026                 }
4027
4028                 connman_timeserver_sync();
4029         }
4030
4031         if (new_state == CONNMAN_SERVICE_STATE_IDLE) {
4032                 connman_bool_t reconnect;
4033
4034                 reconnect = get_reconnect_state(service);
4035                 if (reconnect == TRUE)
4036                         __connman_service_auto_connect();
4037
4038                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
4039         }
4040
4041         if (new_state == CONNMAN_SERVICE_STATE_READY) {
4042                 enum connman_ipconfig_method method;
4043
4044                 set_reconnect_state(service, TRUE);
4045
4046                 __connman_service_set_favorite(service, TRUE);
4047
4048                 reply_pending(service, 0);
4049
4050                 service->userconnect = FALSE;
4051
4052                 g_get_current_time(&service->modified);
4053                 service_save(service);
4054
4055                 update_nameservers(service);
4056                 dns_changed(service);
4057                 domain_changed(service);
4058
4059                 __connman_notifier_connect(service->type);
4060
4061                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
4062                         connman_network_get_bool(service->network,
4063                                                 "WiFi.UseWPS") == TRUE) {
4064                         const char *pass;
4065
4066                         pass = connman_network_get_string(service->network,
4067                                                         "WiFi.Passphrase");
4068
4069                         __connman_service_set_passphrase(service, pass);
4070
4071                         connman_network_set_bool(service->network,
4072                                                         "WiFi.UseWPS", FALSE);
4073                 }
4074
4075                 default_changed();
4076
4077                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
4078                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
4079                         __connman_ipconfig_disable_ipv6(
4080                                                 service->ipconfig_ipv6);
4081
4082         } else if (new_state == CONNMAN_SERVICE_STATE_DISCONNECT) {
4083                 struct connman_service *def_service = get_default();
4084
4085                 if (__connman_notifier_count_connected() == 0 &&
4086                         def_service != NULL &&
4087                                 def_service->provider != NULL)
4088                         __connman_provider_disconnect(def_service->provider);
4089
4090                 __connman_location_finish(service);
4091
4092                 default_changed();
4093
4094                 __connman_wpad_stop(service);
4095
4096                 update_nameservers(service);
4097                 dns_changed(service);
4098                 domain_changed(service);
4099
4100                 __connman_notifier_disconnect(service->type);
4101         }
4102
4103         if (new_state == CONNMAN_SERVICE_STATE_FAILURE) {
4104                 if (service->userconnect == TRUE &&
4105                         __connman_agent_report_error(service,
4106                                         error2string(service->error),
4107                                         report_error_cb, NULL) == -EIO)
4108                         return 0;
4109                 service_complete(service);
4110
4111                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
4112         } else
4113                 service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
4114
4115         iter = g_hash_table_lookup(service_hash, service->identifier);
4116         if (iter != NULL)
4117                 g_sequence_sort_changed(iter, service_compare, NULL);
4118
4119         services_changed(FALSE);
4120
4121         if (new_state == CONNMAN_SERVICE_STATE_ONLINE)
4122                 default_changed();
4123
4124         return 0;
4125 }
4126
4127 int __connman_service_indicate_error(struct connman_service *service,
4128                                         enum connman_service_error error)
4129 {
4130         DBG("service %p error %d", service, error);
4131
4132         if (service == NULL)
4133                 return -EINVAL;
4134
4135         service->error = error;
4136
4137         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
4138                 __connman_service_set_passphrase(service, NULL);
4139
4140         __connman_service_ipconfig_indicate_state(service,
4141                                                 CONNMAN_SERVICE_STATE_FAILURE,
4142                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4143         __connman_service_ipconfig_indicate_state(service,
4144                                                 CONNMAN_SERVICE_STATE_FAILURE,
4145                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
4146         return 0;
4147 }
4148
4149 int __connman_service_clear_error(struct connman_service *service)
4150 {
4151         DBG("service %p", service);
4152
4153         if (service == NULL)
4154                 return -EINVAL;
4155
4156         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
4157                 return -EINVAL;
4158
4159         service->state_ipv4 = service->state_ipv6 =
4160                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
4161         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;;
4162
4163         if (service->favorite == TRUE)
4164                 set_reconnect_state(service, TRUE);
4165
4166         __connman_service_ipconfig_indicate_state(service,
4167                                         CONNMAN_SERVICE_STATE_IDLE,
4168                                         CONNMAN_IPCONFIG_TYPE_IPV6);
4169
4170         /*
4171          * Toggling the IPv6 state to IDLE could trigger the auto connect
4172          * machinery and consequently the IPv4 state.
4173          */
4174         if (service->state_ipv4 != CONNMAN_SERVICE_STATE_UNKNOWN &&
4175                         service->state_ipv4 != CONNMAN_SERVICE_STATE_FAILURE)
4176                 return 0;
4177
4178         return __connman_service_ipconfig_indicate_state(service,
4179                                                 CONNMAN_SERVICE_STATE_IDLE,
4180                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4181 }
4182
4183 int __connman_service_indicate_default(struct connman_service *service)
4184 {
4185         DBG("service %p", service);
4186
4187         default_changed();
4188
4189         __connman_location_detect(service);
4190
4191         return 0;
4192 }
4193
4194 enum connman_service_state __connman_service_ipconfig_get_state(
4195                                         struct connman_service *service,
4196                                         enum connman_ipconfig_type type)
4197 {
4198         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4199                 return service->state_ipv4;
4200
4201         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
4202                 return service->state_ipv6;
4203
4204         return CONNMAN_SERVICE_STATE_UNKNOWN;
4205 }
4206
4207 static void check_proxy_setup(struct connman_service *service)
4208 {
4209         /*
4210          * We start WPAD if we haven't got a PAC URL from DHCP and
4211          * if our proxy manual configuration is either empty or set
4212          * to AUTO with an empty URL.
4213          */
4214
4215         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
4216                 return;
4217
4218         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
4219                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
4220                         service->pac != NULL))
4221                 return;
4222
4223         if (__connman_wpad_start(service) < 0) {
4224                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
4225                 __connman_notifier_proxy_changed(service);
4226         }
4227 }
4228
4229 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
4230                                         enum connman_service_state new_state,
4231                                         enum connman_ipconfig_type type)
4232 {
4233         struct connman_ipconfig *ipconfig = NULL;
4234         enum connman_service_state old_state;
4235
4236         if (service == NULL)
4237                 return -EINVAL;
4238
4239         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
4240                 old_state = service->state_ipv4;
4241                 ipconfig = service->ipconfig_ipv4;
4242         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
4243                 old_state = service->state_ipv6;
4244                 ipconfig = service->ipconfig_ipv6;
4245         }
4246
4247         if (ipconfig == NULL)
4248                 return -EINVAL;
4249
4250         /* Any change? */
4251         if (old_state == new_state)
4252                 return -EALREADY;
4253
4254         DBG("service %p (%s) state %d (%s) type %d (%s)",
4255                 service, service ? service->identifier : NULL,
4256                 new_state, state2string(new_state),
4257                 type, __connman_ipconfig_type2string(type));
4258
4259         switch (new_state) {
4260         case CONNMAN_SERVICE_STATE_UNKNOWN:
4261         case CONNMAN_SERVICE_STATE_IDLE:
4262                 if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
4263                         return -EINVAL;
4264                 break;
4265         case CONNMAN_SERVICE_STATE_ASSOCIATION:
4266                 break;
4267         case CONNMAN_SERVICE_STATE_CONFIGURATION:
4268                 __connman_ipconfig_enable(ipconfig);
4269                 break;
4270         case CONNMAN_SERVICE_STATE_READY:
4271                 update_nameservers(service);
4272
4273                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4274                         check_proxy_setup(service);
4275                 break;
4276         case CONNMAN_SERVICE_STATE_ONLINE:
4277                 break;
4278         case CONNMAN_SERVICE_STATE_DISCONNECT:
4279                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
4280                         return -EINVAL;
4281                 break;
4282         case CONNMAN_SERVICE_STATE_FAILURE:
4283                 break;
4284         }
4285
4286         /* We keep that state */
4287         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4288                 service->state_ipv4 = new_state;
4289         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
4290                 service->state_ipv6 = new_state;
4291
4292         return __connman_service_indicate_state(service);
4293 }
4294
4295 int __connman_service_request_login(struct connman_service *service)
4296 {
4297         DBG("service %p", service);
4298
4299         if (service == NULL)
4300                 return -EINVAL;
4301
4302         service->login_required = TRUE;
4303         login_changed(service);
4304
4305         return 0;
4306 }
4307
4308 static connman_bool_t prepare_network(struct connman_service *service)
4309 {
4310         enum connman_network_type type;
4311         unsigned int ssid_len;
4312
4313         type = connman_network_get_type(service->network);
4314
4315         switch (type) {
4316         case CONNMAN_NETWORK_TYPE_UNKNOWN:
4317         case CONNMAN_NETWORK_TYPE_VENDOR:
4318                 return FALSE;
4319         case CONNMAN_NETWORK_TYPE_WIFI:
4320                 if (connman_network_get_blob(service->network, "WiFi.SSID",
4321                                                         &ssid_len) == NULL)
4322                         return FALSE;
4323
4324                 if (service->passphrase != NULL)
4325                         connman_network_set_string(service->network,
4326                                 "WiFi.Passphrase", service->passphrase);
4327                 break;
4328         case CONNMAN_NETWORK_TYPE_ETHERNET:
4329         case CONNMAN_NETWORK_TYPE_WIMAX:
4330         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
4331         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
4332         case CONNMAN_NETWORK_TYPE_CELLULAR:
4333                 break;
4334         }
4335
4336         return TRUE;
4337 }
4338
4339 static void prepare_8021x(struct connman_service *service)
4340 {
4341         if (service->eap != NULL)
4342                 connman_network_set_string(service->network, "WiFi.EAP",
4343                                                                 service->eap);
4344
4345         if (service->identity != NULL)
4346                 connman_network_set_string(service->network, "WiFi.Identity",
4347                                                         service->identity);
4348
4349         if (service->ca_cert_file != NULL)
4350                 connman_network_set_string(service->network, "WiFi.CACertFile",
4351                                                         service->ca_cert_file);
4352
4353         if (service->client_cert_file != NULL)
4354                 connman_network_set_string(service->network,
4355                                                 "WiFi.ClientCertFile",
4356                                                 service->client_cert_file);
4357
4358         if (service->private_key_file != NULL)
4359                 connman_network_set_string(service->network,
4360                                                 "WiFi.PrivateKeyFile",
4361                                                 service->private_key_file);
4362
4363         if (service->private_key_passphrase != NULL)
4364                 connman_network_set_string(service->network,
4365                                         "WiFi.PrivateKeyPassphrase",
4366                                         service->private_key_passphrase);
4367
4368         if (service->phase2 != NULL)
4369                 connman_network_set_string(service->network, "WiFi.Phase2",
4370                                                         service->phase2);
4371 }
4372
4373 static int service_connect(struct connman_service *service)
4374 {
4375         int err;
4376
4377         switch (service->type) {
4378         case CONNMAN_SERVICE_TYPE_UNKNOWN:
4379         case CONNMAN_SERVICE_TYPE_SYSTEM:
4380         case CONNMAN_SERVICE_TYPE_GPS:
4381         case CONNMAN_SERVICE_TYPE_GADGET:
4382                 return -EINVAL;
4383         case CONNMAN_SERVICE_TYPE_ETHERNET:
4384         case CONNMAN_SERVICE_TYPE_WIMAX:
4385         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
4386         case CONNMAN_SERVICE_TYPE_CELLULAR:
4387         case CONNMAN_SERVICE_TYPE_VPN:
4388                 break;
4389         case CONNMAN_SERVICE_TYPE_WIFI:
4390                 switch (service->security) {
4391                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
4392                 case CONNMAN_SERVICE_SECURITY_NONE:
4393                         break;
4394                 case CONNMAN_SERVICE_SECURITY_WEP:
4395                 case CONNMAN_SERVICE_SECURITY_PSK:
4396                 case CONNMAN_SERVICE_SECURITY_WPA:
4397                 case CONNMAN_SERVICE_SECURITY_RSN:
4398                         if (service->passphrase == NULL) {
4399                                 if (service->network == NULL)
4400                                         return -EOPNOTSUPP;
4401
4402                                 if (service->wps == FALSE ||
4403                                         connman_network_get_bool(
4404                                                         service->network,
4405                                                         "WiFi.UseWPS") == FALSE)
4406                                         return -ENOKEY;
4407                         }
4408                         break;
4409                 case CONNMAN_SERVICE_SECURITY_8021X:
4410                         if (service->eap == NULL)
4411                                 return -EINVAL;
4412
4413                         /*
4414                          * never request credentials if using EAP-TLS
4415                          * (EAP-TLS networks need to be fully provisioned)
4416                          */
4417                         if (g_str_equal(service->eap, "tls") == TRUE)
4418                                 break;
4419
4420                         /*
4421                          * Return -ENOKEY if either identity or passphrase is
4422                          * missing. Agent provided credentials can be used as
4423                          * fallback if needed.
4424                          */
4425                         if ((service->identity == NULL &&
4426                                         service->agent_identity == NULL) ||
4427                                         (service->passphrase == NULL &&
4428                                         service->agent_passphrase == NULL))
4429                                 return -ENOKEY;
4430
4431                         break;
4432                 }
4433                 break;
4434         }
4435
4436         if (service->network != NULL) {
4437                 if (prepare_network(service) == FALSE)
4438                         return -EINVAL;
4439
4440                 switch (service->security) {
4441                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
4442                 case CONNMAN_SERVICE_SECURITY_NONE:
4443                 case CONNMAN_SERVICE_SECURITY_WEP:
4444                 case CONNMAN_SERVICE_SECURITY_PSK:
4445                 case CONNMAN_SERVICE_SECURITY_WPA:
4446                 case CONNMAN_SERVICE_SECURITY_RSN:
4447                         break;
4448                 case CONNMAN_SERVICE_SECURITY_8021X:
4449                         prepare_8021x(service);
4450                         break;
4451                 }
4452
4453                 if (__connman_stats_service_register(service) == 0) {
4454                         __connman_stats_get(service, FALSE,
4455                                                 &service->stats.data);
4456                         __connman_stats_get(service, TRUE,
4457                                                 &service->stats_roaming.data);
4458                 }
4459
4460                 if (service->ipconfig_ipv4)
4461                         __connman_ipconfig_enable(service->ipconfig_ipv4);
4462                 if (service->ipconfig_ipv6)
4463                         __connman_ipconfig_enable(service->ipconfig_ipv6);
4464
4465                 err = __connman_network_connect(service->network);
4466         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
4467                                         service->provider != NULL)
4468                 err = __connman_provider_connect(service->provider);
4469         else
4470                 return -EOPNOTSUPP;
4471
4472         if (err < 0) {
4473                 if (err != -EINPROGRESS) {
4474                         __connman_ipconfig_disable(service->ipconfig_ipv4);
4475                         __connman_ipconfig_disable(service->ipconfig_ipv6);
4476                         __connman_stats_service_unregister(service);
4477                 }
4478         }
4479
4480         return err;
4481 }
4482
4483
4484 int __connman_service_connect(struct connman_service *service)
4485 {
4486         int err;
4487
4488         DBG("service %p state %s", service, state2string(service->state));
4489
4490         if (is_connected(service) == TRUE)
4491                 return -EISCONN;
4492
4493         if (is_connecting(service) == TRUE)
4494                 return -EALREADY;
4495
4496         switch (service->type) {
4497         case CONNMAN_SERVICE_TYPE_UNKNOWN:
4498         case CONNMAN_SERVICE_TYPE_SYSTEM:
4499         case CONNMAN_SERVICE_TYPE_GPS:
4500         case CONNMAN_SERVICE_TYPE_GADGET:
4501                 return -EINVAL;
4502         default:
4503                 err = service_connect(service);
4504         }
4505
4506         if (err >= 0)
4507                 return 0;
4508
4509         if (err == -EINPROGRESS) {
4510                 if (service->timeout == 0)
4511                         service->timeout = g_timeout_add_seconds(
4512                                 CONNECT_TIMEOUT, connect_timeout, service);
4513
4514                 return -EINPROGRESS;
4515         }
4516
4517         __connman_service_ipconfig_indicate_state(service,
4518                                         CONNMAN_SERVICE_STATE_FAILURE,
4519                                         CONNMAN_IPCONFIG_TYPE_IPV4);
4520         __connman_service_ipconfig_indicate_state(service,
4521                                         CONNMAN_SERVICE_STATE_FAILURE,
4522                                         CONNMAN_IPCONFIG_TYPE_IPV6);
4523
4524         if (service->network != NULL)
4525                 __connman_network_disconnect(service->network);
4526         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
4527                                 service->provider != NULL)
4528                         __connman_provider_disconnect(service->provider);
4529
4530         if (service->userconnect == TRUE) {
4531                 if (err == -ENOKEY) {
4532                         if (__connman_agent_request_input(service,
4533                                                         request_input_cb,
4534                                                         NULL) == -EIO)
4535                                 return -EINPROGRESS;
4536                 }
4537                 reply_pending(service, err);
4538         }
4539
4540         return err;
4541 }
4542
4543 int __connman_service_disconnect(struct connman_service *service)
4544 {
4545         int err;
4546
4547         DBG("service %p", service);
4548
4549         if (service->network != NULL) {
4550                 err = __connman_network_disconnect(service->network);
4551         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
4552                                         service->provider != NULL)
4553                 err = __connman_provider_disconnect(service->provider);
4554         else
4555                 return -EOPNOTSUPP;
4556
4557         if (err < 0 && err != -EINPROGRESS)
4558                 return err;
4559
4560         __connman_6to4_remove(service->ipconfig_ipv4);
4561
4562         if (service->ipconfig_ipv4)
4563                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
4564                                                         NULL);
4565         else
4566                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
4567                                                         NULL);
4568
4569         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
4570         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
4571
4572         __connman_ipconfig_disable(service->ipconfig_ipv4);
4573         __connman_ipconfig_disable(service->ipconfig_ipv6);
4574
4575         __connman_stats_service_unregister(service);
4576
4577         return err;
4578 }
4579
4580 int __connman_service_disconnect_all(void)
4581 {
4582         GSequenceIter *iter;
4583
4584         DBG("");
4585
4586         iter = g_sequence_get_begin_iter(service_list);
4587
4588         while (g_sequence_iter_is_end(iter) == FALSE) {
4589                 struct connman_service *service = g_sequence_get(iter);
4590
4591                 service->ignore = TRUE;
4592
4593                 set_reconnect_state(service, FALSE);
4594
4595                 __connman_service_disconnect(service);
4596
4597                 iter = g_sequence_iter_next(iter);
4598         }
4599
4600         return 0;
4601
4602 }
4603
4604 /**
4605  * __connman_service_lookup:
4606  * @pattern: search pattern
4607  * @path: return object path
4608  *
4609  * Look up a service path from a search pattern
4610  */
4611 int __connman_service_lookup(const char *pattern, const char **path)
4612 {
4613         GHashTableIter iter;
4614         gpointer key, value;
4615
4616         g_hash_table_iter_init(&iter, service_hash);
4617
4618         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
4619                 GSequenceIter *iter = value;
4620                 struct connman_service *service = g_sequence_get(iter);
4621
4622                 if (g_strcmp0(service->identifier, pattern) == 0 ||
4623                                 g_strcmp0(service->name, pattern) == 0) {
4624                         *path = (const char *) service->path;
4625                         return 0;
4626                 }
4627         }
4628
4629         return -ENXIO;
4630 }
4631
4632 /**
4633  * lookup_by_identifier:
4634  * @identifier: service identifier
4635  *
4636  * Look up a service by identifier (reference count will not be increased)
4637  */
4638 static struct connman_service *lookup_by_identifier(const char *identifier)
4639 {
4640         GSequenceIter *iter;
4641
4642         iter = g_hash_table_lookup(service_hash, identifier);
4643         if (iter != NULL)
4644                 return g_sequence_get(iter);
4645
4646         return NULL;
4647 }
4648
4649 static struct connman_network *create_hidden_wifi(struct connman_device *device,
4650                 const char *ssid, const char *mode, const char *security,
4651                 const char *group)
4652 {
4653         struct connman_network *network;
4654         char *name;
4655         int index;
4656         unsigned int i, ssid_len;
4657
4658         ssid_len = strlen(ssid);
4659         if (ssid_len < 1)
4660                 return NULL;
4661
4662         network = connman_network_create(group, CONNMAN_NETWORK_TYPE_WIFI);
4663         if (network == NULL)
4664                 return NULL;
4665
4666         connman_network_set_blob(network, "WiFi.SSID",
4667                                         (unsigned char *) ssid, ssid_len);
4668
4669         connman_network_set_string(network, "WiFi.Mode", mode);
4670         connman_network_set_string(network, "WiFi.Security", security);
4671
4672         name = g_try_malloc0(ssid_len + 1);
4673         if (name == NULL) {
4674                 connman_network_unref(network);
4675                 return NULL;
4676         }
4677
4678         for (i = 0; i < ssid_len; i++) {
4679                 if (g_ascii_isprint(ssid[i]))
4680                         name[i] = ssid[i];
4681                 else
4682                         name[i] = ' ';
4683         }
4684
4685         connman_network_set_name(network, name);
4686
4687         g_free(name);
4688
4689         index = connman_device_get_index(device);
4690         connman_network_set_index(network, index);
4691
4692         if (connman_device_add_network(device, network) < 0) {
4693                 connman_network_unref(network);
4694                 return NULL;
4695         }
4696
4697         connman_network_set_available(network, TRUE);
4698
4699         return network;
4700 }
4701
4702 int __connman_service_create_and_connect(DBusMessage *msg)
4703 {
4704         struct connman_service *service;
4705         struct connman_network *network;
4706         struct connman_device *device;
4707         DBusMessageIter iter, array;
4708         const char *mode = "managed", *security = "none", *group_security;
4709         const char *type = NULL, *ssid = NULL, *passphrase = NULL;
4710         unsigned int ssid_len = 0;
4711         const char *ident;
4712         char *name, *group;
4713         int err;
4714
4715         dbus_message_iter_init(msg, &iter);
4716         dbus_message_iter_recurse(&iter, &array);
4717
4718         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
4719                 DBusMessageIter entry, value;
4720                 const char *key;
4721
4722                 dbus_message_iter_recurse(&array, &entry);
4723                 dbus_message_iter_get_basic(&entry, &key);
4724
4725                 dbus_message_iter_next(&entry);
4726                 dbus_message_iter_recurse(&entry, &value);
4727
4728                 switch (dbus_message_iter_get_arg_type(&value)) {
4729                 case DBUS_TYPE_STRING:
4730                         if (g_str_equal(key, "Type") == TRUE)
4731                                 dbus_message_iter_get_basic(&value, &type);
4732                         else if (g_str_equal(key, "WiFi.Mode") == TRUE ||
4733                                         g_str_equal(key, "Mode") == TRUE)
4734                                 dbus_message_iter_get_basic(&value, &mode);
4735                         else if (g_str_equal(key, "WiFi.Security") == TRUE ||
4736                                         g_str_equal(key, "Security") == TRUE)
4737                                 dbus_message_iter_get_basic(&value, &security);
4738                         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE ||
4739                                         g_str_equal(key, "Passphrase") == TRUE)
4740                                 dbus_message_iter_get_basic(&value, &passphrase);
4741                         else if (g_str_equal(key, "WiFi.SSID") == TRUE ||
4742                                         g_str_equal(key, "SSID") == TRUE)
4743                                 dbus_message_iter_get_basic(&value, &ssid);
4744                 }
4745
4746                 dbus_message_iter_next(&array);
4747         }
4748
4749         if (type == NULL)
4750                 return -EINVAL;
4751
4752         if (g_strcmp0(type, "wifi") != 0 || g_strcmp0(mode, "managed") != 0)
4753                 return -EOPNOTSUPP;
4754
4755         if (ssid == NULL)
4756                 return -EINVAL;
4757
4758         ssid_len = strlen(ssid);
4759         if (ssid_len < 1)
4760                 return -EINVAL;
4761
4762         if (g_strcmp0(security, "none") != 0 &&
4763                                 g_strcmp0(security, "wep") != 0 &&
4764                                 g_strcmp0(security, "psk") != 0 &&
4765                                 g_strcmp0(security, "wpa") != 0 &&
4766                                 g_strcmp0(security, "rsn") != 0 &&
4767                                 g_strcmp0(security, "ieee8021x") != 0)
4768                 return -EINVAL;
4769
4770         device = __connman_device_find_device(CONNMAN_SERVICE_TYPE_WIFI);
4771         if (device == NULL)
4772                 return -EOPNOTSUPP;
4773
4774         ident = connman_device_get_ident(device);
4775         if (ident == NULL)
4776                 return -EOPNOTSUPP;
4777
4778
4779         if (!g_strcmp0(security, "wpa") ||
4780                 !g_strcmp0(security, "rsn"))
4781                 group_security = "psk";
4782         else
4783                 group_security = security;
4784
4785         group = wifi_build_group_name((unsigned char *) ssid,
4786                                                 ssid_len, mode, group_security);
4787         if (group == NULL)
4788                 return -EINVAL;
4789
4790         name = g_strdup_printf("%s_%s_%s", type, ident, group);
4791
4792         service = lookup_by_identifier(name);
4793
4794         if (service != NULL)
4795                 goto done;
4796
4797         network = create_hidden_wifi(device, ssid, mode, security, group);
4798         if (network != NULL)
4799                 connman_network_set_group(network, group);
4800
4801         service = lookup_by_identifier(name);
4802
4803 done:
4804         g_free(name);
4805         g_free(group);
4806
4807         if (service == NULL) {
4808                 err = -EOPNOTSUPP;
4809                 goto failed;
4810         }
4811
4812         service->network_created = TRUE;
4813
4814         if (is_connected(service) == TRUE) {
4815                 err = -EISCONN;
4816                 goto failed;
4817         }
4818
4819         if (is_connecting(service) == TRUE) {
4820                 err = -EALREADY;
4821                 goto failed;
4822         }
4823
4824         set_reconnect_state(service, FALSE);
4825
4826         __connman_device_disconnect(device);
4827
4828         if (passphrase != NULL) {
4829                 g_free(service->passphrase);
4830                 service->passphrase = g_strdup(passphrase);
4831         }
4832
4833         service->userconnect = TRUE;
4834
4835         err = __connman_service_connect(service);
4836         if (err < 0 && err != -EINPROGRESS)
4837                 goto failed;
4838
4839         service->pending = dbus_message_ref(msg);
4840
4841         return 0;
4842
4843 failed:
4844         if (service != NULL && service->network_created == TRUE) {
4845                 struct connman_network *network = service->network;
4846
4847                 if (network != NULL) {
4848                         connman_network_set_available(network, FALSE);
4849                         __connman_device_cleanup_networks(device);
4850                 } else
4851                         __connman_service_put(service);
4852         }
4853
4854         return err;
4855 }
4856
4857 static void provision_changed(gpointer value, gpointer user_data)
4858 {
4859         struct connman_service *service = value;
4860         char *path = user_data;
4861
4862         __connman_config_provision_service_ident(service, path);
4863 }
4864
4865 void __connman_service_provision_changed(const char *ident)
4866 {
4867         g_sequence_foreach(service_list, provision_changed, (void *)ident);
4868 }
4869
4870 int __connman_service_provision(DBusMessage *msg)
4871 {
4872         GKeyFile *keyfile = NULL;
4873         const char *config_str = NULL;
4874         char *group = NULL, *ident = NULL;
4875         int err = 0;
4876         struct connman_service *service;
4877
4878         DBG("");
4879
4880         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &config_str,
4881                                                         DBUS_TYPE_INVALID);
4882
4883         if (config_str == NULL || strlen(config_str) == 0)
4884                 return -EINVAL;
4885
4886         keyfile = g_key_file_new();
4887
4888         /* populate GKeyFile with config_str */
4889         if (g_key_file_load_from_data(keyfile, config_str,
4890                                         strlen(config_str), 0, NULL) == FALSE) {
4891                 err = -EINVAL;
4892                 goto done;
4893         }
4894
4895         /*
4896          * read only one group of settings (only one service supported, no
4897          * global settings)
4898          */
4899         group = g_key_file_get_start_group(keyfile);
4900
4901         if (group == NULL || g_str_has_prefix(group, "service_") == FALSE) {
4902                 err = -EINVAL;
4903                 goto done;
4904         }
4905
4906         err = __connman_config_load_service(keyfile, group, TRUE);
4907         if (err < 0)
4908                 goto done;
4909
4910         ident = group + strlen("service_");
4911
4912         /* trigger service provisioning if service exists */
4913         service = lookup_by_identifier(ident);
4914         if (service != NULL)
4915                 __connman_config_provision_service(service);
4916
4917         g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
4918
4919 done:
4920         if (group != NULL)
4921                 g_free(group);
4922
4923         if (keyfile != NULL)
4924                 g_key_file_free(keyfile);
4925
4926         return err;
4927 }
4928
4929 /**
4930  * __connman_service_get:
4931  * @identifier: service identifier
4932  *
4933  * Look up a service by identifier or create a new one if not found
4934  */
4935 static struct connman_service *service_get(const char *identifier)
4936 {
4937         struct connman_service *service;
4938         GSequenceIter *iter;
4939
4940         iter = g_hash_table_lookup(service_hash, identifier);
4941         if (iter != NULL) {
4942                 service = g_sequence_get(iter);
4943                 if (service != NULL)
4944                         connman_service_ref(service);
4945                 return service;
4946         }
4947
4948         service = connman_service_create();
4949         if (service == NULL)
4950                 return NULL;
4951
4952         DBG("service %p", service);
4953
4954         service->identifier = g_strdup(identifier);
4955
4956         iter = g_sequence_insert_sorted(service_list, service,
4957                                                 service_compare, NULL);
4958
4959         g_hash_table_insert(service_hash, service->identifier, iter);
4960
4961         return service;
4962 }
4963
4964 static int service_register(struct connman_service *service)
4965 {
4966         GSequenceIter *iter;
4967
4968         DBG("service %p", service);
4969
4970         if (service->path != NULL)
4971                 return -EALREADY;
4972
4973         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
4974                                                 service->identifier);
4975
4976         DBG("path %s", service->path);
4977
4978         __connman_config_provision_service(service);
4979
4980         service_load(service);
4981
4982         g_dbus_register_interface(connection, service->path,
4983                                         CONNMAN_SERVICE_INTERFACE,
4984                                         service_methods, service_signals,
4985                                                         NULL, service, NULL);
4986
4987         iter = g_hash_table_lookup(service_hash, service->identifier);
4988         if (iter != NULL)
4989                 g_sequence_sort_changed(iter, service_compare, NULL);
4990
4991         services_changed(TRUE);
4992
4993         return 0;
4994 }
4995
4996 static void service_up(struct connman_ipconfig *ipconfig)
4997 {
4998         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
4999
5000         DBG("%s up", connman_ipconfig_get_ifname(ipconfig));
5001
5002         link_changed(service);
5003
5004         service->stats.valid = FALSE;
5005         service->stats_roaming.valid = FALSE;
5006 }
5007
5008 static void service_down(struct connman_ipconfig *ipconfig)
5009 {
5010         DBG("%s down", connman_ipconfig_get_ifname(ipconfig));
5011 }
5012
5013 static void service_lower_up(struct connman_ipconfig *ipconfig)
5014 {
5015         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
5016
5017         DBG("%s lower up", connman_ipconfig_get_ifname(ipconfig));
5018
5019         stats_start(service);
5020 }
5021
5022 static void service_lower_down(struct connman_ipconfig *ipconfig)
5023 {
5024         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
5025
5026         DBG("%s lower down", connman_ipconfig_get_ifname(ipconfig));
5027
5028         stats_stop(service);
5029         service_save(service);
5030 }
5031
5032 static void service_ip_bound(struct connman_ipconfig *ipconfig)
5033 {
5034         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
5035         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
5036         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
5037
5038         DBG("%s ip bound", connman_ipconfig_get_ifname(ipconfig));
5039
5040         type = __connman_ipconfig_get_config_type(ipconfig);
5041         method = __connman_ipconfig_get_method(ipconfig);
5042
5043         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
5044                                                         type, method);
5045
5046         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
5047                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
5048                 __connman_service_ipconfig_indicate_state(service,
5049                                                 CONNMAN_SERVICE_STATE_READY,
5050                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5051
5052         settings_changed(service, ipconfig);
5053 }
5054
5055 static void service_ip_release(struct connman_ipconfig *ipconfig)
5056 {
5057         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
5058         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
5059         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
5060
5061         DBG("%s ip release", connman_ipconfig_get_ifname(ipconfig));
5062
5063         type = __connman_ipconfig_get_config_type(ipconfig);
5064         method = __connman_ipconfig_get_method(ipconfig);
5065
5066         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
5067                                                         type, method);
5068
5069         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
5070                         method == CONNMAN_IPCONFIG_METHOD_OFF)
5071                 __connman_service_ipconfig_indicate_state(service,
5072                                         CONNMAN_SERVICE_STATE_DISCONNECT,
5073                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5074
5075         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
5076                         method == CONNMAN_IPCONFIG_METHOD_OFF)
5077                 __connman_service_ipconfig_indicate_state(service,
5078                                         CONNMAN_SERVICE_STATE_DISCONNECT,
5079                                         CONNMAN_IPCONFIG_TYPE_IPV4);
5080
5081         settings_changed(service, ipconfig);
5082 }
5083
5084 static const struct connman_ipconfig_ops service_ops = {
5085         .up             = service_up,
5086         .down           = service_down,
5087         .lower_up       = service_lower_up,
5088         .lower_down     = service_lower_down,
5089         .ip_bound       = service_ip_bound,
5090         .ip_release     = service_ip_release,
5091 };
5092
5093 static void setup_ip4config(struct connman_service *service, int index,
5094                         enum connman_ipconfig_method method)
5095 {
5096         if (index < 0)
5097                 return;
5098
5099         service->ipconfig_ipv4 = connman_ipconfig_create(index,
5100                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
5101         if (service->ipconfig_ipv4 == NULL)
5102                 return;
5103
5104         connman_ipconfig_set_method(service->ipconfig_ipv4, method);
5105
5106         connman_ipconfig_set_data(service->ipconfig_ipv4, service);
5107
5108         connman_ipconfig_set_ops(service->ipconfig_ipv4, &service_ops);
5109 }
5110
5111 static void setup_ip6config(struct connman_service *service, int index)
5112 {
5113         if (index < 0)
5114                 return;
5115
5116         service->ipconfig_ipv6 = connman_ipconfig_create(index,
5117                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5118         if (service->ipconfig_ipv6 == NULL)
5119                 return;
5120
5121         connman_ipconfig_set_data(service->ipconfig_ipv6, service);
5122
5123         connman_ipconfig_set_ops(service->ipconfig_ipv6, &service_ops);
5124 }
5125
5126 void __connman_service_read_ip4config(struct connman_service *service)
5127 {
5128         GKeyFile *keyfile;
5129
5130         if (service->ipconfig_ipv4 == NULL)
5131                 return;
5132
5133         keyfile = __connman_storage_open_profile("default");
5134         if (keyfile == NULL)
5135                 return;
5136
5137         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
5138                                 service->identifier, "IPv4.");
5139
5140         g_key_file_free(keyfile);
5141 }
5142
5143 void __connman_service_create_ip4config(struct connman_service *service,
5144                                         int index)
5145 {
5146         DBG("ipv4 %p", service->ipconfig_ipv4);
5147
5148         if (service->ipconfig_ipv4 != NULL)
5149                 return;
5150
5151         setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
5152         __connman_service_read_ip4config(service);
5153 }
5154
5155 void __connman_service_read_ip6config(struct connman_service *service)
5156 {
5157         GKeyFile *keyfile;
5158
5159         if (service->ipconfig_ipv6 == NULL)
5160                 return;
5161
5162         keyfile = __connman_storage_open_profile("default");
5163         if (keyfile == NULL)
5164                 return;
5165
5166         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
5167                                 service->identifier, "IPv6.");
5168
5169         g_key_file_free(keyfile);
5170 }
5171
5172 void __connman_service_create_ip6config(struct connman_service *service,
5173                                                                 int index)
5174 {
5175         DBG("ipv6 %p", service->ipconfig_ipv6);
5176
5177         if (service->ipconfig_ipv6 != NULL)
5178                 return;
5179
5180         setup_ip6config(service, index);
5181         __connman_service_read_ip6config(service);
5182 }
5183
5184 /**
5185  * __connman_service_lookup_from_network:
5186  * @network: network structure
5187  *
5188  * Look up a service by network (reference count will not be increased)
5189  */
5190 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
5191 {
5192         struct connman_service *service;
5193         const char *ident, *group;
5194         char *name;
5195
5196         DBG("network %p", network);
5197
5198         ident = __connman_network_get_ident(network);
5199         if (ident == NULL)
5200                 return NULL;
5201
5202         group = connman_network_get_group(network);
5203         if (group == NULL)
5204                 return NULL;
5205
5206         name = g_strdup_printf("%s_%s_%s",
5207                         __connman_network_get_type(network), ident, group);
5208         service = lookup_by_identifier(name);
5209         g_free(name);
5210
5211         return service;
5212 }
5213
5214 struct connman_service *__connman_service_lookup_from_index(int index)
5215 {
5216         struct connman_service *service;
5217         GSequenceIter *iter;
5218
5219         iter = g_sequence_get_begin_iter(service_list);
5220
5221         while (g_sequence_iter_is_end(iter) == FALSE) {
5222                 service = g_sequence_get(iter);
5223
5224                 if (connman_ipconfig_get_index(service->ipconfig_ipv4)
5225                                                         == index)
5226                         return service;
5227
5228                 if (connman_ipconfig_get_index(service->ipconfig_ipv6)
5229                                                         == index)
5230                         return service;
5231
5232                 iter = g_sequence_iter_next(iter);
5233         }
5234
5235         return NULL;
5236 }
5237
5238 const char *__connman_service_get_ident(struct connman_service *service)
5239 {
5240         return service->identifier;
5241 }
5242
5243 const char *__connman_service_get_path(struct connman_service *service)
5244 {
5245         return service->path;
5246 }
5247
5248 unsigned int __connman_service_get_order(struct connman_service *service)
5249 {
5250         GSequenceIter *iter;
5251
5252         if (service == NULL)
5253                 return 0;
5254
5255         if (service->favorite == FALSE) {
5256                 service->order = 0;
5257                 goto done;
5258         }
5259
5260         iter = g_hash_table_lookup(service_hash, service->identifier);
5261         if (iter != NULL) {
5262                 if (g_sequence_iter_get_position(iter) == 0)
5263                         service->order = 1;
5264                 else if (service->type == CONNMAN_SERVICE_TYPE_VPN)
5265                         service->order = 10;
5266                 else
5267                         service->order = 0;
5268         }
5269
5270 done:
5271         return service->order;
5272 }
5273
5274 static enum connman_service_type convert_network_type(struct connman_network *network)
5275 {
5276         enum connman_network_type type = connman_network_get_type(network);
5277
5278         switch (type) {
5279         case CONNMAN_NETWORK_TYPE_UNKNOWN:
5280         case CONNMAN_NETWORK_TYPE_VENDOR:
5281                 break;
5282         case CONNMAN_NETWORK_TYPE_ETHERNET:
5283                 return CONNMAN_SERVICE_TYPE_ETHERNET;
5284         case CONNMAN_NETWORK_TYPE_WIFI:
5285                 return CONNMAN_SERVICE_TYPE_WIFI;
5286         case CONNMAN_NETWORK_TYPE_WIMAX:
5287                 return CONNMAN_SERVICE_TYPE_WIMAX;
5288         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
5289         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
5290                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
5291         case CONNMAN_NETWORK_TYPE_CELLULAR:
5292                 return CONNMAN_SERVICE_TYPE_CELLULAR;
5293         }
5294
5295         return CONNMAN_SERVICE_TYPE_UNKNOWN;
5296 }
5297
5298 static enum connman_service_security convert_wifi_security(const char *security)
5299 {
5300         if (security == NULL)
5301                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
5302         else if (g_str_equal(security, "none") == TRUE)
5303                 return CONNMAN_SERVICE_SECURITY_NONE;
5304         else if (g_str_equal(security, "wep") == TRUE)
5305                 return CONNMAN_SERVICE_SECURITY_WEP;
5306         else if (g_str_equal(security, "psk") == TRUE)
5307                 return CONNMAN_SERVICE_SECURITY_PSK;
5308         else if (g_str_equal(security, "ieee8021x") == TRUE)
5309                 return CONNMAN_SERVICE_SECURITY_8021X;
5310         else if (g_str_equal(security, "wpa") == TRUE)
5311                 return CONNMAN_SERVICE_SECURITY_WPA;
5312         else if (g_str_equal(security, "rsn") == TRUE)
5313                 return CONNMAN_SERVICE_SECURITY_RSN;
5314         else
5315                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
5316 }
5317
5318 static void update_from_network(struct connman_service *service,
5319                                         struct connman_network *network)
5320 {
5321         connman_uint8_t strength = service->strength;
5322         GSequenceIter *iter;
5323         const char *str;
5324
5325         DBG("service %p network %p", service, network);
5326
5327         if (is_connected(service) == TRUE)
5328                 return;
5329
5330         if (is_connecting(service) == TRUE)
5331                 return;
5332
5333         str = connman_network_get_string(network, "Name");
5334         if (str != NULL) {
5335                 g_free(service->name);
5336                 service->name = g_strdup(str);
5337                 service->hidden = FALSE;
5338         } else {
5339                 g_free(service->name);
5340                 service->name = NULL;
5341                 service->hidden = TRUE;
5342         }
5343
5344         service->strength = connman_network_get_strength(network);
5345         service->roaming = connman_network_get_bool(network, "Roaming");
5346
5347         if (service->strength == 0) {
5348                 /*
5349                  * Filter out 0-values; it's unclear what they mean
5350                  * and they cause anomalous sorting of the priority list.
5351                  */
5352                 service->strength = strength;
5353         }
5354
5355         str = connman_network_get_string(network, "WiFi.Security");
5356         service->security = convert_wifi_security(str);
5357
5358         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
5359                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
5360
5361         if (service->strength > strength && service->network != NULL) {
5362                 service->network = network;
5363
5364                 strength_changed(service);
5365         }
5366
5367         if (service->network == NULL)
5368                 service->network = network;
5369
5370         iter = g_hash_table_lookup(service_hash, service->identifier);
5371         if (iter != NULL)
5372                 g_sequence_sort_changed(iter, service_compare, NULL);
5373 }
5374
5375 /**
5376  * __connman_service_create_from_network:
5377  * @network: network structure
5378  *
5379  * Look up service by network and if not found, create one
5380  */
5381 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
5382 {
5383         struct connman_service *service;
5384         struct connman_device *device;
5385         const char *ident, *group;
5386         char *name;
5387         int index;
5388
5389         DBG("network %p", network);
5390
5391         ident = __connman_network_get_ident(network);
5392         if (ident == NULL)
5393                 return NULL;
5394
5395         group = connman_network_get_group(network);
5396         if (group == NULL)
5397                 return NULL;
5398
5399         name = g_strdup_printf("%s_%s_%s",
5400                         __connman_network_get_type(network), ident, group);
5401         service = service_get(name);
5402         g_free(name);
5403
5404         if (service == NULL)
5405                 return NULL;
5406
5407         if (__connman_network_get_weakness(network) == TRUE)
5408                 return service;
5409
5410         if (service->path != NULL) {
5411                 update_from_network(service, network);
5412                 services_changed(TRUE);
5413                 return service;
5414         }
5415
5416         service->type = convert_network_type(network);
5417
5418         switch (service->type) {
5419         case CONNMAN_SERVICE_TYPE_UNKNOWN:
5420         case CONNMAN_SERVICE_TYPE_SYSTEM:
5421         case CONNMAN_SERVICE_TYPE_ETHERNET:
5422         case CONNMAN_SERVICE_TYPE_WIMAX:
5423         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
5424         case CONNMAN_SERVICE_TYPE_GPS:
5425         case CONNMAN_SERVICE_TYPE_VPN:
5426         case CONNMAN_SERVICE_TYPE_GADGET:
5427                 service->autoconnect = FALSE;
5428                 break;
5429         case CONNMAN_SERVICE_TYPE_WIFI:
5430         case CONNMAN_SERVICE_TYPE_CELLULAR:
5431                 service->autoconnect = TRUE;
5432                 break;
5433         }
5434
5435         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
5436         service->state = combine_state(service->state_ipv4, service->state_ipv6);
5437
5438         update_from_network(service, network);
5439
5440         index = connman_network_get_index(network);
5441
5442         if (service->ipconfig_ipv4 == NULL)
5443                 setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
5444
5445         if (service->ipconfig_ipv6 == NULL)
5446                 setup_ip6config(service, index);
5447
5448         service_register(service);
5449
5450         if (service->favorite == TRUE) {
5451                 device = connman_network_get_device(service->network);
5452                 if (device && __connman_device_scanning(device) == FALSE)
5453                         __connman_service_auto_connect();
5454         }
5455
5456         __connman_notifier_service_add(service, service->name);
5457
5458         return service;
5459 }
5460
5461 void __connman_service_update_from_network(struct connman_network *network)
5462 {
5463         struct connman_service *service;
5464         connman_uint8_t strength;
5465         connman_bool_t roaming;
5466         GSequenceIter *iter;
5467         const char *name;
5468         connman_bool_t stats_enable;
5469
5470         DBG("network %p", network);
5471
5472         service = __connman_service_lookup_from_network(network);
5473         if (service == NULL)
5474                 return;
5475
5476         if (service->network == NULL)
5477                 return;
5478
5479         name = connman_network_get_string(service->network, "Name");
5480         if (g_strcmp0(service->name, name) != 0) {
5481                 g_free(service->name);
5482                 service->name = g_strdup(name);
5483                 connman_dbus_property_changed_basic(service->path,
5484                                 CONNMAN_SERVICE_INTERFACE, "Name",
5485                                 DBUS_TYPE_STRING, &service->name);
5486         }
5487
5488         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
5489                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
5490
5491         strength = connman_network_get_strength(service->network);
5492         if (strength == service->strength)
5493                 goto roaming;
5494
5495         service->strength = strength;
5496
5497         strength_changed(service);
5498
5499 roaming:
5500         roaming = connman_network_get_bool(service->network, "Roaming");
5501         if (roaming == service->roaming)
5502                 return;
5503
5504         stats_enable = stats_enabled(service);
5505         if (stats_enable == TRUE)
5506                 stats_stop(service);
5507
5508         service->roaming = roaming;
5509
5510         if (stats_enable == TRUE)
5511                 stats_start(service);
5512
5513         roaming_changed(service);
5514
5515         iter = g_hash_table_lookup(service_hash, service->identifier);
5516         if (iter != NULL)
5517                 g_sequence_sort_changed(iter, service_compare, NULL);
5518 }
5519
5520 void __connman_service_remove_from_network(struct connman_network *network)
5521 {
5522         struct connman_service *service;
5523
5524         DBG("network %p", network);
5525
5526         service = __connman_service_lookup_from_network(network);
5527         if (service == NULL)
5528                 return;
5529
5530         __connman_service_put(service);
5531 }
5532
5533 /**
5534  * __connman_service_create_from_provider:
5535  * @provider: provider structure
5536  *
5537  * Look up service by provider and if not found, create one
5538  */
5539 struct connman_service *
5540 __connman_service_create_from_provider(struct connman_provider *provider)
5541 {
5542         struct connman_service *service;
5543         const char *ident, *str;
5544         char *name;
5545         int index = connman_provider_get_index(provider);
5546
5547         DBG("provider %p", provider);
5548
5549         ident = __connman_provider_get_ident(provider);
5550         if (ident == NULL)
5551                 return NULL;
5552
5553         name = g_strdup_printf("vpn_%s", ident);
5554         service = service_get(name);
5555         g_free(name);
5556
5557         if (service == NULL)
5558                 return NULL;
5559
5560         service->type = CONNMAN_SERVICE_TYPE_VPN;
5561         service->provider = connman_provider_ref(provider);
5562         service->autoconnect = FALSE;
5563         service->userconnect = TRUE;
5564
5565         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
5566
5567         str = connman_provider_get_string(provider, "Name");
5568         if (str != NULL) {
5569                 g_free(service->name);
5570                 service->name = g_strdup(str);
5571                 service->hidden = FALSE;
5572         } else {
5573                 g_free(service->name);
5574                 service->name = NULL;
5575                 service->hidden = TRUE;
5576         }
5577
5578         service->strength = 0;
5579
5580         if (service->ipconfig_ipv4 == NULL)
5581                 setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_MANUAL);
5582
5583         if (service->ipconfig_ipv6 == NULL)
5584                 setup_ip6config(service, index);
5585
5586         service_register(service);
5587
5588         __connman_notifier_service_add(service, service->name);
5589
5590         return service;
5591 }
5592
5593 void __connman_service_downgrade_state(struct connman_service *service)
5594 {
5595         if (service == NULL)
5596                 return;
5597
5598         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
5599                                                 service->state_ipv6);
5600
5601         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
5602                 __connman_service_ipconfig_indicate_state(service,
5603                                                 CONNMAN_SERVICE_STATE_READY,
5604                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
5605
5606         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
5607                 __connman_service_ipconfig_indicate_state(service,
5608                                                 CONNMAN_SERVICE_STATE_READY,
5609                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5610 }
5611
5612 int __connman_service_init(void)
5613 {
5614         DBG("");
5615
5616         connection = connman_dbus_get_connection();
5617
5618         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
5619                                                                 NULL, NULL);
5620
5621         service_list = g_sequence_new(service_free);
5622
5623         return 0;
5624 }
5625
5626 void __connman_service_cleanup(void)
5627 {
5628         GSequence *list;
5629
5630         DBG("");
5631
5632         list = service_list;
5633         service_list = NULL;
5634         g_sequence_free(list);
5635
5636         g_hash_table_destroy(service_hash);
5637         service_hash = NULL;
5638
5639         g_slist_free(counter_list);
5640         counter_list = NULL;
5641
5642         dbus_connection_unref(connection);
5643 }