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