Add support for ConnectedTechnologies property
[framework/connectivity/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         dbus_message_iter_close_container(&array, &dict);
251
252         return reply;
253 }
254
255 static DBusMessage *set_property(DBusConnection *conn,
256                                         DBusMessage *msg, void *data)
257 {
258         DBusMessageIter iter, value;
259         const char *name;
260
261         DBG("conn %p", conn);
262
263         if (dbus_message_iter_init(msg, &iter) == FALSE)
264                 return __connman_error_invalid_arguments(msg);
265
266         dbus_message_iter_get_basic(&iter, &name);
267         dbus_message_iter_next(&iter);
268         dbus_message_iter_recurse(&iter, &value);
269
270         if (__connman_security_check_privilege(msg,
271                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
272                 return __connman_error_permission_denied(msg);
273
274         if (g_str_equal(name, "OfflineMode") == TRUE) {
275                 connman_bool_t offlinemode;
276
277                 dbus_message_iter_get_basic(&value, &offlinemode);
278
279                 if (global_offlinemode == offlinemode)
280                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
281
282                 global_offlinemode = offlinemode;
283
284                 __connman_device_set_offlinemode(offlinemode);
285         } else if (g_str_equal(name, "ActiveProfile") == TRUE) {
286                 const char *str;
287
288                 dbus_message_iter_get_basic(&value, &str);
289
290                 return __connman_error_not_supported(msg);
291         } else
292                 return __connman_error_invalid_property(msg);
293
294         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
295 }
296
297 static DBusMessage *add_profile(DBusConnection *conn,
298                                         DBusMessage *msg, void *data)
299 {
300         const char *name;
301
302         DBG("conn %p", conn);
303
304         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name,
305                                                         DBUS_TYPE_INVALID);
306
307         return __connman_error_not_supported(msg);
308 }
309
310 static DBusMessage *remove_profile(DBusConnection *conn,
311                                         DBusMessage *msg, void *data)
312 {
313         const char *path;
314
315         DBG("conn %p", conn);
316
317         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
318                                                         DBUS_TYPE_INVALID);
319
320         return __connman_error_not_supported(msg);
321 }
322
323 static DBusMessage *request_scan(DBusConnection *conn,
324                                         DBusMessage *msg, void *data)
325 {
326         enum connman_device_type type;
327         const char *str;
328         int err;
329
330         DBG("conn %p", conn);
331
332         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
333                                                         DBUS_TYPE_INVALID);
334
335         if (g_strcmp0(str, "") == 0)
336                 type = CONNMAN_DEVICE_TYPE_UNKNOWN;
337         else if (g_strcmp0(str, "wifi") == 0)
338                 type = CONNMAN_DEVICE_TYPE_WIFI;
339         else if (g_strcmp0(str, "wimax") == 0)
340                 type = CONNMAN_DEVICE_TYPE_WIMAX;
341         else
342                 return __connman_error_invalid_arguments(msg);
343
344         err = __connman_element_request_scan(type);
345         if (err < 0) {
346                 if (err == -EINPROGRESS) {
347                         connman_error("Invalid return code from scan");
348                         err = -EINVAL;
349                 }
350
351                 return __connman_error_failed(msg, -err);
352         }
353
354         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
355 }
356
357 static DBusMessage *enable_technology(DBusConnection *conn,
358                                         DBusMessage *msg, void *data)
359 {
360         enum connman_device_type type;
361         const char *str;
362         int err;
363
364         DBG("conn %p", conn);
365
366         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
367                                                         DBUS_TYPE_INVALID);
368
369         if (g_strcmp0(str, "ethernet") == 0)
370                 type = CONNMAN_DEVICE_TYPE_ETHERNET;
371         else if (g_strcmp0(str, "wifi") == 0)
372                 type = CONNMAN_DEVICE_TYPE_WIFI;
373         else if (g_strcmp0(str, "wimax") == 0)
374                 type = CONNMAN_DEVICE_TYPE_WIMAX;
375         else if (g_strcmp0(str, "bluetooth") == 0)
376                 type = CONNMAN_DEVICE_TYPE_BLUETOOTH;
377         else if (g_strcmp0(str, "gps") == 0)
378                 type = CONNMAN_DEVICE_TYPE_GPS;
379         else
380                 return __connman_error_invalid_arguments(msg);
381
382         err = __connman_element_enable_technology(type);
383         if (err < 0) {
384                 if (err == -EINPROGRESS) {
385                         connman_error("Invalid return code from enable");
386                         err = -EINVAL;
387                 }
388
389                 return __connman_error_failed(msg, -err);
390         }
391
392         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
393 }
394
395 static DBusMessage *disable_technology(DBusConnection *conn,
396                                         DBusMessage *msg, void *data)
397 {
398         enum connman_device_type type;
399         const char *str;
400         int err;
401
402         DBG("conn %p", conn);
403
404         dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
405                                                         DBUS_TYPE_INVALID);
406
407         if (g_strcmp0(str, "ethernet") == 0)
408                 type = CONNMAN_DEVICE_TYPE_ETHERNET;
409         else if (g_strcmp0(str, "wifi") == 0)
410                 type = CONNMAN_DEVICE_TYPE_WIFI;
411         else if (g_strcmp0(str, "wimax") == 0)
412                 type = CONNMAN_DEVICE_TYPE_WIMAX;
413         else if (g_strcmp0(str, "bluetooth") == 0)
414                 type = CONNMAN_DEVICE_TYPE_BLUETOOTH;
415         else if (g_strcmp0(str, "gps") == 0)
416                 type = CONNMAN_DEVICE_TYPE_GPS;
417         else
418                 return __connman_error_invalid_arguments(msg);
419
420         err = __connman_element_disable_technology(type);
421         if (err < 0) {
422                 if (err == -EINPROGRESS) {
423                         connman_error("Invalid return code from disable");
424                         err = -EINVAL;
425                 }
426
427                 return __connman_error_failed(msg, -err);
428         }
429
430         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
431 }
432
433 static DBusMessage *connect_service(DBusConnection *conn,
434                                         DBusMessage *msg, void *data)
435 {
436         int err;
437
438         DBG("conn %p", conn);
439
440         if (__connman_security_check_privilege(msg,
441                                         CONNMAN_SECURITY_PRIVILEGE_MODIFY) < 0)
442                 return __connman_error_permission_denied(msg);
443
444         err = __connman_service_create_and_connect(msg);
445         if (err < 0) {
446                 if (err == -EINPROGRESS) {
447                         connman_error("Invalid return code from connect");
448                         err = -EINVAL;
449                 }
450
451                 return __connman_error_failed(msg, -err);
452         }
453
454         return NULL;
455 }
456
457 static DBusMessage *register_agent(DBusConnection *conn,
458                                         DBusMessage *msg, void *data)
459 {
460         DBusMessage *reply;
461         const char *sender, *path;
462
463         DBG("conn %p", conn);
464
465         sender = dbus_message_get_sender(msg);
466
467         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
468                                                         DBUS_TYPE_INVALID);
469
470         reply = dbus_message_new_method_return(msg);
471         if (reply == NULL)
472                 return NULL;
473
474         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
475
476         __connman_agent_register(sender, path);
477
478         return reply;
479 }
480
481 static DBusMessage *unregister_agent(DBusConnection *conn,
482                                         DBusMessage *msg, void *data)
483 {
484         DBusMessage *reply;
485         const char *sender, *path;
486
487         DBG("conn %p", conn);
488
489         sender = dbus_message_get_sender(msg);
490
491         dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
492                                                         DBUS_TYPE_INVALID);
493
494         reply = dbus_message_new_method_return(msg);
495         if (reply == NULL)
496                 return NULL;
497
498         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
499
500         __connman_agent_unregister(sender, path);
501
502         return reply;
503 }
504
505 static GDBusMethodTable manager_methods[] = {
506         { "GetProperties",     "",      "a{sv}", get_properties     },
507         { "SetProperty",       "sv",    "",      set_property       },
508         { "AddProfile",        "s",     "o",     add_profile        },
509         { "RemoveProfile",     "o",     "",      remove_profile     },
510         { "RequestScan",       "s",     "",      request_scan       },
511         { "EnableTechnology",  "s",     "",      enable_technology  },
512         { "DisableTechnology", "s",     "",      disable_technology },
513         { "ConnectService",    "a{sv}", "o",     connect_service,
514                                                 G_DBUS_METHOD_FLAG_ASYNC },
515         { "RegisterAgent",     "o",     "",      register_agent     },
516         { "UnregisterAgent",   "o",     "",      unregister_agent   },
517         { },
518 };
519
520 static GDBusSignalTable manager_signals[] = {
521         { "PropertyChanged", "sv" },
522         { "StateChanged",    "s"  },
523         { },
524 };
525
526 static DBusMessage *nm_sleep(DBusConnection *conn,
527                                         DBusMessage *msg, void *data)
528 {
529         DBusMessage *reply;
530
531         DBG("conn %p", conn);
532
533         reply = dbus_message_new_method_return(msg);
534         if (reply == NULL)
535                 return NULL;
536
537         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
538
539         return reply;
540 }
541
542 static DBusMessage *nm_wake(DBusConnection *conn,
543                                         DBusMessage *msg, void *data)
544 {
545         DBusMessage *reply;
546
547         DBG("conn %p", conn);
548
549         reply = dbus_message_new_method_return(msg);
550         if (reply == NULL)
551                 return NULL;
552
553         dbus_message_append_args(reply, DBUS_TYPE_INVALID);
554
555         return reply;
556 }
557
558 enum {
559         NM_STATE_UNKNOWN = 0,
560         NM_STATE_ASLEEP,
561         NM_STATE_CONNECTING,
562         NM_STATE_CONNECTED,
563         NM_STATE_DISCONNECTED
564 };
565
566 static DBusMessage *nm_state(DBusConnection *conn,
567                                         DBusMessage *msg, void *data)
568 {
569         DBusMessage *reply;
570         dbus_uint32_t state;
571
572         DBG("conn %p", conn);
573
574         reply = dbus_message_new_method_return(msg);
575         if (reply == NULL)
576                 return NULL;
577
578         state = NM_STATE_DISCONNECTED;
579
580         dbus_message_append_args(reply, DBUS_TYPE_UINT32, &state,
581                                                         DBUS_TYPE_INVALID);
582
583         return reply;
584 }
585
586 static GDBusMethodTable nm_methods[] = {
587         { "sleep", "",  "",   nm_sleep        },
588         { "wake",  "",  "",   nm_wake         },
589         { "state", "",  "u",  nm_state        },
590         { },
591 };
592
593 static DBusConnection *connection = NULL;
594 static gboolean nm_compat = FALSE;
595
596 int __connman_manager_init(DBusConnection *conn, gboolean compat)
597 {
598         DBG("conn %p", conn);
599
600         connection = dbus_connection_ref(conn);
601         if (connection == NULL)
602                 return -1;
603
604         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
605                                         CONNMAN_MANAGER_INTERFACE,
606                                         manager_methods,
607                                         manager_signals, NULL, NULL, NULL);
608
609         if (compat == TRUE) {
610                 g_dbus_register_interface(connection, NM_PATH, NM_INTERFACE,
611                                         nm_methods, NULL, NULL, NULL, NULL);
612
613                 nm_compat = TRUE;
614         }
615
616         return 0;
617 }
618
619 void __connman_manager_cleanup(void)
620 {
621         DBG("conn %p", connection);
622
623         if (nm_compat == TRUE) {
624                 g_dbus_unregister_interface(connection, NM_PATH, NM_INTERFACE);
625         }
626
627         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
628                                                 CONNMAN_MANAGER_INTERFACE);
629
630         dbus_connection_unref(connection);
631 }