mgmtops.c revision b18b51e97bddc67c8b4ff10a3f97241ac480596a
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/sdp.h>
41#include <bluetooth/sdp_lib.h>
42#include <bluetooth/mgmt.h>
43
44#include "plugin.h"
45#include "log.h"
46#include "adapter.h"
47#include "manager.h"
48#include "device.h"
49#include "event.h"
50
51#define MGMT_BUF_SIZE 1024
52
53static int max_index = -1;
54static struct controller_info {
55	gboolean valid;
56	gboolean notified;
57	uint8_t type;
58	bdaddr_t bdaddr;
59	uint8_t features[8];
60	uint8_t dev_class[3];
61	uint16_t manufacturer;
62	uint8_t hci_ver;
63	uint16_t hci_rev;
64	gboolean enabled;
65	gboolean connectable;
66	gboolean discoverable;
67	gboolean pairable;
68	uint8_t sec_mode;
69	GSList *connections;
70} *controllers = NULL;
71
72static int mgmt_sock = -1;
73static guint mgmt_watch = 0;
74
75static uint8_t mgmt_version = 0;
76static uint16_t mgmt_revision = 0;
77
78static void read_version_complete(int sk, void *buf, size_t len)
79{
80	struct mgmt_hdr hdr;
81	struct mgmt_rp_read_version *rp = buf;
82
83	if (len < sizeof(*rp)) {
84		error("Too small read version complete event");
85		return;
86	}
87
88	mgmt_revision = btohs(bt_get_unaligned(&rp->revision));
89	mgmt_version = rp->version;
90
91	DBG("version %u revision %u", mgmt_version, mgmt_revision);
92
93	memset(&hdr, 0, sizeof(hdr));
94	hdr.opcode = htobs(MGMT_OP_READ_INDEX_LIST);
95	if (write(sk, &hdr, sizeof(hdr)) < 0)
96		error("Unable to read controller index list: %s (%d)",
97						strerror(errno), errno);
98}
99
100static void add_controller(uint16_t index)
101{
102	if (index > max_index) {
103		size_t size = sizeof(struct controller_info) * (index + 1);
104		max_index = index;
105		controllers = g_realloc(controllers, size);
106	}
107
108	memset(&controllers[index], 0, sizeof(struct controller_info));
109
110	controllers[index].valid = TRUE;
111
112	DBG("Added controller %u", index);
113}
114
115static void read_info(int sk, uint16_t index)
116{
117	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_read_info)];
118	struct mgmt_hdr *hdr = (void *) buf;
119	struct mgmt_cp_read_info *cp = (void *) &buf[sizeof(*hdr)];
120
121	memset(buf, 0, sizeof(buf));
122	hdr->opcode = htobs(MGMT_OP_READ_INFO);
123	hdr->len = htobs(sizeof(*cp));
124
125	cp->index = htobs(index);
126
127	if (write(sk, buf, sizeof(buf)) < 0)
128		error("Unable to send read_info command: %s (%d)",
129						strerror(errno), errno);
130}
131
132static void get_connections(int sk, uint16_t index)
133{
134	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_get_connections)];
135	struct mgmt_hdr *hdr = (void *) buf;
136	struct mgmt_cp_get_connections *cp = (void *) &buf[sizeof(*hdr)];
137
138	memset(buf, 0, sizeof(buf));
139	hdr->opcode = htobs(MGMT_OP_GET_CONNECTIONS);
140	hdr->len = htobs(sizeof(*cp));
141
142	cp->index = htobs(index);
143
144	if (write(sk, buf, sizeof(buf)) < 0)
145		error("Unable to send get_connections command: %s (%d)",
146						strerror(errno), errno);
147}
148
149static void mgmt_index_added(int sk, void *buf, size_t len)
150{
151	struct mgmt_ev_index_added *ev = buf;
152	uint16_t index;
153
154	if (len < sizeof(*ev)) {
155		error("Too small index added event");
156		return;
157	}
158
159	index = btohs(bt_get_unaligned(&ev->index));
160
161	add_controller(index);
162	read_info(sk, index);
163}
164
165static void remove_controller(uint16_t index)
166{
167	if (index > max_index)
168		return;
169
170	if (!controllers[index].valid)
171		return;
172
173	btd_manager_unregister_adapter(index);
174
175	memset(&controllers[index], 0, sizeof(struct controller_info));
176
177	DBG("Removed controller %u", index);
178}
179
180static void mgmt_index_removed(int sk, void *buf, size_t len)
181{
182	struct mgmt_ev_index_removed *ev = buf;
183	uint16_t index;
184
185	if (len < sizeof(*ev)) {
186		error("Too small index removed event");
187		return;
188	}
189
190	index = btohs(bt_get_unaligned(&ev->index));
191
192	remove_controller(index);
193}
194
195static int mgmt_set_mode(int index, uint16_t opcode, uint8_t val)
196{
197	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_mode)];
198	struct mgmt_hdr *hdr = (void *) buf;
199	struct mgmt_mode *cp = (void *) &buf[sizeof(*hdr)];
200
201	memset(buf, 0, sizeof(buf));
202	hdr->opcode = htobs(opcode);
203	hdr->len = htobs(sizeof(*cp));
204
205	cp->index = htobs(index);
206	cp->val = val;
207
208	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
209		return -errno;
210
211	return 0;
212}
213
214static int mgmt_set_connectable(int index, gboolean connectable)
215{
216	DBG("index %d connectable %d", index, connectable);
217	return mgmt_set_mode(index, MGMT_OP_SET_CONNECTABLE, connectable);
218}
219
220static int mgmt_set_discoverable(int index, gboolean discoverable)
221{
222	DBG("index %d discoverable %d", index, discoverable);
223	return mgmt_set_mode(index, MGMT_OP_SET_DISCOVERABLE, discoverable);
224}
225
226static int mgmt_set_pairable(int index, gboolean pairable)
227{
228	DBG("index %d pairable %d", index, pairable);
229	return mgmt_set_mode(index, MGMT_OP_SET_PAIRABLE, pairable);
230}
231
232static int mgmt_update_powered(int index, uint8_t powered)
233{
234	struct controller_info *info;
235	struct btd_adapter *adapter;
236	gboolean pairable, discoverable;
237	uint8_t on_mode;
238
239	if (index > max_index) {
240		error("Unexpected index %u", index);
241		return -ENODEV;
242	}
243
244	info = &controllers[index];
245
246	info->enabled = powered;
247
248	adapter = manager_find_adapter(&info->bdaddr);
249	if (adapter == NULL) {
250		DBG("Adapter not found");
251		return -ENODEV;
252	}
253
254	if (!powered) {
255		info->connectable = FALSE;
256		info->pairable = FALSE;
257		info->discoverable = FALSE;
258
259		btd_adapter_stop(adapter);
260		return 0;
261	}
262
263	btd_adapter_start(adapter);
264
265	btd_adapter_get_mode(adapter, NULL, &on_mode, &pairable);
266
267	discoverable = (on_mode == MODE_DISCOVERABLE);
268
269	if (on_mode == MODE_DISCOVERABLE && !info->discoverable)
270		mgmt_set_discoverable(index, TRUE);
271	else if (on_mode == MODE_CONNECTABLE && !info->connectable)
272		mgmt_set_connectable(index, TRUE);
273	else {
274		uint8_t mode = 0;
275
276		if (info->connectable)
277			mode |= SCAN_PAGE;
278		if (info->discoverable)
279			mode |= SCAN_INQUIRY;
280
281		adapter_mode_changed(adapter, mode);
282	}
283
284	if (info->pairable != pairable)
285		mgmt_set_pairable(index, pairable);
286
287	return 0;
288}
289
290static void mgmt_powered(int sk, void *buf, size_t len)
291{
292	struct mgmt_mode *ev = buf;
293	uint16_t index;
294
295	if (len < sizeof(*ev)) {
296		error("Too small powered event");
297		return;
298	}
299
300	index = btohs(bt_get_unaligned(&ev->index));
301
302	DBG("Controller %u powered %u", index, ev->val);
303
304	mgmt_update_powered(index, ev->val);
305}
306
307static void mgmt_discoverable(int sk, void *buf, size_t len)
308{
309	struct mgmt_mode *ev = buf;
310	struct controller_info *info;
311	struct btd_adapter *adapter;
312	uint16_t index;
313	uint8_t mode;
314
315	if (len < sizeof(*ev)) {
316		error("Too small discoverable event");
317		return;
318	}
319
320	index = btohs(bt_get_unaligned(&ev->index));
321
322	DBG("Controller %u discoverable %u", index, ev->val);
323
324	if (index > max_index) {
325		error("Unexpected index %u in discoverable event", index);
326		return;
327	}
328
329	info = &controllers[index];
330
331	info->discoverable = ev->val ? TRUE : FALSE;
332
333	adapter = manager_find_adapter(&info->bdaddr);
334	if (!adapter)
335		return;
336
337	if (info->connectable)
338		mode = SCAN_PAGE;
339	else
340		mode = 0;
341
342	if (info->discoverable)
343		mode |= SCAN_INQUIRY;
344
345	adapter_mode_changed(adapter, mode);
346}
347
348static void mgmt_connectable(int sk, void *buf, size_t len)
349{
350	struct mgmt_mode *ev = buf;
351	struct controller_info *info;
352	struct btd_adapter *adapter;
353	uint16_t index;
354	uint8_t mode;
355
356	if (len < sizeof(*ev)) {
357		error("Too small connectable event");
358		return;
359	}
360
361	index = btohs(bt_get_unaligned(&ev->index));
362
363	DBG("Controller %u connectable %u", index, ev->val);
364
365	if (index > max_index) {
366		error("Unexpected index %u in connectable event", index);
367		return;
368	}
369
370	info = &controllers[index];
371
372	info->connectable = ev->val ? TRUE : FALSE;
373
374	adapter = manager_find_adapter(&info->bdaddr);
375	if (!adapter)
376		return;
377
378	if (info->discoverable)
379		mode = SCAN_INQUIRY;
380	else
381		mode = 0;
382
383	if (info->connectable)
384		mode |= SCAN_PAGE;
385
386	adapter_mode_changed(adapter, mode);
387}
388
389static void mgmt_pairable(int sk, void *buf, size_t len)
390{
391	struct mgmt_mode *ev = buf;
392	struct controller_info *info;
393	struct btd_adapter *adapter;
394	uint16_t index;
395
396	if (len < sizeof(*ev)) {
397		error("Too small pairable event");
398		return;
399	}
400
401	index = btohs(bt_get_unaligned(&ev->index));
402
403	DBG("Controller %u pairable %u", index, ev->val);
404
405	if (index > max_index) {
406		error("Unexpected index %u in pairable event", index);
407		return;
408	}
409
410	info = &controllers[index];
411
412	info->pairable = ev->val ? TRUE : FALSE;
413
414	adapter = manager_find_adapter(&info->bdaddr);
415	if (!adapter)
416		return;
417
418	btd_adapter_pairable_changed(adapter, info->pairable);
419}
420
421static void mgmt_new_key(int sk, void *buf, size_t len)
422{
423	struct mgmt_ev_new_key *ev = buf;
424	struct controller_info *info;
425	uint16_t index;
426
427	if (len != sizeof(*ev)) {
428		error("new_key event size mismatch (%zu != %zu)",
429							len, sizeof(*ev));
430		return;
431	}
432
433	index = btohs(bt_get_unaligned(&ev->index));
434
435	DBG("Controller %u new key of type %u pin_len %u", index,
436					ev->key.type, ev->key.pin_len);
437
438	if (index > max_index) {
439		error("Unexpected index %u in new_key event", index);
440		return;
441	}
442
443	if (ev->key.pin_len > 16) {
444		error("Invalid PIN length (%u) in new_key event",
445							ev->key.pin_len);
446		return;
447	}
448
449	info = &controllers[index];
450
451	btd_event_link_key_notify(&info->bdaddr, &ev->key.bdaddr,
452					ev->key.val, ev->key.type,
453					ev->key.pin_len);
454}
455
456static void mgmt_device_connected(int sk, void *buf, size_t len)
457{
458	struct mgmt_ev_device_connected *ev = buf;
459	struct controller_info *info;
460	uint16_t index;
461	char addr[18];
462
463	if (len < sizeof(*ev)) {
464		error("Too small device_connected event");
465		return;
466	}
467
468	index = btohs(bt_get_unaligned(&ev->index));
469	ba2str(&ev->bdaddr, addr);
470
471	DBG("hci%u device %s connected", index, addr);
472
473	if (index > max_index) {
474		error("Unexpected index %u in device_connected event", index);
475		return;
476	}
477
478	info = &controllers[index];
479
480	btd_event_conn_complete(&info->bdaddr, &ev->bdaddr);
481}
482
483static void mgmt_device_disconnected(int sk, void *buf, size_t len)
484{
485	struct mgmt_ev_device_disconnected *ev = buf;
486	struct controller_info *info;
487	uint16_t index;
488	char addr[18];
489
490	if (len < sizeof(*ev)) {
491		error("Too small device_disconnected event");
492		return;
493	}
494
495	index = btohs(bt_get_unaligned(&ev->index));
496	ba2str(&ev->bdaddr, addr);
497
498	DBG("hci%u device %s disconnected", index, addr);
499
500	if (index > max_index) {
501		error("Unexpected index %u in device_disconnected event", index);
502		return;
503	}
504
505	info = &controllers[index];
506
507	btd_event_disconn_complete(&info->bdaddr, &ev->bdaddr);
508}
509
510static void mgmt_connect_failed(int sk, void *buf, size_t len)
511{
512	struct mgmt_ev_connect_failed *ev = buf;
513	struct controller_info *info;
514	uint16_t index;
515	char addr[18];
516
517	if (len < sizeof(*ev)) {
518		error("Too small connect_failed event");
519		return;
520	}
521
522	index = btohs(bt_get_unaligned(&ev->index));
523	ba2str(&ev->bdaddr, addr);
524
525	DBG("hci%u %s status %u", index, addr, ev->status);
526
527	if (index > max_index) {
528		error("Unexpected index %u in connect_failed event", index);
529		return;
530	}
531
532	info = &controllers[index];
533
534	btd_event_conn_failed(&info->bdaddr, &ev->bdaddr, ev->status);
535}
536
537static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
538{
539	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_pin_code_reply)];
540	struct mgmt_hdr *hdr = (void *) buf;
541	size_t buf_len;
542	char addr[18];
543
544	ba2str(bdaddr, addr);
545	DBG("index %d addr %s pin %s", index, addr, pin ? pin : "<none>");
546
547	memset(buf, 0, sizeof(buf));
548
549	if (pin == NULL) {
550		struct mgmt_cp_pin_code_neg_reply *cp;
551
552		hdr->opcode = htobs(MGMT_OP_PIN_CODE_NEG_REPLY);
553		hdr->len = htobs(sizeof(*cp));
554
555		cp = (void *) &buf[sizeof(*hdr)];
556		cp->index = htobs(index);
557		bacpy(&cp->bdaddr, bdaddr);
558
559		buf_len = sizeof(*hdr) + sizeof(*cp);
560	} else {
561		struct mgmt_cp_pin_code_reply *cp;
562		size_t pin_len;
563
564		pin_len = strlen(pin);
565		if (pin_len > 16)
566			return -EINVAL;
567
568		hdr->opcode = htobs(MGMT_OP_PIN_CODE_REPLY);
569		hdr->len = htobs(sizeof(*cp));
570
571		cp = (void *) &buf[sizeof(*hdr)];
572		cp->index = htobs(index);
573		bacpy(&cp->bdaddr, bdaddr);
574		cp->pin_len = pin_len;
575		memcpy(cp->pin_code, pin, pin_len);
576
577		buf_len = sizeof(*hdr) + sizeof(*cp);
578	}
579
580	if (write(mgmt_sock, buf, buf_len) < 0)
581		return -errno;
582
583	return 0;
584}
585
586static void mgmt_pin_code_request(int sk, void *buf, size_t len)
587{
588	struct mgmt_ev_pin_code_request *ev = buf;
589	struct controller_info *info;
590	uint16_t index;
591	char addr[18];
592	int err;
593
594	if (len < sizeof(*ev)) {
595		error("Too small pin_code_request event");
596		return;
597	}
598
599	index = btohs(bt_get_unaligned(&ev->index));
600	ba2str(&ev->bdaddr, addr);
601
602	DBG("hci%u %s", index, addr);
603
604	if (index > max_index) {
605		error("Unexpected index %u in pin_code_request event", index);
606		return;
607	}
608
609	info = &controllers[index];
610
611	err = btd_event_request_pin(&info->bdaddr, &ev->bdaddr);
612	if (err < 0) {
613		error("btd_event_request_pin: %s", strerror(-err));
614		mgmt_pincode_reply(index, &ev->bdaddr, NULL);
615	}
616}
617
618static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
619{
620	if (uuid->type == SDP_UUID16)
621		sdp_uuid16_to_uuid128(uuid128, uuid);
622	else if (uuid->type == SDP_UUID32)
623		sdp_uuid32_to_uuid128(uuid128, uuid);
624	else
625		memcpy(uuid128, uuid, sizeof(*uuid));
626}
627
628static int mgmt_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
629{
630	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_add_uuid)];
631	struct mgmt_hdr *hdr = (void *) buf;
632	struct mgmt_cp_add_uuid *cp = (void *) &buf[sizeof(*hdr)];
633	uuid_t uuid128;
634
635	DBG("index %d", index);
636
637	uuid_to_uuid128(&uuid128, uuid);
638
639	memset(buf, 0, sizeof(buf));
640	hdr->opcode = htobs(MGMT_OP_ADD_UUID);
641	hdr->len = htobs(sizeof(*cp));
642
643	cp->index = htobs(index);
644	memcpy(cp->uuid, uuid128.value.uuid128.data, 16);
645	cp->svc_hint = svc_hint;
646
647	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
648		return -errno;
649
650	return 0;
651}
652
653static int mgmt_remove_uuid(int index, uuid_t *uuid)
654{
655	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_uuid)];
656	struct mgmt_hdr *hdr = (void *) buf;
657	struct mgmt_cp_remove_uuid *cp = (void *) &buf[sizeof(*hdr)];
658	uuid_t uuid128;
659
660	DBG("index %d", index);
661
662	uuid_to_uuid128(&uuid128, uuid);
663
664	memset(buf, 0, sizeof(buf));
665	hdr->opcode = htobs(MGMT_OP_REMOVE_UUID);
666	hdr->len = htobs(sizeof(*cp));
667
668	cp->index = htobs(index);
669	memcpy(cp->uuid, uuid128.value.uuid128.data, 16);
670
671	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
672		return -errno;
673
674	return 0;
675}
676
677static int clear_uuids(int index)
678{
679	uuid_t uuid_any;
680
681	memset(&uuid_any, 0, sizeof(uuid_any));
682	uuid_any.type = SDP_UUID128;
683
684	return mgmt_remove_uuid(index, &uuid_any);
685}
686
687static void read_index_list_complete(int sk, void *buf, size_t len)
688{
689	struct mgmt_rp_read_index_list *rp = buf;
690	uint16_t num;
691	int i;
692
693	if (len < sizeof(*rp)) {
694		error("Too small read index list complete event");
695		return;
696	}
697
698	num = btohs(bt_get_unaligned(&rp->num_controllers));
699
700	if (num * sizeof(uint16_t) + sizeof(*rp) != len) {
701		error("Incorrect packet size for index list event");
702		return;
703	}
704
705	for (i = 0; i < num; i++) {
706		uint16_t index;
707
708		index = btohs(bt_get_unaligned(&rp->index[i]));
709
710		add_controller(index);
711		get_connections(sk, index);
712		clear_uuids(index);
713	}
714}
715
716static int mgmt_set_powered(int index, gboolean powered)
717{
718	DBG("index %d powered %d", index, powered);
719	return mgmt_set_mode(index, MGMT_OP_SET_POWERED, powered);
720}
721
722static void read_info_complete(int sk, void *buf, size_t len)
723{
724	struct mgmt_rp_read_info *rp = buf;
725	struct controller_info *info;
726	struct btd_adapter *adapter;
727	uint8_t mode;
728	uint16_t index;
729	char addr[18];
730
731	if (len < sizeof(*rp)) {
732		error("Too small read info complete event");
733		return;
734	}
735
736	index = btohs(bt_get_unaligned(&rp->index));
737	if (index > max_index) {
738		error("Unexpected index %u in read info complete", index);
739		return;
740	}
741
742	mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 1);
743
744	info = &controllers[index];
745	info->type = rp->type;
746	info->enabled = rp->powered;
747	info->connectable = rp->connectable;
748	info->discoverable = rp->discoverable;
749	info->pairable = rp->pairable;
750	info->sec_mode = rp->sec_mode;
751	bacpy(&info->bdaddr, &rp->bdaddr);
752	memcpy(info->dev_class, rp->dev_class, 3);
753	memcpy(info->features, rp->features, 8);
754	info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
755	info->hci_ver = rp->hci_ver;
756	info->hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
757
758	ba2str(&info->bdaddr, addr);
759	DBG("hci%u type %u addr %s", index, info->type, addr);
760	DBG("hci%u class 0x%02x%02x%02x", index,
761		info->dev_class[2], info->dev_class[1], info->dev_class[0]);
762	DBG("hci%u manufacturer %d HCI ver %d:%d", index, info->manufacturer,
763						info->hci_ver, info->hci_rev);
764	DBG("hci%u enabled %u discoverable %u pairable %u sec_mode %u", index,
765					info->enabled, info->discoverable,
766					info->pairable, info->sec_mode);
767
768	adapter = btd_manager_register_adapter(index);
769	if (adapter == NULL) {
770		error("mgmtops: unable to register adapter");
771		return;
772	}
773
774	btd_adapter_get_mode(adapter, &mode, NULL, NULL);
775	if (mode == MODE_OFF) {
776		mgmt_set_powered(index, FALSE);
777		return;
778	}
779
780	if (info->enabled)
781		mgmt_update_powered(index, TRUE);
782	else
783		mgmt_set_powered(index, TRUE);
784
785	btd_adapter_unref(adapter);
786}
787
788static void set_powered_complete(int sk, void *buf, size_t len)
789{
790	struct mgmt_mode *rp = buf;
791	uint16_t index;
792
793	if (len < sizeof(*rp)) {
794		error("Too small set powered complete event");
795		return;
796	}
797
798	index = btohs(bt_get_unaligned(&rp->index));
799
800	DBG("hci%d powered %u", index, rp->val);
801
802	mgmt_update_powered(index, rp->val);
803}
804
805static void set_discoverable_complete(int sk, void *buf, size_t len)
806{
807	struct mgmt_mode *rp = buf;
808	struct controller_info *info;
809	struct btd_adapter *adapter;
810	uint16_t index;
811	uint8_t mode;
812
813	if (len < sizeof(*rp)) {
814		error("Too small set discoverable complete event");
815		return;
816	}
817
818	index = btohs(bt_get_unaligned(&rp->index));
819
820	DBG("hci%d discoverable %u", index, rp->val);
821
822	if (index > max_index) {
823		error("Unexpected index %u in discoverable complete", index);
824		return;
825	}
826
827	info = &controllers[index];
828
829	info->discoverable = rp->val ? TRUE : FALSE;
830
831	adapter = manager_find_adapter(&info->bdaddr);
832	if (!adapter)
833		return;
834
835	/* set_discoverable will always also change page scanning */
836	mode = SCAN_PAGE;
837
838	if (info->discoverable)
839		mode |= SCAN_INQUIRY;
840
841	adapter_mode_changed(adapter, mode);
842}
843
844static void set_connectable_complete(int sk, void *buf, size_t len)
845{
846	struct mgmt_mode *rp = buf;
847	struct controller_info *info;
848	struct btd_adapter *adapter;
849	uint16_t index;
850
851	if (len < sizeof(*rp)) {
852		error("Too small set connectable complete event");
853		return;
854	}
855
856	index = btohs(bt_get_unaligned(&rp->index));
857
858	DBG("hci%d connectable %u", index, rp->val);
859
860	if (index > max_index) {
861		error("Unexpected index %u in connectable complete", index);
862		return;
863	}
864
865	info = &controllers[index];
866
867	info->connectable = rp->val ? TRUE : FALSE;
868
869	adapter = manager_find_adapter(&info->bdaddr);
870	if (adapter)
871		adapter_mode_changed(adapter, rp->val ? SCAN_PAGE : 0);
872}
873
874static void set_pairable_complete(int sk, void *buf, size_t len)
875{
876	struct mgmt_mode *rp = buf;
877	struct controller_info *info;
878	struct btd_adapter *adapter;
879	uint16_t index;
880
881	if (len < sizeof(*rp)) {
882		error("Too small set pairable complete event");
883		return;
884	}
885
886	index = btohs(bt_get_unaligned(&rp->index));
887
888	DBG("hci%d pairable %u", index, rp->val);
889
890	if (index > max_index) {
891		error("Unexpected index %u in pairable complete", index);
892		return;
893	}
894
895	info = &controllers[index];
896
897	info->pairable = rp->val ? TRUE : FALSE;
898
899	adapter = manager_find_adapter(&info->bdaddr);
900	if (!adapter)
901		return;
902
903	btd_adapter_pairable_changed(adapter, info->pairable);
904}
905
906static void disconnect_complete(int sk, void *buf, size_t len)
907{
908	struct mgmt_rp_disconnect *rp = buf;
909	struct controller_info *info;
910	uint16_t index;
911	char addr[18];
912
913	if (len < sizeof(*rp)) {
914		error("Too small disconnect complete event");
915		return;
916	}
917
918	index = btohs(bt_get_unaligned(&rp->index));
919
920	ba2str(&rp->bdaddr, addr);
921
922	DBG("hci%d %s disconnected", index, addr);
923
924	if (index > max_index) {
925		error("Unexpected index %u in disconnect complete", index);
926		return;
927	}
928
929	info = &controllers[index];
930
931	btd_event_disconn_complete(&info->bdaddr, &rp->bdaddr);
932}
933
934static void get_connections_complete(int sk, void *buf, size_t len)
935{
936	struct mgmt_rp_get_connections *rp = buf;
937	struct controller_info *info;
938	uint16_t index;
939	int i;
940
941	if (len < sizeof(*rp)) {
942		error("Too small get_connections complete event");
943		return;
944	}
945
946	if (len < (sizeof(*rp) + (rp->conn_count * sizeof(bdaddr_t)))) {
947		error("Too small get_connections complete event");
948		return;
949	}
950
951	index = btohs(bt_get_unaligned(&rp->index));
952
953	if (index > max_index) {
954		error("Unexpected index %u in get_connections complete",
955								index);
956		return;
957	}
958
959	info = &controllers[index];
960
961	for (i = 0; i < rp->conn_count; i++) {
962		bdaddr_t *bdaddr = g_memdup(&rp->conn[i], sizeof(bdaddr_t));
963		info->connections = g_slist_append(info->connections, bdaddr);
964	}
965
966	read_info(sk, index);
967}
968
969static void mgmt_cmd_complete(int sk, void *buf, size_t len)
970{
971	struct mgmt_ev_cmd_complete *ev = buf;
972	uint16_t opcode;
973
974	DBG("");
975
976	if (len < sizeof(*ev)) {
977		error("Too small management command complete event packet");
978		return;
979	}
980
981	opcode = btohs(bt_get_unaligned(&ev->opcode));
982
983	switch (opcode) {
984	case MGMT_OP_READ_VERSION:
985		read_version_complete(sk, ev->data, len - sizeof(*ev));
986		break;
987	case MGMT_OP_READ_INDEX_LIST:
988		read_index_list_complete(sk, ev->data, len - sizeof(*ev));
989		break;
990	case MGMT_OP_READ_INFO:
991		read_info_complete(sk, ev->data, len - sizeof(*ev));
992		break;
993	case MGMT_OP_SET_POWERED:
994		set_powered_complete(sk, ev->data, len - sizeof(*ev));
995		break;
996	case MGMT_OP_SET_DISCOVERABLE:
997		set_discoverable_complete(sk, ev->data, len - sizeof(*ev));
998		break;
999	case MGMT_OP_SET_CONNECTABLE:
1000		set_connectable_complete(sk, ev->data, len - sizeof(*ev));
1001		break;
1002	case MGMT_OP_SET_PAIRABLE:
1003		set_pairable_complete(sk, ev->data, len - sizeof(*ev));
1004		break;
1005	case MGMT_OP_ADD_UUID:
1006		DBG("add_uuid complete");
1007		break;
1008	case MGMT_OP_REMOVE_UUID:
1009		DBG("remove_uuid complete");
1010		break;
1011	case MGMT_OP_SET_DEV_CLASS:
1012		DBG("set_dev_class complete");
1013		break;
1014	case MGMT_OP_SET_SERVICE_CACHE:
1015		DBG("set_service_cache complete");
1016		break;
1017	case MGMT_OP_LOAD_KEYS:
1018		DBG("load_keys complete");
1019		break;
1020	case MGMT_OP_REMOVE_KEY:
1021		DBG("remove_key complete");
1022		break;
1023	case MGMT_OP_DISCONNECT:
1024		DBG("disconnect complete");
1025		disconnect_complete(sk, ev->data, len - sizeof(*ev));
1026		break;
1027	case MGMT_OP_GET_CONNECTIONS:
1028		get_connections_complete(sk, ev->data, len - sizeof(*ev));
1029		break;
1030	case MGMT_OP_PIN_CODE_REPLY:
1031		DBG("pin_code_reply complete");
1032		break;
1033	case MGMT_OP_PIN_CODE_NEG_REPLY:
1034		DBG("pin_code_neg_reply complete");
1035		break;
1036	case MGMT_OP_SET_IO_CAPABILITY:
1037		DBG("set_io_capability complete");
1038		break;
1039	default:
1040		error("Unknown command complete for opcode %u", opcode);
1041		break;
1042	}
1043}
1044
1045static void mgmt_cmd_status(int sk, void *buf, size_t len)
1046{
1047	struct mgmt_ev_cmd_status *ev = buf;
1048	uint16_t opcode;
1049
1050	if (len < sizeof(*ev)) {
1051		error("Too small management command status event packet");
1052		return;
1053	}
1054
1055	opcode = btohs(bt_get_unaligned(&ev->opcode));
1056
1057	DBG("status %u opcode %u", ev->status, opcode);
1058}
1059
1060static void mgmt_controller_error(int sk, void *buf, size_t len)
1061{
1062	struct mgmt_ev_controller_error *ev = buf;
1063	uint16_t index;
1064
1065	if (len < sizeof(*ev)) {
1066		error("Too small management controller error event packet");
1067		return;
1068	}
1069
1070	index = btohs(bt_get_unaligned(&ev->index));
1071
1072	DBG("index %u error_code %u", index, ev->error_code);
1073}
1074
1075static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data)
1076{
1077	char buf[MGMT_BUF_SIZE];
1078	struct mgmt_hdr *hdr = (void *) buf;
1079	int sk;
1080	ssize_t ret;
1081	uint16_t len, opcode;
1082
1083	DBG("cond %d", cond);
1084
1085	if (cond & G_IO_NVAL)
1086		return FALSE;
1087
1088	sk = g_io_channel_unix_get_fd(io);
1089
1090	if (cond & (G_IO_ERR | G_IO_HUP)) {
1091		error("Error on management socket");
1092		return FALSE;
1093	}
1094
1095	ret = read(sk, buf, sizeof(buf));
1096	if (ret < 0) {
1097		error("Unable to read from management socket: %s (%d)",
1098						strerror(errno), errno);
1099		return TRUE;
1100	}
1101
1102	DBG("Received %zd bytes from management socket", ret);
1103
1104	if (ret < MGMT_HDR_SIZE) {
1105		error("Too small Management packet");
1106		return TRUE;
1107	}
1108
1109	opcode = btohs(bt_get_unaligned(&hdr->opcode));
1110	len = btohs(bt_get_unaligned(&hdr->len));
1111
1112	if (ret != MGMT_HDR_SIZE + len) {
1113		error("Packet length mismatch. ret %zd len %u", ret, len);
1114		return TRUE;
1115	}
1116
1117	switch (opcode) {
1118	case MGMT_EV_CMD_COMPLETE:
1119		mgmt_cmd_complete(sk, buf + MGMT_HDR_SIZE, len);
1120		break;
1121	case MGMT_EV_CMD_STATUS:
1122		mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len);
1123		break;
1124	case MGMT_EV_CONTROLLER_ERROR:
1125		mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len);
1126		break;
1127	case MGMT_EV_INDEX_ADDED:
1128		mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len);
1129		break;
1130	case MGMT_EV_INDEX_REMOVED:
1131		mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len);
1132		break;
1133	case MGMT_EV_POWERED:
1134		mgmt_powered(sk, buf + MGMT_HDR_SIZE, len);
1135		break;
1136	case MGMT_EV_DISCOVERABLE:
1137		mgmt_discoverable(sk, buf + MGMT_HDR_SIZE, len);
1138		break;
1139	case MGMT_EV_CONNECTABLE:
1140		mgmt_connectable(sk, buf + MGMT_HDR_SIZE, len);
1141		break;
1142	case MGMT_EV_PAIRABLE:
1143		mgmt_pairable(sk, buf + MGMT_HDR_SIZE, len);
1144		break;
1145	case MGMT_EV_NEW_KEY:
1146		mgmt_new_key(sk, buf + MGMT_HDR_SIZE, len);
1147		break;
1148	case MGMT_EV_DEVICE_CONNECTED:
1149		mgmt_device_connected(sk, buf + MGMT_HDR_SIZE, len);
1150		break;
1151	case MGMT_EV_DEVICE_DISCONNECTED:
1152		mgmt_device_disconnected(sk, buf + MGMT_HDR_SIZE, len);
1153		break;
1154	case MGMT_EV_CONNECT_FAILED:
1155		mgmt_connect_failed(sk, buf + MGMT_HDR_SIZE, len);
1156		break;
1157	case MGMT_EV_PIN_CODE_REQUEST:
1158		mgmt_pin_code_request(sk, buf + MGMT_HDR_SIZE, len);
1159		break;
1160	default:
1161		error("Unknown Management opcode %u", opcode);
1162		break;
1163	}
1164
1165	return TRUE;
1166}
1167
1168static int mgmt_setup(void)
1169{
1170	struct mgmt_hdr hdr;
1171	struct sockaddr_hci addr;
1172	GIOChannel *io;
1173	GIOCondition condition;
1174	int dd, err;
1175
1176	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
1177	if (dd < 0)
1178		return -errno;
1179
1180	memset(&addr, 0, sizeof(addr));
1181	addr.hci_family = AF_BLUETOOTH;
1182	addr.hci_dev = HCI_DEV_NONE;
1183	addr.hci_channel = HCI_CHANNEL_CONTROL;
1184
1185	if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1186		err = -errno;
1187		goto fail;
1188	}
1189
1190	memset(&hdr, 0, sizeof(hdr));
1191	hdr.opcode = htobs(MGMT_OP_READ_VERSION);
1192	if (write(dd, &hdr, sizeof(hdr)) < 0) {
1193		err = -errno;
1194		goto fail;
1195	}
1196
1197	io = g_io_channel_unix_new(dd);
1198	condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
1199	mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL);
1200	g_io_channel_unref(io);
1201
1202	mgmt_sock = dd;
1203
1204	info("Bluetooth Management interface initialized");
1205
1206	return 0;
1207
1208fail:
1209	close(dd);
1210	return err;
1211}
1212
1213static void mgmt_cleanup(void)
1214{
1215	g_free(controllers);
1216	controllers = NULL;
1217	max_index = -1;
1218
1219	if (mgmt_sock >= 0) {
1220		close(mgmt_sock);
1221		mgmt_sock = -1;
1222	}
1223
1224	if (mgmt_watch > 0) {
1225		g_source_remove(mgmt_watch);
1226		mgmt_watch = 0;
1227	}
1228}
1229
1230static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor)
1231{
1232	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_dev_class)];
1233	struct mgmt_hdr *hdr = (void *) buf;
1234	struct mgmt_cp_set_dev_class *cp = (void *) &buf[sizeof(*hdr)];
1235
1236	DBG("index %d major %u minor %u", index, major, minor);
1237
1238	memset(buf, 0, sizeof(buf));
1239	hdr->opcode = htobs(MGMT_OP_SET_DEV_CLASS);
1240	hdr->len = htobs(sizeof(*cp));
1241
1242	cp->index = htobs(index);
1243	cp->major = major;
1244	cp->minor = minor;
1245
1246	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
1247		return -errno;
1248
1249	return 0;
1250}
1251
1252static int mgmt_set_limited_discoverable(int index, gboolean limited)
1253{
1254	DBG("index %d limited %d", index, limited);
1255	return -ENOSYS;
1256}
1257
1258static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic)
1259{
1260	DBG("index %d length %u periodic %d", index, length, periodic);
1261	return -ENOSYS;
1262}
1263
1264static int mgmt_stop_inquiry(int index)
1265{
1266	DBG("index %d", index);
1267	return -ENOSYS;
1268}
1269
1270static int mgmt_start_scanning(int index)
1271{
1272	DBG("index %d", index);
1273	return -ENOSYS;
1274}
1275
1276static int mgmt_stop_scanning(int index)
1277{
1278	DBG("index %d", index);
1279	return -ENOSYS;
1280}
1281
1282static int mgmt_resolve_name(int index, bdaddr_t *bdaddr)
1283{
1284	char addr[18];
1285
1286	ba2str(bdaddr, addr);
1287	DBG("index %d addr %s", index, addr);
1288
1289	return -ENOSYS;
1290}
1291
1292static int mgmt_set_name(int index, const char *name)
1293{
1294	DBG("index %d, name %s", index, name);
1295	return -ENOSYS;
1296}
1297
1298static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr)
1299{
1300	char addr[18];
1301
1302	ba2str(bdaddr, addr);
1303	DBG("index %d addr %s", index, addr);
1304
1305	return -ENOSYS;
1306}
1307
1308static int mgmt_fast_connectable(int index, gboolean enable)
1309{
1310	DBG("index %d enable %d", index, enable);
1311	return -ENOSYS;
1312}
1313
1314static int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout,
1315					uint32_t *clock, uint16_t *accuracy)
1316{
1317	char addr[18];
1318
1319	ba2str(bdaddr, addr);
1320	DBG("index %d addr %s which %d timeout %d", index, addr, which,
1321								timeout);
1322
1323	return -ENOSYS;
1324}
1325
1326static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr)
1327{
1328	char addr[18];
1329	struct controller_info *info = &controllers[index];
1330
1331	ba2str(&info->bdaddr, addr);
1332	DBG("index %d addr %s", index, addr);
1333
1334	if (!info->valid)
1335		return -ENODEV;
1336
1337	bacpy(bdaddr, &info->bdaddr);
1338
1339	return 0;
1340}
1341
1342static int mgmt_block_device(int index, bdaddr_t *bdaddr)
1343{
1344	char addr[18];
1345
1346	ba2str(bdaddr, addr);
1347	DBG("index %d addr %s", index, addr);
1348
1349	return -ENOSYS;
1350}
1351
1352static int mgmt_unblock_device(int index, bdaddr_t *bdaddr)
1353{
1354	char addr[18];
1355
1356	ba2str(bdaddr, addr);
1357	DBG("index %d addr %s", index, addr);
1358
1359	return -ENOSYS;
1360}
1361
1362static int mgmt_get_conn_list(int index, GSList **conns)
1363{
1364	struct controller_info *info = &controllers[index];
1365
1366	DBG("index %d", index);
1367
1368	*conns = info->connections;
1369	info->connections = NULL;
1370
1371	return 0;
1372}
1373
1374static int mgmt_read_local_version(int index, struct hci_version *ver)
1375{
1376	struct controller_info *info = &controllers[index];
1377
1378	DBG("index %d", index);
1379
1380	if (!info->valid)
1381		return -ENODEV;
1382
1383	memset(ver, 0, sizeof(*ver));
1384	ver->manufacturer = info->manufacturer;
1385	ver->hci_ver = info->hci_ver;
1386	ver->hci_rev = info->hci_rev;
1387
1388	return 0;
1389}
1390
1391static int mgmt_read_local_features(int index, uint8_t *features)
1392{
1393	struct controller_info *info = &controllers[index];
1394
1395	DBG("index %d", index);
1396
1397	if (!info->valid)
1398		return -ENODEV;
1399
1400	memcpy(features, info->features, 8);
1401
1402	return 0;
1403}
1404
1405static int mgmt_disconnect(int index, bdaddr_t *bdaddr)
1406{
1407	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_disconnect)];
1408	struct mgmt_hdr *hdr = (void *) buf;
1409	struct mgmt_cp_disconnect *cp = (void *) &buf[sizeof(*hdr)];
1410	char addr[18];
1411
1412	ba2str(bdaddr, addr);
1413	DBG("index %d %s", index, addr);
1414
1415	memset(buf, 0, sizeof(buf));
1416	hdr->opcode = htobs(MGMT_OP_DISCONNECT);
1417	hdr->len = htobs(sizeof(*cp));
1418
1419	cp->index = htobs(index);
1420	bacpy(&cp->bdaddr, bdaddr);
1421
1422	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
1423		error("write: %s (%d)", strerror(errno), errno);
1424
1425	return 0;
1426}
1427
1428static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
1429{
1430	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_key)];
1431	struct mgmt_hdr *hdr = (void *) buf;
1432	struct mgmt_cp_remove_key *cp = (void *) &buf[sizeof(*hdr)];
1433	char addr[18];
1434
1435	ba2str(bdaddr, addr);
1436	DBG("index %d addr %s", index, addr);
1437
1438	memset(buf, 0, sizeof(buf));
1439	hdr->opcode = htobs(MGMT_OP_REMOVE_KEY);
1440	hdr->len = htobs(sizeof(*cp));
1441
1442	cp->index = htobs(index);
1443	bacpy(&cp->bdaddr, bdaddr);
1444	cp->disconnect = 1;
1445
1446	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
1447		return -errno;
1448
1449	return 0;
1450}
1451
1452static int mgmt_request_authentication(int index, bdaddr_t *bdaddr)
1453{
1454	char addr[18];
1455
1456	ba2str(bdaddr, addr);
1457	DBG("index %d %s", index, addr);
1458
1459	return -ENOSYS;
1460}
1461
1462static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
1463{
1464	char addr[18];
1465
1466	ba2str(bdaddr, addr);
1467	DBG("index %d addr %s success %d", index, addr, success);
1468
1469	return -ENOSYS;
1470}
1471
1472static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
1473{
1474	char addr[18];
1475
1476	ba2str(bdaddr, addr);
1477	DBG("index %d addr %s passkey %06u", index, addr, passkey);
1478
1479	return -ENOSYS;
1480}
1481
1482static int mgmt_read_scan_enable(int index)
1483{
1484	DBG("index %d", index);
1485	return -ENOSYS;
1486}
1487
1488static int mgmt_enable_le(int index)
1489{
1490	DBG("index %d", index);
1491	return -ENOSYS;
1492}
1493
1494static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
1495							gpointer user_data)
1496{
1497	char addr[18];
1498
1499	ba2str(dst, addr);
1500	DBG("index %d addr %s", index, addr);
1501
1502	return -ENOSYS;
1503}
1504
1505static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
1506							uint16_t version)
1507{
1508	DBG("index %d vendor %u product %u version %u",
1509					index, vendor, product, version);
1510	return -ENOSYS;
1511}
1512
1513static int mgmt_disable_cod_cache(int index)
1514{
1515	DBG("index %d", index);
1516	return mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 0);
1517}
1518
1519static int mgmt_restore_powered(int index)
1520{
1521	DBG("index %d", index);
1522	return -ENOSYS;
1523}
1524
1525static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys)
1526{
1527	char *buf;
1528	struct mgmt_hdr *hdr;
1529	struct mgmt_cp_load_keys *cp;
1530	struct mgmt_key_info *key;
1531	size_t key_count, cp_size;
1532	GSList *l;
1533	int err;
1534
1535	key_count = g_slist_length(keys);
1536
1537	DBG("index %d keys %zu debug_keys %d", index, key_count, debug_keys);
1538
1539	cp_size = sizeof(*cp) + (key_count * sizeof(*key));
1540
1541	buf = g_try_malloc0(sizeof(*hdr) + cp_size);
1542	if (buf == NULL)
1543		return -ENOMEM;
1544
1545	memset(buf, 0, sizeof(buf));
1546
1547	hdr = (void *) buf;
1548	hdr->opcode = htobs(MGMT_OP_LOAD_KEYS);
1549	hdr->len = htobs(cp_size);
1550
1551	cp = (void *) (buf + sizeof(*hdr));
1552	cp->index = htobs(index);
1553	cp->debug_keys = debug_keys;
1554	cp->key_count = htobs(key_count);
1555
1556	for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
1557		struct link_key_info *info = l->data;
1558
1559		bacpy(&key->bdaddr, &info->bdaddr);
1560		key->type = info->type;
1561		memcpy(key->val, info->key, 16);
1562		key->pin_len = info->pin_len;
1563	}
1564
1565	if (write(mgmt_sock, buf, sizeof(*hdr) + cp_size) < 0)
1566		err = -errno;
1567	else
1568		err = 0;
1569
1570	g_free(buf);
1571
1572	return err;
1573}
1574
1575static int mgmt_set_io_capability(int index, uint8_t io_capability)
1576{
1577	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_io_capability)];
1578	struct mgmt_hdr *hdr = (void *) buf;
1579	struct mgmt_cp_set_io_capability *cp = (void *) &buf[sizeof(*hdr)];
1580
1581	DBG("hci%d io_capability 0x%02x", index, io_capability);
1582
1583	memset(buf, 0, sizeof(buf));
1584	hdr->opcode = htobs(MGMT_OP_SET_IO_CAPABILITY);
1585	hdr->len = htobs(sizeof(*cp));
1586
1587	cp->index = htobs(index);
1588	cp->io_capability = io_capability;
1589
1590	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
1591		return -errno;
1592
1593	return 0;
1594}
1595
1596static int mgmt_create_bonding(int index, bdaddr_t *bdaddr, uint8_t io_cap)
1597{
1598	char addr[18];
1599
1600	ba2str(bdaddr, addr);
1601	DBG("hci%d bdaddr %s io_cap 0x%02x", index, addr, io_cap);
1602
1603	return -ENOSYS;
1604}
1605
1606static int mgmt_cancel_bonding(int index, bdaddr_t *bdaddr)
1607{
1608	char addr[18];
1609
1610	ba2str(bdaddr, addr);
1611	DBG("hci%d bdaddr %s", index, addr);
1612
1613	return -ENOSYS;
1614}
1615
1616static struct btd_adapter_ops mgmt_ops = {
1617	.setup = mgmt_setup,
1618	.cleanup = mgmt_cleanup,
1619	.set_powered = mgmt_set_powered,
1620	.set_discoverable = mgmt_set_discoverable,
1621	.set_pairable = mgmt_set_pairable,
1622	.set_limited_discoverable = mgmt_set_limited_discoverable,
1623	.start_inquiry = mgmt_start_inquiry,
1624	.stop_inquiry = mgmt_stop_inquiry,
1625	.start_scanning = mgmt_start_scanning,
1626	.stop_scanning = mgmt_stop_scanning,
1627	.resolve_name = mgmt_resolve_name,
1628	.cancel_resolve_name = mgmt_cancel_resolve_name,
1629	.set_name = mgmt_set_name,
1630	.set_dev_class = mgmt_set_dev_class,
1631	.set_fast_connectable = mgmt_fast_connectable,
1632	.read_clock = mgmt_read_clock,
1633	.read_bdaddr = mgmt_read_bdaddr,
1634	.block_device = mgmt_block_device,
1635	.unblock_device = mgmt_unblock_device,
1636	.get_conn_list = mgmt_get_conn_list,
1637	.read_local_version = mgmt_read_local_version,
1638	.read_local_features = mgmt_read_local_features,
1639	.disconnect = mgmt_disconnect,
1640	.remove_bonding = mgmt_remove_bonding,
1641	.request_authentication = mgmt_request_authentication,
1642	.pincode_reply = mgmt_pincode_reply,
1643	.confirm_reply = mgmt_confirm_reply,
1644	.passkey_reply = mgmt_passkey_reply,
1645	.read_scan_enable = mgmt_read_scan_enable,
1646	.enable_le = mgmt_enable_le,
1647	.encrypt_link = mgmt_encrypt_link,
1648	.set_did = mgmt_set_did,
1649	.add_uuid = mgmt_add_uuid,
1650	.remove_uuid = mgmt_remove_uuid,
1651	.disable_cod_cache = mgmt_disable_cod_cache,
1652	.restore_powered = mgmt_restore_powered,
1653	.load_keys = mgmt_load_keys,
1654	.set_io_capability = mgmt_set_io_capability,
1655	.create_bonding = mgmt_create_bonding,
1656	.cancel_bonding = mgmt_cancel_bonding,
1657};
1658
1659static int mgmt_init(void)
1660{
1661	return btd_register_adapter_ops(&mgmt_ops, TRUE);
1662}
1663
1664static void mgmt_exit(void)
1665{
1666	btd_adapter_cleanup_ops(&mgmt_ops);
1667}
1668
1669BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION,
1670		BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit)
1671