Add support for default technology property
[platform/upstream/connman.git] / src / manager.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <gdbus.h>
27
28 #include "connman.h"
29
30 static connman_bool_t global_offlinemode = FALSE;
31
32 static void append_profiles(DBusMessageIter *dict)
33 {
34         DBusMessageIter entry, value, iter;
35         const char *key = "Profiles";
36
37         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
38                                                                 NULL, &entry);
39
40         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
41
42         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
43                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
44                                                                 &value);
45
46         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
47                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
48         __connman_profile_list(&iter);
49         dbus_message_iter_close_container(&value, &iter);
50
51         dbus_message_iter_close_container(&entry, &value);
52
53         dbus_message_iter_close_container(dict, &entry);
54 }
55
56 static void append_services(DBusMessageIter *dict)
57 {
58         DBusMessageIter entry, value, iter;
59         const char *key = "Services";
60
61         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
62                                                                 NULL, &entry);
63
64         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
65
66         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
67                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
68                                                                 &value);
69
70         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
71                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
72         __connman_service_list(&iter);
73         dbus_message_iter_close_container(&value, &iter);
74
75         dbus_message_iter_close_container(&entry, &value);
76
77         dbus_message_iter_close_container(dict, &entry);
78 }
79
80 static void append_devices(DBusMessageIter *dict)
81 {
82         DBusMessageIter entry, value, iter;
83         const char *key = "Devices";
84
85         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
86                                                                 NULL, &entry);
87
88         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
89
90         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
91                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
92                                                                 &value);
93
94         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
95                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
96         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_DEVICE, &iter);
97         dbus_message_iter_close_container(&value, &iter);
98
99         dbus_message_iter_close_container(&entry, &value);
100
101         dbus_message_iter_close_container(dict, &entry);
102 }
103
104 static void append_connections(DBusMessageIter *dict)
105 {
106         DBusMessageIter entry, value, iter;
107         const char *key = "Connections";
108
109         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
110                                                                 NULL, &entry);
111
112         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
113
114         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
115                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
116                                                                 &value);
117
118         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
119                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
120         __connman_element_list(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION, &iter);
121         dbus_message_iter_close_container(&value, &iter);
122
123         dbus_message_iter_close_container(&entry, &value);
124
125         dbus_message_iter_close_container(dict, &entry);
126 }
127
128 static void append_available_technologies(DBusMessageIter *dict)
129 {
130         DBusMessageIter entry, value, iter;
131         const char *key = "AvailableTechnologies";
132
133         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
134                                                                 NULL, &entry);
135
136         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
137
138         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
139                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
140                                                                 &value);
141
142         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
143                                         DBUS_TYPE_STRING_AS_STRING, &iter);
144         __connman_notifier_list_registered(&iter);
145         dbus_message_iter_close_container(&value, &iter);
146
147         dbus_message_iter_close_container(&entry, &value);
148
149         dbus_message_iter_close_container(dict, &entry);
150 }
151
152 static void append_enabled_technologies(DBusMessageIter *dict)
153 {
154         DBusMessageIter entry, value, iter;
155         const char *key = "EnabledTechnologies";
156
157         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
158                                                                 NULL, &entry);
159
160         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
161
162         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
163                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
164                                                                 &value);
165
166         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
167                                         DBUS_TYPE_STRING_AS_STRING, &iter);
168         __connman_notifier_list_enabled(&iter);
169         dbus_message_iter_close_container(&value, &iter);
170
171         dbus_message_iter_close_container(&entry, &value);
172
173         dbus_message_iter_close_container(dict, &entry);
174 }
175
176 static void append_connected_technologies(DBusMessageIter *dict)
177 {
178         DBusMessageIter entry, value, iter;
179         const char *key = "ConnectedTechnologies";
180
181         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
182                                                                 NULL, &entry);
183
184         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
185
186         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
187                         DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING,
188                                                                 &value);
189
190         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
191                                         DBUS_TYPE_STRING_AS_STRING, &iter);
192         __connman_notifier_list_connected(&iter);
193         dbus_message_iter_close_container(&value, &iter);
194
195         dbus_message_iter_close_container(&entry, &value);
196
197         dbus_message_iter_close_container(dict, &entry);
198 }
199
200 static DBusMessage *get_properties(DBusConnection *conn,
201                                         DBusMessage *msg, void *data)
202 {
203         DBusMessage *reply;
204         DBusMessageIter array, dict;
205         const char *str;
206
207         DBG("conn %p", conn);
208
209         if (__connman_security_check_privilege(msg,
210                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
211                 return __connman_error_permission_denied(msg);
212
213         reply = dbus_message_new_method_return(msg);
214         if (reply == NULL)
215                 return NULL;
216
217         dbus_message_iter_init_append(reply, &array);
218
219         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
220                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
221                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
222                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
223
224         str = __connman_profile_active_path();
225         if (str != NULL)
226                 connman_dbus_dict_append_variant(&dict, "ActiveProfile",
227                                                 DBUS_TYPE_OBJECT_PATH, &str);
228
229         append_profiles(&dict);
230         append_services(&dict);
231
232         append_devices(&dict);
233         append_connections(&dict);
234
235         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
236                 str = "online";
237         else
238                 str = "offline";
239
240         connman_dbus_dict_append_variant(&dict, "State",
241                                                 DBUS_TYPE_STRING, &str);
242
243         connman_dbus_dict_append_variant(&dict, "OfflineMode",
244                                 DBUS_TYPE_BOOLEAN, &global_offlinemode);
245
246         append_available_technologies(&dict);
247         append_enabled_technologies(&dict);
248         append_connected_technologies(&dict);
249
250         str = __connman_service_default();
251         if (str != NULL)
252                 connman_dbus_dict_append_variant(&dict, "DefaultTechnology",
253                                                 DBUS_TYPE_STRING, &str);
254
255         dbus_message_iter_close_container(&array, &dict);
256
257         return reply;
258 }
259
260 static DBusMessage *set_property(DBusConnection *conn,
261                                         DBusMessage *msg, void *data)
262 {
263         DBusMessageIter iter, value;
264         const char *name;
265
266         DBG("conn %p", conn);
267
268         if (dbus_message_iter_init(msg, &iter) == FALSE)
269                 return __connman_error_invalid_arguments(msg);
270
271         dbus_message_iter_get_basic(&iter, &name);
272         dbus_message_iter_next(&iter);
273         dbus_message_iter_recurse(&iter, &value);
274
275         if (__connman_security_check_privilege(msg,
276                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
277                 return __connman_error_permission_denied(msg);
278
279         if (g_str_equal(name, "OfflineMode") == TRUE) {
280                 connman_bool_t offlinemode;
281
282                 dbus_message_iter_get_basic(&value, &offlinemode);
283
284                 if (global_offlinemode == offlinemode)
285                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
286
287                 global_offlinemode = offlinemode;
288
289                 __connman_device_set_offlinemode(offlinemode);
290         } else if (g_str_equal(name, "ActiveProfile") == TRUE) {
291                 const char *str;
292
293                 dbus_message_iter_get_basic(&value, &str);
294
295                 return __connman_error_not_supported(msg);
296         } else
297                 return __connman_error_invalid_property(msg);
298
299         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
300 }
301
302 static DBusMessage *get_state(DBusConnection *conn,
303                                         DBusMessage *msg, void *data)
304 {
305         const char *str;
306
307         DBG("conn %p", conn);
308
309         if (__connman_security_check_privilege(msg,
310                                         CONNMAN_SECURITY_PRIVILEGE_PUBLIC) < 0)
311                 return __connman_error_permission_denied(msg);
312
313         if (__connman_element_count(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION) > 0)
314                 str = "online";
315         else
316                 str = "offline";
317
318         return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &str,
319                                                 DBUS_TYPE_INVALID);
320 }
321
322 static DBusMessage *add_profile(DBusConnection *conn,
323                                         DBusMessage *msg, void *data)
324 {
325         const char *name;
326
327         DBG("conn %p", conn);
328
329         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
330                                                         DBUS_TYPE_INVALID);
331
332         return __connman_error_not_supported(msg);
333 }
334
335 static DBusMessage *remove_profile(DBusConnection *conn,
336                                         DBusMessage *msg, void *data)
337 {
338         const char *path;
339
340         DBG("conn %p", conn);
341
342         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
343                                                         DBUS_TYPE_INVALID);
344
345         return __connman_error_not_supported(msg);
346 }
347
348 static DBusMessage *request_scan(DBusConnection *conn,
349                                         DBusMessage *msg, void *data)
350 {
351         enum connman_device_type type;
352         const char *str;
353         int err;
354
355         DBG("conn %p", conn);
356
357         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
358                                                         DBUS_TYPE_INVALID);
359
360         if (g_strcmp0(str, "") == 0)
361                 type = CONNMAN_DEVICE_TYPE_UNKNOWN;
362         else if (g_strcmp0(str, "wifi") == 0)
363                 type = CONNMAN_DEVICE_TYPE_WIFI;
364         else if (g_strcmp0(str, "wimax") == 0)
365                 type = CONNMAN_DEVICE_TYPE_WIMAX;
366         else
367                 return __connman_error_invalid_arguments(msg);
368
369         err = __connman_element_request_scan(type);
370         if (err < 0) {
371                 if (err == -EINPROGRESS) {
372                         connman_error("Invalid return code from scan");
373                         err = -EINVAL;
374                 }
375
376                 return __connman_error_failed(msg, -err);
377         }
378
379         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
380 }
381
382 static DBusMessage *enable_technology(DBusConnection *conn,
383                                         DBusMessage *msg, void *data)
384 {
385         enum connman_device_type type;
386         const char *str;
387         int err;
388
389         DBG("conn %p", conn);
390
391         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
392                                                         DBUS_TYPE_INVALID);
393
394         if (g_strcmp0(str, "ethernet") == 0)
395                 type = CONNMAN_DEVICE_TYPE_ETHERNET;
396         else if (g_strcmp0(str, "wifi") == 0)
397                 type = CONNMAN_DEVICE_TYPE_WIFI;
398         else if (g_strcmp0(str, "wimax") == 0)
399                 type = CONNMAN_DEVICE_TYPE_WIMAX;
400         else if (g_strcmp0(str, "bluetooth") == 0)
401                 type = CONNMAN_DEVICE_TYPE_BLUETOOTH;
402         else if (g_strcmp0(str, "gps") == 0)
403                 type = CONNMAN_DEVICE_TYPE_GPS;
404         else
405                 return __connman_error_invalid_arguments(msg);
406
407         err = __connman_element_enable_technology(type);
408         if (err < 0) {
409                 if (err == -EINPROGRESS) {
410                         connman_error("Invalid return code from enable");
411                         err = -EINVAL;
412                 }
413
414                 return __connman_error_failed(msg, -err);
415         }
416
417         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
418 }
419
420 static DBusMessage *disable_technology(DBusConnection *conn,
421                                         DBusMessage *msg, void *data)
422 {
423         enum connman_device_type type;
424         const char *str;
425         int err;
426
427         DBG("conn %p", conn);
428
429         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
430                                                         DBUS_TYPE_INVALID);
431
432         if (g_strcmp0(str, "ethernet") == 0)
433                 type = CONNMAN_DEVICE_TYPE_ETHERNET;
434         else if (g_strcmp0(str, "wifi") == 0)
435                 type = CONNMAN_DEVICE_TYPE_WIFI;
436         else if (g_strcmp0(str, "wimax") == 0)
437                 type = CONNMAN_DEVICE_TYPE_WIMAX;
438         else if (g_strcmp0(str, "bluetooth") == 0)
439                 type = CONNMAN_DEVICE_TYPE_BLUETOOTH;
440         else if (g_strcmp0(str, "gps") == 0)
441                 type = CONNMAN_DEVICE_TYPE_GPS;
442         else
443                 return __connman_error_invalid_arguments(msg);
444
445         err = __connman_element_disable_technology(type);
446         if (err < 0) {
447                 if (err == -EINPROGRESS) {
448                         connman_error("Invalid return code from disable");
449                         err = -EINVAL;
450                 }
451
452                 return __connman_error_failed(msg, -err);
453         }
454
455         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
456 }
457
458 static DBusMessage *connect_service(DBusConnection *conn,
459                                         DBusMessage *msg, void *data)
460 {
461         int err;
462
463         DBG("conn %p", conn);
464
465         if (__connman_security_check_privilege(msg,
466                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
467                 return __connman_error_permission_denied(msg);
468
469         err = __connman_service_create_and_connect(msg);
470         if (err < 0) {
471                 if (err == -EINPROGRESS) {
472                         connman_error("Invalid return code from connect");
473                         err = -EINVAL;
474                 }
475
476                 return __connman_error_failed(msg, -err);
477         }
478
479         return NULL;
480 }
481
482 static DBusMessage *register_agent(DBusConnection *conn,
483                                         DBusMessage *msg, void *data)
484 {
485         DBusMessage *reply;
486         const char *sender, *path;
487
488         DBG("conn %p", conn);
489
490         sender = dbus_message_get_sender(msg);
491
492         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
493                                                         DBUS_TYPE_INVALID);
494
495         reply = dbus_message_new_method_return(msg);
496         if (reply == NULL)
497                 return NULL;
498
499         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
500
501         __connman_agent_register(sender, path);
502
503         return reply;
504 }
505
506 static DBusMessage *unregister_agent(DBusConnection *conn,
507                                         DBusMessage *msg, void *data)
508 {
509         DBusMessage *reply;
510         const char *sender, *path;
511
512         DBG("conn %p", conn);
513
514         sender = dbus_message_get_sender(msg);
515
516         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
517                                                         DBUS_TYPE_INVALID);
518
519         reply = dbus_message_new_method_return(msg);
520         if (reply == NULL)
521                 return NULL;
522
523         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
524
525         __connman_agent_unregister(sender, path);
526
527         return reply;
528 }
529
530 static GDBusMethodTable manager_methods[] = {
531         { "GetProperties",     "",      "a{sv}", get_properties     },
532         { "SetProperty",       "sv",    "",      set_property       },
533         { "GetState",          "",      "s",     get_state          },
534         { "AddProfile",        "s",     "o",     add_profile        },
535         { "RemoveProfile",     "o",     "",      remove_profile     },
536         { "RequestScan",       "s",     "",      request_scan       },
537         { "EnableTechnology",  "s",     "",      enable_technology  },
538         { "DisableTechnology", "s",     "",      disable_technology },
539         { "ConnectService",    "a{sv}", "o",     connect_service,
540                                                 G_DBUS_METHOD_FLAG_ASYNC },
541         { "RegisterAgent",     "o",     "",      register_agent     },
542         { "UnregisterAgent",   "o",     "",      unregister_agent   },
543         { },
544 };
545
546 static GDBusSignalTable manager_signals[] = {
547         { "PropertyChanged", "sv" },
548         { "StateChanged",    "s"  },
549         { },
550 };
551
552 static DBusMessage *nm_sleep(DBusConnection *conn,
553                                         DBusMessage *msg, void *data)
554 {
555         DBusMessage *reply;
556
557         DBG("conn %p", conn);
558
559         reply = dbus_message_new_method_return(msg);
560         if (reply == NULL)
561                 return NULL;
562
563         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
564
565         return reply;
566 }
567
568 static DBusMessage *nm_wake(DBusConnection *conn,
569                                         DBusMessage *msg, void *data)
570 {
571         DBusMessage *reply;
572
573         DBG("conn %p", conn);
574
575         reply = dbus_message_new_method_return(msg);
576         if (reply == NULL)
577                 return NULL;
578
579         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
580
581         return reply;
582 }
583
584 enum {
585         NM_STATE_UNKNOWN = 0,
586         NM_STATE_ASLEEP,
587         NM_STATE_CONNECTING,
588         NM_STATE_CONNECTED,
589         NM_STATE_DISCONNECTED
590 };
591
592 static DBusMessage *nm_state(DBusConnection *conn,
593                                         DBusMessage *msg, void *data)
594 {
595         DBusMessage *reply;
596         dbus_uint32_t state;
597
598         DBG("conn %p", conn);
599
600         reply = dbus_message_new_method_return(msg);
601         if (reply == NULL)
602                 return NULL;
603
604         state = NM_STATE_DISCONNECTED;
605
606         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
607                                                         DBUS_TYPE_INVALID);
608
609         return reply;
610 }
611
612 static GDBusMethodTable nm_methods[] = {
613         { "sleep", "",  "",   nm_sleep        },
614         { "wake",  "",  "",   nm_wake         },
615         { "state", "",  "u",  nm_state        },
616         { },
617 };
618
619 static DBusConnection *connection = NULL;
620 static gboolean nm_compat = FALSE;
621
622 int __connman_manager_init(DBusConnection *conn, gboolean compat)
623 {
624         DBG("conn %p", conn);
625
626         connection = dbus_connection_ref(conn);
627         if (connection == NULL)
628                 return -1;
629
630         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
631                                         CONNMAN_MANAGER_INTERFACE,
632                                         manager_methods,
633                                         manager_signals, NULL, NULL, NULL);
634
635         if (compat == TRUE) {
636                 g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
637                                         nm_methods, NULL, NULL, NULL, NULL);
638
639                 nm_compat = TRUE;
640         }
641
642         return 0;
643 }
644
645 void __connman_manager_cleanup(void)
646 {
647         DBG("conn %p", connection);
648
649         if (nm_compat == TRUE) {
650                 g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
651         }
652
653         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
654                                                 CONNMAN_MANAGER_INTERFACE);
655
656         dbus_connection_unref(connection);
657 }