Annotation of sys/netbt/sco_upper.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: sco_upper.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ */
2: /* $NetBSD: sco_upper.c,v 1.6 2007/03/30 20:47:03 plunky Exp $ */
3:
4: /*-
5: * Copyright (c) 2006 Itronix Inc.
6: * All rights reserved.
7: *
8: * Written by Iain Hibbert for Itronix Inc.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. The name of Itronix Inc. may not be used to endorse
19: * or promote products derived from this software without specific
20: * prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
26: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29: * ON ANY THEORY OF LIABILITY, WHETHER IN
30: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32: * POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: #include <sys/cdefs.h>
36:
37: #include <sys/param.h>
38: #include <sys/kernel.h>
39: #include <sys/mbuf.h>
40: #include <sys/proc.h>
41: #include <sys/systm.h>
42:
43: #include <netbt/bluetooth.h>
44: #include <netbt/hci.h>
45: #include <netbt/sco.h>
46:
47: /****************************************************************************
48: *
49: * SCO - Upper Protocol API
50: */
51:
52: struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb);
53:
54: /*
55: * sco_attach(handle, proto, upper)
56: *
57: * Attach a new instance of SCO pcb to handle
58: */
59: int
60: sco_attach(struct sco_pcb **handle,
61: const struct btproto *proto, void *upper)
62: {
63: struct sco_pcb *pcb;
64:
65: KASSERT(handle != NULL);
66: KASSERT(proto != NULL);
67: KASSERT(upper != NULL);
68:
69: pcb = malloc(sizeof(struct sco_pcb), M_BLUETOOTH, M_NOWAIT);
70: if (pcb == NULL)
71: return ENOMEM;
72: bzero(pcb, sizeof *pcb);
73:
74: pcb->sp_proto = proto;
75: pcb->sp_upper = upper;
76:
77: LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next);
78:
79: *handle = pcb;
80: return 0;
81: }
82:
83: /*
84: * sco_bind(pcb, sockaddr)
85: *
86: * Bind SCO pcb to local address
87: */
88: int
89: sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr)
90: {
91:
92: bdaddr_copy(&pcb->sp_laddr, &addr->bt_bdaddr);
93: return 0;
94: }
95:
96: /*
97: * sco_sockaddr(pcb, sockaddr)
98: *
99: * Copy local address of PCB to sockaddr
100: */
101: int
102: sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
103: {
104:
105: memset(addr, 0, sizeof(struct sockaddr_bt));
106: addr->bt_len = sizeof(struct sockaddr_bt);
107: addr->bt_family = AF_BLUETOOTH;
108: bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_laddr);
109: return 0;
110: }
111:
112: /*
113: * sco_connect(pcb, sockaddr)
114: *
115: * Initiate a SCO connection to the destination address.
116: */
117: int
118: sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest)
119: {
120: hci_add_sco_con_cp cp;
121: struct hci_unit *unit;
122: struct hci_link *acl, *sco;
123: int err;
124:
125: if (pcb->sp_flags & SP_LISTENING)
126: return EINVAL;
127:
128: bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr);
129:
130: if (bdaddr_any(&pcb->sp_raddr))
131: return EDESTADDRREQ;
132:
133: if (bdaddr_any(&pcb->sp_laddr)) {
134: err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr);
135: if (err)
136: return err;
137: }
138:
139: unit = hci_unit_lookup(&pcb->sp_laddr);
140: if (unit == NULL)
141: return ENETDOWN;
142:
143: /*
144: * We must have an already open ACL connection before we open the SCO
145: * connection, and since SCO connections dont happen on their own we
146: * will not open one, the application wanting this should have opened
147: * it previously.
148: */
149: acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL);
150: if (acl == NULL || acl->hl_state != HCI_LINK_OPEN)
151: return EHOSTUNREACH;
152:
153: sco = hci_link_alloc(unit);
154: if (sco == NULL)
155: return ENOMEM;
156:
157: sco->hl_type = HCI_LINK_SCO;
158: bdaddr_copy(&sco->hl_bdaddr, &pcb->sp_raddr);
159:
160: sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr);
161: KASSERT(sco->hl_link == acl);
162:
163: cp.con_handle = htole16(acl->hl_handle);
164: cp.pkt_type = htole16(0x00e0); /* HV1, HV2, HV3 */
165: err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp));
166: if (err) {
167: hci_link_free(sco, err);
168: return err;
169: }
170:
171: sco->hl_sco = pcb;
172: pcb->sp_link = sco;
173:
174: pcb->sp_mtu = unit->hci_max_sco_size;
175: return 0;
176: }
177:
178: /*
179: * sco_peeraddr(pcb, sockaddr)
180: *
181: * Copy remote address of SCO pcb to sockaddr
182: */
183: int
184: sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
185: {
186:
187: memset(addr, 0, sizeof(struct sockaddr_bt));
188: addr->bt_len = sizeof(struct sockaddr_bt);
189: addr->bt_family = AF_BLUETOOTH;
190: bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_raddr);
191: return 0;
192: }
193:
194: /*
195: * sco_disconnect(pcb, linger)
196: *
197: * Initiate disconnection of connected SCO pcb
198: */
199: int
200: sco_disconnect(struct sco_pcb *pcb, int linger)
201: {
202: hci_discon_cp cp;
203: struct hci_link *sco;
204: int err;
205:
206: sco = pcb->sp_link;
207: if (sco == NULL)
208: return EINVAL;
209:
210: cp.con_handle = htole16(sco->hl_handle);
211: cp.reason = 0x13; /* "Remote User Terminated Connection" */
212:
213: err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp));
214: if (err || linger == 0) {
215: sco->hl_sco = NULL;
216: pcb->sp_link = NULL;
217: hci_link_free(sco, err);
218: }
219:
220: return err;
221: }
222:
223: /*
224: * sco_detach(handle)
225: *
226: * Detach SCO pcb from handle and clear up
227: */
228: int
229: sco_detach(struct sco_pcb **handle)
230: {
231: struct sco_pcb *pcb;
232:
233: KASSERT(handle != NULL);
234: pcb = *handle;
235: *handle = NULL;
236:
237: if (pcb == NULL)
238: return EINVAL;
239:
240: if (pcb->sp_link != NULL) {
241: sco_disconnect(pcb, 0);
242: pcb->sp_link = NULL;
243: }
244:
245: LIST_REMOVE(pcb, sp_next);
246: free(pcb, M_BLUETOOTH);
247: return 0;
248: }
249:
250: /*
251: * sco_listen(pcb)
252: *
253: * Mark pcb as a listener.
254: */
255: int
256: sco_listen(struct sco_pcb *pcb)
257: {
258:
259: if (pcb->sp_link != NULL)
260: return EINVAL;
261:
262: pcb->sp_flags |= SP_LISTENING;
263: return 0;
264: }
265:
266: /*
267: * sco_send(pcb, mbuf)
268: *
269: * Send data on SCO pcb.
270: *
271: * Gross hackage, we just output the packet directly onto the unit queue.
272: * This will work fine for one channel per unit, but for more channels it
273: * really needs fixing. We set the context so that when the packet is sent,
274: * we can drop a record from the socket buffer.
275: */
276: int
277: sco_send(struct sco_pcb *pcb, struct mbuf *m)
278: {
279: hci_scodata_hdr_t *hdr;
280: int plen;
281:
282: if (pcb->sp_link == NULL) {
283: m_freem(m);
284: return EINVAL;
285: }
286:
287: plen = m->m_pkthdr.len;
288: DPRINTFN(10, "%d bytes\n", plen);
289:
290: /*
291: * This is a temporary limitation, as USB devices cannot
292: * handle SCO packet sizes that are not an integer number
293: * of Isochronous frames. See ubt(4)
294: */
295: if (plen != pcb->sp_mtu) {
296: m_freem(m);
297: return EMSGSIZE;
298: }
299:
300: M_PREPEND(m, sizeof(hci_scodata_hdr_t), M_DONTWAIT);
301: if (m == NULL)
302: return ENOMEM;
303:
304: hdr = mtod(m, hci_scodata_hdr_t *);
305: hdr->type = HCI_SCO_DATA_PKT;
306: hdr->con_handle = htole16(pcb->sp_link->hl_handle);
307: hdr->length = plen;
308:
309: pcb->sp_pending++;
310: M_SETCTX(m, pcb->sp_link);
311: hci_output_sco(pcb->sp_link->hl_unit, m);
312:
313: return 0;
314: }
315:
316: /*
317: * sco_setopt(pcb, option, addr)
318: *
319: * Set SCO pcb options
320: */
321: int
322: sco_setopt(struct sco_pcb *pcb, int opt, void *addr)
323: {
324: int err = 0;
325:
326: switch (opt) {
327: default:
328: err = ENOPROTOOPT;
329: break;
330: }
331:
332: return err;
333: }
334:
335: /*
336: * sco_getopt(pcb, option, addr)
337: *
338: * Get SCO pcb options
339: */
340: int
341: sco_getopt(struct sco_pcb *pcb, int opt, void *addr)
342: {
343:
344: switch (opt) {
345: case SO_SCO_MTU:
346: *(uint16_t *)addr = pcb->sp_mtu;
347: return sizeof(uint16_t);
348:
349: case SO_SCO_HANDLE:
350: if (pcb->sp_link) {
351: *(uint16_t *)addr = pcb->sp_link->hl_handle;
352: return sizeof(uint16_t);
353: }
354: break;
355:
356: default:
357: break;
358: }
359: return 0;
360: }
CVSweb