8786a309cdd3bdf7acd28620614962f66b73303c
[framework/connectivity/connman.git] / src / manager.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 <errno.h>
27
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 connman_bool_t connman_state_idle;
33 DBusMessage *session_mode_pending = NULL;
34
35 static DBusMessage *get_properties(DBusConnection *conn,
36                                         DBusMessage *msg, void *data)
37 {
38         DBusMessage *reply;
39         DBusMessageIter array, dict;
40         connman_bool_t offlinemode, sessionmode;
41         const char *str;
42
43         DBG("conn %p", conn);
44
45         reply = dbus_message_new_method_return(msg);
46         if (reply == NULL)
47                 return NULL;
48
49         dbus_message_iter_init_append(reply, &array);
50
51         connman_dbus_dict_open(&array, &dict);
52
53         connman_dbus_dict_append_array(&dict, "Services",
54                         DBUS_TYPE_OBJECT_PATH, __connman_service_list, NULL);
55         connman_dbus_dict_append_array(&dict, "Technologies",
56                         DBUS_TYPE_OBJECT_PATH, __connman_technology_list, NULL);
57
58         str = __connman_notifier_get_state();
59         connman_dbus_dict_append_basic(&dict, "State",
60                                                 DBUS_TYPE_STRING, &str);
61
62         offlinemode = __connman_technology_get_offlinemode();
63         connman_dbus_dict_append_basic(&dict, "OfflineMode",
64                                         DBUS_TYPE_BOOLEAN, &offlinemode);
65
66         connman_dbus_dict_append_array(&dict, "ConnectedTechnologies",
67                 DBUS_TYPE_STRING, __connman_notifier_list_connected, NULL);
68
69         str = __connman_service_default();
70         if (str != NULL)
71                 connman_dbus_dict_append_basic(&dict, "DefaultTechnology",
72                                                 DBUS_TYPE_STRING, &str);
73
74         connman_dbus_dict_append_array(&dict, "AvailableDebugs",
75                         DBUS_TYPE_STRING, __connman_debug_list_available, NULL);
76         connman_dbus_dict_append_array(&dict, "EnabledDebugs",
77                         DBUS_TYPE_STRING, __connman_debug_list_enabled, NULL);
78
79         sessionmode = __connman_session_mode();
80         connman_dbus_dict_append_basic(&dict, "SessionMode",
81                                         DBUS_TYPE_BOOLEAN,
82                                         &sessionmode);
83
84         connman_dbus_dict_close(&array, &dict);
85
86         return reply;
87 }
88
89 static DBusMessage *set_property(DBusConnection *conn,
90                                         DBusMessage *msg, void *data)
91 {
92         DBusMessageIter iter, value;
93         const char *name;
94         int type;
95
96         DBG("conn %p", conn);
97
98         if (dbus_message_iter_init(msg, &iter) == FALSE)
99                 return __connman_error_invalid_arguments(msg);
100
101         dbus_message_iter_get_basic(&iter, &name);
102         dbus_message_iter_next(&iter);
103         dbus_message_iter_recurse(&iter, &value);
104
105         type = dbus_message_iter_get_arg_type(&value);
106
107         if (g_str_equal(name, "OfflineMode") == TRUE) {
108                 connman_bool_t offlinemode;
109
110                 if (type != DBUS_TYPE_BOOLEAN)
111                         return __connman_error_invalid_arguments(msg);
112
113                 dbus_message_iter_get_basic(&value, &offlinemode);
114
115                 __connman_technology_set_offlinemode(offlinemode);
116         } else if (g_str_equal(name, "SessionMode") == TRUE) {
117                 connman_bool_t sessionmode;
118
119                 if (type != DBUS_TYPE_BOOLEAN)
120                         return __connman_error_invalid_arguments(msg);
121
122                 dbus_message_iter_get_basic(&value, &sessionmode);
123
124                 if (session_mode_pending != NULL)
125                         return __connman_error_in_progress(msg);
126
127                 __connman_session_set_mode(sessionmode);
128
129                 if (sessionmode == TRUE && connman_state_idle == FALSE) {
130                         session_mode_pending = msg;
131                         return NULL;
132                 }
133
134         } else
135                 return __connman_error_invalid_property(msg);
136
137         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
138 }
139
140 static DBusMessage *remove_provider(DBusConnection *conn,
141                                     DBusMessage *msg, void *data)
142 {
143         const char *path;
144         int err;
145
146         DBG("conn %p", conn);
147
148         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
149                                                         DBUS_TYPE_INVALID);
150
151         err = __connman_provider_remove(path);
152         if (err < 0)
153                 return __connman_error_failed(msg, -err);
154
155         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
156 }
157
158 static DBusMessage *request_scan(DBusConnection *conn,
159                                         DBusMessage *msg, void *data)
160 {
161         enum connman_service_type type;
162         const char *str;
163         int err;
164
165         DBG("conn %p", conn);
166
167         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
168                                                         DBUS_TYPE_INVALID);
169
170         if (g_strcmp0(str, "") == 0)
171                 type = CONNMAN_SERVICE_TYPE_UNKNOWN;
172         else if (g_strcmp0(str, "wifi") == 0)
173                 type = CONNMAN_SERVICE_TYPE_WIFI;
174         else if (g_strcmp0(str, "wimax") == 0)
175                 type = CONNMAN_SERVICE_TYPE_WIMAX;
176         else
177                 return __connman_error_invalid_arguments(msg);
178
179         err = __connman_device_request_scan(type);
180         if (err < 0) {
181                 if (err == -EINPROGRESS) {
182                         connman_error("Invalid return code from scan");
183                         err = -EINVAL;
184                 }
185
186                 return __connman_error_failed(msg, -err);
187         }
188
189         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
190 }
191
192 static DBusConnection *connection = NULL;
193
194 static void session_mode_notify(void)
195 {
196         DBusMessage *reply;
197
198         reply = g_dbus_create_reply(session_mode_pending, DBUS_TYPE_INVALID);
199         g_dbus_send_message(connection, reply);
200
201         dbus_message_unref(session_mode_pending);
202         session_mode_pending = NULL;
203 }
204
205 static void idle_state(connman_bool_t idle)
206 {
207
208         DBG("idle %d", idle);
209
210         connman_state_idle = idle;
211
212         if (connman_state_idle == FALSE || session_mode_pending == NULL)
213                 return;
214
215         session_mode_notify();
216 }
217
218 static struct connman_notifier technology_notifier = {
219         .name           = "manager",
220         .priority       = CONNMAN_NOTIFIER_PRIORITY_HIGH,
221         .idle_state     = idle_state,
222 };
223
224 static DBusMessage *enable_technology(DBusConnection *conn,
225                                         DBusMessage *msg, void *data)
226 {
227         enum connman_service_type type;
228         const char *str;
229
230         DBG("conn %p", conn);
231
232         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
233                                                         DBUS_TYPE_INVALID);
234
235         if (g_strcmp0(str, "ethernet") == 0)
236                 type = CONNMAN_SERVICE_TYPE_ETHERNET;
237         else if (g_strcmp0(str, "wifi") == 0)
238                 type = CONNMAN_SERVICE_TYPE_WIFI;
239         else if (g_strcmp0(str, "wimax") == 0)
240                 type = CONNMAN_SERVICE_TYPE_WIMAX;
241         else if (g_strcmp0(str, "bluetooth") == 0)
242                 type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
243         else if (g_strcmp0(str, "cellular") == 0)
244                 type = CONNMAN_SERVICE_TYPE_CELLULAR;
245         else
246                 return __connman_error_invalid_arguments(msg);
247
248         if (__connman_notifier_is_registered(type) == FALSE)
249                 return __connman_error_not_registered(msg);
250
251         if (__connman_notifier_is_enabled(type) == TRUE)
252                 return __connman_error_already_enabled(msg);
253
254          __connman_technology_enable(type, msg);
255
256         return NULL;
257 }
258
259 static DBusMessage *disable_technology(DBusConnection *conn,
260                                         DBusMessage *msg, void *data)
261 {
262         enum connman_service_type type;
263         const char *str;
264
265         DBG("conn %p", conn);
266
267         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
268                                                         DBUS_TYPE_INVALID);
269
270         if (g_strcmp0(str, "ethernet") == 0)
271                 type = CONNMAN_SERVICE_TYPE_ETHERNET;
272         else if (g_strcmp0(str, "wifi") == 0)
273                 type = CONNMAN_SERVICE_TYPE_WIFI;
274         else if (g_strcmp0(str, "wimax") == 0)
275                 type = CONNMAN_SERVICE_TYPE_WIMAX;
276         else if (g_strcmp0(str, "bluetooth") == 0)
277                 type = CONNMAN_SERVICE_TYPE_BLUETOOTH;
278         else if (g_strcmp0(str, "cellular") == 0)
279                 type = CONNMAN_SERVICE_TYPE_CELLULAR;
280         else
281                 return __connman_error_invalid_arguments(msg);
282
283         if (__connman_notifier_is_registered(type) == FALSE)
284                 return __connman_error_not_registered(msg);
285
286         if (__connman_notifier_is_enabled(type) == FALSE)
287                 return __connman_error_already_disabled(msg);
288
289         __connman_technology_disable(type, msg);
290
291         return NULL;
292 }
293
294 static DBusMessage *get_services(DBusConnection *conn,
295                                         DBusMessage *msg, void *data)
296 {
297         DBusMessage *reply;
298         DBusMessageIter iter, array;
299
300         reply = dbus_message_new_method_return(msg);
301         if (reply == NULL)
302                 return NULL;
303
304         dbus_message_iter_init_append(reply, &iter);
305
306         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
307                         DBUS_STRUCT_BEGIN_CHAR_AS_STRING
308                         DBUS_TYPE_OBJECT_PATH_AS_STRING
309                         DBUS_TYPE_ARRAY_AS_STRING
310                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
311                                         DBUS_TYPE_STRING_AS_STRING
312                                         DBUS_TYPE_VARIANT_AS_STRING
313                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
314                         DBUS_STRUCT_END_CHAR_AS_STRING, &array);
315
316         __connman_service_list_struct(&array);
317
318         dbus_message_iter_close_container(&iter, &array);
319
320         return reply;
321 }
322
323 static DBusMessage *connect_provider(DBusConnection *conn,
324                                         DBusMessage *msg, void *data)
325 {
326         int err;
327
328         DBG("conn %p", conn);
329
330         if (__connman_session_mode() == TRUE) {
331                 connman_info("Session mode enabled: "
332                                 "direct provider connect disabled");
333
334                 return __connman_error_failed(msg, -EINVAL);
335         }
336
337         err = __connman_provider_create_and_connect(msg);
338         if (err < 0) {
339                 if (err == -EINPROGRESS) {
340                         connman_error("Invalid return code from connect");
341                         err = -EINVAL;
342                 }
343
344                 return __connman_error_failed(msg, -err);
345         }
346
347         return NULL;
348 }
349
350 static DBusMessage *register_agent(DBusConnection *conn,
351                                         DBusMessage *msg, void *data)
352 {
353         const char *sender, *path;
354         int err;
355
356         DBG("conn %p", conn);
357
358         sender = dbus_message_get_sender(msg);
359
360         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
361                                                         DBUS_TYPE_INVALID);
362
363         err = __connman_agent_register(sender, path);
364         if (err < 0)
365                 return __connman_error_failed(msg, -err);
366
367         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
368 }
369
370 static DBusMessage *unregister_agent(DBusConnection *conn,
371                                         DBusMessage *msg, void *data)
372 {
373         const char *sender, *path;
374         int err;
375
376         DBG("conn %p", conn);
377
378         sender = dbus_message_get_sender(msg);
379
380         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
381                                                         DBUS_TYPE_INVALID);
382
383         err = __connman_agent_unregister(sender, path);
384         if (err < 0)
385                 return __connman_error_failed(msg, -err);
386
387         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
388 }
389
390 static DBusMessage *register_counter(DBusConnection *conn,
391                                         DBusMessage *msg, void *data)
392 {
393         const char *sender, *path;
394         unsigned int accuracy, period;
395         int err;
396
397         DBG("conn %p", conn);
398
399         sender = dbus_message_get_sender(msg);
400
401         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
402                                                 DBUS_TYPE_UINT32, &accuracy,
403                                                 DBUS_TYPE_UINT32, &period,
404                                                         DBUS_TYPE_INVALID);
405
406         /* FIXME: add handling of accuracy parameter */
407
408         err = __connman_counter_register(sender, path, period);
409         if (err < 0)
410                 return __connman_error_failed(msg, -err);
411
412         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
413 }
414
415 static DBusMessage *unregister_counter(DBusConnection *conn,
416                                         DBusMessage *msg, void *data)
417 {
418         const char *sender, *path;
419         int err;
420
421         DBG("conn %p", conn);
422
423         sender = dbus_message_get_sender(msg);
424
425         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
426                                                         DBUS_TYPE_INVALID);
427
428         err = __connman_counter_unregister(sender, path);
429         if (err < 0)
430                 return __connman_error_failed(msg, -err);
431
432         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
433 }
434
435 static DBusMessage *create_session(DBusConnection *conn,
436                                         DBusMessage *msg, void *data)
437 {
438         int err;
439
440         DBG("conn %p", conn);
441
442         err = __connman_session_create(msg);
443         if (err < 0)
444                 return __connman_error_failed(msg, -err);
445
446         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
447 }
448
449 static DBusMessage *destroy_session(DBusConnection *conn,
450                                         DBusMessage *msg, void *data)
451 {
452         int err;
453
454         DBG("conn %p", conn);
455
456         err = __connman_session_destroy(msg);
457         if (err < 0)
458                 return __connman_error_failed(msg, -err);
459
460         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
461 }
462
463 static DBusMessage *request_private_network(DBusConnection *conn,
464                                         DBusMessage *msg, void *data)
465 {
466         const char *sender;
467         int  err;
468
469         DBG("conn %p", conn);
470
471         sender = dbus_message_get_sender(msg);
472
473         err = __connman_private_network_request(msg, sender);
474         if (err < 0)
475                 return __connman_error_failed(msg, -err);
476
477         return NULL;
478 }
479
480 static DBusMessage *release_private_network(DBusConnection *conn,
481                                         DBusMessage *msg, void *data)
482 {
483         const char *path;
484         int err;
485
486         DBG("conn %p", conn);
487
488         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
489                                                         DBUS_TYPE_INVALID);
490
491         err = __connman_private_network_release(path);
492         if (err < 0)
493                 return __connman_error_failed(msg, -err);
494
495         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
496 }
497
498 static GDBusMethodTable manager_methods[] = {
499         { "GetProperties",     "",      "a{sv}", get_properties     },
500         { "SetProperty",       "sv",    "",      set_property,
501                                                 G_DBUS_METHOD_FLAG_ASYNC },
502         { "RemoveProvider",    "o",     "",      remove_provider    },
503         { "RequestScan",       "s",     "",      request_scan       },
504         { "EnableTechnology",  "s",     "",      enable_technology,
505                                                 G_DBUS_METHOD_FLAG_ASYNC },
506         { "DisableTechnology", "s",     "",      disable_technology,
507                                                 G_DBUS_METHOD_FLAG_ASYNC },
508         { "GetServices",       "",      "a(oa{sv})", get_services   },
509         { "ConnectProvider",   "a{sv}", "o",     connect_provider,
510                                                 G_DBUS_METHOD_FLAG_ASYNC },
511         { "RegisterAgent",     "o",     "",      register_agent     },
512         { "UnregisterAgent",   "o",     "",      unregister_agent   },
513         { "RegisterCounter",   "ouu",   "",      register_counter   },
514         { "UnregisterCounter", "o",     "",      unregister_counter },
515         { "CreateSession",     "a{sv}o", "o",    create_session     },
516         { "DestroySession",    "o",     "",      destroy_session    },
517         { "RequestPrivateNetwork",    "",     "oa{sv}h",
518                                                 request_private_network,
519                                                 G_DBUS_METHOD_FLAG_ASYNC },
520         { "ReleasePrivateNetwork",    "o",    "",
521                                                 release_private_network },
522         { },
523 };
524
525 static GDBusSignalTable manager_signals[] = {
526         { "PropertyChanged", "sv" },
527         { },
528 };
529
530 int __connman_manager_init(void)
531 {
532         DBG("");
533
534         connection = connman_dbus_get_connection();
535         if (connection == NULL)
536                 return -1;
537
538         if (connman_notifier_register(&technology_notifier) < 0)
539                 connman_error("Failed to register technology notifier");
540
541         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
542                                         CONNMAN_MANAGER_INTERFACE,
543                                         manager_methods,
544                                         manager_signals, NULL, NULL, NULL);
545
546         connman_state_idle = TRUE;
547
548         return 0;
549 }
550
551 void __connman_manager_cleanup(void)
552 {
553         DBG("");
554
555         if (connection == NULL)
556                 return;
557
558         connman_notifier_unregister(&technology_notifier);
559
560         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
561                                                 CONNMAN_MANAGER_INTERFACE);
562
563         dbus_connection_unref(connection);
564 }