35b7abae0ad9ddf3a54343e14d6304ff4d408f6f
[framework/connectivity/connman.git] / src / service.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <netdb.h>
30 #include <gdbus.h>
31 #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 timeservers_configuration_changed(struct connman_service *service)
1728 {
1729         connman_dbus_property_changed_array(service->path,
1730                         CONNMAN_SERVICE_INTERFACE,
1731                         "Timeservers.Configuration",
1732                         DBUS_TYPE_STRING,
1733                         append_tsconfig, service);
1734 }
1735
1736 static void link_changed(struct connman_service *service)
1737 {
1738         connman_dbus_property_changed_dict(service->path,
1739                                         CONNMAN_SERVICE_INTERFACE, "Ethernet",
1740                                                 append_ethernet, service);
1741 }
1742
1743 static void stats_append_counters(DBusMessageIter *dict,
1744                         struct connman_stats_data *stats,
1745                         struct connman_stats_data *counters,
1746                         connman_bool_t append_all)
1747 {
1748         if (counters->rx_packets != stats->rx_packets || append_all) {
1749                 counters->rx_packets = stats->rx_packets;
1750                 connman_dbus_dict_append_basic(dict, "RX.Packets",
1751                                         DBUS_TYPE_UINT32, &stats->rx_packets);
1752         }
1753
1754         if (counters->tx_packets != stats->tx_packets || append_all) {
1755                 counters->tx_packets = stats->tx_packets;
1756                 connman_dbus_dict_append_basic(dict, "TX.Packets",
1757                                         DBUS_TYPE_UINT32, &stats->tx_packets);
1758         }
1759
1760         if (counters->rx_bytes != stats->rx_bytes || append_all) {
1761                 counters->rx_bytes = stats->rx_bytes;
1762                 connman_dbus_dict_append_basic(dict, "RX.Bytes",
1763                                         DBUS_TYPE_UINT32, &stats->rx_bytes);
1764         }
1765
1766         if (counters->tx_bytes != stats->tx_bytes || append_all) {
1767                 counters->tx_bytes = stats->tx_bytes;
1768                 connman_dbus_dict_append_basic(dict, "TX.Bytes",
1769                                         DBUS_TYPE_UINT32, &stats->tx_bytes);
1770         }
1771
1772         if (counters->rx_errors != stats->rx_errors || append_all) {
1773                 counters->rx_errors = stats->rx_errors;
1774                 connman_dbus_dict_append_basic(dict, "RX.Errors",
1775                                         DBUS_TYPE_UINT32, &stats->rx_errors);
1776         }
1777
1778         if (counters->tx_errors != stats->tx_errors || append_all) {
1779                 counters->tx_errors = stats->tx_errors;
1780                 connman_dbus_dict_append_basic(dict, "TX.Errors",
1781                                         DBUS_TYPE_UINT32, &stats->tx_errors);
1782         }
1783
1784         if (counters->rx_dropped != stats->rx_dropped || append_all) {
1785                 counters->rx_dropped = stats->rx_dropped;
1786                 connman_dbus_dict_append_basic(dict, "RX.Dropped",
1787                                         DBUS_TYPE_UINT32, &stats->rx_dropped);
1788         }
1789
1790         if (counters->tx_dropped != stats->tx_dropped || append_all) {
1791                 counters->tx_dropped = stats->tx_dropped;
1792                 connman_dbus_dict_append_basic(dict, "TX.Dropped",
1793                                         DBUS_TYPE_UINT32, &stats->tx_dropped);
1794         }
1795
1796         if (counters->time != stats->time || append_all) {
1797                 counters->time = stats->time;
1798                 connman_dbus_dict_append_basic(dict, "Time",
1799                                         DBUS_TYPE_UINT32, &stats->time);
1800         }
1801 }
1802
1803 static void stats_append(struct connman_service *service,
1804                                 const char *counter,
1805                                 struct connman_stats_counter *counters,
1806                                 connman_bool_t append_all)
1807 {
1808         DBusMessageIter array, dict;
1809         DBusMessage *msg;
1810
1811         DBG("service %p counter %s", service, counter);
1812
1813         msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
1814         if (msg == NULL)
1815                 return;
1816
1817         dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH,
1818                                 &service->path, DBUS_TYPE_INVALID);
1819
1820         dbus_message_iter_init_append(msg, &array);
1821
1822         /* home counter */
1823         connman_dbus_dict_open(&array, &dict);
1824
1825         stats_append_counters(&dict, &service->stats.data,
1826                                 &counters->stats.data, append_all);
1827
1828         connman_dbus_dict_close(&array, &dict);
1829
1830         /* roaming counter */
1831         connman_dbus_dict_open(&array, &dict);
1832
1833         stats_append_counters(&dict, &service->stats_roaming.data,
1834                                 &counters->stats_roaming.data, append_all);
1835
1836         connman_dbus_dict_close(&array, &dict);
1837
1838         __connman_counter_send_usage(counter, msg);
1839 }
1840
1841 static void stats_update(struct connman_service *service,
1842                                 unsigned int rx_packets, unsigned int tx_packets,
1843                                 unsigned int rx_bytes, unsigned int tx_bytes,
1844                                 unsigned int rx_errors, unsigned int tx_errors,
1845                                 unsigned int rx_dropped, unsigned int tx_dropped)
1846 {
1847         struct connman_stats *stats = stats_get(service);
1848         struct connman_stats_data *data_last = &stats->data_last;
1849         struct connman_stats_data *data = &stats->data;
1850         unsigned int seconds;
1851
1852         DBG("service %p", service);
1853
1854         if (stats->valid == TRUE) {
1855                 data->rx_packets +=
1856                         rx_packets - data_last->rx_packets;
1857                 data->tx_packets +=
1858                         tx_packets - data_last->tx_packets;
1859                 data->rx_bytes +=
1860                         rx_bytes - data_last->rx_bytes;
1861                 data->tx_bytes +=
1862                         tx_bytes - data_last->tx_bytes;
1863                 data->rx_errors +=
1864                         rx_errors - data_last->rx_errors;
1865                 data->tx_errors +=
1866                         tx_errors - data_last->tx_errors;
1867                 data->rx_dropped +=
1868                         rx_dropped - data_last->rx_dropped;
1869                 data->tx_dropped +=
1870                         tx_dropped - data_last->tx_dropped;
1871         } else {
1872                 stats->valid = TRUE;
1873         }
1874
1875         data_last->rx_packets = rx_packets;
1876         data_last->tx_packets = tx_packets;
1877         data_last->rx_bytes = rx_bytes;
1878         data_last->tx_bytes = tx_bytes;
1879         data_last->rx_errors = rx_errors;
1880         data_last->tx_errors = tx_errors;
1881         data_last->rx_dropped = rx_dropped;
1882         data_last->tx_dropped = tx_dropped;
1883
1884         seconds = g_timer_elapsed(stats->timer, NULL);
1885         stats->data.time = stats->data_last.time + seconds;
1886 }
1887
1888 void __connman_service_notify(struct connman_service *service,
1889                         unsigned int rx_packets, unsigned int tx_packets,
1890                         unsigned int rx_bytes, unsigned int tx_bytes,
1891                         unsigned int rx_errors, unsigned int tx_errors,
1892                         unsigned int rx_dropped, unsigned int tx_dropped)
1893 {
1894         GHashTableIter iter;
1895         gpointer key, value;
1896         const char *counter;
1897         struct connman_stats_counter *counters;
1898         struct connman_stats_data *data;
1899         int err;
1900
1901         if (service == NULL)
1902                 return;
1903
1904         if (is_connected(service) == FALSE)
1905                 return;
1906
1907         stats_update(service,
1908                 rx_packets, tx_packets,
1909                 rx_bytes, tx_bytes,
1910                 rx_errors, tx_errors,
1911                 rx_dropped, tx_dropped);
1912
1913         data = &stats_get(service)->data;
1914         err = __connman_stats_update(service, service->roaming, data);
1915         if (err < 0)
1916                 connman_error("Failed to store statistics for %s",
1917                                 service->identifier);
1918
1919         g_hash_table_iter_init(&iter, service->counter_table);
1920         while (g_hash_table_iter_next(&iter, &key, &value)) {
1921                 counter = key;
1922                 counters = value;
1923
1924                 stats_append(service, counter, counters, counters->append_all);
1925                 counters->append_all = FALSE;
1926         }
1927 }
1928
1929 int __connman_service_counter_register(const char *counter)
1930 {
1931         struct connman_service *service;
1932         GSequenceIter *iter;
1933         struct connman_stats_counter *counters;
1934
1935         DBG("counter %s", counter);
1936
1937         counter_list = g_slist_append(counter_list, (gpointer)counter);
1938
1939         iter = g_sequence_get_begin_iter(service_list);
1940
1941         while (g_sequence_iter_is_end(iter) == FALSE) {
1942                 service = g_sequence_get(iter);
1943
1944                 counters = g_try_new0(struct connman_stats_counter, 1);
1945                 if (counters == NULL)
1946                         return -ENOMEM;
1947
1948                 counters->append_all = TRUE;
1949
1950                 g_hash_table_replace(service->counter_table, (gpointer)counter,
1951                                         counters);
1952
1953                 iter = g_sequence_iter_next(iter);
1954         }
1955
1956         return 0;
1957 }
1958
1959 void __connman_service_counter_unregister(const char *counter)
1960 {
1961         struct connman_service *service;
1962         GSequenceIter *iter;
1963
1964         DBG("counter %s", counter);
1965
1966         iter = g_sequence_get_begin_iter(service_list);
1967
1968         while (g_sequence_iter_is_end(iter) == FALSE) {
1969                 service = g_sequence_get(iter);
1970
1971                 g_hash_table_remove(service->counter_table, counter);
1972
1973                 iter = g_sequence_iter_next(iter);
1974         }
1975
1976         counter_list = g_slist_remove(counter_list, counter);
1977 }
1978
1979 GSequence *__connman_service_get_list(struct connman_session *session,
1980                                 service_match_cb service_match,
1981                                 create_service_entry_cb create_service_entry,
1982                                 GDestroyNotify destroy_service_entry)
1983 {
1984         GSequence *list;
1985         GSequenceIter *iter;
1986         struct connman_service *service;
1987         struct service_entry *entry;
1988
1989         list = g_sequence_new(destroy_service_entry);
1990         if (list == NULL)
1991                 return NULL;
1992
1993         iter = g_sequence_get_begin_iter(service_list);
1994
1995         while (g_sequence_iter_is_end(iter) == FALSE) {
1996                 service = g_sequence_get(iter);
1997
1998                 if (service_match(session, service) == TRUE) {
1999                         entry = create_service_entry(service, service->name,
2000                                                         service->state);
2001                         if (entry == NULL)
2002                                 return list;
2003
2004                         g_sequence_append(list, entry);
2005                 }
2006
2007                 iter = g_sequence_iter_next(iter);
2008         }
2009
2010         return list;
2011 }
2012
2013 void __connman_service_session_inc(struct connman_service *service)
2014 {
2015         DBG("service %p ref count %d", service,
2016                 service->session_usage_count + 1);
2017
2018         __sync_fetch_and_add(&service->session_usage_count, 1);
2019 }
2020
2021 connman_bool_t __connman_service_session_dec(struct connman_service *service)
2022 {
2023         DBG("service %p ref count %d", service,
2024                 service->session_usage_count - 1);
2025
2026         if (__sync_fetch_and_sub(&service->session_usage_count, 1) != 1)
2027                 return FALSE;
2028
2029         return TRUE;
2030 }
2031
2032 static void append_properties(DBusMessageIter *dict, dbus_bool_t limited,
2033                                         struct connman_service *service)
2034 {
2035         const char *str;
2036
2037         str = __connman_service_type2string(service->type);
2038         if (str != NULL)
2039                 connman_dbus_dict_append_basic(dict, "Type",
2040                                                 DBUS_TYPE_STRING, &str);
2041
2042         connman_dbus_dict_append_array(dict, "Security",
2043                                 DBUS_TYPE_STRING, append_security, service);
2044
2045         str = state2string(service->state);
2046         if (str != NULL)
2047                 connman_dbus_dict_append_basic(dict, "State",
2048                                                 DBUS_TYPE_STRING, &str);
2049
2050         str = error2string(service->error);
2051         if (str != NULL)
2052                 connman_dbus_dict_append_basic(dict, "Error",
2053                                                 DBUS_TYPE_STRING, &str);
2054
2055         if (service->strength > 0)
2056                 connman_dbus_dict_append_basic(dict, "Strength",
2057                                         DBUS_TYPE_BYTE, &service->strength);
2058
2059         connman_dbus_dict_append_basic(dict, "Favorite",
2060                                         DBUS_TYPE_BOOLEAN, &service->favorite);
2061
2062         connman_dbus_dict_append_basic(dict, "Immutable",
2063                                         DBUS_TYPE_BOOLEAN, &service->immutable);
2064
2065         if (service->favorite == TRUE)
2066                 connman_dbus_dict_append_basic(dict, "AutoConnect",
2067                                 DBUS_TYPE_BOOLEAN, &service->autoconnect);
2068         else
2069                 connman_dbus_dict_append_basic(dict, "AutoConnect",
2070                                         DBUS_TYPE_BOOLEAN, &service->favorite);
2071
2072         if (service->name != NULL)
2073                 connman_dbus_dict_append_basic(dict, "Name",
2074                                         DBUS_TYPE_STRING, &service->name);
2075
2076         switch (service->type) {
2077         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2078         case CONNMAN_SERVICE_TYPE_SYSTEM:
2079         case CONNMAN_SERVICE_TYPE_GPS:
2080         case CONNMAN_SERVICE_TYPE_VPN:
2081         case CONNMAN_SERVICE_TYPE_GADGET:
2082                 break;
2083         case CONNMAN_SERVICE_TYPE_CELLULAR:
2084                 connman_dbus_dict_append_basic(dict, "Roaming",
2085                                         DBUS_TYPE_BOOLEAN, &service->roaming);
2086
2087                 connman_dbus_dict_append_dict(dict, "Ethernet",
2088                                                 append_ethernet, service);
2089                 break;
2090         case CONNMAN_SERVICE_TYPE_WIFI:
2091         case CONNMAN_SERVICE_TYPE_ETHERNET:
2092         case CONNMAN_SERVICE_TYPE_WIMAX:
2093         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2094                 connman_dbus_dict_append_dict(dict, "Ethernet",
2095                                                 append_ethernet, service);
2096                 break;
2097         }
2098
2099         connman_dbus_dict_append_dict(dict, "IPv4", append_ipv4, service);
2100
2101         connman_dbus_dict_append_dict(dict, "IPv4.Configuration",
2102                                                 append_ipv4config, service);
2103
2104         connman_dbus_dict_append_dict(dict, "IPv6", append_ipv6, service);
2105
2106         connman_dbus_dict_append_dict(dict, "IPv6.Configuration",
2107                                                 append_ipv6config, service);
2108
2109         connman_dbus_dict_append_array(dict, "Nameservers",
2110                                 DBUS_TYPE_STRING, append_dns, service);
2111
2112         connman_dbus_dict_append_array(dict, "Nameservers.Configuration",
2113                                 DBUS_TYPE_STRING, append_dnsconfig, service);
2114
2115         connman_dbus_dict_append_array(dict, "Timeservers.Configuration",
2116                                 DBUS_TYPE_STRING, append_tsconfig, service);
2117
2118         connman_dbus_dict_append_array(dict, "Domains",
2119                                 DBUS_TYPE_STRING, append_domain, service);
2120
2121         connman_dbus_dict_append_array(dict, "Domains.Configuration",
2122                                 DBUS_TYPE_STRING, append_domainconfig, service);
2123
2124         connman_dbus_dict_append_dict(dict, "Proxy", append_proxy, service);
2125
2126         connman_dbus_dict_append_dict(dict, "Proxy.Configuration",
2127                                                 append_proxyconfig, service);
2128
2129         connman_dbus_dict_append_dict(dict, "Provider",
2130                                                 append_provider, service);
2131 }
2132
2133 static void append_struct_service(DBusMessageIter *iter,
2134                 connman_dbus_append_cb_t function,
2135                 struct connman_service *service)
2136 {
2137         DBusMessageIter entry, dict;
2138
2139         dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
2140
2141         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
2142                                                         &service->path);
2143
2144         connman_dbus_dict_open(&entry, &dict);
2145         if (function != NULL)
2146                 function(&dict, service);
2147         connman_dbus_dict_close(&entry, &dict);
2148
2149         dbus_message_iter_close_container(iter, &entry);
2150 }
2151
2152 static void append_dict_properties(DBusMessageIter *dict, void *user_data)
2153 {
2154         struct connman_service *service = user_data;
2155
2156         append_properties(dict, TRUE, service);
2157 }
2158
2159 static void append_struct(gpointer value, gpointer user_data)
2160 {
2161         struct connman_service *service = value;
2162         DBusMessageIter *iter = user_data;
2163
2164         if (service->path == NULL)
2165                 return;
2166
2167         append_struct_service(iter, append_dict_properties, service);
2168 }
2169
2170 void __connman_service_list_struct(DBusMessageIter *iter)
2171 {
2172         g_sequence_foreach(service_list, append_struct, iter);
2173 }
2174
2175 connman_bool_t __connman_service_is_hidden(struct connman_service *service)
2176 {
2177         return service->hidden;
2178 }
2179
2180 connman_bool_t
2181 __connman_service_is_split_routing(struct connman_service *service)
2182 {
2183         return service->do_split_routing;
2184 }
2185
2186 int __connman_service_get_index(struct connman_service *service)
2187 {
2188         if (service == NULL)
2189                 return -1;
2190
2191         if (service->network != NULL)
2192                 return connman_network_get_index(service->network);
2193         else if (service->provider != NULL)
2194                 return connman_provider_get_index(service->provider);
2195
2196         return -1;
2197 }
2198
2199 void __connman_service_set_domainname(struct connman_service *service,
2200                                                 const char *domainname)
2201 {
2202         if (service == NULL || service->hidden == TRUE)
2203                 return;
2204
2205         g_free(service->domainname);
2206         service->domainname = g_strdup(domainname);
2207
2208         domain_changed(service);
2209 }
2210
2211 const char *connman_service_get_domainname(struct connman_service *service)
2212 {
2213         if (service == NULL)
2214                 return NULL;
2215
2216         if (service->domains != NULL)
2217                 return service->domains[0];
2218         else
2219                 return service->domainname;
2220 }
2221
2222 char **connman_service_get_nameservers(struct connman_service *service)
2223 {
2224         if (service == NULL)
2225                 return NULL;
2226
2227         if (service->nameservers_config != NULL)
2228                 return g_strdupv(service->nameservers_config);
2229         else if (service->nameservers != NULL ||
2230                                         service->nameservers_auto != NULL) {
2231                 int len = 0, len_auto = 0, i;
2232                 char **nameservers;
2233
2234                 if (service->nameservers != NULL)
2235                         len = g_strv_length(service->nameservers);
2236                 if (service->nameservers_auto != NULL)
2237                         len_auto = g_strv_length(service->nameservers_auto);
2238
2239                 nameservers = g_try_new0(char *, len + len_auto + 1);
2240                 if (nameservers == NULL)
2241                         return NULL;
2242
2243                 for (i = 0; i < len; i++)
2244                         nameservers[i] = g_strdup(service->nameservers[i]);
2245
2246                 for (i = 0; i < len_auto; i++)
2247                         nameservers[i + len] =
2248                                 g_strdup(service->nameservers_auto[i]);
2249
2250                 return nameservers;
2251         }
2252
2253         return NULL;
2254 }
2255
2256 char **connman_service_get_timeservers_config(struct connman_service *service)
2257 {
2258         if (service == NULL)
2259                 return NULL;
2260
2261         return service->timeservers_config;
2262 }
2263
2264 char **connman_service_get_timeservers(struct connman_service *service)
2265 {
2266         if (service == NULL)
2267                 return NULL;
2268
2269         if (service->timeservers != NULL)
2270                 return service->timeservers;
2271
2272         return NULL;
2273 }
2274
2275 void connman_service_set_proxy_method(struct connman_service *service,
2276                                         enum connman_service_proxy_method method)
2277 {
2278         if (service == NULL || service->hidden == TRUE)
2279                 return;
2280
2281         service->proxy = method;
2282
2283         proxy_changed(service);
2284
2285         if (method != CONNMAN_SERVICE_PROXY_METHOD_AUTO)
2286                 __connman_notifier_proxy_changed(service);
2287 }
2288
2289 enum connman_service_proxy_method connman_service_get_proxy_method(
2290                                         struct connman_service *service)
2291 {
2292         if (service == NULL)
2293                 return CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
2294
2295         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN) {
2296                 if (service->proxy_config == CONNMAN_SERVICE_PROXY_METHOD_AUTO &&
2297                                 service->pac == NULL)
2298                         return service->proxy;
2299
2300                 return service->proxy_config;
2301         }
2302
2303         return service->proxy;
2304 }
2305
2306 char **connman_service_get_proxy_servers(struct connman_service *service)
2307 {
2308         return g_strdupv(service->proxies);
2309 }
2310
2311 char **connman_service_get_proxy_excludes(struct connman_service *service)
2312 {
2313         return g_strdupv(service->excludes);
2314 }
2315
2316 const char *connman_service_get_proxy_url(struct connman_service *service)
2317 {
2318         if (service == NULL)
2319                 return NULL;
2320
2321         return service->pac;
2322 }
2323
2324 void __connman_service_set_proxy_autoconfig(struct connman_service *service,
2325                                                         const char *url)
2326 {
2327         if (service == NULL || service->hidden == TRUE)
2328                 return;
2329
2330         service->proxy = CONNMAN_SERVICE_PROXY_METHOD_AUTO;
2331
2332         if (service->ipconfig_ipv4) {
2333                 if (__connman_ipconfig_set_proxy_autoconfig(
2334                             service->ipconfig_ipv4, url) < 0)
2335                         return;
2336         } else if (service->ipconfig_ipv6) {
2337                 if (__connman_ipconfig_set_proxy_autoconfig(
2338                             service->ipconfig_ipv6, url) < 0)
2339                         return;
2340         } else
2341                 return;
2342
2343         proxy_changed(service);
2344
2345         __connman_notifier_proxy_changed(service);
2346 }
2347
2348 const char *connman_service_get_proxy_autoconfig(struct connman_service *service)
2349 {
2350         if (service == NULL)
2351                 return NULL;
2352
2353         if (service->ipconfig_ipv4)
2354                 return __connman_ipconfig_get_proxy_autoconfig(
2355                                                 service->ipconfig_ipv4);
2356         else if (service->ipconfig_ipv6)
2357                 return __connman_ipconfig_get_proxy_autoconfig(
2358                                                 service->ipconfig_ipv6);
2359         return NULL;
2360 }
2361
2362 int __connman_service_timeserver_append(struct connman_service *service,
2363                                                 const char *timeserver)
2364 {
2365         int len;
2366
2367         DBG("service %p timeserver %s", service, timeserver);
2368
2369         if (timeserver == NULL)
2370                 return -EINVAL;
2371
2372         if (service->timeservers != NULL) {
2373                 int i;
2374
2375                 for (i = 0; service->timeservers[i] != NULL; i++)
2376                         if (g_strcmp0(service->timeservers[i], timeserver) == 0)
2377                                 return -EEXIST;
2378
2379                 len = g_strv_length(service->timeservers);
2380                 service->timeservers = g_try_renew(char *, service->timeservers,
2381                                                         len + 2);
2382         } else {
2383                 len = 0;
2384                 service->timeservers = g_try_new0(char *, len + 2);
2385         }
2386
2387         if (service->timeservers == NULL)
2388                 return -ENOMEM;
2389
2390         service->timeservers[len] = g_strdup(timeserver);
2391         service->timeservers[len + 1] = NULL;
2392
2393         return 0;
2394 }
2395
2396 int __connman_service_timeserver_remove(struct connman_service *service,
2397                                                 const char *timeserver)
2398 {
2399         char **servers;
2400         int len, i, j, found = 0;
2401
2402         DBG("service %p timeserver %s", service, timeserver);
2403
2404         if (timeserver == NULL)
2405                 return -EINVAL;
2406
2407         if (service->timeservers == NULL)
2408                 return 0;
2409
2410         for (i = 0; service->timeservers != NULL &&
2411                                         service->timeservers[i] != NULL; i++)
2412                 if (g_strcmp0(service->timeservers[i], timeserver) == 0) {
2413                         found = 1;
2414                         break;
2415                 }
2416
2417         if (found == 0)
2418                 return 0;
2419
2420         len = g_strv_length(service->timeservers);
2421
2422         if (len == 1) {
2423                 g_strfreev(service->timeservers);
2424                 service->timeservers = NULL;
2425
2426                 return 0;
2427         }
2428
2429         servers = g_try_new0(char *, len);
2430         if (servers == NULL)
2431                 return -ENOMEM;
2432
2433         for (i = 0, j = 0; i < len; i++) {
2434                 if (g_strcmp0(service->timeservers[i], timeserver) != 0) {
2435                         servers[j] = g_strdup(service->timeservers[i]);
2436                         if (servers[j] == NULL)
2437                                 return -ENOMEM;
2438                         j++;
2439                 }
2440         }
2441         servers[len - 1] = NULL;
2442
2443         g_strfreev(service->timeservers);
2444         service->timeservers = servers;
2445
2446         return 0;
2447 }
2448
2449 void __connman_service_set_pac(struct connman_service *service,
2450                                         const char *pac)
2451 {
2452         if (service->hidden == TRUE)
2453                 return;
2454         g_free(service->pac);
2455         service->pac = g_strdup(pac);
2456
2457         proxy_changed(service);
2458 }
2459
2460 void __connman_service_set_identity(struct connman_service *service,
2461                                         const char *identity)
2462 {
2463         if (service->immutable || service->hidden == TRUE)
2464                 return;
2465
2466         g_free(service->identity);
2467         service->identity = g_strdup(identity);
2468
2469         if (service->network != NULL)
2470                 connman_network_set_string(service->network,
2471                                         "WiFi.Identity",
2472                                         service->identity);
2473 }
2474
2475 void __connman_service_set_agent_identity(struct connman_service *service,
2476                                                 const char *agent_identity)
2477 {
2478         if (service->hidden == TRUE)
2479                 return;
2480         g_free(service->agent_identity);
2481         service->agent_identity = g_strdup(agent_identity);
2482
2483         if (service->network != NULL)
2484                 connman_network_set_string(service->network,
2485                                         "WiFi.AgentIdentity",
2486                                         service->agent_identity);
2487 }
2488
2489 static int check_passphrase(enum connman_service_security security,
2490                                 const char *passphrase)
2491 {
2492         guint i;
2493         gsize length;
2494
2495         if (passphrase == NULL)
2496                 return 0;
2497
2498         length = strlen(passphrase);
2499
2500         switch (security) {
2501         case CONNMAN_SERVICE_SECURITY_PSK:
2502         case CONNMAN_SERVICE_SECURITY_WPA:
2503         case CONNMAN_SERVICE_SECURITY_RSN:
2504                 /* A raw key is always 64 bytes length,
2505                  * its content is in hex representation.
2506                  * A PSK key must be between [8..63].
2507                  */
2508                 if (length == 64) {
2509                         for (i = 0; i < 64; i++)
2510                                 if (!isxdigit((unsigned char)
2511                                               passphrase[i]))
2512                                         return -ENOKEY;
2513                 } else if (length < 8 || length > 63)
2514                         return -ENOKEY;
2515                 break;
2516         case CONNMAN_SERVICE_SECURITY_WEP:
2517                 /* length of WEP key is 10 or 26
2518                  * length of WEP passphrase is 5 or 13
2519                  */
2520                 if (length == 10 || length == 26) {
2521                         for (i = 0; i < length; i++)
2522                                 if (!isxdigit((unsigned char)
2523                                               passphrase[i]))
2524                                         return -ENOKEY;
2525                 } else if (length != 5 && length != 13)
2526                         return -ENOKEY;
2527                 break;
2528         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
2529         case CONNMAN_SERVICE_SECURITY_NONE:
2530         case CONNMAN_SERVICE_SECURITY_8021X:
2531                 break;
2532         }
2533
2534         return 0;
2535 }
2536
2537 int __connman_service_set_passphrase(struct connman_service *service,
2538                                         const char *passphrase)
2539 {
2540         int err = 0;
2541
2542         if (service->immutable == TRUE || service->hidden == TRUE)
2543                 return -EINVAL;
2544
2545         err = check_passphrase(service->security, passphrase);
2546
2547         if (err == 0) {
2548                 g_free(service->passphrase);
2549                 service->passphrase = g_strdup(passphrase);
2550
2551                 if (service->network != NULL)
2552                         connman_network_set_string(service->network,
2553                                                         "WiFi.Passphrase",
2554                                                         service->passphrase);
2555                 service_save(service);
2556         }
2557
2558         return err;
2559 }
2560
2561 void __connman_service_set_agent_passphrase(struct connman_service *service,
2562                                                 const char *agent_passphrase)
2563 {
2564         if (service->hidden == TRUE)
2565                 return;
2566         g_free(service->agent_passphrase);
2567         service->agent_passphrase = g_strdup(agent_passphrase);
2568
2569         if (service->network != NULL)
2570                 connman_network_set_string(service->network,
2571                                         "WiFi.AgentPassphrase",
2572                                         service->agent_passphrase);
2573 }
2574
2575 static DBusMessage *get_properties(DBusConnection *conn,
2576                                         DBusMessage *msg, void *user_data)
2577 {
2578         struct connman_service *service = user_data;
2579         DBusMessage *reply;
2580         DBusMessageIter array, dict;
2581
2582         DBG("service %p", service);
2583
2584         reply = dbus_message_new_method_return(msg);
2585         if (reply == NULL)
2586                 return NULL;
2587
2588         dbus_message_iter_init_append(reply, &array);
2589
2590         connman_dbus_dict_open(&array, &dict);
2591         append_properties(&dict, FALSE, service);
2592         connman_dbus_dict_close(&array, &dict);
2593
2594         return reply;
2595 }
2596
2597 static int update_proxy_configuration(struct connman_service *service,
2598                                 DBusMessageIter *array)
2599 {
2600         DBusMessageIter dict;
2601         enum connman_service_proxy_method method;
2602         GString *servers_str = NULL;
2603         GString *excludes_str = NULL;
2604         const char *url = NULL;
2605
2606         method = CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN;
2607
2608         dbus_message_iter_recurse(array, &dict);
2609
2610         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
2611                 DBusMessageIter entry, variant;
2612                 const char *key;
2613                 int type;
2614
2615                 dbus_message_iter_recurse(&dict, &entry);
2616
2617                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
2618                         goto error;
2619
2620                 dbus_message_iter_get_basic(&entry, &key);
2621                 dbus_message_iter_next(&entry);
2622
2623                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
2624                         goto error;
2625
2626                 dbus_message_iter_recurse(&entry, &variant);
2627
2628                 type = dbus_message_iter_get_arg_type(&variant);
2629
2630                 if (g_str_equal(key, "Method") == TRUE) {
2631                         const char *val;
2632
2633                         if (type != DBUS_TYPE_STRING)
2634                                 goto error;
2635
2636                         dbus_message_iter_get_basic(&variant, &val);
2637                         method = string2proxymethod(val);
2638                 } else if (g_str_equal(key, "URL") == TRUE) {
2639                         if (type != DBUS_TYPE_STRING)
2640                                 goto error;
2641
2642                         dbus_message_iter_get_basic(&variant, &url);
2643                 } else if (g_str_equal(key, "Servers") == TRUE) {
2644                         DBusMessageIter str_array;
2645
2646                         if (type != DBUS_TYPE_ARRAY)
2647                                 goto error;
2648
2649                         servers_str = g_string_new(NULL);
2650                         if (servers_str == NULL)
2651                                 goto error;
2652
2653                         dbus_message_iter_recurse(&variant, &str_array);
2654
2655                         while (dbus_message_iter_get_arg_type(&str_array) ==
2656                                                         DBUS_TYPE_STRING) {
2657                                 char *val = NULL;
2658
2659                                 dbus_message_iter_get_basic(&str_array, &val);
2660
2661                                 if (servers_str->len > 0)
2662                                         g_string_append_printf(servers_str,
2663                                                         " %s", val);
2664                                 else
2665                                         g_string_append(servers_str, val);
2666
2667                                 dbus_message_iter_next(&str_array);
2668                         }
2669                 } else if (g_str_equal(key, "Excludes") == TRUE) {
2670                         DBusMessageIter str_array;
2671
2672                         if (type != DBUS_TYPE_ARRAY)
2673                                 goto error;
2674
2675                         excludes_str = g_string_new(NULL);
2676                         if (excludes_str == NULL)
2677                                 goto error;
2678
2679                         dbus_message_iter_recurse(&variant, &str_array);
2680
2681                         while (dbus_message_iter_get_arg_type(&str_array) ==
2682                                                         DBUS_TYPE_STRING) {
2683                                 char *val = NULL;
2684
2685                                 dbus_message_iter_get_basic(&str_array, &val);
2686
2687                                 if (excludes_str->len > 0)
2688                                         g_string_append_printf(excludes_str,
2689                                                         " %s", val);
2690                                 else
2691                                         g_string_append(excludes_str, val);
2692
2693                                 dbus_message_iter_next(&str_array);
2694                         }
2695                 }
2696
2697                 dbus_message_iter_next(&dict);
2698         }
2699
2700         switch (method) {
2701         case CONNMAN_SERVICE_PROXY_METHOD_DIRECT:
2702                 break;
2703         case CONNMAN_SERVICE_PROXY_METHOD_MANUAL:
2704                 if (servers_str == NULL && service->proxies == NULL)
2705                         goto error;
2706
2707                 if (servers_str != NULL) {
2708                         g_strfreev(service->proxies);
2709
2710                         if (servers_str->len > 0)
2711                                 service->proxies = g_strsplit_set(
2712                                         servers_str->str, " ", 0);
2713                         else
2714                                 service->proxies = NULL;
2715                 }
2716
2717                 if (excludes_str != NULL) {
2718                         g_strfreev(service->excludes);
2719
2720                         if (excludes_str->len > 0)
2721                                 service->excludes = g_strsplit_set(
2722                                         excludes_str->str, " ", 0);
2723                         else
2724                                 service->excludes = NULL;
2725                 }
2726
2727                 if (service->proxies == NULL)
2728                         method = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
2729
2730                 break;
2731         case CONNMAN_SERVICE_PROXY_METHOD_AUTO:
2732                 g_free(service->pac);
2733
2734                 if (url != NULL && strlen(url) > 0)
2735                         service->pac = g_strdup(url);
2736                 else
2737                         service->pac = NULL;
2738
2739                 /* if we are connected:
2740                    - if service->pac == NULL
2741                    - if __connman_ipconfig_get_proxy_autoconfig(
2742                    service->ipconfig) == NULL
2743                    --> We should start WPAD */
2744
2745                 break;
2746         case CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN:
2747                 goto error;
2748         }
2749
2750         if (servers_str != NULL)
2751                 g_string_free(servers_str, TRUE);
2752
2753         if (excludes_str != NULL)
2754                 g_string_free(excludes_str, TRUE);
2755
2756         service->proxy_config = method;
2757
2758         return 0;
2759
2760 error:
2761         if (servers_str != NULL)
2762                 g_string_free(servers_str, TRUE);
2763
2764         if (excludes_str != NULL)
2765                 g_string_free(excludes_str, TRUE);
2766
2767         return -EINVAL;
2768 }
2769
2770 static int set_ipconfig(struct connman_service *service,
2771                         struct connman_ipconfig *ipconfig,
2772                         DBusMessageIter *array,
2773                         enum connman_service_state state,
2774                         enum connman_service_state *new_state)
2775 {
2776         enum connman_ipconfig_method old_method;
2777         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
2778         enum connman_ipconfig_type type;
2779         int err;
2780
2781         if (ipconfig == NULL)
2782                 return -EINVAL;
2783
2784         old_method = __connman_ipconfig_get_method(ipconfig);
2785
2786         if (is_connecting_state(service, state) ||
2787                                         is_connected_state(service, state))
2788                 __connman_network_clear_ipconfig(service->network, ipconfig);
2789
2790         err = __connman_ipconfig_set_config(ipconfig, array);
2791         method = __connman_ipconfig_get_method(ipconfig);
2792         type = __connman_ipconfig_get_config_type(ipconfig);
2793
2794         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
2795                 if (err == 0 && old_method == CONNMAN_IPCONFIG_METHOD_OFF &&
2796                                 method == CONNMAN_IPCONFIG_METHOD_DHCP) {
2797                         *new_state = service->state_ipv4 =
2798                                 CONNMAN_SERVICE_STATE_CONFIGURATION;
2799                         __connman_ipconfig_enable(ipconfig);
2800                 }
2801
2802         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
2803                 if (err == 0 && old_method == CONNMAN_IPCONFIG_METHOD_OFF &&
2804                                 method == CONNMAN_IPCONFIG_METHOD_AUTO) {
2805                         *new_state = service->state_ipv6;
2806                         __connman_ipconfig_enable(ipconfig);
2807                 }
2808         }
2809
2810         DBG("err %d ipconfig %p type %d method %d state %s", err, ipconfig,
2811                 type, method, state2string(*new_state));
2812
2813         return err;
2814 }
2815
2816 static DBusMessage *set_property(DBusConnection *conn,
2817                                         DBusMessage *msg, void *user_data)
2818 {
2819         struct connman_service *service = user_data;
2820         DBusMessageIter iter, value;
2821         const char *name;
2822         int type;
2823
2824         DBG("service %p", service);
2825
2826         if (dbus_message_iter_init(msg, &iter) == FALSE)
2827                 return __connman_error_invalid_arguments(msg);
2828
2829         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
2830                 return __connman_error_invalid_arguments(msg);
2831
2832         dbus_message_iter_get_basic(&iter, &name);
2833         dbus_message_iter_next(&iter);
2834
2835         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
2836                 return __connman_error_invalid_arguments(msg);
2837
2838         dbus_message_iter_recurse(&iter, &value);
2839
2840         type = dbus_message_iter_get_arg_type(&value);
2841
2842         if (g_str_equal(name, "AutoConnect") == TRUE) {
2843                 connman_bool_t autoconnect;
2844
2845                 if (type != DBUS_TYPE_BOOLEAN)
2846                         return __connman_error_invalid_arguments(msg);
2847
2848                 if (service->favorite == FALSE)
2849                         return __connman_error_invalid_service(msg);
2850
2851                 dbus_message_iter_get_basic(&value, &autoconnect);
2852
2853                 if (service->autoconnect == autoconnect)
2854                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
2855
2856                 service->autoconnect = autoconnect;
2857
2858                 autoconnect_changed(service);
2859
2860                 service_save(service);
2861         } else if (g_str_equal(name, "Nameservers.Configuration") == TRUE) {
2862                 DBusMessageIter entry;
2863                 GString *str;
2864                 int index;
2865                 const char *gw;
2866
2867                 if (type != DBUS_TYPE_ARRAY)
2868                         return __connman_error_invalid_arguments(msg);
2869
2870                 str = g_string_new(NULL);
2871                 if (str == NULL)
2872                         return __connman_error_invalid_arguments(msg);
2873
2874                 index = connman_network_get_index(service->network);
2875                 gw = __connman_ipconfig_get_gateway_from_index(index);
2876
2877                 if (gw && strlen(gw))
2878                         __connman_service_nameserver_del_routes(service,
2879                                                 CONNMAN_IPCONFIG_TYPE_ALL);
2880
2881                 dbus_message_iter_recurse(&value, &entry);
2882
2883                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
2884                         const char *val;
2885                         dbus_message_iter_get_basic(&entry, &val);
2886                         dbus_message_iter_next(&entry);
2887                         if (str->len > 0)
2888                                 g_string_append_printf(str, " %s", val);
2889                         else
2890                                 g_string_append(str, val);
2891                 }
2892
2893                 g_strfreev(service->nameservers_config);
2894
2895                 if (str->len > 0) {
2896                         service->nameservers_config =
2897                                 g_strsplit_set(str->str, " ", 0);
2898                 } else {
2899                         service->nameservers_config = NULL;
2900                 }
2901
2902                 g_string_free(str, TRUE);
2903
2904                 if (gw && strlen(gw))
2905                         __connman_service_nameserver_add_routes(service, gw);
2906
2907                 update_nameservers(service);
2908                 dns_configuration_changed(service);
2909
2910                 service_save(service);
2911         } else if (g_str_equal(name, "Timeservers.Configuration") == TRUE) {
2912                 DBusMessageIter entry;
2913                 GSList *list = NULL;
2914                 int count = 0;
2915
2916                 if (type != DBUS_TYPE_ARRAY)
2917                         return __connman_error_invalid_arguments(msg);
2918
2919                 dbus_message_iter_recurse(&value, &entry);
2920
2921                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
2922                         const char *val;
2923                         dbus_message_iter_get_basic(&entry, &val);
2924
2925                         list = g_slist_prepend(list, strdup(val));
2926                         count++;
2927
2928                         dbus_message_iter_next(&entry);
2929                 }
2930
2931                 g_strfreev(service->timeservers_config);
2932                 service->timeservers_config = NULL;
2933
2934                 if (list != NULL) {
2935                         service->timeservers_config = g_new0(char *, count+1);
2936
2937                         while (list != NULL) {
2938                                 count--;
2939                                 service->timeservers_config[count] = list->data;
2940                                 list = g_slist_delete_link(list, list);
2941                         };
2942                 }
2943
2944                 service_save(service);
2945                 timeservers_configuration_changed(service);
2946
2947                 __connman_timeserver_sync(service);
2948         } else if (g_str_equal(name, "Domains.Configuration") == TRUE) {
2949                 DBusMessageIter entry;
2950                 GString *str;
2951
2952                 if (type != DBUS_TYPE_ARRAY)
2953                         return __connman_error_invalid_arguments(msg);
2954
2955                 str = g_string_new(NULL);
2956                 if (str == NULL)
2957                         return __connman_error_invalid_arguments(msg);
2958
2959                 dbus_message_iter_recurse(&value, &entry);
2960
2961                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
2962                         const char *val;
2963                         dbus_message_iter_get_basic(&entry, &val);
2964                         dbus_message_iter_next(&entry);
2965                         if (str->len > 0)
2966                                 g_string_append_printf(str, " %s", val);
2967                         else
2968                                 g_string_append(str, val);
2969                 }
2970
2971                 g_strfreev(service->domains);
2972
2973                 if (str->len > 0)
2974                         service->domains = g_strsplit_set(str->str, " ", 0);
2975                 else
2976                         service->domains = NULL;
2977
2978                 g_string_free(str, TRUE);
2979
2980                 update_nameservers(service);
2981                 domain_configuration_changed(service);
2982
2983                 service_save(service);
2984         } else if (g_str_equal(name, "Proxy.Configuration") == TRUE) {
2985                 int err;
2986
2987                 if (type != DBUS_TYPE_ARRAY)
2988                         return __connman_error_invalid_arguments(msg);
2989
2990                 err = update_proxy_configuration(service, &value);
2991
2992                 if (err < 0)
2993                         return __connman_error_failed(msg, -err);
2994
2995                 proxy_configuration_changed(service);
2996
2997                 __connman_notifier_proxy_changed(service);
2998
2999                 service_save(service);
3000         } else if (g_str_equal(name, "IPv4.Configuration") == TRUE ||
3001                         g_str_equal(name, "IPv6.Configuration")) {
3002
3003                 struct connman_ipconfig *ipv4 = NULL, *ipv6 = NULL;
3004                 enum connman_service_state state =
3005                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
3006                 int err = 0;
3007
3008                 DBG("%s", name);
3009
3010                 if (service->ipconfig_ipv4 == NULL &&
3011                                         service->ipconfig_ipv6 == NULL)
3012                         return __connman_error_invalid_property(msg);
3013
3014                 if (g_str_equal(name, "IPv4.Configuration") == TRUE) {
3015                         ipv4 = service->ipconfig_ipv4;
3016                         err = set_ipconfig(service, ipv4, &value,
3017                                         service->state_ipv4, &state);
3018
3019                 } else if (g_str_equal(name, "IPv6.Configuration") == TRUE) {
3020                         ipv6 = service->ipconfig_ipv6;
3021                         err = set_ipconfig(service, ipv6, &value,
3022                                         service->state_ipv6, &state);
3023                 }
3024
3025                 if (err < 0) {
3026                         if (is_connected_state(service, state) ||
3027                                         is_connecting_state(service, state))
3028                                 __connman_network_set_ipconfig(service->network,
3029                                                                 ipv4, ipv6);
3030                         return __connman_error_failed(msg, -err);
3031                 }
3032
3033                 if (ipv4)
3034                         ipv4_configuration_changed(service);
3035                 else if (ipv6)
3036                         ipv6_configuration_changed(service);
3037
3038                 if (is_connecting(service) || is_connected(service))
3039                         __connman_network_set_ipconfig(service->network,
3040                                                         ipv4, ipv6);
3041
3042                 service_save(service);
3043         } else
3044                 return __connman_error_invalid_property(msg);
3045
3046         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3047 }
3048
3049 static void set_idle(struct connman_service *service)
3050 {
3051         service->state = service->state_ipv4 = service->state_ipv6 =
3052                                                 CONNMAN_SERVICE_STATE_IDLE;
3053         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
3054         state_changed(service);
3055 }
3056
3057 static DBusMessage *clear_property(DBusConnection *conn,
3058                                         DBusMessage *msg, void *user_data)
3059 {
3060         struct connman_service *service = user_data;
3061         const char *name;
3062
3063         DBG("service %p", service);
3064
3065         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
3066                                                         DBUS_TYPE_INVALID);
3067
3068         if (g_str_equal(name, "Error") == TRUE) {
3069                 set_idle(service);
3070
3071                 g_get_current_time(&service->modified);
3072                 service_save(service);
3073         } else
3074                 return __connman_error_invalid_property(msg);
3075
3076         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3077 }
3078
3079 static connman_bool_t is_ignore(struct connman_service *service)
3080 {
3081         if (service->autoconnect == FALSE)
3082                 return TRUE;
3083
3084         if (service->roaming == TRUE)
3085                 return TRUE;
3086
3087         if (service->ignore == TRUE)
3088                 return TRUE;
3089
3090         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
3091                 return TRUE;
3092
3093         return FALSE;
3094 }
3095
3096 struct preferred_tech_data {
3097         GSequence *preferred_list;
3098         enum connman_service_type type;
3099 };
3100
3101 static void preferred_tech_add_by_type(gpointer data, gpointer user_data)
3102 {
3103         struct connman_service *service = data;
3104         struct preferred_tech_data *tech_data = user_data;
3105
3106         if (service->type == tech_data->type) {
3107                 g_sequence_append(tech_data->preferred_list, service);
3108
3109                 DBG("type %d service %p %s", tech_data->type, service,
3110                                 service->name);
3111         }
3112 }
3113
3114 static GSequence* preferred_tech_list_get(GSequence *list)
3115 {
3116         unsigned int *tech_array;
3117         struct preferred_tech_data tech_data;
3118         int i;
3119
3120         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
3121         if (tech_array == NULL)
3122                 return NULL;
3123
3124         tech_data.preferred_list = g_sequence_new(NULL);
3125
3126         for (i = 0; tech_array[i] != 0; i += 1) {
3127                 tech_data.type = tech_array[i];
3128                 g_sequence_foreach(service_list, preferred_tech_add_by_type,
3129                                 &tech_data);
3130         }
3131
3132         return tech_data.preferred_list;
3133 }
3134
3135 static connman_bool_t auto_connect_service(GSequenceIter* iter,
3136                 connman_bool_t preferred)
3137 {
3138         struct connman_service *service = NULL;
3139
3140         while (g_sequence_iter_is_end(iter) == FALSE) {
3141                 service = g_sequence_get(iter);
3142
3143                 if (service->pending != NULL)
3144                         return TRUE;
3145
3146                 if (is_connecting(service) == TRUE)
3147                         return TRUE;
3148
3149                 if (service->favorite == FALSE) {
3150                         if (preferred == TRUE)
3151                                 goto next_service;
3152                         return FALSE;
3153                 }
3154
3155                 if (is_connected(service) == TRUE) {
3156                         if (preferred == TRUE && service->state !=
3157                                         CONNMAN_SERVICE_STATE_ONLINE)
3158                                 goto next_service;
3159                         return TRUE;
3160                 }
3161
3162                 if (is_ignore(service) == FALSE && service->state ==
3163                                 CONNMAN_SERVICE_STATE_IDLE)
3164                         break;
3165
3166         next_service:
3167                 service = NULL;
3168
3169                 iter = g_sequence_iter_next(iter);
3170         }
3171
3172         if (service != NULL) {
3173
3174                 DBG("service %p %s %s", service, service->name,
3175                                 (preferred == TRUE)? "preferred": "auto");
3176
3177                 service->userconnect = FALSE;
3178                 __connman_service_connect(service);
3179                 return TRUE;
3180         }
3181         return FALSE;
3182 }
3183
3184 static gboolean run_auto_connect(gpointer data)
3185 {
3186         GSequenceIter *iter = NULL;
3187         GSequence *preferred_tech;
3188
3189         autoconnect_timeout = 0;
3190
3191         DBG("");
3192
3193         preferred_tech = preferred_tech_list_get(service_list);
3194         if (preferred_tech != NULL)
3195                 iter = g_sequence_get_begin_iter(preferred_tech);
3196
3197         if (iter == NULL || auto_connect_service(iter, TRUE) == FALSE)
3198                 iter = g_sequence_get_begin_iter(service_list);
3199
3200         if (iter != NULL)
3201                 auto_connect_service(iter, FALSE);
3202
3203         if (preferred_tech != NULL)
3204                 g_sequence_free(preferred_tech);
3205
3206         return FALSE;
3207 }
3208
3209 void __connman_service_auto_connect(void)
3210 {
3211         DBG("");
3212
3213         if (__connman_session_mode() == TRUE) {
3214                 DBG("Session mode enabled: auto connect disabled");
3215                 return;
3216         }
3217
3218         if (autoconnect_timeout != 0)
3219                 return;
3220
3221         autoconnect_timeout = g_timeout_add_seconds(0, run_auto_connect, NULL);
3222 }
3223
3224 static void remove_timeout(struct connman_service *service)
3225 {
3226         if (service->timeout > 0) {
3227                 g_source_remove(service->timeout);
3228                 service->timeout = 0;
3229         }
3230 }
3231
3232 static void reply_pending(struct connman_service *service, int error)
3233 {
3234         remove_timeout(service);
3235
3236         if (service->pending != NULL) {
3237                 if (error > 0) {
3238                         DBusMessage *reply;
3239
3240                         reply = __connman_error_failed(service->pending,
3241                                                                 error);
3242                         if (reply != NULL)
3243                                 g_dbus_send_message(connection, reply);
3244                 } else {
3245                         const char *sender;
3246
3247                         sender = dbus_message_get_interface(service->pending);
3248
3249                         DBG("sender %s", sender);
3250
3251                         if (g_strcmp0(sender, CONNMAN_MANAGER_INTERFACE) == 0)
3252                                 g_dbus_send_reply(connection, service->pending,
3253                                         DBUS_TYPE_OBJECT_PATH, &service->path,
3254                                                         DBUS_TYPE_INVALID);
3255                         else
3256                                 g_dbus_send_reply(connection, service->pending,
3257                                                         DBUS_TYPE_INVALID);
3258                 }
3259
3260                 dbus_message_unref(service->pending);
3261                 service->pending = NULL;
3262         }
3263 }
3264
3265 static gboolean connect_timeout(gpointer user_data)
3266 {
3267         struct connman_service *service = user_data;
3268         connman_bool_t autoconnect = FALSE;
3269
3270         DBG("service %p", service);
3271
3272         service->timeout = 0;
3273
3274         if (service->network != NULL)
3275                 __connman_network_disconnect(service->network);
3276
3277         __connman_ipconfig_disable(service->ipconfig_ipv4);
3278         __connman_ipconfig_disable(service->ipconfig_ipv6);
3279
3280         __connman_stats_service_unregister(service);
3281
3282         if (service->pending != NULL) {
3283                 DBusMessage *reply;
3284
3285                 reply = __connman_error_operation_timeout(service->pending);
3286                 if (reply != NULL)
3287                         g_dbus_send_message(connection, reply);
3288
3289                 dbus_message_unref(service->pending);
3290                 service->pending = NULL;
3291         } else
3292                 autoconnect = TRUE;
3293
3294         __connman_service_ipconfig_indicate_state(service,
3295                                         CONNMAN_SERVICE_STATE_FAILURE,
3296                                         CONNMAN_IPCONFIG_TYPE_IPV4);
3297         __connman_service_ipconfig_indicate_state(service,
3298                                         CONNMAN_SERVICE_STATE_FAILURE,
3299                                         CONNMAN_IPCONFIG_TYPE_IPV6);
3300
3301         if (autoconnect == TRUE && service->userconnect == FALSE)
3302                 __connman_service_auto_connect();
3303
3304         return FALSE;
3305 }
3306
3307 static void set_reconnect_state(struct connman_service *service,
3308                                                 connman_bool_t reconnect)
3309 {
3310         struct connman_device *device;
3311
3312         if (service->network == NULL)
3313                 return;
3314
3315         device = connman_network_get_device(service->network);
3316         if (device == NULL)
3317                 return;
3318
3319         __connman_device_set_reconnect(device, reconnect);
3320 }
3321
3322 static connman_bool_t get_reconnect_state(struct connman_service *service)
3323 {
3324         struct connman_device *device;
3325
3326         if (service->network == NULL)
3327                 return FALSE;
3328
3329         device = connman_network_get_device(service->network);
3330         if (device == NULL)
3331                 return FALSE;
3332
3333         return __connman_device_get_reconnect(device);
3334 }
3335
3336 static DBusMessage *connect_service(DBusConnection *conn,
3337                                         DBusMessage *msg, void *user_data)
3338 {
3339         struct connman_service *service = user_data;
3340         GSequenceIter *iter;
3341         int err;
3342
3343         DBG("service %p", service);
3344
3345         if (service->pending != NULL)
3346                 return __connman_error_in_progress(msg);
3347
3348         iter = g_sequence_get_begin_iter(service_list);
3349
3350         while (g_sequence_iter_is_end(iter) == FALSE) {
3351                 struct connman_service *temp = g_sequence_get(iter);
3352
3353                 if (service->type == temp->type && is_connecting(temp) == TRUE)
3354                         return __connman_error_in_progress(msg);
3355
3356                 iter = g_sequence_iter_next(iter);
3357         }
3358
3359         service->ignore = FALSE;
3360
3361         service->userconnect = TRUE;
3362
3363         service->pending = dbus_message_ref(msg);
3364
3365         set_reconnect_state(service, FALSE);
3366
3367         err = __connman_service_connect(service);
3368         if (err < 0) {
3369                 if (service->pending == NULL)
3370                         return NULL;
3371
3372                 if (err != -EINPROGRESS) {
3373                         dbus_message_unref(service->pending);
3374                         service->pending = NULL;
3375
3376                         return __connman_error_failed(msg, -err);
3377                 }
3378
3379                 return NULL;
3380         }
3381
3382         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3383 }
3384
3385 static DBusMessage *disconnect_service(DBusConnection *conn,
3386                                         DBusMessage *msg, void *user_data)
3387 {
3388         struct connman_service *service = user_data;
3389         int err;
3390
3391         DBG("service %p", service);
3392
3393         reply_pending(service, ECONNABORTED);
3394
3395         service->ignore = TRUE;
3396
3397         set_reconnect_state(service, FALSE);
3398
3399         err = __connman_service_disconnect(service);
3400         if (err < 0) {
3401                 if (err != -EINPROGRESS)
3402                         return __connman_error_failed(msg, -err);
3403
3404                 return NULL;
3405         }
3406
3407         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3408 }
3409
3410 static DBusMessage *remove_service(DBusConnection *conn,
3411                                         DBusMessage *msg, void *user_data)
3412 {
3413         struct connman_service *service = user_data;
3414
3415         DBG("service %p", service);
3416
3417         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
3418                 return __connman_error_not_supported(msg);
3419
3420         if (service->immutable == TRUE || service->hidden == TRUE)
3421                 return __connman_error_not_supported(msg);
3422
3423         if (service->favorite == FALSE && service->state !=
3424                                                 CONNMAN_SERVICE_STATE_FAILURE)
3425                 return __connman_error_not_supported(msg);
3426
3427         set_reconnect_state(service, FALSE);
3428
3429         __connman_service_disconnect(service);
3430
3431         g_free(service->passphrase);
3432         service->passphrase = NULL;
3433
3434         set_idle(service);
3435
3436         __connman_service_set_favorite(service, FALSE);
3437         service_save(service);
3438
3439         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3440 }
3441
3442 static gboolean check_suitable_state(enum connman_service_state a,
3443                                         enum connman_service_state b)
3444 {
3445         /*
3446          * Special check so that "ready" service can be moved before
3447          * "online" one.
3448          */
3449         if ((a == CONNMAN_SERVICE_STATE_ONLINE &&
3450                         b == CONNMAN_SERVICE_STATE_READY) ||
3451                 (b == CONNMAN_SERVICE_STATE_ONLINE &&
3452                         a == CONNMAN_SERVICE_STATE_READY))
3453                 return TRUE;
3454
3455         return a == b;
3456 }
3457
3458 static void downgrade_state(struct connman_service *service)
3459 {
3460         if (service == NULL)
3461                 return;
3462
3463         DBG("service %p state4 %d state6 %d", service, service->state_ipv4,
3464                                                 service->state_ipv6);
3465
3466         if (service->state_ipv4 == CONNMAN_SERVICE_STATE_ONLINE)
3467                 __connman_service_ipconfig_indicate_state(service,
3468                                                 CONNMAN_SERVICE_STATE_READY,
3469                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
3470
3471         if (service->state_ipv6 == CONNMAN_SERVICE_STATE_ONLINE)
3472                 __connman_service_ipconfig_indicate_state(service,
3473                                                 CONNMAN_SERVICE_STATE_READY,
3474                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
3475 }
3476
3477 static void apply_relevant_default_downgrade(struct connman_service *service)
3478 {
3479         struct connman_service *def_service;
3480
3481         def_service = __connman_service_get_default();
3482         if (def_service == NULL)
3483                 return;
3484
3485         if (def_service == service &&
3486                         def_service->state == CONNMAN_SERVICE_STATE_ONLINE)
3487                 def_service->state = CONNMAN_SERVICE_STATE_READY;
3488 }
3489
3490 static void switch_default_service(struct connman_service *default_service,
3491                 struct connman_service *downgrade_service)
3492 {
3493         GSequenceIter *src, *dst;
3494
3495         apply_relevant_default_downgrade(default_service);
3496         src = g_hash_table_lookup(service_hash, downgrade_service->identifier);
3497         dst = g_hash_table_lookup(service_hash, default_service->identifier);
3498         g_sequence_move(src, dst);
3499         downgrade_state(downgrade_service);
3500 }
3501
3502 static DBusMessage *move_service(DBusConnection *conn,
3503                                         DBusMessage *msg, void *user_data,
3504                                                                 gboolean before)
3505 {
3506         struct connman_service *service = user_data;
3507         struct connman_service *target;
3508         const char *path;
3509         enum connman_ipconfig_method target4, target6;
3510         enum connman_ipconfig_method service4, service6;
3511
3512         DBG("service %p", service);
3513
3514         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
3515                                                         DBUS_TYPE_INVALID);
3516
3517         if (service->favorite == FALSE)
3518                 return __connman_error_not_supported(msg);
3519
3520         target = find_service(path);
3521         if (target == NULL || target->favorite == FALSE || target == service)
3522                 return __connman_error_invalid_service(msg);
3523
3524         if (target->type == CONNMAN_SERVICE_TYPE_VPN) {
3525                 /*
3526                  * We only allow VPN route splitting if there are
3527                  * routes defined for a given VPN.
3528                  */
3529                 if (__connman_provider_check_routes(target->provider)
3530                                                                 == FALSE) {
3531                         connman_info("Cannot move service. "
3532                                 "No routes defined for provider %s",
3533                                 __connman_provider_get_ident(target->provider));
3534                         return __connman_error_invalid_service(msg);
3535                 }
3536
3537                 target->do_split_routing = TRUE;
3538         } else
3539                 target->do_split_routing = FALSE;
3540
3541         service->do_split_routing = FALSE;
3542
3543         target4 = __connman_ipconfig_get_method(target->ipconfig_ipv4);
3544         target6 = __connman_ipconfig_get_method(target->ipconfig_ipv6);
3545         service4 = __connman_ipconfig_get_method(service->ipconfig_ipv4);
3546         service6 = __connman_ipconfig_get_method(service->ipconfig_ipv6);
3547
3548         DBG("target %s method %d/%d state %d/%d split %d", target->identifier,
3549                 target4, target6, target->state_ipv4, target->state_ipv6,
3550                 target->do_split_routing);
3551
3552         DBG("service %s method %d/%d state %d/%d", service->identifier,
3553                                 service4, service6,
3554                                 service->state_ipv4, service->state_ipv6);
3555
3556         /*
3557          * If method is OFF, then we do not need to check the corresponding
3558          * ipconfig state.
3559          */
3560         if (target4 == CONNMAN_IPCONFIG_METHOD_OFF) {
3561                 if (service6 != CONNMAN_IPCONFIG_METHOD_OFF) {
3562                         if (check_suitable_state(target->state_ipv6,
3563                                                 service->state_ipv6) == FALSE)
3564                                 return __connman_error_invalid_service(msg);
3565                 }
3566         }
3567
3568         if (target6 == CONNMAN_IPCONFIG_METHOD_OFF) {
3569                 if (service4 != CONNMAN_IPCONFIG_METHOD_OFF) {
3570                         if (check_suitable_state(target->state_ipv4,
3571                                                 service->state_ipv4) == FALSE)
3572                                 return __connman_error_invalid_service(msg);
3573                 }
3574         }
3575
3576         if (service4 == CONNMAN_IPCONFIG_METHOD_OFF) {
3577                 if (target6 != CONNMAN_IPCONFIG_METHOD_OFF) {
3578                         if (check_suitable_state(target->state_ipv6,
3579                                                 service->state_ipv6) == FALSE)
3580                                 return __connman_error_invalid_service(msg);
3581                 }
3582         }
3583
3584         if (service6 == CONNMAN_IPCONFIG_METHOD_OFF) {
3585                 if (target4 != CONNMAN_IPCONFIG_METHOD_OFF) {
3586                         if (check_suitable_state(target->state_ipv4,
3587                                                 service->state_ipv4) == FALSE)
3588                                 return __connman_error_invalid_service(msg);
3589                 }
3590         }
3591
3592         g_get_current_time(&service->modified);
3593         service_save(service);
3594         service_save(target);
3595
3596         /*
3597          * If the service which goes down is the default service and is
3598          * online, we downgrade directly its state to ready so:
3599          * the service which goes up, needs to recompute its state which
3600          * is triggered via downgrading it - if relevant - to state ready.
3601          */
3602         if (before == TRUE)
3603                 switch_default_service(target, service);
3604         else
3605                 switch_default_service(service, target);
3606
3607         __connman_connection_update_gateway();
3608
3609         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3610 }
3611
3612 static DBusMessage *move_before(DBusConnection *conn,
3613                                         DBusMessage *msg, void *user_data)
3614 {
3615         return move_service(conn, msg, user_data, TRUE);
3616 }
3617
3618 static DBusMessage *move_after(DBusConnection *conn,
3619                                         DBusMessage *msg, void *user_data)
3620 {
3621         return move_service(conn, msg, user_data, FALSE);
3622 }
3623
3624 static DBusMessage *reset_counters(DBusConnection *conn,
3625                                         DBusMessage *msg, void *user_data)
3626 {
3627         struct connman_service *service = user_data;
3628
3629         reset_stats(service);
3630
3631         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
3632 }
3633
3634 static struct _services_notify {
3635         int id;
3636         GHashTable *add;
3637         GHashTable *remove;
3638 } *services_notify;
3639
3640 static void service_append_added_foreach(gpointer data, gpointer user_data)
3641 {
3642         struct connman_service *service = data;
3643         DBusMessageIter *iter = user_data;
3644
3645         if (service == NULL || service->path == NULL) {
3646                 DBG("service %p or path is NULL", service);
3647                 return;
3648         }
3649
3650         if (g_hash_table_lookup(services_notify->add, service->path) != NULL) {
3651                 DBG("new %s", service->path);
3652
3653                 append_struct(service, iter);
3654                 g_hash_table_remove(services_notify->add, service->path);
3655         } else {
3656                 DBG("changed %s", service->path);
3657
3658                 append_struct_service(iter, NULL, service);
3659         }
3660 }
3661
3662 static void service_append_ordered(DBusMessageIter *iter, void *user_data)
3663 {
3664         if (service_list != NULL)
3665                 g_sequence_foreach(service_list,
3666                                         service_append_added_foreach, iter);
3667 }
3668
3669 static void append_removed(gpointer key, gpointer value, gpointer user_data)
3670 {
3671         char *objpath = key;
3672         DBusMessageIter *iter = user_data;
3673
3674         DBG("removed %s", objpath);
3675         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &objpath);
3676 }
3677
3678 static gboolean service_send_changed(gpointer data)
3679 {
3680         DBusMessage *signal;
3681         DBusMessageIter iter, array;
3682
3683         DBG("");
3684
3685         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
3686                         CONNMAN_MANAGER_INTERFACE, "ServicesChanged");
3687         if (signal == NULL)
3688                 return FALSE;
3689
3690         __connman_dbus_append_objpath_dict_array(signal,
3691                         service_append_ordered, NULL);
3692
3693         dbus_message_iter_init_append(signal, &iter);
3694         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
3695                         DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
3696
3697         g_hash_table_foreach(services_notify->remove, append_removed, &array);
3698
3699         dbus_message_iter_close_container(&iter, &array);
3700
3701         dbus_connection_send(connection, signal, NULL);
3702         dbus_message_unref(signal);
3703
3704         g_hash_table_remove_all(services_notify->remove);
3705         g_hash_table_remove_all(services_notify->add);
3706
3707         services_notify->id = 0;
3708         return FALSE;
3709 }
3710
3711 static void service_schedule_changed(void)
3712 {
3713         if (services_notify->id != 0)
3714                 return;
3715
3716         services_notify->id = g_timeout_add(100, service_send_changed, NULL);
3717 }
3718
3719 static void service_schedule_added(struct connman_service *service)
3720 {
3721         DBG("service %p", service);
3722
3723         g_hash_table_remove(services_notify->remove, service->path);
3724         g_hash_table_replace(services_notify->add, service->path, service);
3725
3726         service_schedule_changed();
3727 }
3728
3729 static void service_schedule_removed(struct connman_service *service)
3730 {
3731         DBG("service %p %s", service, service->path);
3732
3733         if (service == NULL || service->path == NULL) {
3734                 DBG("service %p or path is NULL", service);
3735                 return;
3736         }
3737
3738         g_hash_table_remove(services_notify->add, service->path);
3739         g_hash_table_replace(services_notify->remove, g_strdup(service->path),
3740                         NULL);
3741
3742         service_schedule_changed();
3743 }
3744
3745 static GDBusMethodTable service_methods[] = {
3746         { "GetProperties", "",   "a{sv}", get_properties     },
3747         { "SetProperty",   "sv", "",      set_property       },
3748         { "ClearProperty", "s",  "",      clear_property     },
3749         { "Connect",       "",   "",      connect_service,
3750                                                 G_DBUS_METHOD_FLAG_ASYNC },
3751         { "Disconnect",    "",   "",      disconnect_service },
3752         { "Remove",        "",   "",      remove_service     },
3753         { "MoveBefore",    "o",  "",      move_before        },
3754         { "MoveAfter",     "o",  "",      move_after         },
3755         { "ResetCounters", "",   "",      reset_counters     },
3756         { },
3757 };
3758
3759 static GDBusSignalTable service_signals[] = {
3760         { "PropertyChanged", "sv" },
3761         { },
3762 };
3763
3764 static void service_free(gpointer user_data)
3765 {
3766         struct connman_service *service = user_data;
3767         char *path = service->path;
3768
3769         DBG("service %p", service);
3770
3771         reply_pending(service, ENOENT);
3772
3773         g_hash_table_remove(service_hash, service->identifier);
3774
3775         __connman_notifier_service_remove(service);
3776         service_schedule_removed(service);
3777
3778         stats_stop(service);
3779
3780         service->path = NULL;
3781
3782         if (path != NULL) {
3783                 __connman_connection_update_gateway();
3784
3785                 g_dbus_unregister_interface(connection, path,
3786                                                 CONNMAN_SERVICE_INTERFACE);
3787                 g_free(path);
3788         }
3789
3790         g_hash_table_destroy(service->counter_table);
3791
3792         if (service->network != NULL) {
3793                 __connman_network_disconnect(service->network);
3794                 connman_network_unref(service->network);
3795                 service->network = NULL;
3796         }
3797
3798         if (service->provider != NULL)
3799                 connman_provider_unref(service->provider);
3800
3801         if (service->ipconfig_ipv4 != NULL) {
3802                 __connman_ipconfig_set_ops(service->ipconfig_ipv4, NULL);
3803                 __connman_ipconfig_set_data(service->ipconfig_ipv4, NULL);
3804                 __connman_ipconfig_unref(service->ipconfig_ipv4);
3805                 service->ipconfig_ipv4 = NULL;
3806         }
3807
3808         if (service->ipconfig_ipv6 != NULL) {
3809                 __connman_ipconfig_set_ops(service->ipconfig_ipv6, NULL);
3810                 __connman_ipconfig_set_data(service->ipconfig_ipv6, NULL);
3811                 __connman_ipconfig_unref(service->ipconfig_ipv6);
3812                 service->ipconfig_ipv6 = NULL;
3813         }
3814
3815         g_strfreev(service->timeservers);
3816         g_strfreev(service->timeservers_config);
3817         g_strfreev(service->nameservers);
3818         g_strfreev(service->nameservers_config);
3819         g_strfreev(service->nameservers_auto);
3820         g_strfreev(service->domains);
3821         g_strfreev(service->proxies);
3822         g_strfreev(service->excludes);
3823
3824         g_free(service->domainname);
3825         g_free(service->pac);
3826         g_free(service->name);
3827         g_free(service->passphrase);
3828         g_free(service->agent_passphrase);
3829         g_free(service->identifier);
3830         g_free(service->eap);
3831         g_free(service->identity);
3832         g_free(service->agent_identity);
3833         g_free(service->ca_cert_file);
3834         g_free(service->client_cert_file);
3835         g_free(service->private_key_file);
3836         g_free(service->private_key_passphrase);
3837         g_free(service->phase2);
3838
3839         if (service->stats.timer != NULL)
3840                 g_timer_destroy(service->stats.timer);
3841         if (service->stats_roaming.timer != NULL)
3842                 g_timer_destroy(service->stats_roaming.timer);
3843
3844         g_free(service);
3845 }
3846
3847 static void stats_init(struct connman_service *service)
3848 {
3849         /* home */
3850         service->stats.valid = FALSE;
3851         service->stats.enabled = FALSE;
3852         service->stats.timer = g_timer_new();
3853
3854         /* roaming */
3855         service->stats_roaming.valid = FALSE;
3856         service->stats_roaming.enabled = FALSE;
3857         service->stats_roaming.timer = g_timer_new();
3858 }
3859
3860 static void service_initialize(struct connman_service *service)
3861 {
3862         DBG("service %p", service);
3863
3864         service->refcount = 1;
3865         service->session_usage_count = 0;
3866
3867         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
3868         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
3869
3870         service->state = CONNMAN_SERVICE_STATE_UNKNOWN;
3871         service->state_ipv4 = CONNMAN_SERVICE_STATE_UNKNOWN;
3872         service->state_ipv6 = CONNMAN_SERVICE_STATE_UNKNOWN;
3873
3874         service->favorite  = FALSE;
3875         service->immutable = FALSE;
3876         service->hidden = FALSE;
3877
3878         service->ignore = FALSE;
3879
3880         service->userconnect = FALSE;
3881
3882         service->order = 0;
3883
3884         stats_init(service);
3885
3886         service->provider = NULL;
3887
3888         service->wps = FALSE;
3889 }
3890
3891 /**
3892  * connman_service_create:
3893  *
3894  * Allocate a new service.
3895  *
3896  * Returns: a newly-allocated #connman_service structure
3897  */
3898 struct connman_service *connman_service_create(void)
3899 {
3900         GSList *list;
3901         struct connman_stats_counter *counters;
3902         const char *counter;
3903
3904         struct connman_service *service;
3905
3906         service = g_try_new0(struct connman_service, 1);
3907         if (service == NULL)
3908                 return NULL;
3909
3910         DBG("service %p", service);
3911
3912         service->counter_table = g_hash_table_new_full(g_str_hash,
3913                                                 g_str_equal, NULL, g_free);
3914
3915         for (list = counter_list; list; list = list->next) {
3916                 counter = list->data;
3917
3918                 counters = g_try_new0(struct connman_stats_counter, 1);
3919                 if (counters == NULL) {
3920                         g_hash_table_destroy(service->counter_table);
3921                         g_free(service);
3922                         return NULL;
3923                 }
3924
3925                 counters->append_all = TRUE;
3926
3927                 g_hash_table_replace(service->counter_table, (gpointer)counter,
3928                                 counters);
3929         }
3930
3931         service_initialize(service);
3932
3933         return service;
3934 }
3935
3936 /**
3937  * connman_service_ref:
3938  * @service: service structure
3939  *
3940  * Increase reference counter of service
3941  */
3942 struct connman_service *
3943 connman_service_ref_debug(struct connman_service *service,
3944                         const char *file, int line, const char *caller)
3945 {
3946         DBG("%p ref %d by %s:%d:%s()", service, service->refcount + 1,
3947                 file, line, caller);
3948
3949         __sync_fetch_and_add(&service->refcount, 1);
3950
3951         return service;
3952 }
3953
3954 /**
3955  * connman_service_unref:
3956  * @service: service structure
3957  *
3958  * Decrease reference counter of service and release service if no
3959  * longer needed.
3960  */
3961 void connman_service_unref_debug(struct connman_service *service,
3962                         const char *file, int line, const char *caller)
3963 {
3964         GSequenceIter *iter;
3965
3966         DBG("%p ref %d by %s:%d:%s()", service, service->refcount - 1,
3967                 file, line, caller);
3968
3969         if (__sync_fetch_and_sub(&service->refcount, 1) != 1)
3970                 return;
3971
3972         iter = g_hash_table_lookup(service_hash, service->identifier);
3973         if (iter != NULL) {
3974                 reply_pending(service, ECONNABORTED);
3975
3976                 __connman_service_disconnect(service);
3977
3978                 g_sequence_remove(iter);
3979         } else {
3980                 service_free(service);
3981         }
3982 }
3983
3984 static gint service_compare(gconstpointer a, gconstpointer b,
3985                                                         gpointer user_data)
3986 {
3987         struct connman_service *service_a = (void *) a;
3988         struct connman_service *service_b = (void *) b;
3989         enum connman_service_state state_a, state_b;
3990
3991         state_a = service_a->state;
3992         state_b = service_b->state;
3993
3994         if (state_a != state_b) {
3995                 gboolean a_connected = is_connected(service_a);
3996                 gboolean b_connected = is_connected(service_b);
3997
3998                 if (a_connected == TRUE && b_connected == TRUE) {
3999                         /* We prefer online over ready state */
4000                         if (state_a == CONNMAN_SERVICE_STATE_ONLINE)
4001                                 return -1;
4002
4003                         if (state_b == CONNMAN_SERVICE_STATE_ONLINE)
4004                                 return 1;
4005                 }
4006
4007                 if (a_connected == TRUE)
4008                         return -1;
4009                 if (b_connected == TRUE)
4010                         return 1;
4011
4012                 if (is_connecting(service_a) == TRUE)
4013                         return -1;
4014                 if (is_connecting(service_b) == TRUE)
4015                         return 1;
4016         }
4017
4018         if (service_a->order > service_b->order)
4019                 return -1;
4020
4021         if (service_a->order < service_b->order)
4022                 return 1;
4023
4024         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
4025                 return -1;
4026
4027         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
4028                 return 1;
4029
4030         if (service_a->type != service_b->type) {
4031                 switch (service_a->type) {
4032                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
4033                 case CONNMAN_SERVICE_TYPE_SYSTEM:
4034                 case CONNMAN_SERVICE_TYPE_ETHERNET:
4035                 case CONNMAN_SERVICE_TYPE_GPS:
4036                 case CONNMAN_SERVICE_TYPE_VPN:
4037                 case CONNMAN_SERVICE_TYPE_GADGET:
4038                         break;
4039                 case CONNMAN_SERVICE_TYPE_WIFI:
4040                         return 1;
4041                 case CONNMAN_SERVICE_TYPE_WIMAX:
4042                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
4043                 case CONNMAN_SERVICE_TYPE_CELLULAR:
4044                         return -1;
4045                 }
4046         }
4047
4048         return (gint) service_b->strength - (gint) service_a->strength;
4049 }
4050
4051 /**
4052  * connman_service_get_type:
4053  * @service: service structure
4054  *
4055  * Get the type of service
4056  */
4057 enum connman_service_type connman_service_get_type(struct connman_service *service)
4058 {
4059         if (service == NULL)
4060                 return CONNMAN_SERVICE_TYPE_UNKNOWN;
4061
4062         return service->type;
4063 }
4064
4065 /**
4066  * connman_service_get_interface:
4067  * @service: service structure
4068  *
4069  * Get network interface of service
4070  */
4071 char *connman_service_get_interface(struct connman_service *service)
4072 {
4073         int index;
4074
4075         if (service == NULL)
4076                 return NULL;
4077
4078         if (service->type == CONNMAN_SERVICE_TYPE_VPN) {
4079                 if (service->ipconfig_ipv4)
4080                         index = __connman_ipconfig_get_index(
4081                                                 service->ipconfig_ipv4);
4082                 else if (service->ipconfig_ipv6)
4083                         index = __connman_ipconfig_get_index(
4084                                                 service->ipconfig_ipv6);
4085                 else
4086                         return NULL;
4087
4088                 return connman_inet_ifname(index);
4089         }
4090
4091         if (service->network == NULL)
4092                 return NULL;
4093
4094         index = connman_network_get_index(service->network);
4095
4096         return connman_inet_ifname(index);
4097 }
4098
4099 /**
4100  * connman_service_get_network:
4101  * @service: service structure
4102  *
4103  * Get the service network
4104  */
4105 struct connman_network *
4106 __connman_service_get_network(struct connman_service *service)
4107 {
4108         if (service == NULL)
4109                 return NULL;
4110
4111         return service->network;
4112 }
4113
4114 struct connman_ipconfig *
4115 __connman_service_get_ip4config(struct connman_service *service)
4116 {
4117         if (service == NULL)
4118                 return NULL;
4119
4120         return service->ipconfig_ipv4;
4121 }
4122
4123 struct connman_ipconfig *
4124 __connman_service_get_ip6config(struct connman_service *service)
4125 {
4126         if (service == NULL)
4127                 return NULL;
4128
4129         return service->ipconfig_ipv6;
4130 }
4131
4132 struct connman_ipconfig *
4133 __connman_service_get_ipconfig(struct connman_service *service, int family)
4134 {
4135         if (family == AF_INET)
4136                 return __connman_service_get_ip4config(service);
4137         else if (family == AF_INET6)
4138                 return __connman_service_get_ip6config(service);
4139         else
4140                 return NULL;
4141
4142 }
4143
4144 connman_bool_t __connman_service_is_connected_state(struct connman_service *service,
4145                                         enum connman_ipconfig_type type)
4146 {
4147         if (service == NULL)
4148                 return FALSE;
4149
4150         switch (type) {
4151         case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
4152                 break;
4153         case CONNMAN_IPCONFIG_TYPE_IPV4:
4154                 return is_connected_state(service, service->state_ipv4);
4155         case CONNMAN_IPCONFIG_TYPE_IPV6:
4156                 return is_connected_state(service, service->state_ipv6);
4157         }
4158
4159         return FALSE;
4160 }
4161 enum connman_service_security __connman_service_get_security(struct connman_service *service)
4162 {
4163         if (service == NULL)
4164                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
4165
4166         return service->security;
4167 }
4168
4169 const char *__connman_service_get_phase2(struct connman_service *service)
4170 {
4171         if (service == NULL)
4172                 return NULL;
4173
4174         return service->phase2;
4175 }
4176
4177 connman_bool_t __connman_service_wps_enabled(struct connman_service *service)
4178 {
4179         if (service == NULL)
4180                 return FALSE;
4181
4182         return service->wps;
4183 }
4184
4185 /**
4186  * __connman_service_set_favorite:
4187  * @service: service structure
4188  * @favorite: favorite value
4189  *
4190  * Change the favorite setting of service
4191  */
4192 int __connman_service_set_favorite(struct connman_service *service,
4193                                                 connman_bool_t favorite)
4194 {
4195         GSequenceIter *iter;
4196
4197         if (service->hidden == TRUE)
4198                 return -EOPNOTSUPP;
4199         iter = g_hash_table_lookup(service_hash, service->identifier);
4200         if (iter == NULL)
4201                 return -ENOENT;
4202
4203         if (service->favorite == favorite)
4204                 return -EALREADY;
4205
4206         service->favorite = favorite;
4207         service->order = __connman_service_get_order(service);
4208
4209         favorite_changed(service);
4210
4211         g_sequence_sort_changed(iter, service_compare, NULL);
4212         service_schedule_changed();
4213
4214         __connman_connection_update_gateway();
4215
4216         return 0;
4217 }
4218
4219 int __connman_service_set_immutable(struct connman_service *service,
4220                                                 connman_bool_t immutable)
4221 {
4222         if (service->hidden == TRUE)
4223                 return -EOPNOTSUPP;
4224         service->immutable = immutable;
4225
4226         immutable_changed(service);
4227
4228         return 0;
4229 }
4230
4231 void __connman_service_set_string(struct connman_service *service,
4232                                   const char *key, const char *value)
4233 {
4234         if (service->hidden == TRUE)
4235                 return;
4236         if (g_str_equal(key, "EAP") == TRUE) {
4237                 g_free(service->eap);
4238                 service->eap = g_strdup(value);
4239         } else if (g_str_equal(key, "Identity") == TRUE) {
4240                 g_free(service->identity);
4241                 service->identity = g_strdup(value);
4242         } else if (g_str_equal(key, "CACertFile") == TRUE) {
4243                 g_free(service->ca_cert_file);
4244                 service->ca_cert_file = g_strdup(value);
4245         } else if (g_str_equal(key, "ClientCertFile") == TRUE) {
4246                 g_free(service->client_cert_file);
4247                 service->client_cert_file = g_strdup(value);
4248         } else if (g_str_equal(key, "PrivateKeyFile") == TRUE) {
4249                 g_free(service->private_key_file);
4250                 service->private_key_file = g_strdup(value);
4251         } else if (g_str_equal(key, "PrivateKeyPassphrase") == TRUE) {
4252                 g_free(service->private_key_passphrase);
4253                 service->private_key_passphrase = g_strdup(value);
4254         } else if (g_str_equal(key, "Phase2") == TRUE) {
4255                 g_free(service->phase2);
4256                 service->phase2 = g_strdup(value);
4257         } else if (g_str_equal(key, "Passphrase") == TRUE) {
4258                 g_free(service->passphrase);
4259                 service->passphrase = g_strdup(value);
4260         }
4261 }
4262
4263 static void service_complete(struct connman_service *service)
4264 {
4265         reply_pending(service, EIO);
4266
4267         if (service->userconnect == FALSE)
4268                 __connman_service_auto_connect();
4269
4270         g_get_current_time(&service->modified);
4271         service_save(service);
4272 }
4273
4274 static void report_error_cb(struct connman_service *service,
4275                         gboolean retry, void *user_data)
4276 {
4277         if (retry == TRUE)
4278                 __connman_service_connect(service);
4279         else {
4280                 service_complete(service);
4281                 __connman_connection_update_gateway();
4282                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
4283         }
4284 }
4285
4286 int __connman_service_add_passphrase(struct connman_service *service,
4287                                 const gchar *passphrase)
4288 {
4289         int err = 0;
4290
4291         switch (service->security) {
4292         case CONNMAN_SERVICE_SECURITY_WEP:
4293         case CONNMAN_SERVICE_SECURITY_PSK:
4294                 err = __connman_service_set_passphrase(service, passphrase);
4295                 break;
4296         case CONNMAN_SERVICE_SECURITY_8021X:
4297                 __connman_service_set_agent_passphrase(service,
4298                                                 passphrase);
4299                 break;
4300         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
4301         case CONNMAN_SERVICE_SECURITY_NONE:
4302         case CONNMAN_SERVICE_SECURITY_WPA:
4303         case CONNMAN_SERVICE_SECURITY_RSN:
4304                 DBG("service security '%s' (%d) not handled",
4305                                 security2string(service->security),
4306                                 service->security);
4307                 break;
4308         }
4309
4310         return err;
4311 }
4312
4313 static int check_wpspin(const char *wpspin)
4314 {
4315         guint i;
4316
4317         if (wpspin == NULL)
4318                 return 0;
4319
4320         /* A WPS PIN is always 8 chars length,
4321          * its content is in digit representation.
4322          */
4323         if (strlen(wpspin) != 8)
4324                 return -ENOKEY;
4325
4326         for (i = 0; i < 8; i++)
4327                 if (!isdigit((unsigned char) wpspin[i]))
4328                         return -ENOKEY;
4329
4330         return 0;
4331 }
4332
4333 static void request_input_cb (struct connman_service *service,
4334                         connman_bool_t values_received,
4335                         const char *name, int name_len,
4336                         const char *identity, const char *passphrase,
4337                         gboolean wps, const char *wpspin,
4338                         void *user_data)
4339 {
4340         struct connman_device *device;
4341         int err = 0;
4342
4343         DBG ("RequestInput return, %p", service);
4344
4345         if (service->hidden == TRUE && name_len > 0 && name_len <= 32) {
4346                 device = connman_network_get_device(service->network);
4347                 __connman_device_request_hidden_scan(device,
4348                                                 name, name_len,
4349                                                 identity, passphrase);
4350         }
4351
4352         if (values_received == FALSE || service->hidden == TRUE) {
4353                 service_complete(service);
4354                 __connman_connection_update_gateway();
4355                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
4356                 return;
4357         }
4358
4359         err = check_wpspin(wpspin);
4360         if (err < 0)
4361                 goto done;
4362         if (service->network != NULL) {
4363                 connman_network_set_bool(service->network, "Wifi.UseWPS", wps);
4364                 connman_network_set_string(service->network, "Wifi.PinWPS",
4365                                                 wpspin);
4366         }
4367
4368         if (identity != NULL)
4369                 __connman_service_set_agent_identity(service, identity);
4370
4371         if (passphrase != NULL)
4372                 err = __connman_service_add_passphrase(service, passphrase);
4373
4374  done:
4375         if (err >= 0) {
4376                 __connman_service_connect(service);
4377
4378                 /* Never cache agent provided credentials */
4379                 __connman_service_set_agent_identity(service, NULL);
4380                 __connman_service_set_agent_passphrase(service, NULL);
4381         } else if (err == -ENOKEY) {
4382                 __connman_service_indicate_error(service,
4383                                         CONNMAN_SERVICE_ERROR_INVALID_KEY);
4384                 __connman_agent_report_error(service,
4385                                         error2string(service->error),
4386                                         report_error_cb, NULL);
4387         }
4388 }
4389
4390 static void downgrade_connected_services(void)
4391 {
4392         struct connman_service *up_service;
4393         GSequenceIter *iter;
4394
4395         iter = g_sequence_get_begin_iter(service_list);
4396         while (g_sequence_iter_is_end(iter) == FALSE) {
4397                 up_service = g_sequence_get(iter);
4398
4399                 if (is_connected(up_service) == FALSE) {
4400                         iter = g_sequence_iter_next(iter);
4401                         continue;
4402                 }
4403
4404                 if (up_service->state == CONNMAN_SERVICE_STATE_ONLINE)
4405                         return;
4406
4407                 downgrade_state(up_service);
4408
4409                 iter = g_sequence_iter_next(iter);
4410         }
4411 }
4412
4413 static int service_update_preferred_order(struct connman_service *default_service,
4414                 struct connman_service *new_service,
4415                 enum connman_service_state new_state)
4416 {
4417         unsigned int *tech_array;
4418         int i;
4419
4420         if (default_service == NULL || default_service == new_service ||
4421                         default_service->state != new_state )
4422                 return 0;
4423
4424         tech_array = connman_setting_get_uint_list("PreferredTechnologies");
4425         if (tech_array != NULL) {
4426
4427                 for (i = 0; tech_array[i] != 0; i += 1) {
4428                         if (default_service->type == tech_array[i])
4429                                 return -EALREADY;
4430
4431                         if (new_service->type == tech_array[i]) {
4432                                 switch_default_service(new_service,
4433                                                 default_service);
4434                                 return 0;
4435                         }
4436                 }
4437                 return -EAGAIN;
4438         }
4439
4440         return -EALREADY;
4441 }
4442
4443 static int service_indicate_state(struct connman_service *service)
4444 {
4445         enum connman_service_state old_state, new_state;
4446         struct connman_service *def_service;
4447         int result;
4448         GSequenceIter *iter;
4449
4450         if (service == NULL)
4451                 return -EINVAL;
4452
4453         old_state = service->state;
4454         new_state = combine_state(service->state_ipv4, service->state_ipv6);
4455
4456         DBG("service %p old %s - new %s/%s => %s",
4457                                         service,
4458                                         state2string(old_state),
4459                                         state2string(service->state_ipv4),
4460                                         state2string(service->state_ipv6),
4461                                         state2string(new_state));
4462
4463         if (old_state == new_state)
4464                 return -EALREADY;
4465
4466         def_service = __connman_service_get_default();
4467
4468         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
4469                 result = service_update_preferred_order(def_service,
4470                                 service, new_state);
4471                 if (result == -EALREADY)
4472                         return result;
4473                 if (result == -EAGAIN)
4474                         __connman_service_auto_connect();
4475         }
4476
4477         service->state = new_state;
4478         state_changed(service);
4479
4480         if (new_state == CONNMAN_SERVICE_STATE_IDLE &&
4481                         old_state != CONNMAN_SERVICE_STATE_DISCONNECT) {
4482                 reply_pending(service, ECONNABORTED);
4483
4484                 __connman_service_disconnect(service);
4485         }
4486
4487         if (new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) {
4488                 if (__connman_stats_service_register(service) == 0) {
4489                         __connman_stats_get(service, FALSE,
4490                                                 &service->stats.data);
4491                         __connman_stats_get(service, TRUE,
4492                                                 &service->stats_roaming.data);
4493                 }
4494         }
4495
4496         if (new_state == CONNMAN_SERVICE_STATE_IDLE) {
4497                 connman_bool_t reconnect;
4498
4499                 reconnect = get_reconnect_state(service);
4500                 if (reconnect == TRUE)
4501                         __connman_service_auto_connect();
4502
4503                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
4504         }
4505
4506         if (new_state == CONNMAN_SERVICE_STATE_READY) {
4507                 enum connman_ipconfig_method method;
4508
4509                 service_update_preferred_order(def_service, service, new_state);
4510
4511                 set_reconnect_state(service, TRUE);
4512
4513                 __connman_service_set_favorite(service, TRUE);
4514
4515                 reply_pending(service, 0);
4516
4517                 service->userconnect = FALSE;
4518
4519                 g_get_current_time(&service->modified);
4520                 service_save(service);
4521
4522                 update_nameservers(service);
4523                 dns_changed(service);
4524                 domain_changed(service);
4525
4526                 __connman_notifier_connect(service->type);
4527
4528                 if (service->type == CONNMAN_SERVICE_TYPE_WIFI &&
4529                         connman_network_get_bool(service->network,
4530                                                 "WiFi.UseWPS") == TRUE) {
4531                         const char *pass;
4532
4533                         pass = connman_network_get_string(service->network,
4534                                                         "WiFi.Passphrase");
4535
4536                         __connman_service_set_passphrase(service, pass);
4537
4538                         connman_network_set_bool(service->network,
4539                                                         "WiFi.UseWPS", FALSE);
4540                 }
4541
4542                 default_changed();
4543
4544                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
4545                 if (method == CONNMAN_IPCONFIG_METHOD_OFF)
4546                         __connman_ipconfig_disable_ipv6(
4547                                                 service->ipconfig_ipv6);
4548
4549         } else if (new_state == CONNMAN_SERVICE_STATE_DISCONNECT) {
4550                 def_service = __connman_service_get_default();
4551
4552                 if (__connman_notifier_is_connected() == FALSE &&
4553                         def_service != NULL &&
4554                                 def_service->provider != NULL)
4555                         __connman_provider_disconnect(def_service->provider);
4556
4557                 default_changed();
4558
4559                 __connman_wispr_stop(service);
4560
4561                 __connman_wpad_stop(service);
4562
4563                 update_nameservers(service);
4564                 dns_changed(service);
4565                 domain_changed(service);
4566
4567                 __connman_notifier_disconnect(service->type, old_state);
4568
4569                 /*
4570                  * Previous services which are connected and which states
4571                  * are set to online should reset relevantly ipconfig_state
4572                  * to ready so wispr/portal will be rerun on those
4573                  */
4574                 downgrade_connected_services();
4575         }
4576
4577         if (new_state == CONNMAN_SERVICE_STATE_FAILURE) {
4578                 if (service->userconnect == TRUE &&
4579                         __connman_agent_report_error(service,
4580                                         error2string(service->error),
4581                                         report_error_cb, NULL) == -EIO)
4582                         return 0;
4583                 service_complete(service);
4584
4585                 __connman_device_request_scan(CONNMAN_DEVICE_TYPE_UNKNOWN);
4586         } else
4587                 service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
4588
4589         iter = g_hash_table_lookup(service_hash, service->identifier);
4590         if (iter != NULL) {
4591                 g_sequence_sort_changed(iter, service_compare, NULL);
4592                 service_schedule_changed();
4593         }
4594
4595         __connman_connection_update_gateway();
4596
4597         if (new_state == CONNMAN_SERVICE_STATE_ONLINE) {
4598                 __connman_notifier_online(service->type);
4599                 default_changed();
4600         }
4601
4602         return 0;
4603 }
4604
4605 int __connman_service_indicate_error(struct connman_service *service,
4606                                         enum connman_service_error error)
4607 {
4608         DBG("service %p error %d", service, error);
4609
4610         if (service == NULL)
4611                 return -EINVAL;
4612
4613         service->error = error;
4614
4615         if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY)
4616                 __connman_service_set_passphrase(service, NULL);
4617
4618         __connman_service_ipconfig_indicate_state(service,
4619                                                 CONNMAN_SERVICE_STATE_FAILURE,
4620                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4621         __connman_service_ipconfig_indicate_state(service,
4622                                                 CONNMAN_SERVICE_STATE_FAILURE,
4623                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
4624         return 0;
4625 }
4626
4627 int __connman_service_clear_error(struct connman_service *service)
4628 {
4629         DBG("service %p", service);
4630
4631         if (service == NULL)
4632                 return -EINVAL;
4633
4634         if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
4635                 return -EINVAL;
4636
4637         service->state_ipv4 = service->state_ipv6 =
4638                                                 CONNMAN_SERVICE_STATE_UNKNOWN;
4639         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;;
4640
4641         if (service->favorite == TRUE)
4642                 set_reconnect_state(service, TRUE);
4643
4644         __connman_service_ipconfig_indicate_state(service,
4645                                         CONNMAN_SERVICE_STATE_IDLE,
4646                                         CONNMAN_IPCONFIG_TYPE_IPV6);
4647
4648         /*
4649          * Toggling the IPv6 state to IDLE could trigger the auto connect
4650          * machinery and consequently the IPv4 state.
4651          */
4652         if (service->state_ipv4 != CONNMAN_SERVICE_STATE_UNKNOWN &&
4653                         service->state_ipv4 != CONNMAN_SERVICE_STATE_FAILURE)
4654                 return 0;
4655
4656         return __connman_service_ipconfig_indicate_state(service,
4657                                                 CONNMAN_SERVICE_STATE_IDLE,
4658                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
4659 }
4660
4661 int __connman_service_indicate_default(struct connman_service *service)
4662 {
4663         struct connman_service *current = __connman_service_get_default();
4664
4665         DBG("service %p default %p", service, current);
4666
4667         if (current == service)
4668                 return 0;
4669
4670         default_changed();
4671
4672         return 0;
4673 }
4674
4675 enum connman_service_state __connman_service_ipconfig_get_state(
4676                                         struct connman_service *service,
4677                                         enum connman_ipconfig_type type)
4678 {
4679         if (service == NULL)
4680                 return CONNMAN_SERVICE_STATE_UNKNOWN;
4681
4682         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4683                 return service->state_ipv4;
4684
4685         if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
4686                 return service->state_ipv6;
4687
4688         return CONNMAN_SERVICE_STATE_UNKNOWN;
4689 }
4690
4691 static void check_proxy_setup(struct connman_service *service)
4692 {
4693         /*
4694          * We start WPAD if we haven't got a PAC URL from DHCP and
4695          * if our proxy manual configuration is either empty or set
4696          * to AUTO with an empty URL.
4697          */
4698
4699         if (service->proxy != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN)
4700                 goto done;
4701
4702         if (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_UNKNOWN &&
4703                 (service->proxy_config != CONNMAN_SERVICE_PROXY_METHOD_AUTO ||
4704                         service->pac != NULL))
4705                 goto done;
4706
4707         if (__connman_wpad_start(service) < 0) {
4708                 service->proxy = CONNMAN_SERVICE_PROXY_METHOD_DIRECT;
4709                 __connman_notifier_proxy_changed(service);
4710                 goto done;
4711         }
4712
4713         return;
4714
4715 done:
4716         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV4);
4717 }
4718
4719 /*
4720  * How many networks are connected at the same time. If more than 1,
4721  * then set the rp_filter setting properly (loose mode routing) so that network
4722  * connectivity works ok. This is only done for IPv4 networks as IPv6
4723  * does not have rp_filter knob.
4724  */
4725 static int connected_networks_count;
4726 static int original_rp_filter;
4727
4728 static void service_rp_filter(struct connman_service *service,
4729                                 gboolean connected)
4730 {
4731         enum connman_ipconfig_method method;
4732
4733         method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
4734
4735         switch (method) {
4736         case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
4737         case CONNMAN_IPCONFIG_METHOD_OFF:
4738         case CONNMAN_IPCONFIG_METHOD_AUTO:
4739                 return;
4740         case CONNMAN_IPCONFIG_METHOD_FIXED:
4741         case CONNMAN_IPCONFIG_METHOD_MANUAL:
4742         case CONNMAN_IPCONFIG_METHOD_DHCP:
4743                 break;
4744         }
4745
4746         if (connected == TRUE) {
4747                 if (connected_networks_count == 1) {
4748                         int filter_value;
4749                         filter_value = __connman_ipconfig_set_rp_filter();
4750                         if (filter_value < 0)
4751                                 return;
4752
4753                         original_rp_filter = filter_value;
4754                 }
4755                 connected_networks_count++;
4756
4757         } else {
4758                 if (connected_networks_count == 2)
4759                         __connman_ipconfig_unset_rp_filter(original_rp_filter);
4760
4761                 connected_networks_count--;
4762                 if (connected_networks_count < 0)
4763                         connected_networks_count = 0;
4764         }
4765
4766         DBG("%s %s ipconfig %p method %d count %d filter %d",
4767                 connected ? "connected" : "disconnected", service->identifier,
4768                 service->ipconfig_ipv4, method,
4769                 connected_networks_count, original_rp_filter);
4770 }
4771
4772 static gboolean redo_wispr(gpointer user_data)
4773 {
4774         struct connman_service *service = user_data;
4775
4776         DBG("");
4777
4778         __connman_wispr_start(service, CONNMAN_IPCONFIG_TYPE_IPV6);
4779
4780         return FALSE;
4781 }
4782
4783 int __connman_service_online_check_failed(struct connman_service *service,
4784                                         enum connman_ipconfig_type type)
4785 {
4786         DBG("service %p type %d count %d", service, type,
4787                                                 service->online_check_count);
4788
4789         /* currently we only retry IPv6 stuff */
4790         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 ||
4791                         service->online_check_count != 1) {
4792                 __connman_service_auto_connect();
4793                 return 0;
4794         }
4795
4796         service->online_check_count = 0;
4797
4798         /*
4799          * We set the timeout to 1 sec so that we have a chance to get
4800          * necessary IPv6 router advertisement messages that might have
4801          * DNS data etc.
4802          */
4803         g_timeout_add_seconds(1, redo_wispr, service);
4804
4805         return EAGAIN;
4806 }
4807
4808 int __connman_service_ipconfig_indicate_state(struct connman_service *service,
4809                                         enum connman_service_state new_state,
4810                                         enum connman_ipconfig_type type)
4811 {
4812         struct connman_ipconfig *ipconfig = NULL;
4813         enum connman_service_state old_state;
4814         int ret;
4815
4816         if (service == NULL)
4817                 return -EINVAL;
4818
4819         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
4820                 old_state = service->state_ipv4;
4821                 ipconfig = service->ipconfig_ipv4;
4822         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
4823                 old_state = service->state_ipv6;
4824                 ipconfig = service->ipconfig_ipv6;
4825         }
4826
4827         if (ipconfig == NULL)
4828                 return -EINVAL;
4829
4830         /* Any change? */
4831         if (old_state == new_state)
4832                 return -EALREADY;
4833
4834         DBG("service %p (%s) state %d (%s) type %d (%s)",
4835                 service, service ? service->identifier : NULL,
4836                 new_state, state2string(new_state),
4837                 type, __connman_ipconfig_type2string(type));
4838
4839         switch (new_state) {
4840         case CONNMAN_SERVICE_STATE_UNKNOWN:
4841         case CONNMAN_SERVICE_STATE_IDLE:
4842                 if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
4843                         return -EINVAL;
4844                 break;
4845         case CONNMAN_SERVICE_STATE_ASSOCIATION:
4846                 break;
4847         case CONNMAN_SERVICE_STATE_CONFIGURATION:
4848                 __connman_ipconfig_enable(ipconfig);
4849                 break;
4850         case CONNMAN_SERVICE_STATE_READY:
4851                 update_nameservers(service);
4852
4853                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
4854                         check_proxy_setup(service);
4855                         service_rp_filter(service, TRUE);
4856                 } else {
4857                         service->online_check_count = 1;
4858                         __connman_wispr_start(service, type);
4859                 }
4860                 break;
4861         case CONNMAN_SERVICE_STATE_ONLINE:
4862                 break;
4863         case CONNMAN_SERVICE_STATE_DISCONNECT:
4864                 if (service->state == CONNMAN_SERVICE_STATE_IDLE)
4865                         return -EINVAL;
4866
4867                 if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4868                         service_rp_filter(service, FALSE);
4869
4870                 break;
4871         case CONNMAN_SERVICE_STATE_FAILURE:
4872                 break;
4873         }
4874
4875         /* We keep that state */
4876         if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
4877                 service->state_ipv4 = new_state;
4878         else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
4879                 service->state_ipv6 = new_state;
4880
4881         ret = service_indicate_state(service);
4882
4883         /*
4884          * If the ipconfig method is OFF, then we set the state to IDLE
4885          * so that it will not affect the combined state in the future.
4886          */
4887         if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
4888                 enum connman_ipconfig_method method;
4889                 method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
4890                 if (method == CONNMAN_IPCONFIG_METHOD_OFF ||
4891                                 method == CONNMAN_IPCONFIG_METHOD_UNKNOWN) {
4892                         service->state_ipv4 = CONNMAN_SERVICE_STATE_IDLE;
4893                         ret = service_indicate_state(service);
4894                 }
4895
4896         } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
4897                 enum connman_ipconfig_method method;
4898                 method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
4899                 if (method == CONNMAN_IPCONFIG_METHOD_OFF ||
4900                                 method == CONNMAN_IPCONFIG_METHOD_UNKNOWN) {
4901                         service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
4902                         ret = service_indicate_state(service);
4903                 }
4904         }
4905
4906         return ret;
4907 }
4908
4909 static connman_bool_t prepare_network(struct connman_service *service)
4910 {
4911         enum connman_network_type type;
4912         unsigned int ssid_len;
4913
4914         type = connman_network_get_type(service->network);
4915
4916         switch (type) {
4917         case CONNMAN_NETWORK_TYPE_UNKNOWN:
4918         case CONNMAN_NETWORK_TYPE_VENDOR:
4919                 return FALSE;
4920         case CONNMAN_NETWORK_TYPE_WIFI:
4921                 if (connman_network_get_blob(service->network, "WiFi.SSID",
4922                                                         &ssid_len) == NULL)
4923                         return FALSE;
4924
4925                 if (service->passphrase != NULL)
4926                         connman_network_set_string(service->network,
4927                                 "WiFi.Passphrase", service->passphrase);
4928                 break;
4929         case CONNMAN_NETWORK_TYPE_ETHERNET:
4930         case CONNMAN_NETWORK_TYPE_WIMAX:
4931         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
4932         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
4933         case CONNMAN_NETWORK_TYPE_CELLULAR:
4934                 break;
4935         }
4936
4937         return TRUE;
4938 }
4939
4940 static void prepare_8021x(struct connman_service *service)
4941 {
4942         if (service->eap != NULL)
4943                 connman_network_set_string(service->network, "WiFi.EAP",
4944                                                                 service->eap);
4945
4946         if (service->identity != NULL)
4947                 connman_network_set_string(service->network, "WiFi.Identity",
4948                                                         service->identity);
4949
4950         if (service->ca_cert_file != NULL)
4951                 connman_network_set_string(service->network, "WiFi.CACertFile",
4952                                                         service->ca_cert_file);
4953
4954         if (service->client_cert_file != NULL)
4955                 connman_network_set_string(service->network,
4956                                                 "WiFi.ClientCertFile",
4957                                                 service->client_cert_file);
4958
4959         if (service->private_key_file != NULL)
4960                 connman_network_set_string(service->network,
4961                                                 "WiFi.PrivateKeyFile",
4962                                                 service->private_key_file);
4963
4964         if (service->private_key_passphrase != NULL)
4965                 connman_network_set_string(service->network,
4966                                         "WiFi.PrivateKeyPassphrase",
4967                                         service->private_key_passphrase);
4968
4969         if (service->phase2 != NULL)
4970                 connman_network_set_string(service->network, "WiFi.Phase2",
4971                                                         service->phase2);
4972 }
4973
4974 static int service_connect(struct connman_service *service)
4975 {
4976         int err;
4977
4978         if (service->hidden == TRUE)
4979                 return -EPERM;
4980
4981         switch (service->type) {
4982         case CONNMAN_SERVICE_TYPE_UNKNOWN:
4983         case CONNMAN_SERVICE_TYPE_SYSTEM:
4984         case CONNMAN_SERVICE_TYPE_GPS:
4985         case CONNMAN_SERVICE_TYPE_GADGET:
4986                 return -EINVAL;
4987         case CONNMAN_SERVICE_TYPE_ETHERNET:
4988         case CONNMAN_SERVICE_TYPE_WIMAX:
4989         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
4990         case CONNMAN_SERVICE_TYPE_CELLULAR:
4991         case CONNMAN_SERVICE_TYPE_VPN:
4992                 break;
4993         case CONNMAN_SERVICE_TYPE_WIFI:
4994                 switch (service->security) {
4995                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
4996                 case CONNMAN_SERVICE_SECURITY_NONE:
4997                         break;
4998                 case CONNMAN_SERVICE_SECURITY_WEP:
4999                 case CONNMAN_SERVICE_SECURITY_PSK:
5000                 case CONNMAN_SERVICE_SECURITY_WPA:
5001                 case CONNMAN_SERVICE_SECURITY_RSN:
5002                         if (service->passphrase == NULL) {
5003                                 if (service->network == NULL)
5004                                         return -EOPNOTSUPP;
5005
5006                                 if (service->wps == FALSE ||
5007                                         connman_network_get_bool(
5008                                                         service->network,
5009                                                         "WiFi.UseWPS") == FALSE)
5010                                         return -ENOKEY;
5011                         }
5012                         break;
5013                 case CONNMAN_SERVICE_SECURITY_8021X:
5014                         if (service->eap == NULL)
5015                                 return -EINVAL;
5016
5017                         /*
5018                          * never request credentials if using EAP-TLS
5019                          * (EAP-TLS networks need to be fully provisioned)
5020                          */
5021                         if (g_str_equal(service->eap, "tls") == TRUE)
5022                                 break;
5023
5024                         /*
5025                          * Return -ENOKEY if either identity or passphrase is
5026                          * missing. Agent provided credentials can be used as
5027                          * fallback if needed.
5028                          */
5029                         if ((service->identity == NULL &&
5030                                         service->agent_identity == NULL) ||
5031                                         (service->passphrase == NULL &&
5032                                         service->agent_passphrase == NULL))
5033                                 return -ENOKEY;
5034
5035                         break;
5036                 }
5037                 break;
5038         }
5039
5040         if (service->network != NULL) {
5041                 if (prepare_network(service) == FALSE)
5042                         return -EINVAL;
5043
5044                 switch (service->security) {
5045                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
5046                 case CONNMAN_SERVICE_SECURITY_NONE:
5047                 case CONNMAN_SERVICE_SECURITY_WEP:
5048                 case CONNMAN_SERVICE_SECURITY_PSK:
5049                 case CONNMAN_SERVICE_SECURITY_WPA:
5050                 case CONNMAN_SERVICE_SECURITY_RSN:
5051                         break;
5052                 case CONNMAN_SERVICE_SECURITY_8021X:
5053                         prepare_8021x(service);
5054                         break;
5055                 }
5056
5057                 if (__connman_stats_service_register(service) == 0) {
5058                         __connman_stats_get(service, FALSE,
5059                                                 &service->stats.data);
5060                         __connman_stats_get(service, TRUE,
5061                                                 &service->stats_roaming.data);
5062                 }
5063
5064                 if (service->ipconfig_ipv4)
5065                         __connman_ipconfig_enable(service->ipconfig_ipv4);
5066                 if (service->ipconfig_ipv6)
5067                         __connman_ipconfig_enable(service->ipconfig_ipv6);
5068
5069                 err = __connman_network_connect(service->network);
5070         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
5071                                         service->provider != NULL)
5072                 err = __connman_provider_connect(service->provider);
5073         else
5074                 return -EOPNOTSUPP;
5075
5076         if (err < 0) {
5077                 if (err != -EINPROGRESS) {
5078                         __connman_ipconfig_disable(service->ipconfig_ipv4);
5079                         __connman_ipconfig_disable(service->ipconfig_ipv6);
5080                         __connman_stats_service_unregister(service);
5081                 }
5082         }
5083
5084         return err;
5085 }
5086
5087
5088 int __connman_service_connect(struct connman_service *service)
5089 {
5090         int err;
5091
5092         DBG("service %p state %s", service, state2string(service->state));
5093
5094         if (is_connected(service) == TRUE)
5095                 return -EISCONN;
5096
5097         if (is_connecting(service) == TRUE)
5098                 return -EALREADY;
5099
5100         switch (service->type) {
5101         case CONNMAN_SERVICE_TYPE_UNKNOWN:
5102         case CONNMAN_SERVICE_TYPE_SYSTEM:
5103         case CONNMAN_SERVICE_TYPE_GPS:
5104         case CONNMAN_SERVICE_TYPE_GADGET:
5105                 return -EINVAL;
5106         default:
5107                 err = service_connect(service);
5108         }
5109
5110         if (err >= 0)
5111                 return 0;
5112
5113         if (err == -EINPROGRESS) {
5114                 if (service->timeout == 0)
5115                         service->timeout = g_timeout_add_seconds(
5116                                 CONNECT_TIMEOUT, connect_timeout, service);
5117
5118                 return -EINPROGRESS;
5119         }
5120
5121         __connman_service_ipconfig_indicate_state(service,
5122                                         CONNMAN_SERVICE_STATE_FAILURE,
5123                                         CONNMAN_IPCONFIG_TYPE_IPV4);
5124         __connman_service_ipconfig_indicate_state(service,
5125                                         CONNMAN_SERVICE_STATE_FAILURE,
5126                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5127
5128         if (service->network != NULL)
5129                 __connman_network_disconnect(service->network);
5130         else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
5131                                 service->provider != NULL)
5132                         __connman_provider_disconnect(service->provider);
5133
5134         if (service->userconnect == TRUE) {
5135                 if (err == -ENOKEY || err == -EPERM) {
5136                         if (__connman_agent_request_passphrase_input(service,
5137                                                         request_input_cb,
5138                                                         NULL) == -EIO)
5139                                 return -EINPROGRESS;
5140                 }
5141                 reply_pending(service, -err);
5142         }
5143
5144         return err;
5145 }
5146
5147 int __connman_service_disconnect(struct connman_service *service)
5148 {
5149         int err;
5150
5151         DBG("service %p", service);
5152
5153         if (service->network != NULL) {
5154                 err = __connman_network_disconnect(service->network);
5155         } else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
5156                                         service->provider != NULL)
5157                 err = __connman_provider_disconnect(service->provider);
5158         else
5159                 return -EOPNOTSUPP;
5160
5161         if (err < 0 && err != -EINPROGRESS)
5162                 return err;
5163
5164         __connman_6to4_remove(service->ipconfig_ipv4);
5165
5166         if (service->ipconfig_ipv4)
5167                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv4,
5168                                                         NULL);
5169         else
5170                 __connman_ipconfig_set_proxy_autoconfig(service->ipconfig_ipv6,
5171                                                         NULL);
5172
5173         __connman_ipconfig_address_remove(service->ipconfig_ipv4);
5174         __connman_ipconfig_address_remove(service->ipconfig_ipv6);
5175
5176         __connman_ipconfig_disable(service->ipconfig_ipv4);
5177         __connman_ipconfig_disable(service->ipconfig_ipv6);
5178
5179         __connman_stats_service_unregister(service);
5180
5181         return err;
5182 }
5183
5184 int __connman_service_disconnect_all(void)
5185 {
5186         GSequenceIter *iter;
5187         GSList *services = NULL, *list;
5188
5189         DBG("");
5190
5191         iter = g_sequence_get_begin_iter(service_list);
5192
5193         while (g_sequence_iter_is_end(iter) == FALSE) {
5194                 struct connman_service *service = g_sequence_get(iter);
5195
5196                 services = g_slist_prepend(services, service);
5197
5198                 iter = g_sequence_iter_next(iter);
5199         }
5200
5201         for (list = services; list != NULL; list = list->next) {
5202                 struct connman_service *service = list->data;
5203
5204                 service->ignore = TRUE;
5205
5206                 set_reconnect_state(service, FALSE);
5207
5208                 __connman_service_disconnect(service);
5209         }
5210
5211         g_slist_free(list);
5212
5213         return 0;
5214
5215 }
5216
5217 /**
5218  * lookup_by_identifier:
5219  * @identifier: service identifier
5220  *
5221  * Look up a service by identifier (reference count will not be increased)
5222  */
5223 static struct connman_service *lookup_by_identifier(const char *identifier)
5224 {
5225         GSequenceIter *iter;
5226
5227         iter = g_hash_table_lookup(service_hash, identifier);
5228         if (iter != NULL)
5229                 return g_sequence_get(iter);
5230
5231         return NULL;
5232 }
5233
5234 static void provision_changed(gpointer value, gpointer user_data)
5235 {
5236         struct connman_service *service = value;
5237         char *path = user_data;
5238
5239         __connman_config_provision_service_ident(service, path);
5240 }
5241
5242 void __connman_service_provision_changed(const char *ident)
5243 {
5244         g_sequence_foreach(service_list, provision_changed, (void *)ident);
5245 }
5246
5247 /**
5248  * __connman_service_get:
5249  * @identifier: service identifier
5250  *
5251  * Look up a service by identifier or create a new one if not found
5252  */
5253 static struct connman_service *service_get(const char *identifier)
5254 {
5255         struct connman_service *service;
5256         GSequenceIter *iter;
5257
5258         iter = g_hash_table_lookup(service_hash, identifier);
5259         if (iter != NULL) {
5260                 service = g_sequence_get(iter);
5261                 if (service != NULL)
5262                         connman_service_ref(service);
5263                 return service;
5264         }
5265
5266         service = connman_service_create();
5267         if (service == NULL)
5268                 return NULL;
5269
5270         DBG("service %p", service);
5271
5272         service->identifier = g_strdup(identifier);
5273
5274         iter = g_sequence_insert_sorted(service_list, service,
5275                                                 service_compare, NULL);
5276
5277         g_hash_table_insert(service_hash, service->identifier, iter);
5278
5279         return service;
5280 }
5281
5282 static int service_register(struct connman_service *service)
5283 {
5284         GSequenceIter *iter;
5285
5286         DBG("service %p", service);
5287
5288         if (service->path != NULL)
5289                 return -EALREADY;
5290
5291         service->path = g_strdup_printf("%s/service/%s", CONNMAN_PATH,
5292                                                 service->identifier);
5293
5294         DBG("path %s", service->path);
5295
5296         __connman_config_provision_service(service);
5297
5298         service_load(service);
5299
5300         g_dbus_register_interface(connection, service->path,
5301                                         CONNMAN_SERVICE_INTERFACE,
5302                                         service_methods, service_signals,
5303                                                         NULL, service, NULL);
5304
5305         iter = g_hash_table_lookup(service_hash, service->identifier);
5306         if (iter != NULL) {
5307                 g_sequence_sort_changed(iter, service_compare, NULL);
5308                 service_schedule_changed();
5309         }
5310
5311         __connman_connection_update_gateway();
5312
5313         return 0;
5314 }
5315
5316 static void service_up(struct connman_ipconfig *ipconfig)
5317 {
5318         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
5319
5320         DBG("%s up", __connman_ipconfig_get_ifname(ipconfig));
5321
5322         link_changed(service);
5323
5324         service->stats.valid = FALSE;
5325         service->stats_roaming.valid = FALSE;
5326 }
5327
5328 static void service_down(struct connman_ipconfig *ipconfig)
5329 {
5330         DBG("%s down", __connman_ipconfig_get_ifname(ipconfig));
5331 }
5332
5333 static void service_lower_up(struct connman_ipconfig *ipconfig)
5334 {
5335         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
5336
5337         DBG("%s lower up", __connman_ipconfig_get_ifname(ipconfig));
5338
5339         stats_start(service);
5340 }
5341
5342 static void service_lower_down(struct connman_ipconfig *ipconfig)
5343 {
5344         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
5345
5346         DBG("%s lower down", __connman_ipconfig_get_ifname(ipconfig));
5347
5348         if (is_idle_state(service, service->state_ipv4) == FALSE)
5349                 __connman_ipconfig_disable(service->ipconfig_ipv4);
5350
5351         if (is_idle_state(service, service->state_ipv6) == FALSE)
5352                 __connman_ipconfig_disable(service->ipconfig_ipv6);
5353
5354         stats_stop(service);
5355         service_save(service);
5356 }
5357
5358 static void service_ip_bound(struct connman_ipconfig *ipconfig)
5359 {
5360         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
5361         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
5362         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
5363
5364         DBG("%s ip bound", __connman_ipconfig_get_ifname(ipconfig));
5365
5366         type = __connman_ipconfig_get_config_type(ipconfig);
5367         method = __connman_ipconfig_get_method(ipconfig);
5368
5369         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
5370                                                         type, method);
5371
5372         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
5373                         method == CONNMAN_IPCONFIG_METHOD_AUTO)
5374                 __connman_service_ipconfig_indicate_state(service,
5375                                                 CONNMAN_SERVICE_STATE_READY,
5376                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5377
5378         settings_changed(service, ipconfig);
5379 }
5380
5381 static void service_ip_release(struct connman_ipconfig *ipconfig)
5382 {
5383         struct connman_service *service = __connman_ipconfig_get_data(ipconfig);
5384         enum connman_ipconfig_method method = CONNMAN_IPCONFIG_METHOD_UNKNOWN;
5385         enum connman_ipconfig_type type = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
5386
5387         DBG("%s ip release", __connman_ipconfig_get_ifname(ipconfig));
5388
5389         type = __connman_ipconfig_get_config_type(ipconfig);
5390         method = __connman_ipconfig_get_method(ipconfig);
5391
5392         DBG("service %p ipconfig %p type %d method %d", service, ipconfig,
5393                                                         type, method);
5394
5395         if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
5396                         method == CONNMAN_IPCONFIG_METHOD_OFF)
5397                 __connman_service_ipconfig_indicate_state(service,
5398                                         CONNMAN_SERVICE_STATE_DISCONNECT,
5399                                         CONNMAN_IPCONFIG_TYPE_IPV6);
5400
5401         if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
5402                         method == CONNMAN_IPCONFIG_METHOD_OFF)
5403                 __connman_service_ipconfig_indicate_state(service,
5404                                         CONNMAN_SERVICE_STATE_DISCONNECT,
5405                                         CONNMAN_IPCONFIG_TYPE_IPV4);
5406
5407         settings_changed(service, ipconfig);
5408 }
5409
5410 static const struct connman_ipconfig_ops service_ops = {
5411         .up             = service_up,
5412         .down           = service_down,
5413         .lower_up       = service_lower_up,
5414         .lower_down     = service_lower_down,
5415         .ip_bound       = service_ip_bound,
5416         .ip_release     = service_ip_release,
5417 };
5418
5419 static void setup_ip4config(struct connman_service *service, int index,
5420                         enum connman_ipconfig_method method)
5421 {
5422         service->ipconfig_ipv4 = __connman_ipconfig_create(index,
5423                                                 CONNMAN_IPCONFIG_TYPE_IPV4);
5424         if (service->ipconfig_ipv4 == NULL)
5425                 return;
5426
5427         __connman_ipconfig_set_method(service->ipconfig_ipv4, method);
5428
5429         __connman_ipconfig_set_data(service->ipconfig_ipv4, service);
5430
5431         __connman_ipconfig_set_ops(service->ipconfig_ipv4, &service_ops);
5432 }
5433
5434 static void setup_ip6config(struct connman_service *service, int index)
5435 {
5436         service->ipconfig_ipv6 = __connman_ipconfig_create(index,
5437                                                 CONNMAN_IPCONFIG_TYPE_IPV6);
5438         if (service->ipconfig_ipv6 == NULL)
5439                 return;
5440
5441         __connman_ipconfig_set_data(service->ipconfig_ipv6, service);
5442
5443         __connman_ipconfig_set_ops(service->ipconfig_ipv6, &service_ops);
5444 }
5445
5446 void __connman_service_read_ip4config(struct connman_service *service)
5447 {
5448         GKeyFile *keyfile;
5449
5450         if (service->ipconfig_ipv4 == NULL)
5451                 return;
5452
5453         keyfile = connman_storage_load_service(service->identifier);
5454         if (keyfile == NULL)
5455                 return;
5456
5457         __connman_ipconfig_load(service->ipconfig_ipv4, keyfile,
5458                                 service->identifier, "IPv4.");
5459
5460         g_key_file_free(keyfile);
5461 }
5462
5463 void __connman_service_create_ip4config(struct connman_service *service,
5464                                         int index)
5465 {
5466         DBG("ipv4 %p", service->ipconfig_ipv4);
5467
5468         if (service->ipconfig_ipv4 != NULL)
5469                 return;
5470
5471         setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
5472         __connman_service_read_ip4config(service);
5473 }
5474
5475 void __connman_service_read_ip6config(struct connman_service *service)
5476 {
5477         GKeyFile *keyfile;
5478
5479         if (service->ipconfig_ipv6 == NULL)
5480                 return;
5481
5482         keyfile = connman_storage_load_service(service->identifier);
5483         if (keyfile == NULL)
5484                 return;
5485
5486         __connman_ipconfig_load(service->ipconfig_ipv6, keyfile,
5487                                 service->identifier, "IPv6.");
5488
5489         g_key_file_free(keyfile);
5490 }
5491
5492 void __connman_service_create_ip6config(struct connman_service *service,
5493                                                                 int index)
5494 {
5495         DBG("ipv6 %p", service->ipconfig_ipv6);
5496
5497         if (service->ipconfig_ipv6 != NULL)
5498                 return;
5499
5500         setup_ip6config(service, index);
5501
5502         __connman_service_read_ip6config(service);
5503 }
5504
5505 /**
5506  * __connman_service_lookup_from_network:
5507  * @network: network structure
5508  *
5509  * Look up a service by network (reference count will not be increased)
5510  */
5511 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
5512 {
5513         struct connman_service *service;
5514         const char *ident, *group;
5515         char *name;
5516
5517         DBG("network %p", network);
5518
5519         if (network == NULL)
5520                 return NULL;
5521
5522         ident = __connman_network_get_ident(network);
5523         if (ident == NULL)
5524                 return NULL;
5525
5526         group = connman_network_get_group(network);
5527         if (group == NULL)
5528                 return NULL;
5529
5530         name = g_strdup_printf("%s_%s_%s",
5531                         __connman_network_get_type(network), ident, group);
5532         service = lookup_by_identifier(name);
5533         g_free(name);
5534
5535         return service;
5536 }
5537
5538 struct connman_service *__connman_service_lookup_from_index(int index)
5539 {
5540         struct connman_service *service;
5541         GSequenceIter *iter;
5542
5543         iter = g_sequence_get_begin_iter(service_list);
5544
5545         while (g_sequence_iter_is_end(iter) == FALSE) {
5546                 service = g_sequence_get(iter);
5547
5548                 if (__connman_ipconfig_get_index(service->ipconfig_ipv4)
5549                                                         == index)
5550                         return service;
5551
5552                 if (__connman_ipconfig_get_index(service->ipconfig_ipv6)
5553                                                         == index)
5554                         return service;
5555
5556                 iter = g_sequence_iter_next(iter);
5557         }
5558
5559         return NULL;
5560 }
5561
5562 const char *__connman_service_get_ident(struct connman_service *service)
5563 {
5564         return service->identifier;
5565 }
5566
5567 const char *__connman_service_get_path(struct connman_service *service)
5568 {
5569         return service->path;
5570 }
5571
5572 unsigned int __connman_service_get_order(struct connman_service *service)
5573 {
5574         GSequenceIter *iter;
5575
5576         if (service == NULL)
5577                 return 0;
5578
5579         if (service->favorite == FALSE) {
5580                 service->order = 0;
5581                 goto done;
5582         }
5583
5584         iter = g_hash_table_lookup(service_hash, service->identifier);
5585         if (iter != NULL) {
5586                 if (g_sequence_iter_get_position(iter) == 0)
5587                         service->order = 1;
5588                 else if (service->type == CONNMAN_SERVICE_TYPE_VPN &&
5589                                 service->do_split_routing == FALSE)
5590                         service->order = 10;
5591                 else
5592                         service->order = 0;
5593         }
5594
5595         DBG("service %p name %s order %d split %d", service, service->name,
5596                 service->order, service->do_split_routing);
5597
5598 done:
5599         return service->order;
5600 }
5601
5602 void __connman_service_update_ordering(void)
5603 {
5604         GSequenceIter *iter;
5605
5606         iter = g_sequence_get_begin_iter(service_list);
5607         if (iter != NULL)
5608                 g_sequence_sort_changed(iter, service_compare, NULL);
5609 }
5610
5611 static enum connman_service_type convert_network_type(struct connman_network *network)
5612 {
5613         enum connman_network_type type = connman_network_get_type(network);
5614
5615         switch (type) {
5616         case CONNMAN_NETWORK_TYPE_UNKNOWN:
5617         case CONNMAN_NETWORK_TYPE_VENDOR:
5618                 break;
5619         case CONNMAN_NETWORK_TYPE_ETHERNET:
5620                 return CONNMAN_SERVICE_TYPE_ETHERNET;
5621         case CONNMAN_NETWORK_TYPE_WIFI:
5622                 return CONNMAN_SERVICE_TYPE_WIFI;
5623         case CONNMAN_NETWORK_TYPE_WIMAX:
5624                 return CONNMAN_SERVICE_TYPE_WIMAX;
5625         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
5626         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
5627                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
5628         case CONNMAN_NETWORK_TYPE_CELLULAR:
5629                 return CONNMAN_SERVICE_TYPE_CELLULAR;
5630         }
5631
5632         return CONNMAN_SERVICE_TYPE_UNKNOWN;
5633 }
5634
5635 static enum connman_service_security convert_wifi_security(const char *security)
5636 {
5637         if (security == NULL)
5638                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
5639         else if (g_str_equal(security, "none") == TRUE)
5640                 return CONNMAN_SERVICE_SECURITY_NONE;
5641         else if (g_str_equal(security, "wep") == TRUE)
5642                 return CONNMAN_SERVICE_SECURITY_WEP;
5643         else if (g_str_equal(security, "psk") == TRUE)
5644                 return CONNMAN_SERVICE_SECURITY_PSK;
5645         else if (g_str_equal(security, "ieee8021x") == TRUE)
5646                 return CONNMAN_SERVICE_SECURITY_8021X;
5647         else if (g_str_equal(security, "wpa") == TRUE)
5648                 return CONNMAN_SERVICE_SECURITY_WPA;
5649         else if (g_str_equal(security, "rsn") == TRUE)
5650                 return CONNMAN_SERVICE_SECURITY_RSN;
5651         else
5652                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
5653 }
5654
5655 static void update_from_network(struct connman_service *service,
5656                                         struct connman_network *network)
5657 {
5658         connman_uint8_t strength = service->strength;
5659         GSequenceIter *iter;
5660         const char *str;
5661
5662         DBG("service %p network %p", service, network);
5663
5664         if (is_connected(service) == TRUE)
5665                 return;
5666
5667         if (is_connecting(service) == TRUE)
5668                 return;
5669
5670         str = connman_network_get_string(network, "Name");
5671         if (str != NULL) {
5672                 g_free(service->name);
5673                 service->name = g_strdup(str);
5674                 service->hidden = FALSE;
5675         } else {
5676                 g_free(service->name);
5677                 service->name = NULL;
5678                 service->hidden = TRUE;
5679         }
5680
5681         service->strength = connman_network_get_strength(network);
5682         service->roaming = connman_network_get_bool(network, "Roaming");
5683
5684         if (service->strength == 0) {
5685                 /*
5686                  * Filter out 0-values; it's unclear what they mean
5687                  * and they cause anomalous sorting of the priority list.
5688                  */
5689                 service->strength = strength;
5690         }
5691
5692         str = connman_network_get_string(network, "WiFi.Security");
5693         service->security = convert_wifi_security(str);
5694
5695         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
5696                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
5697
5698         if (service->strength > strength && service->network != NULL) {
5699                 connman_network_unref(service->network);
5700                 service->network = connman_network_ref(network);
5701
5702                 strength_changed(service);
5703         }
5704
5705         if (service->network == NULL)
5706                 service->network = connman_network_ref(network);
5707
5708         iter = g_hash_table_lookup(service_hash, service->identifier);
5709         if (iter != NULL) {
5710                 g_sequence_sort_changed(iter, service_compare, NULL);
5711                 service_schedule_changed();
5712         }
5713 }
5714
5715 /**
5716  * __connman_service_create_from_network:
5717  * @network: network structure
5718  *
5719  * Look up service by network and if not found, create one
5720  */
5721 struct connman_service * __connman_service_create_from_network(struct connman_network *network)
5722 {
5723         struct connman_service *service;
5724         struct connman_device *device;
5725         const char *ident, *group;
5726         char *name;
5727         unsigned int *auto_connect_types;
5728         int i, index;
5729
5730         DBG("network %p", network);
5731
5732         if (network == NULL)
5733                 return NULL;
5734
5735         ident = __connman_network_get_ident(network);
5736         if (ident == NULL)
5737                 return NULL;
5738
5739         group = connman_network_get_group(network);
5740         if (group == NULL)
5741                 return NULL;
5742
5743         name = g_strdup_printf("%s_%s_%s",
5744                         __connman_network_get_type(network), ident, group);
5745         service = service_get(name);
5746         g_free(name);
5747
5748         if (service == NULL)
5749                 return NULL;
5750
5751         if (__connman_network_get_weakness(network) == TRUE)
5752                 return service;
5753
5754         if (service->path != NULL) {
5755                 update_from_network(service, network);
5756                 __connman_connection_update_gateway();
5757                 return service;
5758         }
5759
5760         service->type = convert_network_type(network);
5761
5762         auto_connect_types = connman_setting_get_uint_list("DefaultAutoConnectTechnologies");
5763         service->autoconnect = FALSE;
5764         for (i = 0; auto_connect_types != NULL &&
5765                      auto_connect_types[i] != 0; i++) {
5766                 if (service->type == auto_connect_types[i]) {
5767                         service->autoconnect = TRUE;
5768                         break;
5769                 }
5770         }
5771
5772         switch (service->type) {
5773         case CONNMAN_SERVICE_TYPE_UNKNOWN:
5774         case CONNMAN_SERVICE_TYPE_SYSTEM:
5775         case CONNMAN_SERVICE_TYPE_WIMAX:
5776         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
5777         case CONNMAN_SERVICE_TYPE_GPS:
5778         case CONNMAN_SERVICE_TYPE_VPN:
5779         case CONNMAN_SERVICE_TYPE_GADGET:
5780         case CONNMAN_SERVICE_TYPE_WIFI:
5781         case CONNMAN_SERVICE_TYPE_CELLULAR:
5782                 break;
5783         case CONNMAN_SERVICE_TYPE_ETHERNET:
5784                 service->favorite = TRUE;
5785                 break;
5786         }
5787
5788         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
5789         service->state = combine_state(service->state_ipv4, service->state_ipv6);
5790
5791         update_from_network(service, network);
5792
5793         index = connman_network_get_index(network);
5794
5795         if (service->ipconfig_ipv4 == NULL)
5796                 setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_DHCP);
5797
5798         if (service->ipconfig_ipv6 == NULL)
5799                 setup_ip6config(service, index);
5800
5801         service_register(service);
5802
5803         if (service->favorite == TRUE) {
5804                 device = connman_network_get_device(service->network);
5805                 if (device && __connman_device_scanning(device) == FALSE)
5806                         __connman_service_auto_connect();
5807         }
5808
5809         __connman_notifier_service_add(service, service->name);
5810         service_schedule_added(service);
5811
5812         return service;
5813 }
5814
5815 void __connman_service_update_from_network(struct connman_network *network)
5816 {
5817         connman_bool_t need_sort = FALSE;
5818         struct connman_service *service;
5819         connman_uint8_t strength;
5820         connman_bool_t roaming;
5821         GSequenceIter *iter;
5822         const char *name;
5823         connman_bool_t stats_enable;
5824
5825         DBG("network %p", network);
5826
5827         service = __connman_service_lookup_from_network(network);
5828         if (service == NULL)
5829                 return;
5830
5831         if (service->network == NULL)
5832                 return;
5833
5834         name = connman_network_get_string(service->network, "Name");
5835         if (g_strcmp0(service->name, name) != 0) {
5836                 g_free(service->name);
5837                 service->name = g_strdup(name);
5838                 connman_dbus_property_changed_basic(service->path,
5839                                 CONNMAN_SERVICE_INTERFACE, "Name",
5840                                 DBUS_TYPE_STRING, &service->name);
5841         }
5842
5843         if (service->type == CONNMAN_SERVICE_TYPE_WIFI)
5844                 service->wps = connman_network_get_bool(network, "WiFi.WPS");
5845
5846         strength = connman_network_get_strength(service->network);
5847         if (strength == service->strength)
5848                 goto roaming;
5849
5850         service->strength = strength;
5851         need_sort = TRUE;
5852
5853         strength_changed(service);
5854
5855 roaming:
5856         roaming = connman_network_get_bool(service->network, "Roaming");
5857         if (roaming == service->roaming)
5858                 goto sorting;
5859
5860         stats_enable = stats_enabled(service);
5861         if (stats_enable == TRUE)
5862                 stats_stop(service);
5863
5864         service->roaming = roaming;
5865         need_sort = TRUE;
5866
5867         if (stats_enable == TRUE)
5868                 stats_start(service);
5869
5870         roaming_changed(service);
5871
5872 sorting:
5873         if (need_sort == TRUE) {
5874                 iter = g_hash_table_lookup(service_hash, service->identifier);
5875                 if (iter != NULL) {
5876                         g_sequence_sort_changed(iter, service_compare, NULL);
5877                         service_schedule_changed();
5878                 }
5879         }
5880 }
5881
5882 void __connman_service_remove_from_network(struct connman_network *network)
5883 {
5884         struct connman_service *service;
5885
5886         DBG("network %p", network);
5887
5888         service = __connman_service_lookup_from_network(network);
5889         if (service == NULL)
5890                 return;
5891
5892         service->ignore = TRUE;
5893
5894         __connman_connection_gateway_remove(service,
5895                                         CONNMAN_IPCONFIG_TYPE_ALL);
5896
5897         connman_service_unref(service);
5898 }
5899
5900 /**
5901  * __connman_service_create_from_provider:
5902  * @provider: provider structure
5903  *
5904  * Look up service by provider and if not found, create one
5905  */
5906 struct connman_service *
5907 __connman_service_create_from_provider(struct connman_provider *provider)
5908 {
5909         struct connman_service *service;
5910         const char *ident, *str;
5911         char *name;
5912         int index = connman_provider_get_index(provider);
5913
5914         DBG("provider %p", provider);
5915
5916         ident = __connman_provider_get_ident(provider);
5917         if (ident == NULL)
5918                 return NULL;
5919
5920         name = g_strdup_printf("vpn_%s", ident);
5921         service = service_get(name);
5922         g_free(name);
5923
5924         if (service == NULL)
5925                 return NULL;
5926
5927         service->type = CONNMAN_SERVICE_TYPE_VPN;
5928         service->provider = connman_provider_ref(provider);
5929         service->autoconnect = FALSE;
5930         service->userconnect = TRUE;
5931
5932         service->state_ipv4 = service->state_ipv6 = CONNMAN_SERVICE_STATE_IDLE;
5933         service->state = combine_state(service->state_ipv4, service->state_ipv6);
5934
5935         str = connman_provider_get_string(provider, "Name");
5936         if (str != NULL) {
5937                 g_free(service->name);
5938                 service->name = g_strdup(str);
5939                 service->hidden = FALSE;
5940         } else {
5941                 g_free(service->name);
5942                 service->name = NULL;
5943                 service->hidden = TRUE;
5944         }
5945
5946         service->strength = 0;
5947
5948         if (service->ipconfig_ipv4 == NULL)
5949                 setup_ip4config(service, index, CONNMAN_IPCONFIG_METHOD_MANUAL);
5950
5951         if (service->ipconfig_ipv6 == NULL)
5952                 setup_ip6config(service, index);
5953
5954         service_register(service);
5955
5956         __connman_notifier_service_add(service, service->name);
5957         service_schedule_added(service);
5958
5959         return service;
5960 }
5961
5962 int __connman_service_init(void)
5963 {
5964         DBG("");
5965
5966         connection = connman_dbus_get_connection();
5967
5968         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
5969                                                                 NULL, NULL);
5970
5971         service_list = g_sequence_new(service_free);
5972
5973         services_notify = g_new0(struct _services_notify, 1);
5974         services_notify->remove = g_hash_table_new_full(g_str_hash,
5975                         g_str_equal, g_free, NULL);
5976         services_notify->add = g_hash_table_new(g_str_hash, g_str_equal);
5977
5978         return 0;
5979 }
5980
5981 void __connman_service_cleanup(void)
5982 {
5983         GSequence *list;
5984
5985         DBG("");
5986
5987         if (autoconnect_timeout != 0) {
5988                 g_source_remove(autoconnect_timeout);
5989                 autoconnect_timeout = 0;
5990         }
5991
5992         list = service_list;
5993         service_list = NULL;
5994         g_sequence_free(list);
5995
5996         g_hash_table_destroy(service_hash);
5997         service_hash = NULL;
5998
5999         g_slist_free(counter_list);
6000         counter_list = NULL;
6001
6002         if (services_notify->id != 0) {
6003                 g_source_remove(services_notify->id);
6004                 service_send_changed(NULL);
6005                 g_hash_table_destroy(services_notify->remove);
6006                 g_hash_table_destroy(services_notify->add);
6007         }
6008         g_free(services_notify);
6009
6010         dbus_connection_unref(connection);
6011 }