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 static int 232 sco_sabort (struct socket *so) 233 { 234 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 235 236 sco_disconnect(pcb, 0); 237 soisdisconnected(so); 238 239 return sco_sdetach(so); 240 } 241 242 static int 243 sco_sdisconnect (struct socket *so) 244 { 245 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 246 247 soisdisconnecting(so); 248 249 return sco_disconnect(pcb, so->so_linger); 250 } 251 252 static int 253 sco_sattach (struct socket *so, int proto, 254 struct pru_attach_info *ai) 255 { 256 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 257 int err=0; 258 259 if (pcb) 260 return EINVAL; 261 262 err = soreserve(so, sco_sendspace, sco_recvspace,NULL); 263 if (err) 264 return err; 265 266 return sco_attach((struct sco_pcb **)&so->so_pcb, 267 &sco_proto, so); 268 } 269 270 static int 271 sco_sbind (struct socket *so, struct sockaddr *nam, 272 struct thread *td) 273 { 274 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 275 struct sockaddr_bt *sa; 276 277 KKASSERT(nam != NULL); 278 sa = (struct sockaddr_bt *)nam; 279 280 if (sa->bt_len != sizeof(struct sockaddr_bt)) 281 return EINVAL; 282 283 if (sa->bt_family != AF_BLUETOOTH) 284 return EAFNOSUPPORT; 285 286 return sco_bind(pcb, sa); 287 } 288 289 static int 290 sco_sconnect (struct socket *so, struct sockaddr *nam, 291 struct thread *td) 292 { 293 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 294 struct sockaddr_bt *sa; 295 296 KKASSERT(nam != NULL); 297 sa = (struct sockaddr_bt *)nam; 298 299 if (sa->bt_len != sizeof(struct sockaddr_bt)) 300 return EINVAL; 301 302 if (sa->bt_family != AF_BLUETOOTH) 303 return EAFNOSUPPORT; 304 305 soisconnecting(so); 306 return sco_connect(pcb, sa); 307 } 308 309 static int 310 sco_speeraddr (struct socket *so, struct sockaddr **nam) 311 { 312 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 313 struct sockaddr_bt *sa, ssa; 314 int e; 315 316 sa = &ssa; 317 bzero(sa, sizeof *sa); 318 sa->bt_len = sizeof(struct sockaddr_bt); 319 sa->bt_family = AF_BLUETOOTH; 320 e = sco_peeraddr(pcb, sa); 321 *nam = dup_sockaddr((struct sockaddr *)sa); 322 323 return (e); 324 } 325 326 static int 327 sco_ssockaddr (struct socket *so, struct sockaddr **nam) 328 { 329 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 330 struct sockaddr_bt *sa, ssa; 331 int e; 332 333 sa = &ssa; 334 bzero(sa, sizeof *sa); 335 sa->bt_len = sizeof(struct sockaddr_bt); 336 sa->bt_family = AF_BLUETOOTH; 337 e = sco_sockaddr(pcb, sa); 338 *nam = dup_sockaddr((struct sockaddr *)sa); 339 340 return (e); 341 } 342 343 static int 344 sco_sshutdown (struct socket *so) 345 { 346 socantsendmore(so); 347 return 0; 348 } 349 350 static int 351 sco_ssend (struct socket *so, int flags, struct mbuf *m, 352 struct sockaddr *addr, struct mbuf *control, struct thread *td) 353 { 354 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 355 struct mbuf *m0; 356 int err = 0; 357 358 KKASSERT(m != NULL); 359 if (m->m_pkthdr.len == 0) 360 goto error; 361 362 if (m->m_pkthdr.len > pcb->sp_mtu) { 363 err = EMSGSIZE; 364 goto error; 365 } 366 367 m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT); 368 if (m0 == NULL) { 369 err = ENOMEM; 370 goto error; 371 } 372 373 if (control) /* no use for that */ 374 m_freem(control); 375 376 sbappendrecord(&so->so_snd.sb, m); 377 return sco_send(pcb, m0); 378 379 error: 380 if (m) m_freem(m); 381 if (control) m_freem(control); 382 return err; 383 } 384 385 static int 386 sco_saccept(struct socket *so, struct sockaddr **nam) 387 { 388 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 389 struct sockaddr_bt *sa, ssa; 390 int e; 391 392 sa = &ssa; 393 bzero(sa, sizeof *sa); 394 sa->bt_len = sizeof(struct sockaddr_bt); 395 sa->bt_family = AF_BLUETOOTH; 396 e = sco_peeraddr(pcb, sa); 397 *nam = dup_sockaddr((struct sockaddr *)sa); 398 399 return (e); 400 } 401 402 static int 403 sco_slisten(struct socket *so, struct thread *td) 404 { 405 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 406 return sco_listen(pcb); 407 } 408 409 410 struct pr_usrreqs sco_usrreqs = { 411 .pru_abort = sco_sabort, 412 .pru_accept = sco_saccept, 413 .pru_attach = sco_sattach, 414 .pru_bind = sco_sbind, 415 .pru_connect = sco_sconnect, 416 .pru_connect2 = pru_connect2_notsupp, 417 .pru_control = pru_control_notsupp, 418 .pru_detach = sco_sdetach, 419 .pru_disconnect = sco_sdisconnect, 420 .pru_listen = sco_slisten, 421 .pru_peeraddr = sco_speeraddr, 422 .pru_rcvd = pru_rcvd_notsupp, 423 .pru_rcvoob = pru_rcvoob_notsupp, 424 .pru_send = sco_ssend, 425 .pru_sense = pru_sense_null, 426 .pru_shutdown = sco_sshutdown, 427 .pru_sockaddr = sco_ssockaddr, 428 .pru_sosend = sosend, 429 .pru_soreceive = soreceive, 430 .pru_sopoll = sopoll 431 }; 432