xref: /netbsd/sys/netbt/hci_ioctl.c (revision fda35a52)
1 /*	$NetBSD: hci_ioctl.c,v 1.8 2009/05/03 17:21:12 elad 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.8 2009/05/03 17:21:12 elad 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 
54 static void
55 hci_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 
134 int
135 hci_ioctl(unsigned long cmd, void *data, struct lwp *l)
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 		SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
179 			if (strncmp(device_xname(unit->hci_dev),
180 			    btr->btr_name, HCI_DEVNAME_SIZE) == 0)
181 				break;
182 		}
183 
184 		if (unit == NULL)
185 			return ENXIO;
186 
187 		break;
188 
189 	default:	/* not one of mine */
190 		return EPASSTHROUGH;
191 	}
192 
193 	switch(cmd) {
194 	case SIOCNBTINFO:	/* get next info */
195 		if (unit)
196 			unit = SIMPLEQ_NEXT(unit, hci_next);
197 		else
198 			unit = SIMPLEQ_FIRST(&hci_unit_list);
199 
200 		if (unit == NULL) {
201 			err = ENXIO;
202 			break;
203 		}
204 
205 		/* and fall through to */
206 	case SIOCGBTINFO:	/* get unit info */
207 	case SIOCGBTINFOA:	/* get info by address */
208 		memset(btr, 0, sizeof(struct btreq));
209 		strlcpy(btr->btr_name, device_xname(unit->hci_dev), HCI_DEVNAME_SIZE);
210 		bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr);
211 
212 		btr->btr_flags = unit->hci_flags;
213 
214 		btr->btr_num_cmd = unit->hci_num_cmd_pkts;
215 		btr->btr_num_acl = unit->hci_num_acl_pkts;
216 		btr->btr_num_sco = unit->hci_num_sco_pkts;
217 		btr->btr_acl_mtu = unit->hci_max_acl_size;
218 		btr->btr_sco_mtu = unit->hci_max_sco_size;
219 
220 		btr->btr_packet_type = unit->hci_packet_type;
221 		btr->btr_link_policy = unit->hci_link_policy;
222 		break;
223 
224 	case SIOCSBTFLAGS:	/* set unit flags (privileged) */
225 		err = kauth_authorize_device(l->l_cred,
226 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
227 		    btr, NULL);
228 		if (err)
229 			break;
230 
231 		if ((unit->hci_flags & BTF_UP)
232 		    && (btr->btr_flags & BTF_UP) == 0) {
233 			hci_disable(unit);
234 			unit->hci_flags &= ~BTF_UP;
235 		}
236 
237 		unit->hci_flags |= (btr->btr_flags & BTF_INIT);
238 
239 		if ((unit->hci_flags & BTF_UP) == 0
240 		    && (btr->btr_flags & BTF_UP)) {
241 			err = hci_enable(unit);
242 			if (err)
243 				break;
244 
245 			unit->hci_flags |= BTF_UP;
246 		}
247 
248 		btr->btr_flags = unit->hci_flags;
249 		break;
250 
251 	case SIOCSBTPOLICY:	/* set unit link policy (privileged) */
252 		err = kauth_authorize_device(l->l_cred,
253 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
254 		    btr, NULL);
255 		if (err)
256 			break;
257 
258 		unit->hci_link_policy = btr->btr_link_policy;
259 		unit->hci_link_policy &= unit->hci_lmp_mask;
260 		btr->btr_link_policy = unit->hci_link_policy;
261 		break;
262 
263 	case SIOCSBTPTYPE:	/* set unit packet types (privileged) */
264 		err = kauth_authorize_device(l->l_cred,
265 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
266 		    btr, NULL);
267 		if (err)
268 			break;
269 
270 		unit->hci_packet_type = btr->btr_packet_type;
271 		unit->hci_packet_type &= unit->hci_acl_mask;
272 		btr->btr_packet_type = unit->hci_packet_type;
273 		break;
274 
275 	case SIOCGBTSTATS:	/* get unit statistics */
276 		(*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 0);
277 		break;
278 
279 	case SIOCZBTSTATS:	/* get & reset unit statistics */
280 		err = kauth_authorize_device(l->l_cred,
281 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
282 		    btr, NULL);
283 		if (err)
284 			break;
285 
286 		(*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 1);
287 		break;
288 
289 	case SIOCSBTSCOMTU:	/* set sco_mtu value for unit */
290 		/*
291 		 * This is a temporary ioctl and may not be supported
292 		 * in the future. The need is that if SCO packets are
293 		 * sent to USB bluetooth controllers that are not an
294 		 * integer number of frame sizes, the USB bus locks up.
295 		 */
296 		err = kauth_authorize_device(l->l_cred,
297 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
298 		    btr, NULL);
299 		if (err)
300 			break;
301 
302 		unit->hci_max_sco_size = btr->btr_sco_mtu;
303 		break;
304 
305 	default:
306 		err = EFAULT;
307 		break;
308 	}
309 
310 	return err;
311 }
312