mgmtops.c revision 3c8ab480f9020f49d51f4b8eb17746b70d16b989
1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
3ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  BlueZ - Bluetooth protocol stack for Linux
4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  Copyright (C) 2010  Nokia Corporation
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  This program is free software; you can redistribute it and/or modify
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  it under the terms of the GNU General Public License as published by
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  the Free Software Foundation; either version 2 of the License, or
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  (at your option) any later version.
12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  This program is distributed in the hope that it will be useful,
14ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  GNU General Public License for more details.
17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  You should have received a copy of the GNU General Public License
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  along with this program; if not, write to the Free Software
20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
22ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#ifdef HAVE_CONFIG_H
25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <config.h>
26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#endif
27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <stdio.h>
29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <errno.h>
30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <unistd.h>
31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <stdlib.h>
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <sys/types.h>
33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <sys/ioctl.h>
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <sys/wait.h>
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <glib.h>
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/bluetooth.h>
39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/hci.h>
40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/sdp.h>
41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/sdp_lib.h>
42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include <bluetooth/mgmt.h>
43ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "plugin.h"
45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "log.h"
46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "adapter.h"
47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "manager.h"
48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "device.h"
49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "event.h"
50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define MGMT_BUF_SIZE 1024
52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int max_index = -1;
54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic struct controller_info {
55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	gboolean valid;
56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	gboolean notified;
57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint8_t type;
58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	bdaddr_t bdaddr;
59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint8_t features[8];
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint8_t dev_class[3];
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint16_t manufacturer;
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint8_t hci_ver;
63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint16_t hci_rev;
64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	gboolean enabled;
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	gboolean connectable;
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	gboolean discoverable;
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	gboolean pairable;
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint8_t sec_mode;
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	GSList *connections;
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} *controllers = NULL;
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_sock = -1;
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic guint mgmt_watch = 0;
74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic uint8_t mgmt_version = 0;
76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic uint16_t mgmt_revision = 0;
77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void read_version_complete(int sk, void *buf, size_t len)
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_hdr hdr;
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_rp_read_version *rp = buf;
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (len < sizeof(*rp)) {
84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Too small read version complete event");
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return;
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	mgmt_revision = btohs(bt_get_unaligned(&rp->revision));
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	mgmt_version = rp->version;
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	DBG("version %u revision %u", mgmt_version, mgmt_revision);
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	memset(&hdr, 0, sizeof(hdr));
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	hdr.opcode = htobs(MGMT_OP_READ_INDEX_LIST);
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (write(sk, &hdr, sizeof(hdr)) < 0)
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Unable to read controller index list: %s (%d)",
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru						strerror(errno), errno);
98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void add_controller(uint16_t index)
101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (index > max_index) {
103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		size_t size = sizeof(struct controller_info) * (index + 1);
104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		max_index = index;
105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		controllers = g_realloc(controllers, size);
106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	memset(&controllers[index], 0, sizeof(struct controller_info));
109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	controllers[index].valid = TRUE;
111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	DBG("Added controller %u", index);
113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void read_info(int sk, uint16_t index)
116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_read_info)];
118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_hdr *hdr = (void *) buf;
119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_cp_read_info *cp = (void *) &buf[sizeof(*hdr)];
120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	memset(buf, 0, sizeof(buf));
122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	hdr->opcode = htobs(MGMT_OP_READ_INFO);
123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	hdr->len = htobs(sizeof(*cp));
124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	cp->index = htobs(index);
126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (write(sk, buf, sizeof(buf)) < 0)
128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Unable to send read_info command: %s (%d)",
129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru						strerror(errno), errno);
130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void get_connections(int sk, uint16_t index)
133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_get_connections)];
135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_hdr *hdr = (void *) buf;
136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_cp_get_connections *cp = (void *) &buf[sizeof(*hdr)];
137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	memset(buf, 0, sizeof(buf));
139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	hdr->opcode = htobs(MGMT_OP_GET_CONNECTIONS);
140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	hdr->len = htobs(sizeof(*cp));
141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	cp->index = htobs(index);
143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (write(sk, buf, sizeof(buf)) < 0)
145ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Unable to send get_connections command: %s (%d)",
146ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru						strerror(errno), errno);
147ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_index_added(int sk, void *buf, size_t len)
150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_ev_index_added *ev = buf;
152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint16_t index;
153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (len < sizeof(*ev)) {
155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Too small index added event");
156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return;
157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	index = btohs(bt_get_unaligned(&ev->index));
160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	add_controller(index);
162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	read_info(sk, index);
163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void remove_controller(uint16_t index)
166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (index > max_index)
168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return;
169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (!controllers[index].valid)
171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return;
172ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	btd_manager_unregister_adapter(index);
174ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	memset(&controllers[index], 0, sizeof(struct controller_info));
176ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	DBG("Removed controller %u", index);
178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_index_removed(int sk, void *buf, size_t len)
181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_ev_index_removed *ev = buf;
183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint16_t index;
184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (len < sizeof(*ev)) {
186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Too small index removed event");
187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return;
188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	index = btohs(bt_get_unaligned(&ev->index));
191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	remove_controller(index);
193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_set_mode(int index, uint16_t opcode, uint8_t val)
196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_mode)];
198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_hdr *hdr = (void *) buf;
199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_mode *cp = (void *) &buf[sizeof(*hdr)];
200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	memset(buf, 0, sizeof(buf));
202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	hdr->opcode = htobs(opcode);
203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	hdr->len = htobs(sizeof(*cp));
204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	cp->index = htobs(index);
206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	cp->val = val;
207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return -errno;
210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
211ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	return 0;
212ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
213ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
214ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_set_connectable(int index, gboolean connectable)
215ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
216ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	DBG("index %d connectable %d", index, connectable);
217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	return mgmt_set_mode(index, MGMT_OP_SET_CONNECTABLE, connectable);
218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_set_discoverable(int index, gboolean discoverable)
221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	DBG("index %d discoverable %d", index, discoverable);
223ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	return mgmt_set_mode(index, MGMT_OP_SET_DISCOVERABLE, discoverable);
224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_set_pairable(int index, gboolean pairable)
227ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
228ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	DBG("index %d pairable %d", index, pairable);
229ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	return mgmt_set_mode(index, MGMT_OP_SET_PAIRABLE, pairable);
230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
231ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int mgmt_update_powered(int index, uint8_t powered)
233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct controller_info *info;
235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct btd_adapter *adapter;
236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	gboolean pairable, discoverable;
237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint8_t on_mode;
238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (index > max_index) {
240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Unexpected index %u", index);
241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return -ENODEV;
242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	info = &controllers[index];
245ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
246ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	info->enabled = powered;
247ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
248ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	adapter = manager_find_adapter(&info->bdaddr);
249ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (adapter == NULL) {
250ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		DBG("Adapter not found");
251ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return -ENODEV;
252ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (!powered) {
255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		info->connectable = FALSE;
256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		info->pairable = FALSE;
257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		info->discoverable = FALSE;
258ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
259ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		btd_adapter_stop(adapter);
260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return 0;
261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	btd_adapter_start(adapter);
264ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
265ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	btd_adapter_get_mode(adapter, NULL, &on_mode, &pairable);
266ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
267ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	discoverable = (on_mode == MODE_DISCOVERABLE);
268ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
269ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (on_mode == MODE_DISCOVERABLE && !info->discoverable)
270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		mgmt_set_discoverable(index, TRUE);
271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	else if (on_mode == MODE_CONNECTABLE && !info->connectable)
272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		mgmt_set_connectable(index, TRUE);
273ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	else {
274ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		uint8_t mode = 0;
275ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
276ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		if (info->connectable)
277ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru			mode |= SCAN_PAGE;
278ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		if (info->discoverable)
279ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru			mode |= SCAN_INQUIRY;
280ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
281ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		adapter_mode_changed(adapter, mode);
282ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
283ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
284ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (info->pairable != pairable)
285ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		mgmt_set_pairable(index, pairable);
286ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
287ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	return 0;
288ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_powered(int sk, void *buf, size_t len)
291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
292ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_mode *ev = buf;
293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint16_t index;
294ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
295ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (len < sizeof(*ev)) {
296ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Too small powered event");
297ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return;
298ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
299ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
300ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	index = btohs(bt_get_unaligned(&ev->index));
301ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
302ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	DBG("Controller %u powered %u", index, ev->val);
303ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
304ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	mgmt_update_powered(index, ev->val);
305ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
306ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
307ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_discoverable(int sk, void *buf, size_t len)
308ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
309ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_mode *ev = buf;
310ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct controller_info *info;
311ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct btd_adapter *adapter;
312ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint16_t index;
313ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	uint8_t mode;
314ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
315ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (len < sizeof(*ev)) {
316ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Too small discoverable event");
317ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return;
318ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
319ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
320ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	index = btohs(bt_get_unaligned(&ev->index));
321ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
322ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	DBG("Controller %u discoverable %u", index, ev->val);
323ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
324ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (index > max_index) {
325ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		error("Unexpected index %u in discoverable event", index);
326ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return;
327ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	}
328ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
329ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	info = &controllers[index];
330ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
331ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	info->discoverable = ev->val ? TRUE : FALSE;
332ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
333ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	adapter = manager_find_adapter(&info->bdaddr);
334ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (!adapter)
335ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		return;
336ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
337ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (info->connectable)
338ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		mode = SCAN_PAGE;
339ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	else
340ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		mode = 0;
341ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
342ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	if (info->discoverable)
343ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru		mode |= SCAN_INQUIRY;
344ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
345ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	adapter_mode_changed(adapter, mode);
346ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
347ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
348ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void mgmt_connectable(int sk, void *buf, size_t len)
349ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{
350ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct mgmt_mode *ev = buf;
351ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct controller_info *info;
352ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	struct btd_adapter *adapter;
353ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru	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, ev->old_key_type);
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, 0, &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_complete(&info->bdaddr, ev->status, &ev->bdaddr);
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	default:
1037		error("Unknown command complete for opcode %u", opcode);
1038		break;
1039	}
1040}
1041
1042static void mgmt_cmd_status(int sk, void *buf, size_t len)
1043{
1044	struct mgmt_ev_cmd_status *ev = buf;
1045	uint16_t opcode;
1046
1047	if (len < sizeof(*ev)) {
1048		error("Too small management command status event packet");
1049		return;
1050	}
1051
1052	opcode = btohs(bt_get_unaligned(&ev->opcode));
1053
1054	DBG("status %u opcode %u", ev->status, opcode);
1055}
1056
1057static void mgmt_controller_error(int sk, void *buf, size_t len)
1058{
1059	struct mgmt_ev_controller_error *ev = buf;
1060	uint16_t index;
1061
1062	if (len < sizeof(*ev)) {
1063		error("Too small management controller error event packet");
1064		return;
1065	}
1066
1067	index = btohs(bt_get_unaligned(&ev->index));
1068
1069	DBG("index %u error_code %u", index, ev->error_code);
1070}
1071
1072static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data)
1073{
1074	char buf[MGMT_BUF_SIZE];
1075	struct mgmt_hdr *hdr = (void *) buf;
1076	int sk;
1077	ssize_t ret;
1078	uint16_t len, opcode;
1079
1080	DBG("cond %d", cond);
1081
1082	if (cond & G_IO_NVAL)
1083		return FALSE;
1084
1085	sk = g_io_channel_unix_get_fd(io);
1086
1087	if (cond & (G_IO_ERR | G_IO_HUP)) {
1088		error("Error on management socket");
1089		return FALSE;
1090	}
1091
1092	ret = read(sk, buf, sizeof(buf));
1093	if (ret < 0) {
1094		error("Unable to read from management socket: %s (%d)",
1095						strerror(errno), errno);
1096		return TRUE;
1097	}
1098
1099	DBG("Received %zd bytes from management socket", ret);
1100
1101	if (ret < MGMT_HDR_SIZE) {
1102		error("Too small Management packet");
1103		return TRUE;
1104	}
1105
1106	opcode = btohs(bt_get_unaligned(&hdr->opcode));
1107	len = btohs(bt_get_unaligned(&hdr->len));
1108
1109	if (ret != MGMT_HDR_SIZE + len) {
1110		error("Packet length mismatch. ret %zd len %u", ret, len);
1111		return TRUE;
1112	}
1113
1114	switch (opcode) {
1115	case MGMT_EV_CMD_COMPLETE:
1116		mgmt_cmd_complete(sk, buf + MGMT_HDR_SIZE, len);
1117		break;
1118	case MGMT_EV_CMD_STATUS:
1119		mgmt_cmd_status(sk, buf + MGMT_HDR_SIZE, len);
1120		break;
1121	case MGMT_EV_CONTROLLER_ERROR:
1122		mgmt_controller_error(sk, buf + MGMT_HDR_SIZE, len);
1123		break;
1124	case MGMT_EV_INDEX_ADDED:
1125		mgmt_index_added(sk, buf + MGMT_HDR_SIZE, len);
1126		break;
1127	case MGMT_EV_INDEX_REMOVED:
1128		mgmt_index_removed(sk, buf + MGMT_HDR_SIZE, len);
1129		break;
1130	case MGMT_EV_POWERED:
1131		mgmt_powered(sk, buf + MGMT_HDR_SIZE, len);
1132		break;
1133	case MGMT_EV_DISCOVERABLE:
1134		mgmt_discoverable(sk, buf + MGMT_HDR_SIZE, len);
1135		break;
1136	case MGMT_EV_CONNECTABLE:
1137		mgmt_connectable(sk, buf + MGMT_HDR_SIZE, len);
1138		break;
1139	case MGMT_EV_PAIRABLE:
1140		mgmt_pairable(sk, buf + MGMT_HDR_SIZE, len);
1141		break;
1142	case MGMT_EV_NEW_KEY:
1143		mgmt_new_key(sk, buf + MGMT_HDR_SIZE, len);
1144		break;
1145	case MGMT_EV_DEVICE_CONNECTED:
1146		mgmt_device_connected(sk, buf + MGMT_HDR_SIZE, len);
1147		break;
1148	case MGMT_EV_DEVICE_DISCONNECTED:
1149		mgmt_device_disconnected(sk, buf + MGMT_HDR_SIZE, len);
1150		break;
1151	case MGMT_EV_CONNECT_FAILED:
1152		mgmt_connect_failed(sk, buf + MGMT_HDR_SIZE, len);
1153		break;
1154	case MGMT_EV_PIN_CODE_REQUEST:
1155		mgmt_pin_code_request(sk, buf + MGMT_HDR_SIZE, len);
1156		break;
1157	default:
1158		error("Unknown Management opcode %u", opcode);
1159		break;
1160	}
1161
1162	return TRUE;
1163}
1164
1165static int mgmt_setup(void)
1166{
1167	struct mgmt_hdr hdr;
1168	struct sockaddr_hci addr;
1169	GIOChannel *io;
1170	GIOCondition condition;
1171	int dd, err;
1172
1173	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
1174	if (dd < 0)
1175		return -errno;
1176
1177	memset(&addr, 0, sizeof(addr));
1178	addr.hci_family = AF_BLUETOOTH;
1179	addr.hci_dev = HCI_DEV_NONE;
1180	addr.hci_channel = HCI_CHANNEL_CONTROL;
1181
1182	if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1183		err = -errno;
1184		goto fail;
1185	}
1186
1187	memset(&hdr, 0, sizeof(hdr));
1188	hdr.opcode = htobs(MGMT_OP_READ_VERSION);
1189	if (write(dd, &hdr, sizeof(hdr)) < 0) {
1190		err = -errno;
1191		goto fail;
1192	}
1193
1194	io = g_io_channel_unix_new(dd);
1195	condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
1196	mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL);
1197	g_io_channel_unref(io);
1198
1199	mgmt_sock = dd;
1200
1201	info("Bluetooth Management interface initialized");
1202
1203	return 0;
1204
1205fail:
1206	close(dd);
1207	return err;
1208}
1209
1210static void mgmt_cleanup(void)
1211{
1212	g_free(controllers);
1213	controllers = NULL;
1214	max_index = -1;
1215
1216	if (mgmt_sock >= 0) {
1217		close(mgmt_sock);
1218		mgmt_sock = -1;
1219	}
1220
1221	if (mgmt_watch > 0) {
1222		g_source_remove(mgmt_watch);
1223		mgmt_watch = 0;
1224	}
1225}
1226
1227static int mgmt_set_dev_class(int index, uint8_t major, uint8_t minor)
1228{
1229	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_dev_class)];
1230	struct mgmt_hdr *hdr = (void *) buf;
1231	struct mgmt_cp_set_dev_class *cp = (void *) &buf[sizeof(*hdr)];
1232
1233	DBG("index %d major %u minor %u", index, major, minor);
1234
1235	memset(buf, 0, sizeof(buf));
1236	hdr->opcode = htobs(MGMT_OP_SET_DEV_CLASS);
1237	hdr->len = htobs(sizeof(*cp));
1238
1239	cp->index = htobs(index);
1240	cp->major = major;
1241	cp->minor = minor;
1242
1243	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
1244		return -errno;
1245
1246	return 0;
1247}
1248
1249static int mgmt_set_limited_discoverable(int index, gboolean limited)
1250{
1251	DBG("index %d limited %d", index, limited);
1252	return -ENOSYS;
1253}
1254
1255static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic)
1256{
1257	DBG("index %d length %u periodic %d", index, length, periodic);
1258	return -ENOSYS;
1259}
1260
1261static int mgmt_stop_inquiry(int index)
1262{
1263	DBG("index %d", index);
1264	return -ENOSYS;
1265}
1266
1267static int mgmt_start_scanning(int index)
1268{
1269	DBG("index %d", index);
1270	return -ENOSYS;
1271}
1272
1273static int mgmt_stop_scanning(int index)
1274{
1275	DBG("index %d", index);
1276	return -ENOSYS;
1277}
1278
1279static int mgmt_resolve_name(int index, bdaddr_t *bdaddr)
1280{
1281	char addr[18];
1282
1283	ba2str(bdaddr, addr);
1284	DBG("index %d addr %s", index, addr);
1285
1286	return -ENOSYS;
1287}
1288
1289static int mgmt_set_name(int index, const char *name)
1290{
1291	DBG("index %d, name %s", index, name);
1292	return -ENOSYS;
1293}
1294
1295static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr)
1296{
1297	char addr[18];
1298
1299	ba2str(bdaddr, addr);
1300	DBG("index %d addr %s", index, addr);
1301
1302	return -ENOSYS;
1303}
1304
1305static int mgmt_fast_connectable(int index, gboolean enable)
1306{
1307	DBG("index %d enable %d", index, enable);
1308	return -ENOSYS;
1309}
1310
1311static int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout,
1312					uint32_t *clock, uint16_t *accuracy)
1313{
1314	char addr[18];
1315
1316	ba2str(bdaddr, addr);
1317	DBG("index %d addr %s which %d timeout %d", index, addr, which,
1318								timeout);
1319
1320	return -ENOSYS;
1321}
1322
1323static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr)
1324{
1325	char addr[18];
1326	struct controller_info *info = &controllers[index];
1327
1328	ba2str(&info->bdaddr, addr);
1329	DBG("index %d addr %s", index, addr);
1330
1331	if (!info->valid)
1332		return -ENODEV;
1333
1334	bacpy(bdaddr, &info->bdaddr);
1335
1336	return 0;
1337}
1338
1339static int mgmt_block_device(int index, bdaddr_t *bdaddr)
1340{
1341	char addr[18];
1342
1343	ba2str(bdaddr, addr);
1344	DBG("index %d addr %s", index, addr);
1345
1346	return -ENOSYS;
1347}
1348
1349static int mgmt_unblock_device(int index, bdaddr_t *bdaddr)
1350{
1351	char addr[18];
1352
1353	ba2str(bdaddr, addr);
1354	DBG("index %d addr %s", index, addr);
1355
1356	return -ENOSYS;
1357}
1358
1359static int mgmt_get_conn_list(int index, GSList **conns)
1360{
1361	struct controller_info *info = &controllers[index];
1362
1363	DBG("index %d", index);
1364
1365	*conns = info->connections;
1366	info->connections = NULL;
1367
1368	return 0;
1369}
1370
1371static int mgmt_read_local_version(int index, struct hci_version *ver)
1372{
1373	struct controller_info *info = &controllers[index];
1374
1375	DBG("index %d", index);
1376
1377	if (!info->valid)
1378		return -ENODEV;
1379
1380	memset(ver, 0, sizeof(*ver));
1381	ver->manufacturer = info->manufacturer;
1382	ver->hci_ver = info->hci_ver;
1383	ver->hci_rev = info->hci_rev;
1384
1385	return 0;
1386}
1387
1388static int mgmt_read_local_features(int index, uint8_t *features)
1389{
1390	struct controller_info *info = &controllers[index];
1391
1392	DBG("index %d", index);
1393
1394	if (!info->valid)
1395		return -ENODEV;
1396
1397	memcpy(features, info->features, 8);
1398
1399	return 0;
1400}
1401
1402static int mgmt_disconnect(int index, bdaddr_t *bdaddr)
1403{
1404	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_disconnect)];
1405	struct mgmt_hdr *hdr = (void *) buf;
1406	struct mgmt_cp_disconnect *cp = (void *) &buf[sizeof(*hdr)];
1407	char addr[18];
1408
1409	ba2str(bdaddr, addr);
1410	DBG("index %d %s", index, addr);
1411
1412	memset(buf, 0, sizeof(buf));
1413	hdr->opcode = htobs(MGMT_OP_DISCONNECT);
1414	hdr->len = htobs(sizeof(*cp));
1415
1416	cp->index = htobs(index);
1417	bacpy(&cp->bdaddr, bdaddr);
1418
1419	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
1420		error("write: %s (%d)", strerror(errno), errno);
1421
1422	return 0;
1423}
1424
1425static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
1426{
1427	char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_key)];
1428	struct mgmt_hdr *hdr = (void *) buf;
1429	struct mgmt_cp_remove_key *cp = (void *) &buf[sizeof(*hdr)];
1430	char addr[18];
1431
1432	ba2str(bdaddr, addr);
1433	DBG("index %d addr %s", index, addr);
1434
1435	memset(buf, 0, sizeof(buf));
1436	hdr->opcode = htobs(MGMT_OP_REMOVE_KEY);
1437	hdr->len = htobs(sizeof(*cp));
1438
1439	cp->index = htobs(index);
1440	bacpy(&cp->bdaddr, bdaddr);
1441	cp->disconnect = 1;
1442
1443	if (write(mgmt_sock, buf, sizeof(buf)) < 0)
1444		return -errno;
1445
1446	return 0;
1447}
1448
1449static int mgmt_request_authentication(int index, bdaddr_t *bdaddr)
1450{
1451	char addr[18];
1452
1453	ba2str(bdaddr, addr);
1454	DBG("index %d %s", index, addr);
1455
1456	return -ENOSYS;
1457}
1458
1459static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
1460{
1461	char addr[18];
1462
1463	ba2str(bdaddr, addr);
1464	DBG("index %d addr %s success %d", index, addr, success);
1465
1466	return -ENOSYS;
1467}
1468
1469static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
1470{
1471	char addr[18];
1472
1473	ba2str(bdaddr, addr);
1474	DBG("index %d addr %s passkey %06u", index, addr, passkey);
1475
1476	return -ENOSYS;
1477}
1478
1479static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth)
1480{
1481	char addr[18];
1482
1483	ba2str(bdaddr, addr);
1484	DBG("index %d addr %s", index, addr);
1485
1486	return -ENOSYS;
1487}
1488
1489static int mgmt_read_scan_enable(int index)
1490{
1491	DBG("index %d", index);
1492	return -ENOSYS;
1493}
1494
1495static int mgmt_enable_le(int index)
1496{
1497	DBG("index %d", index);
1498	return -ENOSYS;
1499}
1500
1501static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
1502							gpointer user_data)
1503{
1504	char addr[18];
1505
1506	ba2str(dst, addr);
1507	DBG("index %d addr %s", index, addr);
1508
1509	return -ENOSYS;
1510}
1511
1512static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
1513							uint16_t version)
1514{
1515	DBG("index %d vendor %u product %u version %u",
1516					index, vendor, product, version);
1517	return -ENOSYS;
1518}
1519
1520static int mgmt_disable_cod_cache(int index)
1521{
1522	DBG("index %d", index);
1523	return mgmt_set_mode(index, MGMT_OP_SET_SERVICE_CACHE, 0);
1524}
1525
1526static int mgmt_restore_powered(int index)
1527{
1528	DBG("index %d", index);
1529	return -ENOSYS;
1530}
1531
1532static int mgmt_load_keys(int index, GSList *keys, gboolean debug_keys)
1533{
1534	char *buf;
1535	struct mgmt_hdr *hdr;
1536	struct mgmt_cp_load_keys *cp;
1537	struct mgmt_key_info *key;
1538	size_t key_count, cp_size;
1539	GSList *l;
1540	int err;
1541
1542	key_count = g_slist_length(keys);
1543
1544	DBG("index %d keys %zu debug_keys %d", index, key_count, debug_keys);
1545
1546	cp_size = sizeof(*cp) + (key_count * sizeof(*key));
1547
1548	buf = g_try_malloc0(sizeof(*hdr) + cp_size);
1549	if (buf == NULL)
1550		return -ENOMEM;
1551
1552	memset(buf, 0, sizeof(buf));
1553
1554	hdr = (void *) buf;
1555	hdr->opcode = htobs(MGMT_OP_LOAD_KEYS);
1556	hdr->len = htobs(cp_size);
1557
1558	cp = (void *) (buf + sizeof(*hdr));
1559	cp->index = htobs(index);
1560	cp->debug_keys = debug_keys;
1561	cp->key_count = htobs(key_count);
1562
1563	for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
1564		struct link_key_info *info = l->data;
1565
1566		bacpy(&key->bdaddr, &info->bdaddr);
1567		key->type = info->type;
1568		memcpy(key->val, info->key, 16);
1569		key->pin_len = info->pin_len;
1570	}
1571
1572	if (write(mgmt_sock, buf, sizeof(*hdr) + cp_size) < 0)
1573		err = -errno;
1574	else
1575		err = 0;
1576
1577	g_free(buf);
1578
1579	return err;
1580}
1581
1582static struct btd_adapter_ops mgmt_ops = {
1583	.setup = mgmt_setup,
1584	.cleanup = mgmt_cleanup,
1585	.set_powered = mgmt_set_powered,
1586	.set_discoverable = mgmt_set_discoverable,
1587	.set_pairable = mgmt_set_pairable,
1588	.set_limited_discoverable = mgmt_set_limited_discoverable,
1589	.start_inquiry = mgmt_start_inquiry,
1590	.stop_inquiry = mgmt_stop_inquiry,
1591	.start_scanning = mgmt_start_scanning,
1592	.stop_scanning = mgmt_stop_scanning,
1593	.resolve_name = mgmt_resolve_name,
1594	.cancel_resolve_name = mgmt_cancel_resolve_name,
1595	.set_name = mgmt_set_name,
1596	.set_dev_class = mgmt_set_dev_class,
1597	.set_fast_connectable = mgmt_fast_connectable,
1598	.read_clock = mgmt_read_clock,
1599	.read_bdaddr = mgmt_read_bdaddr,
1600	.block_device = mgmt_block_device,
1601	.unblock_device = mgmt_unblock_device,
1602	.get_conn_list = mgmt_get_conn_list,
1603	.read_local_version = mgmt_read_local_version,
1604	.read_local_features = mgmt_read_local_features,
1605	.disconnect = mgmt_disconnect,
1606	.remove_bonding = mgmt_remove_bonding,
1607	.request_authentication = mgmt_request_authentication,
1608	.pincode_reply = mgmt_pincode_reply,
1609	.confirm_reply = mgmt_confirm_reply,
1610	.passkey_reply = mgmt_passkey_reply,
1611	.get_auth_info = mgmt_get_auth_info,
1612	.read_scan_enable = mgmt_read_scan_enable,
1613	.enable_le = mgmt_enable_le,
1614	.encrypt_link = mgmt_encrypt_link,
1615	.set_did = mgmt_set_did,
1616	.add_uuid = mgmt_add_uuid,
1617	.remove_uuid = mgmt_remove_uuid,
1618	.disable_cod_cache = mgmt_disable_cod_cache,
1619	.restore_powered = mgmt_restore_powered,
1620	.load_keys = mgmt_load_keys,
1621};
1622
1623static int mgmt_init(void)
1624{
1625	return btd_register_adapter_ops(&mgmt_ops, TRUE);
1626}
1627
1628static void mgmt_exit(void)
1629{
1630	btd_adapter_cleanup_ops(&mgmt_ops);
1631}
1632
1633BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION,
1634		BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit)
1635