• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2006-2010  Nokia Corporation
6  *  Copyright (C) 2004-2010  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 "log.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