service: Directly use service load/save functions
[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         old_method = __connman_ipconfig_get_method(ipconfig);
2736
2737         if (is_connecting_state(service, state) ||
2738                                         is_connected_state(service, state))
2739                 __connman_network_clear_ipconfig(service->network, ipconfig);
2740
2741         err = __connman_ipconfig_set_config(ipconfig, array);
2742         method = __connman_ipconfig_get_method(ipconfig);
2743         type = __connman_ipconfig_get_config_type(ipconfig);
2744
2745         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
2746                 if (err == 0 && old_method == CONNMAN_IPCONFIG_METHOD_OFF &&
2747                                 method == CONNMAN_IPCONFIG_METHOD_DHCP) {
2748                         *new_state = service->state_ipv4 =
2749                                 CONNMAN_SERVICE_STATE_CONFIGURATION;
2750                         __connman_ipconfig_enable(ipconfig);
2751                 }
2752
2753         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
2754                 if (err == 0 && old_method == CONNMAN_IPCONFIG_METHOD_OFF &&
2755                                 method == CONNMAN_IPCONFIG_METHOD_AUTO) {
2756                         *new_state = service->state_ipv6;
2757                         __connman_ipconfig_enable(ipconfig);
2758                 }
2759         }
2760
2761         DBG("err %d ipconfig %p type %d method %d state %s", err, ipconfig,
2762                 type, method, state2string(*new_state));
2763
2764         return err;
2765 }
2766
2767 static DBusMessage *set_property(DBusConnection *conn,
2768                                         DBusMessage *msg, void *user_data)
2769 {
2770         struct connman_service *service = user_data;
2771         DBusMessageIter iter, value;
2772         const char *name;
2773         int type;
2774
2775         DBG("service %p", service);
2776
2777         if (dbus_message_iter_init(msg, &iter) == FALSE)
2778                 return __connman_error_invalid_arguments(msg);
2779
2780         dbus_message_iter_get_basic(&iter, &name);
2781         dbus_message_iter_next(&iter);
2782         dbus_message_iter_recurse(&iter, &value);
2783
2784         type = dbus_message_iter_get_arg_type(&value);
2785
2786         if (g_str_equal(name, "AutoConnect") == TRUE) {
2787                 connman_bool_t autoconnect;
2788
2789                 if (type != DBUS_TYPE_BOOLEAN)
2790                         return __connman_error_invalid_arguments(msg);
2791
2792                 if (service->favorite == FALSE)
2793                         return __connman_error_invalid_service(msg);
2794
2795                 dbus_message_iter_get_basic(&value, &autoconnect);
2796
2797                 if (service->autoconnect == autoconnect)
2798                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2799
2800                 service->autoconnect = autoconnect;
2801
2802                 autoconnect_changed(service);
2803
2804                 service_save(service);
2805         } else if (g_str_equal(name, "Passphrase") == TRUE) {
2806                 const char *passphrase;
2807
2808                 if (type != DBUS_TYPE_STRING)
2809                         return __connman_error_invalid_arguments(msg);
2810
2811                 if (service->immutable == TRUE)
2812                         return __connman_error_not_supported(msg);
2813
2814                 dbus_message_iter_get_basic(&value, &passphrase);
2815
2816                 __connman_service_set_passphrase(service, passphrase);
2817         } else if (g_str_equal(name, "Nameservers.Configuration") == TRUE) {
2818                 DBusMessageIter entry;
2819                 GString *str;
2820                 int index;
2821                 const char *gw;
2822
2823                 if (type != DBUS_TYPE_ARRAY)
2824                         return __connman_error_invalid_arguments(msg);
2825
2826                 str = g_string_new(NULL);
2827                 if (str == NULL)
2828                         return __connman_error_invalid_arguments(msg);
2829
2830                 index = connman_network_get_index(service->network);
2831                 gw = __connman_ipconfig_get_gateway_from_index(index);
2832
2833                 if (gw && strlen(gw))
2834                         __connman_service_nameserver_del_routes(service);
2835
2836                 dbus_message_iter_recurse(&value, &entry);
2837
2838                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
2839                         const char *val;
2840                         dbus_message_iter_get_basic(&entry, &val);
2841                         dbus_message_iter_next(&entry);
2842                         if (str->len > 0)
2843                                 g_string_append_printf(str, " %s", val);
2844                         else
2845                                 g_string_append(str, val);
2846                 }
2847
2848                 g_strfreev(service->nameservers_config);
2849
2850                 if (str->len > 0) {
2851                         service->nameservers_config =
2852                                 g_strsplit_set(str->str, " ", 0);
2853                 } else {
2854                         service->nameservers_config = NULL;
2855                 }
2856
2857                 g_string_free(str, TRUE);
2858
2859                 if (gw && strlen(gw))
2860                         __connman_service_nameserver_add_routes(service, gw);
2861
2862                 update_nameservers(service);
2863                 dns_configuration_changed(service);
2864
2865                 service_save(service);
2866         } else if (g_str_equal(name, "Domains.Configuration") == TRUE) {
2867                 DBusMessageIter entry;
2868                 GString *str;
2869
2870                 if (type != DBUS_TYPE_ARRAY)
2871                         return __connman_error_invalid_arguments(msg);
2872
2873                 str = g_string_new(NULL);
2874                 if (str == NULL)
2875                         return __connman_error_invalid_arguments(msg);
2876
2877                 dbus_message_iter_recurse(&value, &entry);
2878
2879                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
2880                         const char *val;
2881                         dbus_message_iter_get_basic(&entry, &val);
2882                         dbus_message_iter_next(&entry);
2883                         if (str->len > 0)
2884                                 g_string_append_printf(str, " %s", val);
2885                         else
2886                                 g_string_append(str, val);
2887                 }
2888
2889                 g_strfreev(service->domains);
2890
2891                 if (str->len > 0)
2892                         service->domains = g_strsplit_set(str->str, " ", 0);
2893                 else
2894                         service->domains = NULL;
2895
2896                 g_string_free(str, TRUE);
2897
2898                 update_nameservers(service);
2899                 domain_configuration_changed(service);
2900
2901                 service_save(service);
2902         } else if (g_str_equal(name, "Proxy.Configuration") == TRUE) {
2903                 int err;
2904
2905                 if (type != DBUS_TYPE_ARRAY)
2906                         return __connman_error_invalid_arguments(msg);
2907
2908                 err = update_proxy_configuration(service, &value);
2909
2910                 if (err < 0)
2911                         return __connman_error_failed(msg, -err);
2912
2913                 proxy_configuration_changed(service);
2914
2915                 __connman_notifier_proxy_changed(service);
2916
2917                 service_save(service);
2918         } else if (g_str_equal(name, "IPv4.Configuration") == TRUE ||
2919                         g_str_equal(name, "IPv6.Configuration")) {
2920
2921                 struct connman_ipconfig *ipv4 = NULL, *ipv6 = NULL;
2922                 enum connman_service_state state =
2923                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
2924                 int err = 0;
2925
2926                 DBG("%s", name);
2927
2928                 if (service->ipconfig_ipv4 == NULL &&
2929                                         service->ipconfig_ipv6 == NULL)
2930                         return __connman_error_invalid_property(msg);
2931
2932                 if (g_str_equal(name, "IPv4.Configuration") == TRUE) {
2933                         ipv4 = service->ipconfig_ipv4;
2934                         err = set_ipconfig(service, ipv4, &value,
2935                                         service->state_ipv4, &state);
2936
2937                 } else if (g_str_equal(name, "IPv6.Configuration") == TRUE) {
2938                         ipv6 = service->ipconfig_ipv6;
2939                         err = set_ipconfig(service, ipv6, &value,
2940                                         service->state_ipv6, &state);
2941                 }
2942
2943                 if (err < 0) {
2944                         if (is_connected_state(service, state) ||
2945                                         is_connecting_state(service, state))
2946                                 __connman_network_set_ipconfig(service->network,
2947                                                                 ipv4, ipv6);
2948                         return __connman_error_failed(msg, -err);
2949                 }
2950
2951                 if (ipv4)
2952                         ipv4_configuration_changed(service);
2953                 else if (ipv6)
2954                         ipv6_configuration_changed(service);
2955
2956                 if (is_connecting(service) || is_connected(service))
2957                         __connman_network_set_ipconfig(service->network,
2958                                                         ipv4, ipv6);
2959
2960                 service_save(service);
2961         } else
2962                 return __connman_error_invalid_property(msg);
2963
2964         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2965 }
2966
2967 static void set_idle(struct connman_service *service)
2968 {
2969         service->state = service->state_ipv4 = service->state_ipv6 =
2970                                                 CONNMAN_SERVICE_STATE_IDLE;
2971         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
2972         state_changed(service);
2973 }
2974
2975 static DBusMessage *clear_property(DBusConnection *conn,
2976                                         DBusMessage *msg, void *user_data)
2977 {
2978         struct connman_service *service = user_data;
2979         const char *name;
2980
2981         DBG("service %p", service);
2982
2983         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
2984                                                         DBUS_TYPE_INVALID);
2985
2986         if (g_str_equal(name, "Error") == TRUE) {
2987                 set_idle(service);
2988
2989                 g_get_current_time(&service->modified);
2990                 service_save(service);
2991         } else if (g_str_equal(name, "Passphrase") == TRUE) {
2992                 if (service->immutable == TRUE)
2993                         return __connman_error_not_supported(msg);
2994
2995                 g_free(service->passphrase);
2996                 service->passphrase = NULL;
2997
2998                 passphrase_changed(service);
2999
3000                 service_save(service);
3001         } else
3002                 return __connman_error_invalid_property(msg);
3003
3004         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3005 }
3006
3007 static connman_bool_t is_ignore(struct connman_service *service)
3008 {
3009         if (service->autoconnect == FALSE)
3010                 return TRUE;
3011
3012         if (service->roaming == TRUE)
3013                 return TRUE;
3014
3015         if (service->ignore == TRUE)
3016                 return TRUE;
3017
3018         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
3019                 return TRUE;
3020
3021         return FALSE;
3022 }
3023
3024 void __connman_service_auto_connect(void)
3025 {
3026         struct connman_service *service = NULL;
3027         GSequenceIter *iter;
3028
3029         DBG("");
3030
3031         if (__connman_session_mode() == TRUE) {
3032                 DBG("Session mode enabled: auto connect disabled");
3033                 return;
3034         }
3035
3036         iter = g_sequence_get_begin_iter(service_list);
3037
3038         while (g_sequence_iter_is_end(iter) == FALSE) {
3039                 service = g_sequence_get(iter);
3040
3041                 if (service->pending != NULL)
3042                         return;
3043
3044                 if (is_connecting(service) == TRUE)
3045                         return;
3046
3047                 if (service->favorite == FALSE)
3048                         return;
3049
3050                 if (is_connected(service) == TRUE)
3051                         return;
3052
3053                 if (is_ignore(service) == FALSE && service->state ==
3054                                                 CONNMAN_SERVICE_STATE_IDLE)
3055                         break;
3056
3057                 service = NULL;
3058
3059                 iter = g_sequence_iter_next(iter);
3060         }
3061
3062         if (service != NULL) {
3063                 service->userconnect = FALSE;
3064                 __connman_service_connect(service);
3065         }
3066 }
3067
3068 static void remove_timeout(struct connman_service *service)
3069 {
3070         if (service->timeout > 0) {
3071                 g_source_remove(service->timeout);
3072                 service->timeout = 0;
3073         }
3074 }
3075
3076 static void reply_pending(struct connman_service *service, int error)
3077 {
3078         remove_timeout(service);
3079
3080         if (service->pending != NULL) {
3081                 if (error > 0) {
3082                         DBusMessage *reply;
3083
3084                         reply = __connman_error_failed(service->pending,
3085                                                                 error);
3086                         if (reply != NULL)
3087                                 g_dbus_send_message(connection, reply);
3088                 } else {
3089                         const char *sender;
3090
3091                         sender = dbus_message_get_interface(service->pending);
3092
3093                         DBG("sender %s", sender);
3094
3095                         if (g_strcmp0(sender, CONNMAN_MANAGER_INTERFACE) == 0)
3096                                 g_dbus_send_reply(connection, service->pending,
3097                                         DBUS_TYPE_OBJECT_PATH, &service->path,
3098                                                         DBUS_TYPE_INVALID);
3099                         else
3100                                 g_dbus_send_reply(connection, service->pending,
3101                                                         DBUS_TYPE_INVALID);
3102                 }
3103
3104                 dbus_message_unref(service->pending);
3105                 service->pending = NULL;
3106         }
3107 }
3108
3109 static gboolean connect_timeout(gpointer user_data)
3110 {
3111         struct connman_service *service = user_data;
3112         connman_bool_t autoconnect = FALSE;
3113
3114         DBG("service %p", service);
3115
3116         service->timeout = 0;
3117
3118         if (service->network != NULL)
3119                 __connman_network_disconnect(service->network);
3120
3121         __connman_ipconfig_disable(service->ipconfig_ipv4);
3122         __connman_ipconfig_disable(service->ipconfig_ipv6);
3123
3124         __connman_stats_service_unregister(service);
3125
3126         if (service->pending != NULL) {
3127                 DBusMessage *reply;
3128
3129                 reply = __connman_error_operation_timeout(service->pending);
3130                 if (reply != NULL)
3131                         g_dbus_send_message(connection, reply);
3132
3133                 dbus_message_unref(service->pending);
3134                 service->pending = NULL;
3135         } else
3136                 autoconnect = TRUE;
3137
3138         __connman_service_ipconfig_indicate_state(service,
3139                                         CONNMAN_SERVICE_STATE_FAILURE,
3140                                         CONNMAN_IPCONFIG_TYPE_IPV4);
3141         __connman_service_ipconfig_indicate_state(service,
3142                                         CONNMAN_SERVICE_STATE_FAILURE,
3143                                         CONNMAN_IPCONFIG_TYPE_IPV6);
3144
3145         if (autoconnect == TRUE && service->userconnect == FALSE)
3146                 __connman_service_auto_connect();
3147
3148         return FALSE;
3149 }
3150
3151 static void set_reconnect_state(struct connman_service *service,
3152                                                 connman_bool_t reconnect)
3153 {
3154         struct connman_device *device;
3155
3156         if (service->network == NULL)
3157                 return;
3158
3159         device = connman_network_get_device(service->network);
3160         if (device == NULL)
3161                 return;
3162
3163         __connman_device_set_reconnect(device, reconnect);
3164 }
3165
3166 static connman_bool_t get_reconnect_state(struct connman_service *service)
3167 {
3168         struct connman_device *device;
3169
3170         if (service->network == NULL)
3171                 return FALSE;
3172
3173         device = connman_network_get_device(service->network);
3174         if (device == NULL)
3175                 return FALSE;
3176
3177         return __connman_device_get_reconnect(device);
3178 }
3179
3180 static void request_input_cb (struct connman_service *service,
3181                         const char *identity, const char *passphrase,
3182                         void *user_data)
3183 {
3184         DBG ("RequestInput return, %p", service);
3185
3186         if (identity == NULL && passphrase == NULL && service->wps == FALSE)
3187                 return;
3188
3189         if (identity != NULL)
3190                 __connman_service_set_agent_identity(service, identity);
3191
3192         if (passphrase != NULL) {
3193                 switch (service->security) {
3194                 case CONNMAN_SERVICE_SECURITY_WEP:
3195                 case CONNMAN_SERVICE_SECURITY_PSK:
3196                         __connman_service_set_passphrase(service, passphrase);
3197                         break;
3198                 case CONNMAN_SERVICE_SECURITY_8021X:
3199                         __connman_service_set_agent_passphrase(service,
3200                                                         passphrase);
3201                         break;
3202                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
3203                 case CONNMAN_SERVICE_SECURITY_NONE:
3204                 case CONNMAN_SERVICE_SECURITY_WPA:
3205                 case CONNMAN_SERVICE_SECURITY_RSN:
3206                         DBG("service security '%s' not handled",
3207                                 security2string(service->security));
3208                         break;
3209                 }
3210         }
3211
3212         __connman_service_connect(service);
3213
3214         /* Never cache agent provided credentials */
3215         __connman_service_set_agent_identity(service, NULL);
3216         __connman_service_set_agent_passphrase(service, NULL);
3217 }
3218
3219 static DBusMessage *connect_service(DBusConnection *conn,
3220                                         DBusMessage *msg, void *user_data)
3221 {
3222         struct connman_service *service = user_data;
3223         GSequenceIter *iter;
3224         int err;
3225
3226         DBG("service %p", service);
3227
3228         if (service->pending != NULL)
3229                 return __connman_error_in_progress(msg);
3230
3231         iter = g_sequence_get_begin_iter(service_list);
3232
3233         while (g_sequence_iter_is_end(iter) == FALSE) {
3234                 struct connman_service *temp = g_sequence_get(iter);
3235
3236                 if (service->type == temp->type && is_connecting(temp) == TRUE)
3237                         return __connman_error_in_progress(msg);
3238
3239                 iter = g_sequence_iter_next(iter);
3240         }
3241
3242         service->ignore = FALSE;
3243
3244         service->userconnect = TRUE;
3245
3246         service->pending = dbus_message_ref(msg);
3247
3248         set_reconnect_state(service, FALSE);
3249
3250         err = __connman_service_connect(service);
3251         if (err < 0) {
3252                 if (service->pending == NULL)
3253                         return NULL;
3254
3255                 if (err != -EINPROGRESS) {
3256                         dbus_message_unref(service->pending);
3257                         service->pending = NULL;
3258
3259                         return __connman_error_failed(msg, -err);
3260                 }
3261
3262                 return NULL;
3263         }
3264
3265         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3266 }
3267
3268 static DBusMessage *disconnect_service(DBusConnection *conn,
3269                                         DBusMessage *msg, void *user_data)
3270 {
3271         struct connman_service *service = user_data;
3272         int err;
3273
3274         DBG("service %p", service);
3275
3276         reply_pending(service, ECONNABORTED);
3277
3278         service->ignore = TRUE;
3279
3280         set_reconnect_state(service, FALSE);
3281
3282         err = __connman_service_disconnect(service);
3283         if (err < 0) {
3284                 if (err != -EINPROGRESS)
3285                         return __connman_error_failed(msg, -err);
3286
3287                 return NULL;
3288         }
3289
3290         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3291 }
3292
3293 static DBusMessage *remove_service(DBusConnection *conn,
3294                                         DBusMessage *msg, void *user_data)
3295 {
3296         struct connman_service *service = user_data;
3297
3298         DBG("service %p", service);
3299
3300         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
3301                 return __connman_error_not_supported(msg);
3302
3303         if (service->immutable == TRUE)
3304                 return __connman_error_not_supported(msg);
3305
3306         if (service->favorite == FALSE && service->state !=
3307                                                 CONNMAN_SERVICE_STATE_FAILURE)
3308                 return __connman_error_not_supported(msg);
3309
3310         if (service->network != NULL) {
3311                 set_reconnect_state(service, FALSE);
3312
3313                 __connman_network_disconnect(service->network);
3314         }
3315
3316         g_free(service->passphrase);
3317         service->passphrase = NULL;
3318
3319         passphrase_changed(service);
3320
3321         set_idle(service);
3322
3323         __connman_service_set_favorite(service, FALSE);
3324         service_save(service);
3325
3326         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3327 }
3328
3329 static gboolean check_suitable_state(enum connman_service_state a,
3330                                         enum connman_service_state b)
3331 {
3332         /*
3333          * Special check so that "ready" service can be moved before
3334          * "online" one.
3335          */
3336         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
3337                         b == CONNMAN_SERVICE_STATE_READY) ||
3338                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
3339                         a == CONNMAN_SERVICE_STATE_READY))
3340                 return TRUE;
3341
3342         return a == b;
3343 }
3344
3345 static DBusMessage *move_service(DBusConnection *conn,
3346                                         DBusMessage *msg, void *user_data,
3347                                                                 gboolean before)
3348 {
3349         struct connman_service *service = user_data;
3350         struct connman_service *target;
3351         const char *path;
3352         GSequenceIter *src, *dst;
3353         enum connman_ipconfig_method target4, target6;
3354         enum connman_ipconfig_method service4, service6;
3355
3356         DBG("service %p", service);
3357
3358         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
3359                                                         DBUS_TYPE_INVALID);
3360
3361         if (service->favorite == FALSE)
3362                 return __connman_error_not_supported(msg);
3363
3364         target = find_service(path);
3365         if (target == NULL || target->favorite == FALSE || target == service)
3366                 return __connman_error_invalid_service(msg);
3367
3368         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
3369         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
3370         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
3371         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
3372
3373         DBG("target %s method %d/%d state %d/%d", target->identifier,
3374                                 target4, target6,
3375                                 target->state_ipv4, target->state_ipv6);
3376
3377         DBG("service %s method %d/%d state %d/%d", service->identifier,
3378                                 service4, service6,
3379                                 service->state_ipv4, service->state_ipv6);
3380
3381         /*
3382          * If method is OFF, then we do not need to check the corresponding
3383          * ipconfig state.
3384          */
3385         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
3386                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
3387                         if (check_suitable_state(target->state_ipv6,
3388                                                 service->state_ipv6) == FALSE)
3389                                 return __connman_error_invalid_service(msg);
3390                 }
3391         }
3392
3393         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
3394                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
3395                         if (check_suitable_state(target->state_ipv4,
3396                                                 service->state_ipv4) == FALSE)
3397                                 return __connman_error_invalid_service(msg);
3398                 }
3399         }
3400
3401         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
3402                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
3403                         if (check_suitable_state(target->state_ipv6,
3404                                                 service->state_ipv6) == FALSE)
3405                                 return __connman_error_invalid_service(msg);
3406                 }
3407         }
3408
3409         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
3410                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
3411                         if (check_suitable_state(target->state_ipv4,
3412                                                 service->state_ipv4) == FALSE)
3413                                 return __connman_error_invalid_service(msg);
3414                 }
3415         }
3416
3417         g_get_current_time(&service->modified);
3418         service_save(service);
3419
3420         src = g_hash_table_lookup(service_hash, service->identifier);
3421         dst = g_hash_table_lookup(service_hash, target->identifier);
3422
3423         before ? g_sequence_move(src, dst) : g_sequence_move(dst, src);
3424
3425         services_changed(FALSE);
3426
3427         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3428 }
3429
3430 static DBusMessage *move_before(DBusConnection *conn,
3431                                         DBusMessage *msg, void *user_data)
3432 {
3433         return move_service(conn, msg, user_data, TRUE);
3434 }
3435
3436 static DBusMessage *move_after(DBusConnection *conn,
3437                                         DBusMessage *msg, void *user_data)
3438 {
3439         return move_service(conn, msg, user_data, FALSE);
3440 }
3441
3442 static DBusMessage *reset_counters(DBusConnection *conn,
3443                                         DBusMessage *msg, void *user_data)
3444 {
3445         struct connman_service *service = user_data;
3446
3447         reset_stats(service);
3448
3449         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3450 }
3451
3452 static GDBusMethodTable service_methods[] = {
3453         { "GetProperties", "",   "a{sv}", get_properties     },
3454         { "SetProperty",   "sv", "",      set_property       },
3455         { "ClearProperty", "s",  "",      clear_property     },
3456         { "Connect",       "",   "",      connect_service,
3457                                                 G_DBUS_METHOD_FLAG_ASYNC },
3458         { "Disconnect",    "",   "",      disconnect_service },
3459         { "Remove",        "",   "",      remove_service     },
3460         { "MoveBefore",    "o",  "",      move_before        },
3461         { "MoveAfter",     "o",  "",      move_after         },
3462         { "ResetCounters", "",   "",      reset_counters     },
3463         { },
3464 };
3465
3466 static GDBusSignalTable service_signals[] = {
3467         { "PropertyChanged", "sv" },
3468         { },
3469 };
3470
3471 static void service_free(gpointer user_data)
3472 {
3473         struct connman_service *service = user_data;
3474         char *path = service->path;
3475
3476         DBG("service %p", service);
3477
3478         reply_pending(service, ENOENT);
3479
3480         g_hash_table_remove(service_hash, service->identifier);
3481
3482         __connman_notifier_service_remove(service);
3483
3484         stats_stop(service);
3485         service_save(service);
3486
3487         service->path = NULL;
3488
3489         if (path != NULL) {
3490                 services_changed(FALSE);
3491
3492                 g_dbus_unregister_interface(connection, path,
3493                                                 CONNMAN_SERVICE_INTERFACE);
3494                 g_free(path);
3495         }
3496
3497         g_hash_table_destroy(service->counter_table);
3498
3499         if (service->network != NULL) {
3500                 if (service->network_created == TRUE)
3501                         connman_network_unref(service->network);
3502         }
3503
3504         if (service->provider != NULL)
3505                 connman_provider_unref(service->provider);
3506
3507         if (service->ipconfig_ipv4 != NULL) {
3508                 connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
3509                 connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
3510                 connman_ipconfig_unref(service->ipconfig_ipv4);
3511                 service->ipconfig_ipv4 = NULL;
3512         }
3513
3514         if (service->ipconfig_ipv6 != NULL) {
3515                 connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
3516                 connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
3517                 connman_ipconfig_unref(service->ipconfig_ipv6);
3518                 service->ipconfig_ipv6 = NULL;
3519         }
3520
3521         if (service->location != NULL)
3522                 connman_location_unref(service->location);
3523
3524         g_strfreev(service->nameservers);
3525         g_strfreev(service->nameservers_config);
3526         g_strfreev(service->domains);
3527         g_strfreev(service->proxies);
3528         g_strfreev(service->excludes);
3529
3530         g_free(service->domainname);
3531         g_free(service->pac);
3532         g_free(service->name);
3533         g_free(service->passphrase);
3534         g_free(service->agent_passphrase);
3535         g_free(service->identifier);
3536         g_free(service->eap);
3537         g_free(service->identity);
3538         g_free(service->agent_identity);
3539         g_free(service->ca_cert_file);
3540         g_free(service->client_cert_file);
3541         g_free(service->private_key_file);
3542         g_free(service->private_key_passphrase);
3543         g_free(service->phase2);
3544
3545         if (service->stats.timer != NULL)
3546                 g_timer_destroy(service->stats.timer);
3547         if (service->stats_roaming.timer != NULL)
3548                 g_timer_destroy(service->stats_roaming.timer);
3549
3550         g_free(service);
3551 }
3552
3553 /**
3554  * __connman_service_put:
3555  * @service: service structure
3556  *
3557  * Release service if no longer needed
3558  */
3559 void __connman_service_put(struct connman_service *service)
3560 {
3561         DBG("service %p", service);
3562
3563         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
3564                 GSequenceIter *iter;
3565
3566                 iter = g_hash_table_lookup(service_hash, service->identifier);
3567                 if (iter != NULL) {
3568                         reply_pending(service, ECONNABORTED);
3569
3570                         __connman_service_disconnect(service);
3571
3572                         g_sequence_remove(iter);
3573                 } else
3574                         service_free(service);
3575         }
3576 }
3577
3578 static void stats_init(struct connman_service *service)
3579 {
3580         /* home */
3581         service->stats.valid = FALSE;
3582         service->stats.enabled = FALSE;
3583         service->stats.timer = g_timer_new();
3584
3585         /* roaming */
3586         service->stats_roaming.valid = FALSE;
3587         service->stats_roaming.enabled = FALSE;
3588         service->stats_roaming.timer = g_timer_new();
3589 }
3590
3591 static void service_initialize(struct connman_service *service)
3592 {
3593         DBG("service %p", service);
3594
3595         service->refcount = 1;
3596         service->session_usage_count = 0;
3597
3598         service->network_created = FALSE;
3599
3600         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
3601         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
3602
3603         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
3604         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
3605         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
3606
3607         service->favorite  = FALSE;
3608         service->immutable = FALSE;
3609         service->hidden = FALSE;
3610
3611         service->ignore = FALSE;
3612
3613         service->userconnect = FALSE;
3614
3615         service->order = 0;
3616
3617         stats_init(service);
3618
3619         service->provider = NULL;
3620
3621         service->wps = FALSE;
3622 }
3623
3624 /**
3625  * connman_service_create:
3626  *
3627  * Allocate a new service.
3628  *
3629  * Returns: a newly-allocated #connman_service structure
3630  */
3631 struct connman_service *connman_service_create(void)
3632 {
3633         GSList *list;
3634         struct connman_stats_counter *counters;
3635         const char *counter;
3636
3637         struct connman_service *service;
3638
3639         service = g_try_new0(struct connman_service, 1);
3640         if (service == NULL)
3641                 return NULL;
3642
3643         DBG("service %p", service);
3644
3645         service->counter_table = g_hash_table_new_full(g_str_hash,
3646                                                 g_str_equal, NULL, g_free);
3647
3648         for (list = counter_list; list; list = list->next) {
3649                 counter = list->data;
3650
3651                 counters = g_try_new0(struct connman_stats_counter, 1);
3652                 if (counters == NULL) {
3653                         g_hash_table_destroy(service->counter_table);
3654                         g_free(service);
3655                         return NULL;
3656                 }
3657
3658                 counters->append_all = TRUE;
3659
3660                 g_hash_table_replace(service->counter_table, (gpointer)counter,
3661                                 counters);
3662         }
3663
3664         service_initialize(service);
3665
3666         service->location = __connman_location_create(service);
3667
3668         return service;
3669 }
3670
3671 struct connman_location *__connman_service_get_location(struct connman_service *service)
3672 {
3673         return service->location;
3674 }
3675
3676 /**
3677  * connman_service_ref:
3678  * @service: service structure
3679  *
3680  * Increase reference counter of service
3681  */
3682 struct connman_service *connman_service_ref(struct connman_service *service)
3683 {
3684         DBG("%p", service);
3685
3686         g_atomic_int_inc(&service->refcount);
3687
3688         return service;
3689 }
3690
3691 /**
3692  * connman_service_unref:
3693  * @service: service structure
3694  *
3695  * Decrease reference counter of service
3696  */
3697 void connman_service_unref(struct connman_service *service)
3698 {
3699         __connman_service_put(service);
3700 }
3701
3702 static gint service_compare(gconstpointer a, gconstpointer b,
3703                                                         gpointer user_data)
3704 {
3705         struct connman_service *service_a = (void *) a;
3706         struct connman_service *service_b = (void *) b;
3707         enum connman_service_state state_a, state_b;
3708
3709         state_a = service_a->state;
3710         state_b = service_b->state;
3711
3712         if (state_a != state_b) {
3713                 gboolean a_connected = is_connected(service_a);
3714                 gboolean b_connected = is_connected(service_b);
3715
3716                 if (a_connected == TRUE && b_connected == TRUE) {
3717                         /* We prefer online over ready state */
3718                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
3719                                 return -1;
3720
3721                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
3722                                 return 1;
3723                 }
3724
3725                 if (a_connected == TRUE)
3726                         return -1;
3727                 if (b_connected == TRUE)
3728                         return 1;
3729
3730                 if (is_connecting(service_a) == TRUE)
3731                         return -1;
3732                 if (is_connecting(service_b) == TRUE)
3733                         return 1;
3734         }
3735
3736         if (service_a->order > service_b->order)
3737                 return -1;
3738
3739         if (service_a->order < service_b->order)
3740                 return 1;
3741
3742         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
3743                 return -1;
3744
3745         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
3746                 return 1;
3747
3748         if (service_a->type != service_b->type) {
3749                 switch (service_a->type) {
3750                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
3751                 case CONNMAN_SERVICE_TYPE_SYSTEM:
3752                 case CONNMAN_SERVICE_TYPE_ETHERNET:
3753                 case CONNMAN_SERVICE_TYPE_GPS:
3754                 case CONNMAN_SERVICE_TYPE_VPN:
3755                 case CONNMAN_SERVICE_TYPE_GADGET:
3756                         break;
3757                 case CONNMAN_SERVICE_TYPE_WIFI:
3758                         return 1;
3759                 case CONNMAN_SERVICE_TYPE_WIMAX:
3760                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
3761                 case CONNMAN_SERVICE_TYPE_CELLULAR:
3762                         return -1;
3763                 }
3764         }
3765
3766         return (gint) service_b->strength - (gint) service_a->strength;
3767 }
3768
3769 /**
3770  * connman_service_get_type:
3771  * @service: service structure
3772  *
3773  * Get the type of service
3774  */
3775 enum connman_service_type connman_service_get_type(struct connman_service *service)
3776 {
3777         if (service == NULL)
3778                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
3779
3780         return service->type;
3781 }
3782
3783 /**
3784  * connman_service_get_interface:
3785  * @service: service structure
3786  *
3787  * Get network interface of service
3788  */
3789 char *connman_service_get_interface(struct connman_service *service)
3790 {
3791         int index;
3792
3793         if (service == NULL)
3794                 return NULL;
3795
3796         if (service->type == CONNMAN_SERVICE_TYPE_VPN) {
3797                 if (service->ipconfig_ipv4)
3798                         index = connman_ipconfig_get_index(
3799                                                 service->ipconfig_ipv4);
3800                 else if (service->ipconfig_ipv6)
3801                         index = connman_ipconfig_get_index(
3802                                                 service->ipconfig_ipv6);
3803                 else
3804                         return NULL;
3805
3806                 return connman_inet_ifname(index);
3807         }
3808
3809         if (service->network == NULL)
3810                 return NULL;
3811
3812         index = connman_network_get_index(service->network);
3813
3814         return connman_inet_ifname(index);
3815 }
3816
3817 /**
3818  * connman_service_get_network:
3819  * @service: service structure
3820  *
3821  * Get the service network
3822  */
3823 struct connman_network *
3824 __connman_service_get_network(struct connman_service *service)
3825 {
3826         if (service == NULL)
3827                 return NULL;
3828
3829         return service->network;
3830 }
3831
3832 struct connman_ipconfig *
3833 __connman_service_get_ip4config(struct connman_service *service)
3834 {
3835         if (service == NULL)
3836                 return NULL;
3837
3838         return service->ipconfig_ipv4;
3839 }
3840
3841 struct connman_ipconfig *
3842 __connman_service_get_ip6config(struct connman_service *service)
3843 {
3844         if (service == NULL)
3845                 return NULL;
3846
3847         return service->ipconfig_ipv6;
3848 }
3849
3850 struct connman_ipconfig *
3851 __connman_service_get_ipconfig(struct connman_service *service, int family)
3852 {
3853         if (family == AF_INET)
3854                 return __connman_service_get_ip4config(service);
3855         else if (family == AF_INET6)
3856                 return __connman_service_get_ip6config(service);
3857         else
3858                 return NULL;
3859
3860 }
3861
3862 enum connman_service_security __connman_service_get_security(struct connman_service *service)
3863 {
3864         if (service == NULL)
3865                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
3866
3867         return service->security;
3868 }
3869
3870 const char *__connman_service_get_phase2(struct connman_service *service)
3871 {
3872         if (service == NULL)
3873                 return NULL;
3874
3875         return service->phase2;
3876 }
3877
3878 connman_bool_t __connman_service_wps_enabled(struct connman_service *service)
3879 {
3880         if (service == NULL)
3881                 return FALSE;
3882
3883         return service->wps;
3884 }
3885
3886 /**
3887  * __connman_service_set_favorite:
3888  * @service: service structure
3889  * @favorite: favorite value
3890  *
3891  * Change the favorite setting of service
3892  */
3893 int __connman_service_set_favorite(struct connman_service *service,
3894                                                 connman_bool_t favorite)
3895 {
3896         GSequenceIter *iter;
3897
3898         iter = g_hash_table_lookup(service_hash, service->identifier);
3899         if (iter == NULL)
3900                 return -ENOENT;
3901
3902         if (service->favorite == favorite)
3903                 return -EALREADY;
3904
3905         service->favorite = favorite;
3906
3907         favorite_changed(service);
3908
3909         g_sequence_sort_changed(iter, service_compare, NULL);
3910
3911         services_changed(FALSE);
3912
3913         return 0;
3914 }
3915
3916 int __connman_service_set_immutable(struct connman_service *service,
3917                                                 connman_bool_t immutable)
3918 {
3919         service->immutable = immutable;
3920
3921         immutable_changed(service);
3922
3923         return 0;
3924 }
3925
3926 void __connman_service_set_string(struct connman_service *service,
3927                                   const char *key, const char *value)
3928 {
3929         if (g_str_equal(key, "EAP") == TRUE) {
3930                 g_free(service->eap);
3931                 service->eap = g_strdup(value);
3932         } else if (g_str_equal(key, "Identity") == TRUE) {
3933                 g_free(service->identity);
3934                 service->identity = g_strdup(value);
3935         } else if (g_str_equal(key, "CACertFile") == TRUE) {
3936                 g_free(service->ca_cert_file);
3937                 service->ca_cert_file = g_strdup(value);
3938         } else if (g_str_equal(key, "ClientCertFile") == TRUE) {
3939                 g_free(service->client_cert_file);
3940                 service->client_cert_file = g_strdup(value);
3941         } else if (g_str_equal(key, "PrivateKeyFile") == TRUE) {
3942                 g_free(service->private_key_file);
3943                 service->private_key_file = g_strdup(value);
3944         } else if (g_str_equal(key, "PrivateKeyPassphrase") == TRUE) {
3945                 g_free(service->private_key_passphrase);
3946                 service->private_key_passphrase = g_strdup(value);
3947         } else if (g_str_equal(key, "Phase2") == TRUE) {
3948                 g_free(service->phase2);
3949                 service->phase2 = g_strdup(value);
3950         } else if (g_str_equal(key, "Passphrase") == TRUE) {
3951                 g_free(service->passphrase);
3952                 service->passphrase = g_strdup(value);
3953         }
3954 }
3955
3956 static void service_complete(struct connman_service *service)
3957 {
3958         reply_pending(service, EIO);
3959
3960         if (service->userconnect == FALSE)
3961                 __connman_service_auto_connect();
3962
3963         g_get_current_time(&service->modified);
3964         service_save(service);
3965 }
3966
3967 static void report_error_cb(struct connman_service *service,
3968                         gboolean retry, void *user_data)
3969 {
3970         if (retry == TRUE)
3971                 __connman_service_connect(service);
3972         else {
3973                 service_complete(service);
3974                 services_changed(FALSE);
3975                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
3976         }
3977 }
3978
3979 static int __connman_service_indicate_state(struct connman_service *service)
3980 {
3981         enum connman_service_state old_state, new_state;
3982         GSequenceIter *iter;
3983
3984         if (service == NULL)
3985                 return -EINVAL;
3986
3987         old_state = service->state;
3988         new_state = combine_state(service->state_ipv4, service->state_ipv6);
3989
3990         if (old_state == new_state)
3991                 return -EALREADY;
3992
3993         DBG("service %p old %s - new %s/%s => %s",
3994                                         service,
3995                                         state2string(old_state),
3996                                         state2string(service->state_ipv4),
3997                                         state2string(service->state_ipv6),
3998                                         state2string(new_state));
3999
4000         service->state = new_state;
4001         state_changed(service);
4002
4003         if (new_state == CONNMAN_SERVICE_STATE_IDLE &&
4004                         old_state != CONNMAN_SERVICE_STATE_DISCONNECT) {
4005                 reply_pending(service, ECONNABORTED);
4006
4007                 __connman_service_disconnect(service);
4008         }
4009
4010         if (new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) {
4011                 if (__connman_stats_service_register(service) == 0) {
4012                         __connman_stats_get(service, FALSE,
4013                                                 &service->stats.data);
4014                         __connman_stats_get(service, TRUE,
4015                                                 &service->stats_roaming.data);
4016                 }
4017         }
4018
4019         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
4020                 if (service->login_required == TRUE) {
4021                         service->login_required = FALSE;
4022                         login_changed(service);
4023                 }
4024
4025                 connman_timeserver_sync();
4026         }
4027
4028         if (new_state == CONNMAN_SERVICE_STATE_IDLE) {
4029                 connman_bool_t reconnect;
4030
4031                 reconnect = get_reconnect_state(service);
4032                 if (reconnect == TRUE)
4033                         __connman_service_auto_connect();
4034
4035                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
4036         }
4037
4038         if (new_state == CONNMAN_SERVICE_STATE_READY) {
4039                 enum connman_ipconfig_method method;
4040
4041                 set_reconnect_state(service, TRUE);
4042
4043                 __connman_service_set_favorite(service, TRUE);
4044
4045                 reply_pending(service, 0);
4046
4047                 service->userconnect = FALSE;
4048
4049                 g_get_current_time(&service->modified);
4050                 service_save(service);
4051
4052                 update_nameservers(service);
4053                 dns_changed(service);
4054                 domain_changed(service);
4055
4056                 __connman_notifier_connect(service->type);
4057
4058                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
4059                         connman_network_get_bool(service->network,
4060                                                 "WiFi.UseWPS") == TRUE) {
4061                         const char *pass;
4062
4063                         pass = connman_network_get_string(service->network,
4064                                                         "WiFi.Passphrase");
4065
4066                         __connman_service_set_passphrase(service, pass);
4067
4068                         connman_network_set_bool(service->network,
4069                                                         "WiFi.UseWPS", FALSE);
4070                 }
4071
4072                 default_changed();
4073
4074                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
4075                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
4076                         __connman_ipconfig_disable_ipv6(
4077                                                 service->ipconfig_ipv6);
4078
4079         } else if (new_state == CONNMAN_SERVICE_STATE_DISCONNECT) {
4080                 struct connman_service *def_service = get_default();
4081
4082                 if (__connman_notifier_count_connected() == 0 &&
4083                         def_service != NULL &&
4084                                 def_service->provider != NULL)
4085                         __connman_provider_disconnect(def_service->provider);
4086
4087                 __connman_location_finish(service);
4088
4089                 default_changed();
4090
4091                 __connman_wpad_stop(service);
4092
4093                 update_nameservers(service);
4094                 dns_changed(service);
4095                 domain_changed(service);
4096
4097                 __connman_notifier_disconnect(service->type);
4098         }
4099
4100         if (new_state == CONNMAN_SERVICE_STATE_FAILURE) {
4101                 if (service->userconnect == TRUE &&
4102                         __connman_agent_report_error(service,
4103                                         error2string(service->error),
4104                                         report_error_cb, NULL) == -EIO)
4105                         return 0;
4106                 service_complete(service);
4107
4108                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
4109         } else
4110                 service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
4111
4112         iter = g_hash_table_lookup(service_hash, service->identifier);
4113         if (iter != NULL)
4114                 g_sequence_sort_changed(iter, service_compare, NULL);
4115
4116         services_changed(FALSE);
4117
4118         if (new_state == CONNMAN_SERVICE_STATE_ONLINE)
4119                 default_changed();
4120
4121         return 0;
4122 }
4123
4124 int __connman_service_indicate_error(struct connman_service *service,
4125                                         enum connman_service_error error)
4126 {
4127         DBG("service %p error %d", service, error);
4128
4129         if (service == NULL)
4130                 return -EINVAL;
4131
4132         service->error = error;
4133
4134         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
4135                 __connman_service_set_passphrase(service, NULL);
4136
4137         __connman_service_ipconfig_indicate_state(service,
4138                                                 CONNMAN_SERVICE_STATE_FAILURE,
4139                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4140         __connman_service_ipconfig_indicate_state(service,
4141                                                 CONNMAN_SERVICE_STATE_FAILURE,
4142                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
4143         return 0;
4144 }
4145
4146 int __connman_service_clear_error(struct connman_service *service)
4147 {
4148         DBG("service %p", service);
4149
4150         if (service == NULL)
4151                 return -EINVAL;
4152
4153         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
4154                 return -EINVAL;
4155
4156         service->state_ipv4 = service->state_ipv6 =
4157                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
4158         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;;
4159
4160         if (service->favorite == TRUE)
4161                 set_reconnect_state(service, TRUE);
4162
4163         __connman_service_ipconfig_indicate_state(service,
4164                                         CONNMAN_SERVICE_STATE_IDLE,
4165                                         CONNMAN_IPCONFIG_TYPE_IPV6);
4166
4167         /*
4168          * Toggling the IPv6 state to IDLE could trigger the auto connect
4169          * machinery and consequently the IPv4 state.
4170          */
4171         if (service->state_ipv4 != CONNMAN_SERVICE_STATE_UNKNOWN &&
4172                         service->state_ipv4 != CONNMAN_SERVICE_STATE_FAILURE)
4173                 return 0;
4174
4175         return __connman_service_ipconfig_indicate_state(service,
4176                                                 CONNMAN_SERVICE_STATE_IDLE,
4177                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4178 }
4179
4180 int __connman_service_indicate_default(struct connman_service *service)
4181 {
4182         DBG("service %p", service);
4183
4184         default_changed();
4185
4186         __connman_location_detect(service);
4187
4188         return 0;
4189 }
4190
4191 static void check_proxy_setup(struct connman_service *service)
4192 {
4193         /*
4194          * We start WPAD if we haven't got a PAC URL from DHCP and
4195          * if our proxy manual configuration is either empty or set
4196          * to AUTO with an empty URL.
4197          */
4198
4199         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
4200                 return;
4201
4202         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
4203                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
4204                         service->pac != NULL))
4205                 return;
4206
4207         if (__connman_wpad_start(service) < 0) {
4208                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
4209                 __connman_notifier_proxy_changed(service);
4210         }
4211 }
4212
4213 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
4214                                         enum connman_service_state new_state,
4215                                         enum connman_ipconfig_type type)
4216 {
4217         struct connman_ipconfig *ipconfig = NULL;
4218         enum connman_service_state old_state;
4219
4220         if (service == NULL)
4221                 return -EINVAL;
4222
4223         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
4224                 old_state = service->state_ipv4;
4225                 ipconfig = service->ipconfig_ipv4;
4226         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
4227                 old_state = service->state_ipv6;
4228                 ipconfig = service->ipconfig_ipv6;
4229         }
4230
4231         if (ipconfig == NULL)
4232                 return -EINVAL;
4233
4234         /* Any change? */
4235         if (old_state == new_state)
4236                 return -EALREADY;
4237
4238         DBG("service %p (%s) state %d (%s) type %d (%s)",
4239                 service, service ? service->identifier : NULL,
4240                 new_state, state2string(new_state),
4241                 type, __connman_ipconfig_type2string(type));
4242
4243         switch (new_state) {
4244         case CONNMAN_SERVICE_STATE_UNKNOWN:
4245         case CONNMAN_SERVICE_STATE_IDLE:
4246                 if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
4247                         return -EINVAL;
4248                 break;
4249         case CONNMAN_SERVICE_STATE_ASSOCIATION:
4250                 break;
4251         case CONNMAN_SERVICE_STATE_CONFIGURATION:
4252                 __connman_ipconfig_enable(ipconfig);
4253                 break;
4254         case CONNMAN_SERVICE_STATE_READY:
4255                 update_nameservers(service);
4256
4257                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4258                         check_proxy_setup(service);
4259                 break;
4260         case CONNMAN_SERVICE_STATE_ONLINE:
4261                 break;
4262         case CONNMAN_SERVICE_STATE_DISCONNECT:
4263                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
4264                         return -EINVAL;
4265                 break;
4266         case CONNMAN_SERVICE_STATE_FAILURE:
4267                 break;
4268         }
4269
4270         /* We keep that state */
4271         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4272                 service->state_ipv4 = new_state;
4273         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
4274                 service->state_ipv6 = new_state;
4275
4276         return __connman_service_indicate_state(service);
4277 }
4278
4279 int __connman_service_request_login(struct connman_service *service)
4280 {
4281         DBG("service %p", service);
4282
4283         if (service == NULL)
4284                 return -EINVAL;
4285
4286         service->login_required = TRUE;
4287         login_changed(service);
4288
4289         return 0;
4290 }
4291
4292 static connman_bool_t prepare_network(struct connman_service *service)
4293 {
4294         enum connman_network_type type;
4295         unsigned int ssid_len;
4296
4297         type = connman_network_get_type(service->network);
4298
4299         switch (type) {
4300         case CONNMAN_NETWORK_TYPE_UNKNOWN:
4301         case CONNMAN_NETWORK_TYPE_VENDOR:
4302                 return FALSE;
4303         case CONNMAN_NETWORK_TYPE_WIFI:
4304                 if (connman_network_get_blob(service->network, "WiFi.SSID",
4305                                                         &ssid_len) == NULL)
4306                         return FALSE;
4307
4308                 if (service->passphrase != NULL)
4309                         connman_network_set_string(service->network,
4310                                 "WiFi.Passphrase", service->passphrase);
4311                 break;
4312         case CONNMAN_NETWORK_TYPE_ETHERNET:
4313         case CONNMAN_NETWORK_TYPE_WIMAX:
4314         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
4315         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
4316         case CONNMAN_NETWORK_TYPE_CELLULAR:
4317                 break;
4318         }
4319
4320         return TRUE;
4321 }
4322
4323 static void prepare_8021x(struct connman_service *service)
4324 {
4325         if (service->eap != NULL)
4326                 connman_network_set_string(service->network, "WiFi.EAP",
4327                                                                 service->eap);
4328
4329         if (service->identity != NULL)
4330                 connman_network_set_string(service->network, "WiFi.Identity",
4331                                                         service->identity);
4332
4333         if (service->ca_cert_file != NULL)
4334                 connman_network_set_string(service->network, "WiFi.CACertFile",
4335                                                         service->ca_cert_file);
4336
4337         if (service->client_cert_file != NULL)
4338                 connman_network_set_string(service->network,
4339                                                 "WiFi.ClientCertFile",
4340                                                 service->client_cert_file);
4341
4342         if (service->private_key_file != NULL)
4343                 connman_network_set_string(service->network,
4344                                                 "WiFi.PrivateKeyFile",
4345                                                 service->private_key_file);
4346
4347         if (service->private_key_passphrase != NULL)
4348                 connman_network_set_string(service->network,
4349                                         "WiFi.PrivateKeyPassphrase",
4350                                         service->private_key_passphrase);
4351
4352         if (service->phase2 != NULL)
4353                 connman_network_set_string(service->network, "WiFi.Phase2",
4354                                                         service->phase2);
4355 }
4356
4357 static int service_connect(struct connman_service *service)
4358 {
4359         int err;
4360
4361         switch (service->type) {
4362         case CONNMAN_SERVICE_TYPE_UNKNOWN:
4363         case CONNMAN_SERVICE_TYPE_SYSTEM:
4364         case CONNMAN_SERVICE_TYPE_GPS:
4365         case CONNMAN_SERVICE_TYPE_GADGET:
4366                 return -EINVAL;
4367         case CONNMAN_SERVICE_TYPE_ETHERNET:
4368         case CONNMAN_SERVICE_TYPE_WIMAX:
4369         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
4370         case CONNMAN_SERVICE_TYPE_CELLULAR:
4371         case CONNMAN_SERVICE_TYPE_VPN:
4372                 break;
4373         case CONNMAN_SERVICE_TYPE_WIFI:
4374                 switch (service->security) {
4375                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
4376                 case CONNMAN_SERVICE_SECURITY_NONE:
4377                         break;
4378                 case CONNMAN_SERVICE_SECURITY_WEP:
4379                 case CONNMAN_SERVICE_SECURITY_PSK:
4380                 case CONNMAN_SERVICE_SECURITY_WPA:
4381                 case CONNMAN_SERVICE_SECURITY_RSN:
4382                         if (service->passphrase == NULL) {
4383                                 if (service->network == NULL)
4384                                         return -EOPNOTSUPP;
4385
4386                                 if (service->wps == FALSE ||
4387                                         connman_network_get_bool(
4388                                                         service->network,
4389                                                         "WiFi.UseWPS") == FALSE)
4390                                         return -ENOKEY;
4391                         }
4392                         break;
4393                 case CONNMAN_SERVICE_SECURITY_8021X:
4394                         if (service->eap == NULL)
4395                                 return -EINVAL;
4396
4397                         /*
4398                          * never request credentials if using EAP-TLS
4399                          * (EAP-TLS networks need to be fully provisioned)
4400                          */
4401                         if (g_str_equal(service->eap, "tls") == TRUE)
4402                                 break;
4403
4404                         /*
4405                          * Return -ENOKEY if either identity or passphrase is
4406                          * missing. Agent provided credentials can be used as
4407                          * fallback if needed.
4408                          */
4409                         if ((service->identity == NULL &&
4410                                         service->agent_identity == NULL) ||
4411                                         (service->passphrase == NULL &&
4412                                         service->agent_passphrase == NULL))
4413                                 return -ENOKEY;
4414
4415                         break;
4416                 }
4417                 break;
4418         }
4419
4420         if (service->network != NULL) {
4421                 if (prepare_network(service) == FALSE)
4422                         return -EINVAL;
4423
4424                 switch (service->security) {
4425                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
4426                 case CONNMAN_SERVICE_SECURITY_NONE:
4427                 case CONNMAN_SERVICE_SECURITY_WEP:
4428                 case CONNMAN_SERVICE_SECURITY_PSK:
4429                 case CONNMAN_SERVICE_SECURITY_WPA:
4430                 case CONNMAN_SERVICE_SECURITY_RSN:
4431                         break;
4432                 case CONNMAN_SERVICE_SECURITY_8021X:
4433                         prepare_8021x(service);
4434                         break;
4435                 }
4436
4437                 if (__connman_stats_service_register(service) == 0) {
4438                         __connman_stats_get(service, FALSE,
4439                                                 &service->stats.data);
4440                         __connman_stats_get(service, TRUE,
4441                                                 &service->stats_roaming.data);
4442                 }
4443
4444                 if (service->ipconfig_ipv4)
4445                         __connman_ipconfig_enable(service->ipconfig_ipv4);
4446                 if (service->ipconfig_ipv6)
4447                         __connman_ipconfig_enable(service->ipconfig_ipv6);
4448
4449                 err = __connman_network_connect(service->network);
4450         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
4451                                         service->provider != NULL)
4452                 err = __connman_provider_connect(service->provider);
4453         else
4454                 return -EOPNOTSUPP;
4455
4456         if (err < 0) {
4457                 if (err != -EINPROGRESS) {
4458                         __connman_ipconfig_disable(service->ipconfig_ipv4);
4459                         __connman_ipconfig_disable(service->ipconfig_ipv6);
4460                         __connman_stats_service_unregister(service);
4461                 }
4462         }
4463
4464         return err;
4465 }
4466
4467
4468 int __connman_service_connect(struct connman_service *service)
4469 {
4470         int err;
4471
4472         DBG("service %p state %s", service, state2string(service->state));
4473
4474         if (is_connected(service) == TRUE)
4475                 return -EISCONN;
4476
4477         if (is_connecting(service) == TRUE)
4478                 return -EALREADY;
4479
4480         switch (service->type) {
4481         case CONNMAN_SERVICE_TYPE_UNKNOWN:
4482         case CONNMAN_SERVICE_TYPE_SYSTEM:
4483         case CONNMAN_SERVICE_TYPE_GPS:
4484         case CONNMAN_SERVICE_TYPE_GADGET:
4485                 return -EINVAL;
4486         default:
4487                 err = service_connect(service);
4488         }
4489
4490         if (err >= 0)
4491                 return 0;
4492
4493         if (err == -EINPROGRESS) {
4494                 if (service->timeout == 0)
4495                         service->timeout = g_timeout_add_seconds(
4496                                 CONNECT_TIMEOUT, connect_timeout, service);
4497
4498                 return -EINPROGRESS;
4499         }
4500
4501         __connman_service_ipconfig_indicate_state(service,
4502                                         CONNMAN_SERVICE_STATE_FAILURE,
4503                                         CONNMAN_IPCONFIG_TYPE_IPV4);
4504         __connman_service_ipconfig_indicate_state(service,
4505                                         CONNMAN_SERVICE_STATE_FAILURE,
4506                                         CONNMAN_IPCONFIG_TYPE_IPV6);
4507
4508         if (service->network != NULL)
4509                 __connman_network_disconnect(service->network);
4510         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
4511                                 service->provider != NULL)
4512                         __connman_provider_disconnect(service->provider);
4513
4514         if (service->userconnect == TRUE) {
4515                 if (err == -ENOKEY) {
4516                         if (__connman_agent_request_input(service,
4517                                                         request_input_cb,
4518                                                         NULL) == -EIO)
4519                                 return -EINPROGRESS;
4520                 }
4521                 reply_pending(service, err);
4522         }
4523
4524         return err;
4525 }
4526
4527 int __connman_service_disconnect(struct connman_service *service)
4528 {
4529         int err;
4530
4531         DBG("service %p", service);
4532
4533         if (service->network != NULL) {
4534                 err = __connman_network_disconnect(service->network);
4535         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
4536                                         service->provider != NULL)
4537                 err = __connman_provider_disconnect(service->provider);
4538         else
4539                 return -EOPNOTSUPP;
4540
4541         if (err < 0 && err != -EINPROGRESS)
4542                 return err;
4543
4544         __connman_6to4_remove(service->ipconfig_ipv4);
4545
4546         if (service->ipconfig_ipv4)
4547                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
4548                                                         NULL);
4549         else
4550                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
4551                                                         NULL);
4552
4553         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
4554         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
4555
4556         __connman_ipconfig_disable(service->ipconfig_ipv4);
4557         __connman_ipconfig_disable(service->ipconfig_ipv6);
4558
4559         __connman_stats_service_unregister(service);
4560
4561         return err;
4562 }
4563
4564 int __connman_service_disconnect_all(void)
4565 {
4566         GSequenceIter *iter;
4567
4568         DBG("");
4569
4570         iter = g_sequence_get_begin_iter(service_list);
4571
4572         while (g_sequence_iter_is_end(iter) == FALSE) {
4573                 struct connman_service *service = g_sequence_get(iter);
4574
4575                 service->ignore = TRUE;
4576
4577                 set_reconnect_state(service, FALSE);
4578
4579                 __connman_service_disconnect(service);
4580
4581                 iter = g_sequence_iter_next(iter);
4582         }
4583
4584         return 0;
4585
4586 }
4587
4588 /**
4589  * __connman_service_lookup:
4590  * @pattern: search pattern
4591  * @path: return object path
4592  *
4593  * Look up a service path from a search pattern
4594  */
4595 int __connman_service_lookup(const char *pattern, const char **path)
4596 {
4597         GHashTableIter iter;
4598         gpointer key, value;
4599
4600         g_hash_table_iter_init(&iter, service_hash);
4601
4602         while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
4603                 GSequenceIter *iter = value;
4604                 struct connman_service *service = g_sequence_get(iter);
4605
4606                 if (g_strcmp0(service->identifier, pattern) == 0 ||
4607                                 g_strcmp0(service->name, pattern) == 0) {
4608                         *path = (const char *) service->path;
4609                         return 0;
4610                 }
4611         }
4612
4613         return -ENXIO;
4614 }
4615
4616 /**
4617  * lookup_by_identifier:
4618  * @identifier: service identifier
4619  *
4620  * Look up a service by identifier (reference count will not be increased)
4621  */
4622 static struct connman_service *lookup_by_identifier(const char *identifier)
4623 {
4624         GSequenceIter *iter;
4625
4626         iter = g_hash_table_lookup(service_hash, identifier);
4627         if (iter != NULL)
4628                 return g_sequence_get(iter);
4629
4630         return NULL;
4631 }
4632
4633 static struct connman_network *create_hidden_wifi(struct connman_device *device,
4634                 const char *ssid, const char *mode, const char *security,
4635                 const char *group)
4636 {
4637         struct connman_network *network;
4638         char *name;
4639         int index;
4640         unsigned int i, ssid_len;
4641
4642         ssid_len = strlen(ssid);
4643         if (ssid_len < 1)
4644                 return NULL;
4645
4646         network = connman_network_create(group, CONNMAN_NETWORK_TYPE_WIFI);
4647         if (network == NULL)
4648                 return NULL;
4649
4650         connman_network_set_blob(network, "WiFi.SSID",
4651                                         (unsigned char *) ssid, ssid_len);
4652
4653         connman_network_set_string(network, "WiFi.Mode", mode);
4654         connman_network_set_string(network, "WiFi.Security", security);
4655
4656         name = g_try_malloc0(ssid_len + 1);
4657         if (name == NULL) {
4658                 connman_network_unref(network);
4659                 return NULL;
4660         }
4661
4662         for (i = 0; i < ssid_len; i++) {
4663                 if (g_ascii_isprint(ssid[i]))
4664                         name[i] = ssid[i];
4665                 else
4666                         name[i] = ' ';
4667         }
4668
4669         connman_network_set_name(network, name);
4670
4671         g_free(name);
4672
4673         index = connman_device_get_index(device);
4674         connman_network_set_index(network, index);
4675
4676         if (connman_device_add_network(device, network) < 0) {
4677                 connman_network_unref(network);
4678                 return NULL;
4679         }
4680
4681         connman_network_set_available(network, TRUE);
4682
4683         return network;
4684 }
4685
4686 int __connman_service_create_and_connect(DBusMessage *msg)
4687 {
4688         struct connman_service *service;
4689         struct connman_network *network;
4690         struct connman_device *device;
4691         DBusMessageIter iter, array;
4692         const char *mode = "managed", *security = "none", *group_security;
4693         const char *type = NULL, *ssid = NULL, *passphrase = NULL;
4694         unsigned int ssid_len = 0;
4695         const char *ident;
4696         char *name, *group;
4697         int err;
4698
4699         dbus_message_iter_init(msg, &iter);
4700         dbus_message_iter_recurse(&iter, &array);
4701
4702         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
4703                 DBusMessageIter entry, value;
4704                 const char *key;
4705
4706                 dbus_message_iter_recurse(&array, &entry);
4707                 dbus_message_iter_get_basic(&entry, &key);
4708
4709                 dbus_message_iter_next(&entry);
4710                 dbus_message_iter_recurse(&entry, &value);
4711
4712                 switch (dbus_message_iter_get_arg_type(&value)) {
4713                 case DBUS_TYPE_STRING:
4714                         if (g_str_equal(key, "Type") == TRUE)
4715                                 dbus_message_iter_get_basic(&value, &type);
4716                         else if (g_str_equal(key, "WiFi.Mode") == TRUE ||
4717                                         g_str_equal(key, "Mode") == TRUE)
4718                                 dbus_message_iter_get_basic(&value, &mode);
4719                         else if (g_str_equal(key, "WiFi.Security") == TRUE ||
4720                                         g_str_equal(key, "Security") == TRUE)
4721                                 dbus_message_iter_get_basic(&value, &security);
4722                         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE ||
4723                                         g_str_equal(key, "Passphrase") == TRUE)
4724                                 dbus_message_iter_get_basic(&value, &passphrase);
4725                         else if (g_str_equal(key, "WiFi.SSID") == TRUE ||
4726                                         g_str_equal(key, "SSID") == TRUE)
4727                                 dbus_message_iter_get_basic(&value, &ssid);
4728                 }
4729
4730                 dbus_message_iter_next(&array);
4731         }
4732
4733         if (type == NULL)
4734                 return -EINVAL;
4735
4736         if (g_strcmp0(type, "wifi") != 0 || g_strcmp0(mode, "managed") != 0)
4737                 return -EOPNOTSUPP;
4738
4739         if (ssid == NULL)
4740                 return -EINVAL;
4741
4742         ssid_len = strlen(ssid);
4743         if (ssid_len < 1)
4744                 return -EINVAL;
4745
4746         if (g_strcmp0(security, "none") != 0 &&
4747                                 g_strcmp0(security, "wep") != 0 &&
4748                                 g_strcmp0(security, "psk") != 0 &&
4749                                 g_strcmp0(security, "wpa") != 0 &&
4750                                 g_strcmp0(security, "rsn") != 0 &&
4751                                 g_strcmp0(security, "ieee8021x") != 0)
4752                 return -EINVAL;
4753
4754         device = __connman_device_find_device(CONNMAN_SERVICE_TYPE_WIFI);
4755         if (device == NULL)
4756                 return -EOPNOTSUPP;
4757
4758         ident = connman_device_get_ident(device);
4759         if (ident == NULL)
4760                 return -EOPNOTSUPP;
4761
4762
4763         if (!g_strcmp0(security, "wpa") ||
4764                 !g_strcmp0(security, "rsn"))
4765                 group_security = "psk";
4766         else
4767                 group_security = security;
4768
4769         group = wifi_build_group_name((unsigned char *) ssid,
4770                                                 ssid_len, mode, group_security);
4771         if (group == NULL)
4772                 return -EINVAL;
4773
4774         name = g_strdup_printf("%s_%s_%s", type, ident, group);
4775
4776         service = lookup_by_identifier(name);
4777
4778         if (service != NULL)
4779                 goto done;
4780
4781         network = create_hidden_wifi(device, ssid, mode, security, group);
4782         if (network != NULL)
4783                 connman_network_set_group(network, group);
4784
4785         service = lookup_by_identifier(name);
4786
4787 done:
4788         g_free(name);
4789         g_free(group);
4790
4791         if (service == NULL) {
4792                 err = -EOPNOTSUPP;
4793                 goto failed;
4794         }
4795
4796         service->network_created = TRUE;
4797
4798         if (is_connected(service) == TRUE) {
4799                 err = -EISCONN;
4800                 goto failed;
4801         }
4802
4803         if (is_connecting(service) == TRUE) {
4804                 err = -EALREADY;
4805                 goto failed;
4806         }
4807
4808         set_reconnect_state(service, FALSE);
4809
4810         __connman_device_disconnect(device);
4811
4812         if (passphrase != NULL) {
4813                 g_free(service->passphrase);
4814                 service->passphrase = g_strdup(passphrase);
4815         }
4816
4817         service->userconnect = TRUE;
4818
4819         err = __connman_service_connect(service);
4820         if (err < 0 && err != -EINPROGRESS)
4821                 goto failed;
4822
4823         service->pending = dbus_message_ref(msg);
4824
4825         return 0;
4826
4827 failed:
4828         if (service != NULL && service->network_created == TRUE) {
4829                 struct connman_network *network = service->network;
4830
4831                 if (network != NULL) {
4832                         connman_network_set_available(network, FALSE);
4833                         __connman_device_cleanup_networks(device);
4834                 } else
4835                         __connman_service_put(service);
4836         }
4837
4838         return err;
4839 }
4840
4841 static void provision_changed(gpointer value, gpointer user_data)
4842 {
4843         struct connman_service *service = value;
4844         char *path = user_data;
4845
4846         __connman_config_provision_service_ident(service, path);
4847 }
4848
4849 void __connman_service_provision_changed(const char *ident)
4850 {
4851         g_sequence_foreach(service_list, provision_changed, (void *)ident);
4852 }
4853
4854 int __connman_service_provision(DBusMessage *msg)
4855 {
4856         GKeyFile *keyfile = NULL;
4857         const char *config_str = NULL;
4858         char *group = NULL, *ident = NULL;
4859         int err = 0;
4860         struct connman_service *service;
4861
4862         DBG("");
4863
4864         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &config_str,
4865                                                         DBUS_TYPE_INVALID);
4866
4867         if (config_str == NULL || strlen(config_str) == 0)
4868                 return -EINVAL;
4869
4870         keyfile = g_key_file_new();
4871
4872         /* populate GKeyFile with config_str */
4873         if (g_key_file_load_from_data(keyfile, config_str,
4874                                         strlen(config_str), 0, NULL) == FALSE) {
4875                 err = -EINVAL;
4876                 goto done;
4877         }
4878
4879         /*
4880          * read only one group of settings (only one service supported, no
4881          * global settings)
4882          */
4883         group = g_key_file_get_start_group(keyfile);
4884
4885         if (group == NULL || g_str_has_prefix(group, "service_") == FALSE) {
4886                 err = -EINVAL;
4887                 goto done;
4888         }
4889
4890         err = __connman_config_load_service(keyfile, group, TRUE);
4891         if (err < 0)
4892                 goto done;
4893
4894         ident = group + strlen("service_");
4895
4896         /* trigger service provisioning if service exists */
4897         service = lookup_by_identifier(ident);
4898         if (service != NULL)
4899                 __connman_config_provision_service(service);
4900
4901         g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
4902
4903 done:
4904         if (group != NULL)
4905                 g_free(group);
4906
4907         if (keyfile != NULL)
4908                 g_key_file_free(keyfile);
4909
4910         return err;
4911 }
4912
4913 /**
4914  * __connman_service_get:
4915  * @identifier: service identifier
4916  *
4917  * Look up a service by identifier or create a new one if not found
4918  */
4919 static struct connman_service *service_get(const char *identifier)
4920 {
4921         struct connman_service *service;
4922         GSequenceIter *iter;
4923
4924         iter = g_hash_table_lookup(service_hash, identifier);
4925         if (iter != NULL) {
4926                 service = g_sequence_get(iter);
4927                 if (service != NULL)
4928                         connman_service_ref(service);
4929                 return service;
4930         }
4931
4932         service = connman_service_create();
4933         if (service == NULL)
4934                 return NULL;
4935
4936         DBG("service %p", service);
4937
4938         service->identifier = g_strdup(identifier);
4939
4940         iter = g_sequence_insert_sorted(service_list, service,
4941                                                 service_compare, NULL);
4942
4943         g_hash_table_insert(service_hash, service->identifier, iter);
4944
4945         return service;
4946 }
4947
4948 static int service_register(struct connman_service *service)
4949 {
4950         GSequenceIter *iter;
4951
4952         DBG("service %p", service);
4953
4954         if (service->path != NULL)
4955                 return -EALREADY;
4956
4957         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
4958                                                 service->identifier);
4959
4960         DBG("path %s", service->path);
4961
4962         __connman_config_provision_service(service);
4963
4964         service_load(service);
4965
4966         g_dbus_register_interface(connection, service->path,
4967                                         CONNMAN_SERVICE_INTERFACE,
4968                                         service_methods, service_signals,
4969                                                         NULL, service, NULL);
4970
4971         iter = g_hash_table_lookup(service_hash, service->identifier);
4972         if (iter != NULL)
4973                 g_sequence_sort_changed(iter, service_compare, NULL);
4974
4975         services_changed(TRUE);
4976
4977         return 0;
4978 }
4979
4980 static void service_up(struct connman_ipconfig *ipconfig)
4981 {
4982         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
4983
4984         DBG("%s up", connman_ipconfig_get_ifname(ipconfig));
4985
4986         link_changed(service);
4987
4988         service->stats.valid = FALSE;
4989         service->stats_roaming.valid = FALSE;
4990 }
4991
4992 static void service_down(struct connman_ipconfig *ipconfig)
4993 {
4994         DBG("%s down", connman_ipconfig_get_ifname(ipconfig));
4995 }
4996
4997 static void service_lower_up(struct connman_ipconfig *ipconfig)
4998 {
4999         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
5000
5001         DBG("%s lower up", connman_ipconfig_get_ifname(ipconfig));
5002
5003         stats_start(service);
5004 }
5005
5006 static void service_lower_down(struct connman_ipconfig *ipconfig)
5007 {
5008         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
5009
5010         DBG("%s lower down", connman_ipconfig_get_ifname(ipconfig));
5011
5012         stats_stop(service);
5013         service_save(service);
5014 }
5015
5016 static void service_ip_bound(struct connman_ipconfig *ipconfig)
5017 {
5018         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
5019         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
5020         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
5021
5022         DBG("%s ip bound", connman_ipconfig_get_ifname(ipconfig));
5023
5024         type = __connman_ipconfig_get_config_type(ipconfig);
5025         method = __connman_ipconfig_get_method(ipconfig);
5026
5027         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
5028                                                         type, method);
5029
5030         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
5031                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
5032                 __connman_service_ipconfig_indicate_state(service,
5033                                                 CONNMAN_SERVICE_STATE_READY,
5034                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5035
5036         settings_changed(service, ipconfig);
5037 }
5038
5039 static void service_ip_release(struct connman_ipconfig *ipconfig)
5040 {
5041         struct connman_service *service = connman_ipconfig_get_data(ipconfig);
5042         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
5043         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
5044
5045         DBG("%s ip release", connman_ipconfig_get_ifname(ipconfig));
5046
5047         type = __connman_ipconfig_get_config_type(ipconfig);
5048         method = __connman_ipconfig_get_method(ipconfig);
5049
5050         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
5051                                                         type, method);
5052
5053         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
5054                         method == CONNMAN_IPCONFIG_METHOD_OFF)
5055                 __connman_service_ipconfig_indicate_state(service,
5056                                         CONNMAN_SERVICE_STATE_DISCONNECT,
5057                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5058
5059         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
5060                         method == CONNMAN_IPCONFIG_METHOD_OFF)
5061                 __connman_service_ipconfig_indicate_state(service,
5062                                         CONNMAN_SERVICE_STATE_DISCONNECT,
5063                                         CONNMAN_IPCONFIG_TYPE_IPV4);
5064
5065         settings_changed(service, ipconfig);
5066 }
5067
5068 static const struct connman_ipconfig_ops service_ops = {
5069         .up             = service_up,
5070         .down           = service_down,
5071         .lower_up       = service_lower_up,
5072         .lower_down     = service_lower_down,
5073         .ip_bound       = service_ip_bound,
5074         .ip_release     = service_ip_release,
5075 };
5076
5077 static void setup_ip4config(struct connman_service *service, int index,
5078                         enum connman_ipconfig_method method)
5079 {
5080         if (index < 0)
5081                 return;
5082
5083         service->ipconfig_ipv4 = connman_ipconfig_create(index,
5084                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
5085         if (service->ipconfig_ipv4 == NULL)
5086                 return;
5087
5088         connman_ipconfig_set_method(service->ipconfig_ipv4, method);
5089
5090         connman_ipconfig_set_data(service->ipconfig_ipv4, service);
5091
5092         connman_ipconfig_set_ops(service->ipconfig_ipv4, &service_ops);
5093 }
5094
5095 static void setup_ip6config(struct connman_service *service, int index)
5096 {
5097         if (index < 0)
5098                 return;
5099
5100         service->ipconfig_ipv6 = connman_ipconfig_create(index,
5101                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5102         if (service->ipconfig_ipv6 == NULL)
5103                 return;
5104
5105         connman_ipconfig_set_data(service->ipconfig_ipv6, service);
5106
5107         connman_ipconfig_set_ops(service->ipconfig_ipv6, &service_ops);
5108 }
5109
5110 void __connman_service_read_ip4config(struct connman_service *service)
5111 {
5112         GKeyFile *keyfile;
5113
5114         if (service->ipconfig_ipv4 == NULL)
5115                 return;
5116
5117         keyfile = __connman_storage_open_profile("default");
5118         if (keyfile == NULL)
5119                 return;
5120
5121         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
5122                                 service->identifier, "IPv4.");
5123
5124         g_key_file_free(keyfile);
5125 }
5126
5127 void __connman_service_create_ip4config(struct connman_service *service,
5128                                         int index)
5129 {
5130         DBG("ipv4 %p", service->ipconfig_ipv4);
5131
5132         if (service->ipconfig_ipv4 != NULL)
5133                 return;
5134
5135         setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
5136         __connman_service_read_ip4config(service);
5137 }
5138
5139 void __connman_service_read_ip6config(struct connman_service *service)
5140 {
5141         GKeyFile *keyfile;
5142
5143         if (service->ipconfig_ipv6 == NULL)
5144                 return;
5145
5146         keyfile = __connman_storage_open_profile("default");
5147         if (keyfile == NULL)
5148                 return;
5149
5150         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
5151                                 service->identifier, "IPv6.");
5152
5153         g_key_file_free(keyfile);
5154 }
5155
5156 void __connman_service_create_ip6config(struct connman_service *service,
5157                                                                 int index)
5158 {
5159         DBG("ipv6 %p", service->ipconfig_ipv6);
5160
5161         if (service->ipconfig_ipv6 != NULL)
5162                 return;
5163
5164         setup_ip6config(service, index);
5165         __connman_service_read_ip6config(service);
5166 }
5167
5168 /**
5169  * __connman_service_lookup_from_network:
5170  * @network: network structure
5171  *
5172  * Look up a service by network (reference count will not be increased)
5173  */
5174 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
5175 {
5176         struct connman_service *service;
5177         const char *ident, *group;
5178         char *name;
5179
5180         DBG("network %p", network);
5181
5182         ident = __connman_network_get_ident(network);
5183         if (ident == NULL)
5184                 return NULL;
5185
5186         group = connman_network_get_group(network);
5187         if (group == NULL)
5188                 return NULL;
5189
5190         name = g_strdup_printf("%s_%s_%s",
5191                         __connman_network_get_type(network), ident, group);
5192         service = lookup_by_identifier(name);
5193         g_free(name);
5194
5195         return service;
5196 }
5197
5198 struct connman_service *__connman_service_lookup_from_index(int index)
5199 {
5200         struct connman_service *service;
5201         GSequenceIter *iter;
5202
5203         iter = g_sequence_get_begin_iter(service_list);
5204
5205         while (g_sequence_iter_is_end(iter) == FALSE) {
5206                 service = g_sequence_get(iter);
5207
5208                 if (connman_ipconfig_get_index(service->ipconfig_ipv4)
5209                                                         == index)
5210                         return service;
5211
5212                 if (connman_ipconfig_get_index(service->ipconfig_ipv6)
5213                                                         == index)
5214                         return service;
5215
5216                 iter = g_sequence_iter_next(iter);
5217         }
5218
5219         return NULL;
5220 }
5221
5222 const char *__connman_service_get_ident(struct connman_service *service)
5223 {
5224         return service->identifier;
5225 }
5226
5227 const char *__connman_service_get_path(struct connman_service *service)
5228 {
5229         return service->path;
5230 }
5231
5232 unsigned int __connman_service_get_order(struct connman_service *service)
5233 {
5234         GSequenceIter *iter;
5235
5236         if (service == NULL)
5237                 return 0;
5238
5239         if (service->favorite == FALSE) {
5240                 service->order = 0;
5241                 goto done;
5242         }
5243
5244         iter = g_hash_table_lookup(service_hash, service->identifier);
5245         if (iter != NULL) {
5246                 if (g_sequence_iter_get_position(iter) == 0)
5247                         service->order = 1;
5248                 else if (service->type == CONNMAN_SERVICE_TYPE_VPN)
5249                         service->order = 10;
5250                 else
5251                         service->order = 0;
5252         }
5253
5254 done:
5255         return service->order;
5256 }
5257
5258 static enum connman_service_type convert_network_type(struct connman_network *network)
5259 {
5260         enum connman_network_type type = connman_network_get_type(network);
5261
5262         switch (type) {
5263         case CONNMAN_NETWORK_TYPE_UNKNOWN:
5264         case CONNMAN_NETWORK_TYPE_VENDOR:
5265                 break;
5266         case CONNMAN_NETWORK_TYPE_ETHERNET:
5267                 return CONNMAN_SERVICE_TYPE_ETHERNET;
5268         case CONNMAN_NETWORK_TYPE_WIFI:
5269                 return CONNMAN_SERVICE_TYPE_WIFI;
5270         case CONNMAN_NETWORK_TYPE_WIMAX:
5271                 return CONNMAN_SERVICE_TYPE_WIMAX;
5272         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
5273         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
5274                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
5275         case CONNMAN_NETWORK_TYPE_CELLULAR:
5276                 return CONNMAN_SERVICE_TYPE_CELLULAR;
5277         }
5278
5279         return CONNMAN_SERVICE_TYPE_UNKNOWN;
5280 }
5281
5282 static enum connman_service_security convert_wifi_security(const char *security)
5283 {
5284         if (security == NULL)
5285                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
5286         else if (g_str_equal(security, "none") == TRUE)
5287                 return CONNMAN_SERVICE_SECURITY_NONE;
5288         else if (g_str_equal(security, "wep") == TRUE)
5289                 return CONNMAN_SERVICE_SECURITY_WEP;
5290         else if (g_str_equal(security, "psk") == TRUE)
5291                 return CONNMAN_SERVICE_SECURITY_PSK;
5292         else if (g_str_equal(security, "ieee8021x") == TRUE)
5293                 return CONNMAN_SERVICE_SECURITY_8021X;
5294         else if (g_str_equal(security, "wpa") == TRUE)
5295                 return CONNMAN_SERVICE_SECURITY_WPA;
5296         else if (g_str_equal(security, "rsn") == TRUE)
5297                 return CONNMAN_SERVICE_SECURITY_RSN;
5298         else
5299                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
5300 }
5301
5302 static void update_from_network(struct connman_service *service,
5303                                         struct connman_network *network)
5304 {
5305         connman_uint8_t strength = service->strength;
5306         GSequenceIter *iter;
5307         const char *str;
5308
5309         DBG("service %p network %p", service, network);
5310
5311         if (is_connected(service) == TRUE)
5312                 return;
5313
5314         if (is_connecting(service) == TRUE)
5315                 return;
5316
5317         str = connman_network_get_string(network, "Name");
5318         if (str != NULL) {
5319                 g_free(service->name);
5320                 service->name = g_strdup(str);
5321                 service->hidden = FALSE;
5322         } else {
5323                 g_free(service->name);
5324                 service->name = NULL;
5325                 service->hidden = TRUE;
5326         }
5327
5328         service->strength = connman_network_get_strength(network);
5329         service->roaming = connman_network_get_bool(network, "Roaming");
5330
5331         if (service->strength == 0) {
5332                 /*
5333                  * Filter out 0-values; it's unclear what they mean
5334                  * and they cause anomalous sorting of the priority list.
5335                  */
5336                 service->strength = strength;
5337         }
5338
5339         str = connman_network_get_string(network, "WiFi.Security");
5340         service->security = convert_wifi_security(str);
5341
5342         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
5343                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
5344
5345         if (service->strength > strength && service->network != NULL) {
5346                 service->network = network;
5347
5348                 strength_changed(service);
5349         }
5350
5351         if (service->network == NULL)
5352                 service->network = network;
5353
5354         iter = g_hash_table_lookup(service_hash, service->identifier);
5355         if (iter != NULL)
5356                 g_sequence_sort_changed(iter, service_compare, NULL);
5357 }
5358
5359 /**
5360  * __connman_service_create_from_network:
5361  * @network: network structure
5362  *
5363  * Look up service by network and if not found, create one
5364  */
5365 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
5366 {
5367         struct connman_service *service;
5368         struct connman_device *device;
5369         const char *ident, *group;
5370         char *name;
5371         int index;
5372
5373         DBG("network %p", network);
5374
5375         ident = __connman_network_get_ident(network);
5376         if (ident == NULL)
5377                 return NULL;
5378
5379         group = connman_network_get_group(network);
5380         if (group == NULL)
5381                 return NULL;
5382
5383         name = g_strdup_printf("%s_%s_%s",
5384                         __connman_network_get_type(network), ident, group);
5385         service = service_get(name);
5386         g_free(name);
5387
5388         if (service == NULL)
5389                 return NULL;
5390
5391         if (__connman_network_get_weakness(network) == TRUE)
5392                 return service;
5393
5394         if (service->path != NULL) {
5395                 update_from_network(service, network);
5396                 services_changed(TRUE);
5397                 return service;
5398         }
5399
5400         service->type = convert_network_type(network);
5401
5402         switch (service->type) {
5403         case CONNMAN_SERVICE_TYPE_UNKNOWN:
5404         case CONNMAN_SERVICE_TYPE_SYSTEM:
5405         case CONNMAN_SERVICE_TYPE_ETHERNET:
5406         case CONNMAN_SERVICE_TYPE_WIMAX:
5407         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
5408         case CONNMAN_SERVICE_TYPE_GPS:
5409         case CONNMAN_SERVICE_TYPE_VPN:
5410         case CONNMAN_SERVICE_TYPE_GADGET:
5411                 service->autoconnect = FALSE;
5412                 break;
5413         case CONNMAN_SERVICE_TYPE_WIFI:
5414         case CONNMAN_SERVICE_TYPE_CELLULAR:
5415                 service->autoconnect = TRUE;
5416                 break;
5417         }
5418
5419         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
5420         service->state = combine_state(service->state_ipv4, service->state_ipv6);
5421
5422         update_from_network(service, network);
5423
5424         index = connman_network_get_index(network);
5425
5426         if (service->ipconfig_ipv4 == NULL)
5427                 setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
5428
5429         if (service->ipconfig_ipv6 == NULL)
5430                 setup_ip6config(service, index);
5431
5432         service_register(service);
5433
5434         if (service->favorite == TRUE) {
5435                 device = connman_network_get_device(service->network);
5436                 if (device && __connman_device_scanning(device) == FALSE)
5437                         __connman_service_auto_connect();
5438         }
5439
5440         __connman_notifier_service_add(service, service->name);
5441
5442         return service;
5443 }
5444
5445 void __connman_service_update_from_network(struct connman_network *network)
5446 {
5447         struct connman_service *service;
5448         connman_uint8_t strength;
5449         connman_bool_t roaming;
5450         GSequenceIter *iter;
5451         const char *name;
5452         connman_bool_t stats_enable;
5453
5454         DBG("network %p", network);
5455
5456         service = __connman_service_lookup_from_network(network);
5457         if (service == NULL)
5458                 return;
5459
5460         if (service->network == NULL)
5461                 return;
5462
5463         name = connman_network_get_string(service->network, "Name");
5464         if (g_strcmp0(service->name, name) != 0) {
5465                 g_free(service->name);
5466                 service->name = g_strdup(name);
5467                 connman_dbus_property_changed_basic(service->path,
5468                                 CONNMAN_SERVICE_INTERFACE, "Name",
5469                                 DBUS_TYPE_STRING, &service->name);
5470         }
5471
5472         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
5473                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
5474
5475         strength = connman_network_get_strength(service->network);
5476         if (strength == service->strength)
5477                 goto roaming;
5478
5479         service->strength = strength;
5480
5481         strength_changed(service);
5482
5483 roaming:
5484         roaming = connman_network_get_bool(service->network, "Roaming");
5485         if (roaming == service->roaming)
5486                 return;
5487
5488         stats_enable = stats_enabled(service);
5489         if (stats_enable == TRUE)
5490                 stats_stop(service);
5491
5492         service->roaming = roaming;
5493
5494         if (stats_enable == TRUE)
5495                 stats_start(service);
5496
5497         roaming_changed(service);
5498
5499         iter = g_hash_table_lookup(service_hash, service->identifier);
5500         if (iter != NULL)
5501                 g_sequence_sort_changed(iter, service_compare, NULL);
5502 }
5503
5504 void __connman_service_remove_from_network(struct connman_network *network)
5505 {
5506         struct connman_service *service;
5507
5508         DBG("network %p", network);
5509
5510         service = __connman_service_lookup_from_network(network);
5511         if (service == NULL)
5512                 return;
5513
5514         __connman_service_put(service);
5515 }
5516
5517 /**
5518  * __connman_service_create_from_provider:
5519  * @provider: provider structure
5520  *
5521  * Look up service by provider and if not found, create one
5522  */
5523 struct connman_service *
5524 __connman_service_create_from_provider(struct connman_provider *provider)
5525 {
5526         struct connman_service *service;
5527         const char *ident, *str;
5528         char *name;
5529         int index = connman_provider_get_index(provider);
5530
5531         DBG("provider %p", provider);
5532
5533         ident = __connman_provider_get_ident(provider);
5534         if (ident == NULL)
5535                 return NULL;
5536
5537         name = g_strdup_printf("vpn_%s", ident);
5538         service = service_get(name);
5539         g_free(name);
5540
5541         if (service == NULL)
5542                 return NULL;
5543
5544         service->type = CONNMAN_SERVICE_TYPE_VPN;
5545         service->provider = connman_provider_ref(provider);
5546         service->autoconnect = FALSE;
5547
5548         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
5549
5550         str = connman_provider_get_string(provider, "Name");
5551         if (str != NULL) {
5552                 g_free(service->name);
5553                 service->name = g_strdup(str);
5554                 service->hidden = FALSE;
5555         } else {
5556                 g_free(service->name);
5557                 service->name = NULL;
5558                 service->hidden = TRUE;
5559         }
5560
5561         service->strength = 0;
5562
5563         if (service->ipconfig_ipv4 == NULL)
5564                 setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_MANUAL);
5565
5566         if (service->ipconfig_ipv6 == NULL)
5567                 setup_ip6config(service, index);
5568
5569         service_register(service);
5570
5571         __connman_notifier_service_add(service, service->name);
5572
5573         return service;
5574 }
5575
5576 void __connman_service_downgrade_state(struct connman_service *service)
5577 {
5578         if (service == NULL)
5579                 return;
5580
5581         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
5582                                                 service->state_ipv6);
5583
5584         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
5585                 __connman_service_ipconfig_indicate_state(service,
5586                                                 CONNMAN_SERVICE_STATE_READY,
5587                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
5588
5589         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
5590                 __connman_service_ipconfig_indicate_state(service,
5591                                                 CONNMAN_SERVICE_STATE_READY,
5592                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5593 }
5594
5595 int __connman_service_init(void)
5596 {
5597         DBG("");
5598
5599         connection = connman_dbus_get_connection();
5600
5601         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
5602                                                                 NULL, NULL);
5603
5604         service_list = g_sequence_new(service_free);
5605
5606         return 0;
5607 }
5608
5609 void __connman_service_cleanup(void)
5610 {
5611         GSequence *list;
5612
5613         DBG("");
5614
5615         list = service_list;
5616         service_list = NULL;
5617         g_sequence_free(list);
5618
5619         g_hash_table_destroy(service_hash);
5620         service_hash = NULL;
5621
5622         g_slist_free(counter_list);
5623         counter_list = NULL;
5624
5625         dbus_connection_unref(connection);
5626 }