Fix typo with exported device list
[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 DBusMessage *get_properties(DBusConnection *conn,
31                                         DBusMessage *msg, void *data)
32 {
33         DBusMessage *reply;
34         DBusMessageIter array, dict;
35         connman_bool_t offlinemode;
36         const char *str;
37
38         DBG("conn %p", conn);
39
40         if (__connman_security_check_privilege(msg,
41                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
42                 return __connman_error_permission_denied(msg);
43
44         reply = dbus_message_new_method_return(msg);
45         if (reply == NULL)
46                 return NULL;
47
48         dbus_message_iter_init_append(reply, &array);
49
50         connman_dbus_dict_open(&array, &dict);
51
52         str = __connman_profile_active_path();
53         if (str != NULL)
54                 connman_dbus_dict_append_variant(&dict, "ActiveProfile",
55                                                 DBUS_TYPE_OBJECT_PATH, &str);
56
57         connman_dbus_dict_append_variable_array(&dict, "Profiles",
58                         DBUS_TYPE_OBJECT_PATH, __connman_profile_list);
59         connman_dbus_dict_append_variable_array(&dict, "Services",
60                         DBUS_TYPE_OBJECT_PATH, __connman_service_list);
61         connman_dbus_dict_append_variable_array(&dict, "Providers",
62                         DBUS_TYPE_OBJECT_PATH, __connman_provider_list);
63
64         connman_dbus_dict_append_variable_array(&dict, "Devices",
65                         DBUS_TYPE_OBJECT_PATH, __connman_device_list);
66
67         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
68                 str = "online";
69         else
70                 str = "offline";
71
72         connman_dbus_dict_append_variant(&dict, "State",
73                                                 DBUS_TYPE_STRING, &str);
74
75         offlinemode = __connman_profile_get_offlinemode();
76         connman_dbus_dict_append_variant(&dict, "OfflineMode",
77                                         DBUS_TYPE_BOOLEAN, &offlinemode);
78
79         connman_dbus_dict_append_variable_array(&dict, "AvailableTechnologies",
80                         DBUS_TYPE_STRING, __connman_notifier_list_registered);
81         connman_dbus_dict_append_variable_array(&dict, "EnabledTechnologies",
82                         DBUS_TYPE_STRING, __connman_notifier_list_enabled);
83         connman_dbus_dict_append_variable_array(&dict, "ConnectedTechnologies",
84                         DBUS_TYPE_STRING, __connman_notifier_list_connected);
85
86         str = __connman_service_default();
87         if (str != NULL)
88                 connman_dbus_dict_append_variant(&dict, "DefaultTechnology",
89                                                 DBUS_TYPE_STRING, &str);
90
91         connman_dbus_dict_append_variable_array(&dict, "AvailableDebugs",
92                         DBUS_TYPE_STRING, __connman_debug_list_available);
93         connman_dbus_dict_append_variable_array(&dict, "EnabledDebugs",
94                         DBUS_TYPE_STRING, __connman_debug_list_enabled);
95
96         connman_dbus_dict_close(&array, &dict);
97
98         return reply;
99 }
100
101 static DBusMessage *set_property(DBusConnection *conn,
102                                         DBusMessage *msg, void *data)
103 {
104         DBusMessageIter iter, value;
105         const char *name;
106         int type;
107
108         DBG("conn %p", conn);
109
110         if (dbus_message_iter_init(msg, &iter) == FALSE)
111                 return __connman_error_invalid_arguments(msg);
112
113         dbus_message_iter_get_basic(&iter, &name);
114         dbus_message_iter_next(&iter);
115         dbus_message_iter_recurse(&iter, &value);
116
117         if (__connman_security_check_privilege(msg,
118                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
119                 return __connman_error_permission_denied(msg);
120
121         type = dbus_message_iter_get_arg_type(&value);
122
123         if (g_str_equal(name, "OfflineMode") == TRUE) {
124                 connman_bool_t offlinemode;
125
126                 if (type != DBUS_TYPE_BOOLEAN)
127                         return __connman_error_invalid_arguments(msg);
128
129                 dbus_message_iter_get_basic(&value, &offlinemode);
130
131                 __connman_profile_set_offlinemode(offlinemode);
132
133                 __connman_profile_save_default();
134         } else if (g_str_equal(name, "ActiveProfile") == TRUE) {
135                 const char *str;
136
137                 dbus_message_iter_get_basic(&value, &str);
138
139                 return __connman_error_not_supported(msg);
140         } else
141                 return __connman_error_invalid_property(msg);
142
143         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
144 }
145
146 static DBusMessage *get_state(DBusConnection *conn,
147                                         DBusMessage *msg, void *data)
148 {
149         const char *str;
150
151         DBG("conn %p", conn);
152
153         if (__connman_security_check_privilege(msg,
154                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
155                 return __connman_error_permission_denied(msg);
156
157         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
158                 str = "online";
159         else
160                 str = "offline";
161
162         return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &str,
163                                                 DBUS_TYPE_INVALID);
164 }
165
166 static DBusMessage *create_profile(DBusConnection *conn,
167                                         DBusMessage *msg, void *data)
168 {
169         const char *name, *path;
170         int err;
171
172         DBG("conn %p", conn);
173
174         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
175                                                         DBUS_TYPE_INVALID);
176
177         if (__connman_security_check_privilege(msg,
178                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
179                 return __connman_error_permission_denied(msg);
180
181         err = __connman_profile_create(name, &path);
182         if (err < 0)
183                 return __connman_error_failed(msg, -err);
184
185         return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &path,
186                                                         DBUS_TYPE_INVALID);
187 }
188
189 static DBusMessage *remove_profile(DBusConnection *conn,
190                                         DBusMessage *msg, void *data)
191 {
192         const char *path;
193         int err;
194
195         DBG("conn %p", conn);
196
197         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
198                                                         DBUS_TYPE_INVALID);
199
200         if (__connman_security_check_privilege(msg,
201                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
202                 return __connman_error_permission_denied(msg);
203
204         err = __connman_profile_remove(path);
205         if (err < 0)
206                 return __connman_error_failed(msg, -err);
207
208         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
209 }
210
211 static DBusMessage *remove_provider(DBusConnection *conn,
212                                     DBusMessage *msg, void *data)
213 {
214         const char *path;
215         int err;
216
217         DBG("conn %p", conn);
218
219         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &path,
220                               DBUS_TYPE_INVALID);
221
222         if (__connman_security_check_privilege(msg,
223                                 CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
224                 return __connman_error_permission_denied(msg);
225
226         err = __connman_provider_remove(path);
227         if (err < 0)
228                 return __connman_error_failed(msg, -err);
229
230         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
231 }
232
233 static DBusMessage *request_scan(DBusConnection *conn,
234                                         DBusMessage *msg, void *data)
235 {
236         enum connman_service_type type;
237         const char *str;
238         int err;
239
240         DBG("conn %p", conn);
241
242         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
243                                                         DBUS_TYPE_INVALID);
244
245         if (g_strcmp0(str, "") == 0)
246                 type = CONNMAN_SERVICE_TYPE_UNKNOWN;
247         else if (g_strcmp0(str, "wifi") == 0)
248                 type = CONNMAN_SERVICE_TYPE_WIFI;
249         else if (g_strcmp0(str, "wimax") == 0)
250                 type = CONNMAN_SERVICE_TYPE_WIMAX;
251         else
252                 return __connman_error_invalid_arguments(msg);
253
254         err = __connman_element_request_scan(type);
255         if (err < 0) {
256                 if (err == -EINPROGRESS) {
257                         connman_error("Invalid return code from scan");
258                         err = -EINVAL;
259                 }
260
261                 return __connman_error_failed(msg, -err);
262         }
263
264         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
265 }
266
267 static DBusConnection *connection = NULL;
268
269 static enum connman_service_type technology_type;
270 static connman_bool_t technology_enabled;
271 static DBusMessage *technology_pending = NULL;
272 static guint technology_timeout = 0;
273
274 static void technology_reply(int error)
275 {
276         DBG("");
277
278         if (technology_timeout > 0) {
279                 g_source_remove(technology_timeout);
280                 technology_timeout = 0;
281         }
282
283         if (technology_pending != NULL) {
284                 if (error > 0) {
285                         DBusMessage *reply;
286
287                         reply = __connman_error_failed(technology_pending,
288                                                                 error);
289                         if (reply != NULL)
290                                 g_dbus_send_message(connection, reply);
291                 } else
292                         g_dbus_send_reply(connection, technology_pending,
293                                                         DBUS_TYPE_INVALID);
294
295                 dbus_message_unref(technology_pending);
296                 technology_pending = NULL;
297         }
298
299         technology_type = CONNMAN_SERVICE_TYPE_UNKNOWN;
300 }
301
302 static gboolean technology_abort(gpointer user_data)
303 {
304         DBG("");
305
306         technology_timeout = 0;
307
308         technology_reply(ETIMEDOUT);
309
310         return FALSE;
311 }
312
313 static void technology_notify(enum connman_service_type type,
314                                                 connman_bool_t enabled)
315 {
316         DBG("type %d enabled %d", type, enabled);
317
318         if (type == technology_type && enabled == technology_enabled)
319                 technology_reply(0);
320 }
321
322 static struct connman_notifier technology_notifier = {
323         .name           = "manager",
324         .priority       = CONNMAN_NOTIFIER_PRIORITY_HIGH,
325         .service_enabled= technology_notify,
326 };
327
328 static DBusMessage *enable_technology(DBusConnection *conn,
329                                         DBusMessage *msg, void *data)
330 {
331         enum connman_service_type type;
332         const char *str;
333         int err;
334
335         DBG("conn %p", conn);
336
337         if (technology_pending != NULL)
338                 return __connman_error_in_progress(msg);
339
340         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
341                                                         DBUS_TYPE_INVALID);
342
343         if (g_strcmp0(str, "ethernet") == 0)
344                 type = CONNMAN_SERVICE_TYPE_ETHERNET;
345         else if (g_strcmp0(str, "wifi") == 0)
346                 type = CONNMAN_SERVICE_TYPE_WIFI;
347         else if (g_strcmp0(str, "wimax") == 0)
348                 type = CONNMAN_SERVICE_TYPE_WIMAX;
349         else if (g_strcmp0(str, "bluetooth") == 0)
350                 type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
351         else if (g_strcmp0(str, "cellular") == 0)
352                 type = CONNMAN_SERVICE_TYPE_CELLULAR;
353         else
354                 return __connman_error_invalid_arguments(msg);
355
356         if (__connman_notifier_is_enabled(type) == TRUE)
357                 return __connman_error_already_enabled(msg);
358
359         technology_type = type;
360         technology_enabled = TRUE;
361         technology_pending = dbus_message_ref(msg);
362
363         err = __connman_element_enable_technology(type);
364         if (err < 0 && err != -EINPROGRESS)
365                 technology_reply(-err);
366         else
367                 technology_timeout = g_timeout_add_seconds(15,
368                                                 technology_abort, NULL);
369
370         return NULL;
371 }
372
373 static DBusMessage *disable_technology(DBusConnection *conn,
374                                         DBusMessage *msg, void *data)
375 {
376         enum connman_service_type type;
377         const char *str;
378         int err;
379
380         DBG("conn %p", conn);
381
382         if (technology_pending != NULL)
383                 return __connman_error_in_progress(msg);
384
385         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
386                                                         DBUS_TYPE_INVALID);
387
388         if (g_strcmp0(str, "ethernet") == 0)
389                 type = CONNMAN_SERVICE_TYPE_ETHERNET;
390         else if (g_strcmp0(str, "wifi") == 0)
391                 type = CONNMAN_SERVICE_TYPE_WIFI;
392         else if (g_strcmp0(str, "wimax") == 0)
393                 type = CONNMAN_SERVICE_TYPE_WIMAX;
394         else if (g_strcmp0(str, "bluetooth") == 0)
395                 type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
396         else if (g_strcmp0(str, "cellular") == 0)
397                 type = CONNMAN_SERVICE_TYPE_CELLULAR;
398         else
399                 return __connman_error_invalid_arguments(msg);
400
401         if (__connman_notifier_is_enabled(type) == FALSE)
402                 return __connman_error_already_disabled(msg);
403
404         technology_type = type;
405         technology_enabled = FALSE;
406         technology_pending = dbus_message_ref(msg);
407
408         err = __connman_element_disable_technology(type);
409         if (err < 0 && err != -EINPROGRESS)
410                 technology_reply(-err);
411         else
412                 technology_timeout = g_timeout_add_seconds(10,
413                                                 technology_abort, NULL);
414
415         return NULL;
416 }
417
418 static DBusMessage *connect_service(DBusConnection *conn,
419                                         DBusMessage *msg, void *data)
420 {
421         int err;
422
423         DBG("conn %p", conn);
424
425         if (__connman_security_check_privilege(msg,
426                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
427                 return __connman_error_permission_denied(msg);
428
429         err = __connman_service_create_and_connect(msg);
430         if (err < 0) {
431                 if (err == -EINPROGRESS) {
432                         connman_error("Invalid return code from connect");
433                         err = -EINVAL;
434                 }
435
436                 return __connman_error_failed(msg, -err);
437         }
438
439         return NULL;
440 }
441
442
443 static DBusMessage *connect_provider(DBusConnection *conn,
444                                      DBusMessage *msg, void *data)
445 {
446         int err;
447
448         DBG("conn %p", conn);
449
450         if (__connman_security_check_privilege(msg,
451                                 CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
452                 return __connman_error_permission_denied(msg);
453
454         err = __connman_provider_create_and_connect(msg);
455         if (err < 0) {
456                 if (err == -EINPROGRESS) {
457                         connman_error("Invalid return code from connect");
458                         err = -EINVAL;
459                 }
460
461                 return __connman_error_failed(msg, -err);
462         }
463
464         return NULL;
465 }
466
467 static DBusMessage *register_agent(DBusConnection *conn,
468                                         DBusMessage *msg, void *data)
469 {
470         const char *sender, *path;
471         int err;
472
473         DBG("conn %p", conn);
474
475         sender = dbus_message_get_sender(msg);
476
477         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
478                                                         DBUS_TYPE_INVALID);
479
480         err = __connman_agent_register(sender, path);
481         if (err < 0)
482                 return __connman_error_failed(msg, -err);
483
484         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
485 }
486
487 static DBusMessage *unregister_agent(DBusConnection *conn,
488                                         DBusMessage *msg, void *data)
489 {
490         const char *sender, *path;
491         int err;
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         err = __connman_agent_unregister(sender, path);
501         if (err < 0)
502                 return __connman_error_failed(msg, -err);
503
504         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
505 }
506
507 static GDBusMethodTable manager_methods[] = {
508         { "GetProperties",     "",      "a{sv}", get_properties     },
509         { "SetProperty",       "sv",    "",      set_property       },
510         { "GetState",          "",      "s",     get_state          },
511         { "CreateProfile",     "s",     "o",     create_profile     },
512         { "RemoveProfile",     "o",     "",      remove_profile     },
513         { "RemoveProvider",    "s",     "",      remove_provider    },
514         { "RequestScan",       "s",     "",      request_scan       },
515         { "EnableTechnology",  "s",     "",      enable_technology,
516                                                 G_DBUS_METHOD_FLAG_ASYNC },
517         { "DisableTechnology", "s",     "",      disable_technology,
518                                                 G_DBUS_METHOD_FLAG_ASYNC },
519         { "ConnectService",    "a{sv}", "o",     connect_service,
520                                                 G_DBUS_METHOD_FLAG_ASYNC },
521         { "ConnectProvider",   "a{sv}", "o",     connect_provider,
522                                                 G_DBUS_METHOD_FLAG_ASYNC },
523         { "RegisterAgent",     "o",     "",      register_agent     },
524         { "UnregisterAgent",   "o",     "",      unregister_agent   },
525         { },
526 };
527
528 static GDBusSignalTable manager_signals[] = {
529         { "PropertyChanged", "sv" },
530         { "StateChanged",    "s"  },
531         { },
532 };
533
534 static DBusMessage *nm_sleep(DBusConnection *conn,
535                                         DBusMessage *msg, void *data)
536 {
537         DBusMessage *reply;
538
539         DBG("conn %p", conn);
540
541         reply = dbus_message_new_method_return(msg);
542         if (reply == NULL)
543                 return NULL;
544
545         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
546
547         return reply;
548 }
549
550 static DBusMessage *nm_wake(DBusConnection *conn,
551                                         DBusMessage *msg, void *data)
552 {
553         DBusMessage *reply;
554
555         DBG("conn %p", conn);
556
557         reply = dbus_message_new_method_return(msg);
558         if (reply == NULL)
559                 return NULL;
560
561         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
562
563         return reply;
564 }
565
566 enum {
567         NM_STATE_UNKNOWN = 0,
568         NM_STATE_ASLEEP,
569         NM_STATE_CONNECTING,
570         NM_STATE_CONNECTED,
571         NM_STATE_DISCONNECTED
572 };
573
574 static DBusMessage *nm_state(DBusConnection *conn,
575                                         DBusMessage *msg, void *data)
576 {
577         DBusMessage *reply;
578         dbus_uint32_t state;
579
580         DBG("conn %p", conn);
581
582         reply = dbus_message_new_method_return(msg);
583         if (reply == NULL)
584                 return NULL;
585
586         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
587                 state = NM_STATE_CONNECTED;
588         else
589                 state = NM_STATE_DISCONNECTED;
590
591         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
592                                                         DBUS_TYPE_INVALID);
593
594         return reply;
595 }
596
597 static GDBusMethodTable nm_methods[] = {
598         { "sleep", "",  "",   nm_sleep        },
599         { "wake",  "",  "",   nm_wake         },
600         { "state", "",  "u",  nm_state        },
601         { },
602 };
603
604 static gboolean nm_compat = FALSE;
605
606 int __connman_manager_init(gboolean compat)
607 {
608         DBG("");
609
610         connection = connman_dbus_get_connection();
611         if (connection == NULL)
612                 return -1;
613
614         if (connman_notifier_register(&technology_notifier) < 0)
615                 connman_error("Failed to register technology notifier");
616
617         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
618                                         CONNMAN_MANAGER_INTERFACE,
619                                         manager_methods,
620                                         manager_signals, NULL, NULL, NULL);
621
622         if (compat == TRUE) {
623                 g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
624                                         nm_methods, NULL, NULL, NULL, NULL);
625
626                 nm_compat = TRUE;
627         }
628
629         return 0;
630 }
631
632 void __connman_manager_cleanup(void)
633 {
634         DBG("");
635
636         connman_notifier_unregister(&technology_notifier);
637
638         if (connection == NULL)
639                 return;
640
641         if (nm_compat == TRUE) {
642                 g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
643         }
644
645         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
646                                                 CONNMAN_MANAGER_INTERFACE);
647
648         dbus_connection_unref(connection);
649 }