1 1.39 rin /* $NetBSD: sco_socket.c,v 1.39 2024/07/05 04:31:53 rin Exp $ */ 2 1.1 gdamore 3 1.1 gdamore /*- 4 1.1 gdamore * Copyright (c) 2006 Itronix Inc. 5 1.1 gdamore * All rights reserved. 6 1.1 gdamore * 7 1.1 gdamore * Redistribution and use in source and binary forms, with or without 8 1.1 gdamore * modification, are permitted provided that the following conditions 9 1.1 gdamore * are met: 10 1.1 gdamore * 1. Redistributions of source code must retain the above copyright 11 1.1 gdamore * notice, this list of conditions and the following disclaimer. 12 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 gdamore * notice, this list of conditions and the following disclaimer in the 14 1.1 gdamore * documentation and/or other materials provided with the distribution. 15 1.1 gdamore * 3. The name of Itronix Inc. may not be used to endorse 16 1.1 gdamore * or promote products derived from this software without specific 17 1.1 gdamore * prior written permission. 18 1.1 gdamore * 19 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 20 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 23 1.1 gdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 1.1 gdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 1.1 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 1.1 gdamore * ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 gdamore * POSSIBILITY OF SUCH DAMAGE. 30 1.1 gdamore */ 31 1.1 gdamore 32 1.1 gdamore #include <sys/cdefs.h> 33 1.39 rin __KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.39 2024/07/05 04:31:53 rin Exp $"); 34 1.8 plunky 35 1.8 plunky /* load symbolic names */ 36 1.8 plunky #ifdef BLUETOOTH_DEBUG 37 1.8 plunky #define PRUREQUESTS 38 1.8 plunky #define PRCOREQUESTS 39 1.8 plunky #endif 40 1.1 gdamore 41 1.1 gdamore #include <sys/param.h> 42 1.1 gdamore #include <sys/domain.h> 43 1.1 gdamore #include <sys/kernel.h> 44 1.1 gdamore #include <sys/mbuf.h> 45 1.1 gdamore #include <sys/proc.h> 46 1.1 gdamore #include <sys/protosw.h> 47 1.1 gdamore #include <sys/socket.h> 48 1.1 gdamore #include <sys/socketvar.h> 49 1.1 gdamore #include <sys/systm.h> 50 1.1 gdamore 51 1.1 gdamore #include <netbt/bluetooth.h> 52 1.1 gdamore #include <netbt/hci.h> 53 1.1 gdamore #include <netbt/sco.h> 54 1.1 gdamore 55 1.1 gdamore /******************************************************************************* 56 1.1 gdamore * 57 1.1 gdamore * SCO SOCK_SEQPACKET sockets - low latency audio data 58 1.1 gdamore */ 59 1.1 gdamore 60 1.1 gdamore static void sco_connecting(void *); 61 1.1 gdamore static void sco_connected(void *); 62 1.1 gdamore static void sco_disconnected(void *, int); 63 1.1 gdamore static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 64 1.1 gdamore static void sco_complete(void *, int); 65 1.9 plunky static void sco_linkmode(void *, int); 66 1.1 gdamore static void sco_input(void *, struct mbuf *); 67 1.1 gdamore 68 1.1 gdamore static const struct btproto sco_proto = { 69 1.1 gdamore sco_connecting, 70 1.1 gdamore sco_connected, 71 1.1 gdamore sco_disconnected, 72 1.1 gdamore sco_newconn, 73 1.1 gdamore sco_complete, 74 1.9 plunky sco_linkmode, 75 1.1 gdamore sco_input, 76 1.1 gdamore }; 77 1.1 gdamore 78 1.1 gdamore int sco_sendspace = 4096; 79 1.1 gdamore int sco_recvspace = 4096; 80 1.1 gdamore 81 1.14 rmind static int 82 1.16 rmind sco_attach(struct socket *so, int proto) 83 1.14 rmind { 84 1.14 rmind int error; 85 1.14 rmind 86 1.14 rmind KASSERT(so->so_pcb == NULL); 87 1.14 rmind 88 1.14 rmind if (so->so_lock == NULL) { 89 1.14 rmind mutex_obj_hold(bt_lock); 90 1.14 rmind so->so_lock = bt_lock; 91 1.14 rmind solock(so); 92 1.14 rmind } 93 1.14 rmind KASSERT(solocked(so)); 94 1.14 rmind 95 1.14 rmind error = soreserve(so, sco_sendspace, sco_recvspace); 96 1.14 rmind if (error) { 97 1.14 rmind return error; 98 1.14 rmind } 99 1.16 rmind return sco_attach_pcb((struct sco_pcb **)&so->so_pcb, &sco_proto, so); 100 1.14 rmind } 101 1.14 rmind 102 1.14 rmind static void 103 1.16 rmind sco_detach(struct socket *so) 104 1.14 rmind { 105 1.15 martin KASSERT(so->so_pcb != NULL); 106 1.16 rmind sco_detach_pcb((struct sco_pcb **)&so->so_pcb); 107 1.14 rmind KASSERT(so->so_pcb == NULL); 108 1.14 rmind } 109 1.14 rmind 110 1.18 rtr static int 111 1.35 rtr sco_accept(struct socket *so, struct sockaddr *nam) 112 1.25 rtr { 113 1.25 rtr struct sco_pcb *pcb = so->so_pcb; 114 1.25 rtr 115 1.25 rtr KASSERT(solocked(so)); 116 1.25 rtr KASSERT(nam != NULL); 117 1.25 rtr 118 1.25 rtr if (pcb == NULL) 119 1.25 rtr return EINVAL; 120 1.25 rtr 121 1.35 rtr return sco_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam); 122 1.25 rtr } 123 1.25 rtr 124 1.25 rtr static int 125 1.34 rtr sco_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) 126 1.27 rtr { 127 1.27 rtr struct sco_pcb *pcb = so->so_pcb; 128 1.34 rtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; 129 1.27 rtr 130 1.27 rtr KASSERT(solocked(so)); 131 1.27 rtr KASSERT(nam != NULL); 132 1.27 rtr 133 1.27 rtr if (pcb == NULL) 134 1.27 rtr return EINVAL; 135 1.27 rtr 136 1.27 rtr if (sa->bt_len != sizeof(struct sockaddr_bt)) 137 1.27 rtr return EINVAL; 138 1.27 rtr 139 1.27 rtr if (sa->bt_family != AF_BLUETOOTH) 140 1.27 rtr return EAFNOSUPPORT; 141 1.27 rtr 142 1.27 rtr return sco_bind_pcb(pcb, sa); 143 1.27 rtr } 144 1.27 rtr 145 1.27 rtr static int 146 1.30 rtr sco_listen(struct socket *so, struct lwp *l) 147 1.27 rtr { 148 1.27 rtr struct sco_pcb *pcb = so->so_pcb; 149 1.27 rtr 150 1.27 rtr KASSERT(solocked(so)); 151 1.27 rtr 152 1.27 rtr if (pcb == NULL) 153 1.27 rtr return EINVAL; 154 1.27 rtr 155 1.27 rtr return sco_listen_pcb(pcb); 156 1.27 rtr } 157 1.27 rtr 158 1.27 rtr static int 159 1.37 rtr sco_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 160 1.28 rtr { 161 1.28 rtr struct sco_pcb *pcb = so->so_pcb; 162 1.37 rtr struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; 163 1.28 rtr 164 1.28 rtr KASSERT(solocked(so)); 165 1.28 rtr KASSERT(nam != NULL); 166 1.28 rtr 167 1.28 rtr if (pcb == NULL) 168 1.28 rtr return EINVAL; 169 1.28 rtr 170 1.28 rtr if (sa->bt_len != sizeof(struct sockaddr_bt)) 171 1.28 rtr return EINVAL; 172 1.28 rtr 173 1.28 rtr if (sa->bt_family != AF_BLUETOOTH) 174 1.28 rtr return EAFNOSUPPORT; 175 1.28 rtr 176 1.28 rtr soisconnecting(so); 177 1.28 rtr return sco_connect_pcb(pcb, sa); 178 1.28 rtr } 179 1.28 rtr 180 1.28 rtr static int 181 1.33 rtr sco_connect2(struct socket *so, struct socket *so2) 182 1.33 rtr { 183 1.33 rtr struct sco_pcb *pcb = so->so_pcb; 184 1.33 rtr 185 1.33 rtr KASSERT(solocked(so)); 186 1.33 rtr 187 1.33 rtr if (pcb == NULL) 188 1.33 rtr return EINVAL; 189 1.33 rtr 190 1.33 rtr return EOPNOTSUPP; 191 1.33 rtr } 192 1.33 rtr 193 1.33 rtr static int 194 1.29 rtr sco_disconnect(struct socket *so) 195 1.29 rtr { 196 1.29 rtr struct sco_pcb *pcb = so->so_pcb; 197 1.29 rtr 198 1.29 rtr KASSERT(solocked(so)); 199 1.29 rtr 200 1.29 rtr if (pcb == NULL) 201 1.29 rtr return EINVAL; 202 1.29 rtr 203 1.29 rtr soisdisconnecting(so); 204 1.29 rtr return sco_disconnect_pcb(pcb, so->so_linger); 205 1.29 rtr } 206 1.29 rtr 207 1.29 rtr static int 208 1.29 rtr sco_shutdown(struct socket *so) 209 1.29 rtr { 210 1.29 rtr KASSERT(solocked(so)); 211 1.29 rtr 212 1.29 rtr socantsendmore(so); 213 1.29 rtr return 0; 214 1.29 rtr } 215 1.29 rtr 216 1.29 rtr static int 217 1.29 rtr sco_abort(struct socket *so) 218 1.29 rtr { 219 1.29 rtr struct sco_pcb *pcb = so->so_pcb; 220 1.29 rtr 221 1.29 rtr KASSERT(solocked(so)); 222 1.29 rtr 223 1.29 rtr if (pcb == NULL) 224 1.29 rtr return EINVAL; 225 1.29 rtr 226 1.29 rtr sco_disconnect_pcb(pcb, 0); 227 1.29 rtr soisdisconnected(so); 228 1.29 rtr sco_detach(so); 229 1.29 rtr return 0; 230 1.29 rtr } 231 1.29 rtr 232 1.29 rtr static int 233 1.23 rtr sco_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 234 1.18 rtr { 235 1.18 rtr return EOPNOTSUPP; 236 1.18 rtr } 237 1.18 rtr 238 1.20 rtr static int 239 1.20 rtr sco_stat(struct socket *so, struct stat *ub) 240 1.20 rtr { 241 1.23 rtr KASSERT(solocked(so)); 242 1.23 rtr 243 1.22 rtr return 0; 244 1.20 rtr } 245 1.20 rtr 246 1.24 rtr static int 247 1.35 rtr sco_peeraddr(struct socket *so, struct sockaddr *nam) 248 1.24 rtr { 249 1.24 rtr struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 250 1.24 rtr 251 1.24 rtr KASSERT(solocked(so)); 252 1.24 rtr KASSERT(pcb != NULL); 253 1.24 rtr KASSERT(nam != NULL); 254 1.24 rtr 255 1.35 rtr return sco_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam); 256 1.24 rtr } 257 1.24 rtr 258 1.24 rtr static int 259 1.35 rtr sco_sockaddr(struct socket *so, struct sockaddr *nam) 260 1.24 rtr { 261 1.24 rtr struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 262 1.24 rtr 263 1.24 rtr KASSERT(solocked(so)); 264 1.24 rtr KASSERT(pcb != NULL); 265 1.24 rtr KASSERT(nam != NULL); 266 1.24 rtr 267 1.35 rtr return sco_sockaddr_pcb(pcb, (struct sockaddr_bt *)nam); 268 1.24 rtr } 269 1.24 rtr 270 1.26 rtr static int 271 1.32 rtr sco_rcvd(struct socket *so, int flags, struct lwp *l) 272 1.32 rtr { 273 1.32 rtr KASSERT(solocked(so)); 274 1.32 rtr 275 1.32 rtr return EOPNOTSUPP; 276 1.32 rtr } 277 1.32 rtr 278 1.32 rtr static int 279 1.26 rtr sco_recvoob(struct socket *so, struct mbuf *m, int flags) 280 1.26 rtr { 281 1.26 rtr KASSERT(solocked(so)); 282 1.26 rtr 283 1.26 rtr return EOPNOTSUPP; 284 1.26 rtr } 285 1.26 rtr 286 1.26 rtr static int 287 1.37 rtr sco_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, 288 1.31 rtr struct mbuf *control, struct lwp *l) 289 1.31 rtr { 290 1.31 rtr struct sco_pcb *pcb = so->so_pcb; 291 1.31 rtr int err = 0; 292 1.31 rtr struct mbuf *m0; 293 1.31 rtr 294 1.31 rtr KASSERT(solocked(so)); 295 1.31 rtr KASSERT(m != NULL); 296 1.31 rtr 297 1.39 rin m_freem(control); /* no use for that */ 298 1.31 rtr 299 1.31 rtr if (pcb == NULL) { 300 1.31 rtr err = EINVAL; 301 1.31 rtr goto release; 302 1.31 rtr } 303 1.31 rtr 304 1.31 rtr if (m->m_pkthdr.len == 0) 305 1.31 rtr goto release; 306 1.31 rtr 307 1.31 rtr if (m->m_pkthdr.len > pcb->sp_mtu) { 308 1.31 rtr err = EMSGSIZE; 309 1.31 rtr goto release; 310 1.31 rtr } 311 1.31 rtr 312 1.31 rtr m0 = m_copypacket(m, M_DONTWAIT); 313 1.31 rtr if (m0 == NULL) { 314 1.31 rtr err = ENOMEM; 315 1.31 rtr goto release; 316 1.31 rtr } 317 1.31 rtr 318 1.31 rtr sbappendrecord(&so->so_snd, m); 319 1.31 rtr return sco_send_pcb(pcb, m0); 320 1.31 rtr 321 1.31 rtr release: 322 1.31 rtr m_freem(m); 323 1.31 rtr return err; 324 1.31 rtr } 325 1.31 rtr 326 1.31 rtr static int 327 1.26 rtr sco_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 328 1.26 rtr { 329 1.26 rtr KASSERT(solocked(so)); 330 1.26 rtr 331 1.38 martin m_freem(m); 332 1.38 martin m_freem(control); 333 1.26 rtr 334 1.26 rtr return EOPNOTSUPP; 335 1.26 rtr } 336 1.26 rtr 337 1.33 rtr static int 338 1.33 rtr sco_purgeif(struct socket *so, struct ifnet *ifp) 339 1.33 rtr { 340 1.33 rtr 341 1.33 rtr return EOPNOTSUPP; 342 1.33 rtr } 343 1.33 rtr 344 1.1 gdamore /* 345 1.1 gdamore * get/set socket options 346 1.1 gdamore */ 347 1.1 gdamore int 348 1.11 plunky sco_ctloutput(int req, struct socket *so, struct sockopt *sopt) 349 1.1 gdamore { 350 1.1 gdamore struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 351 1.1 gdamore int err = 0; 352 1.1 gdamore 353 1.1 gdamore DPRINTFN(2, "req %s\n", prcorequests[req]); 354 1.1 gdamore 355 1.1 gdamore if (pcb == NULL) 356 1.1 gdamore return EINVAL; 357 1.1 gdamore 358 1.11 plunky if (sopt->sopt_level != BTPROTO_SCO) 359 1.6 plunky return ENOPROTOOPT; 360 1.1 gdamore 361 1.1 gdamore switch(req) { 362 1.1 gdamore case PRCO_GETOPT: 363 1.11 plunky err = sco_getopt(pcb, sopt); 364 1.1 gdamore break; 365 1.1 gdamore 366 1.1 gdamore case PRCO_SETOPT: 367 1.11 plunky err = sco_setopt(pcb, sopt); 368 1.1 gdamore break; 369 1.1 gdamore 370 1.1 gdamore default: 371 1.6 plunky err = ENOPROTOOPT; 372 1.1 gdamore break; 373 1.1 gdamore } 374 1.1 gdamore 375 1.1 gdamore return err; 376 1.1 gdamore } 377 1.1 gdamore 378 1.1 gdamore /***************************************************************************** 379 1.1 gdamore * 380 1.1 gdamore * SCO Protocol socket callbacks 381 1.1 gdamore * 382 1.1 gdamore */ 383 1.1 gdamore static void 384 1.1 gdamore sco_connecting(void *arg) 385 1.1 gdamore { 386 1.1 gdamore struct socket *so = arg; 387 1.1 gdamore 388 1.1 gdamore DPRINTF("Connecting\n"); 389 1.1 gdamore soisconnecting(so); 390 1.1 gdamore } 391 1.1 gdamore 392 1.1 gdamore static void 393 1.1 gdamore sco_connected(void *arg) 394 1.1 gdamore { 395 1.1 gdamore struct socket *so = arg; 396 1.1 gdamore 397 1.1 gdamore DPRINTF("Connected\n"); 398 1.1 gdamore soisconnected(so); 399 1.1 gdamore } 400 1.1 gdamore 401 1.1 gdamore static void 402 1.1 gdamore sco_disconnected(void *arg, int err) 403 1.1 gdamore { 404 1.1 gdamore struct socket *so = arg; 405 1.1 gdamore 406 1.1 gdamore DPRINTF("Disconnected (%d)\n", err); 407 1.1 gdamore 408 1.1 gdamore so->so_error = err; 409 1.1 gdamore soisdisconnected(so); 410 1.1 gdamore } 411 1.1 gdamore 412 1.1 gdamore static void * 413 1.5 christos sco_newconn(void *arg, struct sockaddr_bt *laddr, 414 1.5 christos struct sockaddr_bt *raddr) 415 1.1 gdamore { 416 1.2 tron struct socket *so = arg; 417 1.1 gdamore 418 1.3 plunky DPRINTF("New Connection\n"); 419 1.12 rmind so = sonewconn(so, false); 420 1.2 tron if (so == NULL) 421 1.2 tron return NULL; 422 1.2 tron 423 1.2 tron soisconnecting(so); 424 1.2 tron return so->so_pcb; 425 1.1 gdamore } 426 1.1 gdamore 427 1.1 gdamore static void 428 1.1 gdamore sco_complete(void *arg, int num) 429 1.1 gdamore { 430 1.1 gdamore struct socket *so = arg; 431 1.1 gdamore 432 1.1 gdamore while (num-- > 0) 433 1.1 gdamore sbdroprecord(&so->so_snd); 434 1.1 gdamore 435 1.1 gdamore sowwakeup(so); 436 1.1 gdamore } 437 1.1 gdamore 438 1.1 gdamore static void 439 1.9 plunky sco_linkmode(void *arg, int mode) 440 1.9 plunky { 441 1.9 plunky } 442 1.9 plunky 443 1.9 plunky static void 444 1.1 gdamore sco_input(void *arg, struct mbuf *m) 445 1.1 gdamore { 446 1.1 gdamore struct socket *so = arg; 447 1.1 gdamore 448 1.1 gdamore /* 449 1.1 gdamore * since this data is time sensitive, if the buffer 450 1.1 gdamore * is full we just dump data until the latest one 451 1.1 gdamore * will fit. 452 1.1 gdamore */ 453 1.1 gdamore 454 1.1 gdamore while (m->m_pkthdr.len > sbspace(&so->so_rcv)) 455 1.1 gdamore sbdroprecord(&so->so_rcv); 456 1.1 gdamore 457 1.1 gdamore DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 458 1.1 gdamore 459 1.1 gdamore sbappendrecord(&so->so_rcv, m); 460 1.1 gdamore sorwakeup(so); 461 1.1 gdamore } 462 1.13 rmind 463 1.17 rmind PR_WRAP_USRREQS(sco) 464 1.13 rmind 465 1.17 rmind #define sco_attach sco_attach_wrapper 466 1.17 rmind #define sco_detach sco_detach_wrapper 467 1.25 rtr #define sco_accept sco_accept_wrapper 468 1.27 rtr #define sco_bind sco_bind_wrapper 469 1.27 rtr #define sco_listen sco_listen_wrapper 470 1.28 rtr #define sco_connect sco_connect_wrapper 471 1.33 rtr #define sco_connect2 sco_connect2_wrapper 472 1.29 rtr #define sco_disconnect sco_disconnect_wrapper 473 1.29 rtr #define sco_shutdown sco_shutdown_wrapper 474 1.29 rtr #define sco_abort sco_abort_wrapper 475 1.18 rtr #define sco_ioctl sco_ioctl_wrapper 476 1.20 rtr #define sco_stat sco_stat_wrapper 477 1.24 rtr #define sco_peeraddr sco_peeraddr_wrapper 478 1.24 rtr #define sco_sockaddr sco_sockaddr_wrapper 479 1.32 rtr #define sco_rcvd sco_rcvd_wrapper 480 1.26 rtr #define sco_recvoob sco_recvoob_wrapper 481 1.31 rtr #define sco_send sco_send_wrapper 482 1.26 rtr #define sco_sendoob sco_sendoob_wrapper 483 1.33 rtr #define sco_purgeif sco_purgeif_wrapper 484 1.13 rmind 485 1.13 rmind const struct pr_usrreqs sco_usrreqs = { 486 1.16 rmind .pr_attach = sco_attach, 487 1.16 rmind .pr_detach = sco_detach, 488 1.25 rtr .pr_accept = sco_accept, 489 1.27 rtr .pr_bind = sco_bind, 490 1.27 rtr .pr_listen = sco_listen, 491 1.28 rtr .pr_connect = sco_connect, 492 1.33 rtr .pr_connect2 = sco_connect2, 493 1.29 rtr .pr_disconnect = sco_disconnect, 494 1.29 rtr .pr_shutdown = sco_shutdown, 495 1.29 rtr .pr_abort = sco_abort, 496 1.18 rtr .pr_ioctl = sco_ioctl, 497 1.20 rtr .pr_stat = sco_stat, 498 1.24 rtr .pr_peeraddr = sco_peeraddr, 499 1.24 rtr .pr_sockaddr = sco_sockaddr, 500 1.32 rtr .pr_rcvd = sco_rcvd, 501 1.26 rtr .pr_recvoob = sco_recvoob, 502 1.31 rtr .pr_send = sco_send, 503 1.26 rtr .pr_sendoob = sco_sendoob, 504 1.33 rtr .pr_purgeif = sco_purgeif, 505 1.13 rmind }; 506