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