mgmtops.c revision 983bc0f8ccd66ec217421288a0b5fb2c38b604bd
1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2010  Nokia Corporation
6 *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <stdio.h>
29#include <errno.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <sys/types.h>
33#include <sys/ioctl.h>
34#include <sys/wait.h>
35
36#include <glib.h>
37
38#include <bluetooth/bluetooth.h>
39#include <bluetooth/hci.h>
40#include <bluetooth/mgmt.h>
41
42#include "plugin.h"
43#include "log.h"
44#include "manager.h"
45#include "adapter.h"
46#include "device.h"
47#include "event.h"
48
49#define MGMT_BUF_SIZE 1024
50
51static int max_index = -1;
52static struct controller_info {
53	gboolean valid;
54	gboolean notified;
55	uint8_t type;
56	bdaddr_t bdaddr;
57	uint8_t features[8];
58	uint8_t dev_class[3];
59	uint16_t manufacturer;
60	uint8_t hci_ver;
61	uint16_t hci_rev;
62	gboolean enabled;
63	gboolean discoverable;
64	gboolean pairable;
65	uint8_t sec_mode;
66} *controllers = NULL;
67
68static int mgmt_sock = -1;
69static guint mgmt_watch = 0;
70
71static uint8_t mgmt_version = 0;
72static uint16_t mgmt_revision = 0;
73
74static void read_version_complete(int sk, void *buf, size_t len)
75{
76	struct mgmt_hdr hdr;
77	struct mgmt_rp_read_version *rp = buf;
78
79	if (len < sizeof(*rp)) {
80		error("Too small read version complete event");
81		return;
82	}
83
84	mgmt_revision = btohs(bt_get_unaligned(&rp->revision));
85	mgmt_version = rp->version;
86
87	DBG("version %u revision %u", mgmt_version, mgmt_revision);
88
89	memset(&hdr, 0, sizeof(hdr));
90	hdr.opcode = MGMT_OP_READ_INDEX_LIST;
91	if (write(sk, &hdr, sizeof(hdr)) < 0)
92		error("Unable to read controller index list: %s (%d)",
93						strerror(errno), errno);
94}
95
96static void add_controller(uint16_t index)
97{
98	if (index > max_index) {
99		size_t size = sizeof(struct controller_info) * (index + 1);
100		max_index = index;
101		controllers = g_realloc(controllers, size);
102	}
103
104	memset(&controllers[index], 0, sizeof(struct controller_info));
105
106	controllers[index].valid = TRUE;
107
108	DBG("Added controller %u", index);
109}
110
111static void read_info(int sk, uint16_t index)
112{
113	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_read_info)];
114	struct mgmt_hdr *hdr = (void *) buf;
115	struct mgmt_cp_read_info *cp = (void *) &buf[sizeof(*hdr)];
116
117	memset(buf, 0, sizeof(buf));
118	hdr->opcode = MGMT_OP_READ_INFO;
119	hdr->len = htobs(sizeof(*cp));
120
121	cp->index = htobs(index);
122
123	if (write(sk, buf, sizeof(buf)) < 0)
124		error("Unable to send read_info command: %s (%d)",
125						strerror(errno), errno);
126}
127
128static void mgmt_index_added(int sk, void *buf, size_t len)
129{
130	struct mgmt_ev_index_added *ev = buf;
131	uint16_t index;
132
133	if (len < sizeof(*ev)) {
134		error("Too small index added event");
135		return;
136	}
137
138	index = btohs(bt_get_unaligned(&ev->index));
139
140	add_controller(index);
141	read_info(sk, index);
142}
143
144static void remove_controller(uint16_t index)
145{
146	if (index > max_index)
147		return;
148
149	if (!controllers[index].valid)
150		return;
151
152	manager_unregister_adapter(index);
153
154	memset(&controllers[index], 0, sizeof(struct controller_info));
155
156	DBG("Removed controller %u", index);
157}
158
159static void mgmt_index_removed(int sk, void *buf, size_t len)
160{
161	struct mgmt_ev_index_removed *ev = buf;
162	uint16_t index;
163
164	if (len < sizeof(*ev)) {
165		error("Too small index removed event");
166		return;
167	}
168
169	index = btohs(bt_get_unaligned(&ev->index));
170
171	remove_controller(index);
172}
173
174static void read_index_list_complete(int sk, void *buf, size_t len)
175{
176	struct mgmt_rp_read_index_list *rp = buf;
177	uint16_t num;
178	int i;
179
180	if (len < sizeof(*rp)) {
181		error("Too small read index list complete event");
182		return;
183	}
184
185	num = btohs(bt_get_unaligned(&rp->num_controllers));
186
187	if (num * sizeof(uint16_t) + sizeof(*rp) != len) {
188		error("Incorrect packet size for index list event");
189		return;
190	}
191
192	for (i = 0; i < num; i++) {
193		uint16_t index;
194
195		index = btohs(bt_get_unaligned(&rp->index[i]));
196
197		add_controller(index);
198		read_info(sk, index);
199	}
200}
201
202static void read_info_complete(int sk, void *buf, size_t len)
203{
204	struct mgmt_rp_read_info *rp = buf;
205	struct controller_info *info;
206	uint16_t index;
207	char addr[18];
208
209	if (len < sizeof(*rp)) {
210		error("Too small read info complete event");
211		return;
212	}
213
214	index = btohs(bt_get_unaligned(&rp->index));
215	if (index > max_index) {
216		error("Unexpected index %u in read info complete", index);
217		return;
218	}
219
220	info = &controllers[index];
221	info->type = rp->type;
222	info->enabled = rp->powered;
223	info->discoverable = rp->discoverable;
224	info->pairable = rp->pairable;
225	info->sec_mode = rp->sec_mode;
226	bacpy(&info->bdaddr, &rp->bdaddr);
227	memcpy(info->dev_class, rp->dev_class, 3);
228	memcpy(info->features, rp->features, 8);
229	info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
230	info->hci_ver = rp->hci_ver;
231	info->hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
232
233	ba2str(&info->bdaddr, addr);
234	DBG("hci%u type %u addr %s", index, info->type, addr);
235	DBG("hci%u class 0x%02x%02x%02x", index,
236		info->dev_class[2], info->dev_class[1], info->dev_class[0]);
237	DBG("hci%u manufacturer %d HCI ver %d:%d", index, info->manufacturer,
238						info->hci_ver, info->hci_rev);
239	DBG("hci%u enabled %u discoverable %u pairable %u sec_mode %u", index,
240					info->enabled, info->discoverable,
241					info->pairable, info->sec_mode);
242
243	manager_register_adapter(index, info->enabled);
244
245	if (info->enabled)
246		manager_start_adapter(index);
247}
248
249static void mgmt_cmd_complete(int sk, void *buf, size_t len)
250{
251	struct mgmt_ev_cmd_complete *ev = buf;
252	uint16_t opcode;
253
254	DBG("");
255
256	if (len < sizeof(*ev)) {
257		error("Too small management command complete event packet");
258		return;
259	}
260
261	opcode = btohs(bt_get_unaligned(&ev->opcode));
262
263	switch (opcode) {
264	case MGMT_OP_READ_VERSION:
265		read_version_complete(sk, ev->data, len - sizeof(*ev));
266		break;
267	case MGMT_OP_READ_INDEX_LIST:
268		read_index_list_complete(sk, ev->data, len - sizeof(*ev));
269		break;
270	case MGMT_OP_READ_INFO:
271		read_info_complete(sk, ev->data, len - sizeof(*ev));
272		break;
273	default:
274		error("Unknown command complete for opcode %u", opcode);
275		break;
276	}
277}
278
279static void mgmt_cmd_status(int sk, void *buf, size_t len)
280{
281	struct mgmt_ev_cmd_status *ev = buf;
282	uint16_t opcode;
283
284	if (len < sizeof(*ev)) {
285		error("Too small management command status event packet");
286		return;
287	}
288
289	opcode = btohs(bt_get_unaligned(&ev->opcode));
290
291	DBG("status %u opcode %u", ev->status, opcode);
292}
293
294static void mgmt_controller_error(int sk, void *buf, size_t len)
295{
296	struct mgmt_ev_controller_error *ev = buf;
297	uint16_t index;
298
299	if (len < sizeof(*ev)) {
300		error("Too small management controller error event packet");
301		return;
302	}
303
304	index = btohs(bt_get_unaligned(&ev->index));
305
306	DBG("index %u error_code %u", index, ev->error_code);
307}
308
309static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data)
310{
311	char buf[MGMT_BUF_SIZE];
312	struct mgmt_hdr *hdr = (void *) buf;
313	int sk;
314	ssize_t ret;
315	uint16_t len, opcode;
316
317	DBG("cond %d", cond);
318
319	if (cond & G_IO_NVAL)
320		return FALSE;
321
322	sk = g_io_channel_unix_get_fd(io);
323
324	if (cond & (G_IO_ERR | G_IO_HUP)) {
325		error("Error on management socket");
326		return FALSE;
327	}
328
329	ret = read(sk, buf, sizeof(buf));
330	if (ret < 0) {
331		error("Unable to read from management socket: %s (%d)",
332						strerror(errno), errno);
333		return TRUE;
334	}
335
336	DBG("Received %zd bytes from management socket", ret);
337
338	if (ret < MGMT_HDR_SIZE) {
339		error("Too small Management packet");
340		return TRUE;
341	}
342
343	opcode = btohs(bt_get_unaligned(&hdr->opcode));
344	len = btohs(bt_get_unaligned(&hdr->len));
345
346	if (ret != MGMT_HDR_SIZE + len) {
347		error("Packet length mismatch. ret %zd len %u", ret, len);
348		return TRUE;
349	}
350
351	switch (opcode) {
352	case MGMT_EV_CMD_COMPLETE:
353		mgmt_cmd_complete(sk, buf + MGMT_HDR_SIZE, len);
354		break;
355	case MGMT_EV_CMD_STATUS:
356		mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len);
357		break;
358	case MGMT_EV_CONTROLLER_ERROR:
359		mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len);
360		break;
361	case MGMT_EV_INDEX_ADDED:
362		mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len);
363		break;
364	case MGMT_EV_INDEX_REMOVED:
365		mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len);
366		break;
367	default:
368		error("Unknown Management opcode %u", opcode);
369		break;
370	}
371
372	return TRUE;
373}
374
375static int mgmt_setup(void)
376{
377	struct mgmt_hdr hdr;
378	struct sockaddr_hci addr;
379	GIOChannel *io;
380	GIOCondition condition;
381	int dd, err;
382
383	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
384	if (dd < 0)
385		return -errno;
386
387	memset(&addr, 0, sizeof(addr));
388	addr.hci_family = AF_BLUETOOTH;
389	addr.hci_dev = HCI_DEV_NONE;
390	addr.hci_channel = HCI_CHANNEL_CONTROL;
391
392	if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
393		err = -errno;
394		goto fail;
395	}
396
397	memset(&hdr, 0, sizeof(hdr));
398	hdr.opcode = MGMT_OP_READ_VERSION;
399	if (write(dd, &hdr, sizeof(hdr)) < 0) {
400		err = -errno;
401		goto fail;
402	}
403
404	io = g_io_channel_unix_new(dd);
405	condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
406	mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL);
407	g_io_channel_unref(io);
408
409	mgmt_sock = dd;
410
411	info("Bluetooth Management interface initialized");
412
413	return 0;
414
415fail:
416	close(dd);
417	return err;
418}
419
420static void mgmt_cleanup(void)
421{
422	g_free(controllers);
423	controllers = NULL;
424	max_index = -1;
425
426	if (mgmt_sock >= 0) {
427		close(mgmt_sock);
428		mgmt_sock = -1;
429	}
430
431	if (mgmt_watch > 0) {
432		g_source_remove(mgmt_watch);
433		mgmt_watch = 0;
434	}
435}
436
437static int mgmt_start(int index)
438{
439	DBG("index %d", index);
440	return -ENOSYS;
441}
442
443static int mgmt_stop(int index)
444{
445	DBG("index %d", index);
446	return -ENOSYS;
447}
448
449static int mgmt_powered(int index, gboolean powered)
450{
451	DBG("index %d powered %d", index, powered);
452	return -ENOSYS;
453}
454
455static int mgmt_connectable(int index)
456{
457	DBG("index %d", index);
458	return -ENOSYS;
459}
460
461static int mgmt_discoverable(int index)
462{
463	DBG("index %d", index);
464	return -ENOSYS;
465}
466
467static int mgmt_set_class(int index, uint32_t class)
468{
469	DBG("index %d class %u", index, class);
470	return -ENOSYS;
471}
472
473static int mgmt_set_limited_discoverable(int index, uint32_t class,
474							gboolean limited)
475{
476	DBG("index %d class %u, limited %d", index, class, limited);
477	return -ENOSYS;
478}
479
480static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic)
481{
482	DBG("index %d length %u periodic %d", index, length, periodic);
483	return -ENOSYS;
484}
485
486static int mgmt_stop_inquiry(int index)
487{
488	DBG("index %d", index);
489	return -ENOSYS;
490}
491
492static int mgmt_start_scanning(int index)
493{
494	DBG("index %d", index);
495	return -ENOSYS;
496}
497
498static int mgmt_stop_scanning(int index)
499{
500	DBG("index %d", index);
501	return -ENOSYS;
502}
503
504static int mgmt_resolve_name(int index, bdaddr_t *bdaddr)
505{
506	char addr[18];
507
508	ba2str(bdaddr, addr);
509	DBG("index %d addr %s", index, addr);
510
511	return -ENOSYS;
512}
513
514static int mgmt_set_name(int index, const char *name)
515{
516	DBG("index %d, name %s", index, name);
517	return -ENOSYS;
518}
519
520static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr)
521{
522	char addr[18];
523
524	ba2str(bdaddr, addr);
525	DBG("index %d addr %s", index, addr);
526
527	return -ENOSYS;
528}
529
530static int mgmt_fast_connectable(int index, gboolean enable)
531{
532	DBG("index %d enable %d", index, enable);
533	return -ENOSYS;
534}
535
536static int mgmt_read_clock(int index, int handle, int which, int timeout,
537					uint32_t *clock, uint16_t *accuracy)
538{
539	DBG("index %d handle %d which %d timeout %d", index, handle,
540							which, timeout);
541	return -ENOSYS;
542}
543
544static int mgmt_conn_handle(int index, const bdaddr_t *bdaddr, int *handle)
545{
546	char addr[18];
547
548	ba2str(bdaddr, addr);
549	DBG("index %d addr %s", index, addr);
550
551	return -ENOSYS;
552}
553
554static int mgmt_write_eir_data(int index, uint8_t *data)
555{
556	DBG("index %d", index);
557	return -ENOSYS;
558}
559
560static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr)
561{
562	char addr[18];
563	struct controller_info *info = &controllers[index];
564
565	ba2str(&info->bdaddr, addr);
566	DBG("index %d addr %s", index, addr);
567
568	if (!info->valid)
569		return -ENODEV;
570
571	bacpy(bdaddr, &info->bdaddr);
572
573	return 0;
574}
575
576static int mgmt_block_device(int index, bdaddr_t *bdaddr)
577{
578	char addr[18];
579
580	ba2str(bdaddr, addr);
581	DBG("index %d addr %s", index, addr);
582
583	return -ENOSYS;
584}
585
586static int mgmt_unblock_device(int index, bdaddr_t *bdaddr)
587{
588	char addr[18];
589
590	ba2str(bdaddr, addr);
591	DBG("index %d addr %s", index, addr);
592
593	return -ENOSYS;
594}
595
596static int mgmt_get_conn_list(int index, GSList **conns)
597{
598	DBG("index %d", index);
599	return -ENOSYS;
600}
601
602static int mgmt_read_local_version(int index, struct hci_version *ver)
603{
604	struct controller_info *info = &controllers[index];
605
606	DBG("index %d", index);
607
608	if (!info->valid)
609		return -ENODEV;
610
611	memset(ver, 0, sizeof(*ver));
612	ver->manufacturer = info->manufacturer;
613	ver->hci_ver = info->hci_ver;
614	ver->hci_rev = info->hci_rev;
615
616	return 0;
617}
618
619static int mgmt_read_local_features(int index, uint8_t *features)
620{
621	struct controller_info *info = &controllers[index];
622
623	DBG("index %d", index);
624
625	if (!info->valid)
626		return -ENODEV;
627
628	memcpy(features, info->features, 8);
629
630	return 0;
631}
632
633static int mgmt_read_local_ext_features(int index)
634{
635	DBG("index %d", index);
636	return -ENOSYS;
637}
638
639static int mgmt_disconnect(int index, uint16_t handle)
640{
641	DBG("index %d handle %u", index, handle);
642	return -ENOSYS;
643}
644
645static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
646{
647	char addr[18];
648
649	ba2str(bdaddr, addr);
650	DBG("index %d addr %s", index, addr);
651
652	return -ENOSYS;
653}
654
655static int mgmt_request_authentication(int index, uint16_t handle)
656{
657	DBG("index %d handle %u", index, handle);
658	return -ENOSYS;
659}
660
661static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
662{
663	char addr[18];
664
665	ba2str(bdaddr, addr);
666	DBG("index %d addr %s pin %s", index, addr, pin);
667
668	return -ENOSYS;
669}
670
671static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
672{
673	char addr[18];
674
675	ba2str(bdaddr, addr);
676	DBG("index %d addr %s success %d", index, addr, success);
677
678	return -ENOSYS;
679}
680
681static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
682{
683	char addr[18];
684
685	ba2str(bdaddr, addr);
686	DBG("index %d addr %s passkey %06u", index, addr, passkey);
687
688	return -ENOSYS;
689}
690
691static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth)
692{
693	char addr[18];
694
695	ba2str(bdaddr, addr);
696	DBG("index %d addr %s", index, addr);
697
698	return -ENOSYS;
699}
700
701static int mgmt_read_scan_enable(int index)
702{
703	DBG("index %d", index);
704	return -ENOSYS;
705}
706
707static int mgmt_write_le_host(int index, uint8_t le, uint8_t simul)
708{
709	DBG("index %d le %u simul %u", index, le, simul);
710	return -ENOSYS;
711}
712
713static int mgmt_get_remote_version(int index, uint16_t handle,
714							gboolean delayed)
715{
716	DBG("index %d handle %u delayed %d", index, handle, delayed);
717	return -ENOSYS;
718}
719
720static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
721							gpointer user_data)
722{
723	char addr[18];
724
725	ba2str(dst, addr);
726	DBG("index %d addr %s", index, addr);
727
728	return -ENOSYS;
729}
730
731static struct btd_adapter_ops mgmt_ops = {
732	.setup = mgmt_setup,
733	.cleanup = mgmt_cleanup,
734	.start = mgmt_start,
735	.stop = mgmt_stop,
736	.set_powered = mgmt_powered,
737	.set_connectable = mgmt_connectable,
738	.set_discoverable = mgmt_discoverable,
739	.set_limited_discoverable = mgmt_set_limited_discoverable,
740	.start_inquiry = mgmt_start_inquiry,
741	.stop_inquiry = mgmt_stop_inquiry,
742	.start_scanning = mgmt_start_scanning,
743	.stop_scanning = mgmt_stop_scanning,
744	.resolve_name = mgmt_resolve_name,
745	.cancel_resolve_name = mgmt_cancel_resolve_name,
746	.set_name = mgmt_set_name,
747	.set_class = mgmt_set_class,
748	.set_fast_connectable = mgmt_fast_connectable,
749	.read_clock = mgmt_read_clock,
750	.get_conn_handle = mgmt_conn_handle,
751	.write_eir_data = mgmt_write_eir_data,
752	.read_bdaddr = mgmt_read_bdaddr,
753	.block_device = mgmt_block_device,
754	.unblock_device = mgmt_unblock_device,
755	.get_conn_list = mgmt_get_conn_list,
756	.read_local_version = mgmt_read_local_version,
757	.read_local_features = mgmt_read_local_features,
758	.read_local_ext_features = mgmt_read_local_ext_features,
759	.disconnect = mgmt_disconnect,
760	.remove_bonding = mgmt_remove_bonding,
761	.request_authentication = mgmt_request_authentication,
762	.pincode_reply = mgmt_pincode_reply,
763	.confirm_reply = mgmt_confirm_reply,
764	.passkey_reply = mgmt_passkey_reply,
765	.get_auth_info = mgmt_get_auth_info,
766	.read_scan_enable = mgmt_read_scan_enable,
767	.write_le_host = mgmt_write_le_host,
768	.get_remote_version = mgmt_get_remote_version,
769	.encrypt_link = mgmt_encrypt_link,
770};
771
772static int mgmt_init(void)
773{
774	return btd_register_adapter_ops(&mgmt_ops, TRUE);
775}
776
777static void mgmt_exit(void)
778{
779	btd_adapter_cleanup_ops(&mgmt_ops);
780}
781
782BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION,
783		BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit)
784