1 /*- 2 * Copyright (c) 2006 Itronix Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of Itronix Inc. may not be used to endorse 14 * or promote products derived from this software without specific 15 * prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $OpenBSD: sco_socket.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ 30 * $NetBSD: sco_socket.c,v 1.9 2007/04/21 06:15:23 plunky Exp $ 31 */ 32 33 /* load symbolic names */ 34 #ifdef BLUETOOTH_DEBUG 35 #define PRUREQUESTS 36 #define PRCOREQUESTS 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/domain.h> 41 #include <sys/kernel.h> 42 #include <sys/malloc.h> /* for M_NOWAIT */ 43 #include <sys/mbuf.h> 44 #include <sys/proc.h> 45 #include <sys/protosw.h> 46 #include <sys/socket.h> 47 #include <sys/socketvar.h> 48 #include <sys/systm.h> 49 #include <sys/bus.h> 50 51 #include <sys/msgport2.h> 52 53 #include <netbt/bluetooth.h> 54 #include <netbt/hci.h> 55 #include <netbt/sco.h> 56 57 /******************************************************************************* 58 * 59 * SCO SOCK_SEQPACKET sockets - low latency audio data 60 */ 61 62 static void sco_connecting(void *); 63 static void sco_connected(void *); 64 static void sco_disconnected(void *, int); 65 static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 66 static void sco_complete(void *, int); 67 static void sco_linkmode(void *, int); 68 static void sco_input(void *, struct mbuf *); 69 70 static const struct btproto sco_proto = { 71 sco_connecting, 72 sco_connected, 73 sco_disconnected, 74 sco_newconn, 75 sco_complete, 76 sco_linkmode, 77 sco_input, 78 }; 79 80 int sco_sendspace = 4096; 81 int sco_recvspace = 4096; 82 83 /* 84 * get/set socket options 85 */ 86 void 87 sco_ctloutput(netmsg_t msg) 88 { 89 struct socket *so = msg->ctloutput.base.nm_so; 90 struct sockopt *sopt = msg->ctloutput.nm_sopt; 91 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 92 struct mbuf *m; 93 int err = 0; 94 95 #ifdef notyet /* XXX */ 96 DPRINTFN(2, "req %s\n", prcorequests[req]); 97 #endif 98 99 if (pcb == NULL) { 100 err = EINVAL; 101 goto out; 102 } 103 104 if (sopt->sopt_level != BTPROTO_SCO) { 105 err = ENOPROTOOPT; 106 goto out; 107 } 108 109 switch(sopt->sopt_dir) { 110 case PRCO_GETOPT: 111 m = m_get(M_WAITOK, MT_DATA); 112 m->m_len = sco_getopt(pcb, sopt->sopt_name, mtod(m, uint8_t *)); 113 if (m->m_len == 0) { 114 m_freem(m); 115 m = NULL; 116 err = ENOPROTOOPT; 117 } 118 /* *opt = m; */ 119 /* XXX There are possible memory leaks (Griffin) */ 120 soopt_from_kbuf(sopt, mtod(m, void *), m->m_len); 121 break; 122 123 case PRCO_SETOPT: 124 m = m_get(M_WAITOK, MT_DATA); 125 KKASSERT(m != NULL); 126 err = soopt_to_kbuf(sopt, mtod(m,void*), m->m_len, m->m_len); 127 128 if (m->m_len == 0) { 129 m_freem(m); 130 m = NULL; 131 err = EIO; 132 } 133 134 err = sco_setopt(pcb, sopt->sopt_name, mtod(m, uint8_t *)); 135 m_freem(m); 136 break; 137 138 default: 139 err = ENOPROTOOPT; 140 break; 141 } 142 out: 143 lwkt_replymsg(&msg->ctloutput.base.lmsg, err); 144 } 145 146 /***************************************************************************** 147 * 148 * SCO Protocol socket callbacks 149 * 150 */ 151 static void 152 sco_connecting(void *arg) 153 { 154 struct socket *so = arg; 155 156 DPRINTF("Connecting\n"); 157 soisconnecting(so); 158 } 159 160 static void 161 sco_connected(void *arg) 162 { 163 struct socket *so = arg; 164 165 DPRINTF("Connected\n"); 166 soisconnected(so); 167 } 168 169 static void 170 sco_disconnected(void *arg, int err) 171 { 172 struct socket *so = arg; 173 174 DPRINTF("Disconnected (%d)\n", err); 175 176 so->so_error = err; 177 soisdisconnected(so); 178 } 179 180 static void * 181 sco_newconn(void *arg, struct sockaddr_bt *laddr, 182 struct sockaddr_bt *raddr) 183 { 184 struct socket *so = arg; 185 186 DPRINTF("New Connection\n"); 187 so = sonewconn(so, 0); 188 if (so == NULL) 189 return NULL; 190 191 soisconnecting(so); 192 return so->so_pcb; 193 } 194 195 static void 196 sco_complete(void *arg, int num) 197 { 198 struct socket *so = arg; 199 200 while (num-- > 0) 201 sbdroprecord(&so->so_snd.sb); 202 203 sowwakeup(so); 204 } 205 206 static void 207 sco_linkmode(void *arg, int mode) 208 { 209 } 210 211 static void 212 sco_input(void *arg, struct mbuf *m) 213 { 214 struct socket *so = arg; 215 216 /* 217 * since this data is time sensitive, if the buffer 218 * is full we just dump data until the latest one 219 * will fit. 220 */ 221 222 while (m->m_pkthdr.len > sbspace(&so->so_rcv)) 223 sbdroprecord(&so->so_rcv.sb); 224 225 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 226 227 sbappendrecord(&so->so_rcv.sb, m); 228 sorwakeup(so); 229 } 230 231 /* 232 * Implementation of usrreqs. 233 */ 234 static void 235 sco_sdetach(netmsg_t msg) 236 { 237 struct socket *so = msg->detach.base.nm_so; 238 int error; 239 240 error = sco_detach((struct sco_pcb **)&so->so_pcb); 241 lwkt_replymsg(&msg->detach.base.lmsg, error); 242 } 243 244 /* 245 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort() 246 * will sofree() it when we return. 247 */ 248 static void 249 sco_sabort (netmsg_t msg) 250 { 251 struct socket *so = msg->abort.base.nm_so; 252 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 253 254 sco_disconnect(pcb, 0); 255 soisdisconnected(so); 256 sco_sdetach(msg); 257 /* msg invalid now */ 258 } 259 260 static void 261 sco_sdisconnect (netmsg_t msg) 262 { 263 struct socket *so = msg->abort.base.nm_so; 264 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 265 int error; 266 267 soisdisconnecting(so); 268 269 error = sco_disconnect(pcb, so->so_linger); 270 lwkt_replymsg(&msg->disconnect.base.lmsg, error); 271 } 272 273 static void 274 sco_sattach(netmsg_t msg) 275 { 276 struct socket *so = msg->attach.base.nm_so; 277 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 278 int error; 279 280 if (pcb) { 281 error = EINVAL; 282 } else { 283 error = soreserve(so, sco_sendspace, sco_recvspace,NULL); 284 if (error == 0) { 285 error = sco_attach((struct sco_pcb **)&so->so_pcb, 286 &sco_proto, so); 287 } 288 } 289 lwkt_replymsg(&msg->attach.base.lmsg, error); 290 } 291 292 static void 293 sco_sbind(netmsg_t msg) 294 { 295 struct socket *so = msg->bind.base.nm_so; 296 struct sockaddr *nam = msg->bind.nm_nam; 297 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 298 struct sockaddr_bt *sa; 299 int error; 300 301 KKASSERT(nam != NULL); 302 sa = (struct sockaddr_bt *)nam; 303 304 if (sa->bt_len != sizeof(struct sockaddr_bt)) { 305 error = EINVAL; 306 } else if (sa->bt_family != AF_BLUETOOTH) { 307 error = EAFNOSUPPORT; 308 } else { 309 error = sco_bind(pcb, sa); 310 } 311 lwkt_replymsg(&msg->bind.base.lmsg, error); 312 } 313 314 static void 315 sco_sconnect(netmsg_t msg) 316 { 317 struct socket *so = msg->connect.base.nm_so; 318 struct sockaddr *nam = msg->connect.nm_nam; 319 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 320 struct sockaddr_bt *sa; 321 int error; 322 323 KKASSERT(nam != NULL); 324 sa = (struct sockaddr_bt *)nam; 325 326 if (sa->bt_len != sizeof(struct sockaddr_bt)) { 327 error = EINVAL; 328 } else if (sa->bt_family != AF_BLUETOOTH) { 329 error = EAFNOSUPPORT; 330 } else { 331 soisconnecting(so); 332 error = sco_connect(pcb, sa); 333 } 334 lwkt_replymsg(&msg->connect.base.lmsg, error); 335 } 336 337 static void 338 sco_speeraddr(netmsg_t msg) 339 { 340 struct socket *so = msg->peeraddr.base.nm_so; 341 struct sockaddr **nam = msg->peeraddr.nm_nam; 342 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 343 struct sockaddr_bt *sa, ssa; 344 int error; 345 346 sa = &ssa; 347 bzero(sa, sizeof *sa); 348 sa->bt_len = sizeof(struct sockaddr_bt); 349 sa->bt_family = AF_BLUETOOTH; 350 error = sco_peeraddr(pcb, sa); 351 *nam = dup_sockaddr((struct sockaddr *)sa); 352 lwkt_replymsg(&msg->peeraddr.base.lmsg, error); 353 } 354 355 static void 356 sco_ssockaddr(netmsg_t msg) 357 { 358 struct socket *so = msg->sockaddr.base.nm_so; 359 struct sockaddr **nam = msg->sockaddr.nm_nam; 360 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 361 struct sockaddr_bt *sa, ssa; 362 int error; 363 364 sa = &ssa; 365 bzero(sa, sizeof *sa); 366 sa->bt_len = sizeof(struct sockaddr_bt); 367 sa->bt_family = AF_BLUETOOTH; 368 error = sco_sockaddr(pcb, sa); 369 *nam = dup_sockaddr((struct sockaddr *)sa); 370 371 lwkt_replymsg(&msg->sockaddr.base.lmsg, error); 372 } 373 374 static void 375 sco_sshutdown(netmsg_t msg) 376 { 377 socantsendmore(msg->shutdown.base.nm_so); 378 lwkt_replymsg(&msg->shutdown.base.lmsg, 0); 379 } 380 381 static void 382 sco_ssend(netmsg_t msg) 383 { 384 struct socket *so = msg->send.base.nm_so; 385 struct mbuf *m = msg->send.nm_m; 386 struct mbuf *control = msg->send.nm_control; 387 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 388 struct mbuf *m0; 389 int error = 0; 390 391 KKASSERT(m != NULL); 392 if (m->m_pkthdr.len == 0) 393 goto out; 394 395 if (m->m_pkthdr.len > pcb->sp_mtu) { 396 error = EMSGSIZE; 397 goto out; 398 } 399 400 m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT); 401 if (m0 == NULL) { 402 error = ENOMEM; 403 goto out; 404 } 405 406 /* no use for that */ 407 if (control) { 408 m_freem(control); 409 control = NULL; 410 } 411 412 sbappendrecord(&so->so_snd.sb, m); 413 error = sco_send(pcb, m0); 414 m = NULL; 415 out: 416 if (m) 417 m_freem(m); 418 if (control) 419 m_freem(control); 420 lwkt_replymsg(&msg->send.base.lmsg, error); 421 } 422 423 static void 424 sco_saccept(netmsg_t msg) 425 { 426 struct socket *so = msg->accept.base.nm_so; 427 struct sockaddr **nam = msg->accept.nm_nam; 428 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 429 struct sockaddr_bt *sa, ssa; 430 int error; 431 432 sa = &ssa; 433 bzero(sa, sizeof *sa); 434 sa->bt_len = sizeof(struct sockaddr_bt); 435 sa->bt_family = AF_BLUETOOTH; 436 error = sco_peeraddr(pcb, sa); 437 *nam = dup_sockaddr((struct sockaddr *)sa); 438 439 lwkt_replymsg(&msg->accept.base.lmsg, error); 440 } 441 442 static void 443 sco_slisten(netmsg_t msg) 444 { 445 struct socket *so = msg->listen.base.nm_so; 446 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 447 int error; 448 449 error = sco_listen(pcb); 450 lwkt_replymsg(&msg->accept.base.lmsg, error); 451 } 452 453 struct pr_usrreqs sco_usrreqs = { 454 .pru_abort = sco_sabort, 455 .pru_accept = sco_saccept, 456 .pru_attach = sco_sattach, 457 .pru_bind = sco_sbind, 458 .pru_connect = sco_sconnect, 459 .pru_connect2 = pr_generic_notsupp, 460 .pru_control = pr_generic_notsupp, 461 .pru_detach = sco_sdetach, 462 .pru_disconnect = sco_sdisconnect, 463 .pru_listen = sco_slisten, 464 .pru_peeraddr = sco_speeraddr, 465 .pru_rcvd = pr_generic_notsupp, 466 .pru_rcvoob = pr_generic_notsupp, 467 .pru_send = sco_ssend, 468 .pru_sense = pru_sense_null, 469 .pru_shutdown = sco_sshutdown, 470 .pru_sockaddr = sco_ssockaddr, 471 .pru_sosend = sosend, 472 .pru_soreceive = soreceive 473 }; 474