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