Enable support for initial service drag and drop
[platform/upstream/connman.git] / src / service.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 <gdbus.h>
27
28 #include "connman.h"
29
30 static DBusConnection *connection = NULL;
31
32 static GSequence *service_list = NULL;
33 static GHashTable *service_hash = NULL;
34
35 struct connman_service {
36         gint refcount;
37         char *identifier;
38         char *path;
39         enum connman_service_type type;
40         enum connman_service_mode mode;
41         enum connman_service_security security;
42         enum connman_service_state state;
43         enum connman_service_error error;
44         connman_uint8_t strength;
45         connman_bool_t favorite;
46         connman_bool_t hidden;
47         GTimeVal modified;
48         unsigned int order;
49         char *name;
50         char *passphrase;
51         char *profile;
52         struct connman_ipconfig *ipconfig;
53         struct connman_device *device;
54         struct connman_network *network;
55         DBusMessage *pending;
56         guint timeout;
57 };
58
59 static void append_path(gpointer value, gpointer user_data)
60 {
61         struct connman_service *service = value;
62         DBusMessageIter *iter = user_data;
63
64         if (service->path == NULL)
65                 return;
66
67         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
68                                                         &service->path);
69 }
70
71 void __connman_service_list(DBusMessageIter *iter)
72 {
73         DBG("");
74
75         g_sequence_foreach(service_list, append_path, iter);
76 }
77
78 struct find_data {
79         const char *path;
80         struct connman_service *service;
81 };
82
83 static void compare_path(gpointer value, gpointer user_data)
84 {
85         struct connman_service *service = value;
86         struct find_data *data = user_data;
87
88         if (data->service != NULL)
89                 return;
90
91         if (g_strcmp0(service->path, data->path) == 0)
92                 data->service = service;
93 }
94
95 static struct connman_service *find_service(const char *path)
96 {
97         struct find_data data = { .path = path, .service = NULL };
98
99         DBG("path %s", path);
100
101         g_sequence_foreach(service_list, compare_path, &data);
102
103         return data.service;
104 }
105
106 static const char *type2string(enum connman_service_type type)
107 {
108         switch (type) {
109         case CONNMAN_SERVICE_TYPE_UNKNOWN:
110                 break;
111         case CONNMAN_SERVICE_TYPE_ETHERNET:
112                 return "ethernet";
113         case CONNMAN_SERVICE_TYPE_WIFI:
114                 return "wifi";
115         case CONNMAN_SERVICE_TYPE_WIMAX:
116                 return "wimax";
117         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
118                 return "bluetooth";
119         case CONNMAN_SERVICE_TYPE_CELLULAR:
120                 return "cellular";
121         }
122
123         return NULL;
124 }
125
126 static const char *mode2string(enum connman_service_mode mode)
127 {
128         switch (mode) {
129         case CONNMAN_SERVICE_MODE_UNKNOWN:
130                 break;
131         case CONNMAN_SERVICE_MODE_MANAGED:
132                 return "managed";
133         case CONNMAN_SERVICE_MODE_ADHOC:
134                 return "adhoc";
135         }
136
137         return NULL;
138 }
139
140 static const char *security2string(enum connman_service_security security)
141 {
142         switch (security) {
143         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
144                 break;
145         case CONNMAN_SERVICE_SECURITY_NONE:
146                 return "none";
147         case CONNMAN_SERVICE_SECURITY_WEP:
148                 return "wep";
149         case CONNMAN_SERVICE_SECURITY_WPA:
150                 return "wpa";
151         case CONNMAN_SERVICE_SECURITY_RSN:
152                 return "rsn";
153         }
154
155         return NULL;
156 }
157
158 static const char *state2string(enum connman_service_state state)
159 {
160         switch (state) {
161         case CONNMAN_SERVICE_STATE_UNKNOWN:
162                 break;
163         case CONNMAN_SERVICE_STATE_IDLE:
164                 return "idle";
165         case CONNMAN_SERVICE_STATE_CARRIER:
166                 return "carrier";
167         case CONNMAN_SERVICE_STATE_ASSOCIATION:
168                 return "association";
169         case CONNMAN_SERVICE_STATE_CONFIGURATION:
170                 return "configuration";
171         case CONNMAN_SERVICE_STATE_READY:
172                 return "ready";
173         case CONNMAN_SERVICE_STATE_DISCONNECT:
174                 return "disconnect";
175         case CONNMAN_SERVICE_STATE_FAILURE:
176                 return "failure";
177         }
178
179         return NULL;
180 }
181
182 static const char *error2string(enum connman_service_error error)
183 {
184         switch (error) {
185         case CONNMAN_SERVICE_ERROR_UNKNOWN:
186                 break;
187         case CONNMAN_SERVICE_ERROR_DHCP_FAILED:
188                 return "dhcp-failed";
189         case CONNMAN_SERVICE_ERROR_PIN_MISSING:
190                 return "pin-missing";
191         }
192
193         return NULL;
194 }
195
196 static enum connman_service_error string2error(const char *error)
197 {
198         if (g_strcmp0(error, "dhcp-failed") == 0)
199                 return CONNMAN_SERVICE_ERROR_DHCP_FAILED;
200         else if (g_strcmp0(error, "pin-missing") == 0)
201                 return CONNMAN_SERVICE_ERROR_PIN_MISSING;
202
203         return CONNMAN_SERVICE_ERROR_UNKNOWN;
204 }
205
206 static void state_changed(struct connman_service *service)
207 {
208         DBusMessage *signal;
209         DBusMessageIter entry, value;
210         const char *str, *key = "State";
211
212         if (service->path == NULL)
213                 return;
214
215         str = state2string(service->state);
216         if (str == NULL)
217                 return;
218
219         signal = dbus_message_new_signal(service->path,
220                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
221         if (signal == NULL)
222                 return;
223
224         dbus_message_iter_init_append(signal, &entry);
225
226         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
227
228         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
229                                         DBUS_TYPE_STRING_AS_STRING, &value);
230         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
231         dbus_message_iter_close_container(&entry, &value);
232
233         g_dbus_send_message(connection, signal);
234 }
235
236 static void strength_changed(struct connman_service *service)
237 {
238         DBusMessage *signal;
239         DBusMessageIter entry, value;
240         const char *key = "Strength";
241
242         if (service->path == NULL)
243                 return;
244
245         if (service->strength == 0)
246                 return;
247
248         signal = dbus_message_new_signal(service->path,
249                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
250         if (signal == NULL)
251                 return;
252
253         dbus_message_iter_init_append(signal, &entry);
254
255         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
256
257         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
258                                         DBUS_TYPE_BYTE_AS_STRING, &value);
259         dbus_message_iter_append_basic(&value, DBUS_TYPE_BYTE,
260                                                         &service->strength);
261         dbus_message_iter_close_container(&entry, &value);
262
263         g_dbus_send_message(connection, signal);
264 }
265
266 static DBusMessage *get_properties(DBusConnection *conn,
267                                         DBusMessage *msg, void *user_data)
268 {
269         struct connman_service *service = user_data;
270         DBusMessage *reply;
271         DBusMessageIter array, dict;
272         const char *str;
273
274         DBG("service %p", service);
275
276         reply = dbus_message_new_method_return(msg);
277         if (reply == NULL)
278                 return NULL;
279
280         dbus_message_iter_init_append(reply, &array);
281
282         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
283                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
284                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
285                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
286
287         str = type2string(service->type);
288         if (str != NULL)
289                 connman_dbus_dict_append_variant(&dict, "Type",
290                                                 DBUS_TYPE_STRING, &str);
291
292         str = mode2string(service->mode);
293         if (str != NULL)
294                 connman_dbus_dict_append_variant(&dict, "Mode",
295                                                 DBUS_TYPE_STRING, &str);
296
297         str = security2string(service->security);
298         if (str != NULL)
299                 connman_dbus_dict_append_variant(&dict, "Security",
300                                                 DBUS_TYPE_STRING, &str);
301
302         str = state2string(service->state);
303         if (str != NULL)
304                 connman_dbus_dict_append_variant(&dict, "State",
305                                                 DBUS_TYPE_STRING, &str);
306
307         str = error2string(service->error);
308         if (str != NULL)
309                 connman_dbus_dict_append_variant(&dict, "Error",
310                                                 DBUS_TYPE_STRING, &str);
311
312         if (service->strength > 0)
313                 connman_dbus_dict_append_variant(&dict, "Strength",
314                                         DBUS_TYPE_BYTE, &service->strength);
315
316         connman_dbus_dict_append_variant(&dict, "Favorite",
317                                         DBUS_TYPE_BOOLEAN, &service->favorite);
318
319         if (service->name != NULL)
320                 connman_dbus_dict_append_variant(&dict, "Name",
321                                         DBUS_TYPE_STRING, &service->name);
322
323         if (service->passphrase != NULL &&
324                         __connman_security_check_privilege(msg,
325                                 CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
326                 connman_dbus_dict_append_variant(&dict, "Passphrase",
327                                 DBUS_TYPE_STRING, &service->passphrase);
328
329         __connman_ipconfig_append_ipv4(service->ipconfig, &dict, "IPv4.");
330
331         dbus_message_iter_close_container(&array, &dict);
332
333         return reply;
334 }
335
336 static DBusMessage *set_property(DBusConnection *conn,
337                                         DBusMessage *msg, void *user_data)
338 {
339         struct connman_service *service = user_data;
340         DBusMessageIter iter, value;
341         const char *name;
342         int type;
343
344         DBG("service %p", service);
345
346         if (dbus_message_iter_init(msg, &iter) == FALSE)
347                 return __connman_error_invalid_arguments(msg);
348
349         dbus_message_iter_get_basic(&iter, &name);
350         dbus_message_iter_next(&iter);
351         dbus_message_iter_recurse(&iter, &value);
352
353         if (__connman_security_check_privilege(msg,
354                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
355                 return __connman_error_permission_denied(msg);
356
357         type = dbus_message_iter_get_arg_type(&value);
358
359         if (g_str_equal(name, "Passphrase") == TRUE) {
360                 const char *passphrase;
361
362                 if (type != DBUS_TYPE_STRING)
363                         return __connman_error_invalid_arguments(msg);
364
365                 if (__connman_security_check_privilege(msg,
366                                         CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
367                         return __connman_error_permission_denied(msg);
368
369                 dbus_message_iter_get_basic(&value, &passphrase);
370
371                 g_free(service->passphrase);
372                 service->passphrase = g_strdup(passphrase);
373
374                 if (service->network != NULL)
375                         connman_network_set_string(service->network,
376                                 "WiFi.Passphrase", service->passphrase);
377
378                 __connman_storage_save_service(service);
379         } else if (g_str_has_prefix(name, "IPv4.") == TRUE) {
380                 int err;
381
382                 err = __connman_ipconfig_set_ipv4(service->ipconfig,
383                                                         name + 5, &value);
384                 if (err < 0)
385                         return __connman_error_failed(msg, -err);
386         } else
387                 return __connman_error_invalid_property(msg);
388
389         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
390 }
391
392 static DBusMessage *clear_property(DBusConnection *conn,
393                                         DBusMessage *msg, void *user_data)
394 {
395         struct connman_service *service = user_data;
396         const char *name;
397
398         DBG("service %p", service);
399
400         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
401                                                         DBUS_TYPE_INVALID);
402
403         if (__connman_security_check_privilege(msg,
404                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
405                 return __connman_error_permission_denied(msg);
406
407         if (g_str_equal(name, "Error") == TRUE) {
408                 service->state = CONNMAN_SERVICE_STATE_IDLE;
409                 service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
410                 state_changed(service);
411
412                 g_get_current_time(&service->modified);
413                 __connman_storage_save_service(service);
414         } else
415                 return __connman_error_invalid_property(msg);
416
417         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
418 }
419
420 static connman_bool_t is_connecting(struct connman_service *service)
421 {
422         switch (service->state) {
423         case CONNMAN_SERVICE_STATE_UNKNOWN:
424         case CONNMAN_SERVICE_STATE_IDLE:
425         case CONNMAN_SERVICE_STATE_CARRIER:
426         case CONNMAN_SERVICE_STATE_FAILURE:
427         case CONNMAN_SERVICE_STATE_DISCONNECT:
428         case CONNMAN_SERVICE_STATE_READY:
429                 break;
430         case CONNMAN_SERVICE_STATE_ASSOCIATION:
431         case CONNMAN_SERVICE_STATE_CONFIGURATION:
432                 return TRUE;
433         }
434
435         return FALSE;
436 }
437
438 static void __connman_service_auto_connect(void)
439 {
440         struct connman_service *service;
441         GSequenceIter *iter;
442
443         DBG("");
444
445         iter = g_sequence_get_begin_iter(service_list);
446         if (g_sequence_iter_is_end(iter) == TRUE)
447                 return;
448
449         service = g_sequence_get(iter);
450
451         while (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
452                 iter = g_sequence_iter_next(iter);
453                 if (g_sequence_iter_is_end(iter))
454                         return;
455                 service = g_sequence_get(iter);
456         }
457
458         if (service->favorite == FALSE)
459                 return;
460
461         if (service->state == CONNMAN_SERVICE_STATE_READY)
462                 return;
463
464         if (is_connecting(service) == TRUE)
465                 return;
466
467         if (service->state == CONNMAN_SERVICE_STATE_IDLE)
468                 __connman_service_connect(service);
469 }
470
471 static gboolean connect_timeout(gpointer user_data)
472 {
473         struct connman_service *service = user_data;
474
475         DBG("service %p", service);
476
477         service->timeout = 0;
478
479         if (service->network != NULL) {
480                 connman_bool_t connected;
481
482                 connected = connman_network_get_connected(service->network);
483                 if (connected == TRUE) {
484                         __connman_service_indicate_state(service,
485                                                 CONNMAN_SERVICE_STATE_READY);
486                         return FALSE;
487                 }
488
489                 __connman_network_disconnect(service->network);
490         } else if (service->device != NULL) {
491                 connman_bool_t disconnected;
492
493                 disconnected = connman_device_get_disconnected(service->device);
494                 if (disconnected == FALSE) {
495                         __connman_service_indicate_state(service,
496                                                 CONNMAN_SERVICE_STATE_READY);
497                         return FALSE;
498                 }
499
500                 __connman_device_disconnect(service->device);
501         }
502
503         if (service->pending != NULL) {
504                 DBusMessage *reply;
505
506                 reply = __connman_error_operation_timeout(service->pending);
507                 if (reply != NULL)
508                         g_dbus_send_message(connection, reply);
509
510                 dbus_message_unref(service->pending);
511                 service->pending = NULL;
512         }
513
514         __connman_service_indicate_state(service,
515                                         CONNMAN_SERVICE_STATE_FAILURE);
516
517         __connman_service_auto_connect();
518
519         return FALSE;
520 }
521
522 static DBusMessage *connect_service(DBusConnection *conn,
523                                         DBusMessage *msg, void *user_data)
524 {
525         struct connman_service *service = user_data;
526         int err;
527
528         DBG("service %p", service);
529
530         if (service->pending != NULL)
531                 return __connman_error_in_progress(msg);
532
533         service->pending = dbus_message_ref(msg);
534
535         err = __connman_service_connect(service);
536         if (err < 0) {
537                 if (err != -EINPROGRESS) {
538                         dbus_message_unref(service->pending);
539                         service->pending = NULL;
540
541                         return __connman_error_failed(msg, -err);
542                 }
543
544                 return NULL;
545         }
546
547         dbus_message_unref(service->pending);
548         service->pending = NULL;
549
550         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
551 }
552
553 static DBusMessage *disconnect_service(DBusConnection *conn,
554                                         DBusMessage *msg, void *user_data)
555 {
556         struct connman_service *service = user_data;
557         int err;
558
559         DBG("service %p", service);
560
561         if (service->pending != NULL) {
562                 DBusMessage *reply;
563
564                 reply = __connman_error_operation_aborted(service->pending);
565                 if (reply != NULL)
566                         g_dbus_send_message(conn, reply);
567
568                 dbus_message_unref(service->pending);
569                 service->pending = NULL;
570
571                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
572         }
573
574         err = __connman_service_disconnect(service);
575         if (err < 0) {
576                 if (err != -EINPROGRESS)
577                         return __connman_error_failed(msg, -err);
578
579                 return NULL;
580         }
581
582         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
583 }
584
585 static DBusMessage *remove_service(DBusConnection *conn,
586                                         DBusMessage *msg, void *user_data)
587 {
588         struct connman_service *service = user_data;
589
590         DBG("service %p", service);
591
592         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
593                 return __connman_error_not_supported(msg);
594
595         if (service->favorite == FALSE)
596                 return __connman_error_not_supported(msg);
597
598         if (service->network != NULL)
599                 __connman_network_disconnect(service->network);
600
601         g_free(service->passphrase);
602         service->passphrase = NULL;
603
604         connman_service_set_favorite(service, FALSE);
605         __connman_storage_save_service(service);
606
607         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
608 }
609
610 static DBusMessage *move_before(DBusConnection *conn,
611                                         DBusMessage *msg, void *user_data)
612 {
613         struct connman_service *service = user_data;
614         struct connman_service *target;
615         const char *path;
616         GSequenceIter *src, *dst;
617
618         DBG("service %p", service);
619
620         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
621                                                         DBUS_TYPE_INVALID);
622
623         if (service->favorite == FALSE)
624                 return __connman_error_not_supported(msg);
625
626         target = find_service(path);
627         if (target == NULL || target->favorite == FALSE || target == service)
628                 return __connman_error_invalid_service(msg);
629
630         DBG("target %s", target->identifier);
631
632         g_get_current_time(&service->modified);
633         __connman_storage_save_service(service);
634
635         src = g_hash_table_lookup(service_hash, service->identifier);
636         dst = g_hash_table_lookup(service_hash, target->identifier);
637
638         g_sequence_move(src, dst);
639
640         __connman_profile_changed();
641
642         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
643 }
644
645 static DBusMessage *move_after(DBusConnection *conn,
646                                         DBusMessage *msg, void *user_data)
647 {
648         struct connman_service *service = user_data;
649         struct connman_service *target;
650         const char *path;
651
652         DBG("service %p", service);
653
654         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
655                                                         DBUS_TYPE_INVALID);
656
657         if (service->favorite == FALSE)
658                 return __connman_error_not_supported(msg);
659
660         target = find_service(path);
661         if (target == NULL || target->favorite == FALSE || target == service)
662                 return __connman_error_invalid_service(msg);
663
664         DBG("target %s", target->identifier);
665
666         g_get_current_time(&service->modified);
667         __connman_storage_save_service(service);
668
669         return __connman_error_not_implemented(msg);
670 }
671
672 static GDBusMethodTable service_methods[] = {
673         { "GetProperties", "",   "a{sv}", get_properties     },
674         { "SetProperty",   "sv", "",      set_property       },
675         { "ClearProperty", "s",  "",      clear_property     },
676         { "Connect",       "",   "",      connect_service,
677                                                 G_DBUS_METHOD_FLAG_ASYNC },
678         { "Disconnect",    "",   "",      disconnect_service },
679         { "Remove",        "",   "",      remove_service     },
680         { "MoveBefore",    "o",  "",      move_before        },
681         { "MoveAfter",     "o",  "",      move_after         },
682         { },
683 };
684
685 static GDBusSignalTable service_signals[] = {
686         { "PropertyChanged", "sv" },
687         { },
688 };
689
690 static void service_free(gpointer user_data)
691 {
692         struct connman_service *service = user_data;
693         char *path = service->path;
694
695         DBG("service %p", service);
696
697         g_hash_table_remove(service_hash, service->identifier);
698
699         if (service->timeout > 0) {
700                 g_source_remove(service->timeout);
701                 service->timeout = 0;
702         }
703
704         if (service->pending != NULL) {
705                 dbus_message_unref(service->pending);
706                 service->pending = NULL;
707         }
708
709         service->path = NULL;
710
711         if (path != NULL) {
712                 __connman_profile_changed();
713
714                 g_dbus_unregister_interface(connection, path,
715                                                 CONNMAN_SERVICE_INTERFACE);
716                 g_free(path);
717         }
718
719         if (service->network != NULL)
720                 connman_network_unref(service->network);
721
722         connman_ipconfig_unref(service->ipconfig);
723
724         g_free(service->profile);
725         g_free(service->name);
726         g_free(service->passphrase);
727         g_free(service->identifier);
728         g_free(service);
729 }
730
731 /**
732  * __connman_service_put:
733  * @service: service structure
734  *
735  * Release service if no longer needed
736  */
737 void __connman_service_put(struct connman_service *service)
738 {
739         DBG("service %p", service);
740
741         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
742                 GSequenceIter *iter;
743
744                 iter = g_hash_table_lookup(service_hash, service->identifier);
745                 if (iter != NULL)
746                         g_sequence_remove(iter);
747                 else
748                         service_free(service);
749         }
750 }
751
752 static void __connman_service_initialize(struct connman_service *service)
753 {
754         DBG("service %p", service);
755
756         service->refcount = 1;
757
758         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
759         service->mode     = CONNMAN_SERVICE_MODE_UNKNOWN;
760         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
761         service->state    = CONNMAN_SERVICE_STATE_UNKNOWN;
762
763         service->favorite = FALSE;
764         service->hidden = FALSE;
765
766         service->order = 0;
767 }
768
769 /**
770  * connman_service_create:
771  *
772  * Allocate a new service.
773  *
774  * Returns: a newly-allocated #connman_service structure
775  */
776 struct connman_service *connman_service_create(void)
777 {
778         struct connman_service *service;
779
780         service = g_try_new0(struct connman_service, 1);
781         if (service == NULL)
782                 return NULL;
783
784         DBG("service %p", service);
785
786         __connman_service_initialize(service);
787
788         service->ipconfig = connman_ipconfig_create();
789         if (service->ipconfig == NULL) {
790                 g_free(service);
791                 return NULL;
792         }
793
794         connman_ipconfig_set_method(service->ipconfig,
795                                         CONNMAN_IPCONFIG_METHOD_DHCP);
796
797         return service;
798 }
799
800 /**
801  * connman_service_ref:
802  * @service: service structure
803  *
804  * Increase reference counter of service
805  */
806 struct connman_service *connman_service_ref(struct connman_service *service)
807 {
808         g_atomic_int_inc(&service->refcount);
809
810         return service;
811 }
812
813 /**
814  * connman_service_unref:
815  * @service: service structure
816  *
817  * Decrease reference counter of service
818  */
819 void connman_service_unref(struct connman_service *service)
820 {
821         __connman_service_put(service);
822 }
823
824 static gint service_compare(gconstpointer a, gconstpointer b,
825                                                         gpointer user_data)
826 {
827         struct connman_service *service_a = (void *) a;
828         struct connman_service *service_b = (void *) b;
829
830         if (service_a->state != service_b->state) {
831                 if (service_a->state == CONNMAN_SERVICE_STATE_READY)
832                         return -1;
833                 if (service_b->state == CONNMAN_SERVICE_STATE_READY)
834                         return 1;
835         }
836
837         if (service_a->order > service_b->order)
838                 return -1;
839
840         if (service_a->order < service_b->order)
841                 return 1;
842
843         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
844                 return -1;
845
846         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
847                 return 1;
848
849         return (gint) service_b->strength - (gint) service_a->strength;
850 }
851
852 /**
853  * connman_service_set_favorite:
854  * @service: service structure
855  * @favorite: favorite value
856  *
857  * Change the favorite setting of service
858  */
859 int connman_service_set_favorite(struct connman_service *service,
860                                                 connman_bool_t favorite)
861 {
862         GSequenceIter *iter;
863
864         iter = g_hash_table_lookup(service_hash, service->identifier);
865         if (iter == NULL)
866                 return -ENOENT;
867
868         if (service->favorite == favorite)
869                 return -EALREADY;
870
871         service->favorite = favorite;
872
873         g_sequence_sort_changed(iter, service_compare, NULL);
874
875         __connman_profile_changed();
876
877         return 0;
878 }
879
880 int __connman_service_set_carrier(struct connman_service *service,
881                                                 connman_bool_t carrier)
882 {
883         DBG("service %p carrier %d", service, carrier);
884
885         if (service == NULL)
886                 return -EINVAL;
887
888         switch (service->type) {
889         case CONNMAN_SERVICE_TYPE_UNKNOWN:
890         case CONNMAN_SERVICE_TYPE_WIFI:
891         case CONNMAN_SERVICE_TYPE_WIMAX:
892         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
893         case CONNMAN_SERVICE_TYPE_CELLULAR:
894                 return -EINVAL;
895         case CONNMAN_SERVICE_TYPE_ETHERNET:
896                 break;
897         }
898
899         if (carrier == FALSE) {
900                 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
901                 state_changed(service);
902
903                 service->state = CONNMAN_SERVICE_STATE_IDLE;
904                 state_changed(service);
905         } else {
906                 service->state = CONNMAN_SERVICE_STATE_CARRIER;
907                 state_changed(service);
908         }
909
910         return connman_service_set_favorite(service, carrier);
911 }
912
913 int __connman_service_indicate_state(struct connman_service *service,
914                                         enum connman_service_state state)
915 {
916         GSequenceIter *iter;
917
918         DBG("service %p state %d", service, state);
919
920         if (service == NULL)
921                 return -EINVAL;
922
923         if (state == CONNMAN_SERVICE_STATE_CARRIER)
924                 return __connman_service_set_carrier(service, TRUE);
925
926         if (service->state == state)
927                 return -EALREADY;
928
929         if (service->state == CONNMAN_SERVICE_STATE_IDLE &&
930                                 state == CONNMAN_SERVICE_STATE_DISCONNECT)
931                 return -EINVAL;
932
933         if (state == CONNMAN_SERVICE_STATE_IDLE &&
934                         service->state != CONNMAN_SERVICE_STATE_DISCONNECT) {
935                 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
936                 state_changed(service);
937         }
938
939         service->state = state;
940         state_changed(service);
941
942         if (state == CONNMAN_SERVICE_STATE_READY) {
943                 connman_service_set_favorite(service, TRUE);
944
945                 if (service->timeout > 0) {
946                         g_source_remove(service->timeout);
947                         service->timeout = 0;
948                 }
949
950                 if (service->pending != NULL) {
951                         g_dbus_send_reply(connection, service->pending,
952                                                         DBUS_TYPE_INVALID);
953
954                         dbus_message_unref(service->pending);
955                         service->pending = NULL;
956                 }
957
958                 g_get_current_time(&service->modified);
959                 __connman_storage_save_service(service);
960         }
961
962         if (state == CONNMAN_SERVICE_STATE_FAILURE) {
963                 if (service->timeout > 0) {
964                         g_source_remove(service->timeout);
965                         service->timeout = 0;
966                 }
967
968                 if (service->pending != NULL) {
969                         DBusMessage *reply;
970
971                         reply = __connman_error_failed(service->pending, EIO);
972                         if (reply != NULL)
973                                 g_dbus_send_message(connection, reply);
974
975                         dbus_message_unref(service->pending);
976                         service->pending = NULL;
977                 }
978
979                 g_get_current_time(&service->modified);
980                 __connman_storage_save_service(service);
981         } else
982                 service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
983
984         iter = g_hash_table_lookup(service_hash, service->identifier);
985         if (iter != NULL)
986                 g_sequence_sort_changed(iter, service_compare, NULL);
987
988         __connman_profile_changed();
989
990         return 0;
991 }
992
993 int __connman_service_indicate_error(struct connman_service *service,
994                                         enum connman_service_error error)
995 {
996         DBG("service %p error %d", service, error);
997
998         if (service == NULL)
999                 return -EINVAL;
1000
1001         service->error = error;
1002
1003         return __connman_service_indicate_state(service,
1004                                         CONNMAN_SERVICE_STATE_FAILURE);
1005 }
1006
1007 int __connman_service_indicate_default(struct connman_service *service)
1008 {
1009         DBG("service %p", service);
1010
1011         return 0;
1012 }
1013
1014 int __connman_service_connect(struct connman_service *service)
1015 {
1016         int err;
1017
1018         DBG("service %p", service);
1019
1020         if (service->state == CONNMAN_SERVICE_STATE_READY)
1021                 return -EISCONN;
1022
1023         if (service->network != NULL) {
1024                 if (service->hidden == TRUE)
1025                         return -EINVAL;
1026
1027                 connman_network_set_string(service->network,
1028                                 "WiFi.Passphrase", service->passphrase);
1029
1030                 err = __connman_network_connect(service->network);
1031         } else if (service->device != NULL) {
1032                 if (service->favorite == FALSE)
1033                         return -ENOLINK;
1034
1035                 err = __connman_device_connect(service->device);
1036         } else
1037                 return -EOPNOTSUPP;
1038
1039         if (err < 0) {
1040                 if (err != -EINPROGRESS)
1041                         return err;
1042
1043                 service->timeout = g_timeout_add_seconds(45,
1044                                                 connect_timeout, service);
1045
1046                 return -EINPROGRESS;
1047         }
1048
1049         return 0;
1050 }
1051
1052 int __connman_service_disconnect(struct connman_service *service)
1053 {
1054         int err;
1055
1056         DBG("service %p", service);
1057
1058         if (service->network != NULL) {
1059                 err = __connman_network_disconnect(service->network);
1060         } else if (service->device != NULL) {
1061                 if (service->favorite == FALSE)
1062                         return -ENOLINK;
1063                 err = __connman_device_disconnect(service->device);
1064         } else
1065                 return -EOPNOTSUPP;
1066
1067         if (err < 0) {
1068                 if (err != -EINPROGRESS)
1069                         return err;
1070
1071                 return -EINPROGRESS;
1072         }
1073
1074         return 0;
1075 }
1076
1077 /**
1078  * __connman_service_lookup:
1079  * @identifier: service identifier
1080  *
1081  * Look up a service by identifier (reference count will not be increased)
1082  */
1083 static struct connman_service *__connman_service_lookup(const char *identifier)
1084 {
1085         GSequenceIter *iter;
1086
1087         iter = g_hash_table_lookup(service_hash, identifier);
1088         if (iter != NULL)
1089                 return g_sequence_get(iter);
1090
1091         return NULL;
1092 }
1093
1094 /**
1095  * __connman_service_get:
1096  * @identifier: service identifier
1097  *
1098  * Look up a service by identifier or create a new one if not found
1099  */
1100 static struct connman_service *__connman_service_get(const char *identifier)
1101 {
1102         struct connman_service *service;
1103         GSequenceIter *iter;
1104
1105         iter = g_hash_table_lookup(service_hash, identifier);
1106         if (iter != NULL) {
1107                 service = g_sequence_get(iter);
1108                 if (service != NULL)
1109                         g_atomic_int_inc(&service->refcount);
1110                 return service;
1111         }
1112
1113         service = connman_service_create();
1114         if (service == NULL)
1115                 return NULL;
1116
1117         DBG("service %p", service);
1118
1119         service->identifier = g_strdup(identifier);
1120
1121         service->profile = g_strdup(__connman_profile_active_ident());
1122
1123         __connman_storage_load_service(service);
1124
1125         iter = g_sequence_insert_sorted(service_list, service,
1126                                                 service_compare, NULL);
1127
1128         g_hash_table_insert(service_hash, service->identifier, iter);
1129
1130         return service;
1131 }
1132
1133 static int service_register(struct connman_service *service)
1134 {
1135         const char *path = __connman_profile_active_path();
1136         GSequenceIter *iter;
1137
1138         DBG("service %p", service);
1139
1140         if (service->path != NULL)
1141                 return -EALREADY;
1142
1143         service->path = g_strdup_printf("%s/%s", path, service->identifier);
1144
1145         DBG("path %s", service->path);
1146
1147         g_dbus_register_interface(connection, service->path,
1148                                         CONNMAN_SERVICE_INTERFACE,
1149                                         service_methods, service_signals,
1150                                                         NULL, service, NULL);
1151
1152         __connman_storage_load_service(service);
1153
1154         iter = g_hash_table_lookup(service_hash, service->identifier);
1155         if (iter != NULL)
1156                 g_sequence_sort_changed(iter, service_compare, NULL);
1157
1158         __connman_profile_changed();
1159
1160         return 0;
1161 }
1162
1163 /**
1164  * connman_service_lookup_from_device:
1165  * @device: device structure
1166  *
1167  * Look up a service by device (reference count will not be increased)
1168  */
1169 struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
1170 {
1171         struct connman_service *service;
1172         const char *ident;
1173         char *name;
1174
1175         ident = __connman_device_get_ident(device);
1176         if (ident == NULL)
1177                 return NULL;
1178
1179         name = g_strdup_printf("%s_%s",
1180                                 __connman_device_get_type(device), ident);
1181
1182         service = __connman_service_lookup(name);
1183
1184         g_free(name);
1185
1186         return service;
1187 }
1188
1189 static enum connman_service_type convert_device_type(struct connman_device *device)
1190 {
1191         enum connman_device_type type = connman_device_get_type(device);
1192
1193         switch (type) {
1194         case CONNMAN_DEVICE_TYPE_UNKNOWN:
1195         case CONNMAN_DEVICE_TYPE_VENDOR:
1196         case CONNMAN_DEVICE_TYPE_WIFI:
1197         case CONNMAN_DEVICE_TYPE_WIMAX:
1198         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
1199         case CONNMAN_DEVICE_TYPE_GPS:
1200         case CONNMAN_DEVICE_TYPE_MBM:
1201         case CONNMAN_DEVICE_TYPE_HSO:
1202         case CONNMAN_DEVICE_TYPE_NOZOMI:
1203         case CONNMAN_DEVICE_TYPE_HUAWEI:
1204         case CONNMAN_DEVICE_TYPE_NOVATEL:
1205                 break;
1206         case CONNMAN_DEVICE_TYPE_ETHERNET:
1207                 return CONNMAN_SERVICE_TYPE_ETHERNET;
1208         }
1209
1210         return CONNMAN_SERVICE_TYPE_UNKNOWN;
1211 }
1212
1213 /**
1214  * connman_service_create_from_device:
1215  * @device: device structure
1216  *
1217  * Look up service by device and if not found, create one
1218  */
1219 struct connman_service *__connman_service_create_from_device(struct connman_device *device)
1220 {
1221         struct connman_service *service;
1222         const char *ident;
1223         char *name;
1224
1225         ident = __connman_device_get_ident(device);
1226         if (ident == NULL)
1227                 return NULL;
1228
1229         name = g_strdup_printf("%s_%s",
1230                                 __connman_device_get_type(device), ident);
1231
1232         service = __connman_service_get(name);
1233         if (service == NULL)
1234                 goto done;
1235
1236         if (service->path != NULL) {
1237                 __connman_service_put(service);
1238                 service = NULL;
1239                 goto done;
1240         }
1241
1242         service->type = convert_device_type(device);
1243
1244         service->device = device;
1245
1246         service_register(service);
1247
1248         if (service->favorite == TRUE)
1249                 __connman_service_auto_connect();
1250
1251 done:
1252         g_free(name);
1253
1254         return service;
1255 }
1256
1257 /**
1258  * connman_service_lookup_from_network:
1259  * @network: network structure
1260  *
1261  * Look up a service by network (reference count will not be increased)
1262  */
1263 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
1264 {
1265         struct connman_service *service;
1266         const char *ident, *group;
1267         char *name;
1268
1269         ident = __connman_network_get_ident(network);
1270         if (ident == NULL)
1271                 return NULL;
1272
1273         group = __connman_network_get_group(network);
1274         if (group == NULL)
1275                 return NULL;
1276
1277         name = g_strdup_printf("%s_%s_%s",
1278                         __connman_network_get_type(network), ident, group);
1279
1280         service = __connman_service_lookup(name);
1281
1282         g_free(name);
1283
1284         return service;
1285 }
1286
1287 unsigned int __connman_service_get_order(struct connman_service *service)
1288 {
1289         return service->order;
1290 }
1291
1292 static enum connman_service_type convert_network_type(struct connman_network *network)
1293 {
1294         enum connman_network_type type = connman_network_get_type(network);
1295
1296         switch (type) {
1297         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1298         case CONNMAN_NETWORK_TYPE_VENDOR:
1299         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1300         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1301         case CONNMAN_NETWORK_TYPE_HSO:
1302                 break;
1303         case CONNMAN_NETWORK_TYPE_WIFI:
1304                 return CONNMAN_SERVICE_TYPE_WIFI;
1305         case CONNMAN_NETWORK_TYPE_WIMAX:
1306                 return CONNMAN_SERVICE_TYPE_WIMAX;
1307         }
1308
1309         return CONNMAN_SERVICE_TYPE_UNKNOWN;
1310 }
1311
1312 static enum connman_service_mode convert_wifi_mode(const char *mode)
1313 {
1314         if (mode == NULL)
1315                 return CONNMAN_SERVICE_MODE_UNKNOWN;
1316         else if (g_str_equal(mode, "managed") == TRUE)
1317                 return CONNMAN_SERVICE_MODE_MANAGED;
1318         else if (g_str_equal(mode, "adhoc") == TRUE)
1319                 return CONNMAN_SERVICE_MODE_ADHOC;
1320         else
1321                 return CONNMAN_SERVICE_MODE_UNKNOWN;
1322 }
1323
1324 static enum connman_service_mode convert_wifi_security(const char *security)
1325 {
1326         if (security == NULL)
1327                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
1328         else if (g_str_equal(security, "none") == TRUE)
1329                 return CONNMAN_SERVICE_SECURITY_NONE;
1330         else if (g_str_equal(security, "wep") == TRUE)
1331                 return CONNMAN_SERVICE_SECURITY_WEP;
1332         else if (g_str_equal(security, "wpa") == TRUE)
1333                 return CONNMAN_SERVICE_SECURITY_WPA;
1334         else if (g_str_equal(security, "rsn") == TRUE)
1335                 return CONNMAN_SERVICE_SECURITY_RSN;
1336         else
1337                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
1338 }
1339
1340 static void update_from_network(struct connman_service *service,
1341                                         struct connman_network *network)
1342 {
1343         connman_uint8_t strength = service->strength;
1344         GSequenceIter *iter;
1345         const char *str;
1346
1347         str = connman_network_get_string(network, "Name");
1348         if (str != NULL) {
1349                 g_free(service->name);
1350                 service->name = g_strdup(str);
1351                 service->hidden = FALSE;
1352         } else {
1353                 g_free(service->name);
1354                 service->name = NULL;
1355                 service->hidden = TRUE;
1356         }
1357
1358         service->strength = connman_network_get_uint8(network, "Strength");
1359
1360         str = connman_network_get_string(network, "WiFi.Mode");
1361         service->mode = convert_wifi_mode(str);
1362
1363         str = connman_network_get_string(network, "WiFi.Security");
1364         service->security = convert_wifi_security(str);
1365
1366         if (service->strength > strength && service->network != NULL) {
1367                 connman_network_unref(service->network);
1368                 service->network = NULL;
1369
1370                 strength_changed(service);
1371         }
1372
1373         if (service->network == NULL) {
1374                 service->network = connman_network_ref(network);
1375
1376                 str = connman_network_get_string(network, "WiFi.Passphrase");
1377                 if (str != NULL) {
1378                         g_free(service->passphrase);
1379                         service->passphrase = g_strdup(str);
1380                 }
1381         }
1382
1383         iter = g_hash_table_lookup(service_hash, service->identifier);
1384         if (iter != NULL)
1385                 g_sequence_sort_changed(iter, service_compare, NULL);
1386 }
1387
1388 /**
1389  * connman_service_create_from_network:
1390  * @network: network structure
1391  *
1392  * Look up service by network and if not found, create one
1393  */
1394 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
1395 {
1396         struct connman_service *service;
1397         const char *ident, *group;
1398         char *name;
1399
1400         service = __connman_service_lookup_from_network(network);
1401         if (service != NULL) {
1402                 update_from_network(service, network);
1403                 return service;
1404         }
1405
1406         ident = __connman_network_get_ident(network);
1407         if (ident == NULL)
1408                 return NULL;
1409
1410         group = __connman_network_get_group(network);
1411         if (group == NULL)
1412                 return NULL;
1413
1414         name = g_strdup_printf("%s_%s_%s",
1415                         __connman_network_get_type(network), ident, group);
1416
1417         service = __connman_service_get(name);
1418         if (service == NULL)
1419                 goto done;
1420
1421         if (service->path != NULL) {
1422                 update_from_network(service, network);
1423
1424                 __connman_profile_changed();
1425
1426                 __connman_service_put(service);
1427                 service = NULL;
1428                 goto done;
1429         }
1430
1431         service->type = convert_network_type(network);
1432
1433         service->state = CONNMAN_SERVICE_STATE_IDLE;
1434
1435         update_from_network(service, network);
1436
1437         service_register(service);
1438
1439         if (service->favorite == TRUE)
1440                 __connman_service_auto_connect();
1441
1442 done:
1443         g_free(name);
1444
1445         return service;
1446 }
1447
1448 static int service_load(struct connman_service *service)
1449 {
1450         GKeyFile *keyfile;
1451         gchar *pathname, *data = NULL;
1452         gsize length;
1453         gchar *str;
1454
1455         DBG("service %p", service);
1456
1457         if (service->profile == NULL)
1458                 return -EINVAL;
1459
1460         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile);
1461         if (pathname == NULL)
1462                 return -ENOMEM;
1463
1464         keyfile = g_key_file_new();
1465
1466         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1467                 g_free(pathname);
1468                 return -ENOENT;
1469         }
1470
1471         g_free(pathname);
1472
1473         if (g_key_file_load_from_data(keyfile, data, length,
1474                                                         0, NULL) == FALSE) {
1475                 g_free(data);
1476                 return -EILSEQ;
1477         }
1478
1479         g_free(data);
1480
1481         switch (service->type) {
1482         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1483         case CONNMAN_SERVICE_TYPE_ETHERNET:
1484                 break;
1485         case CONNMAN_SERVICE_TYPE_WIFI:
1486         case CONNMAN_SERVICE_TYPE_WIMAX:
1487         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1488         case CONNMAN_SERVICE_TYPE_CELLULAR:
1489                 service->favorite = g_key_file_get_boolean(keyfile,
1490                                 service->identifier, "Favorite", NULL);
1491
1492                 str = g_key_file_get_string(keyfile,
1493                                 service->identifier, "Failure", NULL);
1494                 if (str != NULL) {
1495                         service->state = CONNMAN_SERVICE_STATE_FAILURE;
1496                         service->error = string2error(str);
1497                 }
1498                 break;
1499         }
1500
1501         str = g_key_file_get_string(keyfile,
1502                                 service->identifier, "Modified", NULL);
1503         if (str != NULL) {
1504                 g_time_val_from_iso8601(str, &service->modified);
1505                 g_free(str);
1506         }
1507
1508         str = g_key_file_get_string(keyfile,
1509                                 service->identifier, "Passphrase", NULL);
1510         if (str != NULL) {
1511                 g_free(service->passphrase);
1512                 service->passphrase = str;
1513         }
1514
1515         __connman_ipconfig_load(service->ipconfig, keyfile,
1516                                         service->identifier, "IPv4.");
1517
1518         g_key_file_free(keyfile);
1519
1520         return 0;
1521 }
1522
1523 static int service_save(struct connman_service *service)
1524 {
1525         GKeyFile *keyfile;
1526         gchar *pathname, *data = NULL;
1527         gsize length;
1528         gchar *str;
1529
1530         DBG("service %p", service);
1531
1532         if (service->profile == NULL)
1533                 return -EINVAL;
1534
1535         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile);
1536         if (pathname == NULL)
1537                 return -ENOMEM;
1538
1539         keyfile = g_key_file_new();
1540
1541         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1542                 goto update;
1543
1544         if (length > 0) {
1545                 if (g_key_file_load_from_data(keyfile, data, length,
1546                                                         0, NULL) == FALSE)
1547                         goto done;
1548         }
1549
1550         g_free(data);
1551
1552 update:
1553         if (service->name != NULL)
1554                 g_key_file_set_string(keyfile, service->identifier,
1555                                                 "Name", service->name);
1556
1557         switch (service->type) {
1558         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1559         case CONNMAN_SERVICE_TYPE_ETHERNET:
1560                 break;
1561         case CONNMAN_SERVICE_TYPE_WIFI:
1562         case CONNMAN_SERVICE_TYPE_WIMAX:
1563         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1564         case CONNMAN_SERVICE_TYPE_CELLULAR:
1565                 g_key_file_set_boolean(keyfile, service->identifier,
1566                                         "Favorite", service->favorite);
1567
1568                 if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
1569                         const char *failure = error2string(service->error);
1570                         if (failure != NULL)
1571                                 g_key_file_set_string(keyfile,
1572                                                         service->identifier,
1573                                                         "Failure", failure);
1574                 } else {
1575                         g_key_file_remove_key(keyfile, service->identifier,
1576                                                         "Failure", NULL);
1577                 }
1578                 break;
1579         }
1580
1581         str = g_time_val_to_iso8601(&service->modified);
1582         if (str != NULL) {
1583                 g_key_file_set_string(keyfile, service->identifier,
1584                                                         "Modified", str);
1585                 g_free(str);
1586         }
1587
1588         if (service->passphrase != NULL)
1589                 g_key_file_set_string(keyfile, service->identifier,
1590                                         "Passphrase", service->passphrase);
1591         else
1592                 g_key_file_remove_key(keyfile, service->identifier,
1593                                                         "Passphrase", NULL);
1594
1595         __connman_ipconfig_save(service->ipconfig, keyfile,
1596                                         service->identifier, "IPv4.");
1597
1598         data = g_key_file_to_data(keyfile, &length, NULL);
1599
1600         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
1601                 connman_error("Failed to store service information");
1602
1603 done:
1604         g_free(data);
1605
1606         g_key_file_free(keyfile);
1607
1608         g_free(pathname);
1609
1610         return 0;
1611 }
1612
1613 static struct connman_storage service_storage = {
1614         .name           = "service",
1615         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1616         .service_load   = service_load,
1617         .service_save   = service_save,
1618 };
1619
1620 int __connman_service_init(void)
1621 {
1622         DBG("");
1623
1624         connection = connman_dbus_get_connection();
1625
1626         if (connman_storage_register(&service_storage) < 0)
1627                 connman_error("Failed to register service storage");
1628
1629         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1630                                                                 NULL, NULL);
1631
1632         service_list = g_sequence_new(service_free);
1633
1634         return 0;
1635 }
1636
1637 void __connman_service_cleanup(void)
1638 {
1639         DBG("");
1640
1641         g_sequence_free(service_list);
1642         service_list = NULL;
1643
1644         g_hash_table_destroy(service_hash);
1645         service_hash = NULL;
1646
1647         connman_storage_unregister(&service_storage);
1648
1649         dbus_connection_unref(connection);
1650 }