mgmtops.c revision 1d555f47c40b26e52b705f3985e63a900e268757
1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2010  Nokia Corporation
6 *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <stdio.h>
29#include <errno.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <sys/types.h>
33#include <sys/ioctl.h>
34#include <sys/wait.h>
35
36#include <glib.h>
37
38#include <bluetooth/bluetooth.h>
39#include <bluetooth/hci.h>
40#include <bluetooth/mgmt.h>
41
42#include "plugin.h"
43#include "log.h"
44#include "manager.h"
45#include "adapter.h"
46#include "device.h"
47#include "event.h"
48
49#define MGMT_BUF_SIZE 1024
50
51static int mgmt_sock = -1;
52static guint mgmt_watch = 0;
53
54static void read_version_complete(int sk, void *buf, size_t len)
55{
56	struct hci_mgmt_read_version_rp *rp = buf;
57	uint16_t revision;
58
59	if (len < HCI_MGMT_READ_VERSION_RP_SIZE) {
60		error("Too small read version complete event");
61		return;
62	}
63
64	revision = btohs(bt_get_unaligned(&rp->revision));
65
66	DBG("status %u version %u revision %u", rp->status, rp->version,
67								revision);
68}
69
70static void mgmt_cmd_complete(int sk, void *buf, size_t len)
71{
72	struct hci_mgmt_cmd_complete_ev *ev = buf;
73	uint16_t opcode;
74
75	DBG("");
76
77	if (len < sizeof(*ev)) {
78		error("Too small management command complete event packet");
79		return;
80	}
81
82	opcode = btohs(bt_get_unaligned(&ev->opcode));
83
84	switch (opcode) {
85	case HCI_MGMT_OP_READ_VERSION:
86		read_version_complete(sk, ev->data, len - sizeof(*ev));
87		break;
88	default:
89		error("Unknown command complete for opcode %u", opcode);
90		break;
91	}
92}
93
94static void mgmt_cmd_status(int sk, void *buf, size_t len)
95{
96	DBG("");
97}
98
99static void mgmt_controller_error(int sk, void *buf, size_t len)
100{
101	DBG("");
102}
103
104static gboolean mgmt_event(GIOChannel *io, GIOCondition cond, gpointer user_data)
105{
106	char buf[MGMT_BUF_SIZE];
107	struct hci_mgmt_hdr *hdr = (void *) buf;
108	int sk;
109	ssize_t ret;
110	uint16_t len, opcode;
111
112	DBG("cond %d", cond);
113
114	if (cond & G_IO_NVAL)
115		return FALSE;
116
117	sk = g_io_channel_unix_get_fd(io);
118
119	if (cond & (G_IO_ERR | G_IO_HUP)) {
120		error("Error on management socket");
121		return FALSE;
122	}
123
124	ret = read(sk, buf, sizeof(buf));
125	if (ret < 0) {
126		error("Unable to read from management socket: %s (%d)",
127						strerror(errno), errno);
128		return TRUE;
129	}
130
131	DBG("Received %zd bytes from management socket", ret);
132
133	if (ret < HCI_MGMT_HDR_SIZE) {
134		error("Too small Management packet");
135		return TRUE;
136	}
137
138	opcode = btohs(bt_get_unaligned(&hdr->opcode));
139	len = btohs(bt_get_unaligned(&hdr->len));
140
141	if (ret != HCI_MGMT_HDR_SIZE + len) {
142		error("Packet length mismatch. ret %zd len %u", ret, len);
143		return TRUE;
144	}
145
146	switch (opcode) {
147	case HCI_MGMT_EV_CMD_COMPLETE:
148		mgmt_cmd_complete(sk, buf + HCI_MGMT_HDR_SIZE, len);
149		break;
150	case HCI_MGMT_EV_CMD_STATUS:
151		mgmt_cmd_status(sk, buf + HCI_MGMT_HDR_SIZE, len);
152		break;
153	case HCI_MGMT_EV_CONTROLLER_ERROR:
154		mgmt_controller_error(sk, buf + HCI_MGMT_HDR_SIZE, len);
155		break;
156	default:
157		error("Unknown Management opcode %u", opcode);
158		break;
159	}
160
161	return TRUE;
162}
163
164static int mgmt_setup(void)
165{
166	struct hci_mgmt_hdr hdr;
167	struct sockaddr_hci addr;
168	GIOChannel *io;
169	GIOCondition condition;
170	int dd, err;
171
172	dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
173	if (dd < 0)
174		return -errno;
175
176	memset(&addr, 0, sizeof(addr));
177	addr.hci_family = AF_BLUETOOTH;
178	addr.hci_dev = HCI_DEV_NONE;
179	addr.hci_channel = HCI_CHANNEL_CONTROL;
180
181	if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
182		err = -errno;
183		goto fail;
184	}
185
186	memset(&hdr, 0, sizeof(hdr));
187	hdr.opcode = HCI_MGMT_OP_READ_VERSION;
188	if (write(dd, &hdr, sizeof(hdr)) < 0) {
189		err = -errno;
190		goto fail;
191	}
192
193	io = g_io_channel_unix_new(dd);
194	condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
195	mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL);
196	g_io_channel_unref(io);
197
198	mgmt_sock = dd;
199
200	info("Bluetooth Management interface initialized");
201
202	return 0;
203
204fail:
205	close(dd);
206	return err;
207}
208
209static void mgmt_cleanup(void)
210{
211	if (mgmt_sock >= 0) {
212		close(mgmt_sock);
213		mgmt_sock = -1;
214	}
215
216	if (mgmt_watch > 0) {
217		g_source_remove(mgmt_watch);
218		mgmt_watch = 0;
219	}
220}
221
222static int mgmt_start(int index)
223{
224	DBG("index %d", index);
225	return -ENOSYS;
226}
227
228static int mgmt_stop(int index)
229{
230	DBG("index %d", index);
231	return -ENOSYS;
232}
233
234static int mgmt_powered(int index, gboolean powered)
235{
236	DBG("index %d powered %d", index, powered);
237	return -ENOSYS;
238}
239
240static int mgmt_connectable(int index)
241{
242	DBG("index %d", index);
243	return -ENOSYS;
244}
245
246static int mgmt_discoverable(int index)
247{
248	DBG("index %d", index);
249	return -ENOSYS;
250}
251
252static int mgmt_set_class(int index, uint32_t class)
253{
254	DBG("index %d class %u", index, class);
255	return -ENOSYS;
256}
257
258static int mgmt_set_limited_discoverable(int index, uint32_t class,
259							gboolean limited)
260{
261	DBG("index %d class %u, limited %d", index, class, limited);
262	return -ENOSYS;
263}
264
265static int mgmt_start_inquiry(int index, uint8_t length, gboolean periodic)
266{
267	DBG("index %d length %u periodic %d", index, length, periodic);
268	return -ENOSYS;
269}
270
271static int mgmt_stop_inquiry(int index)
272{
273	DBG("index %d", index);
274	return -ENOSYS;
275}
276
277static int mgmt_start_scanning(int index)
278{
279	DBG("index %d", index);
280	return -ENOSYS;
281}
282
283static int mgmt_stop_scanning(int index)
284{
285	DBG("index %d", index);
286	return -ENOSYS;
287}
288
289static int mgmt_resolve_name(int index, bdaddr_t *bdaddr)
290{
291	char addr[18];
292
293	ba2str(bdaddr, addr);
294	DBG("index %d addr %s", index, addr);
295
296	return -ENOSYS;
297}
298
299static int mgmt_set_name(int index, const char *name)
300{
301	DBG("index %d, name %s", index, name);
302	return -ENOSYS;
303}
304
305static int mgmt_read_name(int index)
306{
307	DBG("index %d", index);
308	return -ENOSYS;
309}
310
311static int mgmt_cancel_resolve_name(int index, bdaddr_t *bdaddr)
312{
313	char addr[18];
314
315	ba2str(bdaddr, addr);
316	DBG("index %d addr %s", index, addr);
317
318	return -ENOSYS;
319}
320
321static int mgmt_fast_connectable(int index, gboolean enable)
322{
323	DBG("index %d enable %d", index, enable);
324	return -ENOSYS;
325}
326
327static int mgmt_read_clock(int index, int handle, int which, int timeout,
328					uint32_t *clock, uint16_t *accuracy)
329{
330	DBG("index %d handle %d which %d timeout %d", index, handle,
331							which, timeout);
332	return -ENOSYS;
333}
334
335static int mgmt_conn_handle(int index, const bdaddr_t *bdaddr, int *handle)
336{
337	char addr[18];
338
339	ba2str(bdaddr, addr);
340	DBG("index %d addr %s", index, addr);
341
342	return -ENOSYS;
343}
344
345static int mgmt_write_eir_data(int index, uint8_t *data)
346{
347	DBG("index %d", index);
348	return -ENOSYS;
349}
350
351static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr)
352{
353	char addr[18];
354
355	ba2str(bdaddr, addr);
356	DBG("index %d addr %s", index, addr);
357
358	return -ENOSYS;
359}
360
361static int mgmt_set_event_mask(int index, uint8_t *events, size_t count)
362{
363	DBG("index %d", index);
364	return -ENOSYS;
365}
366
367static int mgmt_write_inq_mode(int index, uint8_t mode)
368{
369	DBG("index %d mode %u", index, mode);
370	return -ENOSYS;
371}
372
373static int mgmt_read_inq_tx_pwr(int index)
374{
375	DBG("index %d", index);
376	return -ENOSYS;
377}
378
379static int mgmt_block_device(int index, bdaddr_t *bdaddr)
380{
381	char addr[18];
382
383	ba2str(bdaddr, addr);
384	DBG("index %d addr %s", index, addr);
385
386	return -ENOSYS;
387}
388
389static int mgmt_unblock_device(int index, bdaddr_t *bdaddr)
390{
391	char addr[18];
392
393	ba2str(bdaddr, addr);
394	DBG("index %d addr %s", index, addr);
395
396	return -ENOSYS;
397}
398
399static int mgmt_get_conn_list(int index, GSList **conns)
400{
401	DBG("index %d", index);
402	return -ENOSYS;
403}
404
405static int mgmt_read_local_version(int index, struct hci_version *ver)
406{
407	DBG("index %d", index);
408	return -ENOSYS;
409}
410
411static int mgmt_read_local_features(int index, uint8_t *features)
412{
413	DBG("index %d", index);
414	return -ENOSYS;
415}
416
417static int mgmt_read_local_ext_features(int index)
418{
419	DBG("index %d", index);
420	return -ENOSYS;
421}
422
423static int mgmt_init_ssp_mode(int index, uint8_t *mode)
424{
425	DBG("index %d", index);
426	return -ENOSYS;
427}
428
429static int mgmt_read_link_policy(int index)
430{
431	DBG("index %d", index);
432	return -ENOSYS;
433}
434
435static int mgmt_disconnect(int index, uint16_t handle)
436{
437	DBG("index %d handle %u", index, handle);
438	return -ENOSYS;
439}
440
441static int mgmt_remove_bonding(int index, bdaddr_t *bdaddr)
442{
443	char addr[18];
444
445	ba2str(bdaddr, addr);
446	DBG("index %d addr %s", index, addr);
447
448	return -ENOSYS;
449}
450
451static int mgmt_request_authentication(int index, uint16_t handle,
452							uint8_t *status)
453{
454	DBG("index %d handle %u", index, handle);
455	return -ENOSYS;
456}
457
458static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin)
459{
460	char addr[18];
461
462	ba2str(bdaddr, addr);
463	DBG("index %d addr %s pin %s", index, addr, pin);
464
465	return -ENOSYS;
466}
467
468static int mgmt_confirm_reply(int index, bdaddr_t *bdaddr, gboolean success)
469{
470	char addr[18];
471
472	ba2str(bdaddr, addr);
473	DBG("index %d addr %s success %d", index, addr, success);
474
475	return -ENOSYS;
476}
477
478static int mgmt_passkey_reply(int index, bdaddr_t *bdaddr, uint32_t passkey)
479{
480	char addr[18];
481
482	ba2str(bdaddr, addr);
483	DBG("index %d addr %s passkey %06u", index, addr, passkey);
484
485	return -ENOSYS;
486}
487
488static int mgmt_get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth)
489{
490	char addr[18];
491
492	ba2str(bdaddr, addr);
493	DBG("index %d addr %s", index, addr);
494
495	return -ENOSYS;
496}
497
498static int mgmt_read_scan_enable(int index)
499{
500	DBG("index %d", index);
501	return -ENOSYS;
502}
503
504static int mgmt_read_ssp_mode(int index)
505{
506	DBG("index %d", index);
507	return -ENOSYS;
508}
509
510static int mgmt_write_le_host(int index, uint8_t le, uint8_t simul)
511{
512	DBG("index %d le %u simul %u", index, le, simul);
513	return -ENOSYS;
514}
515
516static int mgmt_get_remote_version(int index, uint16_t handle,
517							gboolean delayed)
518{
519	DBG("index %d handle %u delayed %d", index, handle, delayed);
520	return -ENOSYS;
521}
522
523static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
524							gpointer user_data)
525{
526	char addr[18];
527
528	ba2str(dst, addr);
529	DBG("index %d addr %s", index, addr);
530
531	return -ENOSYS;
532}
533
534static struct btd_adapter_ops mgmt_ops = {
535	.setup = mgmt_setup,
536	.cleanup = mgmt_cleanup,
537	.start = mgmt_start,
538	.stop = mgmt_stop,
539	.set_powered = mgmt_powered,
540	.set_connectable = mgmt_connectable,
541	.set_discoverable = mgmt_discoverable,
542	.set_limited_discoverable = mgmt_set_limited_discoverable,
543	.start_inquiry = mgmt_start_inquiry,
544	.stop_inquiry = mgmt_stop_inquiry,
545	.start_scanning = mgmt_start_scanning,
546	.stop_scanning = mgmt_stop_scanning,
547	.resolve_name = mgmt_resolve_name,
548	.cancel_resolve_name = mgmt_cancel_resolve_name,
549	.set_name = mgmt_set_name,
550	.read_name = mgmt_read_name,
551	.set_class = mgmt_set_class,
552	.set_fast_connectable = mgmt_fast_connectable,
553	.read_clock = mgmt_read_clock,
554	.get_conn_handle = mgmt_conn_handle,
555	.write_eir_data = mgmt_write_eir_data,
556	.read_bdaddr = mgmt_read_bdaddr,
557	.set_event_mask = mgmt_set_event_mask,
558	.write_inq_mode = mgmt_write_inq_mode,
559	.read_inq_tx_pwr = mgmt_read_inq_tx_pwr,
560	.block_device = mgmt_block_device,
561	.unblock_device = mgmt_unblock_device,
562	.get_conn_list = mgmt_get_conn_list,
563	.read_local_version = mgmt_read_local_version,
564	.read_local_features = mgmt_read_local_features,
565	.read_local_ext_features = mgmt_read_local_ext_features,
566	.init_ssp_mode = mgmt_init_ssp_mode,
567	.read_link_policy = mgmt_read_link_policy,
568	.disconnect = mgmt_disconnect,
569	.remove_bonding = mgmt_remove_bonding,
570	.request_authentication = mgmt_request_authentication,
571	.pincode_reply = mgmt_pincode_reply,
572	.confirm_reply = mgmt_confirm_reply,
573	.passkey_reply = mgmt_passkey_reply,
574	.get_auth_info = mgmt_get_auth_info,
575	.read_scan_enable = mgmt_read_scan_enable,
576	.read_ssp_mode = mgmt_read_ssp_mode,
577	.write_le_host = mgmt_write_le_host,
578	.get_remote_version = mgmt_get_remote_version,
579	.encrypt_link = mgmt_encrypt_link,
580};
581
582static int mgmt_init(void)
583{
584	return btd_register_adapter_ops(&mgmt_ops, TRUE);
585}
586
587static void mgmt_exit(void)
588{
589	btd_adapter_cleanup_ops(&mgmt_ops);
590}
591
592BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION,
593		BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit)
594