1 /* $NetBSD: sco_socket.c,v 1.11 2008/08/06 15:01:24 plunky 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.11 2008/08/06 15:01:24 plunky 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 /* 82 * User Request. 83 * up is socket 84 * m is either 85 * optional mbuf chain containing message 86 * ioctl command (PRU_CONTROL) 87 * nam is either 88 * optional mbuf chain containing an address 89 * ioctl data (PRU_CONTROL) 90 * optionally, protocol number (PRU_ATTACH) 91 * ctl is optional mbuf chain containing socket options 92 * l is pointer to process requesting action (if any) 93 * 94 * we are responsible for disposing of m and ctl if 95 * they are mbuf chains 96 */ 97 int 98 sco_usrreq(struct socket *up, int req, struct mbuf *m, 99 struct mbuf *nam, struct mbuf *ctl, struct lwp *l) 100 { 101 struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb; 102 struct sockaddr_bt *sa; 103 struct mbuf *m0; 104 int err = 0; 105 106 DPRINTFN(2, "%s\n", prurequests[req]); 107 108 switch(req) { 109 case PRU_CONTROL: 110 return EOPNOTSUPP; 111 112 case PRU_PURGEIF: 113 return EOPNOTSUPP; 114 115 case PRU_ATTACH: 116 if (up->so_lock == NULL) { 117 mutex_obj_hold(bt_lock); 118 up->so_lock = bt_lock; 119 solock(up); 120 } 121 KASSERT(solocked(up)); 122 if (pcb) 123 return EINVAL; 124 err = soreserve(up, sco_sendspace, sco_recvspace); 125 if (err) 126 return err; 127 128 return sco_attach((struct sco_pcb **)&up->so_pcb, 129 &sco_proto, up); 130 } 131 132 /* anything after here *requires* a pcb */ 133 if (pcb == NULL) { 134 err = EINVAL; 135 goto release; 136 } 137 138 switch(req) { 139 case PRU_DISCONNECT: 140 soisdisconnecting(up); 141 return sco_disconnect(pcb, up->so_linger); 142 143 case PRU_ABORT: 144 sco_disconnect(pcb, 0); 145 soisdisconnected(up); 146 /* fall through to */ 147 case PRU_DETACH: 148 return sco_detach((struct sco_pcb **)&up->so_pcb); 149 150 case PRU_BIND: 151 KASSERT(nam != NULL); 152 sa = mtod(nam, struct sockaddr_bt *); 153 154 if (sa->bt_len != sizeof(struct sockaddr_bt)) 155 return EINVAL; 156 157 if (sa->bt_family != AF_BLUETOOTH) 158 return EAFNOSUPPORT; 159 160 return sco_bind(pcb, sa); 161 162 case PRU_CONNECT: 163 KASSERT(nam != NULL); 164 sa = mtod(nam, struct sockaddr_bt *); 165 166 if (sa->bt_len != sizeof(struct sockaddr_bt)) 167 return EINVAL; 168 169 if (sa->bt_family != AF_BLUETOOTH) 170 return EAFNOSUPPORT; 171 172 soisconnecting(up); 173 return sco_connect(pcb, sa); 174 175 case PRU_PEERADDR: 176 KASSERT(nam != NULL); 177 sa = mtod(nam, struct sockaddr_bt *); 178 nam->m_len = sizeof(struct sockaddr_bt); 179 return sco_peeraddr(pcb, sa); 180 181 case PRU_SOCKADDR: 182 KASSERT(nam != NULL); 183 sa = mtod(nam, struct sockaddr_bt *); 184 nam->m_len = sizeof(struct sockaddr_bt); 185 return sco_sockaddr(pcb, sa); 186 187 case PRU_SHUTDOWN: 188 socantsendmore(up); 189 break; 190 191 case PRU_SEND: 192 KASSERT(m != NULL); 193 if (m->m_pkthdr.len == 0) 194 break; 195 196 if (m->m_pkthdr.len > pcb->sp_mtu) { 197 err = EMSGSIZE; 198 break; 199 } 200 201 m0 = m_copypacket(m, M_DONTWAIT); 202 if (m0 == NULL) { 203 err = ENOMEM; 204 break; 205 } 206 207 if (ctl) /* no use for that */ 208 m_freem(ctl); 209 210 sbappendrecord(&up->so_snd, m); 211 return sco_send(pcb, m0); 212 213 case PRU_SENSE: 214 return 0; /* (no sense - Doh!) */ 215 216 case PRU_RCVD: 217 case PRU_RCVOOB: 218 return EOPNOTSUPP; /* (no release) */ 219 220 case PRU_LISTEN: 221 return sco_listen(pcb); 222 223 case PRU_ACCEPT: 224 KASSERT(nam != NULL); 225 sa = mtod(nam, struct sockaddr_bt *); 226 nam->m_len = sizeof(struct sockaddr_bt); 227 return sco_peeraddr(pcb, sa); 228 229 case PRU_CONNECT2: 230 case PRU_SENDOOB: 231 case PRU_FASTTIMO: 232 case PRU_SLOWTIMO: 233 case PRU_PROTORCV: 234 case PRU_PROTOSEND: 235 err = EOPNOTSUPP; 236 break; 237 238 default: 239 UNKNOWN(req); 240 err = EOPNOTSUPP; 241 break; 242 } 243 244 release: 245 if (m) m_freem(m); 246 if (ctl) m_freem(ctl); 247 return err; 248 } 249 250 /* 251 * get/set socket options 252 */ 253 int 254 sco_ctloutput(int req, struct socket *so, struct sockopt *sopt) 255 { 256 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb; 257 int err = 0; 258 259 DPRINTFN(2, "req %s\n", prcorequests[req]); 260 261 if (pcb == NULL) 262 return EINVAL; 263 264 if (sopt->sopt_level != BTPROTO_SCO) 265 return ENOPROTOOPT; 266 267 switch(req) { 268 case PRCO_GETOPT: 269 err = sco_getopt(pcb, sopt); 270 break; 271 272 case PRCO_SETOPT: 273 err = sco_setopt(pcb, sopt); 274 break; 275 276 default: 277 err = ENOPROTOOPT; 278 break; 279 } 280 281 return err; 282 } 283 284 /***************************************************************************** 285 * 286 * SCO Protocol socket callbacks 287 * 288 */ 289 static void 290 sco_connecting(void *arg) 291 { 292 struct socket *so = arg; 293 294 DPRINTF("Connecting\n"); 295 soisconnecting(so); 296 } 297 298 static void 299 sco_connected(void *arg) 300 { 301 struct socket *so = arg; 302 303 DPRINTF("Connected\n"); 304 soisconnected(so); 305 } 306 307 static void 308 sco_disconnected(void *arg, int err) 309 { 310 struct socket *so = arg; 311 312 DPRINTF("Disconnected (%d)\n", err); 313 314 so->so_error = err; 315 soisdisconnected(so); 316 } 317 318 static void * 319 sco_newconn(void *arg, struct sockaddr_bt *laddr, 320 struct sockaddr_bt *raddr) 321 { 322 struct socket *so = arg; 323 324 DPRINTF("New Connection\n"); 325 so = sonewconn(so, 0); 326 if (so == NULL) 327 return NULL; 328 329 soisconnecting(so); 330 return so->so_pcb; 331 } 332 333 static void 334 sco_complete(void *arg, int num) 335 { 336 struct socket *so = arg; 337 338 while (num-- > 0) 339 sbdroprecord(&so->so_snd); 340 341 sowwakeup(so); 342 } 343 344 static void 345 sco_linkmode(void *arg, int mode) 346 { 347 } 348 349 static void 350 sco_input(void *arg, struct mbuf *m) 351 { 352 struct socket *so = arg; 353 354 /* 355 * since this data is time sensitive, if the buffer 356 * is full we just dump data until the latest one 357 * will fit. 358 */ 359 360 while (m->m_pkthdr.len > sbspace(&so->so_rcv)) 361 sbdroprecord(&so->so_rcv); 362 363 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 364 365 sbappendrecord(&so->so_rcv, m); 366 sorwakeup(so); 367 } 368