bge: Avoid accessing invalid internal memory region on BCM5906
[dragonfly.git] / sys / netbt / sco_upper.c
1 /* $OpenBSD: sco_upper.c,v 1.2 2007/10/01 16:39:30 krw 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/param.h>
36 #include <sys/kernel.h>
37 #include <sys/mbuf.h>
38 #include <sys/proc.h>
39 #include <sys/systm.h>
40 #include <sys/endian.h>
41 #include <sys/bus.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         KKASSERT(handle != NULL);
66         KKASSERT(proto != NULL);
67         KKASSERT(upper != NULL);
68
69         pcb = kmalloc(sizeof(*pcb), M_BLUETOOTH, M_NOWAIT | M_ZERO);
70         if (pcb == NULL)
71                 return ENOMEM;
72
73         pcb->sp_proto = proto;
74         pcb->sp_upper = upper;
75
76         LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next);
77
78         *handle = pcb;
79         return 0;
80 }
81
82 /*
83  * sco_bind(pcb, sockaddr)
84  *
85  *      Bind SCO pcb to local address
86  */
87 int
88 sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr)
89 {
90
91         bdaddr_copy(&pcb->sp_laddr, &addr->bt_bdaddr);
92         return 0;
93 }
94
95 /*
96  * sco_sockaddr(pcb, sockaddr)
97  *
98  *      Copy local address of PCB to sockaddr
99  */
100 int
101 sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
102 {
103
104         memset(addr, 0, sizeof(struct sockaddr_bt));
105         addr->bt_len = sizeof(struct sockaddr_bt);
106         addr->bt_family = AF_BLUETOOTH;
107         bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_laddr);
108         return 0;
109 }
110
111 /*
112  * sco_connect(pcb, sockaddr)
113  *
114  *      Initiate a SCO connection to the destination address.
115  */
116 int
117 sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest)
118 {
119         hci_add_sco_con_cp cp;
120         struct hci_unit *unit;
121         struct hci_link *acl, *sco;
122         int err;
123
124         if (pcb->sp_flags & SP_LISTENING)
125                 return EINVAL;
126
127         bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr);
128
129         if (bdaddr_any(&pcb->sp_raddr))
130                 return EDESTADDRREQ;
131
132         if (bdaddr_any(&pcb->sp_laddr)) {
133                 err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr);
134                 if (err)
135                         return err;
136         }
137
138         unit = hci_unit_lookup(&pcb->sp_laddr);
139         if (unit == NULL)
140                 return ENETDOWN;
141
142         /*
143          * We must have an already open ACL connection before we open the SCO
144          * connection, and since SCO connections dont happen on their own we
145          * will not open one, the application wanting this should have opened
146          * it previously.
147          */
148         acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL);
149         if (acl == NULL || acl->hl_state != HCI_LINK_OPEN)
150                 return EHOSTUNREACH;
151
152         sco = hci_link_alloc(unit);
153         if (sco == NULL)
154                 return ENOMEM;
155
156         sco->hl_type = HCI_LINK_SCO;
157         bdaddr_copy(&sco->hl_bdaddr, &pcb->sp_raddr);
158
159         sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr);
160         KKASSERT(sco->hl_link == acl);
161
162         cp.con_handle = htole16(acl->hl_handle);
163         cp.pkt_type = htole16(0x00e0);          /* HV1, HV2, HV3 */
164         err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp));
165         if (err) {
166                 hci_link_free(sco, err);
167                 return err;
168         }
169
170         sco->hl_sco = pcb;
171         pcb->sp_link = sco;
172
173         pcb->sp_mtu = unit->hci_max_sco_size;
174         return 0;
175 }
176
177 /*
178  * sco_peeraddr(pcb, sockaddr)
179  *
180  *      Copy remote address of SCO pcb to sockaddr
181  */
182 int
183 sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
184 {
185
186         memset(addr, 0, sizeof(struct sockaddr_bt));
187         addr->bt_len = sizeof(struct sockaddr_bt);
188         addr->bt_family = AF_BLUETOOTH;
189         bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_raddr);
190         return 0;
191 }
192
193 /*
194  * sco_disconnect(pcb, linger)
195  *
196  *      Initiate disconnection of connected SCO pcb
197  */
198 int
199 sco_disconnect(struct sco_pcb *pcb, int linger)
200 {
201         hci_discon_cp cp;
202         struct hci_link *sco;
203         int err;
204
205         sco = pcb->sp_link;
206         if (sco == NULL)
207                 return EINVAL;
208
209         cp.con_handle = htole16(sco->hl_handle);
210         cp.reason = 0x13;       /* "Remote User Terminated Connection" */
211
212         err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp));
213         if (err || linger == 0) {
214                 sco->hl_sco = NULL;
215                 pcb->sp_link = NULL;
216                 hci_link_free(sco, err);
217         }
218
219         return err;
220 }
221
222 /*
223  * sco_detach(handle)
224  *
225  *      Detach SCO pcb from handle and clear up
226  */
227 int
228 sco_detach(struct sco_pcb **handle)
229 {
230         struct sco_pcb *pcb;
231
232         KKASSERT(handle != NULL);
233         pcb = *handle;
234         *handle = NULL;
235
236         if (pcb == NULL)
237                 return EINVAL;
238
239         if (pcb->sp_link != NULL) {
240                 sco_disconnect(pcb, 0);
241                 pcb->sp_link = NULL;
242         }
243
244         LIST_REMOVE(pcb, sp_next);
245         kfree(pcb, M_BLUETOOTH);
246         return 0;
247 }
248
249 /*
250  * sco_listen(pcb)
251  *
252  *      Mark pcb as a listener.
253  */
254 int
255 sco_listen(struct sco_pcb *pcb)
256 {
257
258         if (pcb->sp_link != NULL)
259                 return EINVAL;
260
261         pcb->sp_flags |= SP_LISTENING;
262         return 0;
263 }
264
265 /*
266  * sco_send(pcb, mbuf)
267  *
268  *      Send data on SCO pcb.
269  *
270  * Gross hackage, we just output the packet directly onto the unit queue.
271  * This will work fine for one channel per unit, but for more channels it
272  * really needs fixing. We set the context so that when the packet is sent,
273  * we can drop a record from the socket buffer.
274  */
275 int
276 sco_send(struct sco_pcb *pcb, struct mbuf *m)
277 {
278         hci_scodata_hdr_t *hdr;
279         int plen;
280
281         if (pcb->sp_link == NULL) {
282                 m_freem(m);
283                 return EINVAL;
284         }
285
286         plen = m->m_pkthdr.len;
287         DPRINTFN(10, "%d bytes\n", plen);
288
289         /*
290          * This is a temporary limitation, as USB devices cannot
291          * handle SCO packet sizes that are not an integer number
292          * of Isochronous frames. See ubt(4)
293          */
294         if (plen != pcb->sp_mtu) {
295                 m_freem(m);
296                 return EMSGSIZE;
297         }
298
299         M_PREPEND(m, sizeof(hci_scodata_hdr_t), MB_DONTWAIT);
300         if (m == NULL)
301                 return ENOMEM;
302
303         hdr = mtod(m, hci_scodata_hdr_t *);
304         hdr->type = HCI_SCO_DATA_PKT;
305         hdr->con_handle = htole16(pcb->sp_link->hl_handle);
306         hdr->length = plen;
307
308         pcb->sp_pending++;
309         M_SETCTX(m, pcb->sp_link);
310         hci_output_sco(pcb->sp_link->hl_unit, m);
311
312         return 0;
313 }
314
315 /*
316  * sco_setopt(pcb, option, addr)
317  *
318  *      Set SCO pcb options
319  */
320 int
321 sco_setopt(struct sco_pcb *pcb, int opt, void *addr)
322 {
323         int err = 0;
324
325         switch (opt) {
326         default:
327                 err = ENOPROTOOPT;
328                 break;
329         }
330
331         return err;
332 }
333
334 /*
335  * sco_getopt(pcb, option, addr)
336  *
337  *      Get SCO pcb options
338  */
339 int
340 sco_getopt(struct sco_pcb *pcb, int opt, void *addr)
341 {
342
343         switch (opt) {
344         case SO_SCO_MTU:
345                 *(uint16_t *)addr = pcb->sp_mtu;
346                 return sizeof(uint16_t);
347
348         case SO_SCO_HANDLE:
349                 if (pcb->sp_link) {
350                         *(uint16_t *)addr = pcb->sp_link->hl_handle;
351                         return sizeof(uint16_t);
352                 }
353                 break;
354
355         default:
356                 break;
357         }
358         return 0;
359 }