Disable IP configuration callbacks for now
[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 <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 != -EINPROGRESS) {
760                         dbus_message_unref(service->pending);
761                         service->pending = NULL;
762
763                         return __connman_error_failed(msg, -err);
764                 }
765
766                 return NULL;
767         }
768
769         dbus_message_unref(service->pending);
770         service->pending = NULL;
771
772         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
773 }
774
775 static DBusMessage *disconnect_service(DBusConnection *conn,
776                                         DBusMessage *msg, void *user_data)
777 {
778         struct connman_service *service = user_data;
779         int err;
780
781         DBG("service %p", service);
782
783         service->ignore = TRUE;
784
785         err = __connman_service_disconnect(service);
786         if (err < 0) {
787                 if (err != -EINPROGRESS)
788                         return __connman_error_failed(msg, -err);
789
790                 return NULL;
791         }
792
793         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
794 }
795
796 static DBusMessage *remove_service(DBusConnection *conn,
797                                         DBusMessage *msg, void *user_data)
798 {
799         struct connman_service *service = user_data;
800
801         DBG("service %p", service);
802
803         if (service->type == CONNMAN_SERVICE_TYPE_ETHERNET)
804                 return __connman_error_not_supported(msg);
805
806         if (service->favorite == FALSE)
807                 return __connman_error_not_supported(msg);
808
809         if (service->network != NULL)
810                 __connman_network_disconnect(service->network);
811
812         g_free(service->passphrase);
813         service->passphrase = NULL;
814
815         passphrase_changed(service);
816
817         connman_service_set_favorite(service, FALSE);
818         __connman_storage_save_service(service);
819
820         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
821 }
822
823 static DBusMessage *move_before(DBusConnection *conn,
824                                         DBusMessage *msg, void *user_data)
825 {
826         struct connman_service *service = user_data;
827         struct connman_service *target;
828         const char *path;
829         GSequenceIter *src, *dst;
830
831         DBG("service %p", service);
832
833         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
834                                                         DBUS_TYPE_INVALID);
835
836         if (service->favorite == FALSE)
837                 return __connman_error_not_supported(msg);
838
839         target = find_service(path);
840         if (target == NULL || target->favorite == FALSE || target == service)
841                 return __connman_error_invalid_service(msg);
842
843         DBG("target %s", target->identifier);
844
845         if (target->state != service->state)
846                 return __connman_error_invalid_service(msg);
847
848         g_get_current_time(&service->modified);
849         __connman_storage_save_service(service);
850
851         src = g_hash_table_lookup(service_hash, service->identifier);
852         dst = g_hash_table_lookup(service_hash, target->identifier);
853
854         g_sequence_move(src, dst);
855
856         __connman_profile_changed(FALSE);
857
858         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
859 }
860
861 static DBusMessage *move_after(DBusConnection *conn,
862                                         DBusMessage *msg, void *user_data)
863 {
864         struct connman_service *service = user_data;
865         struct connman_service *target;
866         const char *path;
867
868         DBG("service %p", service);
869
870         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
871                                                         DBUS_TYPE_INVALID);
872
873         if (service->favorite == FALSE)
874                 return __connman_error_not_supported(msg);
875
876         target = find_service(path);
877         if (target == NULL || target->favorite == FALSE || target == service)
878                 return __connman_error_invalid_service(msg);
879
880         DBG("target %s", target->identifier);
881
882         if (target->state != service->state)
883                 return __connman_error_invalid_service(msg);
884
885         g_get_current_time(&service->modified);
886         __connman_storage_save_service(service);
887
888         return __connman_error_not_implemented(msg);
889 }
890
891 static GDBusMethodTable service_methods[] = {
892         { "GetProperties", "",   "a{sv}", get_properties     },
893         { "SetProperty",   "sv", "",      set_property       },
894         { "ClearProperty", "s",  "",      clear_property     },
895         { "Connect",       "",   "",      connect_service,
896                                                 G_DBUS_METHOD_FLAG_ASYNC },
897         { "Disconnect",    "",   "",      disconnect_service },
898         { "Remove",        "",   "",      remove_service     },
899         { "MoveBefore",    "o",  "",      move_before        },
900         { "MoveAfter",     "o",  "",      move_after         },
901         { },
902 };
903
904 static GDBusSignalTable service_signals[] = {
905         { "PropertyChanged", "sv" },
906         { },
907 };
908
909 static void service_free(gpointer user_data)
910 {
911         struct connman_service *service = user_data;
912         char *path = service->path;
913
914         DBG("service %p", service);
915
916         reply_pending(service, ENOENT);
917
918         g_hash_table_remove(service_hash, service->identifier);
919
920         service->path = NULL;
921
922         if (path != NULL) {
923                 __connman_profile_changed(FALSE);
924
925                 g_dbus_unregister_interface(connection, path,
926                                                 CONNMAN_SERVICE_INTERFACE);
927                 g_free(path);
928         }
929
930         if (service->network != NULL)
931                 connman_network_unref(service->network);
932
933         if (service->ipconfig != NULL) {
934                 connman_ipconfig_unref(service->ipconfig);
935                 service->ipconfig = NULL;
936         }
937
938         g_free(service->profile);
939         g_free(service->name);
940         g_free(service->passphrase);
941         g_free(service->identifier);
942         g_free(service);
943 }
944
945 /**
946  * __connman_service_put:
947  * @service: service structure
948  *
949  * Release service if no longer needed
950  */
951 void __connman_service_put(struct connman_service *service)
952 {
953         DBG("service %p", service);
954
955         if (g_atomic_int_dec_and_test(&service->refcount) == TRUE) {
956                 GSequenceIter *iter;
957
958                 iter = g_hash_table_lookup(service_hash, service->identifier);
959                 if (iter != NULL) {
960                         __connman_service_disconnect(service);
961                         g_sequence_remove(iter);
962                 } else
963                         service_free(service);
964         }
965 }
966
967 static void __connman_service_initialize(struct connman_service *service)
968 {
969         DBG("service %p", service);
970
971         service->refcount = 1;
972
973         service->type     = CONNMAN_SERVICE_TYPE_UNKNOWN;
974         service->mode     = CONNMAN_SERVICE_MODE_UNKNOWN;
975         service->security = CONNMAN_SERVICE_SECURITY_UNKNOWN;
976         service->state    = CONNMAN_SERVICE_STATE_UNKNOWN;
977
978         service->favorite = FALSE;
979         service->hidden = FALSE;
980
981         service->ignore = FALSE;
982
983         service->order = 0;
984 }
985
986 /**
987  * connman_service_create:
988  *
989  * Allocate a new service.
990  *
991  * Returns: a newly-allocated #connman_service structure
992  */
993 struct connman_service *connman_service_create(void)
994 {
995         struct connman_service *service;
996
997         service = g_try_new0(struct connman_service, 1);
998         if (service == NULL)
999                 return NULL;
1000
1001         DBG("service %p", service);
1002
1003         __connman_service_initialize(service);
1004
1005         return service;
1006 }
1007
1008 /**
1009  * connman_service_ref:
1010  * @service: service structure
1011  *
1012  * Increase reference counter of service
1013  */
1014 struct connman_service *connman_service_ref(struct connman_service *service)
1015 {
1016         g_atomic_int_inc(&service->refcount);
1017
1018         return service;
1019 }
1020
1021 /**
1022  * connman_service_unref:
1023  * @service: service structure
1024  *
1025  * Decrease reference counter of service
1026  */
1027 void connman_service_unref(struct connman_service *service)
1028 {
1029         __connman_service_put(service);
1030 }
1031
1032 static gint service_compare(gconstpointer a, gconstpointer b,
1033                                                         gpointer user_data)
1034 {
1035         struct connman_service *service_a = (void *) a;
1036         struct connman_service *service_b = (void *) b;
1037
1038         if (service_a->state != service_b->state) {
1039                 if (service_a->state == CONNMAN_SERVICE_STATE_READY)
1040                         return -1;
1041                 if (service_b->state == CONNMAN_SERVICE_STATE_READY)
1042                         return 1;
1043         }
1044
1045         if (service_a->order > service_b->order)
1046                 return -1;
1047
1048         if (service_a->order < service_b->order)
1049                 return 1;
1050
1051         if (service_a->favorite == TRUE && service_b->favorite == FALSE)
1052                 return -1;
1053
1054         if (service_a->favorite == FALSE && service_b->favorite == TRUE)
1055                 return 1;
1056
1057         if (service_a->type != service_b->type) {
1058                 switch (service_a->type) {
1059                 case CONNMAN_SERVICE_TYPE_UNKNOWN:
1060                 case CONNMAN_SERVICE_TYPE_ETHERNET:
1061                         break;
1062                 case CONNMAN_SERVICE_TYPE_WIFI:
1063                         return 1;
1064                 case CONNMAN_SERVICE_TYPE_WIMAX:
1065                 case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1066                 case CONNMAN_SERVICE_TYPE_CELLULAR:
1067                         return -1;
1068                 }
1069         }
1070
1071         return (gint) service_b->strength - (gint) service_a->strength;
1072 }
1073
1074 /**
1075  * connman_service_set_favorite:
1076  * @service: service structure
1077  * @favorite: favorite value
1078  *
1079  * Change the favorite setting of service
1080  */
1081 int connman_service_set_favorite(struct connman_service *service,
1082                                                 connman_bool_t favorite)
1083 {
1084         GSequenceIter *iter;
1085
1086         iter = g_hash_table_lookup(service_hash, service->identifier);
1087         if (iter == NULL)
1088                 return -ENOENT;
1089
1090         if (service->favorite == favorite)
1091                 return -EALREADY;
1092
1093         service->favorite = favorite;
1094
1095         g_sequence_sort_changed(iter, service_compare, NULL);
1096
1097         __connman_profile_changed(FALSE);
1098
1099         return 0;
1100 }
1101
1102 static void default_changed(void)
1103 {
1104         DBusMessage *signal;
1105         DBusMessageIter entry, value;
1106         const char *key = "DefaultTechnology";
1107         const char *str = __connman_service_default();
1108
1109         signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
1110                                 CONNMAN_MANAGER_INTERFACE, "PropertyChanged");
1111         if (signal == NULL)
1112                 return;
1113
1114         dbus_message_iter_init_append(signal, &entry);
1115
1116         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
1117
1118         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
1119                                         DBUS_TYPE_STRING_AS_STRING, &value);
1120         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
1121         dbus_message_iter_close_container(&entry, &value);
1122
1123         g_dbus_send_message(connection, signal);
1124 }
1125
1126 int __connman_service_indicate_state(struct connman_service *service,
1127                                         enum connman_service_state state)
1128 {
1129         GSequenceIter *iter;
1130
1131         DBG("service %p state %d", service, state);
1132
1133         if (service == NULL)
1134                 return -EINVAL;
1135
1136         if (service->state == state)
1137                 return -EALREADY;
1138
1139         if (service->state == CONNMAN_SERVICE_STATE_FAILURE &&
1140                                 state == CONNMAN_SERVICE_STATE_IDLE)
1141                 return -EINVAL;
1142
1143         if (service->state == CONNMAN_SERVICE_STATE_IDLE &&
1144                                 state == CONNMAN_SERVICE_STATE_DISCONNECT)
1145                 return -EINVAL;
1146
1147         if (state == CONNMAN_SERVICE_STATE_IDLE &&
1148                         service->state != CONNMAN_SERVICE_STATE_DISCONNECT) {
1149                 service->state = CONNMAN_SERVICE_STATE_DISCONNECT;
1150                 state_changed(service);
1151
1152                 __connman_service_disconnect(service);
1153         }
1154
1155         service->state = state;
1156         state_changed(service);
1157
1158         if (state == CONNMAN_SERVICE_STATE_READY) {
1159                 connman_service_set_favorite(service, TRUE);
1160
1161                 reply_pending(service, 0);
1162
1163                 g_get_current_time(&service->modified);
1164                 __connman_storage_save_service(service);
1165
1166                 __connman_notifier_connect(service->type);
1167
1168                 default_changed();
1169         } else if (state == CONNMAN_SERVICE_STATE_DISCONNECT) {
1170                 default_changed();
1171
1172                 __connman_notifier_disconnect(service->type);
1173         }
1174
1175         if (state == CONNMAN_SERVICE_STATE_FAILURE) {
1176                 reply_pending(service, EIO);
1177
1178                 g_get_current_time(&service->modified);
1179                 __connman_storage_save_service(service);
1180         } else
1181                 service->error = CONNMAN_SERVICE_ERROR_UNKNOWN;
1182
1183         iter = g_hash_table_lookup(service_hash, service->identifier);
1184         if (iter != NULL)
1185                 g_sequence_sort_changed(iter, service_compare, NULL);
1186
1187         __connman_profile_changed(FALSE);
1188
1189         if (service->state == CONNMAN_SERVICE_STATE_IDLE ||
1190                         service->state == CONNMAN_SERVICE_STATE_FAILURE)
1191                 __connman_element_request_scan(CONNMAN_ELEMENT_TYPE_UNKNOWN);
1192
1193         return 0;
1194 }
1195
1196 int __connman_service_indicate_error(struct connman_service *service,
1197                                         enum connman_service_error error)
1198 {
1199         DBG("service %p error %d", service, error);
1200
1201         if (service == NULL)
1202                 return -EINVAL;
1203
1204         service->error = error;
1205
1206         return __connman_service_indicate_state(service,
1207                                         CONNMAN_SERVICE_STATE_FAILURE);
1208 }
1209
1210 int __connman_service_indicate_default(struct connman_service *service)
1211 {
1212         DBG("service %p", service);
1213
1214         default_changed();
1215
1216         return 0;
1217 }
1218
1219 static connman_bool_t prepare_network(struct connman_service *service)
1220 {
1221         enum connman_network_type type;
1222         unsigned int ssid_len;
1223
1224         type = connman_network_get_type(service->network);
1225
1226         switch (type) {
1227         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1228         case CONNMAN_NETWORK_TYPE_VENDOR:
1229                 return FALSE;
1230         case CONNMAN_NETWORK_TYPE_WIFI:
1231                 if (connman_network_get_blob(service->network, "WiFi.SSID",
1232                                                         &ssid_len) == NULL)
1233                         return FALSE;
1234
1235                 connman_network_set_string(service->network,
1236                                 "WiFi.Passphrase", service->passphrase);
1237                 break;
1238         case CONNMAN_NETWORK_TYPE_WIMAX:
1239         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1240         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1241         case CONNMAN_NETWORK_TYPE_MBM:
1242         case CONNMAN_NETWORK_TYPE_HSO:
1243                 break;
1244         }
1245
1246         return TRUE;
1247 }
1248
1249 int __connman_service_connect(struct connman_service *service)
1250 {
1251         int err;
1252
1253         DBG("service %p", service);
1254
1255         if (service->state == CONNMAN_SERVICE_STATE_READY)
1256                 return -EISCONN;
1257
1258         if (is_connecting(service) == TRUE)
1259                 return -EALREADY;
1260
1261         switch (service->type) {
1262         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1263                 return -EINVAL;
1264         case CONNMAN_SERVICE_TYPE_ETHERNET:
1265         case CONNMAN_SERVICE_TYPE_WIMAX:
1266         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1267         case CONNMAN_SERVICE_TYPE_CELLULAR:
1268                 break;
1269         case CONNMAN_SERVICE_TYPE_WIFI:
1270                 switch (service->security) {
1271                 case CONNMAN_SERVICE_SECURITY_UNKNOWN:
1272                 case CONNMAN_SERVICE_SECURITY_NONE:
1273                         break;
1274                 case CONNMAN_SERVICE_SECURITY_WEP:
1275                 case CONNMAN_SERVICE_SECURITY_WPA:
1276                 case CONNMAN_SERVICE_SECURITY_RSN:
1277                         if (service->passphrase == NULL)
1278                                 return -ENOKEY;
1279                         break;
1280                 }
1281                 break;
1282         }
1283
1284         if (service->network != NULL) {
1285                 if (prepare_network(service) == FALSE)
1286                         return -EINVAL;
1287
1288                 __connman_ipconfig_enable(service->ipconfig);
1289
1290                 err = __connman_network_connect(service->network);
1291         } else if (service->device != NULL) {
1292                 if (service->favorite == FALSE)
1293                         return -ENOLINK;
1294
1295                 __connman_ipconfig_enable(service->ipconfig);
1296
1297                 err = __connman_device_connect(service->device);
1298         } else
1299                 return -EOPNOTSUPP;
1300
1301         if (err < 0) {
1302                 if (err != -EINPROGRESS) {
1303                         __connman_ipconfig_disable(service->ipconfig);
1304                         return err;
1305                 }
1306
1307                 service->timeout = g_timeout_add_seconds(45,
1308                                                 connect_timeout, service);
1309
1310                 return -EINPROGRESS;
1311         }
1312
1313         return 0;
1314 }
1315
1316 int __connman_service_disconnect(struct connman_service *service)
1317 {
1318         int err;
1319
1320         DBG("service %p", service);
1321
1322         reply_pending(service, ECONNABORTED);
1323
1324         if (service->network != NULL) {
1325                 err = __connman_network_disconnect(service->network);
1326         } else if (service->device != NULL) {
1327                 if (service->favorite == FALSE)
1328                         return -ENOLINK;
1329                 err = __connman_device_disconnect(service->device);
1330         } else
1331                 return -EOPNOTSUPP;
1332
1333         __connman_ipconfig_disable(service->ipconfig);
1334
1335         if (err < 0) {
1336                 if (err != -EINPROGRESS)
1337                         return err;
1338
1339                 return -EINPROGRESS;
1340         }
1341
1342         return 0;
1343 }
1344
1345 /**
1346  * __connman_service_lookup:
1347  * @identifier: service identifier
1348  *
1349  * Look up a service by identifier (reference count will not be increased)
1350  */
1351 static struct connman_service *__connman_service_lookup(const char *identifier)
1352 {
1353         GSequenceIter *iter;
1354
1355         iter = g_hash_table_lookup(service_hash, identifier);
1356         if (iter != NULL)
1357                 return g_sequence_get(iter);
1358
1359         return NULL;
1360 }
1361
1362 static struct connman_network *create_hidden_wifi(struct connman_device *device,
1363                 const char *ssid, const char *mode, const char *security)
1364 {
1365         struct connman_network *network;
1366         char *name;
1367         int index;
1368         unsigned int i, ssid_len;
1369
1370         ssid_len = strlen(ssid);
1371         if (ssid_len < 1)
1372                 return NULL;
1373
1374         network = connman_network_create(NULL, CONNMAN_NETWORK_TYPE_WIFI);
1375         if (network == NULL)
1376                 return NULL;
1377
1378         connman_network_set_blob(network, "WiFi.SSID",
1379                                         (unsigned char *) ssid, ssid_len);
1380
1381         connman_network_set_string(network, "WiFi.Mode", mode);
1382         connman_network_set_string(network, "WiFi.Security", security);
1383
1384         name = g_try_malloc0(ssid_len + 1);
1385         if (name == NULL) {
1386                 connman_network_unref(network);
1387                 return NULL;
1388         }
1389
1390         for (i = 0; i < ssid_len; i++) {
1391                 if (g_ascii_isprint(ssid[i]))
1392                         name[i] = ssid[i];
1393                 else
1394                         name[i] = ' ';
1395         }
1396
1397         connman_network_set_name(network, name);
1398
1399         g_free(name);
1400
1401         index = connman_device_get_index(device);
1402         connman_network_set_index(network, index);
1403
1404         connman_network_set_protocol(network, CONNMAN_NETWORK_PROTOCOL_IP);
1405
1406         if (connman_device_add_network(device, network) < 0) {
1407                 connman_network_unref(network);
1408                 return NULL;
1409         }
1410
1411         connman_network_set_available(network, TRUE);
1412
1413         return network;
1414 }
1415
1416 int __connman_service_create_and_connect(DBusMessage *msg)
1417 {
1418         struct connman_service *service;
1419         struct connman_network *network;
1420         struct connman_device *device;
1421         DBusMessageIter iter, array;
1422         const char *mode = "managed", *security = "none";
1423         const char *type = NULL, *ssid = NULL, *passphrase = NULL;
1424         unsigned int ssid_len = 0;
1425         const char *ident;
1426         char *name, *group;
1427         gboolean created = FALSE;
1428         int err;
1429
1430         dbus_message_iter_init(msg, &iter);
1431         dbus_message_iter_recurse(&iter, &array);
1432
1433         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
1434                 DBusMessageIter entry, value;
1435                 const char *key;
1436
1437                 dbus_message_iter_recurse(&array, &entry);
1438                 dbus_message_iter_get_basic(&entry, &key);
1439
1440                 dbus_message_iter_next(&entry);
1441                 dbus_message_iter_recurse(&entry, &value);
1442
1443                 switch (dbus_message_iter_get_arg_type(&value)) {
1444                 case DBUS_TYPE_STRING:
1445                         if (g_str_equal(key, "Type") == TRUE)
1446                                 dbus_message_iter_get_basic(&value, &type);
1447                         else if (g_str_equal(key, "WiFi.Mode") == TRUE ||
1448                                         g_str_equal(key, "Mode") == TRUE)
1449                                 dbus_message_iter_get_basic(&value, &mode);
1450                         else if (g_str_equal(key, "WiFi.Security") == TRUE ||
1451                                         g_str_equal(key, "Security") == TRUE)
1452                                 dbus_message_iter_get_basic(&value, &security);
1453                         else if (g_str_equal(key, "WiFi.Passphrase") == TRUE ||
1454                                         g_str_equal(key, "Passphrase") == TRUE)
1455                                 dbus_message_iter_get_basic(&value, &passphrase);
1456                         else if (g_str_equal(key, "WiFi.SSID") == TRUE ||
1457                                         g_str_equal(key, "SSID") == TRUE)
1458                                 dbus_message_iter_get_basic(&value, &ssid);
1459                 }
1460
1461                 dbus_message_iter_next(&array);
1462         }
1463
1464         if (type == NULL)
1465                 return -EINVAL;
1466
1467         if (g_strcmp0(type, "wifi") != 0 || g_strcmp0(mode, "managed") != 0)
1468                 return -EOPNOTSUPP;
1469
1470         if (ssid == NULL)
1471                 return -EINVAL;
1472
1473         ssid_len = strlen(ssid);
1474         if (ssid_len < 1)
1475                 return -EINVAL;
1476
1477         if (g_strcmp0(security, "none") != 0 &&
1478                         g_strcmp0(security, "wep") != 0 &&
1479                                 g_strcmp0(security, "wpa") != 0 &&
1480                                         g_strcmp0(security, "rsn") != 0)
1481                 return -EINVAL;
1482
1483         device = __connman_element_find_device(CONNMAN_SERVICE_TYPE_WIFI);
1484         if (device == NULL)
1485                 return -EOPNOTSUPP;
1486
1487         ident = __connman_device_get_ident(device);
1488         if (ident == NULL)
1489                 return -EOPNOTSUPP;
1490
1491         group = connman_wifi_build_group_name((unsigned char *) ssid,
1492                                                 ssid_len, mode, security);
1493         if (group == NULL)
1494                 return -EINVAL;
1495
1496         name = g_strdup_printf("%s_%s_%s", type, ident, group);
1497
1498         service = __connman_service_lookup(name);
1499
1500         if (service != NULL)
1501                 goto done;
1502
1503         network = create_hidden_wifi(device, ssid, mode, security);
1504         if (network != NULL) {
1505                 connman_network_set_group(network, group);
1506                 created = TRUE;
1507         }
1508
1509         service = __connman_service_lookup(name);
1510
1511 done:
1512         g_free(name);
1513         g_free(group);
1514
1515         if (service == NULL) {
1516                 err = -EOPNOTSUPP;
1517                 goto failed;
1518         }
1519
1520         __connman_device_disconnect(device);
1521
1522         if (passphrase != NULL) {
1523                 g_free(service->passphrase);
1524                 service->passphrase = g_strdup(passphrase);
1525         }
1526
1527         err = __connman_service_connect(service);
1528         if (err < 0 && err != -EINPROGRESS)
1529                 goto failed;
1530
1531         g_dbus_send_reply(connection, msg,
1532                                 DBUS_TYPE_OBJECT_PATH, &service->path,
1533                                                         DBUS_TYPE_INVALID);
1534
1535         return 0;
1536
1537 failed:
1538         if (service != NULL && created == TRUE) {
1539                 struct connman_network *network = service->network;
1540
1541                 if (network != NULL) {
1542                         connman_network_set_available(network, FALSE);
1543                         __connman_device_cleanup_networks(device);
1544                 }
1545
1546                 __connman_service_put(service);
1547         }
1548
1549         return err;
1550 }
1551
1552 /**
1553  * __connman_service_get:
1554  * @identifier: service identifier
1555  *
1556  * Look up a service by identifier or create a new one if not found
1557  */
1558 static struct connman_service *__connman_service_get(const char *identifier)
1559 {
1560         struct connman_service *service;
1561         GSequenceIter *iter;
1562
1563         iter = g_hash_table_lookup(service_hash, identifier);
1564         if (iter != NULL) {
1565                 service = g_sequence_get(iter);
1566                 if (service != NULL)
1567                         g_atomic_int_inc(&service->refcount);
1568                 return service;
1569         }
1570
1571         service = connman_service_create();
1572         if (service == NULL)
1573                 return NULL;
1574
1575         DBG("service %p", service);
1576
1577         service->identifier = g_strdup(identifier);
1578
1579         service->profile = g_strdup(__connman_profile_active_ident());
1580
1581         __connman_storage_load_service(service);
1582
1583         iter = g_sequence_insert_sorted(service_list, service,
1584                                                 service_compare, NULL);
1585
1586         g_hash_table_insert(service_hash, service->identifier, iter);
1587
1588         return service;
1589 }
1590
1591 static int service_register(struct connman_service *service)
1592 {
1593         const char *path = __connman_profile_active_path();
1594         GSequenceIter *iter;
1595
1596         DBG("service %p", service);
1597
1598         if (service->path != NULL)
1599                 return -EALREADY;
1600
1601         service->path = g_strdup_printf("%s/%s", path, service->identifier);
1602
1603         DBG("path %s", service->path);
1604
1605         g_dbus_register_interface(connection, service->path,
1606                                         CONNMAN_SERVICE_INTERFACE,
1607                                         service_methods, service_signals,
1608                                                         NULL, service, NULL);
1609
1610         __connman_storage_load_service(service);
1611
1612         iter = g_hash_table_lookup(service_hash, service->identifier);
1613         if (iter != NULL)
1614                 g_sequence_sort_changed(iter, service_compare, NULL);
1615
1616         __connman_profile_changed(TRUE);
1617
1618         return 0;
1619 }
1620
1621 static void service_up(struct connman_ipconfig *ipconfig)
1622 {
1623         connman_info("%s up", connman_ipconfig_get_ifname(ipconfig));
1624 }
1625
1626 static void service_down(struct connman_ipconfig *ipconfig)
1627 {
1628         connman_info("%s down", connman_ipconfig_get_ifname(ipconfig));
1629 }
1630
1631 static void service_lower_up(struct connman_ipconfig *ipconfig)
1632 {
1633         connman_info("%s lower up", connman_ipconfig_get_ifname(ipconfig));
1634 }
1635
1636 static void service_lower_down(struct connman_ipconfig *ipconfig)
1637 {
1638         connman_info("%s lower down", connman_ipconfig_get_ifname(ipconfig));
1639 }
1640
1641 static void service_ip_bound(struct connman_ipconfig *ipconfig)
1642 {
1643         connman_info("%s ip bound", connman_ipconfig_get_ifname(ipconfig));
1644 }
1645
1646 static void service_ip_release(struct connman_ipconfig *ipconfig)
1647 {
1648         connman_info("%s ip release", connman_ipconfig_get_ifname(ipconfig));
1649 }
1650
1651 static const struct connman_ipconfig_ops service_ops = {
1652         .up             = service_up,
1653         .down           = service_down,
1654         .lower_up       = service_lower_up,
1655         .lower_down     = service_lower_down,
1656         .ip_bound       = service_ip_bound,
1657         .ip_release     = service_ip_release,
1658 };
1659
1660 static void setup_ipconfig(struct connman_service *service, int index)
1661 {
1662         if (index < 0)
1663                 return;
1664
1665         service->ipconfig = connman_ipconfig_create(index);
1666         if (service->ipconfig == NULL)
1667                 return;
1668
1669         connman_ipconfig_set_method(service->ipconfig,
1670                                         CONNMAN_IPCONFIG_METHOD_DHCP);
1671
1672         __connman_storage_load_service(service);
1673
1674         connman_ipconfig_set_data(service->ipconfig, service);
1675
1676         connman_ipconfig_set_ops(service->ipconfig, &service_ops);
1677         connman_ipconfig_set_ops(service->ipconfig, NULL);
1678 }
1679
1680 /**
1681  * __connman_service_lookup_from_device:
1682  * @device: device structure
1683  *
1684  * Look up a service by device (reference count will not be increased)
1685  */
1686 struct connman_service *__connman_service_lookup_from_device(struct connman_device *device)
1687 {
1688         struct connman_service *service;
1689         const char *ident;
1690         char *name;
1691
1692         ident = __connman_device_get_ident(device);
1693         if (ident == NULL)
1694                 return NULL;
1695
1696         name = g_strdup_printf("%s_%s",
1697                                 __connman_device_get_type(device), ident);
1698         service = __connman_service_lookup(name);
1699         g_free(name);
1700
1701         return service;
1702 }
1703
1704 /**
1705  * __connman_service_create_from_device:
1706  * @device: device structure
1707  *
1708  * Look up service by device and if not found, create one
1709  */
1710 struct connman_service *__connman_service_create_from_device(struct connman_device *device)
1711 {
1712         struct connman_service *service;
1713         const char *ident;
1714         char *name;
1715
1716         ident = __connman_device_get_ident(device);
1717         if (ident == NULL)
1718                 return NULL;
1719
1720         name = g_strdup_printf("%s_%s",
1721                                 __connman_device_get_type(device), ident);
1722         service = __connman_service_get(name);
1723         g_free(name);
1724
1725         if (service == NULL)
1726                 return NULL;
1727
1728         if (service->path != NULL) {
1729                 __connman_profile_changed(TRUE);
1730                 return service;
1731         }
1732
1733         service->type = __connman_device_get_service_type(device);
1734
1735         service->autoconnect = FALSE;
1736
1737         service->device = device;
1738
1739         setup_ipconfig(service, connman_device_get_index(device));
1740
1741         service_register(service);
1742
1743         __connman_profile_changed(TRUE);
1744
1745         if (service->favorite == TRUE)
1746                 __connman_service_auto_connect();
1747
1748         return service;
1749 }
1750
1751 void __connman_service_remove_from_device(struct connman_device *device)
1752 {
1753         struct connman_service *service;
1754         enum connman_service_type type;
1755
1756         service = __connman_service_lookup_from_device(device);
1757         if (service == NULL)
1758                 return;
1759
1760         type = service->type;
1761
1762         __connman_service_put(service);
1763
1764         default_changed();
1765
1766         __connman_notifier_disconnect(type);
1767
1768         __connman_service_auto_connect();
1769 }
1770
1771 /**
1772  * __connman_service_lookup_from_network:
1773  * @network: network structure
1774  *
1775  * Look up a service by network (reference count will not be increased)
1776  */
1777 struct connman_service *__connman_service_lookup_from_network(struct connman_network *network)
1778 {
1779         struct connman_service *service;
1780         const char *ident, *group;
1781         char *name;
1782
1783         ident = __connman_network_get_ident(network);
1784         if (ident == NULL)
1785                 return NULL;
1786
1787         group = connman_network_get_group(network);
1788         if (group == NULL)
1789                 return NULL;
1790
1791         name = g_strdup_printf("%s_%s_%s",
1792                         __connman_network_get_type(network), ident, group);
1793         service = __connman_service_lookup(name);
1794         g_free(name);
1795
1796         return service;
1797 }
1798
1799 unsigned int __connman_service_get_order(struct connman_service *service)
1800 {
1801         GSequenceIter *iter;
1802
1803         if (service == NULL)
1804                 return 0;
1805
1806         if (service->favorite == FALSE) {
1807                 service->order = 0;
1808                 goto done;
1809         }
1810
1811         iter = g_hash_table_lookup(service_hash, service->identifier);
1812         if (iter != NULL) {
1813                 if (g_sequence_iter_get_position(iter) == 0)
1814                         service->order = 1;
1815                 else
1816                         service->order = 0;
1817         }
1818
1819 done:
1820         return service->order;
1821 }
1822
1823 static enum connman_service_type convert_network_type(struct connman_network *network)
1824 {
1825         enum connman_network_type type = connman_network_get_type(network);
1826
1827         switch (type) {
1828         case CONNMAN_NETWORK_TYPE_UNKNOWN:
1829         case CONNMAN_NETWORK_TYPE_VENDOR:
1830                 break;
1831         case CONNMAN_NETWORK_TYPE_WIFI:
1832                 return CONNMAN_SERVICE_TYPE_WIFI;
1833         case CONNMAN_NETWORK_TYPE_WIMAX:
1834                 return CONNMAN_SERVICE_TYPE_WIMAX;
1835         case CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN:
1836         case CONNMAN_NETWORK_TYPE_BLUETOOTH_DUN:
1837                 return CONNMAN_SERVICE_TYPE_BLUETOOTH;
1838         case CONNMAN_NETWORK_TYPE_MBM:
1839         case CONNMAN_NETWORK_TYPE_HSO:
1840                 return CONNMAN_SERVICE_TYPE_CELLULAR;
1841         }
1842
1843         return CONNMAN_SERVICE_TYPE_UNKNOWN;
1844 }
1845
1846 static enum connman_service_mode convert_wifi_mode(const char *mode)
1847 {
1848         if (mode == NULL)
1849                 return CONNMAN_SERVICE_MODE_UNKNOWN;
1850         else if (g_str_equal(mode, "managed") == TRUE)
1851                 return CONNMAN_SERVICE_MODE_MANAGED;
1852         else if (g_str_equal(mode, "adhoc") == TRUE)
1853                 return CONNMAN_SERVICE_MODE_ADHOC;
1854         else
1855                 return CONNMAN_SERVICE_MODE_UNKNOWN;
1856 }
1857
1858 static enum connman_service_mode convert_wifi_security(const char *security)
1859 {
1860         if (security == NULL)
1861                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
1862         else if (g_str_equal(security, "none") == TRUE)
1863                 return CONNMAN_SERVICE_SECURITY_NONE;
1864         else if (g_str_equal(security, "wep") == TRUE)
1865                 return CONNMAN_SERVICE_SECURITY_WEP;
1866         else if (g_str_equal(security, "wpa") == TRUE)
1867                 return CONNMAN_SERVICE_SECURITY_WPA;
1868         else if (g_str_equal(security, "rsn") == TRUE)
1869                 return CONNMAN_SERVICE_SECURITY_RSN;
1870         else
1871                 return CONNMAN_SERVICE_SECURITY_UNKNOWN;
1872 }
1873
1874 static void update_from_network(struct connman_service *service,
1875                                         struct connman_network *network)
1876 {
1877         connman_uint8_t strength = service->strength;
1878         GSequenceIter *iter;
1879         const char *str;
1880
1881         if (service->state == CONNMAN_SERVICE_STATE_READY)
1882                 return;
1883
1884         if (is_connecting(service) == TRUE)
1885                 return;
1886
1887         str = connman_network_get_string(network, "Name");
1888         if (str != NULL) {
1889                 g_free(service->name);
1890                 service->name = g_strdup(str);
1891                 service->hidden = FALSE;
1892         } else {
1893                 g_free(service->name);
1894                 service->name = NULL;
1895                 service->hidden = TRUE;
1896         }
1897
1898         service->strength = connman_network_get_uint8(network, "Strength");
1899
1900         str = connman_network_get_string(network, "WiFi.Mode");
1901         service->mode = convert_wifi_mode(str);
1902
1903         str = connman_network_get_string(network, "WiFi.Security");
1904         service->security = convert_wifi_security(str);
1905
1906         if (service->strength > strength && service->network != NULL) {
1907                 connman_network_unref(service->network);
1908                 service->network = connman_network_ref(network);
1909
1910                 strength_changed(service);
1911         }
1912
1913         if (service->network == NULL)
1914                 service->network = connman_network_ref(network);
1915
1916         iter = g_hash_table_lookup(service_hash, service->identifier);
1917         if (iter != NULL)
1918                 g_sequence_sort_changed(iter, service_compare, NULL);
1919 }
1920
1921 /**
1922  * __connman_service_create_from_network:
1923  * @network: network structure
1924  *
1925  * Look up service by network and if not found, create one
1926  */
1927 struct connman_service *__connman_service_create_from_network(struct connman_network *network)
1928 {
1929         struct connman_service *service;
1930         const char *ident, *group;
1931         char *name;
1932
1933         ident = __connman_network_get_ident(network);
1934         if (ident == NULL)
1935                 return NULL;
1936
1937         group = connman_network_get_group(network);
1938         if (group == NULL)
1939                 return NULL;
1940
1941         name = g_strdup_printf("%s_%s_%s",
1942                         __connman_network_get_type(network), ident, group);
1943         service = __connman_service_get(name);
1944         g_free(name);
1945
1946         if (service == NULL)
1947                 return NULL;
1948
1949         if (__connman_network_get_weakness(network) == TRUE)
1950                 return service;
1951
1952         if (service->path != NULL) {
1953                 update_from_network(service, network);
1954                 __connman_profile_changed(TRUE);
1955                 return service;
1956         }
1957
1958         service->type = convert_network_type(network);
1959
1960         switch (service->type) {
1961         case CONNMAN_SERVICE_TYPE_UNKNOWN:
1962         case CONNMAN_SERVICE_TYPE_ETHERNET:
1963         case CONNMAN_SERVICE_TYPE_WIMAX:
1964         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
1965         case CONNMAN_SERVICE_TYPE_CELLULAR:
1966                 service->autoconnect = FALSE;
1967                 break;
1968         case CONNMAN_SERVICE_TYPE_WIFI:
1969                 service->autoconnect = TRUE;
1970                 break;
1971         }
1972
1973         service->state = CONNMAN_SERVICE_STATE_IDLE;
1974
1975         update_from_network(service, network);
1976
1977         setup_ipconfig(service, connman_network_get_index(network));
1978
1979         service_register(service);
1980
1981         __connman_profile_changed(TRUE);
1982
1983         if (service->favorite == TRUE)
1984                 __connman_service_auto_connect();
1985
1986         return service;
1987 }
1988
1989 void __connman_service_update_from_network(struct connman_network *network)
1990 {
1991         struct connman_service *service;
1992         connman_uint8_t strength;
1993
1994         service = __connman_service_lookup_from_network(network);
1995         if (service == NULL)
1996                 return;
1997
1998         if (service->network == NULL)
1999                 return;
2000
2001         strength = connman_network_get_uint8(service->network, "Strength");
2002         if (strength == service->strength)
2003                 return;
2004
2005         service->strength = strength;
2006
2007         strength_changed(service);
2008 }
2009
2010 void __connman_service_remove_from_network(struct connman_network *network)
2011 {
2012         struct connman_service *service;
2013
2014         service = __connman_service_lookup_from_network(network);
2015         if (service == NULL)
2016                 return;
2017
2018         __connman_service_put(service);
2019 }
2020
2021 static int service_load(struct connman_service *service)
2022 {
2023         const char *ident = service->profile;
2024         GKeyFile *keyfile;
2025         gchar *pathname, *data = NULL;
2026         gsize length;
2027         gchar *str;
2028         unsigned int ssid_len;
2029         int err = 0;
2030
2031         DBG("service %p", service);
2032
2033         if (ident == NULL)
2034                 return -EINVAL;
2035
2036         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
2037         if (pathname == NULL)
2038                 return -ENOMEM;
2039
2040         keyfile = g_key_file_new();
2041
2042         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE) {
2043                 g_free(pathname);
2044                 return -ENOENT;
2045         }
2046
2047         g_free(pathname);
2048
2049         if (g_key_file_load_from_data(keyfile, data, length,
2050                                                         0, NULL) == FALSE) {
2051                 g_free(data);
2052                 return -EILSEQ;
2053         }
2054
2055         g_free(data);
2056
2057         switch (service->type) {
2058         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2059         case CONNMAN_SERVICE_TYPE_ETHERNET:
2060                 break;
2061         case CONNMAN_SERVICE_TYPE_WIFI:
2062                 if (service->name == NULL) {
2063                         gchar *name;
2064
2065                         name = g_key_file_get_string(keyfile,
2066                                         service->identifier, "Name", NULL);
2067                         if (name != NULL) {
2068                                 g_free(service->name);
2069                                 service->name = name;
2070                         }
2071
2072                         if (service->network != NULL)
2073                                 connman_network_set_name(service->network,
2074                                                                         name);
2075                 }
2076
2077                 if (service->network &&
2078                                 connman_network_get_blob(service->network,
2079                                         "WiFi.SSID", &ssid_len) == NULL) {
2080                         gchar *hex_ssid;
2081
2082                         hex_ssid = g_key_file_get_string(keyfile,
2083                                                         service->identifier,
2084                                                                 "SSID", NULL);
2085
2086                         if (hex_ssid != NULL) {
2087                                 gchar *ssid;
2088                                 unsigned int i, j = 0, hex;
2089                                 size_t hex_ssid_len = strlen(hex_ssid);
2090
2091                                 ssid = g_try_malloc0(hex_ssid_len / 2);
2092                                 if (ssid == NULL) {
2093                                         g_free(hex_ssid);
2094                                         err = -ENOMEM;
2095                                         goto done;
2096                                 }
2097
2098                                 for (i = 0; i < hex_ssid_len; i += 2) {
2099                                         sscanf(hex_ssid + i, "%02x", &hex);
2100                                         ssid[j++] = hex;
2101                                 }
2102
2103                                 connman_network_set_blob(service->network,
2104                                         "WiFi.SSID", ssid, hex_ssid_len / 2);
2105                         }
2106
2107                         g_free(hex_ssid);
2108                 }
2109                 /* fall through */
2110
2111         case CONNMAN_SERVICE_TYPE_WIMAX:
2112         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2113         case CONNMAN_SERVICE_TYPE_CELLULAR:
2114                 service->favorite = g_key_file_get_boolean(keyfile,
2115                                 service->identifier, "Favorite", NULL);
2116
2117                 service->autoconnect = g_key_file_get_boolean(keyfile,
2118                                 service->identifier, "AutoConnect", NULL);
2119
2120                 str = g_key_file_get_string(keyfile,
2121                                 service->identifier, "Failure", NULL);
2122                 if (str != NULL) {
2123                         service->state = CONNMAN_SERVICE_STATE_FAILURE;
2124                         service->error = string2error(str);
2125                 }
2126                 break;
2127         }
2128
2129         str = g_key_file_get_string(keyfile,
2130                                 service->identifier, "Modified", NULL);
2131         if (str != NULL) {
2132                 g_time_val_from_iso8601(str, &service->modified);
2133                 g_free(str);
2134         }
2135
2136         str = g_key_file_get_string(keyfile,
2137                                 service->identifier, "Passphrase", NULL);
2138         if (str != NULL) {
2139                 g_free(service->passphrase);
2140                 service->passphrase = str;
2141         }
2142
2143         if (service->ipconfig != NULL)
2144                 __connman_ipconfig_load(service->ipconfig, keyfile,
2145                                         service->identifier, "IPv4.");
2146
2147 done:
2148         g_key_file_free(keyfile);
2149
2150         return err;
2151 }
2152
2153 static int service_save(struct connman_service *service)
2154 {
2155         const char *ident = service->profile;
2156         GKeyFile *keyfile;
2157         gchar *pathname, *data = NULL;
2158         gsize length;
2159         gchar *str;
2160         int err = 0;
2161
2162         DBG("service %p", service);
2163
2164         if (ident == NULL)
2165                 return -EINVAL;
2166
2167         pathname = g_strdup_printf("%s/%s.profile", STORAGEDIR, ident);
2168         if (pathname == NULL)
2169                 return -ENOMEM;
2170
2171         keyfile = g_key_file_new();
2172
2173         if (g_file_get_contents(pathname, &data, &length, NULL) == FALSE)
2174                 goto update;
2175
2176         if (length > 0) {
2177                 if (g_key_file_load_from_data(keyfile, data, length,
2178                                                         0, NULL) == FALSE)
2179                         goto done;
2180         }
2181
2182         g_free(data);
2183
2184 update:
2185         if (service->name != NULL)
2186                 g_key_file_set_string(keyfile, service->identifier,
2187                                                 "Name", service->name);
2188
2189         switch (service->type) {
2190         case CONNMAN_SERVICE_TYPE_UNKNOWN:
2191         case CONNMAN_SERVICE_TYPE_ETHERNET:
2192                 break;
2193         case CONNMAN_SERVICE_TYPE_WIFI:
2194                 if (service->network) {
2195                         const unsigned char *ssid;
2196                         unsigned int ssid_len = 0;
2197
2198                         ssid = connman_network_get_blob(service->network,
2199                                                         "WiFi.SSID", &ssid_len);
2200
2201                         if (ssid != NULL && ssid_len > 0 && ssid[0] != '\0') {
2202                                 char *identifier = service->identifier;
2203                                 GString *str;
2204                                 unsigned int i;
2205
2206                                 str = g_string_sized_new(ssid_len * 2);
2207                                 if (str == NULL) {
2208                                         err = -ENOMEM;
2209                                         goto done;
2210                                 }
2211
2212                                 for (i = 0; i < ssid_len; i++)
2213                                         g_string_append_printf(str,
2214                                                         "%02x", ssid[i]);
2215
2216                                 g_key_file_set_string(keyfile, identifier,
2217                                                         "SSID", str->str);
2218
2219                                 g_string_free(str, TRUE);
2220                         }
2221                 }
2222                 /* fall through */
2223
2224         case CONNMAN_SERVICE_TYPE_WIMAX:
2225         case CONNMAN_SERVICE_TYPE_BLUETOOTH:
2226         case CONNMAN_SERVICE_TYPE_CELLULAR:
2227                 g_key_file_set_boolean(keyfile, service->identifier,
2228                                         "Favorite", service->favorite);
2229
2230                 if (service->favorite == TRUE)
2231                         g_key_file_set_boolean(keyfile, service->identifier,
2232                                         "AutoConnect", service->autoconnect);
2233
2234                 if (service->state == CONNMAN_SERVICE_STATE_FAILURE) {
2235                         const char *failure = error2string(service->error);
2236                         if (failure != NULL)
2237                                 g_key_file_set_string(keyfile,
2238                                                         service->identifier,
2239                                                         "Failure", failure);
2240                 } else {
2241                         g_key_file_remove_key(keyfile, service->identifier,
2242                                                         "Failure", NULL);
2243                 }
2244                 break;
2245         }
2246
2247         str = g_time_val_to_iso8601(&service->modified);
2248         if (str != NULL) {
2249                 g_key_file_set_string(keyfile, service->identifier,
2250                                                         "Modified", str);
2251                 g_free(str);
2252         }
2253
2254         if (service->passphrase != NULL && strlen(service->passphrase) > 0)
2255                 g_key_file_set_string(keyfile, service->identifier,
2256                                         "Passphrase", service->passphrase);
2257         else
2258                 g_key_file_remove_key(keyfile, service->identifier,
2259                                                         "Passphrase", NULL);
2260
2261         if (service->ipconfig != NULL)
2262                 __connman_ipconfig_save(service->ipconfig, keyfile,
2263                                         service->identifier, "IPv4.");
2264
2265         data = g_key_file_to_data(keyfile, &length, NULL);
2266
2267         if (g_file_set_contents(pathname, data, length, NULL) == FALSE)
2268                 connman_error("Failed to store service information");
2269
2270 done:
2271         g_free(data);
2272
2273         g_key_file_free(keyfile);
2274
2275         g_free(pathname);
2276
2277         return err;
2278 }
2279
2280 static struct connman_storage service_storage = {
2281         .name           = "service",
2282         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
2283         .service_load   = service_load,
2284         .service_save   = service_save,
2285 };
2286
2287 int __connman_service_init(void)
2288 {
2289         DBG("");
2290
2291         connection = connman_dbus_get_connection();
2292
2293         if (connman_storage_register(&service_storage) < 0)
2294                 connman_error("Failed to register service storage");
2295
2296         service_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
2297                                                                 NULL, NULL);
2298
2299         service_list = g_sequence_new(service_free);
2300
2301         return 0;
2302 }
2303
2304 void __connman_service_cleanup(void)
2305 {
2306         DBG("");
2307
2308         g_sequence_free(service_list);
2309         service_list = NULL;
2310
2311         g_hash_table_destroy(service_hash);
2312         service_hash = NULL;
2313
2314         connman_storage_unregister(&service_storage);
2315
2316         dbus_connection_unref(connection);
2317 }