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