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