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