• 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  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35 
36 #include <bluetooth/bluetooth.h>
37 
38 #include <glib.h>
39 
40 #include <dbus/dbus.h>
41 
42 #include <gdbus.h>
43 
44 #include "hcid.h"
45 #include "dbus-common.h"
46 #include "log.h"
47 #include "adapter.h"
48 #include "error.h"
49 #include "manager.h"
50 
51 static char base_path[50] = "/org/bluez";
52 
53 static DBusConnection *connection = NULL;
54 static int default_adapter_id = -1;
55 static GSList *adapters = NULL;
56 
manager_get_base_path(void)57 const char *manager_get_base_path(void)
58 {
59 	return base_path;
60 }
61 
default_adapter(DBusConnection * conn,DBusMessage * msg,void * data)62 static DBusMessage *default_adapter(DBusConnection *conn,
63 					DBusMessage *msg, void *data)
64 {
65 	DBusMessage *reply;
66 	struct btd_adapter *adapter;
67 	const gchar *path;
68 
69 	adapter = manager_find_adapter_by_id(default_adapter_id);
70 	if (!adapter)
71 		return btd_error_no_such_adapter(msg);
72 
73 	reply = dbus_message_new_method_return(msg);
74 	if (!reply)
75 		return NULL;
76 
77 	path = adapter_get_path(adapter);
78 
79 	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
80 				DBUS_TYPE_INVALID);
81 
82 	return reply;
83 }
84 
find_adapter(DBusConnection * conn,DBusMessage * msg,void * data)85 static DBusMessage *find_adapter(DBusConnection *conn,
86 					DBusMessage *msg, void *data)
87 {
88 	DBusMessage *reply;
89 	struct btd_adapter *adapter;
90 	const char *pattern;
91 	int dev_id;
92 	const gchar *path;
93 
94 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
95 							DBUS_TYPE_INVALID))
96 		return NULL;
97 
98 	/* hci_devid() would make sense to use here, except it is
99 	 * restricted to devices which are up */
100 	if (!strcmp(pattern, "any") || !strcmp(pattern, "00:00:00:00:00:00")) {
101 		path = adapter_any_get_path();
102 		if (path != NULL)
103 			goto done;
104 		return btd_error_no_such_adapter(msg);
105 	} else if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4) {
106 		dev_id = atoi(pattern + 3);
107 		adapter = manager_find_adapter_by_id(dev_id);
108 	} else {
109 		bdaddr_t bdaddr;
110 		str2ba(pattern, &bdaddr);
111 		adapter = manager_find_adapter(&bdaddr);
112 	}
113 
114 	if (!adapter)
115 		return btd_error_no_such_adapter(msg);
116 
117 	path = adapter_get_path(adapter);
118 
119 done:
120 	reply = dbus_message_new_method_return(msg);
121 	if (!reply)
122 		return NULL;
123 
124 	dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
125 							DBUS_TYPE_INVALID);
126 
127 	return reply;
128 }
129 
list_adapters(DBusConnection * conn,DBusMessage * msg,void * data)130 static DBusMessage *list_adapters(DBusConnection *conn,
131 					DBusMessage *msg, void *data)
132 {
133 	DBusMessageIter iter;
134 	DBusMessageIter array_iter;
135 	DBusMessage *reply;
136 	GSList *l;
137 
138 	reply = dbus_message_new_method_return(msg);
139 	if (!reply)
140 		return NULL;
141 
142 	dbus_message_iter_init_append(reply, &iter);
143 
144 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
145 				DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
146 
147 	for (l = adapters; l; l = l->next) {
148 		struct btd_adapter *adapter = l->data;
149 		const gchar *path = adapter_get_path(adapter);
150 
151 		dbus_message_iter_append_basic(&array_iter,
152 					DBUS_TYPE_OBJECT_PATH, &path);
153 	}
154 
155 	dbus_message_iter_close_container(&iter, &array_iter);
156 
157 	return reply;
158 }
159 
get_properties(DBusConnection * conn,DBusMessage * msg,void * data)160 static DBusMessage *get_properties(DBusConnection *conn,
161 					DBusMessage *msg, void *data)
162 {
163 	DBusMessage *reply;
164 	DBusMessageIter iter;
165 	DBusMessageIter dict;
166 	GSList *list;
167 	char **array;
168 	int i;
169 
170 	reply = dbus_message_new_method_return(msg);
171 	if (!reply)
172 		return NULL;
173 
174 	dbus_message_iter_init_append(reply, &iter);
175 
176 	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
177 			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
178 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
179 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
180 
181 	array = g_new0(char *, g_slist_length(adapters) + 1);
182 	for (i = 0, list = adapters; list; list = list->next) {
183 		struct btd_adapter *adapter = list->data;
184 
185 		array[i] = (char *) adapter_get_path(adapter);
186 		i++;
187 	}
188 	dict_append_array(&dict, "Adapters", DBUS_TYPE_OBJECT_PATH, &array, i);
189 	g_free(array);
190 
191 	dbus_message_iter_close_container(&iter, &dict);
192 
193 	return reply;
194 }
195 
196 static GDBusMethodTable manager_methods[] = {
197 	{ "GetProperties",	"",	"a{sv}",get_properties	},
198 	{ "DefaultAdapter",	"",	"o",	default_adapter	},
199 	{ "FindAdapter",	"s",	"o",	find_adapter	},
200 	{ "ListAdapters",	"",	"ao",	list_adapters,
201 						G_DBUS_METHOD_FLAG_DEPRECATED},
202 	{ }
203 };
204 
205 static GDBusSignalTable manager_signals[] = {
206 	{ "PropertyChanged",		"sv"	},
207 	{ "AdapterAdded",		"o"	},
208 	{ "AdapterRemoved",		"o"	},
209 	{ "DefaultAdapterChanged",	"o"	},
210 	{ }
211 };
212 
manager_init(DBusConnection * conn,const char * path)213 dbus_bool_t manager_init(DBusConnection *conn, const char *path)
214 {
215 	connection = conn;
216 
217 	snprintf(base_path, sizeof(base_path), "/org/bluez/%d", getpid());
218 
219 	return g_dbus_register_interface(conn, "/", MANAGER_INTERFACE,
220 					manager_methods, manager_signals,
221 					NULL, NULL, NULL);
222 }
223 
manager_update_adapters(void)224 static void manager_update_adapters(void)
225 {
226 	GSList *list;
227 	char **array;
228 	int i;
229 
230 	array = g_new0(char *, g_slist_length(adapters) + 1);
231 	for (i = 0, list = adapters; list; list = list->next) {
232 		struct btd_adapter *adapter = list->data;
233 
234 		array[i] = (char *) adapter_get_path(adapter);
235 		i++;
236 	}
237 
238 	emit_array_property_changed(connection, "/",
239 					MANAGER_INTERFACE, "Adapters",
240 					DBUS_TYPE_OBJECT_PATH, &array, i);
241 
242 	g_free(array);
243 }
244 
manager_set_default_adapter(int id)245 static void manager_set_default_adapter(int id)
246 {
247 	struct btd_adapter *adapter;
248 	const gchar *path;
249 
250 	default_adapter_id = id;
251 
252 	adapter = manager_find_adapter_by_id(id);
253 	if (!adapter)
254 		return;
255 
256 	path = adapter_get_path(adapter);
257 
258 	g_dbus_emit_signal(connection, "/",
259 			MANAGER_INTERFACE,
260 			"DefaultAdapterChanged",
261 			DBUS_TYPE_OBJECT_PATH, &path,
262 			DBUS_TYPE_INVALID);
263 }
264 
manager_remove_adapter(struct btd_adapter * adapter)265 static void manager_remove_adapter(struct btd_adapter *adapter)
266 {
267 	uint16_t dev_id = adapter_get_dev_id(adapter);
268 	const gchar *path = adapter_get_path(adapter);
269 
270 	adapters = g_slist_remove(adapters, adapter);
271 
272 	manager_update_adapters();
273 
274 	if (default_adapter_id == dev_id || default_adapter_id < 0) {
275 		int new_default = hci_get_route(NULL);
276 
277 		manager_set_default_adapter(new_default);
278 	}
279 
280 	g_dbus_emit_signal(connection, "/",
281 			MANAGER_INTERFACE, "AdapterRemoved",
282 			DBUS_TYPE_OBJECT_PATH, &path,
283 			DBUS_TYPE_INVALID);
284 
285 	adapter_remove(adapter);
286 
287 	if (adapters == NULL)
288 		btd_start_exit_timer();
289 }
290 
manager_cleanup(DBusConnection * conn,const char * path)291 void manager_cleanup(DBusConnection *conn, const char *path)
292 {
293 	g_slist_foreach(adapters, (GFunc) manager_remove_adapter, NULL);
294 	g_slist_free(adapters);
295 
296 	g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE);
297 }
298 
adapter_id_cmp(gconstpointer a,gconstpointer b)299 static gint adapter_id_cmp(gconstpointer a, gconstpointer b)
300 {
301 	struct btd_adapter *adapter = (struct btd_adapter *) a;
302 	uint16_t id = GPOINTER_TO_UINT(b);
303 	uint16_t dev_id = adapter_get_dev_id(adapter);
304 
305 	return dev_id == id ? 0 : -1;
306 }
307 
adapter_cmp(gconstpointer a,gconstpointer b)308 static gint adapter_cmp(gconstpointer a, gconstpointer b)
309 {
310 	struct btd_adapter *adapter = (struct btd_adapter *) a;
311 	const bdaddr_t *bdaddr = b;
312 	bdaddr_t src;
313 
314 	adapter_get_address(adapter, &src);
315 
316 	return bacmp(&src, bdaddr);
317 }
318 
manager_find_adapter(const bdaddr_t * sba)319 struct btd_adapter *manager_find_adapter(const bdaddr_t *sba)
320 {
321 	GSList *match;
322 
323 	match = g_slist_find_custom(adapters, sba, adapter_cmp);
324 	if (!match)
325 		return NULL;
326 
327 	return match->data;
328 }
329 
manager_find_adapter_by_id(int id)330 struct btd_adapter *manager_find_adapter_by_id(int id)
331 {
332 	GSList *match;
333 
334 	match = g_slist_find_custom(adapters, GINT_TO_POINTER(id),
335 							adapter_id_cmp);
336 	if (!match)
337 		return NULL;
338 
339 	return match->data;
340 }
341 
manager_foreach_adapter(adapter_cb func,gpointer user_data)342 void manager_foreach_adapter(adapter_cb func, gpointer user_data)
343 {
344 	g_slist_foreach(adapters, (GFunc) func, user_data);
345 }
346 
manager_get_adapters(void)347 GSList *manager_get_adapters(void)
348 {
349 	return adapters;
350 }
351 
manager_add_adapter(const char * path)352 void manager_add_adapter(const char *path)
353 {
354 	g_dbus_emit_signal(connection, "/",
355 				MANAGER_INTERFACE, "AdapterAdded",
356 				DBUS_TYPE_OBJECT_PATH, &path,
357 				DBUS_TYPE_INVALID);
358 
359 	manager_update_adapters();
360 
361 	btd_stop_exit_timer();
362 }
363 
btd_manager_register_adapter(int id)364 struct btd_adapter *btd_manager_register_adapter(int id)
365 {
366 	struct btd_adapter *adapter;
367 	const char *path;
368 
369 	adapter = manager_find_adapter_by_id(id);
370 	if (adapter) {
371 		error("Unable to register adapter: hci%d already exist", id);
372 		return NULL;
373 	}
374 
375 	adapter = adapter_create(connection, id);
376 	if (!adapter)
377 		return NULL;
378 
379 	adapters = g_slist_append(adapters, adapter);
380 
381 	if (!adapter_init(adapter)) {
382 		btd_adapter_unref(adapter);
383 		return NULL;
384 	}
385 
386 	path = adapter_get_path(adapter);
387 	g_dbus_emit_signal(connection, "/",
388 				MANAGER_INTERFACE, "AdapterAdded",
389 				DBUS_TYPE_OBJECT_PATH, &path,
390 				DBUS_TYPE_INVALID);
391 
392 	manager_update_adapters();
393 
394 	btd_stop_exit_timer();
395 
396 	if (default_adapter_id < 0)
397 		manager_set_default_adapter(id);
398 
399 	DBG("Adapter %s registered", path);
400 
401 	return btd_adapter_ref(adapter);
402 }
403 
btd_manager_unregister_adapter(int id)404 int btd_manager_unregister_adapter(int id)
405 {
406 	struct btd_adapter *adapter;
407 	const gchar *path;
408 
409 	adapter = manager_find_adapter_by_id(id);
410 	if (!adapter)
411 		return -1;
412 
413 	path = adapter_get_path(adapter);
414 
415 	info("Unregister path: %s", path);
416 
417 	manager_remove_adapter(adapter);
418 
419 	return 0;
420 }
421 
btd_manager_set_did(uint16_t vendor,uint16_t product,uint16_t version)422 void btd_manager_set_did(uint16_t vendor, uint16_t product, uint16_t version)
423 {
424 	GSList *l;
425 
426 	for (l = adapters; l != NULL; l = g_slist_next(l)) {
427 		struct btd_adapter *adapter = l->data;
428 
429 		btd_adapter_set_did(adapter, vendor, product, version);
430 	}
431 }
432