1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2006-2007 Nokia Corporation
6 * Copyright (C) 2004-2009 Marcel Holtmann <marcel@holtmann.org>
7 * Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg@nokia.com>
8 *
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <stdio.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <sys/ioctl.h>
36
37 #include <bluetooth/bluetooth.h>
38 #include <bluetooth/hci.h>
39 #include <bluetooth/l2cap.h>
40
41 #include <glib.h>
42 #include <dbus/dbus.h>
43 #include <gdbus.h>
44
45 #include "logging.h"
46
47 #include "manager.h"
48 #include "adapter.h"
49 #include "dbus-hci.h"
50 #include "dbus-common.h"
51
52 #define BLUEZ_NAME "org.bluez"
53
54 #define RECONNECT_RETRY_TIMEOUT 5000
55
system_bus_reconnect(void * data)56 static gboolean system_bus_reconnect(void *data)
57 {
58 DBusConnection *conn = get_dbus_connection();
59 struct hci_dev_list_req *dl = NULL;
60 struct hci_dev_req *dr;
61 int sk, i;
62 gboolean ret_val = TRUE;
63
64 if (conn) {
65 if (dbus_connection_get_is_connected(conn))
66 return FALSE;
67 }
68
69 if (hcid_dbus_init() < 0)
70 return TRUE;
71
72 /* Create and bind HCI socket */
73 sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
74 if (sk < 0) {
75 error("Can't open HCI socket: %s (%d)",
76 strerror(errno), errno);
77 return TRUE;
78 }
79
80 dl = g_malloc0(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl));
81
82 dl->dev_num = HCI_MAX_DEV;
83 dr = dl->dev_req;
84
85 if (ioctl(sk, HCIGETDEVLIST, (void *) dl) < 0) {
86 info("Can't get device list: %s (%d)",
87 strerror(errno), errno);
88 goto failed;
89 }
90
91 /* reset the default device */
92 manager_set_default_adapter(-1);
93
94 /* FIXME: it shouldn't be needed to register adapters again */
95 for (i = 0; i < dl->dev_num; i++, dr++)
96 manager_register_adapter(dr->dev_id, TRUE);
97
98 ret_val = FALSE;
99
100 failed:
101 if (sk >= 0)
102 close(sk);
103
104 g_free(dl);
105
106 return ret_val;
107 }
108
disconnect_callback(DBusConnection * conn,void * user_data)109 static void disconnect_callback(DBusConnection *conn, void *user_data)
110 {
111 set_dbus_connection(NULL);
112
113 g_timeout_add(RECONNECT_RETRY_TIMEOUT,
114 system_bus_reconnect, NULL);
115 }
116
hcid_dbus_unregister(void)117 void hcid_dbus_unregister(void)
118 {
119 DBusConnection *conn = get_dbus_connection();
120 char **children;
121 int i;
122 uint16_t dev_id;
123
124 if (!conn || !dbus_connection_get_is_connected(conn))
125 return;
126
127 /* Unregister all paths in Adapter path hierarchy */
128 if (!dbus_connection_list_registered(conn, "/", &children))
129 return;
130
131 for (i = 0; children[i]; i++) {
132 char path[MAX_PATH_LENGTH];
133 struct btd_adapter *adapter;
134
135 if (children[i][0] != 'h')
136 continue;
137
138 snprintf(path, sizeof(path), "/%s", children[i]);
139
140 adapter = manager_find_adapter_by_path(path);
141 if (!adapter)
142 continue;
143
144 dev_id = adapter_get_dev_id(adapter);
145 manager_unregister_adapter(dev_id);
146 }
147
148 dbus_free_string_array(children);
149 }
150
hcid_dbus_exit(void)151 void hcid_dbus_exit(void)
152 {
153 DBusConnection *conn = get_dbus_connection();
154
155 if (!conn || !dbus_connection_get_is_connected(conn))
156 return;
157
158 manager_cleanup(conn, "/");
159
160 set_dbus_connection(NULL);
161
162 dbus_connection_unref(conn);
163 }
164
hcid_dbus_init(void)165 int hcid_dbus_init(void)
166 {
167 DBusConnection *conn;
168 DBusError err;
169
170 dbus_error_init(&err);
171
172 conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err);
173 if (!conn) {
174 if (dbus_error_is_set(&err)) {
175 dbus_error_free(&err);
176 return -EIO;
177 }
178 return -EALREADY;
179 }
180
181 if (g_dbus_set_disconnect_function(conn, disconnect_callback,
182 NULL, NULL) == FALSE) {
183 dbus_connection_unref(conn);
184 return -EIO;
185 }
186
187 if (!manager_init(conn, "/"))
188 return -EIO;
189
190 set_dbus_connection(conn);
191
192 return 0;
193 }
194
append_variant(DBusMessageIter * iter,int type,void * val)195 static void append_variant(DBusMessageIter *iter, int type, void *val)
196 {
197 DBusMessageIter value;
198 char sig[2] = { type, '\0' };
199
200 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
201
202 dbus_message_iter_append_basic(&value, type, val);
203
204 dbus_message_iter_close_container(iter, &value);
205 }
206
append_array_variant(DBusMessageIter * iter,int type,void * val)207 static void append_array_variant(DBusMessageIter *iter, int type, void *val)
208 {
209 DBusMessageIter variant, array;
210 char type_sig[2] = { type, '\0' };
211 char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
212 const char ***str_array = val;
213 int i;
214
215 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
216 array_sig, &variant);
217
218 dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
219 type_sig, &array);
220
221 for (i = 0; (*str_array)[i]; i++)
222 dbus_message_iter_append_basic(&array, type,
223 &((*str_array)[i]));
224
225 dbus_message_iter_close_container(&variant, &array);
226
227 dbus_message_iter_close_container(iter, &variant);
228 }
229
dict_append_entry(DBusMessageIter * dict,const char * key,int type,void * val)230 void dict_append_entry(DBusMessageIter *dict,
231 const char *key, int type, void *val)
232 {
233 DBusMessageIter entry;
234
235 if (type == DBUS_TYPE_STRING) {
236 const char *str = *((const char **) val);
237 if (str == NULL)
238 return;
239 }
240
241 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
242 NULL, &entry);
243
244 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
245
246 append_variant(&entry, type, val);
247
248 dbus_message_iter_close_container(dict, &entry);
249 }
250
dict_append_array(DBusMessageIter * dict,const char * key,int type,void * val,int n_elements)251 void dict_append_array(DBusMessageIter *dict, const char *key, int type,
252 void *val, int n_elements)
253 {
254 DBusMessageIter entry;
255
256 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
257 NULL, &entry);
258
259 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
260
261 append_array_variant(&entry, type, val);
262
263 dbus_message_iter_close_container(dict, &entry);
264 }
265
emit_property_changed(DBusConnection * conn,const char * path,const char * interface,const char * name,int type,void * value)266 dbus_bool_t emit_property_changed(DBusConnection *conn,
267 const char *path,
268 const char *interface,
269 const char *name,
270 int type, void *value)
271 {
272 DBusMessage *signal;
273 DBusMessageIter iter;
274
275 signal = dbus_message_new_signal(path, interface, "PropertyChanged");
276
277 if (!signal) {
278 error("Unable to allocate new %s.PropertyChanged signal",
279 interface);
280 return FALSE;
281 }
282
283 dbus_message_iter_init_append(signal, &iter);
284
285 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
286
287 append_variant(&iter, type, value);
288
289 return g_dbus_send_message(conn, signal);
290 }
291
emit_array_property_changed(DBusConnection * conn,const char * path,const char * interface,const char * name,int type,void * value)292 dbus_bool_t emit_array_property_changed(DBusConnection *conn,
293 const char *path,
294 const char *interface,
295 const char *name,
296 int type, void *value)
297 {
298 DBusMessage *signal;
299 DBusMessageIter iter;
300
301 signal = dbus_message_new_signal(path, interface, "PropertyChanged");
302
303 if (!signal) {
304 error("Unable to allocate new %s.PropertyChanged signal",
305 interface);
306 return FALSE;
307 }
308
309 dbus_message_iter_init_append(signal, &iter);
310
311 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
312
313 append_array_variant(&iter, type, value);
314
315 return g_dbus_send_message(conn, signal);
316 }
317