xref: /dragonfly/sys/netbt/l2cap_socket.c (revision c443c74f)
10a9108ebSHasso Tepper /* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
20a9108ebSHasso Tepper /* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
30a9108ebSHasso Tepper 
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper  * Copyright (c) 2005 Iain Hibbert.
60a9108ebSHasso Tepper  * Copyright (c) 2006 Itronix Inc.
70a9108ebSHasso Tepper  * All rights reserved.
80a9108ebSHasso Tepper  *
90a9108ebSHasso Tepper  * Redistribution and use in source and binary forms, with or without
100a9108ebSHasso Tepper  * modification, are permitted provided that the following conditions
110a9108ebSHasso Tepper  * are met:
120a9108ebSHasso Tepper  * 1. Redistributions of source code must retain the above copyright
130a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer.
140a9108ebSHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
150a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
160a9108ebSHasso Tepper  *    documentation and/or other materials provided with the distribution.
170a9108ebSHasso Tepper  * 3. The name of Itronix Inc. may not be used to endorse
180a9108ebSHasso Tepper  *    or promote products derived from this software without specific
190a9108ebSHasso Tepper  *    prior written permission.
200a9108ebSHasso Tepper  *
210a9108ebSHasso Tepper  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
220a9108ebSHasso Tepper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
230a9108ebSHasso Tepper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
240a9108ebSHasso Tepper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
250a9108ebSHasso Tepper  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
260a9108ebSHasso Tepper  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
270a9108ebSHasso Tepper  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
280a9108ebSHasso Tepper  * ON ANY THEORY OF LIABILITY, WHETHER IN
290a9108ebSHasso Tepper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300a9108ebSHasso Tepper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
310a9108ebSHasso Tepper  * POSSIBILITY OF SUCH DAMAGE.
320a9108ebSHasso Tepper  */
330a9108ebSHasso Tepper 
340a9108ebSHasso Tepper /* load symbolic names */
350a9108ebSHasso Tepper #ifdef BLUETOOTH_DEBUG
360a9108ebSHasso Tepper #define PRUREQUESTS
370a9108ebSHasso Tepper #define PRCOREQUESTS
380a9108ebSHasso Tepper #endif
390a9108ebSHasso Tepper 
400a9108ebSHasso Tepper #include <sys/param.h>
410a9108ebSHasso Tepper #include <sys/domain.h>
420a9108ebSHasso Tepper #include <sys/kernel.h>
43*c443c74fSzrj #include <sys/malloc.h>	/* for M_NOWAIT */
440a9108ebSHasso Tepper #include <sys/mbuf.h>
450a9108ebSHasso Tepper #include <sys/proc.h>
460a9108ebSHasso Tepper #include <sys/protosw.h>
470a9108ebSHasso Tepper #include <sys/socket.h>
480a9108ebSHasso Tepper #include <sys/socketvar.h>
490a9108ebSHasso Tepper #include <sys/systm.h>
50002c1265SMatthew Dillon 
51002c1265SMatthew Dillon #include <sys/msgport2.h>
52002c1265SMatthew Dillon 
530a9108ebSHasso Tepper #include <vm/vm_zone.h>
540a9108ebSHasso Tepper 
550a9108ebSHasso Tepper #include <netbt/bluetooth.h>
560a9108ebSHasso Tepper #include <netbt/hci.h>		/* XXX for EPASSTHROUGH */
570a9108ebSHasso Tepper #include <netbt/l2cap.h>
580a9108ebSHasso Tepper 
590a9108ebSHasso Tepper /*
600a9108ebSHasso Tepper  * L2CAP Sockets
610a9108ebSHasso Tepper  *
620a9108ebSHasso Tepper  *	SOCK_SEQPACKET - normal L2CAP connection
630a9108ebSHasso Tepper  *
640a9108ebSHasso Tepper  *	SOCK_DGRAM - connectionless L2CAP - XXX not yet
650a9108ebSHasso Tepper  */
660a9108ebSHasso Tepper 
670a9108ebSHasso Tepper static void l2cap_connecting(void *);
680a9108ebSHasso Tepper static void l2cap_connected(void *);
690a9108ebSHasso Tepper static void l2cap_disconnected(void *, int);
700a9108ebSHasso Tepper static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
710a9108ebSHasso Tepper static void l2cap_complete(void *, int);
720a9108ebSHasso Tepper static void l2cap_linkmode(void *, int);
730a9108ebSHasso Tepper static void l2cap_input(void *, struct mbuf *);
740a9108ebSHasso Tepper 
750a9108ebSHasso Tepper static const struct btproto l2cap_proto = {
760a9108ebSHasso Tepper 	l2cap_connecting,
770a9108ebSHasso Tepper 	l2cap_connected,
780a9108ebSHasso Tepper 	l2cap_disconnected,
790a9108ebSHasso Tepper 	l2cap_newconn,
800a9108ebSHasso Tepper 	l2cap_complete,
810a9108ebSHasso Tepper 	l2cap_linkmode,
820a9108ebSHasso Tepper 	l2cap_input,
830a9108ebSHasso Tepper };
840a9108ebSHasso Tepper 
850a9108ebSHasso Tepper /* sysctl variables */
860a9108ebSHasso Tepper int l2cap_sendspace = 4096;
870a9108ebSHasso Tepper int l2cap_recvspace = 4096;
880a9108ebSHasso Tepper 
890a9108ebSHasso Tepper /*
900a9108ebSHasso Tepper  * l2cap_ctloutput(request, socket, level, optname, opt)
910a9108ebSHasso Tepper  *
920a9108ebSHasso Tepper  *	Apply configuration commands to channel. This corresponds to
930a9108ebSHasso Tepper  *	"Reconfigure Channel Request" in the L2CAP specification.
940a9108ebSHasso Tepper  */
95002c1265SMatthew Dillon void
l2cap_ctloutput(netmsg_t msg)96002c1265SMatthew Dillon l2cap_ctloutput(netmsg_t msg)
970a9108ebSHasso Tepper {
98002c1265SMatthew Dillon 	struct socket *so = msg->ctloutput.base.nm_so;
99002c1265SMatthew Dillon 	struct sockopt *sopt = msg->ctloutput.nm_sopt;
1000a9108ebSHasso Tepper 	struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb;
1010a9108ebSHasso Tepper 	struct mbuf *m;
102002c1265SMatthew Dillon 	int error = 0;
1030a9108ebSHasso Tepper 
1040a9108ebSHasso Tepper #ifdef notyet			/* XXX */
1050a9108ebSHasso Tepper 	DPRINTFN(2, "%s\n", prcorequests[req]);
1060a9108ebSHasso Tepper #endif
1070a9108ebSHasso Tepper 
108002c1265SMatthew Dillon 	if (pcb == NULL) {
109002c1265SMatthew Dillon 		error = EINVAL;
110002c1265SMatthew Dillon 		goto out;
111002c1265SMatthew Dillon 	}
1120a9108ebSHasso Tepper 
113002c1265SMatthew Dillon 	if (sopt->sopt_level != BTPROTO_L2CAP) {
114002c1265SMatthew Dillon 		error = ENOPROTOOPT;
115002c1265SMatthew Dillon 		goto out;
116002c1265SMatthew Dillon 	}
1170a9108ebSHasso Tepper 
1180a9108ebSHasso Tepper 	switch(sopt->sopt_dir) {
1190a9108ebSHasso Tepper 	case PRCO_GETOPT:
120b5523eacSSascha Wildner 		m = m_get(M_NOWAIT, MT_DATA);
1210a9108ebSHasso Tepper 		if (m == NULL) {
122002c1265SMatthew Dillon 		    error = ENOMEM;
1230a9108ebSHasso Tepper 		    break;
1240a9108ebSHasso Tepper 		}
1250a9108ebSHasso Tepper 		m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *));
1260a9108ebSHasso Tepper 		if (m->m_len == 0) {
1270a9108ebSHasso Tepper 			m_freem(m);
1280a9108ebSHasso Tepper 			m = NULL;
129002c1265SMatthew Dillon 			error = ENOPROTOOPT;
1300a9108ebSHasso Tepper 		}
131d82b71f8SAggelos Economopoulos 		soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
1320a9108ebSHasso Tepper 		break;
1330a9108ebSHasso Tepper 
1340a9108ebSHasso Tepper 	case PRCO_SETOPT:
135002c1265SMatthew Dillon 		error = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt);
1360a9108ebSHasso Tepper 		break;
1370a9108ebSHasso Tepper 
1380a9108ebSHasso Tepper 	default:
139002c1265SMatthew Dillon 		error = ENOPROTOOPT;
1400a9108ebSHasso Tepper 		break;
1410a9108ebSHasso Tepper 	}
142002c1265SMatthew Dillon out:
143002c1265SMatthew Dillon 	lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
1440a9108ebSHasso Tepper }
1450a9108ebSHasso Tepper 
1460a9108ebSHasso Tepper /**********************************************************************
1470a9108ebSHasso Tepper  *
1480a9108ebSHasso Tepper  *	L2CAP Protocol socket callbacks
1490a9108ebSHasso Tepper  *
1500a9108ebSHasso Tepper  */
1510a9108ebSHasso Tepper 
1520a9108ebSHasso Tepper static void
l2cap_connecting(void * arg)1530a9108ebSHasso Tepper l2cap_connecting(void *arg)
1540a9108ebSHasso Tepper {
1550a9108ebSHasso Tepper 	struct socket *so = arg;
1560a9108ebSHasso Tepper 
1570a9108ebSHasso Tepper 	DPRINTF("Connecting\n");
1580a9108ebSHasso Tepper 	soisconnecting(so);
1590a9108ebSHasso Tepper }
1600a9108ebSHasso Tepper 
1610a9108ebSHasso Tepper static void
l2cap_connected(void * arg)1620a9108ebSHasso Tepper l2cap_connected(void *arg)
1630a9108ebSHasso Tepper {
1640a9108ebSHasso Tepper 	struct socket *so = arg;
1650a9108ebSHasso Tepper 
1660a9108ebSHasso Tepper 	DPRINTF("Connected\n");
1670a9108ebSHasso Tepper 	soisconnected(so);
1680a9108ebSHasso Tepper }
1690a9108ebSHasso Tepper 
1700a9108ebSHasso Tepper static void
l2cap_disconnected(void * arg,int err)1710a9108ebSHasso Tepper l2cap_disconnected(void *arg, int err)
1720a9108ebSHasso Tepper {
1730a9108ebSHasso Tepper 	struct socket *so = arg;
1740a9108ebSHasso Tepper 
1750a9108ebSHasso Tepper 	DPRINTF("Disconnected (%d)\n", err);
1760a9108ebSHasso Tepper 
1770a9108ebSHasso Tepper 	so->so_error = err;
1780a9108ebSHasso Tepper 	soisdisconnected(so);
1790a9108ebSHasso Tepper }
1800a9108ebSHasso Tepper 
1810a9108ebSHasso Tepper static void *
l2cap_newconn(void * arg,struct sockaddr_bt * laddr,struct sockaddr_bt * raddr)1820a9108ebSHasso Tepper l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
1830a9108ebSHasso Tepper     struct sockaddr_bt *raddr)
1840a9108ebSHasso Tepper {
1850a9108ebSHasso Tepper 	struct socket *so = arg;
1860a9108ebSHasso Tepper 
1870a9108ebSHasso Tepper 	DPRINTF("New Connection\n");
1880a9108ebSHasso Tepper 	so = sonewconn(so, 0);
1890a9108ebSHasso Tepper 	if (so == NULL)
1900a9108ebSHasso Tepper 		return NULL;
1910a9108ebSHasso Tepper 
1920a9108ebSHasso Tepper 	soisconnecting(so);
1930a9108ebSHasso Tepper 
1940a9108ebSHasso Tepper 	return so->so_pcb;
1950a9108ebSHasso Tepper }
1960a9108ebSHasso Tepper 
1970a9108ebSHasso Tepper static void
l2cap_complete(void * arg,int count)1980a9108ebSHasso Tepper l2cap_complete(void *arg, int count)
1990a9108ebSHasso Tepper {
2000a9108ebSHasso Tepper 	struct socket *so = arg;
2010a9108ebSHasso Tepper 
2020a9108ebSHasso Tepper 	while (count-- > 0)
2030a9108ebSHasso Tepper 		sbdroprecord(&so->so_snd.sb);
2040a9108ebSHasso Tepper 
2050a9108ebSHasso Tepper 	sowwakeup(so);
2060a9108ebSHasso Tepper }
2070a9108ebSHasso Tepper 
2080a9108ebSHasso Tepper static void
l2cap_linkmode(void * arg,int new)2090a9108ebSHasso Tepper l2cap_linkmode(void *arg, int new)
2100a9108ebSHasso Tepper {
2110a9108ebSHasso Tepper 	struct socket *so = arg;
2120a9108ebSHasso Tepper 	int mode;
2130a9108ebSHasso Tepper 
2140a9108ebSHasso Tepper 	DPRINTF("auth %s, encrypt %s, secure %s\n",
2150a9108ebSHasso Tepper 		(new & L2CAP_LM_AUTH ? "on" : "off"),
2160a9108ebSHasso Tepper 		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
2170a9108ebSHasso Tepper 		(new & L2CAP_LM_SECURE ? "on" : "off"));
2180a9108ebSHasso Tepper 
2190a9108ebSHasso Tepper 	(void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
2200a9108ebSHasso Tepper 	if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
2210a9108ebSHasso Tepper 	    || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
2220a9108ebSHasso Tepper 	    || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
2230a9108ebSHasso Tepper 		l2cap_disconnect(so->so_pcb, 0);
2240a9108ebSHasso Tepper }
2250a9108ebSHasso Tepper 
2260a9108ebSHasso Tepper static void
l2cap_input(void * arg,struct mbuf * m)2270a9108ebSHasso Tepper l2cap_input(void *arg, struct mbuf *m)
2280a9108ebSHasso Tepper {
2290a9108ebSHasso Tepper 	struct socket *so = arg;
2300a9108ebSHasso Tepper 
2310a9108ebSHasso Tepper 	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
2320a9108ebSHasso Tepper 		kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
2330a9108ebSHasso Tepper 			__func__, m->m_pkthdr.len);
2340a9108ebSHasso Tepper 		m_freem(m);
2350a9108ebSHasso Tepper 		return;
2360a9108ebSHasso Tepper 	}
2370a9108ebSHasso Tepper 
2380a9108ebSHasso Tepper 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
2390a9108ebSHasso Tepper 
2400a9108ebSHasso Tepper 	sbappendrecord(&so->so_rcv.sb, m);
2410a9108ebSHasso Tepper 	sorwakeup(so);
2420a9108ebSHasso Tepper }
2430a9108ebSHasso Tepper 
2440a9108ebSHasso Tepper 
2450a9108ebSHasso Tepper /*
2460a9108ebSHasso Tepper  * Implementation of usrreqs.
2470a9108ebSHasso Tepper  */
248002c1265SMatthew Dillon static void
l2cap_sdetach(netmsg_t msg)249002c1265SMatthew Dillon l2cap_sdetach(netmsg_t msg)
2500a9108ebSHasso Tepper {
251002c1265SMatthew Dillon 	struct socket *so = msg->detach.base.nm_so;
252002c1265SMatthew Dillon 	int error;
253002c1265SMatthew Dillon 
254002c1265SMatthew Dillon 	error = l2cap_detach((struct l2cap_channel **)&so->so_pcb);
255002c1265SMatthew Dillon 	lwkt_replymsg(&msg->detach.base.lmsg, error);
2560a9108ebSHasso Tepper }
2570a9108ebSHasso Tepper 
2586cef7136SMatthew Dillon /*
2596cef7136SMatthew Dillon  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
2606cef7136SMatthew Dillon  *	 will sofree() it when we return.
2616cef7136SMatthew Dillon  */
262002c1265SMatthew Dillon static void
l2cap_sabort(netmsg_t msg)263002c1265SMatthew Dillon l2cap_sabort(netmsg_t msg)
2640a9108ebSHasso Tepper {
265002c1265SMatthew Dillon 	struct socket *so = msg->abort.base.nm_so;
2660a9108ebSHasso Tepper 	struct l2cap_channel *pcb = so->so_pcb;
2670a9108ebSHasso Tepper 
2680a9108ebSHasso Tepper 	l2cap_disconnect(pcb, 0);
2690a9108ebSHasso Tepper 	soisdisconnected(so);
2700a9108ebSHasso Tepper 
271002c1265SMatthew Dillon 	l2cap_sdetach(msg);
272002c1265SMatthew Dillon 	/* msg invalid now */
2730a9108ebSHasso Tepper }
2740a9108ebSHasso Tepper 
275002c1265SMatthew Dillon static void
l2cap_sdisconnect(netmsg_t msg)276002c1265SMatthew Dillon l2cap_sdisconnect(netmsg_t msg)
2770a9108ebSHasso Tepper {
278002c1265SMatthew Dillon 	struct socket *so = msg->disconnect.base.nm_so;
2790a9108ebSHasso Tepper 	struct l2cap_channel *pcb = so->so_pcb;
280002c1265SMatthew Dillon 	int error;
2810a9108ebSHasso Tepper 
2820a9108ebSHasso Tepper 	soisdisconnecting(so);
2830a9108ebSHasso Tepper 
284002c1265SMatthew Dillon 	error = l2cap_disconnect(pcb, so->so_linger);
285002c1265SMatthew Dillon 	lwkt_replymsg(&msg->disconnect.base.lmsg, error);
2860a9108ebSHasso Tepper }
2870a9108ebSHasso Tepper 
288002c1265SMatthew Dillon static void
l2cap_scontrol(netmsg_t msg)289002c1265SMatthew Dillon l2cap_scontrol(netmsg_t msg)
2900a9108ebSHasso Tepper {
291002c1265SMatthew Dillon 	lwkt_replymsg(&msg->control.base.lmsg, EPASSTHROUGH);
2920a9108ebSHasso Tepper }
2930a9108ebSHasso Tepper 
294002c1265SMatthew Dillon static void
l2cap_sattach(netmsg_t msg)295002c1265SMatthew Dillon l2cap_sattach(netmsg_t msg)
2960a9108ebSHasso Tepper {
297002c1265SMatthew Dillon 	struct socket *so = msg->attach.base.nm_so;
2980a9108ebSHasso Tepper 	struct l2cap_channel *pcb = so->so_pcb;
299002c1265SMatthew Dillon 	int error;
3000a9108ebSHasso Tepper 
301002c1265SMatthew Dillon 	if (pcb != NULL) {
302002c1265SMatthew Dillon 		error = EINVAL;
303002c1265SMatthew Dillon 		goto out;
304002c1265SMatthew Dillon 	}
3050a9108ebSHasso Tepper 
3060a9108ebSHasso Tepper 	/*
3070a9108ebSHasso Tepper 	 * For L2CAP socket PCB we just use an l2cap_channel structure
3080a9108ebSHasso Tepper 	 * since we have nothing to add..
3090a9108ebSHasso Tepper 	 */
310002c1265SMatthew Dillon 	error = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL);
311002c1265SMatthew Dillon 	if (error == 0) {
312002c1265SMatthew Dillon 		error = l2cap_attach((struct l2cap_channel **)&so->so_pcb,
3130a9108ebSHasso Tepper 				     &l2cap_proto, so);
3140a9108ebSHasso Tepper 	}
315002c1265SMatthew Dillon out:
316002c1265SMatthew Dillon 	lwkt_replymsg(&msg->attach.base.lmsg, error);
3170a9108ebSHasso Tepper }
3180a9108ebSHasso Tepper 
319002c1265SMatthew Dillon static void
l2cap_sbind(netmsg_t msg)320002c1265SMatthew Dillon l2cap_sbind (netmsg_t msg)
3210a9108ebSHasso Tepper {
322002c1265SMatthew Dillon 	struct socket *so = msg->bind.base.nm_so;
323002c1265SMatthew Dillon 	struct sockaddr *nam = msg->bind.nm_nam;
3240a9108ebSHasso Tepper 	struct l2cap_channel *pcb = so->so_pcb;
3250a9108ebSHasso Tepper 	struct sockaddr_bt *sa;
326002c1265SMatthew Dillon 	int error;
3270a9108ebSHasso Tepper 
3280a9108ebSHasso Tepper 	KKASSERT(nam != NULL);
3290a9108ebSHasso Tepper 	sa = (struct sockaddr_bt *)nam;
3300a9108ebSHasso Tepper 
331002c1265SMatthew Dillon 	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
332002c1265SMatthew Dillon 		error = EINVAL;
333002c1265SMatthew Dillon 	} else if (sa->bt_family != AF_BLUETOOTH) {
334002c1265SMatthew Dillon 		error = EAFNOSUPPORT;
335002c1265SMatthew Dillon 	} else {
336002c1265SMatthew Dillon 		error = l2cap_bind(pcb, sa);
337002c1265SMatthew Dillon 	}
338002c1265SMatthew Dillon 	lwkt_replymsg(&msg->bind.base.lmsg, error);
339002c1265SMatthew Dillon }
3400a9108ebSHasso Tepper 
341002c1265SMatthew Dillon static void
l2cap_sconnect(netmsg_t msg)342002c1265SMatthew Dillon l2cap_sconnect(netmsg_t msg)
343002c1265SMatthew Dillon {
344002c1265SMatthew Dillon 	struct socket *so = msg->connect.base.nm_so;
345002c1265SMatthew Dillon 	struct sockaddr *nam = msg->connect.nm_nam;
346002c1265SMatthew Dillon 	struct l2cap_channel *pcb = so->so_pcb;
347002c1265SMatthew Dillon 	struct sockaddr_bt *sa;
348002c1265SMatthew Dillon 	int error;
3490a9108ebSHasso Tepper 
350002c1265SMatthew Dillon 	KKASSERT(nam != NULL);
351002c1265SMatthew Dillon 	sa = (struct sockaddr_bt *)nam;
352002c1265SMatthew Dillon 
353002c1265SMatthew Dillon 	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
354002c1265SMatthew Dillon 		error = EINVAL;
355002c1265SMatthew Dillon 	} else if (sa->bt_family != AF_BLUETOOTH) {
356002c1265SMatthew Dillon 		error = EAFNOSUPPORT;
357002c1265SMatthew Dillon 	} else {
3580a9108ebSHasso Tepper 		soisconnecting(so);
359002c1265SMatthew Dillon 		error = l2cap_connect(pcb, sa);
360002c1265SMatthew Dillon 	}
361002c1265SMatthew Dillon 	lwkt_replymsg(&msg->connect.base.lmsg, error);
3620a9108ebSHasso Tepper }
3630a9108ebSHasso Tepper 
364002c1265SMatthew Dillon static void
l2cap_speeraddr(netmsg_t msg)365002c1265SMatthew Dillon l2cap_speeraddr(netmsg_t msg)
3660a9108ebSHasso Tepper {
367002c1265SMatthew Dillon 	struct socket *so = msg->peeraddr.base.nm_so;
368002c1265SMatthew Dillon 	struct sockaddr **nam = msg->peeraddr.nm_nam;
3690a9108ebSHasso Tepper 	struct l2cap_channel *pcb = so->so_pcb;
3700a9108ebSHasso Tepper 	struct sockaddr_bt *sa, ssa;
371002c1265SMatthew Dillon 	int error;
3720a9108ebSHasso Tepper 
3730a9108ebSHasso Tepper 	sa = &ssa;
3740a9108ebSHasso Tepper 	bzero(sa, sizeof *sa);
3750a9108ebSHasso Tepper 	sa->bt_len = sizeof(struct sockaddr_bt);
3760a9108ebSHasso Tepper 	sa->bt_family = AF_BLUETOOTH;
377002c1265SMatthew Dillon 	error = l2cap_peeraddr(pcb, sa);
3780a9108ebSHasso Tepper 	*nam = dup_sockaddr((struct sockaddr *)sa);
3790a9108ebSHasso Tepper 
380002c1265SMatthew Dillon 	lwkt_replymsg(&msg->peeraddr.base.lmsg, error);
3810a9108ebSHasso Tepper }
3820a9108ebSHasso Tepper 
383002c1265SMatthew Dillon static void
l2cap_ssockaddr(netmsg_t msg)384002c1265SMatthew Dillon l2cap_ssockaddr(netmsg_t msg)
3850a9108ebSHasso Tepper {
386002c1265SMatthew Dillon 	struct socket *so = msg->sockaddr.base.nm_so;
387002c1265SMatthew Dillon 	struct sockaddr **nam = msg->sockaddr.nm_nam;
3880a9108ebSHasso Tepper 	struct l2cap_channel *pcb = so->so_pcb;
3890a9108ebSHasso Tepper 	struct sockaddr_bt *sa, ssa;
390002c1265SMatthew Dillon 	int error;
3910a9108ebSHasso Tepper 
3920a9108ebSHasso Tepper 	sa = &ssa;
3930a9108ebSHasso Tepper 	bzero(sa, sizeof *sa);
3940a9108ebSHasso Tepper 	sa->bt_len = sizeof(struct sockaddr_bt);
3950a9108ebSHasso Tepper 	sa->bt_family = AF_BLUETOOTH;
396002c1265SMatthew Dillon 	error = l2cap_sockaddr(pcb, sa);
3970a9108ebSHasso Tepper 	*nam = dup_sockaddr((struct sockaddr *)sa);
3980a9108ebSHasso Tepper 
399002c1265SMatthew Dillon 	lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
4000a9108ebSHasso Tepper }
4010a9108ebSHasso Tepper 
402002c1265SMatthew Dillon static void
l2cap_sshutdown(netmsg_t msg)403002c1265SMatthew Dillon l2cap_sshutdown(netmsg_t msg)
4040a9108ebSHasso Tepper {
405002c1265SMatthew Dillon 	struct socket *so = msg->shutdown.base.nm_so;
406002c1265SMatthew Dillon 
4070a9108ebSHasso Tepper 	socantsendmore(so);
408002c1265SMatthew Dillon 
409002c1265SMatthew Dillon 	lwkt_replymsg(&msg->shutdown.base.lmsg, 0);
4100a9108ebSHasso Tepper }
4110a9108ebSHasso Tepper 
412002c1265SMatthew Dillon static void
l2cap_ssend(netmsg_t msg)413002c1265SMatthew Dillon l2cap_ssend(netmsg_t msg)
4140a9108ebSHasso Tepper {
415002c1265SMatthew Dillon 	struct socket *so = msg->send.base.nm_so;
416002c1265SMatthew Dillon 	struct mbuf *m = msg->send.nm_m;
417002c1265SMatthew Dillon 	struct mbuf *control = msg->send.nm_control;
4180a9108ebSHasso Tepper 	struct l2cap_channel *pcb = so->so_pcb;
4190a9108ebSHasso Tepper 	struct mbuf *m0;
420002c1265SMatthew Dillon 	int error;
4210a9108ebSHasso Tepper 
4220a9108ebSHasso Tepper 	KKASSERT(m != NULL);
423002c1265SMatthew Dillon 	if (m->m_pkthdr.len == 0) {
424002c1265SMatthew Dillon 		error = 0;
425002c1265SMatthew Dillon 		goto out;
426002c1265SMatthew Dillon 	}
4270a9108ebSHasso Tepper 
4280a9108ebSHasso Tepper 	if (m->m_pkthdr.len > pcb->lc_omtu) {
429002c1265SMatthew Dillon 		error = EMSGSIZE;
430002c1265SMatthew Dillon 		goto out;
4310a9108ebSHasso Tepper 	}
4320a9108ebSHasso Tepper 
433b5523eacSSascha Wildner 	m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
4340a9108ebSHasso Tepper 	if (m0 == NULL) {
435002c1265SMatthew Dillon 		error = ENOMEM;
436002c1265SMatthew Dillon 		goto out;
4370a9108ebSHasso Tepper 	}
4380a9108ebSHasso Tepper 
439b5523eacSSascha Wildner 	m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
440002c1265SMatthew Dillon 	if (m0 == NULL) {
441002c1265SMatthew Dillon 		error = ENOMEM;
442002c1265SMatthew Dillon 		goto out;
443002c1265SMatthew Dillon 	}
444002c1265SMatthew Dillon 
445002c1265SMatthew Dillon 	/* no use for that */
446002c1265SMatthew Dillon 	if (control) {
4470a9108ebSHasso Tepper 		m_freem(control);
448002c1265SMatthew Dillon 		control = NULL;
449002c1265SMatthew Dillon 	}
4500a9108ebSHasso Tepper 	sbappendrecord(&so->so_snd.sb, m);
451002c1265SMatthew Dillon 	error = l2cap_send(pcb, m0);
452002c1265SMatthew Dillon 	m = NULL;
453002c1265SMatthew Dillon out:
4540a9108ebSHasso Tepper 	if (m)
4550a9108ebSHasso Tepper 		m_freem(m);
4560a9108ebSHasso Tepper 	if (control)
4570a9108ebSHasso Tepper 		m_freem(control);
4580a9108ebSHasso Tepper 
459002c1265SMatthew Dillon 	lwkt_replymsg(&msg->send.base.lmsg, error);
4600a9108ebSHasso Tepper }
4610a9108ebSHasso Tepper 
462002c1265SMatthew Dillon static void
l2cap_saccept(netmsg_t msg)463002c1265SMatthew Dillon l2cap_saccept(netmsg_t msg)
4640a9108ebSHasso Tepper {
465002c1265SMatthew Dillon 	struct socket *so = msg->accept.base.nm_so;
466002c1265SMatthew Dillon 	struct sockaddr **nam = msg->accept.nm_nam;
4670a9108ebSHasso Tepper 	struct l2cap_channel *pcb = so->so_pcb;
4680a9108ebSHasso Tepper 	struct sockaddr_bt sa;
469002c1265SMatthew Dillon 	int error;
4700a9108ebSHasso Tepper 
4710a9108ebSHasso Tepper 	KKASSERT(nam != NULL);
4720a9108ebSHasso Tepper 
4730a9108ebSHasso Tepper 	bzero(&sa, sizeof (sa) );
4740a9108ebSHasso Tepper 	sa.bt_len = sizeof(struct sockaddr_bt);
4750a9108ebSHasso Tepper 	sa.bt_family = AF_BLUETOOTH;
4760a9108ebSHasso Tepper 
477002c1265SMatthew Dillon 	error = l2cap_peeraddr(pcb, &sa);
4780a9108ebSHasso Tepper 	*nam = dup_sockaddr((struct sockaddr *)&sa);
4790a9108ebSHasso Tepper 
480002c1265SMatthew Dillon 	lwkt_replymsg(&msg->accept.base.lmsg, error);
4810a9108ebSHasso Tepper }
4820a9108ebSHasso Tepper 
48308764bdcSMatthew Dillon static void
l2cap_slisten(netmsg_t msg)48408764bdcSMatthew Dillon l2cap_slisten(netmsg_t msg)
4850a9108ebSHasso Tepper {
48608764bdcSMatthew Dillon 	struct socket *so = msg->listen.base.nm_so;
4870a9108ebSHasso Tepper 	struct l2cap_channel *pcb = so->so_pcb;
48808764bdcSMatthew Dillon 	int error;
48908764bdcSMatthew Dillon 
49008764bdcSMatthew Dillon 	error = l2cap_listen(pcb);
49108764bdcSMatthew Dillon 	lwkt_replymsg(&msg->accept.base.lmsg, error);
4920a9108ebSHasso Tepper }
4930a9108ebSHasso Tepper 
4940a9108ebSHasso Tepper 
4950a9108ebSHasso Tepper struct pr_usrreqs l2cap_usrreqs = {
4960a9108ebSHasso Tepper         .pru_abort = l2cap_sabort,
4970a9108ebSHasso Tepper         .pru_accept = l2cap_saccept,
4980a9108ebSHasso Tepper         .pru_attach = l2cap_sattach,
4990a9108ebSHasso Tepper         .pru_bind = l2cap_sbind,
5000a9108ebSHasso Tepper         .pru_connect = l2cap_sconnect,
501002c1265SMatthew Dillon         .pru_connect2 = pr_generic_notsupp,
5020a9108ebSHasso Tepper         .pru_control = l2cap_scontrol,
5030a9108ebSHasso Tepper         .pru_detach = l2cap_sdetach,
5040a9108ebSHasso Tepper         .pru_disconnect = l2cap_sdisconnect,
5050a9108ebSHasso Tepper         .pru_listen = l2cap_slisten,
5060a9108ebSHasso Tepper         .pru_peeraddr = l2cap_speeraddr,
507002c1265SMatthew Dillon         .pru_rcvd = pr_generic_notsupp,
508002c1265SMatthew Dillon         .pru_rcvoob = pr_generic_notsupp,
5090a9108ebSHasso Tepper         .pru_send = l2cap_ssend,
5100a9108ebSHasso Tepper         .pru_sense = pru_sense_null,
5110a9108ebSHasso Tepper         .pru_shutdown = l2cap_sshutdown,
5120a9108ebSHasso Tepper         .pru_sockaddr = l2cap_ssockaddr,
5130a9108ebSHasso Tepper         .pru_sosend = sosend,
5148b5c39bbSSamuel J. Greear         .pru_soreceive = soreceive
5150a9108ebSHasso Tepper };
516