sco_socket.c revision 1.3 1 /* $NetBSD: sco_socket.c,v 1.3 2006/08/28 08:19:53 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.3 2006/08/28 08:19:53 plunky 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_LISTEN:
208 return sco_listen(pcb);
209
210 case PRU_ACCEPT:
211 KASSERT(nam);
212 sa = mtod(nam, struct sockaddr_bt *);
213 nam->m_len = sizeof(struct sockaddr_bt);
214 return sco_peeraddr(pcb, sa);
215
216 case PRU_CONNECT2:
217 case PRU_SENDOOB:
218 case PRU_FASTTIMO:
219 case PRU_SLOWTIMO:
220 case PRU_PROTORCV:
221 case PRU_PROTOSEND:
222 err = EOPNOTSUPP;
223 break;
224
225 default:
226 UNKNOWN(req);
227 err = EOPNOTSUPP;
228 break;
229 }
230
231 release:
232 if (m) m_freem(m);
233 if (ctl) m_freem(ctl);
234 return err;
235 }
236
237 /*
238 * get/set socket options
239 */
240 int
241 sco_ctloutput(int req, struct socket *so, int level,
242 int optname, struct mbuf **opt)
243 {
244 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
245 struct mbuf *m;
246 int err = 0;
247
248 DPRINTFN(2, "req %s\n", prcorequests[req]);
249
250 if (pcb == NULL)
251 return EINVAL;
252
253 if (level != BTPROTO_SCO)
254 return 0;
255
256 switch(req) {
257 case PRCO_GETOPT:
258 m = m_get(M_WAIT, MT_SOOPTS);
259 m->m_len = sco_getopt(pcb, optname, mtod(m, uint8_t *));
260 if (m->m_len == 0) {
261 m_freem(m);
262 m = NULL;
263 err = EINVAL;
264 }
265 *opt = m;
266 break;
267
268 case PRCO_SETOPT:
269 m = *opt;
270 KASSERT(m != NULL);
271 err = sco_setopt(pcb, optname, mtod(m, uint8_t *));
272 m_freem(m);
273 break;
274
275 default:
276 err = EINVAL;
277 break;
278 }
279
280 return err;
281 }
282
283 /*****************************************************************************
284 *
285 * SCO Protocol socket callbacks
286 *
287 */
288 static void
289 sco_connecting(void *arg)
290 {
291 struct socket *so = arg;
292
293 DPRINTF("Connecting\n");
294 soisconnecting(so);
295 }
296
297 static void
298 sco_connected(void *arg)
299 {
300 struct socket *so = arg;
301
302 DPRINTF("Connected\n");
303 soisconnected(so);
304 }
305
306 static void
307 sco_disconnected(void *arg, int err)
308 {
309 struct socket *so = arg;
310
311 DPRINTF("Disconnected (%d)\n", err);
312
313 so->so_error = err;
314 soisdisconnected(so);
315 }
316
317 static void *
318 sco_newconn(void *arg, struct sockaddr_bt *laddr, struct sockaddr_bt *raddr)
319 {
320 struct socket *so = arg;
321
322 DPRINTF("New Connection\n");
323 so = sonewconn(so, 0);
324 if (so == NULL)
325 return NULL;
326
327 soisconnecting(so);
328 return so->so_pcb;
329 }
330
331 static void
332 sco_complete(void *arg, int num)
333 {
334 struct socket *so = arg;
335
336 while (num-- > 0)
337 sbdroprecord(&so->so_snd);
338
339 sowwakeup(so);
340 }
341
342 static void
343 sco_input(void *arg, struct mbuf *m)
344 {
345 struct socket *so = arg;
346
347 /*
348 * since this data is time sensitive, if the buffer
349 * is full we just dump data until the latest one
350 * will fit.
351 */
352
353 while (m->m_pkthdr.len > sbspace(&so->so_rcv))
354 sbdroprecord(&so->so_rcv);
355
356 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
357
358 sbappendrecord(&so->so_rcv, m);
359 sorwakeup(so);
360 }
361