Detect missing storage entries for AutoConnect setting
[framework/connectivity/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 <stdio.h>
27 #include <string.h>
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 static DBusConnection *connection = NULL;
33
34 static GSequence *service_list = NULL;
35 static GHashTable *service_hash = NULL;
36
37 struct connman_service {
38         gint refcount;
39         char *identifier;
40         char *path;
41         enum connman_service_type type;
42         enum connman_service_mode mode;
43         enum connman_service_security security;
44         enum connman_service_state state;
45         enum connman_service_error error;
46         connman_uint8_t strength;
47         connman_bool_t favorite;
48         connman_bool_t hidden;
49         connman_bool_t ignore;
50         connman_bool_t autoconnect;
51         GTimeVal modified;
52         unsigned int order;
53         char *name;
54         char *passphrase;
55         char *profile;
56         struct connman_ipconfig *ipconfig;
57         struct connman_device *device;
58         struct connman_network *network;
59         DBusMessage *pending;
60         guint timeout;
61 };
62
63 static void append_path(gpointer value, gpointer user_data)
64 {
65         struct connman_service *service = value;
66         DBusMessageIter *iter = user_data;
67
68         if (service->path == NULL || service->hidden == TRUE)
69                 return;
70
71         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
72                                                         &service->path);
73 }
74
75 void __connman_service_list(DBusMessageIter *iter)
76 {
77         DBG("");
78
79         g_sequence_foreach(service_list, append_path, iter);
80 }
81
82 struct find_data {
83         const char *path;
84         struct connman_service *service;
85 };
86
87 static void compare_path(gpointer value, gpointer user_data)
88 {
89         struct connman_service *service = value;
90         struct find_data *data = user_data;
91
92         if (data->service != NULL)
93                 return;
94
95         if (g_strcmp0(service->path, data->path) == 0)
96                 data->service = service;
97 }
98
99 static struct connman_service *find_service(const char *path)
100 {
101         struct find_data data = { .path = path, .service = NULL };
102
103         DBG("path %s", path);
104
105         g_sequence_foreach(service_list, compare_path, &data);
106
107         return data.service;
108 }
109
110 static const char *type2string(enum connman_service_type type)
111 {
112         switch (type) {
113         case CONNMAN_SERVICE_TYPE_UNKNOWN:
114                 break;
115         case CONNMAN_SERVICE_TYPE_ETHERNET:
116                 return "ethernet";
117         case CONNMAN_SERVICE_TYPE_WIFI:
118                 return "wifi";
119         case CONNMAN_SERVICE_TYPE_WIMAX:
120                 return "wimax";
121         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
122                 return "bluetooth";
123         case CONNMAN_SERVICE_TYPE_CELLULAR:
124                 return "cellular";
125         }
126
127         return NULL;
128 }
129
130 static const char *mode2string(enum connman_service_mode mode)
131 {
132         switch (mode) {
133         case CONNMAN_SERVICE_MODE_UNKNOWN:
134                 break;
135         case CONNMAN_SERVICE_MODE_MANAGED:
136                 return "managed";
137         case CONNMAN_SERVICE_MODE_ADHOC:
138                 return "adhoc";
139         }
140
141         return NULL;
142 }
143
144 static const char *security2string(enum connman_service_security security)
145 {
146         switch (security) {
147         case CONNMAN_SERVICE_SECURITY_UNKNOWN:
148                 break;
149         case CONNMAN_SERVICE_SECURITY_NONE:
150                 return "none";
151         case CONNMAN_SERVICE_SECURITY_WEP:
152                 return "wep";
153         case CONNMAN_SERVICE_SECURITY_WPA:
154                 return "wpa";
155         case CONNMAN_SERVICE_SECURITY_RSN:
156                 return "rsn";
157         }
158
159         return NULL;
160 }
161
162 static const char *state2string(enum connman_service_state state)
163 {
164         switch (state) {
165         case CONNMAN_SERVICE_STATE_UNKNOWN:
166                 break;
167         case CONNMAN_SERVICE_STATE_IDLE:
168                 return "idle";
169         case CONNMAN_SERVICE_STATE_CARRIER:
170                 return "carrier";
171         case CONNMAN_SERVICE_STATE_ASSOCIATION:
172                 return "association";
173         case CONNMAN_SERVICE_STATE_CONFIGURATION:
174                 return "configuration";
175         case CONNMAN_SERVICE_STATE_READY:
176                 return "ready";
177         case CONNMAN_SERVICE_STATE_DISCONNECT:
178                 return "disconnect";
179         case CONNMAN_SERVICE_STATE_FAILURE:
180                 return "failure";
181         }
182
183         return NULL;
184 }
185
186 static const char *error2string(enum connman_service_error error)
187 {
188         switch (error) {
189         case CONNMAN_SERVICE_ERROR_UNKNOWN:
190                 break;
191         case CONNMAN_SERVICE_ERROR_OUT_OF_RANGE:
192                 return "out-of-range";
193         case CONNMAN_SERVICE_ERROR_PIN_MISSING:
194                 return "pin-missing";
195         case CONNMAN_SERVICE_ERROR_DHCP_FAILED:
196                 return "dhcp-failed";
197         case CONNMAN_SERVICE_ERROR_CONNECT_FAILED:
198                 return "connect-failed";
199         }
200
201         return NULL;
202 }
203
204 static enum connman_service_error string2error(const char *error)
205 {
206         if (g_strcmp0(error, "dhcp-failed") == 0)
207                 return CONNMAN_SERVICE_ERROR_DHCP_FAILED;
208         else if (g_strcmp0(error, "pin-missing") == 0)
209                 return CONNMAN_SERVICE_ERROR_PIN_MISSING;
210
211         return CONNMAN_SERVICE_ERROR_UNKNOWN;
212 }
213
214 const char *__connman_service_default(void)
215 {
216         struct connman_service *service;
217         GSequenceIter *iter;
218
219         iter = g_sequence_get_begin_iter(service_list);
220
221         if (g_sequence_iter_is_end(iter) == TRUE)
222                 return "";
223
224         service = g_sequence_get(iter);
225         if (service == NULL)
226                 return "";
227
228         if (service->state != CONNMAN_SERVICE_STATE_READY)
229                 return "";
230
231         return type2string(service->type);
232 }
233
234 static void state_changed(struct connman_service *service)
235 {
236         DBusMessage *signal;
237         DBusMessageIter entry, value;
238         const char *str, *key = "State";
239
240         if (service->path == NULL)
241                 return;
242
243         str = state2string(service->state);
244         if (str == NULL)
245                 return;
246
247         signal = dbus_message_new_signal(service->path,
248                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
249         if (signal == NULL)
250                 return;
251
252         dbus_message_iter_init_append(signal, &entry);
253
254         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
255
256         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
257                                         DBUS_TYPE_STRING_AS_STRING, &value);
258         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
259         dbus_message_iter_close_container(&entry, &value);
260
261         g_dbus_send_message(connection, signal);
262 }
263
264 static void strength_changed(struct connman_service *service)
265 {
266         DBusMessage *signal;
267         DBusMessageIter entry, value;
268         const char *key = "Strength";
269
270         if (service->path == NULL)
271                 return;
272
273         if (service->strength == 0)
274                 return;
275
276         signal = dbus_message_new_signal(service->path,
277                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
278         if (signal == NULL)
279                 return;
280
281         dbus_message_iter_init_append(signal, &entry);
282
283         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
284
285         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
286                                         DBUS_TYPE_BYTE_AS_STRING, &value);
287         dbus_message_iter_append_basic(&value, DBUS_TYPE_BYTE,
288                                                         &service->strength);
289         dbus_message_iter_close_container(&entry, &value);
290
291         g_dbus_send_message(connection, signal);
292 }
293
294 static void passphrase_changed(struct connman_service *service)
295 {
296         DBusMessage *signal;
297         DBusMessageIter entry, value;
298         dbus_bool_t required;
299         const char *key = "PassphraseRequired";
300
301         if (service->path == NULL)
302                 return;
303
304         switch (service->type) {
305         case CONNMAN_SERVICE_TYPE_UNKNOWN:
306         case CONNMAN_SERVICE_TYPE_ETHERNET:
307         case CONNMAN_SERVICE_TYPE_WIMAX:
308         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
309         case CONNMAN_SERVICE_TYPE_CELLULAR:
310                 return;
311         case CONNMAN_SERVICE_TYPE_WIFI:
312                 required = FALSE;
313
314                 switch (service->security) {
315                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
316                 case CONNMAN_SERVICE_SECURITY_NONE:
317                         break;
318                 case CONNMAN_SERVICE_SECURITY_WEP:
319                 case CONNMAN_SERVICE_SECURITY_WPA:
320                 case CONNMAN_SERVICE_SECURITY_RSN:
321                         if (service->passphrase == NULL)
322                                 required = TRUE;
323                         break;
324                 }
325                 break;
326         }
327
328         signal = dbus_message_new_signal(service->path,
329                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
330         if (signal == NULL)
331                 return;
332
333         dbus_message_iter_init_append(signal, &entry);
334
335         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
336
337         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
338                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
339         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &required);
340         dbus_message_iter_close_container(&entry, &value);
341
342         g_dbus_send_message(connection, signal);
343 }
344
345 static void autoconnect_changed(struct connman_service *service)
346 {
347         DBusMessage *signal;
348         DBusMessageIter entry, value;
349         const char *key = "AutoConnect";
350
351         if (service->path == NULL)
352                 return;
353
354         signal = dbus_message_new_signal(service->path,
355                                 CONNMAN_SERVICE_INTERFACE, "PropertyChanged");
356         if (signal == NULL)
357                 return;
358
359         dbus_message_iter_init_append(signal, &entry);
360
361         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
362
363         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
364                                         DBUS_TYPE_BOOLEAN_AS_STRING, &value);
365         dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN,
366                                                         &service->autoconnect);
367         dbus_message_iter_close_container(&entry, &value);
368
369         g_dbus_send_message(connection, signal);
370 }
371
372 static DBusMessage *get_properties(DBusConnection *conn,
373                                         DBusMessage *msg, void *user_data)
374 {
375         struct connman_service *service = user_data;
376         DBusMessage *reply;
377         DBusMessageIter array, dict;
378         dbus_bool_t required;
379         const char *str;
380
381         DBG("service %p", service);
382
383         reply = dbus_message_new_method_return(msg);
384         if (reply == NULL)
385                 return NULL;
386
387         dbus_message_iter_init_append(reply, &array);
388
389         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
390                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
391                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
392                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
393
394         str = type2string(service->type);
395         if (str != NULL)
396                 connman_dbus_dict_append_variant(&dict, "Type",
397                                                 DBUS_TYPE_STRING, &str);
398
399         str = mode2string(service->mode);
400         if (str != NULL)
401                 connman_dbus_dict_append_variant(&dict, "Mode",
402                                                 DBUS_TYPE_STRING, &str);
403
404         str = security2string(service->security);
405         if (str != NULL)
406                 connman_dbus_dict_append_variant(&dict, "Security",
407                                                 DBUS_TYPE_STRING, &str);
408
409         str = state2string(service->state);
410         if (str != NULL)
411                 connman_dbus_dict_append_variant(&dict, "State",
412                                                 DBUS_TYPE_STRING, &str);
413
414         str = error2string(service->error);
415         if (str != NULL)
416                 connman_dbus_dict_append_variant(&dict, "Error",
417                                                 DBUS_TYPE_STRING, &str);
418
419         if (service->strength > 0)
420                 connman_dbus_dict_append_variant(&dict, "Strength",
421                                         DBUS_TYPE_BYTE, &service->strength);
422
423         connman_dbus_dict_append_variant(&dict, "Favorite",
424                                         DBUS_TYPE_BOOLEAN, &service->favorite);
425
426         if (service->favorite == TRUE)
427                 connman_dbus_dict_append_variant(&dict, "AutoConnect",
428                                 DBUS_TYPE_BOOLEAN, &service->autoconnect);
429         else
430                 connman_dbus_dict_append_variant(&dict, "AutoConnect",
431                                         DBUS_TYPE_BOOLEAN, &service->favorite);
432
433         if (service->name != NULL)
434                 connman_dbus_dict_append_variant(&dict, "Name",
435                                         DBUS_TYPE_STRING, &service->name);
436
437         switch (service->type) {
438         case CONNMAN_SERVICE_TYPE_UNKNOWN:
439         case CONNMAN_SERVICE_TYPE_ETHERNET:
440         case CONNMAN_SERVICE_TYPE_WIMAX:
441         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
442         case CONNMAN_SERVICE_TYPE_CELLULAR:
443                 break;
444         case CONNMAN_SERVICE_TYPE_WIFI:
445                 if (service->passphrase != NULL &&
446                                 __connman_security_check_privilege(msg,
447                                         CONNMAN_SECURITY_PRIVILEGE_SECRET) == 0)
448                         connman_dbus_dict_append_variant(&dict, "Passphrase",
449                                 DBUS_TYPE_STRING, &service->passphrase);
450
451                 required = FALSE;
452
453                 switch (service->security) {
454                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
455                 case CONNMAN_SERVICE_SECURITY_NONE:
456                         break;
457                 case CONNMAN_SERVICE_SECURITY_WEP:
458                 case CONNMAN_SERVICE_SECURITY_WPA:
459                 case CONNMAN_SERVICE_SECURITY_RSN:
460                         if (service->passphrase == NULL)
461                                 required = TRUE;
462                         break;
463                 }
464
465                 connman_dbus_dict_append_variant(&dict, "PassphraseRequired",
466                                                 DBUS_TYPE_BOOLEAN, &required);
467                 break;
468         }
469
470         if (service->ipconfig != NULL)
471                 __connman_ipconfig_append_ipv4(service->ipconfig,
472                                                         &dict, "IPv4.");
473
474         dbus_message_iter_close_container(&array, &dict);
475
476         return reply;
477 }
478
479 static DBusMessage *set_property(DBusConnection *conn,
480                                         DBusMessage *msg, void *user_data)
481 {
482         struct connman_service *service = user_data;
483         DBusMessageIter iter, value;
484         const char *name;
485         int type;
486
487         DBG("service %p", service);
488
489         if (dbus_message_iter_init(msg, &iter) == FALSE)
490                 return __connman_error_invalid_arguments(msg);
491
492         dbus_message_iter_get_basic(&iter, &name);
493         dbus_message_iter_next(&iter);
494         dbus_message_iter_recurse(&iter, &value);
495
496         if (__connman_security_check_privilege(msg,
497                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
498                 return __connman_error_permission_denied(msg);
499
500         type = dbus_message_iter_get_arg_type(&value);
501
502         if (g_str_equal(name, "Passphrase") == TRUE) {
503                 const char *passphrase;
504
505                 if (type != DBUS_TYPE_STRING)
506                         return __connman_error_invalid_arguments(msg);
507
508                 if (__connman_security_check_privilege(msg,
509                                         CONNMAN_SECURITY_PRIVILEGE_SECRET) < 0)
510                         return __connman_error_permission_denied(msg);
511
512                 dbus_message_iter_get_basic(&value, &passphrase);
513
514                 g_free(service->passphrase);
515                 service->passphrase = g_strdup(passphrase);
516
517                 passphrase_changed(service);
518
519                 if (service->network != NULL)
520                         connman_network_set_string(service->network,
521                                 "WiFi.Passphrase", service->passphrase);
522
523                 __connman_storage_save_service(service);
524         } else if (g_str_has_prefix(name, "AutoConnect") == TRUE) {
525                 connman_bool_t autoconnect;
526
527                 if (type != DBUS_TYPE_BOOLEAN)
528                         return __connman_error_invalid_arguments(msg);
529
530                 if (service->favorite == FALSE)
531                         return __connman_error_invalid_service(msg);
532
533                 dbus_message_iter_get_basic(&value, &autoconnect);
534
535                 if (service->autoconnect == autoconnect)
536                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
537
538                 service->autoconnect = autoconnect;
539
540                 autoconnect_changed(service);
541
542                 __connman_storage_save_service(service);
543         } else if (g_str_has_prefix(name, "IPv4.") == TRUE) {
544                 int err;
545
546                 if (service->ipconfig == NULL)
547                         return __connman_error_invalid_property(msg);
548
549                 err = __connman_ipconfig_set_ipv4(service->ipconfig,
550                                                         name + 5, &value);
551                 if (err < 0)
552                         return __connman_error_failed(msg, -err);
553         } else
554                 return __connman_error_invalid_property(msg);
555
556         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
557 }
558
559 static void set_idle(struct connman_service *service)
560 {
561         service->state = CONNMAN_SERVICE_STATE_IDLE;
562         service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
563         state_changed(service);
564 }
565
566 static DBusMessage *clear_property(DBusConnection *conn,
567                                         DBusMessage *msg, void *user_data)
568 {
569         struct connman_service *service = user_data;
570         const char *name;
571
572         DBG("service %p", service);
573
574         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
575                                                         DBUS_TYPE_INVALID);
576
577         if (__connman_security_check_privilege(msg,
578                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
579                 return __connman_error_permission_denied(msg);
580
581         if (g_str_equal(name, "Error") == TRUE) {
582                 set_idle(service);
583
584                 g_get_current_time(&service->modified);
585                 __connman_storage_save_service(service);
586         } else if (g_str_equal(name, "Passphrase") == TRUE) {
587                 g_free(service->passphrase);
588                 service->passphrase = NULL;
589
590                 passphrase_changed(service);
591
592                 __connman_storage_save_service(service);
593         } else
594                 return __connman_error_invalid_property(msg);
595
596         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
597 }
598
599 static connman_bool_t is_connecting(struct connman_service *service)
600 {
601         switch (service->state) {
602         case CONNMAN_SERVICE_STATE_UNKNOWN:
603         case CONNMAN_SERVICE_STATE_IDLE:
604         case CONNMAN_SERVICE_STATE_CARRIER:
605         case CONNMAN_SERVICE_STATE_FAILURE:
606         case CONNMAN_SERVICE_STATE_DISCONNECT:
607         case CONNMAN_SERVICE_STATE_READY:
608                 break;
609         case CONNMAN_SERVICE_STATE_ASSOCIATION:
610         case CONNMAN_SERVICE_STATE_CONFIGURATION:
611                 return TRUE;
612         }
613
614         return FALSE;
615 }
616
617 static connman_bool_t is_ignore(struct connman_service *service)
618 {
619         if (service->autoconnect == FALSE)
620                 return TRUE;
621
622         if (service->ignore == TRUE)
623                 return TRUE;
624
625         if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
626                 return TRUE;
627
628         return FALSE;
629 }
630
631 void __connman_service_auto_connect(void)
632 {
633         struct connman_service *service = NULL;
634         GSequenceIter *iter;
635
636         DBG("");
637
638         iter = g_sequence_get_begin_iter(service_list);
639
640         while (g_sequence_iter_is_end(iter) == FALSE) {
641                 service = g_sequence_get(iter);
642
643                 if (service->pending != NULL)
644                         return;
645
646                 if (is_connecting(service) == TRUE)
647                         return;
648
649                 if (service->favorite == FALSE)
650                         return;
651
652                 if (service->state == CONNMAN_SERVICE_STATE_READY)
653                         return;
654
655                 if (is_ignore(service) == FALSE &&
656                                 service->state == CONNMAN_SERVICE_STATE_IDLE)
657                         break;
658
659                 service = NULL;
660
661                 iter = g_sequence_iter_next(iter);
662         }
663
664         if (service != NULL)
665                 __connman_service_connect(service);
666 }
667
668 static void reply_pending(struct connman_service *service, int error)
669 {
670         if (service->timeout > 0) {
671                 g_source_remove(service->timeout);
672                 service->timeout = 0;
673         }
674
675         if (service->pending != NULL) {
676                 if (error > 0) {
677                         DBusMessage *reply;
678
679                         reply = __connman_error_failed(service->pending,
680                                                                 error);
681                         if (reply != NULL)
682                                 g_dbus_send_message(connection, reply);
683                 } else
684                         g_dbus_send_reply(connection, service->pending,
685                                                         DBUS_TYPE_INVALID);
686
687                 dbus_message_unref(service->pending);
688                 service->pending = NULL;
689         }
690 }
691
692 static gboolean connect_timeout(gpointer user_data)
693 {
694         struct connman_service *service = user_data;
695         connman_bool_t auto_connect = FALSE;
696
697         DBG("service %p", service);
698
699         service->timeout = 0;
700
701         if (service->network != NULL)
702                 __connman_network_disconnect(service->network);
703         else if (service->device != NULL)
704                 __connman_device_disconnect(service->device);
705
706         __connman_ipconfig_disable(service->ipconfig);
707
708         if (service->pending != NULL) {
709                 DBusMessage *reply;
710
711                 reply = __connman_error_operation_timeout(service->pending);
712                 if (reply != NULL)
713                         g_dbus_send_message(connection, reply);
714
715                 dbus_message_unref(service->pending);
716                 service->pending = NULL;
717         } else
718                 auto_connect = TRUE;
719
720         __connman_service_indicate_state(service,
721                                         CONNMAN_SERVICE_STATE_FAILURE);
722
723         if (auto_connect == TRUE)
724                 __connman_service_auto_connect();
725
726         return FALSE;
727 }
728
729 static DBusMessage *connect_service(DBusConnection *conn,
730                                         DBusMessage *msg, void *user_data)
731 {
732         struct connman_service *service = user_data;
733         GSequenceIter *iter;
734         int err;
735
736         DBG("service %p", service);
737
738         if (service->pending != NULL)
739                 return __connman_error_in_progress(msg);
740
741         iter = g_sequence_get_begin_iter(service_list);
742
743         while (g_sequence_iter_is_end(iter) == FALSE) {
744                 struct connman_service *temp = g_sequence_get(iter);
745
746                 if (service->type == temp->type &&
747                                         is_connecting(temp) == TRUE)
748                         return __connman_error_in_progress(msg);
749
750                 iter = g_sequence_iter_next(iter);
751         }
752
753         service->ignore = FALSE;
754
755         service->pending = dbus_message_ref(msg);
756
757         err = __connman_service_connect(service);
758         if (err < 0) {
759                 if (err == -ENOKEY) {
760                         if (__connman_agent_request_passphrase(service,
761                                                         NULL, NULL) == 0)
762                                 return NULL;
763                 }
764
765                 if (err != -EINPROGRESS) {
766                         dbus_message_unref(service->pending);
767                         service->pending = NULL;
768
769                         return __connman_error_failed(msg, -err);
770                 }
771
772                 return NULL;
773         }
774
775         dbus_message_unref(service->pending);
776         service->pending = NULL;
777
778         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
779 }
780
781 static DBusMessage *disconnect_service(DBusConnection *conn,
782                                         DBusMessage *msg, void *user_data)
783 {
784         struct connman_service *service = user_data;
785         int err;
786
787         DBG("service %p", service);
788
789         service->ignore = TRUE;
790
791         err = __connman_service_disconnect(service);
792         if (err < 0) {
793                 if (err != -EINPROGRESS)
794                         return __connman_error_failed(msg, -err);
795
796                 return NULL;
797         }
798
799         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
800 }
801
802 static DBusMessage *remove_service(DBusConnection *conn,
803                                         DBusMessage *msg, void *user_data)
804 {
805         struct connman_service *service = user_data;
806
807         DBG("service %p", service);
808
809         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
810                 return __connman_error_not_supported(msg);
811
812         if (service->favorite == FALSE)
813                 return __connman_error_not_supported(msg);
814
815         if (service->network != NULL)
816                 __connman_network_disconnect(service->network);
817
818         g_free(service->passphrase);
819         service->passphrase = NULL;
820
821         passphrase_changed(service);
822
823         connman_service_set_favorite(service, FALSE);
824         __connman_storage_save_service(service);
825
826         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
827 }
828
829 static DBusMessage *move_before(DBusConnection *conn,
830                                         DBusMessage *msg, void *user_data)
831 {
832         struct connman_service *service = user_data;
833         struct connman_service *target;
834         const char *path;
835         GSequenceIter *src, *dst;
836
837         DBG("service %p", service);
838
839         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
840                                                         DBUS_TYPE_INVALID);
841
842         if (service->favorite == FALSE)
843                 return __connman_error_not_supported(msg);
844
845         target = find_service(path);
846         if (target == NULL || target->favorite == FALSE || target == service)
847                 return __connman_error_invalid_service(msg);
848
849         DBG("target %s", target->identifier);
850
851         if (target->state != service->state)
852                 return __connman_error_invalid_service(msg);
853
854         g_get_current_time(&service->modified);
855         __connman_storage_save_service(service);
856
857         src = g_hash_table_lookup(service_hash, service->identifier);
858         dst = g_hash_table_lookup(service_hash, target->identifier);
859
860         g_sequence_move(src, dst);
861
862         __connman_profile_changed(FALSE);
863
864         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
865 }
866
867 static DBusMessage *move_after(DBusConnection *conn,
868                                         DBusMessage *msg, void *user_data)
869 {
870         struct connman_service *service = user_data;
871         struct connman_service *target;
872         const char *path;
873
874         DBG("service %p", service);
875
876         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
877                                                         DBUS_TYPE_INVALID);
878
879         if (service->favorite == FALSE)
880                 return __connman_error_not_supported(msg);
881
882         target = find_service(path);
883         if (target == NULL || target->favorite == FALSE || target == service)
884                 return __connman_error_invalid_service(msg);
885
886         DBG("target %s", target->identifier);
887
888         if (target->state != service->state)
889                 return __connman_error_invalid_service(msg);
890
891         g_get_current_time(&service->modified);
892         __connman_storage_save_service(service);
893
894         return __connman_error_not_implemented(msg);
895 }
896
897 static GDBusMethodTable service_methods[] = {
898         { "GetProperties", "",   "a{sv}", get_properties     },
899         { "SetProperty",   "sv", "",      set_property       },
900         { "ClearProperty", "s",  "",      clear_property     },
901         { "Connect",       "",   "",      connect_service,
902                                                 G_DBUS_METHOD_FLAG_ASYNC },
903         { "Disconnect",    "",   "",      disconnect_service },
904         { "Remove",        "",   "",      remove_service     },
905         { "MoveBefore",    "o",  "",      move_before        },
906         { "MoveAfter",     "o",  "",      move_after         },
907         { },
908 };
909
910 static GDBusSignalTable service_signals[] = {
911         { "PropertyChanged", "sv" },
912         { },
913 };
914
915 static void service_free(gpointer user_data)
916 {
917         struct connman_service *service = user_data;
918         char *path = service->path;
919
920         DBG("service %p", service);
921
922         reply_pending(service, ENOENT);
923
924         g_hash_table_remove(service_hash, service->identifier);
925
926         service->path = NULL;
927
928         if (path != NULL) {
929                 __connman_profile_changed(FALSE);
930
931                 g_dbus_unregister_interface(connection, path,
932                                                 CONNMAN_SERVICE_INTERFACE);
933                 g_free(path);
934         }
935
936         if (service->network != NULL)
937                 connman_network_unref(service->network);
938
939         if (service->ipconfig != NULL) {
940                 connman_ipconfig_unref(service->ipconfig);
941                 service->ipconfig = NULL;
942         }
943
944         g_free(service->profile);
945         g_free(service->name);
946         g_free(service->passphrase);
947         g_free(service->identifier);
948         g_free(service);
949 }
950
951 /**
952  * __connman_service_put:
953  * @service: service structure
954  *
955  * Release service if no longer needed
956  */
957 void __connman_service_put(struct connman_service *service)
958 {
959         DBG("service %p", service);
960
961         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
962                 GSequenceIter *iter;
963
964                 iter = g_hash_table_lookup(service_hash, service->identifier);
965                 if (iter != NULL) {
966                         __connman_service_disconnect(service);
967                         g_sequence_remove(iter);
968                 } else
969                         service_free(service);
970         }
971 }
972
973 static void __connman_service_initialize(struct connman_service *service)
974 {
975         DBG("service %p", service);
976
977         service->refcount = 1;
978
979         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
980         service->mode     = CONNMAN_SERVICE_MODE_UNKNOWN;
981         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
982         service->state    = CONNMAN_SERVICE_STATE_UNKNOWN;
983
984         service->favorite = FALSE;
985         service->hidden = FALSE;
986
987         service->ignore = FALSE;
988
989         service->order = 0;
990 }
991
992 /**
993  * connman_service_create:
994  *
995  * Allocate a new service.
996  *
997  * Returns: a newly-allocated #connman_service structure
998  */
999 struct connman_service *connman_service_create(void)
1000 {
1001         struct connman_service *service;
1002
1003         service = g_try_new0(struct connman_service, 1);
1004         if (service == NULL)
1005                 return NULL;
1006
1007         DBG("service %p", service);
1008
1009         __connman_service_initialize(service);
1010
1011         return service;
1012 }
1013
1014 /**
1015  * connman_service_ref:
1016  * @service: service structure
1017  *
1018  * Increase reference counter of service
1019  */
1020 struct connman_service *connman_service_ref(struct connman_service *service)
1021 {
1022         g_atomic_int_inc(&service->refcount);
1023
1024         return service;
1025 }
1026
1027 /**
1028  * connman_service_unref:
1029  * @service: service structure
1030  *
1031  * Decrease reference counter of service
1032  */
1033 void connman_service_unref(struct connman_service *service)
1034 {
1035         __connman_service_put(service);
1036 }
1037
1038 static gint service_compare(gconstpointer a, gconstpointer b,
1039                                                         gpointer user_data)
1040 {
1041         struct connman_service *service_a = (void *) a;
1042         struct connman_service *service_b = (void *) b;
1043
1044         if (service_a->state != service_b->state) {
1045                 if (service_a->state == CONNMAN_SERVICE_STATE_READY)
1046                         return -1;
1047                 if (service_b->state == CONNMAN_SERVICE_STATE_READY)
1048                         return 1;
1049         }
1050
1051         if (service_a->order > service_b->order)
1052                 return -1;
1053
1054         if (service_a->order < service_b->order)
1055                 return 1;
1056
1057         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
1058                 return -1;
1059
1060         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
1061                 return 1;
1062
1063         if (service_a->type != service_b->type) {
1064                 switch (service_a->type) {
1065                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
1066                 case CONNMAN_SERVICE_TYPE_ETHERNET:
1067                         break;
1068                 case CONNMAN_SERVICE_TYPE_WIFI:
1069                         return 1;
1070                 case CONNMAN_SERVICE_TYPE_WIMAX:
1071                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1072                 case CONNMAN_SERVICE_TYPE_CELLULAR:
1073                         return -1;
1074                 }
1075         }
1076
1077         return (gint) service_b->strength - (gint) service_a->strength;
1078 }
1079
1080 /**
1081  * connman_service_set_favorite:
1082  * @service: service structure
1083  * @favorite: favorite value
1084  *
1085  * Change the favorite setting of service
1086  */
1087 int connman_service_set_favorite(struct connman_service *service,
1088                                                 connman_bool_t favorite)
1089 {
1090         GSequenceIter *iter;
1091
1092         iter = g_hash_table_lookup(service_hash, service->identifier);
1093         if (iter == NULL)
1094                 return -ENOENT;
1095
1096         if (service->favorite == favorite)
1097                 return -EALREADY;
1098
1099         service->favorite = favorite;
1100
1101         g_sequence_sort_changed(iter, service_compare, NULL);
1102
1103         __connman_profile_changed(FALSE);
1104
1105         return 0;
1106 }
1107
1108 static void default_changed(void)
1109 {
1110         DBusMessage *signal;
1111         DBusMessageIter entry, value;
1112         const char *key = "DefaultTechnology";
1113         const char *str = __connman_service_default();
1114
1115         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1116                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1117         if (signal == NULL)
1118                 return;
1119
1120         dbus_message_iter_init_append(signal, &entry);
1121
1122         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1123
1124         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1125                                         DBUS_TYPE_STRING_AS_STRING, &value);
1126         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
1127         dbus_message_iter_close_container(&entry, &value);
1128
1129         g_dbus_send_message(connection, signal);
1130 }
1131
1132 int __connman_service_indicate_state(struct connman_service *service,
1133                                         enum connman_service_state state)
1134 {
1135         GSequenceIter *iter;
1136
1137         DBG("service %p state %d", service, state);
1138
1139         if (service == NULL)
1140                 return -EINVAL;
1141
1142         if (service->state == state)
1143                 return -EALREADY;
1144
1145         if (service->state == CONNMAN_SERVICE_STATE_FAILURE &&
1146                                 state == CONNMAN_SERVICE_STATE_IDLE)
1147                 return -EINVAL;
1148
1149         if (service->state == CONNMAN_SERVICE_STATE_IDLE &&
1150                                 state == CONNMAN_SERVICE_STATE_DISCONNECT)
1151                 return -EINVAL;
1152
1153         if (state == CONNMAN_SERVICE_STATE_IDLE &&
1154                         service->state != CONNMAN_SERVICE_STATE_DISCONNECT) {
1155                 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
1156                 state_changed(service);
1157
1158                 __connman_service_disconnect(service);
1159         }
1160
1161         service->state = state;
1162         state_changed(service);
1163
1164         if (state == CONNMAN_SERVICE_STATE_READY) {
1165                 connman_service_set_favorite(service, TRUE);
1166
1167                 reply_pending(service, 0);
1168
1169                 g_get_current_time(&service->modified);
1170                 __connman_storage_save_service(service);
1171
1172                 __connman_notifier_connect(service->type);
1173
1174                 default_changed();
1175         } else if (state == CONNMAN_SERVICE_STATE_DISCONNECT) {
1176                 default_changed();
1177
1178                 __connman_notifier_disconnect(service->type);
1179         }
1180
1181         if (state == CONNMAN_SERVICE_STATE_FAILURE) {
1182                 reply_pending(service, EIO);
1183
1184                 g_get_current_time(&service->modified);
1185                 __connman_storage_save_service(service);
1186         } else
1187                 service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
1188
1189         iter = g_hash_table_lookup(service_hash, service->identifier);
1190         if (iter != NULL)
1191                 g_sequence_sort_changed(iter, service_compare, NULL);
1192
1193         __connman_profile_changed(FALSE);
1194
1195         if (service->state == CONNMAN_SERVICE_STATE_IDLE ||
1196                         service->state == CONNMAN_SERVICE_STATE_FAILURE)
1197                 __connman_element_request_scan(CONNMAN_ELEMENT_TYPE_UNKNOWN);
1198
1199         return 0;
1200 }
1201
1202 int __connman_service_indicate_error(struct connman_service *service,
1203                                         enum connman_service_error error)
1204 {
1205         DBG("service %p error %d", service, error);
1206
1207         if (service == NULL)
1208                 return -EINVAL;
1209
1210         service->error = error;
1211
1212         return __connman_service_indicate_state(service,
1213                                         CONNMAN_SERVICE_STATE_FAILURE);
1214 }
1215
1216 int __connman_service_indicate_default(struct connman_service *service)
1217 {
1218         DBG("service %p", service);
1219
1220         default_changed();
1221
1222         return 0;
1223 }
1224
1225 static connman_bool_t prepare_network(struct connman_service *service)
1226 {
1227         enum connman_network_type type;
1228         unsigned int ssid_len;
1229
1230         type = connman_network_get_type(service->network);
1231
1232         switch (type) {
1233         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1234         case CONNMAN_NETWORK_TYPE_VENDOR:
1235                 return FALSE;
1236         case CONNMAN_NETWORK_TYPE_WIFI:
1237                 if (connman_network_get_blob(service->network, "WiFi.SSID",
1238                                                         &ssid_len) == NULL)
1239                         return FALSE;
1240
1241                 connman_network_set_string(service->network,
1242                                 "WiFi.Passphrase", service->passphrase);
1243                 break;
1244         case CONNMAN_NETWORK_TYPE_WIMAX:
1245         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1246         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1247         case CONNMAN_NETWORK_TYPE_MBM:
1248         case CONNMAN_NETWORK_TYPE_HSO:
1249                 break;
1250         }
1251
1252         return TRUE;
1253 }
1254
1255 int __connman_service_connect(struct connman_service *service)
1256 {
1257         int err;
1258
1259         DBG("service %p", service);
1260
1261         if (service->state == CONNMAN_SERVICE_STATE_READY)
1262                 return -EISCONN;
1263
1264         if (is_connecting(service) == TRUE)
1265                 return -EALREADY;
1266
1267         switch (service->type) {
1268         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1269                 return -EINVAL;
1270         case CONNMAN_SERVICE_TYPE_ETHERNET:
1271         case CONNMAN_SERVICE_TYPE_WIMAX:
1272         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1273         case CONNMAN_SERVICE_TYPE_CELLULAR:
1274                 break;
1275         case CONNMAN_SERVICE_TYPE_WIFI:
1276                 switch (service->security) {
1277                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
1278                 case CONNMAN_SERVICE_SECURITY_NONE:
1279                         break;
1280                 case CONNMAN_SERVICE_SECURITY_WEP:
1281                 case CONNMAN_SERVICE_SECURITY_WPA:
1282                 case CONNMAN_SERVICE_SECURITY_RSN:
1283                         if (service->passphrase == NULL)
1284                                 return -ENOKEY;
1285                         break;
1286                 }
1287                 break;
1288         }
1289
1290         if (service->network != NULL) {
1291                 if (prepare_network(service) == FALSE)
1292                         return -EINVAL;
1293
1294                 __connman_ipconfig_enable(service->ipconfig);
1295
1296                 err = __connman_network_connect(service->network);
1297         } else if (service->device != NULL) {
1298                 if (service->favorite == FALSE)
1299                         return -ENOLINK;
1300
1301                 __connman_ipconfig_enable(service->ipconfig);
1302
1303                 err = __connman_device_connect(service->device);
1304         } else
1305                 return -EOPNOTSUPP;
1306
1307         if (err < 0) {
1308                 if (err != -EINPROGRESS) {
1309                         __connman_ipconfig_disable(service->ipconfig);
1310                         return err;
1311                 }
1312
1313                 service->timeout = g_timeout_add_seconds(45,
1314                                                 connect_timeout, service);
1315
1316                 return -EINPROGRESS;
1317         }
1318
1319         return 0;
1320 }
1321
1322 int __connman_service_disconnect(struct connman_service *service)
1323 {
1324         int err;
1325
1326         DBG("service %p", service);
1327
1328         reply_pending(service, ECONNABORTED);
1329
1330         if (service->network != NULL) {
1331                 err = __connman_network_disconnect(service->network);
1332         } else if (service->device != NULL) {
1333                 if (service->favorite == FALSE)
1334                         return -ENOLINK;
1335                 err = __connman_device_disconnect(service->device);
1336         } else
1337                 return -EOPNOTSUPP;
1338
1339         __connman_ipconfig_disable(service->ipconfig);
1340
1341         if (err < 0) {
1342                 if (err != -EINPROGRESS)
1343                         return err;
1344
1345                 return -EINPROGRESS;
1346         }
1347
1348         return 0;
1349 }
1350
1351 /**
1352  * __connman_service_lookup:
1353  * @identifier: service identifier
1354  *
1355  * Look up a service by identifier (reference count will not be increased)
1356  */
1357 static struct connman_service *__connman_service_lookup(const char *identifier)
1358 {
1359         GSequenceIter *iter;
1360
1361         iter = g_hash_table_lookup(service_hash, identifier);
1362         if (iter != NULL)
1363                 return g_sequence_get(iter);
1364
1365         return NULL;
1366 }
1367
1368 static struct connman_network *create_hidden_wifi(struct connman_device *device,
1369                 const char *ssid, const char *mode, const char *security)
1370 {
1371         struct connman_network *network;
1372         char *name;
1373         int index;
1374         unsigned int i, ssid_len;
1375
1376         ssid_len = strlen(ssid);
1377         if (ssid_len < 1)
1378                 return NULL;
1379
1380         network = connman_network_create(NULL, CONNMAN_NETWORK_TYPE_WIFI);
1381         if (network == NULL)
1382                 return NULL;
1383
1384         connman_network_set_blob(network, "WiFi.SSID",
1385                                         (unsigned char *) ssid, ssid_len);
1386
1387         connman_network_set_string(network, "WiFi.Mode", mode);
1388         connman_network_set_string(network, "WiFi.Security", security);
1389
1390         name = g_try_malloc0(ssid_len + 1);
1391         if (name == NULL) {
1392                 connman_network_unref(network);
1393                 return NULL;
1394         }
1395
1396         for (i = 0; i < ssid_len; i++) {
1397                 if (g_ascii_isprint(ssid[i]))
1398                         name[i] = ssid[i];
1399                 else
1400                         name[i] = ' ';
1401         }
1402
1403         connman_network_set_name(network, name);
1404
1405         g_free(name);
1406
1407         index = connman_device_get_index(device);
1408         connman_network_set_index(network, index);
1409
1410         connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
1411
1412         if (connman_device_add_network(device, network) < 0) {
1413                 connman_network_unref(network);
1414                 return NULL;
1415         }
1416
1417         connman_network_set_available(network, TRUE);
1418
1419         return network;
1420 }
1421
1422 int __connman_service_create_and_connect(DBusMessage *msg)
1423 {
1424         struct connman_service *service;
1425         struct connman_network *network;
1426         struct connman_device *device;
1427         DBusMessageIter iter, array;
1428         const char *mode = "managed", *security = "none";
1429         const char *type = NULL, *ssid = NULL, *passphrase = NULL;
1430         unsigned int ssid_len = 0;
1431         const char *ident;
1432         char *name, *group;
1433         gboolean created = FALSE;
1434         int err;
1435
1436         dbus_message_iter_init(msg, &iter);
1437         dbus_message_iter_recurse(&iter, &array);
1438
1439         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
1440                 DBusMessageIter entry, value;
1441                 const char *key;
1442
1443                 dbus_message_iter_recurse(&array, &entry);
1444                 dbus_message_iter_get_basic(&entry, &key);
1445
1446                 dbus_message_iter_next(&entry);
1447                 dbus_message_iter_recurse(&entry, &value);
1448
1449                 switch (dbus_message_iter_get_arg_type(&value)) {
1450                 case DBUS_TYPE_STRING:
1451                         if (g_str_equal(key, "Type") == TRUE)
1452                                 dbus_message_iter_get_basic(&value, &type);
1453                         else if (g_str_equal(key, "WiFi.Mode") == TRUE ||
1454                                         g_str_equal(key, "Mode") == TRUE)
1455                                 dbus_message_iter_get_basic(&value, &mode);
1456                         else if (g_str_equal(key, "WiFi.Security") == TRUE ||
1457                                         g_str_equal(key, "Security") == TRUE)
1458                                 dbus_message_iter_get_basic(&value, &security);
1459                         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE ||
1460                                         g_str_equal(key, "Passphrase") == TRUE)
1461                                 dbus_message_iter_get_basic(&value, &passphrase);
1462                         else if (g_str_equal(key, "WiFi.SSID") == TRUE ||
1463                                         g_str_equal(key, "SSID") == TRUE)
1464                                 dbus_message_iter_get_basic(&value, &ssid);
1465                 }
1466
1467                 dbus_message_iter_next(&array);
1468         }
1469
1470         if (type == NULL)
1471                 return -EINVAL;
1472
1473         if (g_strcmp0(type, "wifi") != 0 || g_strcmp0(mode, "managed") != 0)
1474                 return -EOPNOTSUPP;
1475
1476         if (ssid == NULL)
1477                 return -EINVAL;
1478
1479         ssid_len = strlen(ssid);
1480         if (ssid_len < 1)
1481                 return -EINVAL;
1482
1483         if (g_strcmp0(security, "none") != 0 &&
1484                         g_strcmp0(security, "wep") != 0 &&
1485                                 g_strcmp0(security, "wpa") != 0 &&
1486                                         g_strcmp0(security, "rsn") != 0)
1487                 return -EINVAL;
1488
1489         device = __connman_element_find_device(CONNMAN_SERVICE_TYPE_WIFI);
1490         if (device == NULL)
1491                 return -EOPNOTSUPP;
1492
1493         ident = __connman_device_get_ident(device);
1494         if (ident == NULL)
1495                 return -EOPNOTSUPP;
1496
1497         group = connman_wifi_build_group_name((unsigned char *) ssid,
1498                                                 ssid_len, mode, security);
1499         if (group == NULL)
1500                 return -EINVAL;
1501
1502         name = g_strdup_printf("%s_%s_%s", type, ident, group);
1503
1504         service = __connman_service_lookup(name);
1505
1506         if (service != NULL)
1507                 goto done;
1508
1509         network = create_hidden_wifi(device, ssid, mode, security);
1510         if (network != NULL) {
1511                 connman_network_set_group(network, group);
1512                 created = TRUE;
1513         }
1514
1515         service = __connman_service_lookup(name);
1516
1517 done:
1518         g_free(name);
1519         g_free(group);
1520
1521         if (service == NULL) {
1522                 err = -EOPNOTSUPP;
1523                 goto failed;
1524         }
1525
1526         __connman_device_disconnect(device);
1527
1528         if (passphrase != NULL) {
1529                 g_free(service->passphrase);
1530                 service->passphrase = g_strdup(passphrase);
1531         }
1532
1533         err = __connman_service_connect(service);
1534         if (err < 0 && err != -EINPROGRESS)
1535                 goto failed;
1536
1537         g_dbus_send_reply(connection, msg,
1538                                 DBUS_TYPE_OBJECT_PATH, &service->path,
1539                                                         DBUS_TYPE_INVALID);
1540
1541         return 0;
1542
1543 failed:
1544         if (service != NULL && created == TRUE) {
1545                 struct connman_network *network = service->network;
1546
1547                 if (network != NULL) {
1548                         connman_network_set_available(network, FALSE);
1549                         __connman_device_cleanup_networks(device);
1550                 }
1551
1552                 __connman_service_put(service);
1553         }
1554
1555         return err;
1556 }
1557
1558 /**
1559  * __connman_service_get:
1560  * @identifier: service identifier
1561  *
1562  * Look up a service by identifier or create a new one if not found
1563  */
1564 static struct connman_service *__connman_service_get(const char *identifier)
1565 {
1566         struct connman_service *service;
1567         GSequenceIter *iter;
1568
1569         iter = g_hash_table_lookup(service_hash, identifier);
1570         if (iter != NULL) {
1571                 service = g_sequence_get(iter);
1572                 if (service != NULL)
1573                         g_atomic_int_inc(&service->refcount);
1574                 return service;
1575         }
1576
1577         service = connman_service_create();
1578         if (service == NULL)
1579                 return NULL;
1580
1581         DBG("service %p", service);
1582
1583         service->identifier = g_strdup(identifier);
1584
1585         service->profile = g_strdup(__connman_profile_active_ident());
1586
1587         __connman_storage_load_service(service);
1588
1589         iter = g_sequence_insert_sorted(service_list, service,
1590                                                 service_compare, NULL);
1591
1592         g_hash_table_insert(service_hash, service->identifier, iter);
1593
1594         return service;
1595 }
1596
1597 static int service_register(struct connman_service *service)
1598 {
1599         const char *path = __connman_profile_active_path();
1600         GSequenceIter *iter;
1601
1602         DBG("service %p", service);
1603
1604         if (service->path != NULL)
1605                 return -EALREADY;
1606
1607         service->path = g_strdup_printf("%s/%s", path, service->identifier);
1608
1609         DBG("path %s", service->path);
1610
1611         g_dbus_register_interface(connection, service->path,
1612                                         CONNMAN_SERVICE_INTERFACE,
1613                                         service_methods, service_signals,
1614                                                         NULL, service, NULL);
1615
1616         __connman_storage_load_service(service);
1617
1618         iter = g_hash_table_lookup(service_hash, service->identifier);
1619         if (iter != NULL)
1620                 g_sequence_sort_changed(iter, service_compare, NULL);
1621
1622         __connman_profile_changed(TRUE);
1623
1624         return 0;
1625 }
1626
1627 static void service_up(struct connman_ipconfig *ipconfig)
1628 {
1629         connman_info("%s up", connman_ipconfig_get_ifname(ipconfig));
1630 }
1631
1632 static void service_down(struct connman_ipconfig *ipconfig)
1633 {
1634         connman_info("%s down", connman_ipconfig_get_ifname(ipconfig));
1635 }
1636
1637 static void service_lower_up(struct connman_ipconfig *ipconfig)
1638 {
1639         connman_info("%s lower up", connman_ipconfig_get_ifname(ipconfig));
1640 }
1641
1642 static void service_lower_down(struct connman_ipconfig *ipconfig)
1643 {
1644         connman_info("%s lower down", connman_ipconfig_get_ifname(ipconfig));
1645 }
1646
1647 static void service_ip_bound(struct connman_ipconfig *ipconfig)
1648 {
1649         connman_info("%s ip bound", connman_ipconfig_get_ifname(ipconfig));
1650 }
1651
1652 static void service_ip_release(struct connman_ipconfig *ipconfig)
1653 {
1654         connman_info("%s ip release", connman_ipconfig_get_ifname(ipconfig));
1655 }
1656
1657 static const struct connman_ipconfig_ops service_ops = {
1658         .up             = service_up,
1659         .down           = service_down,
1660         .lower_up       = service_lower_up,
1661         .lower_down     = service_lower_down,
1662         .ip_bound       = service_ip_bound,
1663         .ip_release     = service_ip_release,
1664 };
1665
1666 static void setup_ipconfig(struct connman_service *service, int index)
1667 {
1668         if (index < 0)
1669                 return;
1670
1671         service->ipconfig = connman_ipconfig_create(index);
1672         if (service->ipconfig == NULL)
1673                 return;
1674
1675         connman_ipconfig_set_method(service->ipconfig,
1676                                         CONNMAN_IPCONFIG_METHOD_DHCP);
1677
1678         __connman_storage_load_service(service);
1679
1680         connman_ipconfig_set_data(service->ipconfig, service);
1681
1682         connman_ipconfig_set_ops(service->ipconfig, &service_ops);
1683         connman_ipconfig_set_ops(service->ipconfig, NULL);
1684 }
1685
1686 /**
1687  * __connman_service_lookup_from_device:
1688  * @device: device structure
1689  *
1690  * Look up a service by device (reference count will not be increased)
1691  */
1692 struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
1693 {
1694         struct connman_service *service;
1695         const char *ident;
1696         char *name;
1697
1698         ident = __connman_device_get_ident(device);
1699         if (ident == NULL)
1700                 return NULL;
1701
1702         name = g_strdup_printf("%s_%s",
1703                                 __connman_device_get_type(device), ident);
1704         service = __connman_service_lookup(name);
1705         g_free(name);
1706
1707         return service;
1708 }
1709
1710 /**
1711  * __connman_service_create_from_device:
1712  * @device: device structure
1713  *
1714  * Look up service by device and if not found, create one
1715  */
1716 struct connman_service *__connman_service_create_from_device(struct connman_device *device)
1717 {
1718         struct connman_service *service;
1719         const char *ident;
1720         char *name;
1721
1722         ident = __connman_device_get_ident(device);
1723         if (ident == NULL)
1724                 return NULL;
1725
1726         name = g_strdup_printf("%s_%s",
1727                                 __connman_device_get_type(device), ident);
1728         service = __connman_service_get(name);
1729         g_free(name);
1730
1731         if (service == NULL)
1732                 return NULL;
1733
1734         if (service->path != NULL) {
1735                 __connman_profile_changed(TRUE);
1736                 return service;
1737         }
1738
1739         service->type = __connman_device_get_service_type(device);
1740
1741         service->autoconnect = FALSE;
1742
1743         service->device = device;
1744
1745         setup_ipconfig(service, connman_device_get_index(device));
1746
1747         service_register(service);
1748
1749         __connman_profile_changed(TRUE);
1750
1751         if (service->favorite == TRUE)
1752                 __connman_service_auto_connect();
1753
1754         return service;
1755 }
1756
1757 void __connman_service_remove_from_device(struct connman_device *device)
1758 {
1759         struct connman_service *service;
1760         enum connman_service_type type;
1761
1762         service = __connman_service_lookup_from_device(device);
1763         if (service == NULL)
1764                 return;
1765
1766         type = service->type;
1767
1768         __connman_service_put(service);
1769
1770         default_changed();
1771
1772         __connman_notifier_disconnect(type);
1773
1774         __connman_service_auto_connect();
1775 }
1776
1777 /**
1778  * __connman_service_lookup_from_network:
1779  * @network: network structure
1780  *
1781  * Look up a service by network (reference count will not be increased)
1782  */
1783 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
1784 {
1785         struct connman_service *service;
1786         const char *ident, *group;
1787         char *name;
1788
1789         ident = __connman_network_get_ident(network);
1790         if (ident == NULL)
1791                 return NULL;
1792
1793         group = connman_network_get_group(network);
1794         if (group == NULL)
1795                 return NULL;
1796
1797         name = g_strdup_printf("%s_%s_%s",
1798                         __connman_network_get_type(network), ident, group);
1799         service = __connman_service_lookup(name);
1800         g_free(name);
1801
1802         return service;
1803 }
1804
1805 const char *__connman_service_get_path(struct connman_service *service)
1806 {
1807         return service->path;
1808 }
1809
1810 unsigned int __connman_service_get_order(struct connman_service *service)
1811 {
1812         GSequenceIter *iter;
1813
1814         if (service == NULL)
1815                 return 0;
1816
1817         if (service->favorite == FALSE) {
1818                 service->order = 0;
1819                 goto done;
1820         }
1821
1822         iter = g_hash_table_lookup(service_hash, service->identifier);
1823         if (iter != NULL) {
1824                 if (g_sequence_iter_get_position(iter) == 0)
1825                         service->order = 1;
1826                 else
1827                         service->order = 0;
1828         }
1829
1830 done:
1831         return service->order;
1832 }
1833
1834 static enum connman_service_type convert_network_type(struct connman_network *network)
1835 {
1836         enum connman_network_type type = connman_network_get_type(network);
1837
1838         switch (type) {
1839         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1840         case CONNMAN_NETWORK_TYPE_VENDOR:
1841                 break;
1842         case CONNMAN_NETWORK_TYPE_WIFI:
1843                 return CONNMAN_SERVICE_TYPE_WIFI;
1844         case CONNMAN_NETWORK_TYPE_WIMAX:
1845                 return CONNMAN_SERVICE_TYPE_WIMAX;
1846         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1847         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1848                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
1849         case CONNMAN_NETWORK_TYPE_MBM:
1850         case CONNMAN_NETWORK_TYPE_HSO:
1851                 return CONNMAN_SERVICE_TYPE_CELLULAR;
1852         }
1853
1854         return CONNMAN_SERVICE_TYPE_UNKNOWN;
1855 }
1856
1857 static enum connman_service_mode convert_wifi_mode(const char *mode)
1858 {
1859         if (mode == NULL)
1860                 return CONNMAN_SERVICE_MODE_UNKNOWN;
1861         else if (g_str_equal(mode, "managed") == TRUE)
1862                 return CONNMAN_SERVICE_MODE_MANAGED;
1863         else if (g_str_equal(mode, "adhoc") == TRUE)
1864                 return CONNMAN_SERVICE_MODE_ADHOC;
1865         else
1866                 return CONNMAN_SERVICE_MODE_UNKNOWN;
1867 }
1868
1869 static enum connman_service_mode convert_wifi_security(const char *security)
1870 {
1871         if (security == NULL)
1872                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
1873         else if (g_str_equal(security, "none") == TRUE)
1874                 return CONNMAN_SERVICE_SECURITY_NONE;
1875         else if (g_str_equal(security, "wep") == TRUE)
1876                 return CONNMAN_SERVICE_SECURITY_WEP;
1877         else if (g_str_equal(security, "wpa") == TRUE)
1878                 return CONNMAN_SERVICE_SECURITY_WPA;
1879         else if (g_str_equal(security, "rsn") == TRUE)
1880                 return CONNMAN_SERVICE_SECURITY_RSN;
1881         else
1882                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
1883 }
1884
1885 static void update_from_network(struct connman_service *service,
1886                                         struct connman_network *network)
1887 {
1888         connman_uint8_t strength = service->strength;
1889         GSequenceIter *iter;
1890         const char *str;
1891
1892         if (service->state == CONNMAN_SERVICE_STATE_READY)
1893                 return;
1894
1895         if (is_connecting(service) == TRUE)
1896                 return;
1897
1898         str = connman_network_get_string(network, "Name");
1899         if (str != NULL) {
1900                 g_free(service->name);
1901                 service->name = g_strdup(str);
1902                 service->hidden = FALSE;
1903         } else {
1904                 g_free(service->name);
1905                 service->name = NULL;
1906                 service->hidden = TRUE;
1907         }
1908
1909         service->strength = connman_network_get_uint8(network, "Strength");
1910
1911         str = connman_network_get_string(network, "WiFi.Mode");
1912         service->mode = convert_wifi_mode(str);
1913
1914         str = connman_network_get_string(network, "WiFi.Security");
1915         service->security = convert_wifi_security(str);
1916
1917         if (service->strength > strength && service->network != NULL) {
1918                 connman_network_unref(service->network);
1919                 service->network = connman_network_ref(network);
1920
1921                 strength_changed(service);
1922         }
1923
1924         if (service->network == NULL)
1925                 service->network = connman_network_ref(network);
1926
1927         iter = g_hash_table_lookup(service_hash, service->identifier);
1928         if (iter != NULL)
1929                 g_sequence_sort_changed(iter, service_compare, NULL);
1930 }
1931
1932 /**
1933  * __connman_service_create_from_network:
1934  * @network: network structure
1935  *
1936  * Look up service by network and if not found, create one
1937  */
1938 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
1939 {
1940         struct connman_service *service;
1941         const char *ident, *group;
1942         char *name;
1943
1944         ident = __connman_network_get_ident(network);
1945         if (ident == NULL)
1946                 return NULL;
1947
1948         group = connman_network_get_group(network);
1949         if (group == NULL)
1950                 return NULL;
1951
1952         name = g_strdup_printf("%s_%s_%s",
1953                         __connman_network_get_type(network), ident, group);
1954         service = __connman_service_get(name);
1955         g_free(name);
1956
1957         if (service == NULL)
1958                 return NULL;
1959
1960         if (__connman_network_get_weakness(network) == TRUE)
1961                 return service;
1962
1963         if (service->path != NULL) {
1964                 update_from_network(service, network);
1965                 __connman_profile_changed(TRUE);
1966                 return service;
1967         }
1968
1969         service->type = convert_network_type(network);
1970
1971         switch (service->type) {
1972         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1973         case CONNMAN_SERVICE_TYPE_ETHERNET:
1974         case CONNMAN_SERVICE_TYPE_WIMAX:
1975         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1976         case CONNMAN_SERVICE_TYPE_CELLULAR:
1977                 service->autoconnect = FALSE;
1978                 break;
1979         case CONNMAN_SERVICE_TYPE_WIFI:
1980                 service->autoconnect = TRUE;
1981                 break;
1982         }
1983
1984         service->state = CONNMAN_SERVICE_STATE_IDLE;
1985
1986         update_from_network(service, network);
1987
1988         setup_ipconfig(service, connman_network_get_index(network));
1989
1990         service_register(service);
1991
1992         __connman_profile_changed(TRUE);
1993
1994         if (service->favorite == TRUE)
1995                 __connman_service_auto_connect();
1996
1997         return service;
1998 }
1999
2000 void __connman_service_update_from_network(struct connman_network *network)
2001 {
2002         struct connman_service *service;
2003         connman_uint8_t strength;
2004
2005         service = __connman_service_lookup_from_network(network);
2006         if (service == NULL)
2007                 return;
2008
2009         if (service->network == NULL)
2010                 return;
2011
2012         strength = connman_network_get_uint8(service->network, "Strength");
2013         if (strength == service->strength)
2014                 return;
2015
2016         service->strength = strength;
2017
2018         strength_changed(service);
2019 }
2020
2021 void __connman_service_remove_from_network(struct connman_network *network)
2022 {
2023         struct connman_service *service;
2024
2025         service = __connman_service_lookup_from_network(network);
2026         if (service == NULL)
2027                 return;
2028
2029         __connman_service_put(service);
2030 }
2031
2032 static int service_load(struct connman_service *service)
2033 {
2034         const char *ident = service->profile;
2035         GKeyFile *keyfile;
2036         GError *error = NULL;
2037         gchar *pathname, *data = NULL;
2038         gsize length;
2039         gchar *str;
2040         connman_bool_t autoconnect;
2041         unsigned int ssid_len;
2042         int err = 0;
2043
2044         DBG("service %p", service);
2045
2046         if (ident == NULL)
2047                 return -EINVAL;
2048
2049         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
2050         if (pathname == NULL)
2051                 return -ENOMEM;
2052
2053         keyfile = g_key_file_new();
2054
2055         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
2056                 g_free(pathname);
2057                 return -ENOENT;
2058         }
2059
2060         g_free(pathname);
2061
2062         if (g_key_file_load_from_data(keyfile, data, length,
2063                                                         0, NULL) == FALSE) {
2064                 g_free(data);
2065                 return -EILSEQ;
2066         }
2067
2068         g_free(data);
2069
2070         switch (service->type) {
2071         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2072         case CONNMAN_SERVICE_TYPE_ETHERNET:
2073                 break;
2074         case CONNMAN_SERVICE_TYPE_WIFI:
2075                 if (service->name == NULL) {
2076                         gchar *name;
2077
2078                         name = g_key_file_get_string(keyfile,
2079                                         service->identifier, "Name", NULL);
2080                         if (name != NULL) {
2081                                 g_free(service->name);
2082                                 service->name = name;
2083                         }
2084
2085                         if (service->network != NULL)
2086                                 connman_network_set_name(service->network,
2087                                                                         name);
2088                 }
2089
2090                 if (service->network &&
2091                                 connman_network_get_blob(service->network,
2092                                         "WiFi.SSID", &ssid_len) == NULL) {
2093                         gchar *hex_ssid;
2094
2095                         hex_ssid = g_key_file_get_string(keyfile,
2096                                                         service->identifier,
2097                                                                 "SSID", NULL);
2098
2099                         if (hex_ssid != NULL) {
2100                                 gchar *ssid;
2101                                 unsigned int i, j = 0, hex;
2102                                 size_t hex_ssid_len = strlen(hex_ssid);
2103
2104                                 ssid = g_try_malloc0(hex_ssid_len / 2);
2105                                 if (ssid == NULL) {
2106                                         g_free(hex_ssid);
2107                                         err = -ENOMEM;
2108                                         goto done;
2109                                 }
2110
2111                                 for (i = 0; i < hex_ssid_len; i += 2) {
2112                                         sscanf(hex_ssid + i, "%02x", &hex);
2113                                         ssid[j++] = hex;
2114                                 }
2115
2116                                 connman_network_set_blob(service->network,
2117                                         "WiFi.SSID", ssid, hex_ssid_len / 2);
2118                         }
2119
2120                         g_free(hex_ssid);
2121                 }
2122                 /* fall through */
2123
2124         case CONNMAN_SERVICE_TYPE_WIMAX:
2125         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2126         case CONNMAN_SERVICE_TYPE_CELLULAR:
2127                 service->favorite = g_key_file_get_boolean(keyfile,
2128                                 service->identifier, "Favorite", NULL);
2129
2130                 autoconnect = g_key_file_get_boolean(keyfile,
2131                                 service->identifier, "AutoConnect", &error);
2132                 if (error == NULL)
2133                         service->autoconnect = autoconnect;
2134                 g_clear_error(&error);
2135
2136                 str = g_key_file_get_string(keyfile,
2137                                 service->identifier, "Failure", NULL);
2138                 if (str != NULL) {
2139                         service->state = CONNMAN_SERVICE_STATE_FAILURE;
2140                         service->error = string2error(str);
2141                 }
2142                 break;
2143         }
2144
2145         str = g_key_file_get_string(keyfile,
2146                                 service->identifier, "Modified", NULL);
2147         if (str != NULL) {
2148                 g_time_val_from_iso8601(str, &service->modified);
2149                 g_free(str);
2150         }
2151
2152         str = g_key_file_get_string(keyfile,
2153                                 service->identifier, "Passphrase", NULL);
2154         if (str != NULL) {
2155                 g_free(service->passphrase);
2156                 service->passphrase = str;
2157         }
2158
2159         if (service->ipconfig != NULL)
2160                 __connman_ipconfig_load(service->ipconfig, keyfile,
2161                                         service->identifier, "IPv4.");
2162
2163 done:
2164         g_key_file_free(keyfile);
2165
2166         return err;
2167 }
2168
2169 static int service_save(struct connman_service *service)
2170 {
2171         const char *ident = service->profile;
2172         GKeyFile *keyfile;
2173         gchar *pathname, *data = NULL;
2174         gsize length;
2175         gchar *str;
2176         int err = 0;
2177
2178         DBG("service %p", service);
2179
2180         if (ident == NULL)
2181                 return -EINVAL;
2182
2183         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
2184         if (pathname == NULL)
2185                 return -ENOMEM;
2186
2187         keyfile = g_key_file_new();
2188
2189         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
2190                 goto update;
2191
2192         if (length > 0) {
2193                 if (g_key_file_load_from_data(keyfile, data, length,
2194                                                         0, NULL) == FALSE)
2195                         goto done;
2196         }
2197
2198         g_free(data);
2199
2200 update:
2201         if (service->name != NULL)
2202                 g_key_file_set_string(keyfile, service->identifier,
2203                                                 "Name", service->name);
2204
2205         switch (service->type) {
2206         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2207         case CONNMAN_SERVICE_TYPE_ETHERNET:
2208                 break;
2209         case CONNMAN_SERVICE_TYPE_WIFI:
2210                 if (service->network) {
2211                         const unsigned char *ssid;
2212                         unsigned int ssid_len = 0;
2213
2214                         ssid = connman_network_get_blob(service->network,
2215                                                         "WiFi.SSID", &ssid_len);
2216
2217                         if (ssid != NULL && ssid_len > 0 && ssid[0] != '\0') {
2218                                 char *identifier = service->identifier;
2219                                 GString *str;
2220                                 unsigned int i;
2221
2222                                 str = g_string_sized_new(ssid_len * 2);
2223                                 if (str == NULL) {
2224                                         err = -ENOMEM;
2225                                         goto done;
2226                                 }
2227
2228                                 for (i = 0; i < ssid_len; i++)
2229                                         g_string_append_printf(str,
2230                                                         "%02x", ssid[i]);
2231
2232                                 g_key_file_set_string(keyfile, identifier,
2233                                                         "SSID", str->str);
2234
2235                                 g_string_free(str, TRUE);
2236                         }
2237                 }
2238                 /* fall through */
2239
2240         case CONNMAN_SERVICE_TYPE_WIMAX:
2241         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2242         case CONNMAN_SERVICE_TYPE_CELLULAR:
2243                 g_key_file_set_boolean(keyfile, service->identifier,
2244                                         "Favorite", service->favorite);
2245
2246                 if (service->favorite == TRUE)
2247                         g_key_file_set_boolean(keyfile, service->identifier,
2248                                         "AutoConnect", service->autoconnect);
2249
2250                 if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
2251                         const char *failure = error2string(service->error);
2252                         if (failure != NULL)
2253                                 g_key_file_set_string(keyfile,
2254                                                         service->identifier,
2255                                                         "Failure", failure);
2256                 } else {
2257                         g_key_file_remove_key(keyfile, service->identifier,
2258                                                         "Failure", NULL);
2259                 }
2260                 break;
2261         }
2262
2263         str = g_time_val_to_iso8601(&service->modified);
2264         if (str != NULL) {
2265                 g_key_file_set_string(keyfile, service->identifier,
2266                                                         "Modified", str);
2267                 g_free(str);
2268         }
2269
2270         if (service->passphrase != NULL && strlen(service->passphrase) > 0)
2271                 g_key_file_set_string(keyfile, service->identifier,
2272                                         "Passphrase", service->passphrase);
2273         else
2274                 g_key_file_remove_key(keyfile, service->identifier,
2275                                                         "Passphrase", NULL);
2276
2277         if (service->ipconfig != NULL)
2278                 __connman_ipconfig_save(service->ipconfig, keyfile,
2279                                         service->identifier, "IPv4.");
2280
2281         data = g_key_file_to_data(keyfile, &length, NULL);
2282
2283         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
2284                 connman_error("Failed to store service information");
2285
2286 done:
2287         g_free(data);
2288
2289         g_key_file_free(keyfile);
2290
2291         g_free(pathname);
2292
2293         return err;
2294 }
2295
2296 static struct connman_storage service_storage = {
2297         .name           = "service",
2298         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
2299         .service_load   = service_load,
2300         .service_save   = service_save,
2301 };
2302
2303 int __connman_service_init(void)
2304 {
2305         DBG("");
2306
2307         connection = connman_dbus_get_connection();
2308
2309         if (connman_storage_register(&service_storage) < 0)
2310                 connman_error("Failed to register service storage");
2311
2312         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2313                                                                 NULL, NULL);
2314
2315         service_list = g_sequence_new(service_free);
2316
2317         return 0;
2318 }
2319
2320 void __connman_service_cleanup(void)
2321 {
2322         DBG("");
2323
2324         g_sequence_free(service_list);
2325         service_list = NULL;
2326
2327         g_hash_table_destroy(service_hash);
2328         service_hash = NULL;
2329
2330         connman_storage_unregister(&service_storage);
2331
2332         dbus_connection_unref(connection);
2333 }