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