1 /* $NetBSD: sco_socket.c,v 1.19 2014/07/01 05:49:18 rtr Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Itronix Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of Itronix Inc. may not be used to endorse 16 * or promote products derived from this software without specific 17 * prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.19 2014/07/01 05:49:18 rtr Exp $"); 34 35 /* load symbolic names */ 36 #ifdef BLUETOOTH_DEBUG 37 #define PRUREQUESTS 38 #define PRCOREQUESTS 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/domain.h> 43 #include <sys/kernel.h> 44 #include <sys/mbuf.h> 45 #include <sys/proc.h> 46 #include <sys/protosw.h> 47 #include <sys/socket.h> 48 #include <sys/socketvar.h> 49 #include <sys/systm.h> 50 51 #include <netbt/bluetooth.h> 52 #include <netbt/hci.h> 53 #include <netbt/sco.h> 54 55 /******************************************************************************* 56 * 57 * SCO SOCK_SEQPACKET sockets - low latency audio data 58 */ 59 60 static void sco_connecting(void *); 61 static void sco_connected(void *); 62 static void sco_disconnected(void *, int); 63 static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 64 static void sco_complete(void *, int); 65 static void sco_linkmode(void *, int); 66 static void sco_input(void *, struct mbuf *); 67 68 static const struct btproto sco_proto = { 69 sco_connecting, 70 sco_connected, 71 sco_disconnected, 72 sco_newconn, 73 sco_complete, 74 sco_linkmode, 75 sco_input, 76 }; 77 78 int sco_sendspace = 4096; 79 int sco_recvspace = 4096; 80 81 static int 82 sco_attach(struct socket *so, int proto) 83 { 84 int error; 85 86 KASSERT(so->so_pcb == NULL); 87 88 if (so->so_lock == NULL) { 89 mutex_obj_hold(bt_lock); 90 so->so_lock = bt_lock; 91 solock(so); 92 } 93 KASSERT(solocked(so)); 94 95 error = soreserve(so, sco_sendspace, sco_recvspace); 96 if (error) { 97 return error; 98 } 99 return sco_attach_pcb((struct sco_pcb **)&so->so_pcb, &sco_proto, so); 100 } 101 102 static void 103 sco_detach(struct socket *so) 104 { 105 KASSERT(so->so_pcb != NULL); 106 sco_detach_pcb((struct sco_pcb **)&so->so_pcb); 107 KASSERT(so->so_pcb == NULL); 108 } 109 110 static int 111 sco_ioctl(struct socket *up, u_long cmd, void *nam, struct ifnet *ifp) 112 { 113 return EOPNOTSUPP; 114 } 115 116 /* 117 * User Request. 118 * up is socket 119 * m is optional mbuf chain containing message 120 * nam is optional mbuf chain containing an address 121 * ctl is optional mbuf chain containing socket options 122 * l is pointer to process requesting action (if any) 123 * 124 * we are responsible for disposing of m and ctl if 125 * they are mbuf chains 126 */ 127 static int 128 sco_usrreq(struct socket *up, int req, struct mbuf *m, 129 struct mbuf *nam, struct mbuf *ctl, struct lwp *l) 130 { 131 struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb; 132 struct sockaddr_bt *sa; 133 struct mbuf *m0; 134 int err = 0; 135 136 DPRINTFN(2, "%s\n", prurequests[req]); 137 KASSERT(req != PRU_ATTACH); 138 KASSERT(req != PRU_DETACH); 139 KASSERT(req != PRU_CONTROL); 140 141 switch(req) { 142 case PRU_PURGEIF: 143 return EOPNOTSUPP; 144 } 145 146 /* anything after here *requires* a pcb */ 147 if (pcb == NULL) { 148 err = EINVAL; 149 goto release; 150 } 151 152 switch(req) { 153 case PRU_DISCONNECT: 154 soisdisconnecting(up); 155 return sco_disconnect(pcb, up->so_linger); 156 157 case PRU_ABORT: 158 sco_disconnect(pcb, 0); 159 soisdisconnected(up); 160 sco_detach(up); 161 return 0; 162 163 case PRU_BIND: 164 KASSERT(nam != NULL); 165 sa = mtod(nam, struct sockaddr_bt *); 166 167 if (sa->bt_len != sizeof(struct sockaddr_bt)) 168 return EINVAL; 169 170 if (sa->bt_family != AF_BLUETOOTH) 171 return EAFNOSUPPORT; 172 173 return sco_bind(pcb, sa); 174 175 case PRU_CONNECT: 176 KASSERT(nam != NULL); 177 sa = mtod(nam, struct sockaddr_bt *); 178 179 if (sa->bt_len != sizeof(struct sockaddr_bt)) 180 return EINVAL; 181 182 if (sa->bt_family != AF_BLUETOOTH) 183 return EAFNOSUPPORT; 184 185 soisconnecting(up); 186 return sco_connect(pcb, sa); 187 188 case PRU_PEERADDR: 189 KASSERT(nam != NULL); 190 sa = mtod(nam, struct sockaddr_bt *); 191 nam->m_len = sizeof(struct sockaddr_bt); 192 return sco_peeraddr(pcb, sa); 193 194 case PRU_SOCKADDR: 195 KASSERT(nam != NULL); 196 sa = mtod(nam, struct sockaddr_bt *); 197 nam->m_len = sizeof(struct sockaddr_bt); 198 return sco_sockaddr(pcb, sa); 199 200 case PRU_SHUTDOWN: 201 socantsendmore(up); 202 break; 203 204 case PRU_SEND: 205 KASSERT(m != NULL); 206 if (m->m_pkthdr.len == 0) 207 break; 208 209 if (m->m_pkthdr.len > pcb->sp_mtu) { 210 err = EMSGSIZE; 211 break; 212 } 213 214 m0 = m_copypacket(m, M_DONTWAIT); 215 if (m0 == NULL) { 216 err = ENOMEM; 217 break; 218 } 219 220 if (ctl) /* no use for that */ 221 m_freem(ctl); 222 223 sbappendrecord(&up->so_snd, m); 224 return sco_send(pcb, m0); 225 226 case PRU_SENSE: 227 return 0; /* (no sense - Doh!) */ 228 229 case PRU_RCVD: 230 case PRU_RCVOOB: 231 return EOPNOTSUPP; /* (no release) */ 232 233 case PRU_LISTEN: 234 return sco_listen(pcb); 235 236 case PRU_ACCEPT: 237 KASSERT(nam != NULL); 238 sa = mtod(nam, struct sockaddr_bt *); 239 nam->m_len = sizeof(struct sockaddr_bt); 240 return sco_peeraddr(pcb, sa); 241 242 case PRU_CONNECT2: 243 case PRU_SENDOOB: 244 case PRU_FASTTIMO: 245 case PRU_SLOWTIMO: 246 case PRU_PROTORCV: 247 case PRU_PROTOSEND: 248 err = EOPNOTSUPP; 249 break; 250 251 default: 252 UNKNOWN(req); 253 err = EOPNOTSUPP; 254 break; 255 } 256 257 release: 258 if (m) m_freem(m); 259 if (ctl) m_freem(ctl); 260 return err; 261 } 262 263 /* 264 * get/set socket options 265 */ 266 int 267 sco_ctloutput(int req, struct socket *so, struct sockopt *sopt) 268 { 269 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 270 int err = 0; 271 272 DPRINTFN(2, "req %s\n", prcorequests[req]); 273 274 if (pcb == NULL) 275 return EINVAL; 276 277 if (sopt->sopt_level != BTPROTO_SCO) 278 return ENOPROTOOPT; 279 280 switch(req) { 281 case PRCO_GETOPT: 282 err = sco_getopt(pcb, sopt); 283 break; 284 285 case PRCO_SETOPT: 286 err = sco_setopt(pcb, sopt); 287 break; 288 289 default: 290 err = ENOPROTOOPT; 291 break; 292 } 293 294 return err; 295 } 296 297 /***************************************************************************** 298 * 299 * SCO Protocol socket callbacks 300 * 301 */ 302 static void 303 sco_connecting(void *arg) 304 { 305 struct socket *so = arg; 306 307 DPRINTF("Connecting\n"); 308 soisconnecting(so); 309 } 310 311 static void 312 sco_connected(void *arg) 313 { 314 struct socket *so = arg; 315 316 DPRINTF("Connected\n"); 317 soisconnected(so); 318 } 319 320 static void 321 sco_disconnected(void *arg, int err) 322 { 323 struct socket *so = arg; 324 325 DPRINTF("Disconnected (%d)\n", err); 326 327 so->so_error = err; 328 soisdisconnected(so); 329 } 330 331 static void * 332 sco_newconn(void *arg, struct sockaddr_bt *laddr, 333 struct sockaddr_bt *raddr) 334 { 335 struct socket *so = arg; 336 337 DPRINTF("New Connection\n"); 338 so = sonewconn(so, false); 339 if (so == NULL) 340 return NULL; 341 342 soisconnecting(so); 343 return so->so_pcb; 344 } 345 346 static void 347 sco_complete(void *arg, int num) 348 { 349 struct socket *so = arg; 350 351 while (num-- > 0) 352 sbdroprecord(&so->so_snd); 353 354 sowwakeup(so); 355 } 356 357 static void 358 sco_linkmode(void *arg, int mode) 359 { 360 } 361 362 static void 363 sco_input(void *arg, struct mbuf *m) 364 { 365 struct socket *so = arg; 366 367 /* 368 * since this data is time sensitive, if the buffer 369 * is full we just dump data until the latest one 370 * will fit. 371 */ 372 373 while (m->m_pkthdr.len > sbspace(&so->so_rcv)) 374 sbdroprecord(&so->so_rcv); 375 376 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 377 378 sbappendrecord(&so->so_rcv, m); 379 sorwakeup(so); 380 } 381 382 PR_WRAP_USRREQS(sco) 383 384 #define sco_attach sco_attach_wrapper 385 #define sco_detach sco_detach_wrapper 386 #define sco_ioctl sco_ioctl_wrapper 387 #define sco_usrreq sco_usrreq_wrapper 388 389 const struct pr_usrreqs sco_usrreqs = { 390 .pr_attach = sco_attach, 391 .pr_detach = sco_detach, 392 .pr_ioctl = sco_ioctl, 393 .pr_generic = sco_usrreq, 394 }; 395