Don't trigger auto-connect when connection attempt is pending
[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 struct connman_service *find_pending_service(void)
439 {
440         struct connman_service *service;
441         GSequenceIter *iter;
442
443         iter = g_sequence_get_begin_iter(service_list);
444
445         while (g_sequence_iter_is_end(iter) == FALSE) {
446                 service = g_sequence_get(iter);
447                 if (service->pending != NULL)
448                         return service;
449
450                 iter = g_sequence_iter_next(iter);
451         }
452
453         return NULL;
454 }
455
456 static void __connman_service_auto_connect(void)
457 {
458         struct connman_service *service;
459         GSequenceIter *iter;
460
461         DBG("");
462
463         service = find_pending_service();
464         if (service != NULL)
465                 return;
466
467         iter = g_sequence_get_begin_iter(service_list);
468         if (g_sequence_iter_is_end(iter) == TRUE)
469                 return;
470
471         service = g_sequence_get(iter);
472
473         while (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
474                 iter = g_sequence_iter_next(iter);
475                 if (g_sequence_iter_is_end(iter))
476                         return;
477                 service = g_sequence_get(iter);
478         }
479
480         if (service->favorite == FALSE)
481                 return;
482
483         if (service->state == CONNMAN_SERVICE_STATE_READY)
484                 return;
485
486         if (is_connecting(service) == TRUE)
487                 return;
488
489         if (service->state == CONNMAN_SERVICE_STATE_IDLE)
490                 __connman_service_connect(service);
491 }
492
493 static gboolean connect_timeout(gpointer user_data)
494 {
495         struct connman_service *service = user_data;
496         connman_bool_t auto_connect = FALSE;
497
498         DBG("service %p", service);
499
500         service->timeout = 0;
501
502         if (service->network != NULL) {
503                 connman_bool_t connected;
504
505                 connected = connman_network_get_connected(service->network);
506                 if (connected == TRUE) {
507                         __connman_service_indicate_state(service,
508                                                 CONNMAN_SERVICE_STATE_READY);
509                         return FALSE;
510                 }
511
512                 __connman_network_disconnect(service->network);
513         } else if (service->device != NULL) {
514                 connman_bool_t disconnected;
515
516                 disconnected = connman_device_get_disconnected(service->device);
517                 if (disconnected == FALSE) {
518                         __connman_service_indicate_state(service,
519                                                 CONNMAN_SERVICE_STATE_READY);
520                         return FALSE;
521                 }
522
523                 __connman_device_disconnect(service->device);
524         }
525
526         if (service->pending != NULL) {
527                 DBusMessage *reply;
528
529                 reply = __connman_error_operation_timeout(service->pending);
530                 if (reply != NULL)
531                         g_dbus_send_message(connection, reply);
532
533                 dbus_message_unref(service->pending);
534                 service->pending = NULL;
535         } else
536                 auto_connect = TRUE;
537
538         __connman_service_indicate_state(service,
539                                         CONNMAN_SERVICE_STATE_FAILURE);
540
541         if (auto_connect == TRUE)
542                 __connman_service_auto_connect();
543
544         return FALSE;
545 }
546
547 static DBusMessage *connect_service(DBusConnection *conn,
548                                         DBusMessage *msg, void *user_data)
549 {
550         struct connman_service *service = user_data;
551         int err;
552
553         DBG("service %p", service);
554
555         if (service->pending != NULL)
556                 return __connman_error_in_progress(msg);
557
558         service->pending = dbus_message_ref(msg);
559
560         err = __connman_service_connect(service);
561         if (err < 0) {
562                 if (err != -EINPROGRESS) {
563                         dbus_message_unref(service->pending);
564                         service->pending = NULL;
565
566                         return __connman_error_failed(msg, -err);
567                 }
568
569                 return NULL;
570         }
571
572         dbus_message_unref(service->pending);
573         service->pending = NULL;
574
575         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
576 }
577
578 static DBusMessage *disconnect_service(DBusConnection *conn,
579                                         DBusMessage *msg, void *user_data)
580 {
581         struct connman_service *service = user_data;
582         int err;
583
584         DBG("service %p", service);
585
586         if (service->pending != NULL) {
587                 DBusMessage *reply;
588
589                 reply = __connman_error_operation_aborted(service->pending);
590                 if (reply != NULL)
591                         g_dbus_send_message(conn, reply);
592
593                 dbus_message_unref(service->pending);
594                 service->pending = NULL;
595
596                 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
597         }
598
599         err = __connman_service_disconnect(service);
600         if (err < 0) {
601                 if (err != -EINPROGRESS)
602                         return __connman_error_failed(msg, -err);
603
604                 return NULL;
605         }
606
607         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
608 }
609
610 static DBusMessage *remove_service(DBusConnection *conn,
611                                         DBusMessage *msg, void *user_data)
612 {
613         struct connman_service *service = user_data;
614
615         DBG("service %p", service);
616
617         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
618                 return __connman_error_not_supported(msg);
619
620         if (service->favorite == FALSE)
621                 return __connman_error_not_supported(msg);
622
623         if (service->network != NULL)
624                 __connman_network_disconnect(service->network);
625
626         g_free(service->passphrase);
627         service->passphrase = NULL;
628
629         connman_service_set_favorite(service, FALSE);
630         __connman_storage_save_service(service);
631
632         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
633 }
634
635 static DBusMessage *move_before(DBusConnection *conn,
636                                         DBusMessage *msg, void *user_data)
637 {
638         struct connman_service *service = user_data;
639         struct connman_service *target;
640         const char *path;
641         GSequenceIter *src, *dst;
642
643         DBG("service %p", service);
644
645         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
646                                                         DBUS_TYPE_INVALID);
647
648         if (service->favorite == FALSE)
649                 return __connman_error_not_supported(msg);
650
651         target = find_service(path);
652         if (target == NULL || target->favorite == FALSE || target == service)
653                 return __connman_error_invalid_service(msg);
654
655         DBG("target %s", target->identifier);
656
657         g_get_current_time(&service->modified);
658         __connman_storage_save_service(service);
659
660         src = g_hash_table_lookup(service_hash, service->identifier);
661         dst = g_hash_table_lookup(service_hash, target->identifier);
662
663         g_sequence_move(src, dst);
664
665         __connman_profile_changed();
666
667         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
668 }
669
670 static DBusMessage *move_after(DBusConnection *conn,
671                                         DBusMessage *msg, void *user_data)
672 {
673         struct connman_service *service = user_data;
674         struct connman_service *target;
675         const char *path;
676
677         DBG("service %p", service);
678
679         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
680                                                         DBUS_TYPE_INVALID);
681
682         if (service->favorite == FALSE)
683                 return __connman_error_not_supported(msg);
684
685         target = find_service(path);
686         if (target == NULL || target->favorite == FALSE || target == service)
687                 return __connman_error_invalid_service(msg);
688
689         DBG("target %s", target->identifier);
690
691         g_get_current_time(&service->modified);
692         __connman_storage_save_service(service);
693
694         return __connman_error_not_implemented(msg);
695 }
696
697 static GDBusMethodTable service_methods[] = {
698         { "GetProperties", "",   "a{sv}", get_properties     },
699         { "SetProperty",   "sv", "",      set_property       },
700         { "ClearProperty", "s",  "",      clear_property     },
701         { "Connect",       "",   "",      connect_service,
702                                                 G_DBUS_METHOD_FLAG_ASYNC },
703         { "Disconnect",    "",   "",      disconnect_service },
704         { "Remove",        "",   "",      remove_service     },
705         { "MoveBefore",    "o",  "",      move_before        },
706         { "MoveAfter",     "o",  "",      move_after         },
707         { },
708 };
709
710 static GDBusSignalTable service_signals[] = {
711         { "PropertyChanged", "sv" },
712         { },
713 };
714
715 static void service_free(gpointer user_data)
716 {
717         struct connman_service *service = user_data;
718         char *path = service->path;
719
720         DBG("service %p", service);
721
722         g_hash_table_remove(service_hash, service->identifier);
723
724         if (service->timeout > 0) {
725                 g_source_remove(service->timeout);
726                 service->timeout = 0;
727         }
728
729         if (service->pending != NULL) {
730                 dbus_message_unref(service->pending);
731                 service->pending = NULL;
732         }
733
734         service->path = NULL;
735
736         if (path != NULL) {
737                 __connman_profile_changed();
738
739                 g_dbus_unregister_interface(connection, path,
740                                                 CONNMAN_SERVICE_INTERFACE);
741                 g_free(path);
742         }
743
744         if (service->network != NULL)
745                 connman_network_unref(service->network);
746
747         connman_ipconfig_unref(service->ipconfig);
748
749         g_free(service->profile);
750         g_free(service->name);
751         g_free(service->passphrase);
752         g_free(service->identifier);
753         g_free(service);
754 }
755
756 /**
757  * __connman_service_put:
758  * @service: service structure
759  *
760  * Release service if no longer needed
761  */
762 void __connman_service_put(struct connman_service *service)
763 {
764         DBG("service %p", service);
765
766         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
767                 GSequenceIter *iter;
768
769                 iter = g_hash_table_lookup(service_hash, service->identifier);
770                 if (iter != NULL)
771                         g_sequence_remove(iter);
772                 else
773                         service_free(service);
774         }
775 }
776
777 static void __connman_service_initialize(struct connman_service *service)
778 {
779         DBG("service %p", service);
780
781         service->refcount = 1;
782
783         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
784         service->mode     = CONNMAN_SERVICE_MODE_UNKNOWN;
785         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
786         service->state    = CONNMAN_SERVICE_STATE_UNKNOWN;
787
788         service->favorite = FALSE;
789         service->hidden = FALSE;
790
791         service->order = 0;
792 }
793
794 /**
795  * connman_service_create:
796  *
797  * Allocate a new service.
798  *
799  * Returns: a newly-allocated #connman_service structure
800  */
801 struct connman_service *connman_service_create(void)
802 {
803         struct connman_service *service;
804
805         service = g_try_new0(struct connman_service, 1);
806         if (service == NULL)
807                 return NULL;
808
809         DBG("service %p", service);
810
811         __connman_service_initialize(service);
812
813         service->ipconfig = connman_ipconfig_create();
814         if (service->ipconfig == NULL) {
815                 g_free(service);
816                 return NULL;
817         }
818
819         connman_ipconfig_set_method(service->ipconfig,
820                                         CONNMAN_IPCONFIG_METHOD_DHCP);
821
822         return service;
823 }
824
825 /**
826  * connman_service_ref:
827  * @service: service structure
828  *
829  * Increase reference counter of service
830  */
831 struct connman_service *connman_service_ref(struct connman_service *service)
832 {
833         g_atomic_int_inc(&service->refcount);
834
835         return service;
836 }
837
838 /**
839  * connman_service_unref:
840  * @service: service structure
841  *
842  * Decrease reference counter of service
843  */
844 void connman_service_unref(struct connman_service *service)
845 {
846         __connman_service_put(service);
847 }
848
849 static gint service_compare(gconstpointer a, gconstpointer b,
850                                                         gpointer user_data)
851 {
852         struct connman_service *service_a = (void *) a;
853         struct connman_service *service_b = (void *) b;
854
855         if (service_a->state != service_b->state) {
856                 if (service_a->state == CONNMAN_SERVICE_STATE_READY)
857                         return -1;
858                 if (service_b->state == CONNMAN_SERVICE_STATE_READY)
859                         return 1;
860         }
861
862         if (service_a->order > service_b->order)
863                 return -1;
864
865         if (service_a->order < service_b->order)
866                 return 1;
867
868         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
869                 return -1;
870
871         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
872                 return 1;
873
874         return (gint) service_b->strength - (gint) service_a->strength;
875 }
876
877 /**
878  * connman_service_set_favorite:
879  * @service: service structure
880  * @favorite: favorite value
881  *
882  * Change the favorite setting of service
883  */
884 int connman_service_set_favorite(struct connman_service *service,
885                                                 connman_bool_t favorite)
886 {
887         GSequenceIter *iter;
888
889         iter = g_hash_table_lookup(service_hash, service->identifier);
890         if (iter == NULL)
891                 return -ENOENT;
892
893         if (service->favorite == favorite)
894                 return -EALREADY;
895
896         service->favorite = favorite;
897
898         g_sequence_sort_changed(iter, service_compare, NULL);
899
900         __connman_profile_changed();
901
902         return 0;
903 }
904
905 int __connman_service_set_carrier(struct connman_service *service,
906                                                 connman_bool_t carrier)
907 {
908         DBG("service %p carrier %d", service, carrier);
909
910         if (service == NULL)
911                 return -EINVAL;
912
913         switch (service->type) {
914         case CONNMAN_SERVICE_TYPE_UNKNOWN:
915         case CONNMAN_SERVICE_TYPE_WIFI:
916         case CONNMAN_SERVICE_TYPE_WIMAX:
917         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
918         case CONNMAN_SERVICE_TYPE_CELLULAR:
919                 return -EINVAL;
920         case CONNMAN_SERVICE_TYPE_ETHERNET:
921                 break;
922         }
923
924         if (carrier == FALSE) {
925                 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
926                 state_changed(service);
927
928                 service->state = CONNMAN_SERVICE_STATE_IDLE;
929                 state_changed(service);
930         } else {
931                 service->state = CONNMAN_SERVICE_STATE_CARRIER;
932                 state_changed(service);
933         }
934
935         return connman_service_set_favorite(service, carrier);
936 }
937
938 int __connman_service_indicate_state(struct connman_service *service,
939                                         enum connman_service_state state)
940 {
941         GSequenceIter *iter;
942
943         DBG("service %p state %d", service, state);
944
945         if (service == NULL)
946                 return -EINVAL;
947
948         if (state == CONNMAN_SERVICE_STATE_CARRIER)
949                 return __connman_service_set_carrier(service, TRUE);
950
951         if (service->state == state)
952                 return -EALREADY;
953
954         if (service->state == CONNMAN_SERVICE_STATE_IDLE &&
955                                 state == CONNMAN_SERVICE_STATE_DISCONNECT)
956                 return -EINVAL;
957
958         if (state == CONNMAN_SERVICE_STATE_IDLE &&
959                         service->state != CONNMAN_SERVICE_STATE_DISCONNECT) {
960                 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
961                 state_changed(service);
962         }
963
964         service->state = state;
965         state_changed(service);
966
967         if (state == CONNMAN_SERVICE_STATE_READY) {
968                 connman_service_set_favorite(service, TRUE);
969
970                 if (service->timeout > 0) {
971                         g_source_remove(service->timeout);
972                         service->timeout = 0;
973                 }
974
975                 if (service->pending != NULL) {
976                         g_dbus_send_reply(connection, service->pending,
977                                                         DBUS_TYPE_INVALID);
978
979                         dbus_message_unref(service->pending);
980                         service->pending = NULL;
981                 }
982
983                 g_get_current_time(&service->modified);
984                 __connman_storage_save_service(service);
985         }
986
987         if (state == CONNMAN_SERVICE_STATE_FAILURE) {
988                 if (service->timeout > 0) {
989                         g_source_remove(service->timeout);
990                         service->timeout = 0;
991                 }
992
993                 if (service->pending != NULL) {
994                         DBusMessage *reply;
995
996                         reply = __connman_error_failed(service->pending, EIO);
997                         if (reply != NULL)
998                                 g_dbus_send_message(connection, reply);
999
1000                         dbus_message_unref(service->pending);
1001                         service->pending = NULL;
1002                 }
1003
1004                 g_get_current_time(&service->modified);
1005                 __connman_storage_save_service(service);
1006         } else
1007                 service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
1008
1009         iter = g_hash_table_lookup(service_hash, service->identifier);
1010         if (iter != NULL)
1011                 g_sequence_sort_changed(iter, service_compare, NULL);
1012
1013         __connman_profile_changed();
1014
1015         return 0;
1016 }
1017
1018 int __connman_service_indicate_error(struct connman_service *service,
1019                                         enum connman_service_error error)
1020 {
1021         DBG("service %p error %d", service, error);
1022
1023         if (service == NULL)
1024                 return -EINVAL;
1025
1026         service->error = error;
1027
1028         return __connman_service_indicate_state(service,
1029                                         CONNMAN_SERVICE_STATE_FAILURE);
1030 }
1031
1032 int __connman_service_indicate_default(struct connman_service *service)
1033 {
1034         DBG("service %p", service);
1035
1036         return 0;
1037 }
1038
1039 int __connman_service_connect(struct connman_service *service)
1040 {
1041         int err;
1042
1043         DBG("service %p", service);
1044
1045         if (service->state == CONNMAN_SERVICE_STATE_READY)
1046                 return -EISCONN;
1047
1048         if (service->network != NULL) {
1049                 if (service->hidden == TRUE)
1050                         return -EINVAL;
1051
1052                 connman_network_set_string(service->network,
1053                                 "WiFi.Passphrase", service->passphrase);
1054
1055                 err = __connman_network_connect(service->network);
1056         } else if (service->device != NULL) {
1057                 if (service->favorite == FALSE)
1058                         return -ENOLINK;
1059
1060                 err = __connman_device_connect(service->device);
1061         } else
1062                 return -EOPNOTSUPP;
1063
1064         if (err < 0) {
1065                 if (err != -EINPROGRESS)
1066                         return err;
1067
1068                 service->timeout = g_timeout_add_seconds(45,
1069                                                 connect_timeout, service);
1070
1071                 return -EINPROGRESS;
1072         }
1073
1074         return 0;
1075 }
1076
1077 int __connman_service_disconnect(struct connman_service *service)
1078 {
1079         int err;
1080
1081         DBG("service %p", service);
1082
1083         if (service->network != NULL) {
1084                 err = __connman_network_disconnect(service->network);
1085         } else if (service->device != NULL) {
1086                 if (service->favorite == FALSE)
1087                         return -ENOLINK;
1088                 err = __connman_device_disconnect(service->device);
1089         } else
1090                 return -EOPNOTSUPP;
1091
1092         if (err < 0) {
1093                 if (err != -EINPROGRESS)
1094                         return err;
1095
1096                 return -EINPROGRESS;
1097         }
1098
1099         return 0;
1100 }
1101
1102 /**
1103  * __connman_service_lookup:
1104  * @identifier: service identifier
1105  *
1106  * Look up a service by identifier (reference count will not be increased)
1107  */
1108 static struct connman_service *__connman_service_lookup(const char *identifier)
1109 {
1110         GSequenceIter *iter;
1111
1112         iter = g_hash_table_lookup(service_hash, identifier);
1113         if (iter != NULL)
1114                 return g_sequence_get(iter);
1115
1116         return NULL;
1117 }
1118
1119 /**
1120  * __connman_service_get:
1121  * @identifier: service identifier
1122  *
1123  * Look up a service by identifier or create a new one if not found
1124  */
1125 static struct connman_service *__connman_service_get(const char *identifier)
1126 {
1127         struct connman_service *service;
1128         GSequenceIter *iter;
1129
1130         iter = g_hash_table_lookup(service_hash, identifier);
1131         if (iter != NULL) {
1132                 service = g_sequence_get(iter);
1133                 if (service != NULL)
1134                         g_atomic_int_inc(&service->refcount);
1135                 return service;
1136         }
1137
1138         service = connman_service_create();
1139         if (service == NULL)
1140                 return NULL;
1141
1142         DBG("service %p", service);
1143
1144         service->identifier = g_strdup(identifier);
1145
1146         service->profile = g_strdup(__connman_profile_active_ident());
1147
1148         __connman_storage_load_service(service);
1149
1150         iter = g_sequence_insert_sorted(service_list, service,
1151                                                 service_compare, NULL);
1152
1153         g_hash_table_insert(service_hash, service->identifier, iter);
1154
1155         return service;
1156 }
1157
1158 static int service_register(struct connman_service *service)
1159 {
1160         const char *path = __connman_profile_active_path();
1161         GSequenceIter *iter;
1162
1163         DBG("service %p", service);
1164
1165         if (service->path != NULL)
1166                 return -EALREADY;
1167
1168         service->path = g_strdup_printf("%s/%s", path, service->identifier);
1169
1170         DBG("path %s", service->path);
1171
1172         g_dbus_register_interface(connection, service->path,
1173                                         CONNMAN_SERVICE_INTERFACE,
1174                                         service_methods, service_signals,
1175                                                         NULL, service, NULL);
1176
1177         __connman_storage_load_service(service);
1178
1179         iter = g_hash_table_lookup(service_hash, service->identifier);
1180         if (iter != NULL)
1181                 g_sequence_sort_changed(iter, service_compare, NULL);
1182
1183         __connman_profile_changed();
1184
1185         return 0;
1186 }
1187
1188 /**
1189  * connman_service_lookup_from_device:
1190  * @device: device structure
1191  *
1192  * Look up a service by device (reference count will not be increased)
1193  */
1194 struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
1195 {
1196         struct connman_service *service;
1197         const char *ident;
1198         char *name;
1199
1200         ident = __connman_device_get_ident(device);
1201         if (ident == NULL)
1202                 return NULL;
1203
1204         name = g_strdup_printf("%s_%s",
1205                                 __connman_device_get_type(device), ident);
1206
1207         service = __connman_service_lookup(name);
1208
1209         g_free(name);
1210
1211         return service;
1212 }
1213
1214 static enum connman_service_type convert_device_type(struct connman_device *device)
1215 {
1216         enum connman_device_type type = connman_device_get_type(device);
1217
1218         switch (type) {
1219         case CONNMAN_DEVICE_TYPE_UNKNOWN:
1220         case CONNMAN_DEVICE_TYPE_VENDOR:
1221         case CONNMAN_DEVICE_TYPE_WIFI:
1222         case CONNMAN_DEVICE_TYPE_WIMAX:
1223         case CONNMAN_DEVICE_TYPE_BLUETOOTH:
1224         case CONNMAN_DEVICE_TYPE_GPS:
1225         case CONNMAN_DEVICE_TYPE_MBM:
1226         case CONNMAN_DEVICE_TYPE_HSO:
1227         case CONNMAN_DEVICE_TYPE_NOZOMI:
1228         case CONNMAN_DEVICE_TYPE_HUAWEI:
1229         case CONNMAN_DEVICE_TYPE_NOVATEL:
1230                 break;
1231         case CONNMAN_DEVICE_TYPE_ETHERNET:
1232                 return CONNMAN_SERVICE_TYPE_ETHERNET;
1233         }
1234
1235         return CONNMAN_SERVICE_TYPE_UNKNOWN;
1236 }
1237
1238 /**
1239  * connman_service_create_from_device:
1240  * @device: device structure
1241  *
1242  * Look up service by device and if not found, create one
1243  */
1244 struct connman_service *__connman_service_create_from_device(struct connman_device *device)
1245 {
1246         struct connman_service *service;
1247         const char *ident;
1248         char *name;
1249
1250         ident = __connman_device_get_ident(device);
1251         if (ident == NULL)
1252                 return NULL;
1253
1254         name = g_strdup_printf("%s_%s",
1255                                 __connman_device_get_type(device), ident);
1256
1257         service = __connman_service_get(name);
1258         if (service == NULL)
1259                 goto done;
1260
1261         if (service->path != NULL) {
1262                 __connman_service_put(service);
1263                 service = NULL;
1264                 goto done;
1265         }
1266
1267         service->type = convert_device_type(device);
1268
1269         service->device = device;
1270
1271         service_register(service);
1272
1273         if (service->favorite == TRUE)
1274                 __connman_service_auto_connect();
1275
1276 done:
1277         g_free(name);
1278
1279         return service;
1280 }
1281
1282 /**
1283  * connman_service_lookup_from_network:
1284  * @network: network structure
1285  *
1286  * Look up a service by network (reference count will not be increased)
1287  */
1288 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
1289 {
1290         struct connman_service *service;
1291         const char *ident, *group;
1292         char *name;
1293
1294         ident = __connman_network_get_ident(network);
1295         if (ident == NULL)
1296                 return NULL;
1297
1298         group = __connman_network_get_group(network);
1299         if (group == NULL)
1300                 return NULL;
1301
1302         name = g_strdup_printf("%s_%s_%s",
1303                         __connman_network_get_type(network), ident, group);
1304
1305         service = __connman_service_lookup(name);
1306
1307         g_free(name);
1308
1309         return service;
1310 }
1311
1312 unsigned int __connman_service_get_order(struct connman_service *service)
1313 {
1314         if (service == NULL)
1315                 return 0;
1316
1317         return service->order;
1318 }
1319
1320 static enum connman_service_type convert_network_type(struct connman_network *network)
1321 {
1322         enum connman_network_type type = connman_network_get_type(network);
1323
1324         switch (type) {
1325         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1326         case CONNMAN_NETWORK_TYPE_VENDOR:
1327         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1328         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1329         case CONNMAN_NETWORK_TYPE_HSO:
1330                 break;
1331         case CONNMAN_NETWORK_TYPE_WIFI:
1332                 return CONNMAN_SERVICE_TYPE_WIFI;
1333         case CONNMAN_NETWORK_TYPE_WIMAX:
1334                 return CONNMAN_SERVICE_TYPE_WIMAX;
1335         }
1336
1337         return CONNMAN_SERVICE_TYPE_UNKNOWN;
1338 }
1339
1340 static enum connman_service_mode convert_wifi_mode(const char *mode)
1341 {
1342         if (mode == NULL)
1343                 return CONNMAN_SERVICE_MODE_UNKNOWN;
1344         else if (g_str_equal(mode, "managed") == TRUE)
1345                 return CONNMAN_SERVICE_MODE_MANAGED;
1346         else if (g_str_equal(mode, "adhoc") == TRUE)
1347                 return CONNMAN_SERVICE_MODE_ADHOC;
1348         else
1349                 return CONNMAN_SERVICE_MODE_UNKNOWN;
1350 }
1351
1352 static enum connman_service_mode convert_wifi_security(const char *security)
1353 {
1354         if (security == NULL)
1355                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
1356         else if (g_str_equal(security, "none") == TRUE)
1357                 return CONNMAN_SERVICE_SECURITY_NONE;
1358         else if (g_str_equal(security, "wep") == TRUE)
1359                 return CONNMAN_SERVICE_SECURITY_WEP;
1360         else if (g_str_equal(security, "wpa") == TRUE)
1361                 return CONNMAN_SERVICE_SECURITY_WPA;
1362         else if (g_str_equal(security, "rsn") == TRUE)
1363                 return CONNMAN_SERVICE_SECURITY_RSN;
1364         else
1365                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
1366 }
1367
1368 static void update_from_network(struct connman_service *service,
1369                                         struct connman_network *network)
1370 {
1371         connman_uint8_t strength = service->strength;
1372         GSequenceIter *iter;
1373         const char *str;
1374
1375         if (service->state == CONNMAN_SERVICE_STATE_READY)
1376                 return;
1377
1378         if (is_connecting(service) == TRUE)
1379                 return;
1380
1381         str = connman_network_get_string(network, "Name");
1382         if (str != NULL) {
1383                 g_free(service->name);
1384                 service->name = g_strdup(str);
1385                 service->hidden = FALSE;
1386         } else {
1387                 g_free(service->name);
1388                 service->name = NULL;
1389                 service->hidden = TRUE;
1390         }
1391
1392         service->strength = connman_network_get_uint8(network, "Strength");
1393
1394         str = connman_network_get_string(network, "WiFi.Mode");
1395         service->mode = convert_wifi_mode(str);
1396
1397         str = connman_network_get_string(network, "WiFi.Security");
1398         service->security = convert_wifi_security(str);
1399
1400         if (service->strength > strength && service->network != NULL) {
1401                 connman_network_unref(service->network);
1402                 service->network = NULL;
1403
1404                 strength_changed(service);
1405         }
1406
1407         if (service->network == NULL) {
1408                 service->network = connman_network_ref(network);
1409
1410                 str = connman_network_get_string(network, "WiFi.Passphrase");
1411                 if (str != NULL) {
1412                         g_free(service->passphrase);
1413                         service->passphrase = g_strdup(str);
1414                 }
1415         }
1416
1417         iter = g_hash_table_lookup(service_hash, service->identifier);
1418         if (iter != NULL)
1419                 g_sequence_sort_changed(iter, service_compare, NULL);
1420 }
1421
1422 /**
1423  * connman_service_create_from_network:
1424  * @network: network structure
1425  *
1426  * Look up service by network and if not found, create one
1427  */
1428 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
1429 {
1430         struct connman_service *service;
1431         const char *ident, *group;
1432         char *name;
1433
1434         service = __connman_service_lookup_from_network(network);
1435         if (service != NULL) {
1436                 update_from_network(service, network);
1437                 return service;
1438         }
1439
1440         ident = __connman_network_get_ident(network);
1441         if (ident == NULL)
1442                 return NULL;
1443
1444         group = __connman_network_get_group(network);
1445         if (group == NULL)
1446                 return NULL;
1447
1448         name = g_strdup_printf("%s_%s_%s",
1449                         __connman_network_get_type(network), ident, group);
1450
1451         service = __connman_service_get(name);
1452         if (service == NULL)
1453                 goto done;
1454
1455         if (service->path != NULL) {
1456                 update_from_network(service, network);
1457
1458                 __connman_profile_changed();
1459
1460                 __connman_service_put(service);
1461                 service = NULL;
1462                 goto done;
1463         }
1464
1465         service->type = convert_network_type(network);
1466
1467         service->state = CONNMAN_SERVICE_STATE_IDLE;
1468
1469         update_from_network(service, network);
1470
1471         service_register(service);
1472
1473         if (service->favorite == TRUE)
1474                 __connman_service_auto_connect();
1475
1476 done:
1477         g_free(name);
1478
1479         return service;
1480 }
1481
1482 static int service_load(struct connman_service *service)
1483 {
1484         GKeyFile *keyfile;
1485         gchar *pathname, *data = NULL;
1486         gsize length;
1487         gchar *str;
1488
1489         DBG("service %p", service);
1490
1491         if (service->profile == NULL)
1492                 return -EINVAL;
1493
1494         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile);
1495         if (pathname == NULL)
1496                 return -ENOMEM;
1497
1498         keyfile = g_key_file_new();
1499
1500         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
1501                 g_free(pathname);
1502                 return -ENOENT;
1503         }
1504
1505         g_free(pathname);
1506
1507         if (g_key_file_load_from_data(keyfile, data, length,
1508                                                         0, NULL) == FALSE) {
1509                 g_free(data);
1510                 return -EILSEQ;
1511         }
1512
1513         g_free(data);
1514
1515         switch (service->type) {
1516         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1517         case CONNMAN_SERVICE_TYPE_ETHERNET:
1518                 break;
1519         case CONNMAN_SERVICE_TYPE_WIFI:
1520         case CONNMAN_SERVICE_TYPE_WIMAX:
1521         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1522         case CONNMAN_SERVICE_TYPE_CELLULAR:
1523                 service->favorite = g_key_file_get_boolean(keyfile,
1524                                 service->identifier, "Favorite", NULL);
1525
1526                 str = g_key_file_get_string(keyfile,
1527                                 service->identifier, "Failure", NULL);
1528                 if (str != NULL) {
1529                         service->state = CONNMAN_SERVICE_STATE_FAILURE;
1530                         service->error = string2error(str);
1531                 }
1532                 break;
1533         }
1534
1535         str = g_key_file_get_string(keyfile,
1536                                 service->identifier, "Modified", NULL);
1537         if (str != NULL) {
1538                 g_time_val_from_iso8601(str, &service->modified);
1539                 g_free(str);
1540         }
1541
1542         str = g_key_file_get_string(keyfile,
1543                                 service->identifier, "Passphrase", NULL);
1544         if (str != NULL) {
1545                 g_free(service->passphrase);
1546                 service->passphrase = str;
1547         }
1548
1549         __connman_ipconfig_load(service->ipconfig, keyfile,
1550                                         service->identifier, "IPv4.");
1551
1552         g_key_file_free(keyfile);
1553
1554         return 0;
1555 }
1556
1557 static int service_save(struct connman_service *service)
1558 {
1559         GKeyFile *keyfile;
1560         gchar *pathname, *data = NULL;
1561         gsize length;
1562         gchar *str;
1563
1564         DBG("service %p", service);
1565
1566         if (service->profile == NULL)
1567                 return -EINVAL;
1568
1569         pathname = g_strdup_printf("%s/%s.conf", STORAGEDIR, service->profile);
1570         if (pathname == NULL)
1571                 return -ENOMEM;
1572
1573         keyfile = g_key_file_new();
1574
1575         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
1576                 goto update;
1577
1578         if (length > 0) {
1579                 if (g_key_file_load_from_data(keyfile, data, length,
1580                                                         0, NULL) == FALSE)
1581                         goto done;
1582         }
1583
1584         g_free(data);
1585
1586 update:
1587         if (service->name != NULL)
1588                 g_key_file_set_string(keyfile, service->identifier,
1589                                                 "Name", service->name);
1590
1591         switch (service->type) {
1592         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1593         case CONNMAN_SERVICE_TYPE_ETHERNET:
1594                 break;
1595         case CONNMAN_SERVICE_TYPE_WIFI:
1596         case CONNMAN_SERVICE_TYPE_WIMAX:
1597         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1598         case CONNMAN_SERVICE_TYPE_CELLULAR:
1599                 g_key_file_set_boolean(keyfile, service->identifier,
1600                                         "Favorite", service->favorite);
1601
1602                 if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
1603                         const char *failure = error2string(service->error);
1604                         if (failure != NULL)
1605                                 g_key_file_set_string(keyfile,
1606                                                         service->identifier,
1607                                                         "Failure", failure);
1608                 } else {
1609                         g_key_file_remove_key(keyfile, service->identifier,
1610                                                         "Failure", NULL);
1611                 }
1612                 break;
1613         }
1614
1615         str = g_time_val_to_iso8601(&service->modified);
1616         if (str != NULL) {
1617                 g_key_file_set_string(keyfile, service->identifier,
1618                                                         "Modified", str);
1619                 g_free(str);
1620         }
1621
1622         if (service->passphrase != NULL)
1623                 g_key_file_set_string(keyfile, service->identifier,
1624                                         "Passphrase", service->passphrase);
1625         else
1626                 g_key_file_remove_key(keyfile, service->identifier,
1627                                                         "Passphrase", NULL);
1628
1629         __connman_ipconfig_save(service->ipconfig, keyfile,
1630                                         service->identifier, "IPv4.");
1631
1632         data = g_key_file_to_data(keyfile, &length, NULL);
1633
1634         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
1635                 connman_error("Failed to store service information");
1636
1637 done:
1638         g_free(data);
1639
1640         g_key_file_free(keyfile);
1641
1642         g_free(pathname);
1643
1644         return 0;
1645 }
1646
1647 static struct connman_storage service_storage = {
1648         .name           = "service",
1649         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
1650         .service_load   = service_load,
1651         .service_save   = service_save,
1652 };
1653
1654 int __connman_service_init(void)
1655 {
1656         DBG("");
1657
1658         connection = connman_dbus_get_connection();
1659
1660         if (connman_storage_register(&service_storage) < 0)
1661                 connman_error("Failed to register service storage");
1662
1663         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
1664                                                                 NULL, NULL);
1665
1666         service_list = g_sequence_new(service_free);
1667
1668         return 0;
1669 }
1670
1671 void __connman_service_cleanup(void)
1672 {
1673         DBG("");
1674
1675         g_sequence_free(service_list);
1676         service_list = NULL;
1677
1678         g_hash_table_destroy(service_hash);
1679         service_hash = NULL;
1680
1681         connman_storage_unregister(&service_storage);
1682
1683         dbus_connection_unref(connection);
1684 }