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