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