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