hciops.c revision 61f0df8f18c417df50a296e10893c82b5eb83879
194e91856179a268805256055ffd5155d1468b99cAlok Barsode/*
294e91856179a268805256055ffd5155d1468b99cAlok Barsode *
394e91856179a268805256055ffd5155d1468b99cAlok Barsode *  BlueZ - Bluetooth protocol stack for Linux
494e91856179a268805256055ffd5155d1468b99cAlok Barsode *
59184e2eeb7b97371c6b83b747c8984e2340d2b47Marcel Holtmann *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
694e91856179a268805256055ffd5155d1468b99cAlok Barsode *
794e91856179a268805256055ffd5155d1468b99cAlok Barsode *  This program is free software; you can redistribute it and/or modify
894e91856179a268805256055ffd5155d1468b99cAlok Barsode *  it under the terms of the GNU General Public License as published by
994e91856179a268805256055ffd5155d1468b99cAlok Barsode *  the Free Software Foundation; either version 2 of the License, or
1094e91856179a268805256055ffd5155d1468b99cAlok Barsode *  (at your option) any later version.
1194e91856179a268805256055ffd5155d1468b99cAlok Barsode *
1294e91856179a268805256055ffd5155d1468b99cAlok Barsode *  This program is distributed in the hope that it will be useful,
1394e91856179a268805256055ffd5155d1468b99cAlok Barsode *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1494e91856179a268805256055ffd5155d1468b99cAlok Barsode *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1594e91856179a268805256055ffd5155d1468b99cAlok Barsode *  GNU General Public License for more details.
1694e91856179a268805256055ffd5155d1468b99cAlok Barsode *
1794e91856179a268805256055ffd5155d1468b99cAlok Barsode *  You should have received a copy of the GNU General Public License
1894e91856179a268805256055ffd5155d1468b99cAlok Barsode *  along with this program; if not, write to the Free Software
1994e91856179a268805256055ffd5155d1468b99cAlok Barsode *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
2094e91856179a268805256055ffd5155d1468b99cAlok Barsode *
2194e91856179a268805256055ffd5155d1468b99cAlok Barsode */
2294e91856179a268805256055ffd5155d1468b99cAlok Barsode
2394e91856179a268805256055ffd5155d1468b99cAlok Barsode#ifdef HAVE_CONFIG_H
2494e91856179a268805256055ffd5155d1468b99cAlok Barsode#include <config.h>
2594e91856179a268805256055ffd5155d1468b99cAlok Barsode#endif
26a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
27a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode#include <stdio.h>
28cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode#include <errno.h>
29a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode#include <unistd.h>
30a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode#include <stdlib.h>
31cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode#include <sys/types.h>
32cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode#include <sys/ioctl.h>
33a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode#include <sys/wait.h>
3494e91856179a268805256055ffd5155d1468b99cAlok Barsode
3594e91856179a268805256055ffd5155d1468b99cAlok Barsode#include <bluetooth/bluetooth.h>
36cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode#include <bluetooth/hci.h>
37cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode#include <bluetooth/hci_lib.h>
3894e91856179a268805256055ffd5155d1468b99cAlok Barsode
39cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode#include <glib.h>
40cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
41cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode#include "hcid.h"
42a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode#include "sdpd.h"
43a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode#include "adapter.h"
4494e91856179a268805256055ffd5155d1468b99cAlok Barsode#include "plugin.h"
45e891f7df6225c758da0d95f7554c6cc67f72f31eGustavo F. Padovan#include "log.h"
46a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode#include "manager.h"
47a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
4818e8b33f0d60b9e1f4a6521720e14e9db1cda01dJohan Hedbergstatic int child_pipe[2] = { -1, -1 };
4994e91856179a268805256055ffd5155d1468b99cAlok Barsode
508b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedbergstatic guint child_io_id = 0;
518b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedbergstatic guint ctl_io_id = 0;
528b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg
53a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsodestatic gboolean child_exit(GIOChannel *io, GIOCondition cond, void *user_data)
54a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode{
55a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	int status, fd = g_io_channel_unix_get_fd(io);
56a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	pid_t child_pid;
57a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
58a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	if (read(fd, &child_pid, sizeof(child_pid)) != sizeof(child_pid)) {
59a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		error("child_exit: unable to read child pid from pipe");
60a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		return TRUE;
61a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
62a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
63a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	if (waitpid(child_pid, &status, 0) != child_pid)
64a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		error("waitpid(%d) failed", child_pid);
65a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	else
668e58667ef0a4cda88ac64137728da28d8fdf3f0fGustavo F. Padovan		DBG("child %d exited", child_pid);
67a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
68a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	return TRUE;
69a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode}
70a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
71a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsodestatic void at_child_exit(void)
72a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode{
73a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	pid_t pid = getpid();
74a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
75a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	if (write(child_pipe[1], &pid, sizeof(pid)) != sizeof(pid))
76a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		error("unable to write to child pipe");
77a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode}
78a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
79fccdf4a50765ef5a2dbde00d95f65e94ce0a543bJohan Hedbergstatic void device_devup_setup(int index)
80a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode{
81a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	struct hci_dev_info di;
82a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	uint16_t policy;
8383003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	int dd, err;
84a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
85ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode	if (hci_devinfo(index, &di) < 0)
86a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		return;
87a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
8865bf1321203b55b11167ac8b869da28a86ce49d2David Scherba	if (ignore_device(&di))
89a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		return;
90a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
91ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode	dd = hci_open_dev(index);
92a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	if (dd < 0) {
9383003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
94a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		error("Can't open device hci%d: %s (%d)",
9583003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi						index, strerror(err), err);
96a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		return;
97a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
98a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
99a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	/* Set page timeout */
100a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	if ((main_opts.flags & (1 << HCID_SET_PAGETO))) {
101a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		write_page_timeout_cp cp;
102a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
103a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		cp.timeout = htobs(main_opts.pageto);
104a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT,
105a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode					WRITE_PAGE_TIMEOUT_CP_SIZE, &cp);
106a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
107a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
108a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	/* Set default link policy */
109a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	policy = htobs(main_opts.link_policy);
110a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	hci_send_cmd(dd, OGF_LINK_POLICY,
111a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode				OCF_WRITE_DEFAULT_LINK_POLICY, 2, &policy);
112a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
113a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	hci_close_dev(dd);
114fccdf4a50765ef5a2dbde00d95f65e94ce0a543bJohan Hedberg
115fccdf4a50765ef5a2dbde00d95f65e94ce0a543bJohan Hedberg	start_security_manager(index);
116fccdf4a50765ef5a2dbde00d95f65e94ce0a543bJohan Hedberg
117fccdf4a50765ef5a2dbde00d95f65e94ce0a543bJohan Hedberg	/* Return value 1 means ioctl(DEVDOWN) was performed */
118fccdf4a50765ef5a2dbde00d95f65e94ce0a543bJohan Hedberg	if (manager_start_adapter(index) == 1)
119fccdf4a50765ef5a2dbde00d95f65e94ce0a543bJohan Hedberg		stop_security_manager(index);
120a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode}
121a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
122ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsodestatic void init_device(int index)
123a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode{
124a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	struct hci_dev_req dr;
12565bf1321203b55b11167ac8b869da28a86ce49d2David Scherba	struct hci_dev_info di;
126a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	pid_t pid;
12783003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	int dd, err;
128a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
129a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	/* Do initialization in the separate process */
130a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	pid = fork();
131a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	switch (pid) {
132a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		case 0:
133a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode			atexit(at_child_exit);
134a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode			break;
135a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		case -1:
13683003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi			err = errno;
137a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode			error("Fork failed. Can't init device hci%d: %s (%d)",
13883003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi					index, strerror(err), err);
139a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		default:
1408e58667ef0a4cda88ac64137728da28d8fdf3f0fGustavo F. Padovan			DBG("child %d forked", pid);
141a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode			return;
142a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
143a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
144ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode	dd = hci_open_dev(index);
145a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	if (dd < 0) {
14683003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
147a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		error("Can't open device hci%d: %s (%d)",
14883003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi					index, strerror(err), err);
149a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		exit(1);
150a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
151a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
152a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	memset(&dr, 0, sizeof(dr));
153ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode	dr.dev_id = index;
154a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
155a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	/* Set link mode */
156a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	dr.dev_opt = main_opts.link_mode;
157a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0) {
15883003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
159a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		error("Can't set link mode on hci%d: %s (%d)",
16083003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi					index, strerror(err), err);
161a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
162a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
16365bf1321203b55b11167ac8b869da28a86ce49d2David Scherba	/* Set link policy for BR/EDR HCI devices */
16465bf1321203b55b11167ac8b869da28a86ce49d2David Scherba	if (hci_devinfo(index, &di) < 0)
16565bf1321203b55b11167ac8b869da28a86ce49d2David Scherba		goto fail;
16665bf1321203b55b11167ac8b869da28a86ce49d2David Scherba
16765bf1321203b55b11167ac8b869da28a86ce49d2David Scherba	if (!ignore_device(&di)) {
16865bf1321203b55b11167ac8b869da28a86ce49d2David Scherba		dr.dev_opt = main_opts.link_policy;
16965bf1321203b55b11167ac8b869da28a86ce49d2David Scherba		if (ioctl(dd, HCISETLINKPOL, (unsigned long) &dr) < 0 &&
170a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode							errno != ENETDOWN) {
17165bf1321203b55b11167ac8b869da28a86ce49d2David Scherba			error("Can't set link policy on hci%d: %s (%d)",
17265bf1321203b55b11167ac8b869da28a86ce49d2David Scherba						index, strerror(errno), errno);
17365bf1321203b55b11167ac8b869da28a86ce49d2David Scherba		}
174a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
175a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
176a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	/* Start HCI device */
177ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode	if (ioctl(dd, HCIDEVUP, index) < 0 && errno != EALREADY) {
178a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		error("Can't init device hci%d: %s (%d)",
179ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode					index, strerror(errno), errno);
180a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		goto fail;
181a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
182a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
183a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	hci_close_dev(dd);
184a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	exit(0);
185a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
186a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsodefail:
187a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	hci_close_dev(dd);
188a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	exit(1);
189a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode}
190a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
191ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsodestatic void device_devreg_setup(int index)
192a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode{
193a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	struct hci_dev_info di;
194a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	gboolean devup;
195a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
196ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode	init_device(index);
197a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
198a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	memset(&di, 0, sizeof(di));
199a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
200ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode	if (hci_devinfo(index, &di) < 0)
201a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		return;
202a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
203a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	devup = hci_test_bit(HCI_UP, &di.flags);
204a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
20565bf1321203b55b11167ac8b869da28a86ce49d2David Scherba	if (!ignore_device(&di))
206ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		manager_register_adapter(index, devup);
207a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode}
208a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
209ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsodestatic void device_event(int event, int index)
210a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode{
211a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	switch (event) {
212a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	case HCI_DEV_REG:
213ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		info("HCI dev %d registered", index);
214ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		device_devreg_setup(index);
215a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		break;
216a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
217a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	case HCI_DEV_UNREG:
218ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		info("HCI dev %d unregistered", index);
219ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		manager_unregister_adapter(index);
220a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		break;
221a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
222a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	case HCI_DEV_UP:
223ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		info("HCI dev %d up", index);
224ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		device_devup_setup(index);
225a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		break;
226a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
227a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	case HCI_DEV_DOWN:
228ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		info("HCI dev %d down", index);
229ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		manager_stop_adapter(index);
230ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode		stop_security_manager(index);
231a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode		break;
232a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
233a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode}
234cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
235ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsodestatic int init_known_adapters(int ctl)
23694e91856179a268805256055ffd5155d1468b99cAlok Barsode{
237cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	struct hci_dev_list_req *dl;
238cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	struct hci_dev_req *dr;
23918e8b33f0d60b9e1f4a6521720e14e9db1cda01dJohan Hedberg	int i, err;
240cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
241cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	dl = g_try_malloc0(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
242cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	if (!dl) {
24383003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
24418e8b33f0d60b9e1f4a6521720e14e9db1cda01dJohan Hedberg		error("Can't allocate devlist buffer: %s (%d)",
24583003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi							strerror(err), err);
24683003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		return -err;
247cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	}
248cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
249cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	dl->dev_num = HCI_MAX_DEV;
250cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	dr = dl->dev_req;
251cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
252cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
25383003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
25418e8b33f0d60b9e1f4a6521720e14e9db1cda01dJohan Hedberg		error("Can't get device list: %s (%d)",
25583003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi							strerror(err), err);
25683003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		g_free(dl);
25783003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		return -err;
258cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	}
259cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
260cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	for (i = 0; i < dl->dev_num; i++, dr++) {
261cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		device_event(HCI_DEV_REG, dr->dev_id);
262cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
26383003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		if (hci_test_bit(HCI_UP, &dr->dev_opt))
264cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode			device_event(HCI_DEV_UP, dr->dev_id);
265cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	}
266cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
267cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	g_free(dl);
26894e91856179a268805256055ffd5155d1468b99cAlok Barsode	return 0;
26994e91856179a268805256055ffd5155d1468b99cAlok Barsode}
27094e91856179a268805256055ffd5155d1468b99cAlok Barsode
271cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsodestatic gboolean io_stack_event(GIOChannel *chan, GIOCondition cond,
272cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode								gpointer data)
273cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode{
274cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
275cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	evt_stack_internal *si;
276cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	evt_si_device *sd;
277cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	hci_event_hdr *eh;
278cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	int type;
279cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	size_t len;
280cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	GIOError err;
281cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
282cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	ptr = buf;
283cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
284cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len);
285cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	if (err) {
286cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		if (err == G_IO_ERROR_AGAIN)
287cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode			return TRUE;
288cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
289cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		error("Read from control socket failed: %s (%d)",
290cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode							strerror(errno), errno);
291cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		return FALSE;
292cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	}
293cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
294cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	type = *ptr++;
295cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
296cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	if (type != HCI_EVENT_PKT)
297cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		return TRUE;
298cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
299cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	eh = (hci_event_hdr *) ptr;
300cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	if (eh->evt != EVT_STACK_INTERNAL)
301cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		return TRUE;
302cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
303cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	ptr += HCI_EVENT_HDR_SIZE;
304cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
305cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	si = (evt_stack_internal *) ptr;
306cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	switch (si->type) {
307cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	case EVT_SI_DEVICE:
308cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		sd = (void *) &si->data;
309cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		device_event(sd->event, sd->dev_id);
310cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		break;
311cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	}
312cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
313cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	return TRUE;
314cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode}
315cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
31634c4239984722c169e3e821ec5ca7c88528827bdAlok Barsodestatic int hciops_setup(void)
317cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode{
318cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	struct sockaddr_hci addr;
319cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	struct hci_filter flt;
320a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	GIOChannel *ctl_io, *child_io;
32118e8b33f0d60b9e1f4a6521720e14e9db1cda01dJohan Hedberg	int sock, err;
32218e8b33f0d60b9e1f4a6521720e14e9db1cda01dJohan Hedberg
32318e8b33f0d60b9e1f4a6521720e14e9db1cda01dJohan Hedberg	if (child_pipe[0] != -1)
32418e8b33f0d60b9e1f4a6521720e14e9db1cda01dJohan Hedberg		return -EALREADY;
325cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
326a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	if (pipe(child_pipe) < 0) {
32783003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
32883003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		error("pipe(): %s (%d)", strerror(err), err);
32983003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		return -err;
330a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	}
331a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
332a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	child_io = g_io_channel_unix_new(child_pipe[0]);
333a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	g_io_channel_set_close_on_unref(child_io, TRUE);
3348b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	child_io_id = g_io_add_watch(child_io,
3358b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg				G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
3368b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg				child_exit, NULL);
337a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode	g_io_channel_unref(child_io);
338a557e08d8c3e39439e922b1267d13c8cf34e37eaAlok Barsode
339cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	/* Create and bind HCI socket */
340cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
341cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	if (sock < 0) {
34283003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
34383003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		error("Can't open HCI socket: %s (%d)", strerror(err),
34483003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi								err);
34583003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		return -err;
346cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	}
347cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
348cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	/* Set filter */
349cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	hci_filter_clear(&flt);
350cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
351cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
352cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	if (setsockopt(sock, SOL_HCI, HCI_FILTER, &flt,
353cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode							sizeof(flt)) < 0) {
35483003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
35583003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		error("Can't set filter: %s (%d)", strerror(err), err);
35683003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		return -err;
357cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	}
358cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
359cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	memset(&addr, 0, sizeof(addr));
360cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	addr.hci_family = AF_BLUETOOTH;
361cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	addr.hci_dev = HCI_DEV_NONE;
362cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	if (bind(sock, (struct sockaddr *) &addr,
363cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode							sizeof(addr)) < 0) {
36483003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
365cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode		error("Can't bind HCI socket: %s (%d)",
36683003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi							strerror(err), err);
36783003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		return -err;
368cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	}
369cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
370cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	ctl_io = g_io_channel_unix_new(sock);
371cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	g_io_channel_set_close_on_unref(ctl_io, TRUE);
372cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
3738b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	ctl_io_id = g_io_add_watch(ctl_io, G_IO_IN, io_stack_event, NULL);
374cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
375cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	g_io_channel_unref(ctl_io);
376cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
377cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode	/* Initialize already connected devices */
378ffff055ee50ab909b61e2b904bfa71dde42ee5c7Alok Barsode	return init_known_adapters(sock);
379cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode}
380cce9e28ea1ea1cbf5f9e9027c949632ce67cd27fAlok Barsode
38134c4239984722c169e3e821ec5ca7c88528827bdAlok Barsodestatic void hciops_cleanup(void)
38234c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode{
3838b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	if (child_io_id) {
3848b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg		g_source_remove(child_io_id);
3858b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg		child_io_id = 0;
3868b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	}
3878b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg
3888b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	if (ctl_io_id) {
3898b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg		g_source_remove(ctl_io_id);
3908b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg		ctl_io_id = 0;
3918b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	}
3928b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg
3938b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	if (child_pipe[0] >= 0) {
3948b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg		close(child_pipe[0]);
3958b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg		child_pipe[0] = -1;
3968b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	}
3978b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg
3988b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	if (child_pipe[1] >= 0) {
3998b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg		close(child_pipe[1]);
4008b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg		child_pipe[1] = -1;
4018b9bab24d5e35777c6838a48d487355ad790a5f4Johan Hedberg	}
40234c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode}
40334c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode
404076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsodestatic int hciops_start(int index)
405076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode{
406076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode	int dd;
407076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode	int err = 0;
408076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode
409076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode	dd = hci_open_dev(index);
410076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode	if (dd < 0)
411076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode		return -EIO;
412076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode
413076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode	if (ioctl(dd, HCIDEVUP, index) == 0)
414076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode		goto done; /* on success */
415076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode
416076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode	if (errno != EALREADY) {
41783003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
418076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode		error("Can't init device hci%d: %s (%d)",
41983003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi				index, strerror(err), err);
420076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode	}
421076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode
422076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsodedone:
423076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode	hci_close_dev(dd);
42483003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	return -err;
425076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode}
426076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode
4274e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsodestatic int hciops_stop(int index)
4284e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode{
4294e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode	int dd;
4304e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode	int err = 0;
4314e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode
4324e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode	dd = hci_open_dev(index);
4334e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode	if (dd < 0)
4344e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode		return -EIO;
4354e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode
4364e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode	if (ioctl(dd, HCIDEVDOWN, index) == 0)
4374e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode		goto done; /* on success */
4384e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode
4394e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode	if (errno != EALREADY) {
44083003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi		err = errno;
4414e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode		error("Can't stop device hci%d: %s (%d)",
44283003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi				index, strerror(err), err);
4434e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode	}
4444e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode
4454e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsodedone:
4464e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode	hci_close_dev(dd);
44783003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	return -err;
4484e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode}
4494e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode
450030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsodestatic int hciops_powered(int index, gboolean powered)
451030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode{
45290608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	int dd, err;
453030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode	uint8_t mode = SCAN_DISABLED;
454030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode
455030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode	if (powered)
456030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode		return hciops_start(index);
457030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode
458030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode	dd = hci_open_dev(index);
459030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode	if (dd < 0)
460030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode		return -EIO;
461030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode
46290608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
463030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode					1, &mode);
46490608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	if (err < 0) {
46590608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz		err = -errno;
46690608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz		hci_close_dev(dd);
46790608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz		return err;
46890608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	}
469030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode
470030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode	hci_close_dev(dd);
471030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode
472030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode	return hciops_stop(index);
473030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode}
474030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode
4758b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsodestatic int hciops_connectable(int index)
4768b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode{
47790608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	int dd, err;
4788b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode	uint8_t mode = SCAN_PAGE;
4798b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode
4808b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode	dd = hci_open_dev(index);
4818b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode	if (dd < 0)
4828b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode		return -EIO;
4838b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode
48490608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
4858b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode					1, &mode);
48690608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	if (err < 0)
48790608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz		err = -errno;
4888b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode
4898b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode	hci_close_dev(dd);
4908b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode
49190608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	return err;
4928b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode}
4938b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode
49455927114c520807297b2fc63148aa467bed60218Alok Barsodestatic int hciops_discoverable(int index)
49555927114c520807297b2fc63148aa467bed60218Alok Barsode{
49690608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	int dd, err;
49755927114c520807297b2fc63148aa467bed60218Alok Barsode	uint8_t mode = (SCAN_PAGE | SCAN_INQUIRY);
49855927114c520807297b2fc63148aa467bed60218Alok Barsode
49955927114c520807297b2fc63148aa467bed60218Alok Barsode	dd = hci_open_dev(index);
50055927114c520807297b2fc63148aa467bed60218Alok Barsode	if (dd < 0)
50155927114c520807297b2fc63148aa467bed60218Alok Barsode		return -EIO;
50255927114c520807297b2fc63148aa467bed60218Alok Barsode
50390608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
50455927114c520807297b2fc63148aa467bed60218Alok Barsode					1, &mode);
50590608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	if (err < 0)
50690608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz		err = -errno;
50755927114c520807297b2fc63148aa467bed60218Alok Barsode
50855927114c520807297b2fc63148aa467bed60218Alok Barsode	hci_close_dev(dd);
50955927114c520807297b2fc63148aa467bed60218Alok Barsode
51090608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	return err;
51155927114c520807297b2fc63148aa467bed60218Alok Barsode}
51255927114c520807297b2fc63148aa467bed60218Alok Barsode
513d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsodestatic int hciops_set_class(int index, uint32_t class)
514d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode{
515d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	int dd, err;
516d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	write_class_of_dev_cp cp;
517d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode
518d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	dd = hci_open_dev(index);
519d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	if (dd < 0)
520d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode		return -EIO;
521d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode
522d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	memcpy(cp.dev_class, &class, 3);
523d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode
524d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
525d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode					WRITE_CLASS_OF_DEV_CP_SIZE, &cp);
526d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode
527d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	if (err < 0)
528d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode		err = -errno;
529d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode
530d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	hci_close_dev(dd);
531d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode
532d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	return err;
533d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode}
534d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode
535d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsodestatic int hciops_set_limited_discoverable(int index, uint32_t class,
536eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode							gboolean limited)
537eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode{
53890608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	int dd, err;
539eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	int num = (limited ? 2 : 1);
540eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
541d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	write_current_iac_lap_cp cp;
542d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode
543eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	/*
544eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	 * 1: giac
545eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	 * 2: giac + liac
546eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	 */
547eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	dd = hci_open_dev(index);
548eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	if (dd < 0)
549eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode		return -EIO;
550eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode
551d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	memset(&cp, 0, sizeof(cp));
552d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	cp.num_current_iac = num;
553d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	memcpy(&cp.lap, lap, num * 3);
554eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode
55590608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CURRENT_IAC_LAP,
55683003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi			(num * 3 + 1), &cp);
55790608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	if (err < 0) {
55890608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz		err = -errno;
55990608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz		hci_close_dev(dd);
56090608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz		return err;
56190608519f3701763ca00b27d6ae133d6bbb07badLuiz Augusto von Dentz	}
562eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode
563eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	hci_close_dev(dd);
564d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode
565d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	return hciops_set_class(index, class);
566eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode}
567eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode
568a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsodestatic int hciops_start_discovery(int index, gboolean periodic)
569a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode{
570a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
57183003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	int dd, err;
572a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
573a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	dd = hci_open_dev(index);
574a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	if (dd < 0)
575a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		return -EIO;
576a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
577a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	if (periodic) {
578a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		periodic_inquiry_cp cp;
579a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
580a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		memset(&cp, 0, sizeof(cp));
581a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		memcpy(&cp.lap, lap, 3);
582a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		cp.max_period = htobs(24);
583a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		cp.min_period = htobs(16);
584a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		cp.length  = 0x08;
585a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		cp.num_rsp = 0x00;
586a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
587a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		err = hci_send_cmd(dd, OGF_LINK_CTL, OCF_PERIODIC_INQUIRY,
588a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode					PERIODIC_INQUIRY_CP_SIZE, &cp);
589a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	} else {
590a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		inquiry_cp inq_cp;
591a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
592a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		memset(&inq_cp, 0, sizeof(inq_cp));
593a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		memcpy(&inq_cp.lap, lap, 3);
594a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		inq_cp.length = 0x08;
595a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		inq_cp.num_rsp = 0x00;
596a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
597a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		err = hci_send_cmd(dd, OGF_LINK_CTL, OCF_INQUIRY,
598a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode					INQUIRY_CP_SIZE, &inq_cp);
599a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	}
600a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
601a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	if (err < 0)
602a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode		err = -errno;
603a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
604a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	hci_close_dev(dd);
605a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
606a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	return err;
607a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode}
608a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode
609f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsodestatic int hciops_stop_discovery(int index)
610f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode{
611f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	struct hci_dev_info di;
61283003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	int dd, err;
613f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode
614f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	if (hci_devinfo(index, &di) < 0)
615f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode		return -errno;
616f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode
617f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	dd = hci_open_dev(index);
618f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	if (dd < 0)
619f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode		return -EIO;
620f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode
621f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	if (hci_test_bit(HCI_INQUIRY, &di.flags))
622f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode		err = hci_send_cmd(dd, OGF_LINK_CTL, OCF_INQUIRY_CANCEL,
623f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode				0, 0);
624f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	else
625f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode		err = hci_send_cmd(dd, OGF_LINK_CTL, OCF_EXIT_PERIODIC_INQUIRY,
626f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode				0, 0);
627f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	if (err < 0)
628f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode		err = -errno;
629f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode
630f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	hci_close_dev(dd);
631f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode
632f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	return err;
633f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode}
634f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode
635ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsodestatic int hciops_resolve_name(int index, bdaddr_t *bdaddr)
636ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode{
637ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	remote_name_req_cp cp;
63883003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	int dd, err;
639ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode
640ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	dd = hci_open_dev(index);
641ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	if (dd < 0)
642ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode		return -EIO;
643ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode
644ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	memset(&cp, 0, sizeof(cp));
645ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	bacpy(&cp.bdaddr, bdaddr);
646ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	cp.pscan_rep_mode = 0x02;
647ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode
648ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	err = hci_send_cmd(dd, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
649ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode					REMOTE_NAME_REQ_CP_SIZE, &cp);
650ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	if (err < 0)
651ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode		err = -errno;
652ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode
653ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	hci_close_dev(dd);
654ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode
655ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	return err;
656ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode}
657ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode
658164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsodestatic int hciops_set_name(int index, const char *name)
659164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode{
660164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	change_local_name_cp cp;
66183003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	int dd, err;
662164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode
663164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	dd = hci_open_dev(index);
664164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	if (dd < 0)
665164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode		return -EIO;
666164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode
667164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	memset(&cp, 0, sizeof(cp));
668164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	strncpy((char *) cp.name, name, sizeof(cp.name));
669164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode
670164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME,
671164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode					CHANGE_LOCAL_NAME_CP_SIZE, &cp);
672164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	if (err < 0)
673164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode		err = -errno;
674164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode
675164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	hci_close_dev(dd);
676164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode
677164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	return err;
678164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode}
679164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode
680d209c50141349ee9413d0717002af3d036db4762Alok Barsodestatic int hciops_read_name(int index)
681d209c50141349ee9413d0717002af3d036db4762Alok Barsode{
68283003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	int dd, err;
683d209c50141349ee9413d0717002af3d036db4762Alok Barsode
684d209c50141349ee9413d0717002af3d036db4762Alok Barsode	dd = hci_open_dev(index);
685d209c50141349ee9413d0717002af3d036db4762Alok Barsode	if (dd < 0)
686d209c50141349ee9413d0717002af3d036db4762Alok Barsode		return -EIO;
687d209c50141349ee9413d0717002af3d036db4762Alok Barsode
688d209c50141349ee9413d0717002af3d036db4762Alok Barsode	err = hci_send_cmd(dd, OGF_HOST_CTL, OCF_READ_LOCAL_NAME, 0, 0);
689d209c50141349ee9413d0717002af3d036db4762Alok Barsode	if (err < 0)
690d209c50141349ee9413d0717002af3d036db4762Alok Barsode		err = -errno;
691d209c50141349ee9413d0717002af3d036db4762Alok Barsode
692d209c50141349ee9413d0717002af3d036db4762Alok Barsode	hci_close_dev(dd);
693d209c50141349ee9413d0717002af3d036db4762Alok Barsode
694d209c50141349ee9413d0717002af3d036db4762Alok Barsode	return err;
695d209c50141349ee9413d0717002af3d036db4762Alok Barsode}
696d209c50141349ee9413d0717002af3d036db4762Alok Barsode
697b96f44db8e91325968a0149595b2522d4a22481aAlok Barsodestatic int hciops_cancel_resolve_name(int index, bdaddr_t *bdaddr)
698b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode{
699b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	remote_name_req_cancel_cp cp;
70083003660808c30390f21c569a5ba7dbdd8344a41Claudio Takahasi	int dd, err;
701b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode
702b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	dd = hci_open_dev(index);
703b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	if (dd < 0)
704b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode		return -EIO;
705b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode
706b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	memset(&cp, 0, sizeof(cp));
707b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	bacpy(&cp.bdaddr, bdaddr);
708b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode
709b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	err = hci_send_cmd(dd, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL,
710b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode					REMOTE_NAME_REQ_CANCEL_CP_SIZE, &cp);
711b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	if (err < 0)
712b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode		err = -errno;
713b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode
714b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	hci_close_dev(dd);
715b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode
716b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	return err;
717b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode}
718b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode
71961f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliystatic int hciops_fast_connectable(int index, gboolean enable)
72061f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy{
72161f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	int dd, err = 0;
72261f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	write_page_activity_cp cp;
72361f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	uint8_t type;
72461f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy
72561f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	if (enable) {
72661f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy		type = PAGE_SCAN_TYPE_INTERLACED;
72761f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy		cp.interval = 0x0024;	/* 22.5 msec page scan interval */
72861f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	} else {
72961f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy		type = PAGE_SCAN_TYPE_STANDARD;	/* default */
73061f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy		cp.interval = 0x0800;	/* default 1.28 sec page scan */
73161f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	}
73261f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy
73361f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	cp.window = 0x0012;	/* default 11.25 msec page scan window */
73461f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy
73561f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	dd = hci_open_dev(index);
73661f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	if (dd < 0)
73761f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy		return -EIO;
73861f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy
73961f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	if (hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_PAGE_ACTIVITY,
74061f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy					WRITE_PAGE_ACTIVITY_CP_SIZE, &cp) < 0)
74161f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy		err = -errno;
74261f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	else if (hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_PAGE_SCAN_TYPE,
74361f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy								1, &type) < 0)
74461f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy		err = -errno;
74561f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy
74661f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	hci_close_dev(dd);
74761f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy
74861f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	return err;
74961f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy}
75061f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy
75134c4239984722c169e3e821ec5ca7c88528827bdAlok Barsodestatic struct btd_adapter_ops hci_ops = {
75234c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode	.setup = hciops_setup,
75334c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode	.cleanup = hciops_cleanup,
754076540a14a41acf8eba0bdb65e2dd5d4d42c7946Alok Barsode	.start = hciops_start,
7554e71ac8617182584edf8ca57879e33d98879eb5dAlok Barsode	.stop = hciops_stop,
756030d865e4a2c9ff498a925a63264a419ff6c0780Alok Barsode	.set_powered = hciops_powered,
7578b000e17009d5b6772ab3b4367881dfcef763e7eAlok Barsode	.set_connectable = hciops_connectable,
75855927114c520807297b2fc63148aa467bed60218Alok Barsode	.set_discoverable = hciops_discoverable,
759eeba5fdb9c807191893b9e82cb4952e23df3ca56Alok Barsode	.set_limited_discoverable = hciops_set_limited_discoverable,
760a67cf482f872ae7c87de9478a471cd1e478d688fAlok Barsode	.start_discovery = hciops_start_discovery,
761f8c3e9f4a68af6e6687e754f871e03e2e8cc80b8Alok Barsode	.stop_discovery = hciops_stop_discovery,
762ef876daebf32cbe65fb4d9ec6fb1ffead60086eaAlok Barsode	.resolve_name = hciops_resolve_name,
763b96f44db8e91325968a0149595b2522d4a22481aAlok Barsode	.cancel_resolve_name = hciops_cancel_resolve_name,
764164ccf9a6641fe646d8476f6b860d5ff4905632bAlok Barsode	.set_name = hciops_set_name,
765d209c50141349ee9413d0717002af3d036db4762Alok Barsode	.read_name = hciops_read_name,
766d2a6bf00afbaeef82f9210639150e1f93cb44589Alok Barsode	.set_class = hciops_set_class,
76761f0df8f18c417df50a296e10893c82b5eb83879Dmitriy Paliy	.set_fast_connectable = hciops_fast_connectable,
76834c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode};
76934c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode
77034c4239984722c169e3e821ec5ca7c88528827bdAlok Barsodestatic int hciops_init(void)
77134c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode{
77234c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode	return btd_register_adapter_ops(&hci_ops);
77334c4239984722c169e3e821ec5ca7c88528827bdAlok Barsode}
77494e91856179a268805256055ffd5155d1468b99cAlok Barsodestatic void hciops_exit(void)
77594e91856179a268805256055ffd5155d1468b99cAlok Barsode{
776929393b82db06368ff5fa4074bc209d1d4d03a48Marcel Holtmann	btd_adapter_cleanup_ops(&hci_ops);
77794e91856179a268805256055ffd5155d1468b99cAlok Barsode}
77894e91856179a268805256055ffd5155d1468b99cAlok Barsode
77994e91856179a268805256055ffd5155d1468b99cAlok BarsodeBLUETOOTH_PLUGIN_DEFINE(hciops, VERSION,
7801ab388feb37980f1afc940c7cf530b9baadeabb1Marcel Holtmann		BLUETOOTH_PLUGIN_PRIORITY_LOW, hciops_init, hciops_exit)
781