1/* $NetBSD: sco_socket.c,v 1.38 2019/01/28 12:53:01 martin 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.38 2019/01/28 12:53:01 martin 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 60static void sco_connecting(void *); 61static void sco_connected(void *); 62static void sco_disconnected(void *, int); 63static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 64static void sco_complete(void *, int); 65static void sco_linkmode(void *, int); 66static void sco_input(void *, struct mbuf *); 67 68static 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 78int sco_sendspace = 4096; 79int sco_recvspace = 4096; 80 81static int 82sco_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 102static void 103sco_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 110static int 111sco_accept(struct socket *so, struct sockaddr *nam) 112{ 113 struct sco_pcb *pcb = so->so_pcb; 114 115 KASSERT(solocked(so)); 116 KASSERT(nam != NULL); 117 118 if (pcb == NULL) 119 return EINVAL; 120 121 return sco_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam); 122} 123 124static int 125sco_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) 126{ 127 struct sco_pcb *pcb = so->so_pcb; 128 struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; 129 130 KASSERT(solocked(so)); 131 KASSERT(nam != NULL); 132 133 if (pcb == NULL) 134 return EINVAL; 135 136 if (sa->bt_len != sizeof(struct sockaddr_bt)) 137 return EINVAL; 138 139 if (sa->bt_family != AF_BLUETOOTH) 140 return EAFNOSUPPORT; 141 142 return sco_bind_pcb(pcb, sa); 143} 144 145static int 146sco_listen(struct socket *so, struct lwp *l) 147{ 148 struct sco_pcb *pcb = so->so_pcb; 149 150 KASSERT(solocked(so)); 151 152 if (pcb == NULL) 153 return EINVAL; 154 155 return sco_listen_pcb(pcb); 156} 157 158static int 159sco_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 160{ 161 struct sco_pcb *pcb = so->so_pcb; 162 struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; 163 164 KASSERT(solocked(so)); 165 KASSERT(nam != NULL); 166 167 if (pcb == NULL) 168 return EINVAL; 169 170 if (sa->bt_len != sizeof(struct sockaddr_bt)) 171 return EINVAL; 172 173 if (sa->bt_family != AF_BLUETOOTH) 174 return EAFNOSUPPORT; 175 176 soisconnecting(so); 177 return sco_connect_pcb(pcb, sa); 178} 179 180static int 181sco_connect2(struct socket *so, struct socket *so2) 182{ 183 struct sco_pcb *pcb = so->so_pcb; 184 185 KASSERT(solocked(so)); 186 187 if (pcb == NULL) 188 return EINVAL; 189 190 return EOPNOTSUPP; 191} 192 193static int 194sco_disconnect(struct socket *so) 195{ 196 struct sco_pcb *pcb = so->so_pcb; 197 198 KASSERT(solocked(so)); 199 200 if (pcb == NULL) 201 return EINVAL; 202 203 soisdisconnecting(so); 204 return sco_disconnect_pcb(pcb, so->so_linger); 205} 206 207static int 208sco_shutdown(struct socket *so) 209{ 210 KASSERT(solocked(so)); 211 212 socantsendmore(so); 213 return 0; 214} 215 216static int 217sco_abort(struct socket *so) 218{ 219 struct sco_pcb *pcb = so->so_pcb; 220 221 KASSERT(solocked(so)); 222 223 if (pcb == NULL) 224 return EINVAL; 225 226 sco_disconnect_pcb(pcb, 0); 227 soisdisconnected(so); 228 sco_detach(so); 229 return 0; 230} 231 232static int 233sco_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 234{ 235 return EOPNOTSUPP; 236} 237 238static int 239sco_stat(struct socket *so, struct stat *ub) 240{ 241 KASSERT(solocked(so)); 242 243 return 0; 244} 245 246static int 247sco_peeraddr(struct socket *so, struct sockaddr *nam) 248{ 249 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 250 251 KASSERT(solocked(so)); 252 KASSERT(pcb != NULL); 253 KASSERT(nam != NULL); 254 255 return sco_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam); 256} 257 258static int 259sco_sockaddr(struct socket *so, struct sockaddr *nam) 260{ 261 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 262 263 KASSERT(solocked(so)); 264 KASSERT(pcb != NULL); 265 KASSERT(nam != NULL); 266 267 return sco_sockaddr_pcb(pcb, (struct sockaddr_bt *)nam); 268} 269 270static int 271sco_rcvd(struct socket *so, int flags, struct lwp *l) 272{ 273 KASSERT(solocked(so)); 274 275 return EOPNOTSUPP; 276} 277 278static int 279sco_recvoob(struct socket *so, struct mbuf *m, int flags) 280{ 281 KASSERT(solocked(so)); 282 283 return EOPNOTSUPP; 284} 285 286static int 287sco_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, 288 struct mbuf *control, struct lwp *l) 289{ 290 struct sco_pcb *pcb = so->so_pcb; 291 int err = 0; 292 struct mbuf *m0; 293 294 KASSERT(solocked(so)); 295 KASSERT(m != NULL); 296 297 if (control) /* no use for that */ 298 m_freem(control); 299 300 if (pcb == NULL) { 301 err = EINVAL; 302 goto release; 303 } 304 305 if (m->m_pkthdr.len == 0) 306 goto release; 307 308 if (m->m_pkthdr.len > pcb->sp_mtu) { 309 err = EMSGSIZE; 310 goto release; 311 } 312 313 m0 = m_copypacket(m, M_DONTWAIT); 314 if (m0 == NULL) { 315 err = ENOMEM; 316 goto release; 317 } 318 319 sbappendrecord(&so->so_snd, m); 320 return sco_send_pcb(pcb, m0); 321 322release: 323 m_freem(m); 324 return err; 325} 326 327static int 328sco_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 329{ 330 KASSERT(solocked(so)); 331 332 m_freem(m); 333 m_freem(control); 334 335 return EOPNOTSUPP; 336} 337 338static int 339sco_purgeif(struct socket *so, struct ifnet *ifp) 340{ 341 342 return EOPNOTSUPP; 343} 344 345/* 346 * get/set socket options 347 */ 348int 349sco_ctloutput(int req, struct socket *so, struct sockopt *sopt) 350{ 351 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 352 int err = 0; 353 354 DPRINTFN(2, "req %s\n", prcorequests[req]); 355 356 if (pcb == NULL) 357 return EINVAL; 358 359 if (sopt->sopt_level != BTPROTO_SCO) 360 return ENOPROTOOPT; 361 362 switch(req) { 363 case PRCO_GETOPT: 364 err = sco_getopt(pcb, sopt); 365 break; 366 367 case PRCO_SETOPT: 368 err = sco_setopt(pcb, sopt); 369 break; 370 371 default: 372 err = ENOPROTOOPT; 373 break; 374 } 375 376 return err; 377} 378 379/***************************************************************************** 380 * 381 * SCO Protocol socket callbacks 382 * 383 */ 384static void 385sco_connecting(void *arg) 386{ 387 struct socket *so = arg; 388 389 DPRINTF("Connecting\n"); 390 soisconnecting(so); 391} 392 393static void 394sco_connected(void *arg) 395{ 396 struct socket *so = arg; 397 398 DPRINTF("Connected\n"); 399 soisconnected(so); 400} 401 402static void 403sco_disconnected(void *arg, int err) 404{ 405 struct socket *so = arg; 406 407 DPRINTF("Disconnected (%d)\n", err); 408 409 so->so_error = err; 410 soisdisconnected(so); 411} 412 413static void * 414sco_newconn(void *arg, struct sockaddr_bt *laddr, 415 struct sockaddr_bt *raddr) 416{ 417 struct socket *so = arg; 418 419 DPRINTF("New Connection\n"); 420 so = sonewconn(so, false); 421 if (so == NULL) 422 return NULL; 423 424 soisconnecting(so); 425 return so->so_pcb; 426} 427 428static void 429sco_complete(void *arg, int num) 430{ 431 struct socket *so = arg; 432 433 while (num-- > 0) 434 sbdroprecord(&so->so_snd); 435 436 sowwakeup(so); 437} 438 439static void 440sco_linkmode(void *arg, int mode) 441{ 442} 443 444static void 445sco_input(void *arg, struct mbuf *m) 446{ 447 struct socket *so = arg; 448 449 /* 450 * since this data is time sensitive, if the buffer 451 * is full we just dump data until the latest one 452 * will fit. 453 */ 454 455 while (m->m_pkthdr.len > sbspace(&so->so_rcv)) 456 sbdroprecord(&so->so_rcv); 457 458 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 459 460 sbappendrecord(&so->so_rcv, m); 461 sorwakeup(so); 462} 463 464PR_WRAP_USRREQS(sco) 465 466#define sco_attach sco_attach_wrapper 467#define sco_detach sco_detach_wrapper 468#define sco_accept sco_accept_wrapper 469#define sco_bind sco_bind_wrapper 470#define sco_listen sco_listen_wrapper 471#define sco_connect sco_connect_wrapper 472#define sco_connect2 sco_connect2_wrapper 473#define sco_disconnect sco_disconnect_wrapper 474#define sco_shutdown sco_shutdown_wrapper 475#define sco_abort sco_abort_wrapper 476#define sco_ioctl sco_ioctl_wrapper 477#define sco_stat sco_stat_wrapper 478#define sco_peeraddr sco_peeraddr_wrapper 479#define sco_sockaddr sco_sockaddr_wrapper 480#define sco_rcvd sco_rcvd_wrapper 481#define sco_recvoob sco_recvoob_wrapper 482#define sco_send sco_send_wrapper 483#define sco_sendoob sco_sendoob_wrapper 484#define sco_purgeif sco_purgeif_wrapper 485 486const struct pr_usrreqs sco_usrreqs = { 487 .pr_attach = sco_attach, 488 .pr_detach = sco_detach, 489 .pr_accept = sco_accept, 490 .pr_bind = sco_bind, 491 .pr_listen = sco_listen, 492 .pr_connect = sco_connect, 493 .pr_connect2 = sco_connect2, 494 .pr_disconnect = sco_disconnect, 495 .pr_shutdown = sco_shutdown, 496 .pr_abort = sco_abort, 497 .pr_ioctl = sco_ioctl, 498 .pr_stat = sco_stat, 499 .pr_peeraddr = sco_peeraddr, 500 .pr_sockaddr = sco_sockaddr, 501 .pr_rcvd = sco_rcvd, 502 .pr_recvoob = sco_recvoob, 503 .pr_send = sco_send, 504 .pr_sendoob = sco_sendoob, 505 .pr_purgeif = sco_purgeif, 506}; 507