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