mgmtops.c revision 27a311476a53c72ac06d6cdc3cffbef14a0caba7
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 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	btd_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 mgmt_powered(int sk, void *buf, size_t len)
175{
176	struct btd_adapter *adapter;
177	struct mgmt_ev_powered *ev = buf;
178	uint16_t index;
179
180	if (len < sizeof(*ev)) {
181		error("Too small powered event");
182		return;
183	}
184
185	index = btohs(bt_get_unaligned(&ev->index));
186
187	if (index > max_index) {
188		DBG("Ignoring powered event for unknown controller %u", index);
189		return;
190	}
191
192	controllers[index].enabled = ev->powered;
193
194	DBG("Controller %u powered %s", index, ev->powered ? "on" : "off");
195
196	adapter = manager_find_adapter(&controllers[index].bdaddr);
197	if (adapter == NULL) {
198		DBG("Adapter not found");
199		return;
200	}
201
202	if (ev->powered)
203		btd_adapter_start(adapter);
204	else
205		btd_adapter_stop(adapter);
206}
207
208static void read_index_list_complete(int sk, void *buf, size_t len)
209{
210	struct mgmt_rp_read_index_list *rp = buf;
211	uint16_t num;
212	int i;
213
214	if (len < sizeof(*rp)) {
215		error("Too small read index list complete event");
216		return;
217	}
218
219	num = btohs(bt_get_unaligned(&rp->num_controllers));
220
221	if (num * sizeof(uint16_t) + sizeof(*rp) != len) {
222		error("Incorrect packet size for index list event");
223		return;
224	}
225
226	for (i = 0; i < num; i++) {
227		uint16_t index;
228
229		index = btohs(bt_get_unaligned(&rp->index[i]));
230
231		add_controller(index);
232		read_info(sk, index);
233	}
234}
235
236static int mgmt_power_off(int index)
237{
238	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_power_off)];
239	struct mgmt_hdr *hdr = (void *) buf;
240	struct mgmt_cp_power_off *cp = (void *) &buf[sizeof(*hdr)];
241
242	DBG("index %d", index);
243
244	memset(buf, 0, sizeof(buf));
245	hdr->opcode = MGMT_OP_POWER_OFF;
246	hdr->len = htobs(sizeof(*cp));
247
248	cp->index = htobs(index);
249
250	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
251		return -errno;
252
253	return 0;
254}
255
256static int mgmt_set_discoverable(int index, gboolean discoverable)
257{
258	DBG("index %d discoverable %d", index, discoverable);
259	return -ENOSYS;
260}
261
262static int mgmt_set_pairable(int index, gboolean pairable)
263{
264	DBG("index %d pairable %d", index, pairable);
265	return -ENOSYS;
266}
267
268static void read_info_complete(int sk, void *buf, size_t len)
269{
270	struct mgmt_rp_read_info *rp = buf;
271	struct controller_info *info;
272	struct btd_adapter *adapter;
273	uint8_t mode;
274	gboolean pairable, discoverable;
275	uint16_t index;
276	char addr[18];
277
278	if (len < sizeof(*rp)) {
279		error("Too small read info complete event");
280		return;
281	}
282
283	index = btohs(bt_get_unaligned(&rp->index));
284	if (index > max_index) {
285		error("Unexpected index %u in read info complete", index);
286		return;
287	}
288
289	info = &controllers[index];
290	info->type = rp->type;
291	info->enabled = rp->powered;
292	info->discoverable = rp->discoverable;
293	info->pairable = rp->pairable;
294	info->sec_mode = rp->sec_mode;
295	bacpy(&info->bdaddr, &rp->bdaddr);
296	memcpy(info->dev_class, rp->dev_class, 3);
297	memcpy(info->features, rp->features, 8);
298	info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
299	info->hci_ver = rp->hci_ver;
300	info->hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
301
302	ba2str(&info->bdaddr, addr);
303	DBG("hci%u type %u addr %s", index, info->type, addr);
304	DBG("hci%u class 0x%02x%02x%02x", index,
305		info->dev_class[2], info->dev_class[1], info->dev_class[0]);
306	DBG("hci%u manufacturer %d HCI ver %d:%d", index, info->manufacturer,
307						info->hci_ver, info->hci_rev);
308	DBG("hci%u enabled %u discoverable %u pairable %u sec_mode %u", index,
309					info->enabled, info->discoverable,
310					info->pairable, info->sec_mode);
311
312	adapter = btd_manager_register_adapter(index);
313	if (adapter == NULL) {
314		error("mgmtops: unable to register adapter");
315		return;
316	}
317
318	btd_adapter_get_state(adapter, &mode, NULL, &pairable);
319	if (mode == MODE_OFF) {
320		mgmt_power_off(index);
321		return;
322	}
323
324	discoverable = (mode == MODE_DISCOVERABLE);
325
326	if (info->discoverable != discoverable)
327		mgmt_set_discoverable(index, discoverable);
328
329	if (info->pairable != pairable)
330		mgmt_set_pairable(index, pairable);
331
332	if (info->enabled)
333		btd_adapter_start(adapter);
334
335	btd_adapter_unref(adapter);
336}
337
338static void mgmt_cmd_complete(int sk, void *buf, size_t len)
339{
340	struct mgmt_ev_cmd_complete *ev = buf;
341	uint16_t opcode;
342
343	DBG("");
344
345	if (len < sizeof(*ev)) {
346		error("Too small management command complete event packet");
347		return;
348	}
349
350	opcode = btohs(bt_get_unaligned(&ev->opcode));
351
352	switch (opcode) {
353	case MGMT_OP_READ_VERSION:
354		read_version_complete(sk, ev->data, len - sizeof(*ev));
355		break;
356	case MGMT_OP_READ_INDEX_LIST:
357		read_index_list_complete(sk, ev->data, len - sizeof(*ev));
358		break;
359	case MGMT_OP_READ_INFO:
360		read_info_complete(sk, ev->data, len - sizeof(*ev));
361		break;
362	default:
363		error("Unknown command complete for opcode %u", opcode);
364		break;
365	}
366}
367
368static void mgmt_cmd_status(int sk, void *buf, size_t len)
369{
370	struct mgmt_ev_cmd_status *ev = buf;
371	uint16_t opcode;
372
373	if (len < sizeof(*ev)) {
374		error("Too small management command status event packet");
375		return;
376	}
377
378	opcode = btohs(bt_get_unaligned(&ev->opcode));
379
380	DBG("status %u opcode %u", ev->status, opcode);
381}
382
383static void mgmt_controller_error(int sk, void *buf, size_t len)
384{
385	struct mgmt_ev_controller_error *ev = buf;
386	uint16_t index;
387
388	if (len < sizeof(*ev)) {
389		error("Too small management controller error event packet");
390		return;
391	}
392
393	index = btohs(bt_get_unaligned(&ev->index));
394
395	DBG("index %u error_code %u", index, ev->error_code);
396}
397
398static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data)
399{
400	char buf[MGMT_BUF_SIZE];
401	struct mgmt_hdr *hdr = (void *) buf;
402	int sk;
403	ssize_t ret;
404	uint16_t len, opcode;
405
406	DBG("cond %d", cond);
407
408	if (cond & G_IO_NVAL)
409		return FALSE;
410
411	sk = g_io_channel_unix_get_fd(io);
412
413	if (cond & (G_IO_ERR | G_IO_HUP)) {
414		error("Error on management socket");
415		return FALSE;
416	}
417
418	ret = read(sk, buf, sizeof(buf));
419	if (ret < 0) {
420		error("Unable to read from management socket: %s (%d)",
421						strerror(errno), errno);
422		return TRUE;
423	}
424
425	DBG("Received %zd bytes from management socket", ret);
426
427	if (ret < MGMT_HDR_SIZE) {
428		error("Too small Management packet");
429		return TRUE;
430	}
431
432	opcode = btohs(bt_get_unaligned(&hdr->opcode));
433	len = btohs(bt_get_unaligned(&hdr->len));
434
435	if (ret != MGMT_HDR_SIZE + len) {
436		error("Packet length mismatch. ret %zd len %u", ret, len);
437		return TRUE;
438	}
439
440	switch (opcode) {
441	case MGMT_EV_CMD_COMPLETE:
442		mgmt_cmd_complete(sk, buf + MGMT_HDR_SIZE, len);
443		break;
444	case MGMT_EV_CMD_STATUS:
445		mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len);
446		break;
447	case MGMT_EV_CONTROLLER_ERROR:
448		mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len);
449		break;
450	case MGMT_EV_INDEX_ADDED:
451		mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len);
452		break;
453	case MGMT_EV_INDEX_REMOVED:
454		mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len);
455		break;
456	case MGMT_EV_POWERED:
457		mgmt_powered(sk, buf + MGMT_HDR_SIZE, len);
458		break;
459	default:
460		error("Unknown Management opcode %u", opcode);
461		break;
462	}
463
464	return TRUE;
465}
466
467static int mgmt_setup(void)
468{
469	struct mgmt_hdr hdr;
470	struct sockaddr_hci addr;
471	GIOChannel *io;
472	GIOCondition condition;
473	int dd, err;
474
475	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
476	if (dd < 0)
477		return -errno;
478
479	memset(&addr, 0, sizeof(addr));
480	addr.hci_family = AF_BLUETOOTH;
481	addr.hci_dev = HCI_DEV_NONE;
482	addr.hci_channel = HCI_CHANNEL_CONTROL;
483
484	if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
485		err = -errno;
486		goto fail;
487	}
488
489	memset(&hdr, 0, sizeof(hdr));
490	hdr.opcode = MGMT_OP_READ_VERSION;
491	if (write(dd, &hdr, sizeof(hdr)) < 0) {
492		err = -errno;
493		goto fail;
494	}
495
496	io = g_io_channel_unix_new(dd);
497	condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
498	mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL);
499	g_io_channel_unref(io);
500
501	mgmt_sock = dd;
502
503	info("Bluetooth Management interface initialized");
504
505	return 0;
506
507fail:
508	close(dd);
509	return err;
510}
511
512static void mgmt_cleanup(void)
513{
514	g_free(controllers);
515	controllers = NULL;
516	max_index = -1;
517
518	if (mgmt_sock >= 0) {
519		close(mgmt_sock);
520		mgmt_sock = -1;
521	}
522
523	if (mgmt_watch > 0) {
524		g_source_remove(mgmt_watch);
525		mgmt_watch = 0;
526	}
527}
528
529static int mgmt_power_on(int index, gboolean discoverable)
530{
531	struct controller_info *info = &controllers[index];
532	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_power_on)];
533	struct mgmt_hdr *hdr = (void *) buf;
534	struct mgmt_cp_power_on *cp = (void *) &buf[sizeof(*hdr)];
535
536	DBG("index %d discoverable %d", index, discoverable);
537
538	memset(buf, 0, sizeof(buf));
539	hdr->opcode = MGMT_OP_POWER_ON;
540	hdr->len = htobs(sizeof(*cp));
541
542	cp->index = htobs(index);
543	cp->discoverable = discoverable;
544	cp->pairable = info->pairable;
545
546	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
547		return -errno;
548
549	return 0;
550}
551
552static int mgmt_set_connectable(int index, gboolean connectable)
553{
554	DBG("index %d connectable %d", index, connectable);
555	return -ENOSYS;
556}
557
558static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor)
559{
560	DBG("index %d major %u minor %u", index, major, minor);
561	return -ENOSYS;
562}
563
564static int mgmt_set_limited_discoverable(int index, gboolean limited)
565{
566	DBG("index %d limited %d", index, limited);
567	return -ENOSYS;
568}
569
570static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic)
571{
572	DBG("index %d length %u periodic %d", index, length, periodic);
573	return -ENOSYS;
574}
575
576static int mgmt_stop_inquiry(int index)
577{
578	DBG("index %d", index);
579	return -ENOSYS;
580}
581
582static int mgmt_start_scanning(int index)
583{
584	DBG("index %d", index);
585	return -ENOSYS;
586}
587
588static int mgmt_stop_scanning(int index)
589{
590	DBG("index %d", index);
591	return -ENOSYS;
592}
593
594static int mgmt_resolve_name(int index, bdaddr_t *bdaddr)
595{
596	char addr[18];
597
598	ba2str(bdaddr, addr);
599	DBG("index %d addr %s", index, addr);
600
601	return -ENOSYS;
602}
603
604static int mgmt_set_name(int index, const char *name)
605{
606	DBG("index %d, name %s", index, name);
607	return -ENOSYS;
608}
609
610static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr)
611{
612	char addr[18];
613
614	ba2str(bdaddr, addr);
615	DBG("index %d addr %s", index, addr);
616
617	return -ENOSYS;
618}
619
620static int mgmt_fast_connectable(int index, gboolean enable)
621{
622	DBG("index %d enable %d", index, enable);
623	return -ENOSYS;
624}
625
626static int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout,
627					uint32_t *clock, uint16_t *accuracy)
628{
629	char addr[18];
630
631	ba2str(bdaddr, addr);
632	DBG("index %d addr %s which %d timeout %d", index, addr, which,
633								timeout);
634
635	return -ENOSYS;
636}
637
638static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr)
639{
640	char addr[18];
641	struct controller_info *info = &controllers[index];
642
643	ba2str(&info->bdaddr, addr);
644	DBG("index %d addr %s", index, addr);
645
646	if (!info->valid)
647		return -ENODEV;
648
649	bacpy(bdaddr, &info->bdaddr);
650
651	return 0;
652}
653
654static int mgmt_block_device(int index, bdaddr_t *bdaddr)
655{
656	char addr[18];
657
658	ba2str(bdaddr, addr);
659	DBG("index %d addr %s", index, addr);
660
661	return -ENOSYS;
662}
663
664static int mgmt_unblock_device(int index, bdaddr_t *bdaddr)
665{
666	char addr[18];
667
668	ba2str(bdaddr, addr);
669	DBG("index %d addr %s", index, addr);
670
671	return -ENOSYS;
672}
673
674static int mgmt_get_conn_list(int index, GSList **conns)
675{
676	DBG("index %d", index);
677	return -ENOSYS;
678}
679
680static int mgmt_read_local_version(int index, struct hci_version *ver)
681{
682	struct controller_info *info = &controllers[index];
683
684	DBG("index %d", index);
685
686	if (!info->valid)
687		return -ENODEV;
688
689	memset(ver, 0, sizeof(*ver));
690	ver->manufacturer = info->manufacturer;
691	ver->hci_ver = info->hci_ver;
692	ver->hci_rev = info->hci_rev;
693
694	return 0;
695}
696
697static int mgmt_read_local_features(int index, uint8_t *features)
698{
699	struct controller_info *info = &controllers[index];
700
701	DBG("index %d", index);
702
703	if (!info->valid)
704		return -ENODEV;
705
706	memcpy(features, info->features, 8);
707
708	return 0;
709}
710
711static int mgmt_disconnect(int index, uint16_t handle)
712{
713	DBG("index %d handle %u", index, handle);
714	return -ENOSYS;
715}
716
717static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
718{
719	char addr[18];
720
721	ba2str(bdaddr, addr);
722	DBG("index %d addr %s", index, addr);
723
724	return -ENOSYS;
725}
726
727static int mgmt_request_authentication(int index, uint16_t handle)
728{
729	DBG("index %d handle %u", index, handle);
730	return -ENOSYS;
731}
732
733static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
734{
735	char addr[18];
736
737	ba2str(bdaddr, addr);
738	DBG("index %d addr %s pin %s", index, addr, pin);
739
740	return -ENOSYS;
741}
742
743static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
744{
745	char addr[18];
746
747	ba2str(bdaddr, addr);
748	DBG("index %d addr %s success %d", index, addr, success);
749
750	return -ENOSYS;
751}
752
753static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
754{
755	char addr[18];
756
757	ba2str(bdaddr, addr);
758	DBG("index %d addr %s passkey %06u", index, addr, passkey);
759
760	return -ENOSYS;
761}
762
763static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth)
764{
765	char addr[18];
766
767	ba2str(bdaddr, addr);
768	DBG("index %d addr %s", index, addr);
769
770	return -ENOSYS;
771}
772
773static int mgmt_read_scan_enable(int index)
774{
775	DBG("index %d", index);
776	return -ENOSYS;
777}
778
779static int mgmt_enable_le(int index)
780{
781	DBG("index %d", index);
782	return -ENOSYS;
783}
784
785static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
786							gpointer user_data)
787{
788	char addr[18];
789
790	ba2str(dst, addr);
791	DBG("index %d addr %s", index, addr);
792
793	return -ENOSYS;
794}
795
796static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
797							uint16_t version)
798{
799	DBG("index %d vendor %u product %u version %u",
800					index, vendor, product, version);
801	return -ENOSYS;
802}
803
804static int mgmt_services_updated(int index)
805{
806	DBG("index %d", index);
807	return -ENOSYS;
808}
809
810static int mgmt_disable_cod_cache(int index)
811{
812	DBG("index %d", index);
813	return -ENOSYS;
814}
815
816static int mgmt_restore_powered(int index)
817{
818	DBG("index %d", index);
819	return -ENOSYS;
820}
821
822static int mgmt_load_keys(int index, GSList *keys)
823{
824	DBG("index %d keys %d", index, g_slist_length(keys));
825	return -ENOSYS;
826}
827
828static struct btd_adapter_ops mgmt_ops = {
829	.setup = mgmt_setup,
830	.cleanup = mgmt_cleanup,
831	.power_on = mgmt_power_on,
832	.power_off = mgmt_power_off,
833	.set_connectable = mgmt_set_connectable,
834	.set_discoverable = mgmt_set_discoverable,
835	.set_pairable = mgmt_set_pairable,
836	.set_limited_discoverable = mgmt_set_limited_discoverable,
837	.start_inquiry = mgmt_start_inquiry,
838	.stop_inquiry = mgmt_stop_inquiry,
839	.start_scanning = mgmt_start_scanning,
840	.stop_scanning = mgmt_stop_scanning,
841	.resolve_name = mgmt_resolve_name,
842	.cancel_resolve_name = mgmt_cancel_resolve_name,
843	.set_name = mgmt_set_name,
844	.set_dev_class = mgmt_set_dev_class,
845	.set_fast_connectable = mgmt_fast_connectable,
846	.read_clock = mgmt_read_clock,
847	.read_bdaddr = mgmt_read_bdaddr,
848	.block_device = mgmt_block_device,
849	.unblock_device = mgmt_unblock_device,
850	.get_conn_list = mgmt_get_conn_list,
851	.read_local_version = mgmt_read_local_version,
852	.read_local_features = mgmt_read_local_features,
853	.disconnect = mgmt_disconnect,
854	.remove_bonding = mgmt_remove_bonding,
855	.request_authentication = mgmt_request_authentication,
856	.pincode_reply = mgmt_pincode_reply,
857	.confirm_reply = mgmt_confirm_reply,
858	.passkey_reply = mgmt_passkey_reply,
859	.get_auth_info = mgmt_get_auth_info,
860	.read_scan_enable = mgmt_read_scan_enable,
861	.enable_le = mgmt_enable_le,
862	.encrypt_link = mgmt_encrypt_link,
863	.set_did = mgmt_set_did,
864	.services_updated = mgmt_services_updated,
865	.disable_cod_cache = mgmt_disable_cod_cache,
866	.restore_powered = mgmt_restore_powered,
867	.load_keys = mgmt_load_keys,
868};
869
870static int mgmt_init(void)
871{
872	return btd_register_adapter_ops(&mgmt_ops, TRUE);
873}
874
875static void mgmt_exit(void)
876{
877	btd_adapter_cleanup_ops(&mgmt_ops);
878}
879
880BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION,
881		BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit)
882