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