1 /* $NetBSD: sco_socket.c,v 1.10 2008/04/24 11:38:37 ad Exp $ */
4 * Copyright (c) 2006 Itronix Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of Itronix Inc. may not be used to endorse
16 * or promote products derived from this software without specific
17 * prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.10 2008/04/24 11:38:37 ad Exp $");
35 /* load symbolic names */
36 #ifdef BLUETOOTH_DEBUG
41 #include <sys/param.h>
42 #include <sys/domain.h>
43 #include <sys/kernel.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/systm.h>
51 #include <netbt/bluetooth.h>
52 #include <netbt/hci.h>
53 #include <netbt/sco.h>
55 /*******************************************************************************
57 * SCO SOCK_SEQPACKET sockets - low latency audio data
60 static void sco_connecting(void *);
61 static void sco_connected(void *);
62 static void sco_disconnected(void *, int);
63 static void *sco_newconn(void *, struct sockaddr_bt
*, struct sockaddr_bt
*);
64 static void sco_complete(void *, int);
65 static void sco_linkmode(void *, int);
66 static void sco_input(void *, struct mbuf
*);
68 static const struct btproto sco_proto
= {
78 int sco_sendspace
= 4096;
79 int sco_recvspace
= 4096;
85 * optional mbuf chain containing message
86 * ioctl command (PRU_CONTROL)
88 * optional mbuf chain containing an address
89 * ioctl data (PRU_CONTROL)
90 * optionally, protocol number (PRU_ATTACH)
91 * ctl is optional mbuf chain containing socket options
92 * l is pointer to process requesting action (if any)
94 * we are responsible for disposing of m and ctl if
95 * they are mbuf chains
98 sco_usrreq(struct socket
*up
, int req
, struct mbuf
*m
,
99 struct mbuf
*nam
, struct mbuf
*ctl
, struct lwp
*l
)
101 struct sco_pcb
*pcb
= (struct sco_pcb
*)up
->so_pcb
;
102 struct sockaddr_bt
*sa
;
106 DPRINTFN(2, "%s\n", prurequests
[req
]);
116 if (up
->so_lock
== NULL
) {
117 mutex_obj_hold(bt_lock
);
118 up
->so_lock
= bt_lock
;
121 KASSERT(solocked(up
));
124 err
= soreserve(up
, sco_sendspace
, sco_recvspace
);
128 return sco_attach((struct sco_pcb
**)&up
->so_pcb
,
132 /* anything after here *requires* a pcb */
140 soisdisconnecting(up
);
141 return sco_disconnect(pcb
, up
->so_linger
);
144 sco_disconnect(pcb
, 0);
145 soisdisconnected(up
);
146 /* fall through to */
148 return sco_detach((struct sco_pcb
**)&up
->so_pcb
);
151 KASSERT(nam
!= NULL
);
152 sa
= mtod(nam
, struct sockaddr_bt
*);
154 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
))
157 if (sa
->bt_family
!= AF_BLUETOOTH
)
160 return sco_bind(pcb
, sa
);
163 KASSERT(nam
!= NULL
);
164 sa
= mtod(nam
, struct sockaddr_bt
*);
166 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
))
169 if (sa
->bt_family
!= AF_BLUETOOTH
)
173 return sco_connect(pcb
, sa
);
176 KASSERT(nam
!= NULL
);
177 sa
= mtod(nam
, struct sockaddr_bt
*);
178 nam
->m_len
= sizeof(struct sockaddr_bt
);
179 return sco_peeraddr(pcb
, sa
);
182 KASSERT(nam
!= NULL
);
183 sa
= mtod(nam
, struct sockaddr_bt
*);
184 nam
->m_len
= sizeof(struct sockaddr_bt
);
185 return sco_sockaddr(pcb
, sa
);
193 if (m
->m_pkthdr
.len
== 0)
196 if (m
->m_pkthdr
.len
> pcb
->sp_mtu
) {
201 m0
= m_copypacket(m
, M_DONTWAIT
);
207 if (ctl
) /* no use for that */
210 sbappendrecord(&up
->so_snd
, m
);
211 return sco_send(pcb
, m0
);
214 return 0; /* (no sense - Doh!) */
218 return EOPNOTSUPP
; /* (no release) */
221 return sco_listen(pcb
);
224 KASSERT(nam
!= NULL
);
225 sa
= mtod(nam
, struct sockaddr_bt
*);
226 nam
->m_len
= sizeof(struct sockaddr_bt
);
227 return sco_peeraddr(pcb
, sa
);
246 if (ctl
) m_freem(ctl
);
251 * get/set socket options
254 sco_ctloutput(int req
, struct socket
*so
, struct sockopt
*sopt
)
256 struct sco_pcb
*pcb
= (struct sco_pcb
*)so
->so_pcb
;
259 DPRINTFN(2, "req %s\n", prcorequests
[req
]);
264 if (sopt
->sopt_level
!= BTPROTO_SCO
)
269 err
= sco_getopt(pcb
, sopt
);
273 err
= sco_setopt(pcb
, sopt
);
284 /*****************************************************************************
286 * SCO Protocol socket callbacks
290 sco_connecting(void *arg
)
292 struct socket
*so
= arg
;
294 DPRINTF("Connecting\n");
299 sco_connected(void *arg
)
301 struct socket
*so
= arg
;
303 DPRINTF("Connected\n");
308 sco_disconnected(void *arg
, int err
)
310 struct socket
*so
= arg
;
312 DPRINTF("Disconnected (%d)\n", err
);
315 soisdisconnected(so
);
319 sco_newconn(void *arg
, struct sockaddr_bt
*laddr
,
320 struct sockaddr_bt
*raddr
)
322 struct socket
*so
= arg
;
324 DPRINTF("New Connection\n");
325 so
= sonewconn(so
, 0);
334 sco_complete(void *arg
, int num
)
336 struct socket
*so
= arg
;
339 sbdroprecord(&so
->so_snd
);
345 sco_linkmode(void *arg
, int mode
)
350 sco_input(void *arg
, struct mbuf
*m
)
352 struct socket
*so
= arg
;
355 * since this data is time sensitive, if the buffer
356 * is full we just dump data until the latest one
360 while (m
->m_pkthdr
.len
> sbspace(&so
->so_rcv
))
361 sbdroprecord(&so
->so_rcv
);
363 DPRINTFN(10, "received %d bytes\n", m
->m_pkthdr
.len
);
365 sbappendrecord(&so
->so_rcv
, m
);