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