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