sco_socket.c revision 1.1.4.2 1 /* $NetBSD: sco_socket.c,v 1.1.4.2 2006/06/22 03:39:50 chap Exp $ */
2
3 /*-
4 * Copyright (c) 2006 Itronix Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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.
18 *
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.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.1.4.2 2006/06/22 03:39:50 chap Exp $");
34
35 #include <sys/param.h>
36 #include <sys/domain.h>
37 #include <sys/kernel.h>
38 #include <sys/mbuf.h>
39 #include <sys/proc.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/systm.h>
44
45 #include <netbt/bluetooth.h>
46 #include <netbt/hci.h>
47 #include <netbt/sco.h>
48
49 /*******************************************************************************
50 *
51 * SCO SOCK_SEQPACKET sockets - low latency audio data
52 */
53
54 static void sco_connecting(void *);
55 static void sco_connected(void *);
56 static void sco_disconnected(void *, int);
57 static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
58 static void sco_complete(void *, int);
59 static void sco_input(void *, struct mbuf *);
60
61 static const struct btproto sco_proto = {
62 sco_connecting,
63 sco_connected,
64 sco_disconnected,
65 sco_newconn,
66 sco_complete,
67 sco_input,
68 };
69
70 int sco_sendspace = 4096;
71 int sco_recvspace = 4096;
72
73 /*
74 * User Request.
75 * up is socket
76 * m is either
77 * optional mbuf chain containing message
78 * ioctl command (PRU_CONTROL)
79 * nam is either
80 * optional mbuf chain containing an address
81 * ioctl data (PRU_CONTROL)
82 * optionally, protocol number (PRU_ATTACH)
83 * ctl is optional mbuf chain containing socket options
84 * l is pointer to process requesting action (if any)
85 *
86 * we are responsible for disposing of m and ctl if
87 * they are mbuf chains
88 */
89 int
90 sco_usrreq(struct socket *up, int req, struct mbuf *m,
91 struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
92 {
93 struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb;
94 struct sockaddr_bt *sa;
95 struct mbuf *m0;
96 int err = 0;
97
98 DPRINTFN(2, "%s\n", prurequests[req]);
99
100 switch(req) {
101 case PRU_CONTROL:
102 return EOPNOTSUPP;
103
104 case PRU_PURGEIF:
105 return EOPNOTSUPP;
106
107 case PRU_ATTACH:
108 if (pcb)
109 return EINVAL;
110
111 err = soreserve(up, sco_sendspace, sco_recvspace);
112 if (err)
113 return err;
114
115 return sco_attach((struct sco_pcb **)&up->so_pcb,
116 &sco_proto, up);
117 }
118
119 /* anything after here *requires* a pcb */
120 if (pcb == NULL) {
121 err = EINVAL;
122 goto release;
123 }
124
125 switch(req) {
126 case PRU_DISCONNECT:
127 soisdisconnecting(up);
128 return sco_disconnect(pcb, up->so_linger);
129
130 case PRU_ABORT:
131 sco_disconnect(pcb, 0);
132 soisdisconnected(up);
133 /* fall through to */
134 case PRU_DETACH:
135 return sco_detach((struct sco_pcb **)&up->so_pcb);
136
137 case PRU_BIND:
138 KASSERT(nam);
139 sa = mtod(nam, struct sockaddr_bt *);
140
141 if (sa->bt_len != sizeof(struct sockaddr_bt))
142 return EINVAL;
143
144 if (sa->bt_family != AF_BLUETOOTH)
145 return EAFNOSUPPORT;
146
147 return sco_bind(pcb, sa);
148
149 case PRU_CONNECT:
150 KASSERT(nam);
151 sa = mtod(nam, struct sockaddr_bt *);
152
153 if (sa->bt_len != sizeof(struct sockaddr_bt))
154 return EINVAL;
155
156 if (sa->bt_family != AF_BLUETOOTH)
157 return EAFNOSUPPORT;
158
159 soisconnecting(up);
160 return sco_connect(pcb, sa);
161
162 case PRU_PEERADDR:
163 KASSERT(nam);
164 sa = mtod(nam, struct sockaddr_bt *);
165 nam->m_len = sizeof(struct sockaddr_bt);
166 return sco_peeraddr(pcb, sa);
167
168 case PRU_SOCKADDR:
169 KASSERT(nam);
170 sa = mtod(nam, struct sockaddr_bt *);
171 nam->m_len = sizeof(struct sockaddr_bt);
172 return sco_sockaddr(pcb, sa);
173
174 case PRU_SHUTDOWN:
175 socantsendmore(up);
176 break;
177
178 case PRU_SEND:
179 KASSERT(m);
180 if (m->m_pkthdr.len == 0)
181 break;
182
183 if (m->m_pkthdr.len > pcb->sp_mtu) {
184 err = EMSGSIZE;
185 break;
186 }
187
188 m0 = m_copypacket(m, M_DONTWAIT);
189 if (m0 == NULL) {
190 err = ENOMEM;
191 break;
192 }
193
194 if (ctl) /* no use for that */
195 m_freem(ctl);
196
197 sbappendrecord(&up->so_snd, m);
198 return sco_send(pcb, m0);
199
200 case PRU_SENSE:
201 return 0; /* (no sense - Doh!) */
202
203 case PRU_RCVD:
204 case PRU_RCVOOB:
205 return EOPNOTSUPP; /* (no release) */
206
207 case PRU_ACCEPT:
208 KASSERT(nam);
209 sa = mtod(nam, struct sockaddr_bt *);
210 nam->m_len = sizeof(struct sockaddr_bt);
211 return sco_peeraddr(pcb, sa);
212
213 case PRU_CONNECT2:
214 case PRU_LISTEN:
215 case PRU_SENDOOB:
216 case PRU_FASTTIMO:
217 case PRU_SLOWTIMO:
218 case PRU_PROTORCV:
219 case PRU_PROTOSEND:
220 err = EOPNOTSUPP;
221 break;
222
223 default:
224 UNKNOWN(req);
225 err = EOPNOTSUPP;
226 break;
227 }
228
229 release:
230 if (m) m_freem(m);
231 if (ctl) m_freem(ctl);
232 return err;
233 }
234
235 /*
236 * get/set socket options
237 */
238 int
239 sco_ctloutput(int req, struct socket *so, int level,
240 int optname, struct mbuf **opt)
241 {
242 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
243 struct mbuf *m;
244 int err = 0;
245
246 DPRINTFN(2, "req %s\n", prcorequests[req]);
247
248 if (pcb == NULL)
249 return EINVAL;
250
251 if (level != BTPROTO_SCO)
252 return 0;
253
254 switch(req) {
255 case PRCO_GETOPT:
256 m = m_get(M_WAIT, MT_SOOPTS);
257 m->m_len = sco_getopt(pcb, optname, mtod(m, uint8_t *));
258 if (m->m_len == 0) {
259 m_freem(m);
260 m = NULL;
261 err = EINVAL;
262 }
263 *opt = m;
264 break;
265
266 case PRCO_SETOPT:
267 m = *opt;
268 KASSERT(m != NULL);
269 err = sco_setopt(pcb, optname, mtod(m, uint8_t *));
270 m_freem(m);
271 break;
272
273 default:
274 err = EINVAL;
275 break;
276 }
277
278 return err;
279 }
280
281 /*****************************************************************************
282 *
283 * SCO Protocol socket callbacks
284 *
285 */
286 static void
287 sco_connecting(void *arg)
288 {
289 struct socket *so = arg;
290
291 DPRINTF("Connecting\n");
292 soisconnecting(so);
293 }
294
295 static void
296 sco_connected(void *arg)
297 {
298 struct socket *so = arg;
299
300 DPRINTF("Connected\n");
301 soisconnected(so);
302 }
303
304 static void
305 sco_disconnected(void *arg, int err)
306 {
307 struct socket *so = arg;
308
309 DPRINTF("Disconnected (%d)\n", err);
310
311 so->so_error = err;
312 soisdisconnected(so);
313 }
314
315 static void *
316 sco_newconn(void *arg, struct sockaddr_bt *laddr, struct sockaddr_bt *raddr)
317 {
318 // struct socket *so = arg;
319
320 DPRINTF("New Connection");
321 return NULL;
322 }
323
324 static void
325 sco_complete(void *arg, int num)
326 {
327 struct socket *so = arg;
328
329 while (num-- > 0)
330 sbdroprecord(&so->so_snd);
331
332 sowwakeup(so);
333 }
334
335 static void
336 sco_input(void *arg, struct mbuf *m)
337 {
338 struct socket *so = arg;
339
340 /*
341 * since this data is time sensitive, if the buffer
342 * is full we just dump data until the latest one
343 * will fit.
344 */
345
346 while (m->m_pkthdr.len > sbspace(&so->so_rcv))
347 sbdroprecord(&so->so_rcv);
348
349 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
350
351 sbappendrecord(&so->so_rcv, m);
352 sorwakeup(so);
353 }
354