Add support for blocking enable and disable technology changes
[platform/upstream/connman.git] / src / manager.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <gdbus.h>
27
28 #include "connman.h"
29
30 static connman_bool_t global_offlinemode = FALSE;
31
32 connman_bool_t __connman_manager_get_offlinemode(void)
33 {
34         return global_offlinemode;
35 }
36
37 static void append_profiles(DBusMessageIter *dict)
38 {
39         DBusMessageIter entry, value, iter;
40         const char *key = "Profiles";
41
42         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
43                                                                 NULL, &entry);
44
45         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
46
47         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
48                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
49                                                                 &value);
50
51         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
52                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
53         __connman_profile_list(&iter);
54         dbus_message_iter_close_container(&value, &iter);
55
56         dbus_message_iter_close_container(&entry, &value);
57
58         dbus_message_iter_close_container(dict, &entry);
59 }
60
61 static void append_services(DBusMessageIter *dict)
62 {
63         DBusMessageIter entry, value, iter;
64         const char *key = "Services";
65
66         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
67                                                                 NULL, &entry);
68
69         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
70
71         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
72                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
73                                                                 &value);
74
75         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
76                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
77         __connman_service_list(&iter);
78         dbus_message_iter_close_container(&value, &iter);
79
80         dbus_message_iter_close_container(&entry, &value);
81
82         dbus_message_iter_close_container(dict, &entry);
83 }
84
85 static void append_devices(DBusMessageIter *dict)
86 {
87         DBusMessageIter entry, value, iter;
88         const char *key = "Devices";
89
90         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
91                                                                 NULL, &entry);
92
93         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
94
95         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
96                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
97                                                                 &value);
98
99         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
100                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
101         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
102         dbus_message_iter_close_container(&value, &iter);
103
104         dbus_message_iter_close_container(&entry, &value);
105
106         dbus_message_iter_close_container(dict, &entry);
107 }
108
109 static void append_connections(DBusMessageIter *dict)
110 {
111         DBusMessageIter entry, value, iter;
112         const char *key = "Connections";
113
114         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
115                                                                 NULL, &entry);
116
117         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
118
119         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
120                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
121                                                                 &value);
122
123         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
124                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
125         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
126         dbus_message_iter_close_container(&value, &iter);
127
128         dbus_message_iter_close_container(&entry, &value);
129
130         dbus_message_iter_close_container(dict, &entry);
131 }
132
133 static void append_available_technologies(DBusMessageIter *dict)
134 {
135         DBusMessageIter entry, value, iter;
136         const char *key = "AvailableTechnologies";
137
138         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
139                                                                 NULL, &entry);
140
141         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
142
143         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
144                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
145                                                                 &value);
146
147         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
148                                         DBUS_TYPE_STRING_AS_STRING, &iter);
149         __connman_notifier_list_registered(&iter);
150         dbus_message_iter_close_container(&value, &iter);
151
152         dbus_message_iter_close_container(&entry, &value);
153
154         dbus_message_iter_close_container(dict, &entry);
155 }
156
157 static void append_enabled_technologies(DBusMessageIter *dict)
158 {
159         DBusMessageIter entry, value, iter;
160         const char *key = "EnabledTechnologies";
161
162         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
163                                                                 NULL, &entry);
164
165         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
166
167         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
168                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
169                                                                 &value);
170
171         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
172                                         DBUS_TYPE_STRING_AS_STRING, &iter);
173         __connman_notifier_list_enabled(&iter);
174         dbus_message_iter_close_container(&value, &iter);
175
176         dbus_message_iter_close_container(&entry, &value);
177
178         dbus_message_iter_close_container(dict, &entry);
179 }
180
181 static void append_connected_technologies(DBusMessageIter *dict)
182 {
183         DBusMessageIter entry, value, iter;
184         const char *key = "ConnectedTechnologies";
185
186         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
187                                                                 NULL, &entry);
188
189         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
190
191         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
192                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
193                                                                 &value);
194
195         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
196                                         DBUS_TYPE_STRING_AS_STRING, &iter);
197         __connman_notifier_list_connected(&iter);
198         dbus_message_iter_close_container(&value, &iter);
199
200         dbus_message_iter_close_container(&entry, &value);
201
202         dbus_message_iter_close_container(dict, &entry);
203 }
204
205 static DBusMessage *get_properties(DBusConnection *conn,
206                                         DBusMessage *msg, void *data)
207 {
208         DBusMessage *reply;
209         DBusMessageIter array, dict;
210         const char *str;
211
212         DBG("conn %p", conn);
213
214         if (__connman_security_check_privilege(msg,
215                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
216                 return __connman_error_permission_denied(msg);
217
218         reply = dbus_message_new_method_return(msg);
219         if (reply == NULL)
220                 return NULL;
221
222         dbus_message_iter_init_append(reply, &array);
223
224         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
225                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
226                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
227                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
228
229         str = __connman_profile_active_path();
230         if (str != NULL)
231                 connman_dbus_dict_append_variant(&dict, "ActiveProfile",
232                                                 DBUS_TYPE_OBJECT_PATH, &str);
233
234         append_profiles(&dict);
235         append_services(&dict);
236
237         append_devices(&dict);
238         append_connections(&dict);
239
240         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
241                 str = "online";
242         else
243                 str = "offline";
244
245         connman_dbus_dict_append_variant(&dict, "State",
246                                                 DBUS_TYPE_STRING, &str);
247
248         connman_dbus_dict_append_variant(&dict, "OfflineMode",
249                                 DBUS_TYPE_BOOLEAN, &global_offlinemode);
250
251         append_available_technologies(&dict);
252         append_enabled_technologies(&dict);
253         append_connected_technologies(&dict);
254
255         str = __connman_service_default();
256         if (str != NULL)
257                 connman_dbus_dict_append_variant(&dict, "DefaultTechnology",
258                                                 DBUS_TYPE_STRING, &str);
259
260         dbus_message_iter_close_container(&array, &dict);
261
262         return reply;
263 }
264
265 static DBusMessage *set_property(DBusConnection *conn,
266                                         DBusMessage *msg, void *data)
267 {
268         DBusMessageIter iter, value;
269         const char *name;
270
271         DBG("conn %p", conn);
272
273         if (dbus_message_iter_init(msg, &iter) == FALSE)
274                 return __connman_error_invalid_arguments(msg);
275
276         dbus_message_iter_get_basic(&iter, &name);
277         dbus_message_iter_next(&iter);
278         dbus_message_iter_recurse(&iter, &value);
279
280         if (__connman_security_check_privilege(msg,
281                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
282                 return __connman_error_permission_denied(msg);
283
284         if (g_str_equal(name, "OfflineMode") == TRUE) {
285                 connman_bool_t offlinemode;
286
287                 dbus_message_iter_get_basic(&value, &offlinemode);
288
289                 if (global_offlinemode == offlinemode)
290                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
291
292                 global_offlinemode = offlinemode;
293
294                 __connman_storage_save_global();
295
296                 __connman_device_set_offlinemode(offlinemode);
297         } else if (g_str_equal(name, "ActiveProfile") == TRUE) {
298                 const char *str;
299
300                 dbus_message_iter_get_basic(&value, &str);
301
302                 return __connman_error_not_supported(msg);
303         } else
304                 return __connman_error_invalid_property(msg);
305
306         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
307 }
308
309 static DBusMessage *get_state(DBusConnection *conn,
310                                         DBusMessage *msg, void *data)
311 {
312         const char *str;
313
314         DBG("conn %p", conn);
315
316         if (__connman_security_check_privilege(msg,
317                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
318                 return __connman_error_permission_denied(msg);
319
320         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
321                 str = "online";
322         else
323                 str = "offline";
324
325         return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &str,
326                                                 DBUS_TYPE_INVALID);
327 }
328
329 static DBusMessage *add_profile(DBusConnection *conn,
330                                         DBusMessage *msg, void *data)
331 {
332         const char *name;
333
334         DBG("conn %p", conn);
335
336         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
337                                                         DBUS_TYPE_INVALID);
338
339         return __connman_error_not_supported(msg);
340 }
341
342 static DBusMessage *remove_profile(DBusConnection *conn,
343                                         DBusMessage *msg, void *data)
344 {
345         const char *path;
346
347         DBG("conn %p", conn);
348
349         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
350                                                         DBUS_TYPE_INVALID);
351
352         return __connman_error_not_supported(msg);
353 }
354
355 static DBusMessage *request_scan(DBusConnection *conn,
356                                         DBusMessage *msg, void *data)
357 {
358         enum connman_service_type type;
359         const char *str;
360         int err;
361
362         DBG("conn %p", conn);
363
364         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
365                                                         DBUS_TYPE_INVALID);
366
367         if (g_strcmp0(str, "") == 0)
368                 type = CONNMAN_SERVICE_TYPE_UNKNOWN;
369         else if (g_strcmp0(str, "wifi") == 0)
370                 type = CONNMAN_SERVICE_TYPE_WIFI;
371         else if (g_strcmp0(str, "wimax") == 0)
372                 type = CONNMAN_SERVICE_TYPE_WIMAX;
373         else
374                 return __connman_error_invalid_arguments(msg);
375
376         err = __connman_element_request_scan(type);
377         if (err < 0) {
378                 if (err == -EINPROGRESS) {
379                         connman_error("Invalid return code from scan");
380                         err = -EINVAL;
381                 }
382
383                 return __connman_error_failed(msg, -err);
384         }
385
386         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
387 }
388
389 static DBusConnection *connection = NULL;
390
391 static enum connman_service_type technology_type;
392 static connman_bool_t technology_enabled;
393 static DBusMessage *technology_pending = NULL;
394
395 static void technology_reply(int error)
396 {
397         if (technology_reply != NULL) {
398                 if (error > 0) {
399                         DBusMessage *reply;
400
401                         reply = __connman_error_failed(technology_pending,
402                                                                 error);
403                         if (reply != NULL)
404                                 g_dbus_send_message(connection, reply);
405                 } else
406                         g_dbus_send_reply(connection, technology_pending,
407                                                         DBUS_TYPE_INVALID);
408
409                 dbus_message_unref(technology_pending);
410                 technology_pending = NULL;
411         }
412
413         technology_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
414 }
415
416 static void technology_notify(enum connman_service_type type,
417                                                 connman_bool_t enabled)
418 {
419         DBG("type %d enabled %d", type, enabled);
420
421         if (type == technology_type && enabled == technology_enabled)
422                 technology_reply(0);
423 }
424
425 static struct connman_notifier technology_notifier = {
426         .name           = "manager",
427         .priority       = CONNMAN_NOTIFIER_PRIORITY_HIGH,
428         .service_enabled= technology_notify,
429 };
430
431 static DBusMessage *enable_technology(DBusConnection *conn,
432                                         DBusMessage *msg, void *data)
433 {
434         enum connman_service_type type;
435         const char *str;
436         int err;
437
438         DBG("conn %p", conn);
439
440         if (technology_pending != NULL)
441                 return __connman_error_in_progress(msg);
442
443         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
444                                                         DBUS_TYPE_INVALID);
445
446         if (g_strcmp0(str, "ethernet") == 0)
447                 type = CONNMAN_SERVICE_TYPE_ETHERNET;
448         else if (g_strcmp0(str, "wifi") == 0)
449                 type = CONNMAN_SERVICE_TYPE_WIFI;
450         else if (g_strcmp0(str, "wimax") == 0)
451                 type = CONNMAN_SERVICE_TYPE_WIMAX;
452         else if (g_strcmp0(str, "bluetooth") == 0)
453                 type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
454         else if (g_strcmp0(str, "cellular") == 0)
455                 type = CONNMAN_SERVICE_TYPE_CELLULAR;
456         else
457                 return __connman_error_invalid_arguments(msg);
458
459         if (__connman_notifier_is_enabled(type) == TRUE)
460                 return __connman_error_already_enabled(msg);
461
462         technology_type = type;
463         technology_enabled = TRUE;
464         technology_pending = dbus_message_ref(msg);
465
466         err = __connman_element_enable_technology(type);
467         if (err < 0 && err != -EINPROGRESS)
468                 technology_reply(-err);
469
470         return NULL;
471 }
472
473 static DBusMessage *disable_technology(DBusConnection *conn,
474                                         DBusMessage *msg, void *data)
475 {
476         enum connman_service_type type;
477         const char *str;
478         int err;
479
480         DBG("conn %p", conn);
481
482         if (technology_pending != NULL)
483                 return __connman_error_in_progress(msg);
484
485         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
486                                                         DBUS_TYPE_INVALID);
487
488         if (g_strcmp0(str, "ethernet") == 0)
489                 type = CONNMAN_SERVICE_TYPE_ETHERNET;
490         else if (g_strcmp0(str, "wifi") == 0)
491                 type = CONNMAN_SERVICE_TYPE_WIFI;
492         else if (g_strcmp0(str, "wimax") == 0)
493                 type = CONNMAN_SERVICE_TYPE_WIMAX;
494         else if (g_strcmp0(str, "bluetooth") == 0)
495                 type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
496         else if (g_strcmp0(str, "cellular") == 0)
497                 type = CONNMAN_SERVICE_TYPE_CELLULAR;
498         else
499                 return __connman_error_invalid_arguments(msg);
500
501         if (__connman_notifier_is_enabled(type) == FALSE)
502                 return __connman_error_already_disabled(msg);
503
504         technology_type = type;
505         technology_enabled = FALSE;
506         technology_pending = dbus_message_ref(msg);
507
508         err = __connman_element_disable_technology(type);
509         if (err < 0 && err != -EINPROGRESS)
510                 technology_reply(-err);
511
512         return NULL;
513 }
514
515 static DBusMessage *connect_service(DBusConnection *conn,
516                                         DBusMessage *msg, void *data)
517 {
518         int err;
519
520         DBG("conn %p", conn);
521
522         if (__connman_security_check_privilege(msg,
523                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
524                 return __connman_error_permission_denied(msg);
525
526         err = __connman_service_create_and_connect(msg);
527         if (err < 0) {
528                 if (err == -EINPROGRESS) {
529                         connman_error("Invalid return code from connect");
530                         err = -EINVAL;
531                 }
532
533                 return __connman_error_failed(msg, -err);
534         }
535
536         return NULL;
537 }
538
539 static DBusMessage *register_agent(DBusConnection *conn,
540                                         DBusMessage *msg, void *data)
541 {
542         DBusMessage *reply;
543         const char *sender, *path;
544
545         DBG("conn %p", conn);
546
547         sender = dbus_message_get_sender(msg);
548
549         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
550                                                         DBUS_TYPE_INVALID);
551
552         reply = dbus_message_new_method_return(msg);
553         if (reply == NULL)
554                 return NULL;
555
556         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
557
558         __connman_agent_register(sender, path);
559
560         return reply;
561 }
562
563 static DBusMessage *unregister_agent(DBusConnection *conn,
564                                         DBusMessage *msg, void *data)
565 {
566         DBusMessage *reply;
567         const char *sender, *path;
568
569         DBG("conn %p", conn);
570
571         sender = dbus_message_get_sender(msg);
572
573         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
574                                                         DBUS_TYPE_INVALID);
575
576         reply = dbus_message_new_method_return(msg);
577         if (reply == NULL)
578                 return NULL;
579
580         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
581
582         __connman_agent_unregister(sender, path);
583
584         return reply;
585 }
586
587 static GDBusMethodTable manager_methods[] = {
588         { "GetProperties",     "",      "a{sv}", get_properties     },
589         { "SetProperty",       "sv",    "",      set_property       },
590         { "GetState",          "",      "s",     get_state          },
591         { "AddProfile",        "s",     "o",     add_profile        },
592         { "RemoveProfile",     "o",     "",      remove_profile     },
593         { "RequestScan",       "s",     "",      request_scan       },
594         { "EnableTechnology",  "s",     "",      enable_technology,
595                                                 G_DBUS_METHOD_FLAG_ASYNC },
596         { "DisableTechnology", "s",     "",      disable_technology,
597                                                 G_DBUS_METHOD_FLAG_ASYNC },
598         { "ConnectService",    "a{sv}", "o",     connect_service,
599                                                 G_DBUS_METHOD_FLAG_ASYNC },
600         { "RegisterAgent",     "o",     "",      register_agent     },
601         { "UnregisterAgent",   "o",     "",      unregister_agent   },
602         { },
603 };
604
605 static GDBusSignalTable manager_signals[] = {
606         { "PropertyChanged", "sv" },
607         { "StateChanged",    "s"  },
608         { },
609 };
610
611 static DBusMessage *nm_sleep(DBusConnection *conn,
612                                         DBusMessage *msg, void *data)
613 {
614         DBusMessage *reply;
615
616         DBG("conn %p", conn);
617
618         reply = dbus_message_new_method_return(msg);
619         if (reply == NULL)
620                 return NULL;
621
622         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
623
624         return reply;
625 }
626
627 static DBusMessage *nm_wake(DBusConnection *conn,
628                                         DBusMessage *msg, void *data)
629 {
630         DBusMessage *reply;
631
632         DBG("conn %p", conn);
633
634         reply = dbus_message_new_method_return(msg);
635         if (reply == NULL)
636                 return NULL;
637
638         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
639
640         return reply;
641 }
642
643 enum {
644         NM_STATE_UNKNOWN = 0,
645         NM_STATE_ASLEEP,
646         NM_STATE_CONNECTING,
647         NM_STATE_CONNECTED,
648         NM_STATE_DISCONNECTED
649 };
650
651 static DBusMessage *nm_state(DBusConnection *conn,
652                                         DBusMessage *msg, void *data)
653 {
654         DBusMessage *reply;
655         dbus_uint32_t state;
656
657         DBG("conn %p", conn);
658
659         reply = dbus_message_new_method_return(msg);
660         if (reply == NULL)
661                 return NULL;
662
663         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
664                 state = NM_STATE_CONNECTED;
665         else
666                 state = NM_STATE_DISCONNECTED;
667
668         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
669                                                         DBUS_TYPE_INVALID);
670
671         return reply;
672 }
673
674 static GDBusMethodTable nm_methods[] = {
675         { "sleep", "",  "",   nm_sleep        },
676         { "wake",  "",  "",   nm_wake         },
677         { "state", "",  "u",  nm_state        },
678         { },
679 };
680
681 static int manager_load(void)
682 {
683         GKeyFile *keyfile;
684         GError *error = NULL;
685         connman_bool_t offlinemode;
686
687         DBG("");
688
689         keyfile = __connman_storage_open();
690         if (keyfile == NULL)
691                 return -EIO;
692
693         offlinemode = g_key_file_get_boolean(keyfile, "global",
694                                                 "OfflineMode", &error);
695         if (error == NULL) {
696                 global_offlinemode = offlinemode;
697
698                 __connman_device_set_offlinemode(offlinemode);
699         }
700         g_clear_error(&error);
701
702         __connman_storage_close(keyfile, FALSE);
703
704         return 0;
705 }
706
707 static int manager_save(void)
708 {
709         GKeyFile *keyfile;
710
711         DBG("");
712
713         keyfile = __connman_storage_open();
714         if (keyfile == NULL)
715                 return -EIO;
716
717         g_key_file_set_boolean(keyfile, "global",
718                                         "OfflineMode", global_offlinemode);
719
720         __connman_storage_close(keyfile, TRUE);
721
722         return 0;
723 }
724
725 static struct connman_storage manager_storage = {
726         .name           = "manager",
727         .priority       = CONNMAN_STORAGE_PRIORITY_LOW,
728         .global_load    = manager_load,
729         .global_save    = manager_save,
730 };
731
732 static gboolean nm_compat = FALSE;
733
734 int __connman_manager_init(DBusConnection *conn, gboolean compat)
735 {
736         DBG("conn %p", conn);
737
738         connection = dbus_connection_ref(conn);
739         if (connection == NULL)
740                 return -1;
741
742         if (connman_storage_register(&manager_storage) < 0)
743                 connman_error("Failed to register manager storage");
744
745         if (connman_notifier_register(&technology_notifier) < 0)
746                 connman_error("Failed to register technology notifier");
747
748         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
749                                         CONNMAN_MANAGER_INTERFACE,
750                                         manager_methods,
751                                         manager_signals, NULL, NULL, NULL);
752
753         if (compat == TRUE) {
754                 g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
755                                         nm_methods, NULL, NULL, NULL, NULL);
756
757                 nm_compat = TRUE;
758         }
759
760         return 0;
761 }
762
763 void __connman_manager_cleanup(void)
764 {
765         DBG("conn %p", connection);
766
767         connman_notifier_unregister(&technology_notifier);
768
769         connman_storage_unregister(&manager_storage);
770
771         if (nm_compat == TRUE) {
772                 g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
773         }
774
775         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
776                                                 CONNMAN_MANAGER_INTERFACE);
777
778         dbus_connection_unref(connection);
779 }