Home | History | Annotate | Line # | Download | only in netbt
l2cap_socket.c revision 1.3.8.1
      1 /*	$NetBSD: l2cap_socket.c,v 1.3.8.1 2007/09/03 07:05:11 wrstuden Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005 Iain Hibbert.
      5  * Copyright (c) 2006 Itronix Inc.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of Itronix Inc. may not be used to endorse
     17  *    or promote products derived from this software without specific
     18  *    prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     27  * ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.3.8.1 2007/09/03 07:05:11 wrstuden Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/domain.h>
     38 #include <sys/kernel.h>
     39 #include <sys/mbuf.h>
     40 #include <sys/proc.h>
     41 #include <sys/protosw.h>
     42 #include <sys/socket.h>
     43 #include <sys/socketvar.h>
     44 #include <sys/systm.h>
     45 
     46 #include <netbt/bluetooth.h>
     47 #include <netbt/l2cap.h>
     48 
     49 /*
     50  * L2CAP Sockets
     51  *
     52  *	SOCK_SEQPACKET - normal L2CAP connection
     53  *
     54  *	SOCK_DGRAM - connectionless L2CAP - XXX not yet
     55  */
     56 
     57 static void l2cap_connecting(void *);
     58 static void l2cap_connected(void *);
     59 static void l2cap_disconnected(void *, int);
     60 static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
     61 static void l2cap_complete(void *, int);
     62 static void l2cap_linkmode(void *, int);
     63 static void l2cap_input(void *, struct mbuf *);
     64 
     65 static const struct btproto l2cap_proto = {
     66 	l2cap_connecting,
     67 	l2cap_connected,
     68 	l2cap_disconnected,
     69 	l2cap_newconn,
     70 	l2cap_complete,
     71 	l2cap_linkmode,
     72 	l2cap_input,
     73 };
     74 
     75 /* sysctl variables */
     76 int l2cap_sendspace = 4096;
     77 int l2cap_recvspace = 4096;
     78 
     79 /*
     80  * User Request.
     81  * up is socket
     82  * m is either
     83  *	optional mbuf chain containing message
     84  *	ioctl command (PRU_CONTROL)
     85  * nam is either
     86  *	optional mbuf chain containing an address
     87  *	ioctl data (PRU_CONTROL)
     88  *	optionally protocol number (PRU_ATTACH)
     89  *	message flags (PRU_RCVD)
     90  * ctl is either
     91  *	optional mbuf chain containing socket options
     92  *	optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
     93  * l is pointer to process requesting action (if any)
     94  *
     95  * we are responsible for disposing of m and ctl if
     96  * they are mbuf chains
     97  */
     98 int
     99 l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
    100     struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
    101 {
    102 	struct l2cap_channel *pcb = up->so_pcb;
    103 	struct sockaddr_bt *sa;
    104 	struct mbuf *m0;
    105 	int err = 0;
    106 
    107 	DPRINTFN(2, "%s\n", prurequests[req]);
    108 
    109 	switch (req) {
    110 	case PRU_CONTROL:
    111 		return EPASSTHROUGH;
    112 
    113 	case PRU_PURGEIF:
    114 		return EOPNOTSUPP;
    115 
    116 	case PRU_ATTACH:
    117 		if (pcb != NULL)
    118 			return EINVAL;
    119 
    120 		/*
    121 		 * For L2CAP socket PCB we just use an l2cap_channel structure
    122 		 * since we have nothing to add..
    123 		 */
    124 		err = soreserve(up, l2cap_sendspace, l2cap_recvspace);
    125 		if (err)
    126 			return err;
    127 
    128 		return l2cap_attach((struct l2cap_channel **)&up->so_pcb,
    129 					&l2cap_proto, up);
    130 	}
    131 
    132 	if (pcb == NULL) {
    133 		err = EINVAL;
    134 		goto release;
    135 	}
    136 
    137 	switch(req) {
    138 	case PRU_DISCONNECT:
    139 		soisdisconnecting(up);
    140 		return l2cap_disconnect(pcb, up->so_linger);
    141 
    142 	case PRU_ABORT:
    143 		l2cap_disconnect(pcb, 0);
    144 		soisdisconnected(up);
    145 		/* fall through to */
    146 	case PRU_DETACH:
    147 		return l2cap_detach((struct l2cap_channel **)&up->so_pcb);
    148 
    149 	case PRU_BIND:
    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 		return l2cap_bind(pcb, sa);
    160 
    161 	case PRU_CONNECT:
    162 		KASSERT(nam);
    163 		sa = mtod(nam, struct sockaddr_bt *);
    164 
    165 		if (sa->bt_len != sizeof(struct sockaddr_bt))
    166 			return EINVAL;
    167 
    168 		if (sa->bt_family != AF_BLUETOOTH)
    169 			return EAFNOSUPPORT;
    170 
    171 		soisconnecting(up);
    172 		return l2cap_connect(pcb, sa);
    173 
    174 	case PRU_PEERADDR:
    175 		KASSERT(nam);
    176 		sa = mtod(nam, struct sockaddr_bt *);
    177 		nam->m_len = sizeof(struct sockaddr_bt);
    178 		return l2cap_peeraddr(pcb, sa);
    179 
    180 	case PRU_SOCKADDR:
    181 		KASSERT(nam);
    182 		sa = mtod(nam, struct sockaddr_bt *);
    183 		nam->m_len = sizeof(struct sockaddr_bt);
    184 		return l2cap_sockaddr(pcb, sa);
    185 
    186 	case PRU_SHUTDOWN:
    187 		socantsendmore(up);
    188 		break;
    189 
    190 	case PRU_SEND:
    191 		KASSERT(m);
    192 		if (m->m_pkthdr.len == 0)
    193 			break;
    194 
    195 		if (m->m_pkthdr.len > pcb->lc_omtu) {
    196 			err = EMSGSIZE;
    197 			break;
    198 		}
    199 
    200 		m0 = m_copypacket(m, M_DONTWAIT);
    201 		if (m0 == NULL) {
    202 			err = ENOMEM;
    203 			break;
    204 		}
    205 
    206 		if (ctl)	/* no use for that */
    207 			m_freem(ctl);
    208 
    209 		sbappendrecord(&up->so_snd, m);
    210 		return l2cap_send(pcb, m0);
    211 
    212 	case PRU_SENSE:
    213 		return 0;		/* (no release) */
    214 
    215 	case PRU_RCVD:
    216 	case PRU_RCVOOB:
    217 		return EOPNOTSUPP;	/* (no release) */
    218 
    219 	case PRU_LISTEN:
    220 		return l2cap_listen(pcb);
    221 
    222 	case PRU_ACCEPT:
    223 		KASSERT(nam);
    224 		sa = mtod(nam, struct sockaddr_bt *);
    225 		nam->m_len = sizeof(struct sockaddr_bt);
    226 		return l2cap_peeraddr(pcb, sa);
    227 
    228 	case PRU_CONNECT2:
    229 	case PRU_SENDOOB:
    230 	case PRU_FASTTIMO:
    231 	case PRU_SLOWTIMO:
    232 	case PRU_PROTORCV:
    233 	case PRU_PROTOSEND:
    234 		err = EOPNOTSUPP;
    235 		break;
    236 
    237 	default:
    238 		UNKNOWN(req);
    239 		err = EOPNOTSUPP;
    240 		break;
    241 	}
    242 
    243 release:
    244 	if (m) m_freem(m);
    245 	if (ctl) m_freem(ctl);
    246 	return err;
    247 }
    248 
    249 /*
    250  * l2cap_ctloutput(request, socket, level, optname, opt)
    251  *
    252  *	Apply configuration commands to channel. This corresponds to
    253  *	"Reconfigure Channel Request" in the L2CAP specification.
    254  */
    255 int
    256 l2cap_ctloutput(int req, struct socket *so, int level,
    257 		int optname, struct mbuf **opt)
    258 {
    259 	struct l2cap_channel *pcb = so->so_pcb;
    260 	struct mbuf *m;
    261 	int err = 0;
    262 
    263 	DPRINTFN(2, "%s\n", prcorequests[req]);
    264 
    265 	if (level != BTPROTO_L2CAP)
    266 		return 0;		// err?
    267 
    268 	switch(req) {
    269 	case PRCO_GETOPT:
    270 		m = m_get(M_WAIT, MT_SOOPTS);
    271 		m->m_len = l2cap_getopt(pcb, optname, mtod(m, void *));
    272 		if (m->m_len == 0) {
    273 			m_freem(m);
    274 			m = NULL;
    275 			err = EINVAL;
    276 		}
    277 		*opt = m;
    278 		break;
    279 
    280 	case PRCO_SETOPT:
    281 		m = *opt;
    282 		KASSERT(m != NULL);
    283 		err = l2cap_setopt(pcb, optname, mtod(m, void *));
    284 		m_freem(m);
    285 		break;
    286 
    287 	default:
    288 		err = EINVAL;
    289 		break;
    290 	}
    291 
    292 	return err;
    293 }
    294 
    295 /**********************************************************************
    296  *
    297  *	L2CAP Protocol socket callbacks
    298  *
    299  */
    300 
    301 static void
    302 l2cap_connecting(void *arg)
    303 {
    304 	struct socket *so = arg;
    305 
    306 	DPRINTF("Connecting\n");
    307 	soisconnecting(so);
    308 }
    309 
    310 static void
    311 l2cap_connected(void *arg)
    312 {
    313 	struct socket *so = arg;
    314 
    315 	DPRINTF("Connected\n");
    316 	soisconnected(so);
    317 }
    318 
    319 static void
    320 l2cap_disconnected(void *arg, int err)
    321 {
    322 	struct socket *so = arg;
    323 
    324 	DPRINTF("Disconnected (%d)\n", err);
    325 
    326 	so->so_error = err;
    327 	soisdisconnected(so);
    328 }
    329 
    330 static void *
    331 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
    332     struct sockaddr_bt *raddr)
    333 {
    334 	struct socket *so = arg;
    335 
    336 	DPRINTF("New Connection\n");
    337 	so = sonewconn(so, 0);
    338 	if (so == NULL)
    339 		return NULL;
    340 
    341 	soisconnecting(so);
    342 
    343 	return so->so_pcb;
    344 }
    345 
    346 static void
    347 l2cap_complete(void *arg, int count)
    348 {
    349 	struct socket *so = arg;
    350 
    351 	while (count-- > 0)
    352 		sbdroprecord(&so->so_snd);
    353 
    354 	sowwakeup(so);
    355 }
    356 
    357 static void
    358 l2cap_linkmode(void *arg, int new)
    359 {
    360 	struct socket *so = arg;
    361 	int mode;
    362 
    363 	DPRINTF("auth %s, encrypt %s, secure %s\n",
    364 		(new & L2CAP_LM_AUTH ? "on" : "off"),
    365 		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
    366 		(new & L2CAP_LM_SECURE ? "on" : "off"));
    367 
    368 	(void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
    369 	if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
    370 	    || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
    371 	    || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
    372 		l2cap_disconnect(so->so_pcb, 0);
    373 }
    374 
    375 static void
    376 l2cap_input(void *arg, struct mbuf *m)
    377 {
    378 	struct socket *so = arg;
    379 
    380 	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
    381 		printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
    382 			__func__, m->m_pkthdr.len);
    383 		m_freem(m);
    384 		return;
    385 	}
    386 
    387 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
    388 
    389 	sbappendrecord(&so->so_rcv, m);
    390 	sorwakeup(so);
    391 }
    392