xref: /dflybsd-src/sys/netbt/rfcomm_socket.c (revision c443c74f42cc6a7f2385d56cc2b07c21939330d1)
183aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/rfcomm_socket.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
283aacedeSHasso Tepper /* $NetBSD: rfcomm_socket.c,v 1.8 2007/10/15 18:04:34 plunky Exp $ */
30a9108ebSHasso Tepper 
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper  * Copyright (c) 2006 Itronix Inc.
60a9108ebSHasso Tepper  * All rights reserved.
70a9108ebSHasso Tepper  *
80a9108ebSHasso Tepper  * Written by Iain Hibbert for Itronix Inc.
90a9108ebSHasso Tepper  *
100a9108ebSHasso Tepper  * Redistribution and use in source and binary forms, with or without
110a9108ebSHasso Tepper  * modification, are permitted provided that the following conditions
120a9108ebSHasso Tepper  * are met:
130a9108ebSHasso Tepper  * 1. Redistributions of source code must retain the above copyright
140a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer.
150a9108ebSHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
160a9108ebSHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
170a9108ebSHasso Tepper  *    documentation and/or other materials provided with the distribution.
180a9108ebSHasso Tepper  * 3. The name of Itronix Inc. may not be used to endorse
190a9108ebSHasso Tepper  *    or promote products derived from this software without specific
200a9108ebSHasso Tepper  *    prior written permission.
210a9108ebSHasso Tepper  *
220a9108ebSHasso Tepper  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
230a9108ebSHasso Tepper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
240a9108ebSHasso Tepper  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
250a9108ebSHasso Tepper  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
260a9108ebSHasso Tepper  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
270a9108ebSHasso Tepper  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
280a9108ebSHasso Tepper  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
290a9108ebSHasso Tepper  * ON ANY THEORY OF LIABILITY, WHETHER IN
300a9108ebSHasso Tepper  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
310a9108ebSHasso Tepper  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
320a9108ebSHasso Tepper  * POSSIBILITY OF SUCH DAMAGE.
330a9108ebSHasso Tepper  */
340a9108ebSHasso Tepper 
350a9108ebSHasso Tepper /* load symbolic names */
360a9108ebSHasso Tepper #ifdef BLUETOOTH_DEBUG
370a9108ebSHasso Tepper #define PRUREQUESTS
380a9108ebSHasso Tepper #define PRCOREQUESTS
390a9108ebSHasso Tepper #endif
400a9108ebSHasso Tepper 
410a9108ebSHasso Tepper #include <sys/param.h>
420a9108ebSHasso Tepper #include <sys/domain.h>
430a9108ebSHasso Tepper #include <sys/kernel.h>
44*c443c74fSzrj #include <sys/malloc.h>	/* for M_NOWAIT */
450a9108ebSHasso Tepper #include <sys/mbuf.h>
460a9108ebSHasso Tepper #include <sys/proc.h>
470a9108ebSHasso Tepper #include <sys/protosw.h>
480a9108ebSHasso Tepper #include <sys/socket.h>
490a9108ebSHasso Tepper #include <sys/socketvar.h>
500a9108ebSHasso Tepper #include <sys/systm.h>
51002c1265SMatthew Dillon 
52002c1265SMatthew Dillon #include <sys/msgport2.h>
53002c1265SMatthew Dillon 
540a9108ebSHasso Tepper #include <vm/vm_zone.h>
550a9108ebSHasso Tepper 
560a9108ebSHasso Tepper #include <netbt/bluetooth.h>
570a9108ebSHasso Tepper #include <netbt/hci.h>		/* XXX for EPASSTHROUGH */
580a9108ebSHasso Tepper #include <netbt/rfcomm.h>
590a9108ebSHasso Tepper 
600a9108ebSHasso Tepper /****************************************************************************
610a9108ebSHasso Tepper  *
620a9108ebSHasso Tepper  *	RFCOMM SOCK_STREAM Sockets - serial line emulation
630a9108ebSHasso Tepper  *
640a9108ebSHasso Tepper  */
650a9108ebSHasso Tepper 
660a9108ebSHasso Tepper static void rfcomm_connecting(void *);
670a9108ebSHasso Tepper static void rfcomm_connected(void *);
680a9108ebSHasso Tepper static void rfcomm_disconnected(void *, int);
690a9108ebSHasso Tepper static void *rfcomm_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
700a9108ebSHasso Tepper static void rfcomm_complete(void *, int);
710a9108ebSHasso Tepper static void rfcomm_linkmode(void *, int);
720a9108ebSHasso Tepper static void rfcomm_input(void *, struct mbuf *);
730a9108ebSHasso Tepper 
740a9108ebSHasso Tepper static const struct btproto rfcomm_proto = {
750a9108ebSHasso Tepper 	rfcomm_connecting,
760a9108ebSHasso Tepper 	rfcomm_connected,
770a9108ebSHasso Tepper 	rfcomm_disconnected,
780a9108ebSHasso Tepper 	rfcomm_newconn,
790a9108ebSHasso Tepper 	rfcomm_complete,
800a9108ebSHasso Tepper 	rfcomm_linkmode,
810a9108ebSHasso Tepper 	rfcomm_input,
820a9108ebSHasso Tepper };
830a9108ebSHasso Tepper 
840a9108ebSHasso Tepper /* sysctl variables */
850a9108ebSHasso Tepper int rfcomm_sendspace = 4096;
860a9108ebSHasso Tepper int rfcomm_recvspace = 4096;
870a9108ebSHasso Tepper 
880a9108ebSHasso Tepper /*
890a9108ebSHasso Tepper  * rfcomm_ctloutput(request, socket, level, optname, opt)
900a9108ebSHasso Tepper  *
910a9108ebSHasso Tepper  */
92002c1265SMatthew Dillon void
rfcomm_ctloutput(netmsg_t msg)93002c1265SMatthew Dillon rfcomm_ctloutput(netmsg_t msg)
940a9108ebSHasso Tepper {
95002c1265SMatthew Dillon 	struct socket *so = msg->ctloutput.base.nm_so;
96002c1265SMatthew Dillon 	struct sockopt *sopt = msg->ctloutput.nm_sopt;
970a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
980a9108ebSHasso Tepper 	struct mbuf *m;
99002c1265SMatthew Dillon 	int error = 0;
1000a9108ebSHasso Tepper 
1010a9108ebSHasso Tepper #ifdef notyet			/* XXX */
1020a9108ebSHasso Tepper 	DPRINTFN(2, "%s\n", prcorequests[sopt->sopt_dir]);
1030a9108ebSHasso Tepper #endif
1040a9108ebSHasso Tepper 
105002c1265SMatthew Dillon 	if (pcb == NULL) {
106002c1265SMatthew Dillon 		error = EINVAL;
107002c1265SMatthew Dillon 		goto out;
108002c1265SMatthew Dillon 	}
1090a9108ebSHasso Tepper 
110002c1265SMatthew Dillon 	if (sopt->sopt_level != BTPROTO_RFCOMM) {
111002c1265SMatthew Dillon 		error = ENOPROTOOPT;
112002c1265SMatthew Dillon 		goto out;
113002c1265SMatthew Dillon 	}
1140a9108ebSHasso Tepper 
1150a9108ebSHasso Tepper 	switch(sopt->sopt_dir) {
1160a9108ebSHasso Tepper 	case PRCO_GETOPT:
117b5523eacSSascha Wildner 		m = m_get(M_WAITOK, MT_DATA);
1180a9108ebSHasso Tepper 		crit_enter();
1190a9108ebSHasso Tepper 		m->m_len = rfcomm_getopt(pcb, sopt->sopt_name, mtod(m, void *));
1200a9108ebSHasso Tepper 		crit_exit();
1210a9108ebSHasso Tepper 		if (m->m_len == 0) {
1220a9108ebSHasso Tepper 			m_freem(m);
1230a9108ebSHasso Tepper 			m = NULL;
124002c1265SMatthew Dillon 			error = ENOPROTOOPT;
1250a9108ebSHasso Tepper 		}
126d82b71f8SAggelos Economopoulos 		soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
1270a9108ebSHasso Tepper 		break;
1280a9108ebSHasso Tepper 
1290a9108ebSHasso Tepper 	case PRCO_SETOPT:
130002c1265SMatthew Dillon 		error = rfcomm_setopt2(pcb, sopt->sopt_name, so, sopt);
1310a9108ebSHasso Tepper 
1320a9108ebSHasso Tepper 		break;
1330a9108ebSHasso Tepper 
1340a9108ebSHasso Tepper 	default:
135002c1265SMatthew Dillon 		error = ENOPROTOOPT;
1360a9108ebSHasso Tepper 		break;
1370a9108ebSHasso Tepper 	}
138002c1265SMatthew Dillon out:
139002c1265SMatthew Dillon 	lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
1400a9108ebSHasso Tepper }
1410a9108ebSHasso Tepper 
1420a9108ebSHasso Tepper /**********************************************************************
1430a9108ebSHasso Tepper  *
1440a9108ebSHasso Tepper  * RFCOMM callbacks
1450a9108ebSHasso Tepper  */
1460a9108ebSHasso Tepper 
1470a9108ebSHasso Tepper static void
rfcomm_connecting(void * arg)1480a9108ebSHasso Tepper rfcomm_connecting(void *arg)
1490a9108ebSHasso Tepper {
1500a9108ebSHasso Tepper 	/* struct socket *so = arg; */
1510a9108ebSHasso Tepper 
1520a9108ebSHasso Tepper 	KKASSERT(arg != NULL);
1530a9108ebSHasso Tepper 	DPRINTF("Connecting\n");
1540a9108ebSHasso Tepper }
1550a9108ebSHasso Tepper 
1560a9108ebSHasso Tepper static void
rfcomm_connected(void * arg)1570a9108ebSHasso Tepper rfcomm_connected(void *arg)
1580a9108ebSHasso Tepper {
1590a9108ebSHasso Tepper 	struct socket *so = arg;
1600a9108ebSHasso Tepper 
1610a9108ebSHasso Tepper 	KKASSERT(so != NULL);
1620a9108ebSHasso Tepper 	DPRINTF("Connected\n");
1630a9108ebSHasso Tepper 	soisconnected(so);
1640a9108ebSHasso Tepper }
1650a9108ebSHasso Tepper 
1660a9108ebSHasso Tepper static void
rfcomm_disconnected(void * arg,int err)1670a9108ebSHasso Tepper rfcomm_disconnected(void *arg, int err)
1680a9108ebSHasso Tepper {
1690a9108ebSHasso Tepper 	struct socket *so = arg;
1700a9108ebSHasso Tepper 
1710a9108ebSHasso Tepper 	KKASSERT(so != NULL);
1720a9108ebSHasso Tepper 	DPRINTF("Disconnected\n");
1730a9108ebSHasso Tepper 
1740a9108ebSHasso Tepper 	so->so_error = err;
1750a9108ebSHasso Tepper 	soisdisconnected(so);
1760a9108ebSHasso Tepper }
1770a9108ebSHasso Tepper 
1780a9108ebSHasso Tepper static void *
rfcomm_newconn(void * arg,struct sockaddr_bt * laddr,struct sockaddr_bt * raddr)1790a9108ebSHasso Tepper rfcomm_newconn(void *arg, struct sockaddr_bt *laddr,
1800a9108ebSHasso Tepper     struct sockaddr_bt *raddr)
1810a9108ebSHasso Tepper {
1820a9108ebSHasso Tepper 	struct socket *so = arg;
1830a9108ebSHasso Tepper 
1840a9108ebSHasso Tepper 	DPRINTF("New Connection\n");
1850a9108ebSHasso Tepper 	so = sonewconn(so, 0);
1860a9108ebSHasso Tepper 	if (so == NULL)
1870a9108ebSHasso Tepper 		return NULL;
1880a9108ebSHasso Tepper 
1890a9108ebSHasso Tepper 	soisconnecting(so);
1900a9108ebSHasso Tepper 
1910a9108ebSHasso Tepper 	return so->so_pcb;
1920a9108ebSHasso Tepper }
1930a9108ebSHasso Tepper 
1940a9108ebSHasso Tepper /*
1950a9108ebSHasso Tepper  * rfcomm_complete(rfcomm_dlc, length)
1960a9108ebSHasso Tepper  *
1970a9108ebSHasso Tepper  * length bytes are sent and may be removed from socket buffer
1980a9108ebSHasso Tepper  */
1990a9108ebSHasso Tepper static void
rfcomm_complete(void * arg,int length)2000a9108ebSHasso Tepper rfcomm_complete(void *arg, int length)
2010a9108ebSHasso Tepper {
2020a9108ebSHasso Tepper 	struct socket *so = arg;
2030a9108ebSHasso Tepper 
2040a9108ebSHasso Tepper 	sbdrop(&so->so_snd.sb, length);
2050a9108ebSHasso Tepper 	sowwakeup(so);
2060a9108ebSHasso Tepper }
2070a9108ebSHasso Tepper 
2080a9108ebSHasso Tepper /*
2090a9108ebSHasso Tepper  * rfcomm_linkmode(rfcomm_dlc, new)
2100a9108ebSHasso Tepper  *
2110a9108ebSHasso Tepper  * link mode change notification.
2120a9108ebSHasso Tepper  */
2130a9108ebSHasso Tepper static void
rfcomm_linkmode(void * arg,int new)2140a9108ebSHasso Tepper rfcomm_linkmode(void *arg, int new)
2150a9108ebSHasso Tepper {
2160a9108ebSHasso Tepper 	struct socket *so = arg;
2170a9108ebSHasso Tepper 	int mode;
2180a9108ebSHasso Tepper 
2190a9108ebSHasso Tepper 	DPRINTF("auth %s, encrypt %s, secure %s\n",
2200a9108ebSHasso Tepper 		(new & RFCOMM_LM_AUTH ? "on" : "off"),
2210a9108ebSHasso Tepper 		(new & RFCOMM_LM_ENCRYPT ? "on" : "off"),
2220a9108ebSHasso Tepper 		(new & RFCOMM_LM_SECURE ? "on" : "off"));
2230a9108ebSHasso Tepper 
2240a9108ebSHasso Tepper 	(void)rfcomm_getopt(so->so_pcb, SO_RFCOMM_LM, &mode);
2250a9108ebSHasso Tepper 	if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH))
2260a9108ebSHasso Tepper 	    || ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT))
2270a9108ebSHasso Tepper 	    || ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE)))
2280a9108ebSHasso Tepper 		rfcomm_disconnect(so->so_pcb, 0);
2290a9108ebSHasso Tepper }
2300a9108ebSHasso Tepper 
2310a9108ebSHasso Tepper /*
2320a9108ebSHasso Tepper  * rfcomm_input(rfcomm_dlc, mbuf)
2330a9108ebSHasso Tepper  */
2340a9108ebSHasso Tepper static void
rfcomm_input(void * arg,struct mbuf * m)2350a9108ebSHasso Tepper rfcomm_input(void *arg, struct mbuf *m)
2360a9108ebSHasso Tepper {
2370a9108ebSHasso Tepper 	struct socket *so = arg;
2380a9108ebSHasso Tepper 
2390a9108ebSHasso Tepper 	KKASSERT(so != NULL);
2400a9108ebSHasso Tepper 
2410a9108ebSHasso Tepper 	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
2420a9108ebSHasso Tepper 		kprintf("%s: %d bytes dropped (socket buffer full)\n",
2430a9108ebSHasso Tepper 			__func__, m->m_pkthdr.len);
2440a9108ebSHasso Tepper 		m_freem(m);
2450a9108ebSHasso Tepper 		return;
2460a9108ebSHasso Tepper 	}
2470a9108ebSHasso Tepper 
2480a9108ebSHasso Tepper 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
2490a9108ebSHasso Tepper 
2500a9108ebSHasso Tepper 	sbappendstream(&so->so_rcv.sb, m);
2510a9108ebSHasso Tepper 	sorwakeup(so);
2520a9108ebSHasso Tepper }
2530a9108ebSHasso Tepper 
2540a9108ebSHasso Tepper /*
2550a9108ebSHasso Tepper  * Implementation of usrreqs.
2560a9108ebSHasso Tepper  */
257002c1265SMatthew Dillon static void
rfcomm_sdetach(netmsg_t msg)258002c1265SMatthew Dillon rfcomm_sdetach(netmsg_t msg)
2590a9108ebSHasso Tepper {
260002c1265SMatthew Dillon 	struct socket *so = msg->detach.base.nm_so;
261002c1265SMatthew Dillon 	int error;
262002c1265SMatthew Dillon 
263002c1265SMatthew Dillon 	error = rfcomm_detach((struct rfcomm_dlc **)&so->so_pcb);
264002c1265SMatthew Dillon 	lwkt_replymsg(&msg->detach.base.lmsg, error);
2650a9108ebSHasso Tepper }
2660a9108ebSHasso Tepper 
2676cef7136SMatthew Dillon /*
2686cef7136SMatthew Dillon  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
2696cef7136SMatthew Dillon  *	 will sofree() it when we return.
2706cef7136SMatthew Dillon  */
271002c1265SMatthew Dillon static void
rfcomm_sabort(netmsg_t msg)272002c1265SMatthew Dillon rfcomm_sabort(netmsg_t msg)
2730a9108ebSHasso Tepper {
274002c1265SMatthew Dillon 	struct socket *so = msg->abort.base.nm_so;
2750a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
2760a9108ebSHasso Tepper 
2770a9108ebSHasso Tepper 	rfcomm_disconnect(pcb, 0);
2780a9108ebSHasso Tepper 	soisdisconnected(so);
279002c1265SMatthew Dillon 	rfcomm_sdetach(msg);
280002c1265SMatthew Dillon 	/* msg invalid now */
2810a9108ebSHasso Tepper }
2820a9108ebSHasso Tepper 
283002c1265SMatthew Dillon static void
rfcomm_sdisconnect(netmsg_t msg)284002c1265SMatthew Dillon rfcomm_sdisconnect(netmsg_t msg)
2850a9108ebSHasso Tepper {
286002c1265SMatthew Dillon 	struct socket *so = msg->abort.base.nm_so;
2870a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
288002c1265SMatthew Dillon 	int error;
2890a9108ebSHasso Tepper 
2900a9108ebSHasso Tepper 	soisdisconnecting(so);
291002c1265SMatthew Dillon 	error = rfcomm_disconnect(pcb, so->so_linger);
292002c1265SMatthew Dillon 	lwkt_replymsg(&msg->disconnect.base.lmsg, error);
2930a9108ebSHasso Tepper }
2940a9108ebSHasso Tepper 
295002c1265SMatthew Dillon static void
rfcomm_scontrol(netmsg_t msg)296002c1265SMatthew Dillon rfcomm_scontrol(netmsg_t msg)
2970a9108ebSHasso Tepper {
298002c1265SMatthew Dillon 	lwkt_replymsg(&msg->control.base.lmsg, EPASSTHROUGH);
2990a9108ebSHasso Tepper }
3000a9108ebSHasso Tepper 
301002c1265SMatthew Dillon static void
rfcomm_sattach(netmsg_t msg)302002c1265SMatthew Dillon rfcomm_sattach(netmsg_t msg)
3030a9108ebSHasso Tepper {
304002c1265SMatthew Dillon 	struct socket *so = msg->attach.base.nm_so;
3050a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
306002c1265SMatthew Dillon 	int error;
3070a9108ebSHasso Tepper 
308002c1265SMatthew Dillon 	if (pcb != NULL) {
309002c1265SMatthew Dillon 		error = EINVAL;
310002c1265SMatthew Dillon 		goto out;
311002c1265SMatthew Dillon 	}
3120a9108ebSHasso Tepper 
3130a9108ebSHasso Tepper 	/*
3140a9108ebSHasso Tepper 	 * Since we have nothing to add, we attach the DLC
3150a9108ebSHasso Tepper 	 * structure directly to our PCB pointer.
3160a9108ebSHasso Tepper 	 */
317002c1265SMatthew Dillon 	error = soreserve(so, rfcomm_sendspace, rfcomm_recvspace, NULL);
318002c1265SMatthew Dillon 	if (error)
319002c1265SMatthew Dillon 		goto out;
32083aacedeSHasso Tepper 
321002c1265SMatthew Dillon 	error = rfcomm_attach((struct rfcomm_dlc **)&so->so_pcb,
3220a9108ebSHasso Tepper 			      &rfcomm_proto, so);
323002c1265SMatthew Dillon 	if (error)
324002c1265SMatthew Dillon 		goto out;
3250a9108ebSHasso Tepper 
326002c1265SMatthew Dillon 	error = rfcomm_rcvd(so->so_pcb, sbspace(&so->so_rcv));
327002c1265SMatthew Dillon 	if (error)
32883aacedeSHasso Tepper 		rfcomm_detach((struct rfcomm_dlc **)&so->so_pcb);
329002c1265SMatthew Dillon out:
330002c1265SMatthew Dillon 	lwkt_replymsg(&msg->attach.base.lmsg, error);
33183aacedeSHasso Tepper }
3320a9108ebSHasso Tepper 
333002c1265SMatthew Dillon static void
rfcomm_sbind(netmsg_t msg)334002c1265SMatthew Dillon rfcomm_sbind(netmsg_t msg)
3350a9108ebSHasso Tepper {
336002c1265SMatthew Dillon 	struct socket *so = msg->bind.base.nm_so;
337002c1265SMatthew Dillon 	struct sockaddr *nam = msg->bind.nm_nam;
3380a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
3390a9108ebSHasso Tepper 	struct sockaddr_bt *sa;
340002c1265SMatthew Dillon 	int error;
3410a9108ebSHasso Tepper 
3420a9108ebSHasso Tepper 	KKASSERT(nam != NULL);
3430a9108ebSHasso Tepper 	sa = (struct sockaddr_bt *)nam;
3440a9108ebSHasso Tepper 
345002c1265SMatthew Dillon 	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
346002c1265SMatthew Dillon 		error = EINVAL;
347002c1265SMatthew Dillon 	} else if (sa->bt_family != AF_BLUETOOTH) {
348002c1265SMatthew Dillon 		error = EAFNOSUPPORT;
349002c1265SMatthew Dillon 	} else {
350002c1265SMatthew Dillon 		error = rfcomm_bind(pcb, sa);
351002c1265SMatthew Dillon 	}
352002c1265SMatthew Dillon 	lwkt_replymsg(&msg->bind.base.lmsg, error);
3530a9108ebSHasso Tepper }
3540a9108ebSHasso Tepper 
355002c1265SMatthew Dillon static void
rfcomm_sconnect(netmsg_t msg)356002c1265SMatthew Dillon rfcomm_sconnect(netmsg_t msg)
3570a9108ebSHasso Tepper {
358002c1265SMatthew Dillon 	struct socket *so = msg->connect.base.nm_so;
359002c1265SMatthew Dillon 	struct sockaddr *nam = msg->connect.nm_nam;
3600a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
3610a9108ebSHasso Tepper 	struct sockaddr_bt *sa;
362002c1265SMatthew Dillon 	int error;
3630a9108ebSHasso Tepper 
3640a9108ebSHasso Tepper 	KKASSERT(nam != NULL);
3650a9108ebSHasso Tepper 	sa = (struct sockaddr_bt *)nam;
3660a9108ebSHasso Tepper 
367002c1265SMatthew Dillon 	if (sa->bt_len != sizeof(struct sockaddr_bt)) {
368002c1265SMatthew Dillon 		error = EINVAL;
369002c1265SMatthew Dillon 	} else if (sa->bt_family != AF_BLUETOOTH) {
370002c1265SMatthew Dillon 		error = EAFNOSUPPORT;
371002c1265SMatthew Dillon 	} else {
3720a9108ebSHasso Tepper 		soisconnecting(so);
373002c1265SMatthew Dillon 		error = rfcomm_connect(pcb, sa);
374002c1265SMatthew Dillon 	}
375002c1265SMatthew Dillon 	lwkt_replymsg(&msg->connect.base.lmsg, error);
3760a9108ebSHasso Tepper }
3770a9108ebSHasso Tepper 
378002c1265SMatthew Dillon static void
rfcomm_speeraddr(netmsg_t msg)379002c1265SMatthew Dillon rfcomm_speeraddr(netmsg_t msg)
3800a9108ebSHasso Tepper {
381002c1265SMatthew Dillon 	struct socket *so = msg->peeraddr.base.nm_so;
382002c1265SMatthew Dillon 	struct sockaddr **nam = msg->peeraddr.nm_nam;
3830a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
3840a9108ebSHasso Tepper 	struct sockaddr_bt *sa, ssa;
385002c1265SMatthew Dillon 	int error;
3860a9108ebSHasso Tepper 
3870a9108ebSHasso Tepper 	sa = &ssa;
3880a9108ebSHasso Tepper 	bzero(sa, sizeof *sa);
3890a9108ebSHasso Tepper 	sa->bt_len = sizeof(struct sockaddr_bt);
3900a9108ebSHasso Tepper 	sa->bt_family = AF_BLUETOOTH;
3913598cc14SSascha Wildner 	error = rfcomm_peeraddr(pcb, sa);
3920a9108ebSHasso Tepper 	*nam = dup_sockaddr((struct sockaddr *)sa);
393002c1265SMatthew Dillon 
394002c1265SMatthew Dillon 	lwkt_replymsg(&msg->peeraddr.base.lmsg, error);
3950a9108ebSHasso Tepper }
3960a9108ebSHasso Tepper 
397002c1265SMatthew Dillon static void
rfcomm_ssockaddr(netmsg_t msg)398002c1265SMatthew Dillon rfcomm_ssockaddr(netmsg_t msg)
3990a9108ebSHasso Tepper {
400002c1265SMatthew Dillon 	struct socket *so = msg->sockaddr.base.nm_so;
401002c1265SMatthew Dillon 	struct sockaddr **nam = msg->sockaddr.nm_nam;
4020a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
4030a9108ebSHasso Tepper 	struct sockaddr_bt *sa, ssa;
404002c1265SMatthew Dillon 	int error;
4050a9108ebSHasso Tepper 
4060a9108ebSHasso Tepper 	sa = &ssa;
4070a9108ebSHasso Tepper 	bzero(sa, sizeof *sa);
4080a9108ebSHasso Tepper 	sa->bt_len = sizeof(struct sockaddr_bt);
4090a9108ebSHasso Tepper 	sa->bt_family = AF_BLUETOOTH;
4103598cc14SSascha Wildner 	error = rfcomm_sockaddr(pcb, sa);
4110a9108ebSHasso Tepper 	*nam = dup_sockaddr((struct sockaddr *)sa);
412002c1265SMatthew Dillon 
413002c1265SMatthew Dillon 	lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
4140a9108ebSHasso Tepper }
4150a9108ebSHasso Tepper 
416002c1265SMatthew Dillon static void
rfcomm_sshutdown(netmsg_t msg)417002c1265SMatthew Dillon rfcomm_sshutdown(netmsg_t msg)
4180a9108ebSHasso Tepper {
419002c1265SMatthew Dillon 	struct socket *so = msg->shutdown.base.nm_so;
420002c1265SMatthew Dillon 
4210a9108ebSHasso Tepper 	socantsendmore(so);
422002c1265SMatthew Dillon 	lwkt_replymsg(&msg->shutdown.base.lmsg, 0);
4230a9108ebSHasso Tepper }
4240a9108ebSHasso Tepper 
425002c1265SMatthew Dillon static void
rfcomm_ssend(netmsg_t msg)426002c1265SMatthew Dillon rfcomm_ssend(netmsg_t msg)
4270a9108ebSHasso Tepper {
428002c1265SMatthew Dillon 	struct socket *so = msg->send.base.nm_so;
429002c1265SMatthew Dillon 	struct mbuf *m = msg->send.nm_m;
430002c1265SMatthew Dillon 	struct mbuf *control = msg->send.nm_control;
4310a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
4320a9108ebSHasso Tepper 	struct mbuf *m0;
433002c1265SMatthew Dillon 	int error;
4340a9108ebSHasso Tepper 
4350a9108ebSHasso Tepper 	KKASSERT(m != NULL);
4360a9108ebSHasso Tepper 
437002c1265SMatthew Dillon 	/* no use for that */
438002c1265SMatthew Dillon 	if (control) {
4390a9108ebSHasso Tepper 		m_freem(control);
440002c1265SMatthew Dillon 		control = NULL;
4410a9108ebSHasso Tepper 	}
4420a9108ebSHasso Tepper 
443b5523eacSSascha Wildner 	m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
444002c1265SMatthew Dillon 	if (m0) {
445002c1265SMatthew Dillon 		sbappendstream(&so->so_snd.sb, m);
446002c1265SMatthew Dillon 		error = rfcomm_send(pcb, m0);
447002c1265SMatthew Dillon 	} else {
448002c1265SMatthew Dillon 		error = ENOMEM;
449002c1265SMatthew Dillon 	}
450002c1265SMatthew Dillon 	lwkt_replymsg(&msg->send.base.lmsg, error);
451002c1265SMatthew Dillon }
452002c1265SMatthew Dillon 
453002c1265SMatthew Dillon static void
rfcomm_saccept(netmsg_t msg)454002c1265SMatthew Dillon rfcomm_saccept(netmsg_t msg)
4550a9108ebSHasso Tepper {
456002c1265SMatthew Dillon 	struct socket *so = msg->accept.base.nm_so;
457002c1265SMatthew Dillon 	struct sockaddr **nam = msg->accept.nm_nam;
4580a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
4590a9108ebSHasso Tepper 	struct sockaddr_bt *sa, ssa;
460002c1265SMatthew Dillon 	int error;
4610a9108ebSHasso Tepper 
4620a9108ebSHasso Tepper 	sa = &ssa;
4630a9108ebSHasso Tepper 	bzero(sa, sizeof *sa);
4640a9108ebSHasso Tepper 	sa->bt_len = sizeof(struct sockaddr_bt);
4650a9108ebSHasso Tepper 	sa->bt_family = AF_BLUETOOTH;
4663598cc14SSascha Wildner 	error = rfcomm_peeraddr(pcb, sa);
4670a9108ebSHasso Tepper 	*nam = dup_sockaddr((struct sockaddr *)sa);
468002c1265SMatthew Dillon 
469002c1265SMatthew Dillon 	lwkt_replymsg(&msg->accept.base.lmsg, error);
4700a9108ebSHasso Tepper }
4710a9108ebSHasso Tepper 
472002c1265SMatthew Dillon static void
rfcomm_slisten(netmsg_t msg)473002c1265SMatthew Dillon rfcomm_slisten(netmsg_t msg)
4740a9108ebSHasso Tepper {
475002c1265SMatthew Dillon 	struct socket *so = msg->listen.base.nm_so;
4760a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *)so->so_pcb;
477002c1265SMatthew Dillon 	int error;
478002c1265SMatthew Dillon 
479002c1265SMatthew Dillon 	error = rfcomm_listen(pcb);
480002c1265SMatthew Dillon 	lwkt_replymsg(&msg->listen.base.lmsg, error);
4810a9108ebSHasso Tepper }
4820a9108ebSHasso Tepper 
483002c1265SMatthew Dillon static void
rfcomm_srcvd(netmsg_t msg)484002c1265SMatthew Dillon rfcomm_srcvd(netmsg_t msg)
4850a9108ebSHasso Tepper {
486002c1265SMatthew Dillon 	struct socket *so = msg->rcvd.base.nm_so;
4870a9108ebSHasso Tepper 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
488002c1265SMatthew Dillon 	int error;
489002c1265SMatthew Dillon 
490002c1265SMatthew Dillon 	error = rfcomm_rcvd(pcb, sbspace(&so->so_rcv));
491002c1265SMatthew Dillon 	lwkt_replymsg(&msg->rcvd.base.lmsg, error);
4920a9108ebSHasso Tepper }
4930a9108ebSHasso Tepper 
4940a9108ebSHasso Tepper struct pr_usrreqs rfcomm_usrreqs = {
4950a9108ebSHasso Tepper         .pru_abort = rfcomm_sabort,
4960a9108ebSHasso Tepper         .pru_accept = rfcomm_saccept,
4970a9108ebSHasso Tepper         .pru_attach = rfcomm_sattach,
4980a9108ebSHasso Tepper         .pru_bind = rfcomm_sbind,
4990a9108ebSHasso Tepper         .pru_connect = rfcomm_sconnect,
500002c1265SMatthew Dillon         .pru_connect2 = pr_generic_notsupp,
5010a9108ebSHasso Tepper         .pru_control = rfcomm_scontrol,
5020a9108ebSHasso Tepper         .pru_detach = rfcomm_sdetach,
5030a9108ebSHasso Tepper         .pru_disconnect = rfcomm_sdisconnect,
5040a9108ebSHasso Tepper         .pru_listen = rfcomm_slisten,
5050a9108ebSHasso Tepper         .pru_peeraddr = rfcomm_speeraddr,
5060a9108ebSHasso Tepper         .pru_rcvd = rfcomm_srcvd,
507002c1265SMatthew Dillon         .pru_rcvoob = pr_generic_notsupp,
5080a9108ebSHasso Tepper         .pru_send = rfcomm_ssend,
5090a9108ebSHasso Tepper         .pru_sense = pru_sense_null,
5100a9108ebSHasso Tepper         .pru_shutdown = rfcomm_sshutdown,
5110a9108ebSHasso Tepper         .pru_sockaddr = rfcomm_ssockaddr,
5120a9108ebSHasso Tepper         .pru_sosend = sosend,
5138b5c39bbSSamuel J. Greear         .pru_soreceive = soreceive
5140a9108ebSHasso Tepper };
515