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