Enforce current offline mode for new devices
[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_device_set_offlinemode(offlinemode);
295         } else if (g_str_equal(name, "ActiveProfile") == TRUE) {
296                 const char *str;
297
298                 dbus_message_iter_get_basic(&value, &str);
299
300                 return __connman_error_not_supported(msg);
301         } else
302                 return __connman_error_invalid_property(msg);
303
304         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
305 }
306
307 static DBusMessage *get_state(DBusConnection *conn,
308                                         DBusMessage *msg, void *data)
309 {
310         const char *str;
311
312         DBG("conn %p", conn);
313
314         if (__connman_security_check_privilege(msg,
315                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
316                 return __connman_error_permission_denied(msg);
317
318         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
319                 str = "online";
320         else
321                 str = "offline";
322
323         return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &str,
324                                                 DBUS_TYPE_INVALID);
325 }
326
327 static DBusMessage *add_profile(DBusConnection *conn,
328                                         DBusMessage *msg, void *data)
329 {
330         const char *name;
331
332         DBG("conn %p", conn);
333
334         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
335                                                         DBUS_TYPE_INVALID);
336
337         return __connman_error_not_supported(msg);
338 }
339
340 static DBusMessage *remove_profile(DBusConnection *conn,
341                                         DBusMessage *msg, void *data)
342 {
343         const char *path;
344
345         DBG("conn %p", conn);
346
347         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
348                                                         DBUS_TYPE_INVALID);
349
350         return __connman_error_not_supported(msg);
351 }
352
353 static DBusMessage *request_scan(DBusConnection *conn,
354                                         DBusMessage *msg, void *data)
355 {
356         enum connman_device_type type;
357         const char *str;
358         int err;
359
360         DBG("conn %p", conn);
361
362         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
363                                                         DBUS_TYPE_INVALID);
364
365         if (g_strcmp0(str, "") == 0)
366                 type = CONNMAN_DEVICE_TYPE_UNKNOWN;
367         else if (g_strcmp0(str, "wifi") == 0)
368                 type = CONNMAN_DEVICE_TYPE_WIFI;
369         else if (g_strcmp0(str, "wimax") == 0)
370                 type = CONNMAN_DEVICE_TYPE_WIMAX;
371         else
372                 return __connman_error_invalid_arguments(msg);
373
374         err = __connman_element_request_scan(type);
375         if (err < 0) {
376                 if (err == -EINPROGRESS) {
377                         connman_error("Invalid return code from scan");
378                         err = -EINVAL;
379                 }
380
381                 return __connman_error_failed(msg, -err);
382         }
383
384         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
385 }
386
387 static DBusMessage *enable_technology(DBusConnection *conn,
388                                         DBusMessage *msg, void *data)
389 {
390         enum connman_device_type type;
391         const char *str;
392         int err;
393
394         DBG("conn %p", conn);
395
396         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
397                                                         DBUS_TYPE_INVALID);
398
399         if (g_strcmp0(str, "ethernet") == 0)
400                 type = CONNMAN_DEVICE_TYPE_ETHERNET;
401         else if (g_strcmp0(str, "wifi") == 0)
402                 type = CONNMAN_DEVICE_TYPE_WIFI;
403         else if (g_strcmp0(str, "wimax") == 0)
404                 type = CONNMAN_DEVICE_TYPE_WIMAX;
405         else if (g_strcmp0(str, "bluetooth") == 0)
406                 type = CONNMAN_DEVICE_TYPE_BLUETOOTH;
407         else if (g_strcmp0(str, "gps") == 0)
408                 type = CONNMAN_DEVICE_TYPE_GPS;
409         else
410                 return __connman_error_invalid_arguments(msg);
411
412         err = __connman_element_enable_technology(type);
413         if (err < 0) {
414                 if (err == -EINPROGRESS) {
415                         connman_error("Invalid return code from enable");
416                         err = -EINVAL;
417                 }
418
419                 return __connman_error_failed(msg, -err);
420         }
421
422         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
423 }
424
425 static DBusMessage *disable_technology(DBusConnection *conn,
426                                         DBusMessage *msg, void *data)
427 {
428         enum connman_device_type type;
429         const char *str;
430         int err;
431
432         DBG("conn %p", conn);
433
434         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
435                                                         DBUS_TYPE_INVALID);
436
437         if (g_strcmp0(str, "ethernet") == 0)
438                 type = CONNMAN_DEVICE_TYPE_ETHERNET;
439         else if (g_strcmp0(str, "wifi") == 0)
440                 type = CONNMAN_DEVICE_TYPE_WIFI;
441         else if (g_strcmp0(str, "wimax") == 0)
442                 type = CONNMAN_DEVICE_TYPE_WIMAX;
443         else if (g_strcmp0(str, "bluetooth") == 0)
444                 type = CONNMAN_DEVICE_TYPE_BLUETOOTH;
445         else if (g_strcmp0(str, "gps") == 0)
446                 type = CONNMAN_DEVICE_TYPE_GPS;
447         else
448                 return __connman_error_invalid_arguments(msg);
449
450         err = __connman_element_disable_technology(type);
451         if (err < 0) {
452                 if (err == -EINPROGRESS) {
453                         connman_error("Invalid return code from disable");
454                         err = -EINVAL;
455                 }
456
457                 return __connman_error_failed(msg, -err);
458         }
459
460         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
461 }
462
463 static DBusMessage *connect_service(DBusConnection *conn,
464                                         DBusMessage *msg, void *data)
465 {
466         int err;
467
468         DBG("conn %p", conn);
469
470         if (__connman_security_check_privilege(msg,
471                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
472                 return __connman_error_permission_denied(msg);
473
474         err = __connman_service_create_and_connect(msg);
475         if (err < 0) {
476                 if (err == -EINPROGRESS) {
477                         connman_error("Invalid return code from connect");
478                         err = -EINVAL;
479                 }
480
481                 return __connman_error_failed(msg, -err);
482         }
483
484         return NULL;
485 }
486
487 static DBusMessage *register_agent(DBusConnection *conn,
488                                         DBusMessage *msg, void *data)
489 {
490         DBusMessage *reply;
491         const char *sender, *path;
492
493         DBG("conn %p", conn);
494
495         sender = dbus_message_get_sender(msg);
496
497         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
498                                                         DBUS_TYPE_INVALID);
499
500         reply = dbus_message_new_method_return(msg);
501         if (reply == NULL)
502                 return NULL;
503
504         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
505
506         __connman_agent_register(sender, path);
507
508         return reply;
509 }
510
511 static DBusMessage *unregister_agent(DBusConnection *conn,
512                                         DBusMessage *msg, void *data)
513 {
514         DBusMessage *reply;
515         const char *sender, *path;
516
517         DBG("conn %p", conn);
518
519         sender = dbus_message_get_sender(msg);
520
521         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
522                                                         DBUS_TYPE_INVALID);
523
524         reply = dbus_message_new_method_return(msg);
525         if (reply == NULL)
526                 return NULL;
527
528         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
529
530         __connman_agent_unregister(sender, path);
531
532         return reply;
533 }
534
535 static GDBusMethodTable manager_methods[] = {
536         { "GetProperties",     "",      "a{sv}", get_properties     },
537         { "SetProperty",       "sv",    "",      set_property       },
538         { "GetState",          "",      "s",     get_state          },
539         { "AddProfile",        "s",     "o",     add_profile        },
540         { "RemoveProfile",     "o",     "",      remove_profile     },
541         { "RequestScan",       "s",     "",      request_scan       },
542         { "EnableTechnology",  "s",     "",      enable_technology  },
543         { "DisableTechnology", "s",     "",      disable_technology },
544         { "ConnectService",    "a{sv}", "o",     connect_service,
545                                                 G_DBUS_METHOD_FLAG_ASYNC },
546         { "RegisterAgent",     "o",     "",      register_agent     },
547         { "UnregisterAgent",   "o",     "",      unregister_agent   },
548         { },
549 };
550
551 static GDBusSignalTable manager_signals[] = {
552         { "PropertyChanged", "sv" },
553         { "StateChanged",    "s"  },
554         { },
555 };
556
557 static DBusMessage *nm_sleep(DBusConnection *conn,
558                                         DBusMessage *msg, void *data)
559 {
560         DBusMessage *reply;
561
562         DBG("conn %p", conn);
563
564         reply = dbus_message_new_method_return(msg);
565         if (reply == NULL)
566                 return NULL;
567
568         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
569
570         return reply;
571 }
572
573 static DBusMessage *nm_wake(DBusConnection *conn,
574                                         DBusMessage *msg, void *data)
575 {
576         DBusMessage *reply;
577
578         DBG("conn %p", conn);
579
580         reply = dbus_message_new_method_return(msg);
581         if (reply == NULL)
582                 return NULL;
583
584         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
585
586         return reply;
587 }
588
589 enum {
590         NM_STATE_UNKNOWN = 0,
591         NM_STATE_ASLEEP,
592         NM_STATE_CONNECTING,
593         NM_STATE_CONNECTED,
594         NM_STATE_DISCONNECTED
595 };
596
597 static DBusMessage *nm_state(DBusConnection *conn,
598                                         DBusMessage *msg, void *data)
599 {
600         DBusMessage *reply;
601         dbus_uint32_t state;
602
603         DBG("conn %p", conn);
604
605         reply = dbus_message_new_method_return(msg);
606         if (reply == NULL)
607                 return NULL;
608
609         state = NM_STATE_DISCONNECTED;
610
611         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
612                                                         DBUS_TYPE_INVALID);
613
614         return reply;
615 }
616
617 static GDBusMethodTable nm_methods[] = {
618         { "sleep", "",  "",   nm_sleep        },
619         { "wake",  "",  "",   nm_wake         },
620         { "state", "",  "u",  nm_state        },
621         { },
622 };
623
624 static DBusConnection *connection = NULL;
625 static gboolean nm_compat = FALSE;
626
627 int __connman_manager_init(DBusConnection *conn, gboolean compat)
628 {
629         DBG("conn %p", conn);
630
631         connection = dbus_connection_ref(conn);
632         if (connection == NULL)
633                 return -1;
634
635         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
636                                         CONNMAN_MANAGER_INTERFACE,
637                                         manager_methods,
638                                         manager_signals, NULL, NULL, NULL);
639
640         if (compat == TRUE) {
641                 g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
642                                         nm_methods, NULL, NULL, NULL, NULL);
643
644                 nm_compat = TRUE;
645         }
646
647         return 0;
648 }
649
650 void __connman_manager_cleanup(void)
651 {
652         DBG("conn %p", connection);
653
654         if (nm_compat == TRUE) {
655                 g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
656         }
657
658         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
659                                                 CONNMAN_MANAGER_INTERFACE);
660
661         dbus_connection_unref(connection);
662 }