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