mgmtops.c revision 14655825c95fd065afc41bfc1c810987bfb1a2c6
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 "adapter.h"
45#include "manager.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 connectable;
64	gboolean discoverable;
65	gboolean pairable;
66	uint8_t sec_mode;
67} *controllers = NULL;
68
69static int mgmt_sock = -1;
70static guint mgmt_watch = 0;
71
72static uint8_t mgmt_version = 0;
73static uint16_t mgmt_revision = 0;
74
75static void read_version_complete(int sk, void *buf, size_t len)
76{
77	struct mgmt_hdr hdr;
78	struct mgmt_rp_read_version *rp = buf;
79
80	if (len < sizeof(*rp)) {
81		error("Too small read version complete event");
82		return;
83	}
84
85	mgmt_revision = btohs(bt_get_unaligned(&rp->revision));
86	mgmt_version = rp->version;
87
88	DBG("version %u revision %u", mgmt_version, mgmt_revision);
89
90	memset(&hdr, 0, sizeof(hdr));
91	hdr.opcode = MGMT_OP_READ_INDEX_LIST;
92	if (write(sk, &hdr, sizeof(hdr)) < 0)
93		error("Unable to read controller index list: %s (%d)",
94						strerror(errno), errno);
95}
96
97static void add_controller(uint16_t index)
98{
99	if (index > max_index) {
100		size_t size = sizeof(struct controller_info) * (index + 1);
101		max_index = index;
102		controllers = g_realloc(controllers, size);
103	}
104
105	memset(&controllers[index], 0, sizeof(struct controller_info));
106
107	controllers[index].valid = TRUE;
108
109	DBG("Added controller %u", index);
110}
111
112static void read_info(int sk, uint16_t index)
113{
114	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_read_info)];
115	struct mgmt_hdr *hdr = (void *) buf;
116	struct mgmt_cp_read_info *cp = (void *) &buf[sizeof(*hdr)];
117
118	memset(buf, 0, sizeof(buf));
119	hdr->opcode = MGMT_OP_READ_INFO;
120	hdr->len = htobs(sizeof(*cp));
121
122	cp->index = htobs(index);
123
124	if (write(sk, buf, sizeof(buf)) < 0)
125		error("Unable to send read_info command: %s (%d)",
126						strerror(errno), errno);
127}
128
129static void mgmt_index_added(int sk, void *buf, size_t len)
130{
131	struct mgmt_ev_index_added *ev = buf;
132	uint16_t index;
133
134	if (len < sizeof(*ev)) {
135		error("Too small index added event");
136		return;
137	}
138
139	index = btohs(bt_get_unaligned(&ev->index));
140
141	add_controller(index);
142	read_info(sk, index);
143}
144
145static void remove_controller(uint16_t index)
146{
147	if (index > max_index)
148		return;
149
150	if (!controllers[index].valid)
151		return;
152
153	btd_manager_unregister_adapter(index);
154
155	memset(&controllers[index], 0, sizeof(struct controller_info));
156
157	DBG("Removed controller %u", index);
158}
159
160static void mgmt_index_removed(int sk, void *buf, size_t len)
161{
162	struct mgmt_ev_index_removed *ev = buf;
163	uint16_t index;
164
165	if (len < sizeof(*ev)) {
166		error("Too small index removed event");
167		return;
168	}
169
170	index = btohs(bt_get_unaligned(&ev->index));
171
172	remove_controller(index);
173}
174
175static int mgmt_set_connectable(int index, gboolean connectable)
176{
177	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_connectable)];
178	struct mgmt_hdr *hdr = (void *) buf;
179	struct mgmt_cp_set_connectable *cp = (void *) &buf[sizeof(*hdr)];
180
181	DBG("index %d connectable %d", index, connectable);
182
183	memset(buf, 0, sizeof(buf));
184	hdr->opcode = MGMT_OP_SET_CONNECTABLE;
185	hdr->len = htobs(sizeof(*cp));
186
187	cp->index = htobs(index);
188	cp->connectable = connectable;
189
190	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
191		return -errno;
192
193	return 0;
194}
195
196static int mgmt_set_discoverable(int index, gboolean discoverable)
197{
198	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_discoverable)];
199	struct mgmt_hdr *hdr = (void *) buf;
200	struct mgmt_cp_set_discoverable *cp = (void *) &buf[sizeof(*hdr)];
201
202	DBG("index %d discoverable %d", index, discoverable);
203
204	memset(buf, 0, sizeof(buf));
205	hdr->opcode = MGMT_OP_SET_DISCOVERABLE;
206	hdr->len = htobs(sizeof(*cp));
207
208	cp->index = htobs(index);
209	cp->discoverable = discoverable;
210
211	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
212		return -errno;
213
214	return 0;
215}
216
217static int mgmt_set_pairable(int index, gboolean pairable)
218{
219	DBG("index %d pairable %d", index, pairable);
220	return -ENOSYS;
221}
222
223static int mgmt_update_mode(int index, uint8_t powered)
224{
225	struct controller_info *info;
226	struct btd_adapter *adapter;
227	gboolean pairable, discoverable;
228	uint8_t on_mode;
229
230	if (index > max_index) {
231		error("Unexpected index %u", index);
232		return -ENODEV;
233	}
234
235	info = &controllers[index];
236
237	info->enabled = powered;
238
239	adapter = manager_find_adapter(&info->bdaddr);
240	if (adapter == NULL) {
241		DBG("Adapter not found");
242		return -ENODEV;
243	}
244
245	if (!powered) {
246		info->connectable = FALSE;
247		info->pairable = FALSE;
248		info->discoverable = FALSE;
249
250		btd_adapter_stop(adapter);
251		return 0;
252	}
253
254	btd_adapter_start(adapter);
255
256	btd_adapter_get_mode(adapter, NULL, &on_mode, &pairable);
257
258	discoverable = (on_mode == MODE_DISCOVERABLE);
259
260	if (on_mode == MODE_DISCOVERABLE && !info->discoverable)
261		mgmt_set_discoverable(index, TRUE);
262	else if (on_mode == MODE_CONNECTABLE && !info->connectable)
263		mgmt_set_connectable(index, TRUE);
264	else {
265		uint8_t mode = 0;
266
267		if (info->connectable)
268			mode |= SCAN_PAGE;
269		if (info->discoverable)
270			mode |= SCAN_INQUIRY;
271
272		adapter_mode_changed(adapter, mode);
273	}
274
275	mgmt_set_pairable(index, pairable);
276
277	return 0;
278}
279
280static void mgmt_powered(int sk, void *buf, size_t len)
281{
282	struct mgmt_ev_powered *ev = buf;
283	uint16_t index;
284
285	if (len < sizeof(*ev)) {
286		error("Too small powered event");
287		return;
288	}
289
290	index = btohs(bt_get_unaligned(&ev->index));
291
292	DBG("Controller %u powered %u", index, ev->powered);
293
294	mgmt_update_mode(index, ev->powered);
295}
296
297static void mgmt_discoverable(int sk, void *buf, size_t len)
298{
299	struct mgmt_ev_discoverable *ev = buf;
300	struct controller_info *info;
301	struct btd_adapter *adapter;
302	uint16_t index;
303
304	if (len < sizeof(*ev)) {
305		error("Too small discoverable event");
306		return;
307	}
308
309	index = btohs(bt_get_unaligned(&ev->index));
310
311	DBG("Controller %u discoverable %u", index, ev->discoverable);
312
313	if (index > max_index) {
314		error("Unexpected index %u in discoverable event", index);
315		return;
316	}
317
318	info = &controllers[index];
319
320	info->discoverable = ev->discoverable ? TRUE : FALSE;
321
322	adapter = manager_find_adapter(&info->bdaddr);
323	if (adapter)
324		adapter_mode_changed(adapter, ev->discoverable ? 0x03 : 0x02);
325}
326
327static void mgmt_connectable(int sk, void *buf, size_t len)
328{
329	struct mgmt_ev_connectable *ev = buf;
330	struct controller_info *info;
331	struct btd_adapter *adapter;
332	uint16_t index;
333	uint8_t mode;
334
335	if (len < sizeof(*ev)) {
336		error("Too small connectable event");
337		return;
338	}
339
340	index = btohs(bt_get_unaligned(&ev->index));
341
342	DBG("Controller %u connectable %u", index, ev->connectable);
343
344	if (index > max_index) {
345		error("Unexpected index %u in connectable event", index);
346		return;
347	}
348
349	info = &controllers[index];
350
351	info->connectable = ev->connectable ? TRUE : FALSE;
352
353	adapter = manager_find_adapter(&info->bdaddr);
354	if (!adapter)
355		return;
356
357	if (info->discoverable)
358		mode = SCAN_INQUIRY;
359	else
360		mode = 0;
361
362	if (info->connectable)
363		mode |= SCAN_PAGE;
364
365	adapter_mode_changed(adapter, mode);
366}
367
368static void read_index_list_complete(int sk, void *buf, size_t len)
369{
370	struct mgmt_rp_read_index_list *rp = buf;
371	uint16_t num;
372	int i;
373
374	if (len < sizeof(*rp)) {
375		error("Too small read index list complete event");
376		return;
377	}
378
379	num = btohs(bt_get_unaligned(&rp->num_controllers));
380
381	if (num * sizeof(uint16_t) + sizeof(*rp) != len) {
382		error("Incorrect packet size for index list event");
383		return;
384	}
385
386	for (i = 0; i < num; i++) {
387		uint16_t index;
388
389		index = btohs(bt_get_unaligned(&rp->index[i]));
390
391		add_controller(index);
392		read_info(sk, index);
393	}
394}
395
396static int mgmt_set_powered(int index, gboolean powered)
397{
398	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_powered)];
399	struct mgmt_hdr *hdr = (void *) buf;
400	struct mgmt_cp_set_powered *cp = (void *) &buf[sizeof(*hdr)];
401
402	DBG("index %d powered %d", index, powered);
403
404	memset(buf, 0, sizeof(buf));
405	hdr->opcode = MGMT_OP_SET_POWERED;
406	hdr->len = htobs(sizeof(*cp));
407
408	cp->index = htobs(index);
409	cp->powered = powered;
410
411	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
412		return -errno;
413
414	return 0;
415}
416
417static void read_info_complete(int sk, void *buf, size_t len)
418{
419	struct mgmt_rp_read_info *rp = buf;
420	struct controller_info *info;
421	struct btd_adapter *adapter;
422	uint8_t mode;
423	uint16_t index;
424	char addr[18];
425
426	if (len < sizeof(*rp)) {
427		error("Too small read info complete event");
428		return;
429	}
430
431	index = btohs(bt_get_unaligned(&rp->index));
432	if (index > max_index) {
433		error("Unexpected index %u in read info complete", index);
434		return;
435	}
436
437	info = &controllers[index];
438	info->type = rp->type;
439	info->enabled = rp->powered;
440	info->connectable = rp->connectable;
441	info->discoverable = rp->discoverable;
442	info->pairable = rp->pairable;
443	info->sec_mode = rp->sec_mode;
444	bacpy(&info->bdaddr, &rp->bdaddr);
445	memcpy(info->dev_class, rp->dev_class, 3);
446	memcpy(info->features, rp->features, 8);
447	info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
448	info->hci_ver = rp->hci_ver;
449	info->hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
450
451	ba2str(&info->bdaddr, addr);
452	DBG("hci%u type %u addr %s", index, info->type, addr);
453	DBG("hci%u class 0x%02x%02x%02x", index,
454		info->dev_class[2], info->dev_class[1], info->dev_class[0]);
455	DBG("hci%u manufacturer %d HCI ver %d:%d", index, info->manufacturer,
456						info->hci_ver, info->hci_rev);
457	DBG("hci%u enabled %u discoverable %u pairable %u sec_mode %u", index,
458					info->enabled, info->discoverable,
459					info->pairable, info->sec_mode);
460
461	adapter = btd_manager_register_adapter(index);
462	if (adapter == NULL) {
463		error("mgmtops: unable to register adapter");
464		return;
465	}
466
467	btd_adapter_get_mode(adapter, &mode, NULL, NULL);
468	if (mode == MODE_OFF) {
469		mgmt_set_powered(index, FALSE);
470		return;
471	}
472
473	if (info->enabled)
474		mgmt_update_mode(index, TRUE);
475	else
476		mgmt_set_powered(index, TRUE);
477
478	btd_adapter_unref(adapter);
479}
480
481static void set_powered_complete(int sk, void *buf, size_t len)
482{
483	struct mgmt_rp_set_powered *rp = buf;
484	uint16_t index;
485
486	if (len < sizeof(*rp)) {
487		error("Too small set powered complete event");
488		return;
489	}
490
491	index = btohs(bt_get_unaligned(&rp->index));
492
493	DBG("hci%d powered %u", index, rp->powered);
494
495	mgmt_update_mode(index, rp->powered);
496}
497
498static void set_discoverable_complete(int sk, void *buf, size_t len)
499{
500	struct mgmt_rp_set_discoverable *rp = buf;
501	struct controller_info *info;
502	struct btd_adapter *adapter;
503	uint16_t index;
504
505	if (len < sizeof(*rp)) {
506		error("Too small set discoverable complete event");
507		return;
508	}
509
510	index = btohs(bt_get_unaligned(&rp->index));
511
512	DBG("hci%d discoverable %u", index, rp->discoverable);
513
514	if (index > max_index) {
515		error("Unexpected index %u in discoverable complete", index);
516		return;
517	}
518
519	info = &controllers[index];
520
521	info->discoverable = rp->discoverable ? TRUE : FALSE;
522
523	adapter = manager_find_adapter(&info->bdaddr);
524	if (adapter)
525		adapter_mode_changed(adapter, rp->discoverable ? 0x03 : 0x02);
526}
527
528static void set_connectable_complete(int sk, void *buf, size_t len)
529{
530	struct mgmt_rp_set_connectable *rp = buf;
531	struct controller_info *info;
532	struct btd_adapter *adapter;
533	uint16_t index;
534
535	if (len < sizeof(*rp)) {
536		error("Too small set connectable complete event");
537		return;
538	}
539
540	index = btohs(bt_get_unaligned(&rp->index));
541
542	DBG("hci%d connectable %u", index, rp->connectable);
543
544	if (index > max_index) {
545		error("Unexpected index %u in connectable complete", index);
546		return;
547	}
548
549	info = &controllers[index];
550
551	info->connectable = rp->connectable ? TRUE : FALSE;
552
553	adapter = manager_find_adapter(&info->bdaddr);
554	if (adapter)
555		adapter_mode_changed(adapter, rp->connectable ? SCAN_PAGE : 0);
556}
557
558static void mgmt_cmd_complete(int sk, void *buf, size_t len)
559{
560	struct mgmt_ev_cmd_complete *ev = buf;
561	uint16_t opcode;
562
563	DBG("");
564
565	if (len < sizeof(*ev)) {
566		error("Too small management command complete event packet");
567		return;
568	}
569
570	opcode = btohs(bt_get_unaligned(&ev->opcode));
571
572	switch (opcode) {
573	case MGMT_OP_READ_VERSION:
574		read_version_complete(sk, ev->data, len - sizeof(*ev));
575		break;
576	case MGMT_OP_READ_INDEX_LIST:
577		read_index_list_complete(sk, ev->data, len - sizeof(*ev));
578		break;
579	case MGMT_OP_READ_INFO:
580		read_info_complete(sk, ev->data, len - sizeof(*ev));
581		break;
582	case MGMT_OP_SET_POWERED:
583		set_powered_complete(sk, ev->data, len - sizeof(*ev));
584		break;
585	case MGMT_OP_SET_DISCOVERABLE:
586		set_discoverable_complete(sk, ev->data, len - sizeof(*ev));
587		break;
588	case MGMT_OP_SET_CONNECTABLE:
589		set_connectable_complete(sk, ev->data, len - sizeof(*ev));
590		break;
591	default:
592		error("Unknown command complete for opcode %u", opcode);
593		break;
594	}
595}
596
597static void mgmt_cmd_status(int sk, void *buf, size_t len)
598{
599	struct mgmt_ev_cmd_status *ev = buf;
600	uint16_t opcode;
601
602	if (len < sizeof(*ev)) {
603		error("Too small management command status event packet");
604		return;
605	}
606
607	opcode = btohs(bt_get_unaligned(&ev->opcode));
608
609	DBG("status %u opcode %u", ev->status, opcode);
610}
611
612static void mgmt_controller_error(int sk, void *buf, size_t len)
613{
614	struct mgmt_ev_controller_error *ev = buf;
615	uint16_t index;
616
617	if (len < sizeof(*ev)) {
618		error("Too small management controller error event packet");
619		return;
620	}
621
622	index = btohs(bt_get_unaligned(&ev->index));
623
624	DBG("index %u error_code %u", index, ev->error_code);
625}
626
627static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data)
628{
629	char buf[MGMT_BUF_SIZE];
630	struct mgmt_hdr *hdr = (void *) buf;
631	int sk;
632	ssize_t ret;
633	uint16_t len, opcode;
634
635	DBG("cond %d", cond);
636
637	if (cond & G_IO_NVAL)
638		return FALSE;
639
640	sk = g_io_channel_unix_get_fd(io);
641
642	if (cond & (G_IO_ERR | G_IO_HUP)) {
643		error("Error on management socket");
644		return FALSE;
645	}
646
647	ret = read(sk, buf, sizeof(buf));
648	if (ret < 0) {
649		error("Unable to read from management socket: %s (%d)",
650						strerror(errno), errno);
651		return TRUE;
652	}
653
654	DBG("Received %zd bytes from management socket", ret);
655
656	if (ret < MGMT_HDR_SIZE) {
657		error("Too small Management packet");
658		return TRUE;
659	}
660
661	opcode = btohs(bt_get_unaligned(&hdr->opcode));
662	len = btohs(bt_get_unaligned(&hdr->len));
663
664	if (ret != MGMT_HDR_SIZE + len) {
665		error("Packet length mismatch. ret %zd len %u", ret, len);
666		return TRUE;
667	}
668
669	switch (opcode) {
670	case MGMT_EV_CMD_COMPLETE:
671		mgmt_cmd_complete(sk, buf + MGMT_HDR_SIZE, len);
672		break;
673	case MGMT_EV_CMD_STATUS:
674		mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len);
675		break;
676	case MGMT_EV_CONTROLLER_ERROR:
677		mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len);
678		break;
679	case MGMT_EV_INDEX_ADDED:
680		mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len);
681		break;
682	case MGMT_EV_INDEX_REMOVED:
683		mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len);
684		break;
685	case MGMT_EV_POWERED:
686		mgmt_powered(sk, buf + MGMT_HDR_SIZE, len);
687		break;
688	case MGMT_EV_DISCOVERABLE:
689		mgmt_discoverable(sk, buf + MGMT_HDR_SIZE, len);
690		break;
691	case MGMT_EV_CONNECTABLE:
692		mgmt_connectable(sk, buf + MGMT_HDR_SIZE, len);
693		break;
694	default:
695		error("Unknown Management opcode %u", opcode);
696		break;
697	}
698
699	return TRUE;
700}
701
702static int mgmt_setup(void)
703{
704	struct mgmt_hdr hdr;
705	struct sockaddr_hci addr;
706	GIOChannel *io;
707	GIOCondition condition;
708	int dd, err;
709
710	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
711	if (dd < 0)
712		return -errno;
713
714	memset(&addr, 0, sizeof(addr));
715	addr.hci_family = AF_BLUETOOTH;
716	addr.hci_dev = HCI_DEV_NONE;
717	addr.hci_channel = HCI_CHANNEL_CONTROL;
718
719	if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
720		err = -errno;
721		goto fail;
722	}
723
724	memset(&hdr, 0, sizeof(hdr));
725	hdr.opcode = MGMT_OP_READ_VERSION;
726	if (write(dd, &hdr, sizeof(hdr)) < 0) {
727		err = -errno;
728		goto fail;
729	}
730
731	io = g_io_channel_unix_new(dd);
732	condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
733	mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL);
734	g_io_channel_unref(io);
735
736	mgmt_sock = dd;
737
738	info("Bluetooth Management interface initialized");
739
740	return 0;
741
742fail:
743	close(dd);
744	return err;
745}
746
747static void mgmt_cleanup(void)
748{
749	g_free(controllers);
750	controllers = NULL;
751	max_index = -1;
752
753	if (mgmt_sock >= 0) {
754		close(mgmt_sock);
755		mgmt_sock = -1;
756	}
757
758	if (mgmt_watch > 0) {
759		g_source_remove(mgmt_watch);
760		mgmt_watch = 0;
761	}
762}
763
764static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor)
765{
766	DBG("index %d major %u minor %u", index, major, minor);
767	return -ENOSYS;
768}
769
770static int mgmt_set_limited_discoverable(int index, gboolean limited)
771{
772	DBG("index %d limited %d", index, limited);
773	return -ENOSYS;
774}
775
776static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic)
777{
778	DBG("index %d length %u periodic %d", index, length, periodic);
779	return -ENOSYS;
780}
781
782static int mgmt_stop_inquiry(int index)
783{
784	DBG("index %d", index);
785	return -ENOSYS;
786}
787
788static int mgmt_start_scanning(int index)
789{
790	DBG("index %d", index);
791	return -ENOSYS;
792}
793
794static int mgmt_stop_scanning(int index)
795{
796	DBG("index %d", index);
797	return -ENOSYS;
798}
799
800static int mgmt_resolve_name(int index, bdaddr_t *bdaddr)
801{
802	char addr[18];
803
804	ba2str(bdaddr, addr);
805	DBG("index %d addr %s", index, addr);
806
807	return -ENOSYS;
808}
809
810static int mgmt_set_name(int index, const char *name)
811{
812	DBG("index %d, name %s", index, name);
813	return -ENOSYS;
814}
815
816static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr)
817{
818	char addr[18];
819
820	ba2str(bdaddr, addr);
821	DBG("index %d addr %s", index, addr);
822
823	return -ENOSYS;
824}
825
826static int mgmt_fast_connectable(int index, gboolean enable)
827{
828	DBG("index %d enable %d", index, enable);
829	return -ENOSYS;
830}
831
832static int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout,
833					uint32_t *clock, uint16_t *accuracy)
834{
835	char addr[18];
836
837	ba2str(bdaddr, addr);
838	DBG("index %d addr %s which %d timeout %d", index, addr, which,
839								timeout);
840
841	return -ENOSYS;
842}
843
844static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr)
845{
846	char addr[18];
847	struct controller_info *info = &controllers[index];
848
849	ba2str(&info->bdaddr, addr);
850	DBG("index %d addr %s", index, addr);
851
852	if (!info->valid)
853		return -ENODEV;
854
855	bacpy(bdaddr, &info->bdaddr);
856
857	return 0;
858}
859
860static int mgmt_block_device(int index, bdaddr_t *bdaddr)
861{
862	char addr[18];
863
864	ba2str(bdaddr, addr);
865	DBG("index %d addr %s", index, addr);
866
867	return -ENOSYS;
868}
869
870static int mgmt_unblock_device(int index, bdaddr_t *bdaddr)
871{
872	char addr[18];
873
874	ba2str(bdaddr, addr);
875	DBG("index %d addr %s", index, addr);
876
877	return -ENOSYS;
878}
879
880static int mgmt_get_conn_list(int index, GSList **conns)
881{
882	DBG("index %d", index);
883	return -ENOSYS;
884}
885
886static int mgmt_read_local_version(int index, struct hci_version *ver)
887{
888	struct controller_info *info = &controllers[index];
889
890	DBG("index %d", index);
891
892	if (!info->valid)
893		return -ENODEV;
894
895	memset(ver, 0, sizeof(*ver));
896	ver->manufacturer = info->manufacturer;
897	ver->hci_ver = info->hci_ver;
898	ver->hci_rev = info->hci_rev;
899
900	return 0;
901}
902
903static int mgmt_read_local_features(int index, uint8_t *features)
904{
905	struct controller_info *info = &controllers[index];
906
907	DBG("index %d", index);
908
909	if (!info->valid)
910		return -ENODEV;
911
912	memcpy(features, info->features, 8);
913
914	return 0;
915}
916
917static int mgmt_disconnect(int index, uint16_t handle)
918{
919	DBG("index %d handle %u", index, handle);
920	return -ENOSYS;
921}
922
923static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
924{
925	char addr[18];
926
927	ba2str(bdaddr, addr);
928	DBG("index %d addr %s", index, addr);
929
930	return -ENOSYS;
931}
932
933static int mgmt_request_authentication(int index, uint16_t handle)
934{
935	DBG("index %d handle %u", index, handle);
936	return -ENOSYS;
937}
938
939static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
940{
941	char addr[18];
942
943	ba2str(bdaddr, addr);
944	DBG("index %d addr %s pin %s", index, addr, pin);
945
946	return -ENOSYS;
947}
948
949static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
950{
951	char addr[18];
952
953	ba2str(bdaddr, addr);
954	DBG("index %d addr %s success %d", index, addr, success);
955
956	return -ENOSYS;
957}
958
959static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
960{
961	char addr[18];
962
963	ba2str(bdaddr, addr);
964	DBG("index %d addr %s passkey %06u", index, addr, passkey);
965
966	return -ENOSYS;
967}
968
969static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth)
970{
971	char addr[18];
972
973	ba2str(bdaddr, addr);
974	DBG("index %d addr %s", index, addr);
975
976	return -ENOSYS;
977}
978
979static int mgmt_read_scan_enable(int index)
980{
981	DBG("index %d", index);
982	return -ENOSYS;
983}
984
985static int mgmt_enable_le(int index)
986{
987	DBG("index %d", index);
988	return -ENOSYS;
989}
990
991static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
992							gpointer user_data)
993{
994	char addr[18];
995
996	ba2str(dst, addr);
997	DBG("index %d addr %s", index, addr);
998
999	return -ENOSYS;
1000}
1001
1002static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
1003							uint16_t version)
1004{
1005	DBG("index %d vendor %u product %u version %u",
1006					index, vendor, product, version);
1007	return -ENOSYS;
1008}
1009
1010static int mgmt_services_updated(int index)
1011{
1012	DBG("index %d", index);
1013	return -ENOSYS;
1014}
1015
1016static int mgmt_disable_cod_cache(int index)
1017{
1018	DBG("index %d", index);
1019	return -ENOSYS;
1020}
1021
1022static int mgmt_restore_powered(int index)
1023{
1024	DBG("index %d", index);
1025	return -ENOSYS;
1026}
1027
1028static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys)
1029{
1030	DBG("index %d keys %d debug_keys %d", index, g_slist_length(keys),
1031								debug_keys);
1032	return -ENOSYS;
1033}
1034
1035static struct btd_adapter_ops mgmt_ops = {
1036	.setup = mgmt_setup,
1037	.cleanup = mgmt_cleanup,
1038	.set_powered = mgmt_set_powered,
1039	.set_discoverable = mgmt_set_discoverable,
1040	.set_pairable = mgmt_set_pairable,
1041	.set_limited_discoverable = mgmt_set_limited_discoverable,
1042	.start_inquiry = mgmt_start_inquiry,
1043	.stop_inquiry = mgmt_stop_inquiry,
1044	.start_scanning = mgmt_start_scanning,
1045	.stop_scanning = mgmt_stop_scanning,
1046	.resolve_name = mgmt_resolve_name,
1047	.cancel_resolve_name = mgmt_cancel_resolve_name,
1048	.set_name = mgmt_set_name,
1049	.set_dev_class = mgmt_set_dev_class,
1050	.set_fast_connectable = mgmt_fast_connectable,
1051	.read_clock = mgmt_read_clock,
1052	.read_bdaddr = mgmt_read_bdaddr,
1053	.block_device = mgmt_block_device,
1054	.unblock_device = mgmt_unblock_device,
1055	.get_conn_list = mgmt_get_conn_list,
1056	.read_local_version = mgmt_read_local_version,
1057	.read_local_features = mgmt_read_local_features,
1058	.disconnect = mgmt_disconnect,
1059	.remove_bonding = mgmt_remove_bonding,
1060	.request_authentication = mgmt_request_authentication,
1061	.pincode_reply = mgmt_pincode_reply,
1062	.confirm_reply = mgmt_confirm_reply,
1063	.passkey_reply = mgmt_passkey_reply,
1064	.get_auth_info = mgmt_get_auth_info,
1065	.read_scan_enable = mgmt_read_scan_enable,
1066	.enable_le = mgmt_enable_le,
1067	.encrypt_link = mgmt_encrypt_link,
1068	.set_did = mgmt_set_did,
1069	.services_updated = mgmt_services_updated,
1070	.disable_cod_cache = mgmt_disable_cod_cache,
1071	.restore_powered = mgmt_restore_powered,
1072	.load_keys = mgmt_load_keys,
1073};
1074
1075static int mgmt_init(void)
1076{
1077	return btd_register_adapter_ops(&mgmt_ops, TRUE);
1078}
1079
1080static void mgmt_exit(void)
1081{
1082	btd_adapter_cleanup_ops(&mgmt_ops);
1083}
1084
1085BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION,
1086		BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit)
1087