Annotation of sys/netbt/hci_ioctl.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: hci_ioctl.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
2: /* $NetBSD: hci_ioctl.c,v 1.5 2007/01/04 19:07:03 elad 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/cdefs.h>
35:
36: #include <sys/param.h>
37: #include <sys/domain.h>
38: #include <sys/ioctl.h>
39: #include <sys/kernel.h>
40: #include <sys/mbuf.h>
41: #include <sys/proc.h>
42: #include <sys/systm.h>
43:
44: #include <netbt/bluetooth.h>
45: #include <netbt/hci.h>
46: #include <netbt/l2cap.h>
47: #include <netbt/rfcomm.h>
48:
49: #ifdef BLUETOOTH_DEBUG
50: #define BDADDR(bd) (bd).b[5], (bd).b[4], (bd).b[3], \
51: (bd).b[2], (bd).b[1], (bd).b[0]
52:
53: static void
54: hci_dump(void)
55: {
56: struct hci_unit *unit;
57: struct hci_link *link;
58: struct l2cap_channel *chan;
59: struct rfcomm_session *rs;
60: struct rfcomm_dlc *dlc;
61:
62: printf("HCI:\n");
63: TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
64: printf("UNIT %s: flags 0x%4.4x, "
65: "num_cmd=%d, num_acl=%d, num_sco=%d\n",
66: unit->hci_devname, unit->hci_flags,
67: unit->hci_num_cmd_pkts,
68: unit->hci_num_acl_pkts,
69: unit->hci_num_sco_pkts);
70: TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
71: printf("+HANDLE #%d: %s "
72: "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
73: "state %d, refcnt %d\n",
74: link->hl_handle,
75: (link->hl_type == HCI_LINK_ACL ? "ACL":"SCO"),
76: BDADDR(link->hl_bdaddr),
77: link->hl_state, link->hl_refcnt);
78: }
79: }
80:
81: printf("L2CAP:\n");
82: LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
83: printf("CID #%d state %d, psm=0x%4.4x, "
84: "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
85: "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
86: chan->lc_lcid, chan->lc_state, chan->lc_raddr.bt_psm,
87: BDADDR(chan->lc_laddr.bt_bdaddr),
88: BDADDR(chan->lc_raddr.bt_bdaddr));
89: }
90:
91: LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
92: printf("LISTEN psm=0x%4.4x, "
93: "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
94: chan->lc_laddr.bt_psm,
95: BDADDR(chan->lc_laddr.bt_bdaddr));
96: }
97:
98: printf("RFCOMM:\n");
99: LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
100: chan = rs->rs_l2cap;
101: printf("SESSION: state=%d, flags=0x%4.4x, psm 0x%4.4x "
102: "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
103: "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
104: rs->rs_state, rs->rs_flags, chan->lc_raddr.bt_psm,
105: BDADDR(chan->lc_laddr.bt_bdaddr),
106: BDADDR(chan->lc_raddr.bt_bdaddr));
107: LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
108: printf("+DLC channel=%d, dlci=%d, "
109: "state=%d, flags=0x%4.4x, rxcred=%d, rxsize=%ld, "
110: "txcred=%d, pending=%d, txqlen=%d\n",
111: dlc->rd_raddr.bt_channel, dlc->rd_dlci,
112: dlc->rd_state, dlc->rd_flags,
113: dlc->rd_rxcred, (unsigned long)dlc->rd_rxsize,
114: dlc->rd_txcred, dlc->rd_pending,
115: (dlc->rd_txbuf ? dlc->rd_txbuf->m_pkthdr.len : 0));
116: }
117: }
118:
119: LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
120: chan = rs->rs_l2cap;
121: printf("LISTEN: psm 0x%4.4x, "
122: "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
123: chan->lc_laddr.bt_psm,
124: BDADDR(chan->lc_laddr.bt_bdaddr));
125: LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next)
126: printf("+DLC channel=%d\n", dlc->rd_laddr.bt_channel);
127: }
128: }
129:
130: #undef BDADDR
131: #endif
132:
133: int
134: hci_ioctl(unsigned long cmd, void *data, struct proc *p)
135: {
136: struct btreq *btr = data;
137: struct hci_unit *unit;
138: int s, err = 0;
139:
140: DPRINTFN(1, "cmd %#lx\n", cmd);
141:
142: switch(cmd) {
143: #ifdef BLUETOOTH_DEBUG
144: case SIOCBTDUMP:
145: hci_dump();
146: return 0;
147: #endif
148: /*
149: * Get unit info based on address rather than name
150: */
151: case SIOCGBTINFOA:
152: unit = hci_unit_lookup(&btr->btr_bdaddr);
153: if (unit == NULL)
154: return ENXIO;
155:
156: break;
157:
158: /*
159: * The remaining ioctl's all use the same btreq structure and
160: * index on the name of the device, so we look that up first.
161: */
162: case SIOCNBTINFO:
163: /* empty name means give the first unit */
164: if (btr->btr_name[0] == '\0') {
165: unit = NULL;
166: break;
167: }
168:
169: /* else fall through and look it up */
170: case SIOCGBTINFO:
171: case SIOCSBTFLAGS:
172: case SIOCSBTPOLICY:
173: case SIOCSBTPTYPE:
174: case SIOCGBTSTATS:
175: case SIOCZBTSTATS:
176: case SIOCSBTSCOMTU:
177: TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
178: if (strncmp(unit->hci_devname, btr->btr_name,
179: HCI_DEVNAME_SIZE) == 0)
180: break;
181: }
182:
183: if (unit == NULL)
184: return ENXIO;
185:
186: break;
187:
188: default: /* not one of mine */
189: return EPASSTHROUGH;
190: }
191:
192: switch(cmd) {
193: case SIOCNBTINFO: /* get next info */
194: if (unit)
195: unit = TAILQ_NEXT(unit, hci_next);
196: else
197: unit = TAILQ_FIRST(&hci_unit_list);
198:
199: if (unit == NULL) {
200: err = ENXIO;
201: break;
202: }
203:
204: /* and fall through to */
205: case SIOCGBTINFO: /* get unit info */
206: case SIOCGBTINFOA: /* get info by address */
207: memset(btr, 0, sizeof(struct btreq));
208: strlcpy(btr->btr_name, unit->hci_devname, 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 = suser(p, 0);
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: s = splraiseipl(unit->hci_ipl);
235: unit->hci_flags |= (btr->btr_flags & BTF_INIT);
236: splx(s);
237:
238: if ((unit->hci_flags & BTF_UP) == 0
239: && (btr->btr_flags & BTF_UP)) {
240: err = hci_enable(unit);
241: if (err)
242: break;
243:
244: s = splraiseipl(unit->hci_ipl);
245: unit->hci_flags |= BTF_UP;
246: splx(s);
247: }
248:
249: btr->btr_flags = unit->hci_flags;
250: break;
251:
252: case SIOCSBTPOLICY: /* set unit link policy (privileged) */
253: err = suser(p, 0);
254: if (err)
255: break;
256:
257: unit->hci_link_policy = btr->btr_link_policy;
258: unit->hci_link_policy &= unit->hci_lmp_mask;
259: btr->btr_link_policy = unit->hci_link_policy;
260: break;
261:
262: case SIOCSBTPTYPE: /* set unit packet types (privileged) */
263: err = suser(p, 0);
264: if (err)
265: break;
266:
267: unit->hci_packet_type = btr->btr_packet_type;
268: unit->hci_packet_type &= unit->hci_acl_mask;
269: btr->btr_packet_type = unit->hci_packet_type;
270: break;
271:
272: case SIOCGBTSTATS: /* get unit statistics */
273: s = splraiseipl(unit->hci_ipl);
274: memcpy(&btr->btr_stats, &unit->hci_stats,
275: sizeof(struct bt_stats));
276: splx(s);
277: break;
278:
279: case SIOCZBTSTATS: /* get & reset unit statistics */
280: err = suser(p, 0);
281: if (err)
282: break;
283:
284: s = splraiseipl(unit->hci_ipl);
285: memcpy(&btr->btr_stats, &unit->hci_stats,
286: sizeof(struct bt_stats));
287: memset(&unit->hci_stats, 0, sizeof(struct bt_stats));
288: splx(s);
289:
290: break;
291:
292: case SIOCSBTSCOMTU: /* set sco_mtu value for unit */
293: /*
294: * This is a temporary ioctl and may not be supported
295: * in the future. The need is that if SCO packets are
296: * sent to USB bluetooth controllers that are not an
297: * integer number of frame sizes, the USB bus locks up.
298: */
299: err = suser(p, 0);
300: if (err)
301: break;
302:
303: unit->hci_max_sco_size = btr->btr_sco_mtu;
304: break;
305:
306: default:
307: err = EFAULT;
308: break;
309: }
310:
311: return err;
312: }
CVSweb