1/* $NetBSD: hci_ioctl.c,v 1.13 2015/11/28 09:04:34 plunky Exp $ */
2
3/*-
4 * Copyright (c) 2005 Iain Hibbert.
5 * Copyright (c) 2006 Itronix Inc.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of Itronix Inc. may not be used to endorse
17 * or promote products derived from this software without specific
18 * prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: hci_ioctl.c,v 1.13 2015/11/28 09:04:34 plunky Exp $");
35
36#include <sys/param.h>
37#include <sys/domain.h>
38#include <sys/ioctl.h>
39#include <sys/kauth.h>
40#include <sys/kernel.h>
41#include <sys/mbuf.h>
42#include <sys/proc.h>
43#include <sys/systm.h>
44
45#include <netbt/bluetooth.h>
46#include <netbt/hci.h>
47#include <netbt/l2cap.h>
48#include <netbt/rfcomm.h>
49
50#ifdef BLUETOOTH_DEBUG
51#define BDADDR(bd) (bd).b[5], (bd).b[4], (bd).b[3], \
52 (bd).b[2], (bd).b[1], (bd).b[0]
53
54static void
55hci_dump(void)
56{
57 struct hci_unit *unit;
58 struct hci_link *link;
59 struct l2cap_channel *chan;
60 struct rfcomm_session *rs;
61 struct rfcomm_dlc *dlc;
62
63 uprintf("HCI:\n");
64 SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
65 uprintf("UNIT %s: flags 0x%4.4x, "
66 "num_cmd=%d, num_acl=%d, num_sco=%d\n",
67 device_xname(unit->hci_dev), unit->hci_flags,
68 unit->hci_num_cmd_pkts,
69 unit->hci_num_acl_pkts,
70 unit->hci_num_sco_pkts);
71 TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
72 uprintf("+HANDLE #%d: %s "
73 "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
74 "state %d, refcnt %d\n",
75 link->hl_handle,
76 (link->hl_type == HCI_LINK_ACL ? "ACL":"SCO"),
77 BDADDR(link->hl_bdaddr),
78 link->hl_state, link->hl_refcnt);
79 }
80 }
81
82 uprintf("L2CAP:\n");
83 LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
84 uprintf("CID #%d state %d, psm=0x%4.4x, "
85 "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
86 "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
87 chan->lc_lcid, chan->lc_state, chan->lc_raddr.bt_psm,
88 BDADDR(chan->lc_laddr.bt_bdaddr),
89 BDADDR(chan->lc_raddr.bt_bdaddr));
90 }
91
92 LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
93 uprintf("LISTEN psm=0x%4.4x, "
94 "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
95 chan->lc_laddr.bt_psm,
96 BDADDR(chan->lc_laddr.bt_bdaddr));
97 }
98
99 uprintf("RFCOMM:\n");
100 LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
101 chan = rs->rs_l2cap;
102 uprintf("SESSION: state=%d, flags=0x%4.4x, psm 0x%4.4x "
103 "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
104 "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
105 rs->rs_state, rs->rs_flags, chan->lc_raddr.bt_psm,
106 BDADDR(chan->lc_laddr.bt_bdaddr),
107 BDADDR(chan->lc_raddr.bt_bdaddr));
108 LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
109 uprintf("+DLC channel=%d, dlci=%d, "
110 "state=%d, flags=0x%4.4x, rxcred=%d, rxsize=%ld, "
111 "txcred=%d, pending=%d, txqlen=%d\n",
112 dlc->rd_raddr.bt_channel, dlc->rd_dlci,
113 dlc->rd_state, dlc->rd_flags,
114 dlc->rd_rxcred, (unsigned long)dlc->rd_rxsize,
115 dlc->rd_txcred, dlc->rd_pending,
116 (dlc->rd_txbuf ? dlc->rd_txbuf->m_pkthdr.len : 0));
117 }
118 }
119
120 LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
121 chan = rs->rs_l2cap;
122 uprintf("LISTEN: psm 0x%4.4x, "
123 "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
124 chan->lc_laddr.bt_psm,
125 BDADDR(chan->lc_laddr.bt_bdaddr));
126 LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next)
127 uprintf("+DLC channel=%d\n", dlc->rd_laddr.bt_channel);
128 }
129}
130
131#undef BDADDR
132#endif
133
134int
135hci_ioctl_pcb(unsigned long cmd, void *data)
136{
137 struct btreq *btr = data;
138 struct hci_unit *unit;
139 int err = 0;
140
141 DPRINTFN(1, "cmd %#lx\n", cmd);
142
143 switch(cmd) {
144#ifdef BLUETOOTH_DEBUG
145 case SIOCBTDUMP:
146 hci_dump();
147 return 0;
148#endif
149 /*
150 * Get unit info based on address rather than name
151 */
152 case SIOCGBTINFOA:
153 unit = hci_unit_lookup(&btr->btr_bdaddr);
154 if (unit == NULL)
155 return ENXIO;
156
157 break;
158
159 /*
160 * The remaining ioctl's all use the same btreq structure and
161 * index on the name of the device, so we look that up first.
162 */
163 case SIOCNBTINFO:
164 /* empty name means give the first unit */
165 if (btr->btr_name[0] == '\0') {
166 unit = NULL;
167 break;
168 }
169
170 /* else fall through and look it up */
171 case SIOCGBTINFO:
172 case SIOCSBTFLAGS:
173 case SIOCSBTPOLICY:
174 case SIOCSBTPTYPE:
175 case SIOCGBTSTATS:
176 case SIOCZBTSTATS:
177 case SIOCSBTSCOMTU:
178 case SIOCGBTFEAT:
179 SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
180 if (strncmp(device_xname(unit->hci_dev),
181 btr->btr_name, HCI_DEVNAME_SIZE) == 0)
182 break;
183 }
184
185 if (unit == NULL)
186 return ENXIO;
187
188 break;
189
190 default: /* not one of mine */
191 return EPASSTHROUGH;
192 }
193
194 switch(cmd) {
195 case SIOCNBTINFO: /* get next info */
196 if (unit)
197 unit = SIMPLEQ_NEXT(unit, hci_next);
198 else
199 unit = SIMPLEQ_FIRST(&hci_unit_list);
200
201 if (unit == NULL) {
202 err = ENXIO;
203 break;
204 }
205
206 /* and fall through to */
207 case SIOCGBTINFO: /* get unit info */
208 case SIOCGBTINFOA: /* get info by address */
209 memset(btr, 0, sizeof(struct btreq));
210 strlcpy(btr->btr_name, device_xname(unit->hci_dev), HCI_DEVNAME_SIZE);
211 bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr);
212
213 btr->btr_flags = unit->hci_flags;
214
215 btr->btr_num_cmd = unit->hci_num_cmd_pkts;
216 btr->btr_num_acl = unit->hci_num_acl_pkts;
217 btr->btr_num_sco = unit->hci_num_sco_pkts;
218 btr->btr_acl_mtu = unit->hci_max_acl_size;
219 btr->btr_sco_mtu = unit->hci_max_sco_size;
220 btr->btr_max_acl = unit->hci_max_acl_pkts;
221 btr->btr_max_sco = unit->hci_max_sco_pkts;
222
223 btr->btr_packet_type = unit->hci_packet_type;
224 btr->btr_link_policy = unit->hci_link_policy;
225 break;
226
227 case SIOCSBTFLAGS: /* set unit flags (privileged) */
228 err = kauth_authorize_device(curlwp->l_cred,
229 KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
230 btr, NULL);
231 if (err)
232 break;
233
234 if ((unit->hci_flags & BTF_UP)
235 && (btr->btr_flags & BTF_UP) == 0) {
236 hci_disable(unit);
237 unit->hci_flags &= ~BTF_UP;
238 }
239
240 unit->hci_flags &= ~BTF_MASTER;
241 unit->hci_flags |= (btr->btr_flags & (BTF_INIT | BTF_MASTER));
242
243 if ((unit->hci_flags & BTF_UP) == 0
244 && (btr->btr_flags & BTF_UP)) {
245 err = hci_enable(unit);
246 if (err)
247 break;
248
249 unit->hci_flags |= BTF_UP;
250 }
251
252 btr->btr_flags = unit->hci_flags;
253 break;
254
255 case SIOCSBTPOLICY: /* set unit link policy (privileged) */
256 err = kauth_authorize_device(curlwp->l_cred,
257 KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
258 btr, NULL);
259 if (err)
260 break;
261
262 unit->hci_link_policy = btr->btr_link_policy;
263 unit->hci_link_policy &= unit->hci_lmp_mask;
264 btr->btr_link_policy = unit->hci_link_policy;
265 break;
266
267 case SIOCSBTPTYPE: /* set unit packet types (privileged) */
268 err = kauth_authorize_device(curlwp->l_cred,
269 KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
270 btr, NULL);
271 if (err)
272 break;
273
274 unit->hci_packet_type = btr->btr_packet_type;
275 unit->hci_packet_type &= unit->hci_acl_mask;
276 btr->btr_packet_type = unit->hci_packet_type;
277 break;
278
279 case SIOCGBTSTATS: /* get unit statistics */
280 (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 0);
281 break;
282
283 case SIOCZBTSTATS: /* get & reset unit statistics */
284 err = kauth_authorize_device(curlwp->l_cred,
285 KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
286 btr, NULL);
287 if (err)
288 break;
289
290 (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 1);
291 break;
292
293 case SIOCSBTSCOMTU: /* set sco_mtu value for unit */
294 /*
295 * This is a temporary ioctl and may not be supported
296 * in the future. The need is that if SCO packets are
297 * sent to USB bluetooth controllers that are not an
298 * integer number of frame sizes, the USB bus locks up.
299 */
300 err = kauth_authorize_device(curlwp->l_cred,
301 KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
302 btr, NULL);
303 if (err)
304 break;
305
306 unit->hci_max_sco_size = btr->btr_sco_mtu;
307 break;
308
309 case SIOCGBTFEAT: /* get unit features */
310 memset(btr, 0, sizeof(struct btreq));
311 strlcpy(btr->btr_name, device_xname(unit->hci_dev), HCI_DEVNAME_SIZE);
312 memcpy(btr->btr_features0, unit->hci_feat0, HCI_FEATURES_SIZE);
313 memcpy(btr->btr_features1, unit->hci_feat1, HCI_FEATURES_SIZE);
314 memcpy(btr->btr_features2, unit->hci_feat2, HCI_FEATURES_SIZE);
315 break;
316
317 default:
318 err = EFAULT;
319 break;
320 }
321
322 return err;
323}
324