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