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