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