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