sco_socket.c revision 1.31 1 /* $NetBSD: sco_socket.c,v 1.31 2014/08/05 07:55:32 rtr 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.31 2014/08/05 07:55:32 rtr 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_attach(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 solock(so);
92 }
93 KASSERT(solocked(so));
94
95 error = soreserve(so, sco_sendspace, sco_recvspace);
96 if (error) {
97 return error;
98 }
99 return sco_attach_pcb((struct sco_pcb **)&so->so_pcb, &sco_proto, so);
100 }
101
102 static void
103 sco_detach(struct socket *so)
104 {
105 KASSERT(so->so_pcb != NULL);
106 sco_detach_pcb((struct sco_pcb **)&so->so_pcb);
107 KASSERT(so->so_pcb == NULL);
108 }
109
110 static int
111 sco_accept(struct socket *so, struct mbuf *nam)
112 {
113 struct sco_pcb *pcb = so->so_pcb;
114 struct sockaddr_bt *sa;
115
116 KASSERT(solocked(so));
117 KASSERT(nam != NULL);
118
119 if (pcb == NULL)
120 return EINVAL;
121
122 sa = mtod(nam, struct sockaddr_bt *);
123 nam->m_len = sizeof(struct sockaddr_bt);
124 return sco_peeraddr_pcb(pcb, sa);
125 }
126
127 static int
128 sco_bind(struct socket *so, struct mbuf *nam, struct lwp *l)
129 {
130 struct sco_pcb *pcb = so->so_pcb;
131 struct sockaddr_bt *sa;
132
133 KASSERT(solocked(so));
134 KASSERT(nam != NULL);
135
136 if (pcb == NULL)
137 return EINVAL;
138
139 sa = mtod(nam, struct sockaddr_bt *);
140 if (sa->bt_len != sizeof(struct sockaddr_bt))
141 return EINVAL;
142
143 if (sa->bt_family != AF_BLUETOOTH)
144 return EAFNOSUPPORT;
145
146 return sco_bind_pcb(pcb, sa);
147 }
148
149 static int
150 sco_listen(struct socket *so, struct lwp *l)
151 {
152 struct sco_pcb *pcb = so->so_pcb;
153
154 KASSERT(solocked(so));
155
156 if (pcb == NULL)
157 return EINVAL;
158
159 return sco_listen_pcb(pcb);
160 }
161
162 static int
163 sco_connect(struct socket *so, struct mbuf *nam, struct lwp *l)
164 {
165 struct sco_pcb *pcb = so->so_pcb;
166 struct sockaddr_bt *sa;
167
168 KASSERT(solocked(so));
169 KASSERT(nam != NULL);
170
171 if (pcb == NULL)
172 return EINVAL;
173
174 sa = mtod(nam, struct sockaddr_bt *);
175 if (sa->bt_len != sizeof(struct sockaddr_bt))
176 return EINVAL;
177
178 if (sa->bt_family != AF_BLUETOOTH)
179 return EAFNOSUPPORT;
180
181 soisconnecting(so);
182 return sco_connect_pcb(pcb, sa);
183 }
184
185 static int
186 sco_disconnect(struct socket *so)
187 {
188 struct sco_pcb *pcb = so->so_pcb;
189
190 KASSERT(solocked(so));
191
192 if (pcb == NULL)
193 return EINVAL;
194
195 soisdisconnecting(so);
196 return sco_disconnect_pcb(pcb, so->so_linger);
197 }
198
199 static int
200 sco_shutdown(struct socket *so)
201 {
202 KASSERT(solocked(so));
203
204 socantsendmore(so);
205 return 0;
206 }
207
208 static int
209 sco_abort(struct socket *so)
210 {
211 struct sco_pcb *pcb = so->so_pcb;
212
213 KASSERT(solocked(so));
214
215 if (pcb == NULL)
216 return EINVAL;
217
218 sco_disconnect_pcb(pcb, 0);
219 soisdisconnected(so);
220 sco_detach(so);
221 return 0;
222 }
223
224 static int
225 sco_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
226 {
227 return EOPNOTSUPP;
228 }
229
230 static int
231 sco_stat(struct socket *so, struct stat *ub)
232 {
233 KASSERT(solocked(so));
234
235 return 0;
236 }
237
238 static int
239 sco_peeraddr(struct socket *so, struct mbuf *nam)
240 {
241 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
242 struct sockaddr_bt *sa;
243
244 KASSERT(solocked(so));
245 KASSERT(pcb != NULL);
246 KASSERT(nam != NULL);
247
248 sa = mtod(nam, struct sockaddr_bt *);
249 nam->m_len = sizeof(struct sockaddr_bt);
250 return sco_peeraddr_pcb(pcb, sa);
251 }
252
253 static int
254 sco_sockaddr(struct socket *so, struct mbuf *nam)
255 {
256 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
257 struct sockaddr_bt *sa;
258
259 KASSERT(solocked(so));
260 KASSERT(pcb != NULL);
261 KASSERT(nam != NULL);
262
263 sa = mtod(nam, struct sockaddr_bt *);
264 nam->m_len = sizeof(struct sockaddr_bt);
265 return sco_sockaddr_pcb(pcb, sa);
266 }
267
268 static int
269 sco_recvoob(struct socket *so, struct mbuf *m, int flags)
270 {
271 KASSERT(solocked(so));
272
273 return EOPNOTSUPP;
274 }
275
276 static int
277 sco_send(struct socket *so, struct mbuf *m, struct mbuf *nam,
278 struct mbuf *control, struct lwp *l)
279 {
280 struct sco_pcb *pcb = so->so_pcb;
281 int err = 0;
282 struct mbuf *m0;
283
284 KASSERT(solocked(so));
285 KASSERT(m != NULL);
286
287 if (control) /* no use for that */
288 m_freem(control);
289
290 if (pcb == NULL) {
291 err = EINVAL;
292 goto release;
293 }
294
295 if (m->m_pkthdr.len == 0)
296 goto release;
297
298 if (m->m_pkthdr.len > pcb->sp_mtu) {
299 err = EMSGSIZE;
300 goto release;
301 }
302
303 m0 = m_copypacket(m, M_DONTWAIT);
304 if (m0 == NULL) {
305 err = ENOMEM;
306 goto release;
307 }
308
309 sbappendrecord(&so->so_snd, m);
310 return sco_send_pcb(pcb, m0);
311
312 release:
313 m_freem(m);
314 return err;
315 }
316
317 static int
318 sco_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
319 {
320 KASSERT(solocked(so));
321
322 if (m)
323 m_freem(m);
324 if (control)
325 m_freem(control);
326
327 return EOPNOTSUPP;
328 }
329
330 /*
331 * User Request.
332 * up is socket
333 * m is optional mbuf chain containing message
334 * nam is optional mbuf chain containing an address
335 * ctl is optional mbuf chain containing socket options
336 * l is pointer to process requesting action (if any)
337 *
338 * we are responsible for disposing of m and ctl if
339 * they are mbuf chains
340 */
341 static int
342 sco_usrreq(struct socket *up, int req, struct mbuf *m,
343 struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
344 {
345 struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb;
346 int err = 0;
347
348 DPRINTFN(2, "%s\n", prurequests[req]);
349 KASSERT(req != PRU_ATTACH);
350 KASSERT(req != PRU_DETACH);
351 KASSERT(req != PRU_ACCEPT);
352 KASSERT(req != PRU_BIND);
353 KASSERT(req != PRU_LISTEN);
354 KASSERT(req != PRU_CONNECT);
355 KASSERT(req != PRU_DISCONNECT);
356 KASSERT(req != PRU_SHUTDOWN);
357 KASSERT(req != PRU_ABORT);
358 KASSERT(req != PRU_CONTROL);
359 KASSERT(req != PRU_SENSE);
360 KASSERT(req != PRU_PEERADDR);
361 KASSERT(req != PRU_SOCKADDR);
362 KASSERT(req != PRU_RCVOOB);
363 KASSERT(req != PRU_SEND);
364 KASSERT(req != PRU_SENDOOB);
365
366 switch(req) {
367 case PRU_PURGEIF:
368 return EOPNOTSUPP;
369 }
370
371 /* anything after here *requires* a pcb */
372 if (pcb == NULL) {
373 err = EINVAL;
374 goto release;
375 }
376
377 switch(req) {
378 case PRU_RCVD:
379 return EOPNOTSUPP; /* (no release) */
380
381 case PRU_CONNECT2:
382 case PRU_FASTTIMO:
383 case PRU_SLOWTIMO:
384 case PRU_PROTORCV:
385 case PRU_PROTOSEND:
386 err = EOPNOTSUPP;
387 break;
388
389 default:
390 UNKNOWN(req);
391 err = EOPNOTSUPP;
392 break;
393 }
394
395 release:
396 if (m) m_freem(m);
397 if (ctl) m_freem(ctl);
398 return err;
399 }
400
401 /*
402 * get/set socket options
403 */
404 int
405 sco_ctloutput(int req, struct socket *so, struct sockopt *sopt)
406 {
407 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
408 int err = 0;
409
410 DPRINTFN(2, "req %s\n", prcorequests[req]);
411
412 if (pcb == NULL)
413 return EINVAL;
414
415 if (sopt->sopt_level != BTPROTO_SCO)
416 return ENOPROTOOPT;
417
418 switch(req) {
419 case PRCO_GETOPT:
420 err = sco_getopt(pcb, sopt);
421 break;
422
423 case PRCO_SETOPT:
424 err = sco_setopt(pcb, sopt);
425 break;
426
427 default:
428 err = ENOPROTOOPT;
429 break;
430 }
431
432 return err;
433 }
434
435 /*****************************************************************************
436 *
437 * SCO Protocol socket callbacks
438 *
439 */
440 static void
441 sco_connecting(void *arg)
442 {
443 struct socket *so = arg;
444
445 DPRINTF("Connecting\n");
446 soisconnecting(so);
447 }
448
449 static void
450 sco_connected(void *arg)
451 {
452 struct socket *so = arg;
453
454 DPRINTF("Connected\n");
455 soisconnected(so);
456 }
457
458 static void
459 sco_disconnected(void *arg, int err)
460 {
461 struct socket *so = arg;
462
463 DPRINTF("Disconnected (%d)\n", err);
464
465 so->so_error = err;
466 soisdisconnected(so);
467 }
468
469 static void *
470 sco_newconn(void *arg, struct sockaddr_bt *laddr,
471 struct sockaddr_bt *raddr)
472 {
473 struct socket *so = arg;
474
475 DPRINTF("New Connection\n");
476 so = sonewconn(so, false);
477 if (so == NULL)
478 return NULL;
479
480 soisconnecting(so);
481 return so->so_pcb;
482 }
483
484 static void
485 sco_complete(void *arg, int num)
486 {
487 struct socket *so = arg;
488
489 while (num-- > 0)
490 sbdroprecord(&so->so_snd);
491
492 sowwakeup(so);
493 }
494
495 static void
496 sco_linkmode(void *arg, int mode)
497 {
498 }
499
500 static void
501 sco_input(void *arg, struct mbuf *m)
502 {
503 struct socket *so = arg;
504
505 /*
506 * since this data is time sensitive, if the buffer
507 * is full we just dump data until the latest one
508 * will fit.
509 */
510
511 while (m->m_pkthdr.len > sbspace(&so->so_rcv))
512 sbdroprecord(&so->so_rcv);
513
514 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
515
516 sbappendrecord(&so->so_rcv, m);
517 sorwakeup(so);
518 }
519
520 PR_WRAP_USRREQS(sco)
521
522 #define sco_attach sco_attach_wrapper
523 #define sco_detach sco_detach_wrapper
524 #define sco_accept sco_accept_wrapper
525 #define sco_bind sco_bind_wrapper
526 #define sco_listen sco_listen_wrapper
527 #define sco_connect sco_connect_wrapper
528 #define sco_disconnect sco_disconnect_wrapper
529 #define sco_shutdown sco_shutdown_wrapper
530 #define sco_abort sco_abort_wrapper
531 #define sco_ioctl sco_ioctl_wrapper
532 #define sco_stat sco_stat_wrapper
533 #define sco_peeraddr sco_peeraddr_wrapper
534 #define sco_sockaddr sco_sockaddr_wrapper
535 #define sco_recvoob sco_recvoob_wrapper
536 #define sco_send sco_send_wrapper
537 #define sco_sendoob sco_sendoob_wrapper
538 #define sco_usrreq sco_usrreq_wrapper
539
540 const struct pr_usrreqs sco_usrreqs = {
541 .pr_attach = sco_attach,
542 .pr_detach = sco_detach,
543 .pr_accept = sco_accept,
544 .pr_bind = sco_bind,
545 .pr_listen = sco_listen,
546 .pr_connect = sco_connect,
547 .pr_disconnect = sco_disconnect,
548 .pr_shutdown = sco_shutdown,
549 .pr_abort = sco_abort,
550 .pr_ioctl = sco_ioctl,
551 .pr_stat = sco_stat,
552 .pr_peeraddr = sco_peeraddr,
553 .pr_sockaddr = sco_sockaddr,
554 .pr_recvoob = sco_recvoob,
555 .pr_send = sco_send,
556 .pr_sendoob = sco_sendoob,
557 .pr_generic = sco_usrreq,
558 };
559