Module Name:    src
Committed By:   tls
Date:           Sun Aug 10 06:56:23 UTC 2014

Modified Files:
        src/sys/netbt [tls-earlyentropy]: bluetooth.h bt_proto.c hci.h
            hci_ioctl.c hci_link.c hci_socket.c hci_unit.c l2cap.h
            l2cap_lower.c l2cap_socket.c l2cap_upper.c rfcomm.h rfcomm_dlc.c
            rfcomm_session.c rfcomm_socket.c rfcomm_upper.c sco.h sco_socket.c
            sco_upper.c

Log Message:
Rebase.


To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.11.28.1 src/sys/netbt/bluetooth.h
cvs rdiff -u -r1.12 -r1.12.36.1 src/sys/netbt/bt_proto.c
cvs rdiff -u -r1.35 -r1.35.26.1 src/sys/netbt/hci.h
cvs rdiff -u -r1.10 -r1.10.32.1 src/sys/netbt/hci_ioctl.c
cvs rdiff -u -r1.23 -r1.23.26.1 src/sys/netbt/hci_link.c
cvs rdiff -u -r1.20 -r1.20.28.1 src/sys/netbt/hci_socket.c
cvs rdiff -u -r1.13 -r1.13.26.1 src/sys/netbt/hci_unit.c
cvs rdiff -u -r1.10 -r1.10.28.1 src/sys/netbt/l2cap.h
cvs rdiff -u -r1.9 -r1.9.54.1 src/sys/netbt/l2cap_lower.c
cvs rdiff -u -r1.10 -r1.10.2.1 src/sys/netbt/l2cap_socket.c
cvs rdiff -u -r1.11 -r1.11.36.1 src/sys/netbt/l2cap_upper.c
cvs rdiff -u -r1.9 -r1.9.36.1 src/sys/netbt/rfcomm.h \
    src/sys/netbt/sco_upper.c
cvs rdiff -u -r1.7 -r1.7.26.1 src/sys/netbt/rfcomm_dlc.c
cvs rdiff -u -r1.18 -r1.18.26.1 src/sys/netbt/rfcomm_session.c
cvs rdiff -u -r1.11 -r1.11.2.1 src/sys/netbt/rfcomm_socket.c
cvs rdiff -u -r1.13 -r1.13.36.1 src/sys/netbt/rfcomm_upper.c
cvs rdiff -u -r1.3 -r1.3.54.1 src/sys/netbt/sco.h
cvs rdiff -u -r1.12 -r1.12.2.1 src/sys/netbt/sco_socket.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netbt/bluetooth.h
diff -u src/sys/netbt/bluetooth.h:1.11 src/sys/netbt/bluetooth.h:1.11.28.1
--- src/sys/netbt/bluetooth.h:1.11	Wed Apr 27 00:36:48 2011
+++ src/sys/netbt/bluetooth.h	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: bluetooth.h,v 1.11 2011/04/27 00:36:48 rmind Exp $	*/
+/*	$NetBSD: bluetooth.h,v 1.11.28.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -103,6 +103,8 @@ struct sockaddr_bt {
 
 #ifdef _KERNEL
 
+#include <sys/protosw.h>
+
 #include <sys/mallocvar.h>
 MALLOC_DECLARE(M_BLUETOOTH);
 
@@ -120,6 +122,13 @@ struct btproto {
 	void (*input)(void *, struct mbuf *);
 };
 
+extern const struct pr_usrreqs hci_usrreqs;
+extern const struct pr_usrreqs sco_usrreqs;
+extern const struct pr_usrreqs l2cap_usrreqs;
+extern const struct pr_usrreqs rfcomm_usrreqs;
+
+extern kmutex_t *bt_lock;
+
 /*
  * Debugging stuff
  */
@@ -147,8 +156,6 @@ extern int bluetooth_debug;
 # define UNKNOWN(x) ((void)0)
 #endif	/* BLUETOOTH_DEBUG */
 
-extern kmutex_t *bt_lock;
-
 #endif	/* _KERNEL */
 
 #endif	/* _NETBT_BLUETOOTH_H_ */

Index: src/sys/netbt/bt_proto.c
diff -u src/sys/netbt/bt_proto.c:1.12 src/sys/netbt/bt_proto.c:1.12.36.1
--- src/sys/netbt/bt_proto.c:1.12	Sun Sep 13 18:45:11 2009
+++ src/sys/netbt/bt_proto.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: bt_proto.c,v 1.12 2009/09/13 18:45:11 pooka Exp $	*/
+/*	$NetBSD: bt_proto.c,v 1.12.36.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bt_proto.c,v 1.12 2009/09/13 18:45:11 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bt_proto.c,v 1.12.36.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/domain.h>
@@ -62,17 +62,7 @@ PR_WRAP_CTLOUTPUT(rfcomm_ctloutput)
 #define	l2cap_ctloutput		l2cap_ctloutput_wrapper
 #define	rfcomm_ctloutput	rfcomm_ctloutput_wrapper
 
-PR_WRAP_USRREQ(hci_usrreq)
-PR_WRAP_USRREQ(sco_usrreq)
-PR_WRAP_USRREQ(l2cap_usrreq)
-PR_WRAP_USRREQ(rfcomm_usrreq)
-
-#define	hci_usrreq		hci_usrreq_wrapper
-#define	sco_usrreq		sco_usrreq_wrapper
-#define	l2cap_usrreq		l2cap_usrreq_wrapper
-#define	rfcomm_usrreq		rfcomm_usrreq_wrapper
-
-const struct protosw btsw[] = {
+static const struct protosw btsw[] = {
 	{ /* raw HCI commands */
 		.pr_type = SOCK_RAW,
 		.pr_domain = &btdomain,
@@ -80,7 +70,7 @@ const struct protosw btsw[] = {
 		.pr_flags = (PR_ADDR | PR_ATOMIC),
 		.pr_init = hci_init,
 		.pr_ctloutput = hci_ctloutput,
-		.pr_usrreq = hci_usrreq,
+		.pr_usrreqs = &hci_usrreqs,
 	},
 	{ /* HCI SCO data (audio) */
 		.pr_type = SOCK_SEQPACKET,
@@ -88,7 +78,7 @@ const struct protosw btsw[] = {
 		.pr_protocol = BTPROTO_SCO,
 		.pr_flags = (PR_CONNREQUIRED | PR_ATOMIC | PR_LISTEN),
 		.pr_ctloutput = sco_ctloutput,
-		.pr_usrreq = sco_usrreq,
+		.pr_usrreqs = &sco_usrreqs,
 	},
 	{ /* L2CAP Connection Oriented */
 		.pr_type = SOCK_SEQPACKET,
@@ -96,7 +86,7 @@ const struct protosw btsw[] = {
 		.pr_protocol = BTPROTO_L2CAP,
 		.pr_flags = (PR_CONNREQUIRED | PR_ATOMIC | PR_LISTEN),
 		.pr_ctloutput = l2cap_ctloutput,
-		.pr_usrreq = l2cap_usrreq,
+		.pr_usrreqs = &l2cap_usrreqs,
 		.pr_init = l2cap_init,
 	},
 	{ /* RFCOMM */
@@ -105,7 +95,7 @@ const struct protosw btsw[] = {
 		.pr_protocol = BTPROTO_RFCOMM,
 		.pr_flags = (PR_CONNREQUIRED | PR_LISTEN | PR_WANTRCVD),
 		.pr_ctloutput = rfcomm_ctloutput,
-		.pr_usrreq = rfcomm_usrreq,
+		.pr_usrreqs = &rfcomm_usrreqs,
 		.pr_init = rfcomm_init,
 	},
 };

Index: src/sys/netbt/hci.h
diff -u src/sys/netbt/hci.h:1.35 src/sys/netbt/hci.h:1.35.26.1
--- src/sys/netbt/hci.h:1.35	Sat Sep 17 08:23:36 2011
+++ src/sys/netbt/hci.h	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: hci.h,v 1.35 2011/09/17 08:23:36 plunky Exp $	*/
+/*	$NetBSD: hci.h,v 1.35.26.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -54,7 +54,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: hci.h,v 1.35 2011/09/17 08:23:36 plunky Exp $
+ * $Id: hci.h,v 1.35.26.1 2014/08/10 06:56:23 tls Exp $
  * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_hci.h,v 1.6 2005/01/07 01:45:43 imp Exp $
  */
 
@@ -2536,7 +2536,7 @@ extern SIMPLEQ_HEAD(hci_unit_list, hci_u
 void hci_event(struct mbuf *, struct hci_unit *);
 
 /* hci_ioctl.c */
-int hci_ioctl(unsigned long, void *, struct lwp *);
+int hci_ioctl_pcb(unsigned long, void *);
 
 /* hci_link.c */
 struct hci_link *hci_acl_open(struct hci_unit *, bdaddr_t *);
@@ -2567,13 +2567,12 @@ void hci_memo_free(struct hci_memo *);
 /* hci_socket.c */
 void hci_drop(void *);
 void hci_init(void);
-int hci_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *);
 int hci_ctloutput(int, struct socket *, struct sockopt *);
 void hci_mtap(struct mbuf *, struct hci_unit *);
 
 /* hci_unit.c */
-struct hci_unit *hci_attach(const struct hci_if *, device_t, uint16_t);
-void hci_detach(struct hci_unit *);
+struct hci_unit *hci_attach_pcb(const struct hci_if *, device_t, uint16_t);
+void hci_detach_pcb(struct hci_unit *);
 int hci_enable(struct hci_unit *);
 void hci_disable(struct hci_unit *);
 struct hci_unit *hci_unit_lookup(const bdaddr_t *);

Index: src/sys/netbt/hci_ioctl.c
diff -u src/sys/netbt/hci_ioctl.c:1.10 src/sys/netbt/hci_ioctl.c:1.10.32.1
--- src/sys/netbt/hci_ioctl.c:1.10	Mon Nov 22 19:56:51 2010
+++ src/sys/netbt/hci_ioctl.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: hci_ioctl.c,v 1.10 2010/11/22 19:56:51 plunky Exp $	*/
+/*	$NetBSD: hci_ioctl.c,v 1.10.32.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hci_ioctl.c,v 1.10 2010/11/22 19:56:51 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hci_ioctl.c,v 1.10.32.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/domain.h>
@@ -132,7 +132,7 @@ hci_dump(void)
 #endif
 
 int
-hci_ioctl(unsigned long cmd, void *data, struct lwp *l)
+hci_ioctl_pcb(unsigned long cmd, void *data)
 {
 	struct btreq *btr = data;
 	struct hci_unit *unit;
@@ -225,7 +225,7 @@ hci_ioctl(unsigned long cmd, void *data,
 		break;
 
 	case SIOCSBTFLAGS:	/* set unit flags (privileged) */
-		err = kauth_authorize_device(l->l_cred,
+		err = kauth_authorize_device(curlwp->l_cred,
 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
 		    btr, NULL);
 		if (err)
@@ -253,7 +253,7 @@ hci_ioctl(unsigned long cmd, void *data,
 		break;
 
 	case SIOCSBTPOLICY:	/* set unit link policy (privileged) */
-		err = kauth_authorize_device(l->l_cred,
+		err = kauth_authorize_device(curlwp->l_cred,
 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
 		    btr, NULL);
 		if (err)
@@ -265,7 +265,7 @@ hci_ioctl(unsigned long cmd, void *data,
 		break;
 
 	case SIOCSBTPTYPE:	/* set unit packet types (privileged) */
-		err = kauth_authorize_device(l->l_cred,
+		err = kauth_authorize_device(curlwp->l_cred,
 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
 		    btr, NULL);
 		if (err)
@@ -281,7 +281,7 @@ hci_ioctl(unsigned long cmd, void *data,
 		break;
 
 	case SIOCZBTSTATS:	/* get & reset unit statistics */
-		err = kauth_authorize_device(l->l_cred,
+		err = kauth_authorize_device(curlwp->l_cred,
 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
 		    btr, NULL);
 		if (err)
@@ -297,7 +297,7 @@ hci_ioctl(unsigned long cmd, void *data,
 		 * sent to USB bluetooth controllers that are not an
 		 * integer number of frame sizes, the USB bus locks up.
 		 */
-		err = kauth_authorize_device(l->l_cred,
+		err = kauth_authorize_device(curlwp->l_cred,
 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
 		    btr, NULL);
 		if (err)

Index: src/sys/netbt/hci_link.c
diff -u src/sys/netbt/hci_link.c:1.23 src/sys/netbt/hci_link.c:1.23.26.1
--- src/sys/netbt/hci_link.c:1.23	Wed Jul 27 10:25:09 2011
+++ src/sys/netbt/hci_link.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: hci_link.c,v 1.23 2011/07/27 10:25:09 plunky Exp $	*/
+/*	$NetBSD: hci_link.c,v 1.23.26.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hci_link.c,v 1.23 2011/07/27 10:25:09 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hci_link.c,v 1.23.26.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -799,7 +799,7 @@ hci_sco_newconn(struct hci_unit *unit, b
 
 		sco = hci_link_alloc(unit, bdaddr, HCI_LINK_SCO);
 		if (sco == NULL) {
-			sco_detach(&new);
+			sco_detach_pcb(&new);
 			return NULL;
 		}
 

Index: src/sys/netbt/hci_socket.c
diff -u src/sys/netbt/hci_socket.c:1.20 src/sys/netbt/hci_socket.c:1.20.28.1
--- src/sys/netbt/hci_socket.c:1.20	Sun Jan 30 17:23:23 2011
+++ src/sys/netbt/hci_socket.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: hci_socket.c,v 1.20 2011/01/30 17:23:23 plunky Exp $	*/
+/*	$NetBSD: hci_socket.c,v 1.20.28.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hci_socket.c,v 1.20 2011/01/30 17:23:23 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hci_socket.c,v 1.20.28.1 2014/08/10 06:56:23 tls Exp $");
 
 /* load symbolic names */
 #ifdef BLUETOOTH_DEBUG
@@ -43,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: hci_socket.c
 #include <sys/domain.h>
 #include <sys/kauth.h>
 #include <sys/kernel.h>
+#include <sys/kmem.h>
 #include <sys/mbuf.h>
 #include <sys/proc.h>
 #include <sys/protosw.h>
@@ -352,7 +353,7 @@ hci_cmdwait_flush(struct socket *so)
  *     This came from userland, so check it out.
  */
 static int
-hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr)
+hci_send_pcb(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr)
 {
 	struct hci_unit *unit;
 	struct mbuf *m0;
@@ -425,206 +426,352 @@ bad:
 	return err;
 }
 
-/*
- * User Request.
- * up is socket
- * m is either
- *	optional mbuf chain containing message
- *	ioctl command (PRU_CONTROL)
- * nam is either
- *	optional mbuf chain containing an address
- *	ioctl data (PRU_CONTROL)
- *      optionally, protocol number (PRU_ATTACH)
- * ctl is optional mbuf chain containing socket options
- * l is pointer to process requesting action (if any)
- *
- * we are responsible for disposing of m and ctl if
- * they are mbuf chains
- */
-int
-hci_usrreq(struct socket *up, int req, struct mbuf *m,
-		struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
+static int
+hci_attach(struct socket *so, int proto)
+{
+	struct hci_pcb *pcb;
+	int error;
+
+	KASSERT(so->so_pcb == NULL);
+
+	if (so->so_lock == NULL) {
+		mutex_obj_hold(bt_lock);
+		so->so_lock = bt_lock;
+		solock(so);
+	}
+	KASSERT(solocked(so));
+
+	error = soreserve(so, hci_sendspace, hci_recvspace);
+	if (error) {
+		return error;
+	}
+
+	pcb = kmem_zalloc(sizeof(struct hci_pcb), KM_SLEEP);
+	pcb->hp_cred = kauth_cred_dup(curlwp->l_cred);
+	pcb->hp_socket = so;
+
+	/*
+	 * Set default user filter. By default, socket only passes
+	 * Command_Complete and Command_Status Events.
+	 */
+	hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter);
+	hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter);
+	hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter);
+
+	LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next);
+	so->so_pcb = pcb;
+
+	return 0;
+}
+
+static void
+hci_detach(struct socket *so)
+{
+	struct hci_pcb *pcb;
+
+	pcb = (struct hci_pcb *)so->so_pcb;
+	KASSERT(pcb != NULL);
+
+	if (so->so_snd.sb_mb != NULL)
+		hci_cmdwait_flush(so);
+
+	if (pcb->hp_cred != NULL)
+		kauth_cred_free(pcb->hp_cred);
+
+	so->so_pcb = NULL;
+	LIST_REMOVE(pcb, hp_next);
+	kmem_free(pcb, sizeof(*pcb));
+}
+
+static int
+hci_accept(struct socket *so, struct mbuf *nam)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+hci_bind(struct socket *so, struct mbuf *nam, struct lwp *l)
 {
-	struct hci_pcb *pcb = (struct hci_pcb *)up->so_pcb;
+	struct hci_pcb *pcb = so->so_pcb;
 	struct sockaddr_bt *sa;
-	int err = 0;
 
-	DPRINTFN(2, "%s\n", prurequests[req]);
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
 
-	switch(req) {
-	case PRU_CONTROL:
-		mutex_enter(bt_lock);
-		err = hci_ioctl((unsigned long)m, (void *)nam, l);
-		mutex_exit(bt_lock);
-		return err;
-
-	case PRU_PURGEIF:
-		return EOPNOTSUPP;
-
-	case PRU_ATTACH:
-		if (up->so_lock == NULL) {
-			mutex_obj_hold(bt_lock);
-			up->so_lock = bt_lock;
-			solock(up);
-		}
-		KASSERT(solocked(up));
-		if (pcb)
-			return EINVAL;
-		err = soreserve(up, hci_sendspace, hci_recvspace);
-		if (err)
-			return err;
-
-		pcb = malloc(sizeof(struct hci_pcb), M_PCB, M_NOWAIT | M_ZERO);
-		if (pcb == NULL)
-			return ENOMEM;
+	sa = mtod(nam, struct sockaddr_bt *);
+	if (sa->bt_len != sizeof(struct sockaddr_bt))
+		return EINVAL;
 
-		up->so_pcb = pcb;
-		pcb->hp_socket = up;
+	if (sa->bt_family != AF_BLUETOOTH)
+		return EAFNOSUPPORT;
 
-		if (l != NULL)
-			pcb->hp_cred = kauth_cred_dup(l->l_cred);
+	bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr);
 
-		/*
-		 * Set default user filter. By default, socket only passes
-		 * Command_Complete and Command_Status Events.
-		 */
-		hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter);
-		hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter);
-		hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter);
+	if (bdaddr_any(&sa->bt_bdaddr))
+		pcb->hp_flags |= HCI_PROMISCUOUS;
+	else
+		pcb->hp_flags &= ~HCI_PROMISCUOUS;
 
-		LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next);
+	return 0;
+}
 
-		return 0;
-	}
+static int
+hci_listen(struct socket *so, struct lwp *l)
+{
+	KASSERT(solocked(so));
 
-	/* anything after here *requires* a pcb */
-	if (pcb == NULL) {
-		err = EINVAL;
-		goto release;
-	}
+	return EOPNOTSUPP;
+}
 
-	switch(req) {
-	case PRU_DISCONNECT:
-		bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY);
+static int
+hci_connect(struct socket *so, struct mbuf *nam, struct lwp *l)
+{
+	struct hci_pcb *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
 
-		/* XXX we cannot call soisdisconnected() here, as it sets
-		 * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being,
-		 * that soisconnected() does not clear these and if you
-		 * try to reconnect this socket (which is permitted) you
-		 * get a broken pipe when you try to write any data.
-		 */
-		up->so_state &= ~SS_ISCONNECTED;
-		break;
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
 
-	case PRU_ABORT:
-		soisdisconnected(up);
-		/* fall through to */
-	case PRU_DETACH:
-		if (up->so_snd.sb_mb != NULL)
-			hci_cmdwait_flush(up);
-
-		if (pcb->hp_cred != NULL)
-			kauth_cred_free(pcb->hp_cred);
-
-		up->so_pcb = NULL;
-		LIST_REMOVE(pcb, hp_next);
-		free(pcb, M_PCB);
-		return 0;
+	sa = mtod(nam, struct sockaddr_bt *);
+	if (sa->bt_len != sizeof(struct sockaddr_bt))
+		return EINVAL;
 
-	case PRU_BIND:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
+	if (sa->bt_family != AF_BLUETOOTH)
+		return EAFNOSUPPORT;
 
-		if (sa->bt_len != sizeof(struct sockaddr_bt))
-			return EINVAL;
+	if (hci_unit_lookup(&sa->bt_bdaddr) == NULL)
+		return EADDRNOTAVAIL;
 
-		if (sa->bt_family != AF_BLUETOOTH)
-			return EAFNOSUPPORT;
+	bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr);
+	soisconnected(so);
+	return 0;
+}
 
-		bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr);
+static int
+hci_connect2(struct socket *so, struct socket *so2)
+{
+	KASSERT(solocked(so));
 
-		if (bdaddr_any(&sa->bt_bdaddr))
-			pcb->hp_flags |= HCI_PROMISCUOUS;
-		else
-			pcb->hp_flags &= ~HCI_PROMISCUOUS;
+	return EOPNOTSUPP;
+}
 
-		return 0;
+static int
+hci_disconnect(struct socket *so)
+{
+	struct hci_pcb *pcb = so->so_pcb;
 
-	case PRU_CONNECT:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
 
-		if (sa->bt_len != sizeof(struct sockaddr_bt))
-			return EINVAL;
+	bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY);
 
-		if (sa->bt_family != AF_BLUETOOTH)
-			return EAFNOSUPPORT;
+	/* XXX we cannot call soisdisconnected() here, as it sets
+	 * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being,
+	 * that soisconnected() does not clear these and if you
+	 * try to reconnect this socket (which is permitted) you
+	 * get a broken pipe when you try to write any data.
+	 */
+	so->so_state &= ~SS_ISCONNECTED;
+	return 0;
+}
 
-		if (hci_unit_lookup(&sa->bt_bdaddr) == NULL)
-			return EADDRNOTAVAIL;
+static int
+hci_shutdown(struct socket *so)
+{
+	KASSERT(solocked(so));
 
-		bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr);
-		soisconnected(up);
-		return 0;
+	socantsendmore(so);
+	return 0;
+}
 
-	case PRU_PEERADDR:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
+static int
+hci_abort(struct socket *so)
+{
+	KASSERT(solocked(so));
 
-		memset(sa, 0, sizeof(struct sockaddr_bt));
-		nam->m_len =
-		sa->bt_len = sizeof(struct sockaddr_bt);
-		sa->bt_family = AF_BLUETOOTH;
-		bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr);
-		return 0;
+	soisdisconnected(so);
+	hci_detach(so);
+	return 0;
+}
 
-	case PRU_SOCKADDR:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
+static int
+hci_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
+{
+	int err;
+	mutex_enter(bt_lock);
+	err = hci_ioctl_pcb(cmd, nam);
+	mutex_exit(bt_lock);
+	return err;
+}
 
-		memset(sa, 0, sizeof(struct sockaddr_bt));
-		nam->m_len =
-		sa->bt_len = sizeof(struct sockaddr_bt);
-		sa->bt_family = AF_BLUETOOTH;
-		bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr);
-		return 0;
+static int
+hci_stat(struct socket *so, struct stat *ub)
+{
+	KASSERT(solocked(so));
 
-	case PRU_SHUTDOWN:
-		socantsendmore(up);
-		break;
+	return 0;
+}
 
-	case PRU_SEND:
-		sa = NULL;
-		if (nam) {
-			sa = mtod(nam, struct sockaddr_bt *);
-
-			if (sa->bt_len != sizeof(struct sockaddr_bt)) {
-				err = EINVAL;
-				goto release;
-			}
+static int
+hci_peeraddr(struct socket *so, struct mbuf *nam)
+{
+	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
+	struct sockaddr_bt *sa;
 
-			if (sa->bt_family != AF_BLUETOOTH) {
-				err = EAFNOSUPPORT;
-				goto release;
-			}
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	memset(sa, 0, sizeof(struct sockaddr_bt));
+	nam->m_len =
+	sa->bt_len = sizeof(struct sockaddr_bt);
+	sa->bt_family = AF_BLUETOOTH;
+	bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr);
+	return 0;
+}
+
+static int
+hci_sockaddr(struct socket *so, struct mbuf *nam)
+{
+	struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	memset(sa, 0, sizeof(struct sockaddr_bt));
+	nam->m_len =
+	sa->bt_len = sizeof(struct sockaddr_bt);
+	sa->bt_family = AF_BLUETOOTH;
+	bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr);
+	return 0;
+}
+
+static int
+hci_rcvd(struct socket *so, int flags, struct lwp *l)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+hci_recvoob(struct socket *so, struct mbuf *m, int flags)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+hci_send(struct socket *so, struct mbuf *m, struct mbuf *nam,
+    struct mbuf *control, struct lwp *l)
+{
+	struct hci_pcb *pcb = so->so_pcb;
+	struct sockaddr_bt * sa = NULL;
+	int err = 0;
+
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+
+	if (control) /* have no use for this */
+		m_freem(control);
+
+	if (nam) {
+		sa = mtod(nam, struct sockaddr_bt *);
+
+		if (sa->bt_len != sizeof(struct sockaddr_bt)) {
+			err = EINVAL;
+			goto release;
+		}
+
+		if (sa->bt_family != AF_BLUETOOTH) {
+			err = EAFNOSUPPORT;
+			goto release;
 		}
+	}
+
+	return hci_send_pcb(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr));
+
+release:
+	if (m)
+		m_freem(m);
+
+	return err;
+}
+
+static int
+hci_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
+{
+	KASSERT(solocked(so));
+
+	if (m)
+		m_freem(m);
+	if (control)
+		m_freem(control);
+
+	return EOPNOTSUPP;
+}
+
+static int
+hci_purgeif(struct socket *so, struct ifnet *ifp)
+{
+
+	return EOPNOTSUPP;
+}
 
-		if (ctl) /* have no use for this */
-			m_freem(ctl);
+/*
+ * User Request.
+ * up is socket
+ * m is optional mbuf chain containing message
+ * nam is optional mbuf chain containing an address
+ * ctl is optional mbuf chain containing socket options
+ * l is pointer to process requesting action (if any)
+ *
+ * we are responsible for disposing of m and ctl
+ */
+static int
+hci_usrreq(struct socket *up, int req, struct mbuf *m,
+		struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
+{
+	struct hci_pcb *pcb = up->so_pcb;
+	int err = 0;
 
-		return hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr));
+	DPRINTFN(2, "%s\n", prurequests[req]);
+	KASSERT(req != PRU_ATTACH);
+	KASSERT(req != PRU_DETACH);
+	KASSERT(req != PRU_ACCEPT);
+	KASSERT(req != PRU_BIND);
+	KASSERT(req != PRU_LISTEN);
+	KASSERT(req != PRU_CONNECT);
+	KASSERT(req != PRU_CONNECT2);
+	KASSERT(req != PRU_DISCONNECT);
+	KASSERT(req != PRU_SHUTDOWN);
+	KASSERT(req != PRU_ABORT);
+	KASSERT(req != PRU_CONTROL);
+	KASSERT(req != PRU_SENSE);
+	KASSERT(req != PRU_PEERADDR);
+	KASSERT(req != PRU_SOCKADDR);
+	KASSERT(req != PRU_RCVD);
+	KASSERT(req != PRU_RCVOOB);
+	KASSERT(req != PRU_SEND);
+	KASSERT(req != PRU_SENDOOB);
+	KASSERT(req != PRU_PURGEIF);
 
-	case PRU_SENSE:
-		return 0;		/* (no sense - Doh!) */
+	/* anything after here *requires* a pcb */
+	if (pcb == NULL) {
+		err = EINVAL;
+		goto release;
+	}
 
-	case PRU_RCVD:
-	case PRU_RCVOOB:
-		return EOPNOTSUPP;	/* (no release) */
-
-	case PRU_ACCEPT:
-	case PRU_CONNECT2:
-	case PRU_LISTEN:
-	case PRU_SENDOOB:
+	switch(req) {
 	case PRU_FASTTIMO:
 	case PRU_SLOWTIMO:
 	case PRU_PROTORCV:
@@ -849,3 +996,49 @@ hci_mtap(struct mbuf *m, struct hci_unit
 		}
 	}
 }
+
+PR_WRAP_USRREQS(hci)
+
+#define	hci_attach		hci_attach_wrapper
+#define	hci_detach		hci_detach_wrapper
+#define	hci_accept		hci_accept_wrapper
+#define	hci_bind		hci_bind_wrapper
+#define	hci_listen		hci_listen_wrapper
+#define	hci_connect		hci_connect_wrapper
+#define	hci_connect2		hci_connect2_wrapper
+#define	hci_disconnect		hci_disconnect_wrapper
+#define	hci_shutdown		hci_shutdown_wrapper
+#define	hci_abort		hci_abort_wrapper
+#define	hci_ioctl		hci_ioctl_wrapper
+#define	hci_stat		hci_stat_wrapper
+#define	hci_peeraddr		hci_peeraddr_wrapper
+#define	hci_sockaddr		hci_sockaddr_wrapper
+#define	hci_rcvd		hci_rcvd_wrapper
+#define	hci_recvoob		hci_recvoob_wrapper
+#define	hci_send		hci_send_wrapper
+#define	hci_sendoob		hci_sendoob_wrapper
+#define	hci_purgeif		hci_purgeif_wrapper
+#define	hci_usrreq		hci_usrreq_wrapper
+
+const struct pr_usrreqs hci_usrreqs = {
+	.pr_attach	= hci_attach,
+	.pr_detach	= hci_detach,
+	.pr_accept	= hci_accept,
+	.pr_bind	= hci_bind,
+	.pr_listen	= hci_listen,
+	.pr_connect	= hci_connect,
+	.pr_connect2	= hci_connect2,
+	.pr_disconnect	= hci_disconnect,
+	.pr_shutdown	= hci_shutdown,
+	.pr_abort	= hci_abort,
+	.pr_ioctl	= hci_ioctl,
+	.pr_stat	= hci_stat,
+	.pr_peeraddr	= hci_peeraddr,
+	.pr_sockaddr	= hci_sockaddr,
+	.pr_rcvd	= hci_rcvd,
+	.pr_recvoob	= hci_recvoob,
+	.pr_send	= hci_send,
+	.pr_sendoob	= hci_sendoob,
+	.pr_purgeif	= hci_purgeif,
+	.pr_generic	= hci_usrreq,
+};

Index: src/sys/netbt/hci_unit.c
diff -u src/sys/netbt/hci_unit.c:1.13 src/sys/netbt/hci_unit.c:1.13.26.1
--- src/sys/netbt/hci_unit.c:1.13	Sat Sep 17 08:23:37 2011
+++ src/sys/netbt/hci_unit.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: hci_unit.c,v 1.13 2011/09/17 08:23:37 plunky Exp $	*/
+/*	$NetBSD: hci_unit.c,v 1.13.26.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.13 2011/09/17 08:23:37 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.13.26.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/conf.h>
@@ -81,7 +81,7 @@ static const uint8_t hci_cmds_v10[HCI_CO
 static void hci_intr (void *);
 
 struct hci_unit *
-hci_attach(const struct hci_if *hci_if, device_t dev, uint16_t flags)
+hci_attach_pcb(const struct hci_if *hci_if, device_t dev, uint16_t flags)
 {
 	struct hci_unit *unit;
 
@@ -120,7 +120,7 @@ hci_attach(const struct hci_if *hci_if, 
 }
 
 void
-hci_detach(struct hci_unit *unit)
+hci_detach_pcb(struct hci_unit *unit)
 {
 
 	mutex_enter(bt_lock);

Index: src/sys/netbt/l2cap.h
diff -u src/sys/netbt/l2cap.h:1.10 src/sys/netbt/l2cap.h:1.10.28.1
--- src/sys/netbt/l2cap.h:1.10	Sun Feb  6 18:50:59 2011
+++ src/sys/netbt/l2cap.h	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: l2cap.h,v 1.10 2011/02/06 18:50:59 plunky Exp $	*/
+/*	$NetBSD: l2cap.h,v 1.10.28.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -54,7 +54,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: l2cap.h,v 1.10 2011/02/06 18:50:59 plunky Exp $
+ * $Id: l2cap.h,v 1.10.28.1 2014/08/10 06:56:23 tls Exp $
  * $FreeBSD: src/sys/netgraph/bluetooth/include/l2cap.h,v 1.4 2005/08/31 18:13:23 emax Exp $
  */
 
@@ -458,19 +458,18 @@ int l2cap_send_disconnect_req(struct l2c
 int l2cap_send_connect_rsp(struct hci_link *, uint8_t, uint16_t, uint16_t, uint16_t);
 
 /* l2cap_socket.c */
-int l2cap_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *);
 int l2cap_ctloutput(int, struct socket *, struct sockopt *);
 
 /* l2cap_upper.c */
-int l2cap_attach(struct l2cap_channel **, const struct btproto *, void *);
-int l2cap_bind(struct l2cap_channel *, struct sockaddr_bt *);
-int l2cap_sockaddr(struct l2cap_channel *, struct sockaddr_bt *);
-int l2cap_connect(struct l2cap_channel *, struct sockaddr_bt *);
-int l2cap_peeraddr(struct l2cap_channel *, struct sockaddr_bt *);
-int l2cap_disconnect(struct l2cap_channel *, int);
-int l2cap_detach(struct l2cap_channel **);
-int l2cap_listen(struct l2cap_channel *);
-int l2cap_send(struct l2cap_channel *, struct mbuf *);
+int l2cap_attach_pcb(struct l2cap_channel **, const struct btproto *, void *);
+int l2cap_bind_pcb(struct l2cap_channel *, struct sockaddr_bt *);
+int l2cap_sockaddr_pcb(struct l2cap_channel *, struct sockaddr_bt *);
+int l2cap_connect_pcb(struct l2cap_channel *, struct sockaddr_bt *);
+int l2cap_peeraddr_pcb(struct l2cap_channel *, struct sockaddr_bt *);
+int l2cap_disconnect_pcb(struct l2cap_channel *, int);
+void l2cap_detach_pcb(struct l2cap_channel **);
+int l2cap_listen_pcb(struct l2cap_channel *);
+int l2cap_send_pcb(struct l2cap_channel *, struct mbuf *);
 int l2cap_setopt(struct l2cap_channel *, const struct sockopt *);
 int l2cap_getopt(struct l2cap_channel *, struct sockopt *);
 

Index: src/sys/netbt/l2cap_lower.c
diff -u src/sys/netbt/l2cap_lower.c:1.9 src/sys/netbt/l2cap_lower.c:1.9.54.1
--- src/sys/netbt/l2cap_lower.c:1.9	Tue Aug  5 13:08:31 2008
+++ src/sys/netbt/l2cap_lower.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: l2cap_lower.c,v 1.9 2008/08/05 13:08:31 plunky Exp $	*/
+/*	$NetBSD: l2cap_lower.c,v 1.9.54.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: l2cap_lower.c,v 1.9 2008/08/05 13:08:31 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: l2cap_lower.c,v 1.9.54.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -150,7 +150,7 @@ failed:
 }
 
 /*
- * Start another L2CAP packet on its way. This is called from l2cap_send
+ * Start another L2CAP packet on its way. This is called from l2cap_send_pcb
  * (when no PDU is pending) and hci_acl_start (when PDU has been placed on
  * device queue). Thus we can have more than one PDU waiting at the device
  * if space is available but no single channel will hog the link.

Index: src/sys/netbt/l2cap_socket.c
diff -u src/sys/netbt/l2cap_socket.c:1.10 src/sys/netbt/l2cap_socket.c:1.10.2.1
--- src/sys/netbt/l2cap_socket.c:1.10	Thu Aug 29 17:49:21 2013
+++ src/sys/netbt/l2cap_socket.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: l2cap_socket.c,v 1.10 2013/08/29 17:49:21 rmind Exp $	*/
+/*	$NetBSD: l2cap_socket.c,v 1.10.2.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.10 2013/08/29 17:49:21 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.10.2.1 2014/08/10 06:56:23 tls Exp $");
 
 /* load symbolic names */
 #ifdef BLUETOOTH_DEBUG
@@ -82,63 +82,326 @@ static const struct btproto l2cap_proto 
 int l2cap_sendspace = 4096;
 int l2cap_recvspace = 4096;
 
+static int
+l2cap_attach(struct socket *so, int proto)
+{
+	int error;
+
+	KASSERT(so->so_pcb == NULL);
+
+	if (so->so_lock == NULL) {
+		mutex_obj_hold(bt_lock);
+		so->so_lock = bt_lock;
+		solock(so);
+	}
+	KASSERT(solocked(so));
+
+	/*
+	 * For L2CAP socket PCB we just use an l2cap_channel structure
+	 * since we have nothing to add..
+	 */
+	error = soreserve(so, l2cap_sendspace, l2cap_recvspace);
+	if (error)
+		return error;
+
+	return l2cap_attach_pcb((struct l2cap_channel **)&so->so_pcb,
+				&l2cap_proto, so);
+}
+
+static void
+l2cap_detach(struct socket *so)
+{
+	KASSERT(so->so_pcb != NULL);
+	l2cap_detach_pcb((struct l2cap_channel **)&so->so_pcb);
+	KASSERT(so->so_pcb == NULL);
+}
+
+static int
+l2cap_accept(struct socket *so, struct mbuf *nam)
+{
+	struct l2cap_channel *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	nam->m_len = sizeof(struct sockaddr_bt);
+	return l2cap_peeraddr_pcb(pcb, sa);
+}
+
+static int
+l2cap_bind(struct socket *so, struct mbuf *nam, struct lwp *l)
+{
+	struct l2cap_channel *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	if (sa->bt_len != sizeof(struct sockaddr_bt))
+		return EINVAL;
+
+	if (sa->bt_family != AF_BLUETOOTH)
+		return EAFNOSUPPORT;
+
+	return l2cap_bind_pcb(pcb, sa);
+}
+
+static int
+l2cap_listen(struct socket *so, struct lwp *l)
+{
+	struct l2cap_channel *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	return l2cap_listen_pcb(pcb);
+}
+
+static int
+l2cap_connect(struct socket *so, struct mbuf *nam, struct lwp *l)
+{
+	struct l2cap_channel *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	if (sa->bt_len != sizeof(struct sockaddr_bt))
+		return EINVAL;
+
+	if (sa->bt_family != AF_BLUETOOTH)
+		return EAFNOSUPPORT;
+
+	soisconnecting(so);
+	return l2cap_connect_pcb(pcb, sa);
+}
+
+static int
+l2cap_connect2(struct socket *so, struct socket *so2)
+{
+	KASSERT(solocked(so));
+
+	if (so->so_pcb == NULL)
+		return EINVAL;
+
+	return EOPNOTSUPP;
+}
+
+static int
+l2cap_disconnect(struct socket *so)
+{
+	struct l2cap_channel *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	soisdisconnecting(so);
+	return l2cap_disconnect_pcb(pcb, so->so_linger);
+}
+
+static int
+l2cap_shutdown(struct socket *so)
+{
+	KASSERT(solocked(so));
+
+	socantsendmore(so);
+	return 0;
+}
+
+static int
+l2cap_abort(struct socket *so)
+{
+	struct l2cap_channel *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	l2cap_disconnect_pcb(pcb, 0);
+	soisdisconnected(so);
+	l2cap_detach(so);
+	return 0;
+}
+
+static int
+l2cap_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
+{
+	return EPASSTHROUGH;
+}
+
+static int
+l2cap_stat(struct socket *so, struct stat *ub)
+{
+	KASSERT(solocked(so));
+
+	return 0;
+}
+
+static int
+l2cap_peeraddr(struct socket *so, struct mbuf *nam)
+{
+	struct l2cap_channel *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	nam->m_len = sizeof(struct sockaddr_bt);
+	return l2cap_peeraddr_pcb(pcb, sa);
+}
+
+static int
+l2cap_sockaddr(struct socket *so, struct mbuf *nam)
+{
+	struct l2cap_channel *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	nam->m_len = sizeof(struct sockaddr_bt);
+	return l2cap_sockaddr_pcb(pcb, sa);
+}
+
+static int
+l2cap_rcvd(struct socket *so, int flags, struct lwp *l)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+l2cap_recvoob(struct socket *so, struct mbuf *m, int flags)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+l2cap_send(struct socket *so, struct mbuf *m, struct mbuf *nam,
+    struct mbuf *control, struct lwp *l)
+{
+	struct l2cap_channel *pcb = so->so_pcb;
+	struct mbuf *m0;
+	int error = 0;
+
+	KASSERT(solocked(so));
+	KASSERT(m != NULL);
+
+	if (control)
+		m_freem(control);
+
+	if (pcb == NULL) {
+		error = EINVAL;
+		goto release;
+	}
+
+	if (m->m_pkthdr.len == 0)
+		goto release;
+
+	if (m->m_pkthdr.len > pcb->lc_omtu) {
+		error = EMSGSIZE;
+		goto release;
+	}
+
+	m0 = m_copypacket(m, M_DONTWAIT);
+	if (m0 == NULL) {
+		error = ENOMEM;
+		goto release;
+	}
+
+	sbappendrecord(&so->so_snd, m);
+	return l2cap_send_pcb(pcb, m0);
+
+release:
+	if (m)
+		m_freem(m);
+
+	return error;
+}
+
+static int
+l2cap_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
+{
+	KASSERT(solocked(so));
+
+	if (m)
+		m_freem(m);
+	if (control)
+		m_freem(control);
+
+	return EOPNOTSUPP;
+}
+
+static int
+l2cap_purgeif(struct socket *so, struct ifnet *ifp)
+{
+
+	return EOPNOTSUPP;
+}
+
 /*
  * User Request.
  * up is socket
- * m is either
- *	optional mbuf chain containing message
- *	ioctl command (PRU_CONTROL)
- * nam is either
- *	optional mbuf chain containing an address
- *	ioctl data (PRU_CONTROL)
- *	optionally protocol number (PRU_ATTACH)
- *	message flags (PRU_RCVD)
+ * m is optional mbuf chain containing message
  * ctl is either
  *	optional mbuf chain containing socket options
- *	optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
  * l is pointer to process requesting action (if any)
  *
  * we are responsible for disposing of m and ctl if
  * they are mbuf chains
  */
-int
+static int
 l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
     struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
 {
 	struct l2cap_channel *pcb = up->so_pcb;
-	struct sockaddr_bt *sa;
-	struct mbuf *m0;
 	int err = 0;
 
 	DPRINTFN(2, "%s\n", prurequests[req]);
-
-	switch (req) {
-	case PRU_CONTROL:
-		return EPASSTHROUGH;
-
-	case PRU_PURGEIF:
-		return EOPNOTSUPP;
-
-	case PRU_ATTACH:
-		if (up->so_lock == NULL) {
-			mutex_obj_hold(bt_lock);
-			up->so_lock = bt_lock;
-			solock(up);
-		}
-		KASSERT(solocked(up));
-		if (pcb != NULL)
-			return EINVAL;
-		/*
-		 * For L2CAP socket PCB we just use an l2cap_channel structure
-		 * since we have nothing to add..
-		 */
-		err = soreserve(up, l2cap_sendspace, l2cap_recvspace);
-		if (err)
-			return err;
-
-		return l2cap_attach((struct l2cap_channel **)&up->so_pcb,
-					&l2cap_proto, up);
-	}
+	KASSERT(req != PRU_ATTACH);
+	KASSERT(req != PRU_DETACH);
+	KASSERT(req != PRU_ACCEPT);
+	KASSERT(req != PRU_BIND);
+	KASSERT(req != PRU_LISTEN);
+	KASSERT(req != PRU_CONNECT);
+	KASSERT(req != PRU_CONNECT2);
+	KASSERT(req != PRU_DISCONNECT);
+	KASSERT(req != PRU_SHUTDOWN);
+	KASSERT(req != PRU_ABORT);
+	KASSERT(req != PRU_CONTROL);
+	KASSERT(req != PRU_SENSE);
+	KASSERT(req != PRU_PEERADDR);
+	KASSERT(req != PRU_SOCKADDR);
+	KASSERT(req != PRU_RCVD);
+	KASSERT(req != PRU_RCVOOB);
+	KASSERT(req != PRU_SEND);
+	KASSERT(req != PRU_SENDOOB);
+	KASSERT(req != PRU_PURGEIF);
 
 	if (pcb == NULL) {
 		err = EINVAL;
@@ -146,98 +409,6 @@ l2cap_usrreq(struct socket *up, int req,
 	}
 
 	switch(req) {
-	case PRU_DISCONNECT:
-		soisdisconnecting(up);
-		return l2cap_disconnect(pcb, up->so_linger);
-
-	case PRU_ABORT:
-		l2cap_disconnect(pcb, 0);
-		soisdisconnected(up);
-		/* fall through to */
-	case PRU_DETACH:
-		return l2cap_detach((struct l2cap_channel **)&up->so_pcb);
-
-	case PRU_BIND:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-
-		if (sa->bt_len != sizeof(struct sockaddr_bt))
-			return EINVAL;
-
-		if (sa->bt_family != AF_BLUETOOTH)
-			return EAFNOSUPPORT;
-
-		return l2cap_bind(pcb, sa);
-
-	case PRU_CONNECT:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-
-		if (sa->bt_len != sizeof(struct sockaddr_bt))
-			return EINVAL;
-
-		if (sa->bt_family != AF_BLUETOOTH)
-			return EAFNOSUPPORT;
-
-		soisconnecting(up);
-		return l2cap_connect(pcb, sa);
-
-	case PRU_PEERADDR:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-		nam->m_len = sizeof(struct sockaddr_bt);
-		return l2cap_peeraddr(pcb, sa);
-
-	case PRU_SOCKADDR:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-		nam->m_len = sizeof(struct sockaddr_bt);
-		return l2cap_sockaddr(pcb, sa);
-
-	case PRU_SHUTDOWN:
-		socantsendmore(up);
-		break;
-
-	case PRU_SEND:
-		KASSERT(m != NULL);
-		if (m->m_pkthdr.len == 0)
-			break;
-
-		if (m->m_pkthdr.len > pcb->lc_omtu) {
-			err = EMSGSIZE;
-			break;
-		}
-
-		m0 = m_copypacket(m, M_DONTWAIT);
-		if (m0 == NULL) {
-			err = ENOMEM;
-			break;
-		}
-
-		if (ctl)	/* no use for that */
-			m_freem(ctl);
-
-		sbappendrecord(&up->so_snd, m);
-		return l2cap_send(pcb, m0);
-
-	case PRU_SENSE:
-		return 0;		/* (no release) */
-
-	case PRU_RCVD:
-	case PRU_RCVOOB:
-		return EOPNOTSUPP;	/* (no release) */
-
-	case PRU_LISTEN:
-		return l2cap_listen(pcb);
-
-	case PRU_ACCEPT:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-		nam->m_len = sizeof(struct sockaddr_bt);
-		return l2cap_peeraddr(pcb, sa);
-
-	case PRU_CONNECT2:
-	case PRU_SENDOOB:
 	case PRU_FASTTIMO:
 	case PRU_SLOWTIMO:
 	case PRU_PROTORCV:
@@ -376,7 +547,7 @@ l2cap_linkmode(void *arg, int new)
 	if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
 	    || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
 	    || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
-		l2cap_disconnect(so->so_pcb, 0);
+		l2cap_disconnect_pcb(so->so_pcb, 0);
 }
 
 static void
@@ -396,3 +567,49 @@ l2cap_input(void *arg, struct mbuf *m)
 	sbappendrecord(&so->so_rcv, m);
 	sorwakeup(so);
 }
+
+PR_WRAP_USRREQS(l2cap)
+
+#define	l2cap_attach		l2cap_attach_wrapper
+#define	l2cap_detach		l2cap_detach_wrapper
+#define	l2cap_accept		l2cap_accept_wrapper
+#define	l2cap_bind		l2cap_bind_wrapper
+#define	l2cap_listen		l2cap_listen_wrapper
+#define	l2cap_connect		l2cap_connect_wrapper
+#define	l2cap_connect2		l2cap_connect2_wrapper
+#define	l2cap_disconnect	l2cap_disconnect_wrapper
+#define	l2cap_shutdown		l2cap_shutdown_wrapper
+#define	l2cap_abort		l2cap_abort_wrapper
+#define	l2cap_ioctl		l2cap_ioctl_wrapper
+#define	l2cap_stat		l2cap_stat_wrapper
+#define	l2cap_peeraddr		l2cap_peeraddr_wrapper
+#define	l2cap_sockaddr		l2cap_sockaddr_wrapper
+#define	l2cap_rcvd		l2cap_rcvd_wrapper
+#define	l2cap_recvoob		l2cap_recvoob_wrapper
+#define	l2cap_send		l2cap_send_wrapper
+#define	l2cap_sendoob		l2cap_sendoob_wrapper
+#define	l2cap_purgeif		l2cap_purgeif_wrapper
+#define	l2cap_usrreq		l2cap_usrreq_wrapper
+
+const struct pr_usrreqs l2cap_usrreqs = {
+	.pr_attach	= l2cap_attach,
+	.pr_detach	= l2cap_detach,
+	.pr_accept	= l2cap_accept,
+	.pr_bind	= l2cap_bind,
+	.pr_listen	= l2cap_listen,
+	.pr_connect	= l2cap_connect,
+	.pr_connect2	= l2cap_connect2,
+	.pr_disconnect	= l2cap_disconnect,
+	.pr_shutdown	= l2cap_shutdown,
+	.pr_abort	= l2cap_abort,
+	.pr_ioctl	= l2cap_ioctl,
+	.pr_stat	= l2cap_stat,
+	.pr_peeraddr	= l2cap_peeraddr,
+	.pr_sockaddr	= l2cap_sockaddr,
+	.pr_rcvd	= l2cap_rcvd,
+	.pr_recvoob	= l2cap_recvoob,
+	.pr_send	= l2cap_send,
+	.pr_sendoob	= l2cap_sendoob,
+	.pr_purgeif	= l2cap_purgeif,
+	.pr_generic	= l2cap_usrreq,
+};

Index: src/sys/netbt/l2cap_upper.c
diff -u src/sys/netbt/l2cap_upper.c:1.11 src/sys/netbt/l2cap_upper.c:1.11.36.1
--- src/sys/netbt/l2cap_upper.c:1.11	Mon Jan  4 19:20:05 2010
+++ src/sys/netbt/l2cap_upper.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: l2cap_upper.c,v 1.11 2010/01/04 19:20:05 plunky Exp $	*/
+/*	$NetBSD: l2cap_upper.c,v 1.11.36.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2005 Iain Hibbert.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.11 2010/01/04 19:20:05 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: l2cap_upper.c,v 1.11.36.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -52,13 +52,13 @@ __KERNEL_RCSID(0, "$NetBSD: l2cap_upper.
  */
 
 /*
- * l2cap_attach(handle, btproto, upper)
+ * l2cap_attach_pcb(handle, btproto, upper)
  *
  *	attach new l2cap_channel to handle, populate
  *	with reasonable defaults
  */
 int
-l2cap_attach(struct l2cap_channel **handle,
+l2cap_attach_pcb(struct l2cap_channel **handle,
 		const struct btproto *proto, void *upper)
 {
 	struct l2cap_channel *chan;
@@ -102,12 +102,12 @@ l2cap_attach(struct l2cap_channel **hand
 }
 
 /*
- * l2cap_bind(l2cap_channel, sockaddr)
+ * l2cap_bind_pcb(l2cap_channel, sockaddr)
  *
  *	set local address of channel
  */
 int
-l2cap_bind(struct l2cap_channel *chan, struct sockaddr_bt *addr)
+l2cap_bind_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr)
 {
 
 	if (chan->lc_lcid != L2CAP_NULL_CID)
@@ -118,12 +118,12 @@ l2cap_bind(struct l2cap_channel *chan, s
 }
 
 /*
- * l2cap_sockaddr(l2cap_channel, sockaddr)
+ * l2cap_sockaddr_pcb(l2cap_channel, sockaddr)
  *
  *	get local address of channel
  */
 int
-l2cap_sockaddr(struct l2cap_channel *chan, struct sockaddr_bt *addr)
+l2cap_sockaddr_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr)
 {
 
 	memcpy(addr, &chan->lc_laddr, sizeof(struct sockaddr_bt));
@@ -131,7 +131,7 @@ l2cap_sockaddr(struct l2cap_channel *cha
 }
 
 /*
- * l2cap_connect(l2cap_channel, sockaddr)
+ * l2cap_connect_pcb(l2cap_channel, sockaddr)
  *
  *	Initiate a connection to destination. This corresponds to
  *	"Open Channel Request" in the L2CAP specification and will
@@ -144,7 +144,7 @@ l2cap_sockaddr(struct l2cap_channel *cha
  *		proto->connecting(upper)
  */
 int
-l2cap_connect(struct l2cap_channel *chan, struct sockaddr_bt *dest)
+l2cap_connect_pcb(struct l2cap_channel *chan, struct sockaddr_bt *dest)
 {
 	struct hci_unit *unit;
 	int err;
@@ -209,12 +209,12 @@ fail:
 }
 
 /*
- * l2cap_peeraddr(l2cap_channel, sockaddr)
+ * l2cap_peeraddr_pcb(l2cap_channel, sockaddr)
  *
  *	get remote address of channel
  */
 int
-l2cap_peeraddr(struct l2cap_channel *chan, struct sockaddr_bt *addr)
+l2cap_peeraddr_pcb(struct l2cap_channel *chan, struct sockaddr_bt *addr)
 {
 
 	memcpy(addr, &chan->lc_raddr, sizeof(struct sockaddr_bt));
@@ -222,7 +222,7 @@ l2cap_peeraddr(struct l2cap_channel *cha
 }
 
 /*
- * l2cap_disconnect(l2cap_channel, linger)
+ * l2cap_disconnect_pcb(l2cap_channel, linger)
  *
  *	Initiate L2CAP disconnection. This corresponds to
  *	"Close Channel Request" in the L2CAP specification
@@ -235,7 +235,7 @@ l2cap_peeraddr(struct l2cap_channel *cha
  *	the queue.
  */
 int
-l2cap_disconnect(struct l2cap_channel *chan, int linger)
+l2cap_disconnect_pcb(struct l2cap_channel *chan, int linger)
 {
 	int err = 0;
 
@@ -260,12 +260,12 @@ l2cap_disconnect(struct l2cap_channel *c
 }
 
 /*
- * l2cap_detach(handle)
+ * l2cap_detach_pcb(handle)
  *
  *	Detach l2cap channel from handle & close it down
  */
-int
-l2cap_detach(struct l2cap_channel **handle)
+void
+l2cap_detach_pcb(struct l2cap_channel **handle)
 {
 	struct l2cap_channel *chan;
 
@@ -288,11 +288,10 @@ l2cap_detach(struct l2cap_channel **hand
 	 */
 
 	free(chan, M_BLUETOOTH);
-	return 0;
 }
 
 /*
- * l2cap_listen(l2cap_channel)
+ * l2cap_listen_pcb(l2cap_channel)
  *
  *	Use this channel as a listening post (until detached). This will
  *	result in calls to:
@@ -309,7 +308,7 @@ l2cap_detach(struct l2cap_channel **hand
  *	You cannot use this channel for anything else subsequent to this call
  */
 int
-l2cap_listen(struct l2cap_channel *chan)
+l2cap_listen_pcb(struct l2cap_channel *chan)
 {
 	struct l2cap_channel *used, *prev = NULL;
 	uint32_t psm;
@@ -373,7 +372,7 @@ l2cap_listen(struct l2cap_channel *chan)
 }
 
 /*
- * l2cap_send(l2cap_channel, mbuf)
+ * l2cap_send_pcb(l2cap_channel, mbuf)
  *
  *	Output SDU on channel described by channel. This corresponds
  *	to "Send Data Request" in the L2CAP specification. The upper
@@ -395,7 +394,7 @@ l2cap_listen(struct l2cap_channel *chan)
  *	B-Frame header and start sending if we are not already
  */
 int
-l2cap_send(struct l2cap_channel *chan, struct mbuf *m)
+l2cap_send_pcb(struct l2cap_channel *chan, struct mbuf *m)
 {
 	l2cap_hdr_t *hdr;
 	int plen;

Index: src/sys/netbt/rfcomm.h
diff -u src/sys/netbt/rfcomm.h:1.9 src/sys/netbt/rfcomm.h:1.9.36.1
--- src/sys/netbt/rfcomm.h:1.9	Sun Sep 13 18:45:11 2009
+++ src/sys/netbt/rfcomm.h	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm.h,v 1.9 2009/09/13 18:45:11 pooka Exp $	*/
+/*	$NetBSD: rfcomm.h,v 1.9.36.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -55,7 +55,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: rfcomm.h,v 1.9 2009/09/13 18:45:11 pooka Exp $
+ * $Id: rfcomm.h,v 1.9.36.1 2014/08/10 06:56:23 tls Exp $
  * $FreeBSD: src/sys/netgraph/bluetooth/include/ng_btsocket_rfcomm.h,v 1.4 2005/01/11 01:39:53 emax Exp $
  */
 
@@ -404,20 +404,19 @@ int rfcomm_session_send_mcc(struct rfcom
 void rfcomm_init(void);
 
 /* rfcomm_socket.c */
-int rfcomm_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct lwp *);
 int rfcomm_ctloutput(int, struct socket *, struct sockopt *);
 
 /* rfcomm_upper.c */
-int rfcomm_attach(struct rfcomm_dlc **, const struct btproto *, void *);
-int rfcomm_bind(struct rfcomm_dlc *, struct sockaddr_bt *);
-int rfcomm_sockaddr(struct rfcomm_dlc *, struct sockaddr_bt *);
-int rfcomm_connect(struct rfcomm_dlc *, struct sockaddr_bt *);
-int rfcomm_peeraddr(struct rfcomm_dlc *, struct sockaddr_bt *);
-int rfcomm_disconnect(struct rfcomm_dlc *, int);
-int rfcomm_detach(struct rfcomm_dlc **);
-int rfcomm_listen(struct rfcomm_dlc *);
-int rfcomm_send(struct rfcomm_dlc *, struct mbuf *);
-int rfcomm_rcvd(struct rfcomm_dlc *, size_t);
+int rfcomm_attach_pcb(struct rfcomm_dlc **, const struct btproto *, void *);
+int rfcomm_bind_pcb(struct rfcomm_dlc *, struct sockaddr_bt *);
+int rfcomm_sockaddr_pcb(struct rfcomm_dlc *, struct sockaddr_bt *);
+int rfcomm_connect_pcb(struct rfcomm_dlc *, struct sockaddr_bt *);
+int rfcomm_peeraddr_pcb(struct rfcomm_dlc *, struct sockaddr_bt *);
+int rfcomm_disconnect_pcb(struct rfcomm_dlc *, int);
+void rfcomm_detach_pcb(struct rfcomm_dlc **);
+int rfcomm_listen_pcb(struct rfcomm_dlc *);
+int rfcomm_send_pcb(struct rfcomm_dlc *, struct mbuf *);
+int rfcomm_rcvd_pcb(struct rfcomm_dlc *, size_t);
 int rfcomm_setopt(struct rfcomm_dlc *, const struct sockopt *);
 int rfcomm_getopt(struct rfcomm_dlc *, struct sockopt *);
 
Index: src/sys/netbt/sco_upper.c
diff -u src/sys/netbt/sco_upper.c:1.9 src/sys/netbt/sco_upper.c:1.9.36.1
--- src/sys/netbt/sco_upper.c:1.9	Mon Jan  4 19:20:05 2010
+++ src/sys/netbt/sco_upper.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: sco_upper.c,v 1.9 2010/01/04 19:20:05 plunky Exp $	*/
+/*	$NetBSD: sco_upper.c,v 1.9.36.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sco_upper.c,v 1.9 2010/01/04 19:20:05 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sco_upper.c,v 1.9.36.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -53,12 +53,12 @@ __KERNEL_RCSID(0, "$NetBSD: sco_upper.c,
 struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb);
 
 /*
- * sco_attach(handle, proto, upper)
+ * sco_attach_pcb(handle, proto, upper)
  *
  *	Attach a new instance of SCO pcb to handle
  */
 int
-sco_attach(struct sco_pcb **handle,
+sco_attach_pcb(struct sco_pcb **handle,
 		const struct btproto *proto, void *upper)
 {
 	struct sco_pcb *pcb;
@@ -82,12 +82,12 @@ sco_attach(struct sco_pcb **handle,
 }
 
 /*
- * sco_bind(pcb, sockaddr)
+ * sco_bind_pcb(pcb, sockaddr)
  *
  *	Bind SCO pcb to local address
  */
 int
-sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr)
+sco_bind_pcb(struct sco_pcb *pcb, struct sockaddr_bt *addr)
 {
 
 	if (pcb->sp_link != NULL || pcb->sp_flags & SP_LISTENING)
@@ -98,12 +98,12 @@ sco_bind(struct sco_pcb *pcb, struct soc
 }
 
 /*
- * sco_sockaddr(pcb, sockaddr)
+ * sco_sockaddr_pcb(pcb, sockaddr)
  *
  *	Copy local address of PCB to sockaddr
  */
 int
-sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
+sco_sockaddr_pcb(struct sco_pcb *pcb, struct sockaddr_bt *addr)
 {
 
 	memset(addr, 0, sizeof(struct sockaddr_bt));
@@ -114,12 +114,12 @@ sco_sockaddr(struct sco_pcb *pcb, struct
 }
 
 /*
- * sco_connect(pcb, sockaddr)
+ * sco_connect_pcb(pcb, sockaddr)
  *
  *	Initiate a SCO connection to the destination address.
  */
 int
-sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest)
+sco_connect_pcb(struct sco_pcb *pcb, struct sockaddr_bt *dest)
 {
 	hci_add_sco_con_cp cp;
 	struct hci_unit *unit;
@@ -177,12 +177,12 @@ sco_connect(struct sco_pcb *pcb, struct 
 }
 
 /*
- * sco_peeraddr(pcb, sockaddr)
+ * sco_peeraddr_pcb(pcb, sockaddr)
  *
  *	Copy remote address of SCO pcb to sockaddr
  */
 int
-sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
+sco_peeraddr_pcb(struct sco_pcb *pcb, struct sockaddr_bt *addr)
 {
 
 	memset(addr, 0, sizeof(struct sockaddr_bt));
@@ -193,12 +193,12 @@ sco_peeraddr(struct sco_pcb *pcb, struct
 }
 
 /*
- * sco_disconnect(pcb, linger)
+ * sco_disconnect_pcb(pcb, linger)
  *
  *	Initiate disconnection of connected SCO pcb
  */
 int
-sco_disconnect(struct sco_pcb *pcb, int linger)
+sco_disconnect_pcb(struct sco_pcb *pcb, int linger)
 {
 	hci_discon_cp cp;
 	struct hci_link *sco;
@@ -222,12 +222,12 @@ sco_disconnect(struct sco_pcb *pcb, int 
 }
 
 /*
- * sco_detach(handle)
+ * sco_detach_pcb(handle)
  *
  *	Detach SCO pcb from handle and clear up
  */
-int
-sco_detach(struct sco_pcb **handle)
+void
+sco_detach_pcb(struct sco_pcb **handle)
 {
 	struct sco_pcb *pcb;
 
@@ -235,26 +235,22 @@ sco_detach(struct sco_pcb **handle)
 	pcb = *handle;
 	*handle = NULL;
 
-	if (pcb == NULL)
-		return EINVAL;
-
 	if (pcb->sp_link != NULL) {
-		sco_disconnect(pcb, 0);
+		sco_disconnect_pcb(pcb, 0);
 		pcb->sp_link = NULL;
 	}
 
 	LIST_REMOVE(pcb, sp_next);
 	free(pcb, M_BLUETOOTH);
-	return 0;
 }
 
 /*
- * sco_listen(pcb)
+ * sco_listen_pcb(pcb)
  *
  *	Mark pcb as a listener.
  */
 int
-sco_listen(struct sco_pcb *pcb)
+sco_listen_pcb(struct sco_pcb *pcb)
 {
 
 	if (pcb->sp_link != NULL)
@@ -265,7 +261,7 @@ sco_listen(struct sco_pcb *pcb)
 }
 
 /*
- * sco_send(pcb, mbuf)
+ * sco_send_pcb(pcb, mbuf)
  *
  *	Send data on SCO pcb.
  *
@@ -275,7 +271,7 @@ sco_listen(struct sco_pcb *pcb)
  * we can drop a record from the socket buffer.
  */
 int
-sco_send(struct sco_pcb *pcb, struct mbuf *m)
+sco_send_pcb(struct sco_pcb *pcb, struct mbuf *m)
 {
 	hci_scodata_hdr_t *hdr;
 	int plen;

Index: src/sys/netbt/rfcomm_dlc.c
diff -u src/sys/netbt/rfcomm_dlc.c:1.7 src/sys/netbt/rfcomm_dlc.c:1.7.26.1
--- src/sys/netbt/rfcomm_dlc.c:1.7	Sun Aug 21 14:20:34 2011
+++ src/sys/netbt/rfcomm_dlc.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm_dlc.c,v 1.7 2011/08/21 14:20:34 plunky Exp $	*/
+/*	$NetBSD: rfcomm_dlc.c,v 1.7.26.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rfcomm_dlc.c,v 1.7 2011/08/21 14:20:34 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rfcomm_dlc.c,v 1.7.26.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -84,14 +84,14 @@ rfcomm_dlc_newconn(struct rfcomm_session
 	 * a note of the best address and BDADDR_ANY matches in order to find
 	 * the oldest and most specific match.
 	 */
-	l2cap_sockaddr(rs->rs_l2cap, &laddr);
-	l2cap_peeraddr(rs->rs_l2cap, &raddr);
+	l2cap_sockaddr_pcb(rs->rs_l2cap, &laddr);
+	l2cap_peeraddr_pcb(rs->rs_l2cap, &raddr);
 	chan = RFCOMM_CHANNEL(dlci);
 	new = NULL;
 
 	any = best = NULL;
 	LIST_FOREACH(ls, &rfcomm_session_listen, rs_next) {
-		l2cap_sockaddr(ls->rs_l2cap, &addr);
+		l2cap_sockaddr_pcb(ls->rs_l2cap, &addr);
 
 		if (addr.bt_psm != laddr.bt_psm)
 			continue;

Index: src/sys/netbt/rfcomm_session.c
diff -u src/sys/netbt/rfcomm_session.c:1.18 src/sys/netbt/rfcomm_session.c:1.18.26.1
--- src/sys/netbt/rfcomm_session.c:1.18	Wed Jul 27 10:25:09 2011
+++ src/sys/netbt/rfcomm_session.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm_session.c,v 1.18 2011/07/27 10:25:09 plunky Exp $	*/
+/*	$NetBSD: rfcomm_session.c,v 1.18.26.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rfcomm_session.c,v 1.18 2011/07/27 10:25:09 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rfcomm_session.c,v 1.18.26.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -185,7 +185,7 @@ rfcomm_session_alloc(struct rfcomm_sessi
 	SIMPLEQ_INIT(&rs->rs_credits);
 	LIST_INIT(&rs->rs_dlcs);
 
-	err = l2cap_attach(&rs->rs_l2cap, &rfcomm_session_proto, rs);
+	err = l2cap_attach_pcb(&rs->rs_l2cap, &rfcomm_session_proto, rs);
 	if (err) {
 		free(rs, M_BLUETOOTH);
 		return NULL;
@@ -199,7 +199,7 @@ rfcomm_session_alloc(struct rfcomm_sessi
 	if (laddr->bt_psm == L2CAP_PSM_ANY)
 		laddr->bt_psm = L2CAP_PSM_RFCOMM;
 
-	(void)l2cap_bind(rs->rs_l2cap, laddr);
+	(void)l2cap_bind_pcb(rs->rs_l2cap, laddr);
 
 	LIST_INSERT_HEAD(list, rs, rs_next);
 
@@ -250,7 +250,7 @@ rfcomm_session_free(struct rfcomm_sessio
 
 	/* Goodbye! */
 	LIST_REMOVE(rs, rs_next);
-	l2cap_detach(&rs->rs_l2cap);
+	l2cap_detach_pcb(&rs->rs_l2cap);
 	callout_destroy(&rs->rs_timeout);
 	free(rs, M_BLUETOOTH);
 }
@@ -271,13 +271,13 @@ rfcomm_session_lookup(struct sockaddr_bt
 		if (rs->rs_state == RFCOMM_SESSION_CLOSED)
 			continue;
 
-		l2cap_sockaddr(rs->rs_l2cap, &addr);
+		l2cap_sockaddr_pcb(rs->rs_l2cap, &addr);
 
 		if (bdaddr_same(&src->bt_bdaddr, &addr.bt_bdaddr) == 0)
 			if (bdaddr_any(&src->bt_bdaddr) == 0)
 				continue;
 
-		l2cap_peeraddr(rs->rs_l2cap, &addr);
+		l2cap_peeraddr_pcb(rs->rs_l2cap, &addr);
 
 		if (addr.bt_psm != dest->bt_psm)
 			continue;
@@ -499,7 +499,7 @@ rfcomm_session_complete(void *arg, int c
 	 */
 	if (rs->rs_state == RFCOMM_SESSION_CLOSED) {
 		if (SIMPLEQ_EMPTY(&rs->rs_credits))
-			l2cap_disconnect(rs->rs_l2cap, 0);
+			l2cap_disconnect_pcb(rs->rs_l2cap, 0);
 	}
 }
 
@@ -853,7 +853,7 @@ rfcomm_session_recv_ua(struct rfcomm_ses
 		case RFCOMM_SESSION_WAIT_DISCONNECT:	/* We sent DISC */
 			callout_stop(&rs->rs_timeout);
 			rs->rs_state = RFCOMM_SESSION_CLOSED;
-			l2cap_disconnect(rs->rs_l2cap, 0);
+			l2cap_disconnect_pcb(rs->rs_l2cap, 0);
 			break;
 
 		default:
@@ -1510,7 +1510,7 @@ rfcomm_session_send_frame(struct rfcomm_
 	DPRINTFN(5, "dlci %d type %2.2x (%d bytes, fcs=%#2.2x)\n",
 		dlci, type, m->m_pkthdr.len, fcs);
 
-	return l2cap_send(rs->rs_l2cap, m);
+	return l2cap_send_pcb(rs->rs_l2cap, m);
 }
 
 /*
@@ -1610,7 +1610,7 @@ rfcomm_session_send_uih(struct rfcomm_se
 	/*
 	 * UIH frame ready to go..
 	 */
-	err = l2cap_send(rs->rs_l2cap, m0);
+	err = l2cap_send_pcb(rs->rs_l2cap, m0);
 	if (err)
 		goto fail;
 

Index: src/sys/netbt/rfcomm_socket.c
diff -u src/sys/netbt/rfcomm_socket.c:1.11 src/sys/netbt/rfcomm_socket.c:1.11.2.1
--- src/sys/netbt/rfcomm_socket.c:1.11	Thu Aug 29 17:49:21 2013
+++ src/sys/netbt/rfcomm_socket.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm_socket.c,v 1.11 2013/08/29 17:49:21 rmind Exp $	*/
+/*	$NetBSD: rfcomm_socket.c,v 1.11.2.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rfcomm_socket.c,v 1.11 2013/08/29 17:49:21 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rfcomm_socket.c,v 1.11.2.1 2014/08/10 06:56:23 tls Exp $");
 
 /* load symbolic names */
 #ifdef BLUETOOTH_DEBUG
@@ -81,73 +81,332 @@ static const struct btproto rfcomm_proto
 int rfcomm_sendspace = 4096;
 int rfcomm_recvspace = 4096;
 
+static int
+rfcomm_attach(struct socket *so, int proto)
+{
+	int error;
+
+	KASSERT(so->so_pcb == NULL);
+
+	if (so->so_lock == NULL) {
+		mutex_obj_hold(bt_lock);
+		so->so_lock = bt_lock;
+		solock(so);
+	}
+	KASSERT(solocked(so));
+
+	/*
+	 * Since we have nothing to add, we attach the DLC
+	 * structure directly to our PCB pointer.
+	 */
+	error = soreserve(so, rfcomm_sendspace, rfcomm_recvspace);
+	if (error)
+		return error;
+
+	error = rfcomm_attach_pcb((struct rfcomm_dlc **)&so->so_pcb,
+				&rfcomm_proto, so);
+	if (error)
+		return error;
+
+	error = rfcomm_rcvd_pcb(so->so_pcb, sbspace(&so->so_rcv));
+	if (error) {
+		rfcomm_detach_pcb((struct rfcomm_dlc **)&so->so_pcb);
+		return error;
+	}
+	return 0;
+}
+
+static void
+rfcomm_detach(struct socket *so)
+{
+	KASSERT(so->so_pcb != NULL);
+	rfcomm_detach_pcb((struct rfcomm_dlc **)&so->so_pcb);
+	KASSERT(so->so_pcb == NULL);
+}
+
+static int
+rfcomm_accept(struct socket *so, struct mbuf *nam)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	nam->m_len = sizeof(struct sockaddr_bt);
+	return rfcomm_peeraddr_pcb(pcb, sa);
+}
+
+static int
+rfcomm_bind(struct socket *so, struct mbuf *nam, struct lwp *l)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	if (sa->bt_len != sizeof(struct sockaddr_bt))
+		return EINVAL;
+
+	if (sa->bt_family != AF_BLUETOOTH)
+		return EAFNOSUPPORT;
+
+	return rfcomm_bind_pcb(pcb, sa);
+}
+
+static int
+rfcomm_listen(struct socket *so, struct lwp *l)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	return rfcomm_listen_pcb(pcb);
+}
+
+static int
+rfcomm_connect(struct socket *so, struct mbuf *nam, struct lwp *l)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	if (sa->bt_len != sizeof(struct sockaddr_bt))
+		return EINVAL;
+
+	if (sa->bt_family != AF_BLUETOOTH)
+		return EAFNOSUPPORT;
+
+	soisconnecting(so);
+	return rfcomm_connect_pcb(pcb, sa);
+}
+
+static int
+rfcomm_connect2(struct socket *so, struct socket *so2)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	return EOPNOTSUPP;
+}
+
+static int
+rfcomm_disconnect(struct socket *so)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	soisdisconnecting(so);
+	return rfcomm_disconnect_pcb(pcb, so->so_linger);
+}
+
+static int
+rfcomm_shutdown(struct socket *so)
+{
+	KASSERT(solocked(so));
+
+	socantsendmore(so);
+	return 0;
+}
+
+static int
+rfcomm_abort(struct socket *so)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	rfcomm_disconnect_pcb(pcb, 0);
+	soisdisconnected(so);
+	rfcomm_detach(so);
+	return 0;
+}
+
+static int
+rfcomm_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
+{
+	return EPASSTHROUGH;
+}
+
+static int
+rfcomm_stat(struct socket *so, struct stat *ub)
+{
+	KASSERT(solocked(so));
+
+	return 0;
+}
+
+static int
+rfcomm_peeraddr(struct socket *so, struct mbuf *nam)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	nam->m_len = sizeof(struct sockaddr_bt);
+	return rfcomm_peeraddr_pcb(pcb, sa);
+}
+
+static int
+rfcomm_sockaddr(struct socket *so, struct mbuf *nam)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	nam->m_len = sizeof(struct sockaddr_bt);
+	return rfcomm_sockaddr_pcb(pcb, sa);
+}
+
+static int
+rfcomm_rcvd(struct socket *so, int flags, struct lwp *l)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	return rfcomm_rcvd_pcb(pcb, sbspace(&so->so_rcv));
+}
+
+static int
+rfcomm_recvoob(struct socket *so, struct mbuf *m, int flags)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+rfcomm_send(struct socket *so, struct mbuf *m, struct mbuf *nam,
+    struct mbuf *control, struct lwp *l)
+{
+	struct rfcomm_dlc *pcb = so->so_pcb;
+	int err = 0;
+	struct mbuf *m0;
+
+	KASSERT(solocked(so));
+	KASSERT(m != NULL);
+
+	if (control)	/* no use for that */
+		m_freem(control);
+
+	if (pcb == NULL) {
+		err = EINVAL;
+		goto release;
+	}
+
+	m0 = m_copypacket(m, M_DONTWAIT);
+	if (m0 == NULL) {
+		err = ENOMEM;
+		goto release;
+	}
+
+	sbappendstream(&so->so_snd, m);
+	return rfcomm_send_pcb(pcb, m0);
+
+release:
+	m_freem(m);
+	return err;
+}
+
+static int
+rfcomm_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
+{
+	KASSERT(solocked(so));
+
+	if (m)
+		m_freem(m);
+	if (control)
+		m_freem(control);
+
+	return EOPNOTSUPP;
+}
+
+static int
+rfcomm_purgeif(struct socket *so, struct ifnet *ifp)
+{
+
+	return EOPNOTSUPP;
+}
+
 /*
  * User Request.
  * up is socket
- * m is either
- *	optional mbuf chain containing message
- *	ioctl command (PRU_CONTROL)
- * nam is either
- *	optional mbuf chain containing an address
- *	ioctl data (PRU_CONTROL)
- *	optionally protocol number (PRU_ATTACH)
- *	message flags (PRU_RCVD)
+ * m is optional mbuf chain containing message
  * ctl is either
  *	optional mbuf chain containing socket options
- *	optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
  * l is pointer to process requesting action (if any)
  *
  * we are responsible for disposing of m and ctl if
  * they are mbuf chains
  */
-int
+static int
 rfcomm_usrreq(struct socket *up, int req, struct mbuf *m,
 		struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
 {
 	struct rfcomm_dlc *pcb = up->so_pcb;
-	struct sockaddr_bt *sa;
-	struct mbuf *m0;
 	int err = 0;
 
 	DPRINTFN(2, "%s\n", prurequests[req]);
-
-	switch (req) {
-	case PRU_CONTROL:
-		return EPASSTHROUGH;
-
-	case PRU_PURGEIF:
-		return EOPNOTSUPP;
-
-	case PRU_ATTACH:
-		if (up->so_lock == NULL) {
-			mutex_obj_hold(bt_lock);
-			up->so_lock = bt_lock;
-			solock(up);
-		}
-		KASSERT(solocked(up));
-		if (pcb != NULL)
-			return EINVAL;
-		/*
-		 * Since we have nothing to add, we attach the DLC
-		 * structure directly to our PCB pointer.
-		 */
-		err = soreserve(up, rfcomm_sendspace, rfcomm_recvspace);
-		if (err)
-			return err;
-
-		err = rfcomm_attach((struct rfcomm_dlc **)&up->so_pcb,
-					&rfcomm_proto, up);
-		if (err)
-			return err;
-
-		err = rfcomm_rcvd(up->so_pcb, sbspace(&up->so_rcv));
-		if (err) {
-			rfcomm_detach((struct rfcomm_dlc **)&up->so_pcb);
-			return err;
-		}
-
-		return 0;
-	}
+	KASSERT(req != PRU_ATTACH);
+	KASSERT(req != PRU_DETACH);
+	KASSERT(req != PRU_ACCEPT);
+	KASSERT(req != PRU_BIND);
+	KASSERT(req != PRU_LISTEN);
+	KASSERT(req != PRU_CONNECT);
+	KASSERT(req != PRU_CONNECT2);
+	KASSERT(req != PRU_DISCONNECT);
+	KASSERT(req != PRU_SHUTDOWN);
+	KASSERT(req != PRU_ABORT);
+	KASSERT(req != PRU_CONTROL);
+	KASSERT(req != PRU_SENSE);
+	KASSERT(req != PRU_PEERADDR);
+	KASSERT(req != PRU_SOCKADDR);
+	KASSERT(req != PRU_RCVD);
+	KASSERT(req != PRU_RCVOOB);
+	KASSERT(req != PRU_SEND);
+	KASSERT(req != PRU_SENDOOB);
+	KASSERT(req != PRU_PURGEIF);
 
 	if (pcb == NULL) {
 		err = EINVAL;
@@ -155,92 +414,6 @@ rfcomm_usrreq(struct socket *up, int req
 	}
 
 	switch(req) {
-	case PRU_DISCONNECT:
-		soisdisconnecting(up);
-		return rfcomm_disconnect(pcb, up->so_linger);
-
-	case PRU_ABORT:
-		rfcomm_disconnect(pcb, 0);
-		soisdisconnected(up);
-		/* fall through to */
-	case PRU_DETACH:
-		return rfcomm_detach((struct rfcomm_dlc **)&up->so_pcb);
-
-	case PRU_BIND:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-
-		if (sa->bt_len != sizeof(struct sockaddr_bt))
-			return EINVAL;
-
-		if (sa->bt_family != AF_BLUETOOTH)
-			return EAFNOSUPPORT;
-
-		return rfcomm_bind(pcb, sa);
-
-	case PRU_CONNECT:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-
-		if (sa->bt_len != sizeof(struct sockaddr_bt))
-			return EINVAL;
-
-		if (sa->bt_family != AF_BLUETOOTH)
-			return EAFNOSUPPORT;
-
-		soisconnecting(up);
-		return rfcomm_connect(pcb, sa);
-
-	case PRU_PEERADDR:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-		nam->m_len = sizeof(struct sockaddr_bt);
-		return rfcomm_peeraddr(pcb, sa);
-
-	case PRU_SOCKADDR:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-		nam->m_len = sizeof(struct sockaddr_bt);
-		return rfcomm_sockaddr(pcb, sa);
-
-	case PRU_SHUTDOWN:
-		socantsendmore(up);
-		break;
-
-	case PRU_SEND:
-		KASSERT(m != NULL);
-
-		if (ctl)	/* no use for that */
-			m_freem(ctl);
-
-		m0 = m_copypacket(m, M_DONTWAIT);
-		if (m0 == NULL)
-			return ENOMEM;
-
-		sbappendstream(&up->so_snd, m);
-
-		return rfcomm_send(pcb, m0);
-
-	case PRU_SENSE:
-		return 0;		/* (no release) */
-
-	case PRU_RCVD:
-		return rfcomm_rcvd(pcb, sbspace(&up->so_rcv));
-
-	case PRU_RCVOOB:
-		return EOPNOTSUPP;	/* (no release) */
-
-	case PRU_LISTEN:
-		return rfcomm_listen(pcb);
-
-	case PRU_ACCEPT:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-		nam->m_len = sizeof(struct sockaddr_bt);
-		return rfcomm_peeraddr(pcb, sa);
-
-	case PRU_CONNECT2:
-	case PRU_SENDOOB:
 	case PRU_FASTTIMO:
 	case PRU_SLOWTIMO:
 	case PRU_PROTORCV:
@@ -386,7 +559,7 @@ rfcomm_linkmode(void *arg, int new)
 	if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH))
 	    || ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT))
 	    || ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE)))
-		rfcomm_disconnect(so->so_pcb, 0);
+		rfcomm_disconnect_pcb(so->so_pcb, 0);
 }
 
 /*
@@ -411,3 +584,49 @@ rfcomm_input(void *arg, struct mbuf *m)
 	sbappendstream(&so->so_rcv, m);
 	sorwakeup(so);
 }
+
+PR_WRAP_USRREQS(rfcomm)
+
+#define	rfcomm_attach		rfcomm_attach_wrapper
+#define	rfcomm_detach		rfcomm_detach_wrapper
+#define	rfcomm_accept		rfcomm_accept_wrapper
+#define	rfcomm_bind		rfcomm_bind_wrapper
+#define	rfcomm_listen		rfcomm_listen_wrapper
+#define	rfcomm_connect		rfcomm_connect_wrapper
+#define	rfcomm_connect2		rfcomm_connect2_wrapper
+#define	rfcomm_disconnect	rfcomm_disconnect_wrapper
+#define	rfcomm_shutdown		rfcomm_shutdown_wrapper
+#define	rfcomm_abort		rfcomm_abort_wrapper
+#define	rfcomm_ioctl		rfcomm_ioctl_wrapper
+#define	rfcomm_stat		rfcomm_stat_wrapper
+#define	rfcomm_peeraddr		rfcomm_peeraddr_wrapper
+#define	rfcomm_sockaddr		rfcomm_sockaddr_wrapper
+#define	rfcomm_rcvd		rfcomm_rcvd_wrapper
+#define	rfcomm_recvoob		rfcomm_recvoob_wrapper
+#define	rfcomm_send		rfcomm_send_wrapper
+#define	rfcomm_sendoob		rfcomm_sendoob_wrapper
+#define	rfcomm_purgeif		rfcomm_purgeif_wrapper
+#define	rfcomm_usrreq		rfcomm_usrreq_wrapper
+
+const struct pr_usrreqs rfcomm_usrreqs = {
+	.pr_attach	= rfcomm_attach,
+	.pr_detach	= rfcomm_detach,
+	.pr_accept	= rfcomm_accept,
+	.pr_bind	= rfcomm_bind,
+	.pr_listen	= rfcomm_listen,
+	.pr_connect	= rfcomm_connect,
+	.pr_connect2	= rfcomm_connect2,
+	.pr_disconnect	= rfcomm_disconnect,
+	.pr_shutdown	= rfcomm_shutdown,
+	.pr_abort	= rfcomm_abort,
+	.pr_ioctl	= rfcomm_ioctl,
+	.pr_stat	= rfcomm_stat,
+	.pr_peeraddr	= rfcomm_peeraddr,
+	.pr_sockaddr	= rfcomm_sockaddr,
+	.pr_rcvd	= rfcomm_rcvd,
+	.pr_recvoob	= rfcomm_recvoob,
+	.pr_send	= rfcomm_send,
+	.pr_sendoob	= rfcomm_sendoob,
+	.pr_purgeif	= rfcomm_purgeif,
+	.pr_generic	= rfcomm_usrreq,
+};

Index: src/sys/netbt/rfcomm_upper.c
diff -u src/sys/netbt/rfcomm_upper.c:1.13 src/sys/netbt/rfcomm_upper.c:1.13.36.1
--- src/sys/netbt/rfcomm_upper.c:1.13	Mon Jan  4 19:20:05 2010
+++ src/sys/netbt/rfcomm_upper.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: rfcomm_upper.c,v 1.13 2010/01/04 19:20:05 plunky Exp $	*/
+/*	$NetBSD: rfcomm_upper.c,v 1.13.36.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -32,12 +32,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rfcomm_upper.c,v 1.13 2010/01/04 19:20:05 plunky Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rfcomm_upper.c,v 1.13.36.1 2014/08/10 06:56:23 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/mbuf.h>
-#include <sys/proc.h>
+#include <sys/kmem.h>
 #include <sys/socketvar.h>
 #include <sys/systm.h>
 
@@ -56,12 +56,12 @@ __KERNEL_RCSID(0, "$NetBSD: rfcomm_upper
  */
 
 /*
- * rfcomm_attach(handle, proto, upper)
+ * rfcomm_attach_pcb(handle, proto, upper)
  *
  * attach a new RFCOMM DLC to handle, populate with reasonable defaults
  */
 int
-rfcomm_attach(struct rfcomm_dlc **handle,
+rfcomm_attach_pcb(struct rfcomm_dlc **handle,
 		const struct btproto *proto, void *upper)
 {
 	struct rfcomm_dlc *dlc;
@@ -70,9 +70,7 @@ rfcomm_attach(struct rfcomm_dlc **handle
 	KASSERT(proto != NULL);
 	KASSERT(upper != NULL);
 
-	dlc = malloc(sizeof(struct rfcomm_dlc), M_BLUETOOTH, M_NOWAIT | M_ZERO);
-	if (dlc == NULL)
-		return ENOMEM;
+	dlc = kmem_zalloc(sizeof(struct rfcomm_dlc), KM_SLEEP);
 
 	dlc->rd_state = RFCOMM_DLC_CLOSED;
 	dlc->rd_mtu = rfcomm_mtu_default;
@@ -98,12 +96,12 @@ rfcomm_attach(struct rfcomm_dlc **handle
 }
 
 /*
- * rfcomm_bind(dlc, sockaddr)
+ * rfcomm_bind_pcb(dlc, sockaddr)
  *
  * bind DLC to local address
  */
 int
-rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
+rfcomm_bind_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
 {
 
 	if (dlc->rd_state != RFCOMM_DLC_CLOSED)
@@ -114,12 +112,12 @@ rfcomm_bind(struct rfcomm_dlc *dlc, stru
 }
 
 /*
- * rfcomm_sockaddr(dlc, sockaddr)
+ * rfcomm_sockaddr_pcb(dlc, sockaddr)
  *
  * return local address
  */
 int
-rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
+rfcomm_sockaddr_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
 {
 
 	memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
@@ -127,12 +125,12 @@ rfcomm_sockaddr(struct rfcomm_dlc *dlc, 
 }
 
 /*
- * rfcomm_connect(dlc, sockaddr)
+ * rfcomm_connect_pcb(dlc, sockaddr)
  *
  * Initiate connection of RFCOMM DLC to remote address.
  */
 int
-rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
+rfcomm_connect_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
 {
 	struct rfcomm_session *rs;
 	int err = 0;
@@ -169,7 +167,7 @@ rfcomm_connect(struct rfcomm_dlc *dlc, s
 		rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
 		rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
 
-		err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr);
+		err = l2cap_connect_pcb(rs->rs_l2cap, &dlc->rd_raddr);
 		if (err) {
 			rfcomm_session_free(rs);
 			return err;
@@ -186,7 +184,7 @@ rfcomm_connect(struct rfcomm_dlc *dlc, s
 	if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
 		return EBUSY;
 
-	l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr);
+	l2cap_sockaddr_pcb(rs->rs_l2cap, &dlc->rd_laddr);
 
 	/*
 	 * attach the DLC to the session and start it off
@@ -202,12 +200,12 @@ rfcomm_connect(struct rfcomm_dlc *dlc, s
 }
 
 /*
- * rfcomm_peeraddr(dlc, sockaddr)
+ * rfcomm_peeraddr_pcb(dlc, sockaddr)
  *
  * return remote address
  */
 int
-rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
+rfcomm_peeraddr_pcb(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
 {
 
 	memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
@@ -215,12 +213,12 @@ rfcomm_peeraddr(struct rfcomm_dlc *dlc, 
 }
 
 /*
- * rfcomm_disconnect(dlc, linger)
+ * rfcomm_disconnect_pcb(dlc, linger)
  *
  * disconnect RFCOMM DLC
  */
 int
-rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
+rfcomm_disconnect_pcb(struct rfcomm_dlc *dlc, int linger)
 {
 	struct rfcomm_session *rs = dlc->rd_session;
 	int err = 0;
@@ -270,12 +268,12 @@ rfcomm_disconnect(struct rfcomm_dlc *dlc
 }
 
 /*
- * rfcomm_detach(handle)
+ * rfcomm_detach_pcb(handle)
  *
  * detach RFCOMM DLC from handle
  */
-int
-rfcomm_detach(struct rfcomm_dlc **handle)
+void
+rfcomm_detach_pcb(struct rfcomm_dlc **handle)
 {
 	struct rfcomm_dlc *dlc = *handle;
 
@@ -298,14 +296,12 @@ rfcomm_detach(struct rfcomm_dlc **handle
 		dlc->rd_flags |= RFCOMM_DLC_DETACH;
 	else {
 		callout_destroy(&dlc->rd_timeout);
-		free(dlc, M_BLUETOOTH);
+		kmem_free(dlc, sizeof(*dlc));
 	}
-
-	return 0;
 }
 
 /*
- * rfcomm_listen(dlc)
+ * rfcomm_listen_pcb(dlc)
  *
  * This DLC is a listener. We look for an existing listening session
  * with a matching address to attach to or else create a new one on
@@ -313,7 +309,7 @@ rfcomm_detach(struct rfcomm_dlc **handle
  * available for the session.
  */
 int
-rfcomm_listen(struct rfcomm_dlc *dlc)
+rfcomm_listen_pcb(struct rfcomm_dlc *dlc)
 {
 	struct rfcomm_session *rs;
 	struct rfcomm_dlc *used;
@@ -336,7 +332,7 @@ rfcomm_listen(struct rfcomm_dlc *dlc)
 		return EADDRNOTAVAIL;
 
 	LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
-		l2cap_sockaddr(rs->rs_l2cap, &addr);
+		l2cap_sockaddr_pcb(rs->rs_l2cap, &addr);
 
 		if (addr.bt_psm != dlc->rd_laddr.bt_psm)
 			continue;
@@ -353,7 +349,7 @@ rfcomm_listen(struct rfcomm_dlc *dlc)
 
 		rs->rs_state = RFCOMM_SESSION_LISTEN;
 
-		err = l2cap_listen(rs->rs_l2cap);
+		err = l2cap_listen_pcb(rs->rs_l2cap);
 		if (err) {
 			rfcomm_session_free(rs);
 			return err;
@@ -386,14 +382,14 @@ rfcomm_listen(struct rfcomm_dlc *dlc)
 }
 
 /*
- * rfcomm_send(dlc, mbuf)
+ * rfcomm_send_pcb(dlc, mbuf)
  *
  * Output data on DLC. This is streamed data, so we add it
  * to our buffer and start the DLC, which will assemble
  * packets and send them if it can.
  */
 int
-rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
+rfcomm_send_pcb(struct rfcomm_dlc *dlc, struct mbuf *m)
 {
 
 	if (dlc->rd_txbuf != NULL) {
@@ -410,7 +406,7 @@ rfcomm_send(struct rfcomm_dlc *dlc, stru
 }
 
 /*
- * rfcomm_rcvd(dlc, space)
+ * rfcomm_rcvd_pcb(dlc, space)
  *
  * Indicate space now available in receive buffer
  *
@@ -419,7 +415,7 @@ rfcomm_send(struct rfcomm_dlc *dlc, stru
  * buffer after that.
  */
 int
-rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
+rfcomm_rcvd_pcb(struct rfcomm_dlc *dlc, size_t space)
 {
 
 	KASSERT(dlc != NULL);

Index: src/sys/netbt/sco.h
diff -u src/sys/netbt/sco.h:1.3 src/sys/netbt/sco.h:1.3.54.1
--- src/sys/netbt/sco.h:1.3	Wed Aug  6 15:01:24 2008
+++ src/sys/netbt/sco.h	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: sco.h,v 1.3 2008/08/06 15:01:24 plunky Exp $	*/
+/*	$NetBSD: sco.h,v 1.3.54.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -65,20 +65,18 @@ struct sockopt;
 /* sco_socket.c */
 extern int sco_sendspace;
 extern int sco_recvspace;
-int sco_usrreq(struct socket *, int, struct mbuf *,
-		struct mbuf *, struct mbuf *, struct lwp *);
 int sco_ctloutput(int, struct socket *, struct sockopt *);
 
 /* sco_upper.c */
-int sco_attach(struct sco_pcb **, const struct btproto *, void *);
-int sco_bind(struct sco_pcb *, struct sockaddr_bt *);
-int sco_sockaddr(struct sco_pcb *, struct sockaddr_bt *);
-int sco_connect(struct sco_pcb *, struct sockaddr_bt *);
-int sco_peeraddr(struct sco_pcb *, struct sockaddr_bt *);
-int sco_disconnect(struct sco_pcb *, int);
-int sco_detach(struct sco_pcb **);
-int sco_listen(struct sco_pcb *);
-int sco_send(struct sco_pcb *, struct mbuf *);
+int sco_attach_pcb(struct sco_pcb **, const struct btproto *, void *);
+int sco_bind_pcb(struct sco_pcb *, struct sockaddr_bt *);
+int sco_sockaddr_pcb(struct sco_pcb *, struct sockaddr_bt *);
+int sco_connect_pcb(struct sco_pcb *, struct sockaddr_bt *);
+int sco_peeraddr_pcb(struct sco_pcb *, struct sockaddr_bt *);
+int sco_disconnect_pcb(struct sco_pcb *, int);
+void sco_detach_pcb(struct sco_pcb **);
+int sco_listen_pcb(struct sco_pcb *);
+int sco_send_pcb(struct sco_pcb *, struct mbuf *);
 int sco_setopt(struct sco_pcb *, const struct sockopt *);
 int sco_getopt(struct sco_pcb *, struct sockopt *);
 

Index: src/sys/netbt/sco_socket.c
diff -u src/sys/netbt/sco_socket.c:1.12 src/sys/netbt/sco_socket.c:1.12.2.1
--- src/sys/netbt/sco_socket.c:1.12	Thu Aug 29 17:49:21 2013
+++ src/sys/netbt/sco_socket.c	Sun Aug 10 06:56:23 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: sco_socket.c,v 1.12 2013/08/29 17:49:21 rmind Exp $	*/
+/*	$NetBSD: sco_socket.c,v 1.12.2.1 2014/08/10 06:56:23 tls Exp $	*/
 
 /*-
  * Copyright (c) 2006 Itronix Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.12 2013/08/29 17:49:21 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.12.2.1 2014/08/10 06:56:23 tls Exp $");
 
 /* load symbolic names */
 #ifdef BLUETOOTH_DEBUG
@@ -78,56 +78,321 @@ static const struct btproto sco_proto = 
 int sco_sendspace = 4096;
 int sco_recvspace = 4096;
 
+static int
+sco_attach(struct socket *so, int proto)
+{
+	int error;
+
+	KASSERT(so->so_pcb == NULL);
+
+	if (so->so_lock == NULL) {
+		mutex_obj_hold(bt_lock);
+		so->so_lock = bt_lock;
+		solock(so);
+	}
+	KASSERT(solocked(so));
+
+	error = soreserve(so, sco_sendspace, sco_recvspace);
+	if (error) {
+		return error;
+	}
+	return sco_attach_pcb((struct sco_pcb **)&so->so_pcb, &sco_proto, so);
+}
+
+static void
+sco_detach(struct socket *so)
+{
+	KASSERT(so->so_pcb != NULL);
+	sco_detach_pcb((struct sco_pcb **)&so->so_pcb);
+	KASSERT(so->so_pcb == NULL);
+}
+
+static int
+sco_accept(struct socket *so, struct mbuf *nam)
+{
+	struct sco_pcb *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	nam->m_len = sizeof(struct sockaddr_bt);
+	return sco_peeraddr_pcb(pcb, sa);
+}
+
+static int
+sco_bind(struct socket *so, struct mbuf *nam, struct lwp *l)
+{
+	struct sco_pcb *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	if (sa->bt_len != sizeof(struct sockaddr_bt))
+		return EINVAL;
+
+	if (sa->bt_family != AF_BLUETOOTH)
+		return EAFNOSUPPORT;
+
+	return sco_bind_pcb(pcb, sa);
+}
+
+static int
+sco_listen(struct socket *so, struct lwp *l)
+{
+	struct sco_pcb *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	return sco_listen_pcb(pcb);
+}
+
+static int
+sco_connect(struct socket *so, struct mbuf *nam, struct lwp *l)
+{
+	struct sco_pcb *pcb = so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(nam != NULL);
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	if (sa->bt_len != sizeof(struct sockaddr_bt))
+		return EINVAL;
+
+	if (sa->bt_family != AF_BLUETOOTH)
+		return EAFNOSUPPORT;
+
+	soisconnecting(so);
+	return sco_connect_pcb(pcb, sa);
+}
+
+static int
+sco_connect2(struct socket *so, struct socket *so2)
+{
+	struct sco_pcb *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	return EOPNOTSUPP;
+}
+
+static int
+sco_disconnect(struct socket *so)
+{
+	struct sco_pcb *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	soisdisconnecting(so);
+	return sco_disconnect_pcb(pcb, so->so_linger);
+}
+
+static int
+sco_shutdown(struct socket *so)
+{
+	KASSERT(solocked(so));
+
+	socantsendmore(so);
+	return 0;
+}
+
+static int
+sco_abort(struct socket *so)
+{
+	struct sco_pcb *pcb = so->so_pcb;
+
+	KASSERT(solocked(so));
+
+	if (pcb == NULL)
+		return EINVAL;
+
+	sco_disconnect_pcb(pcb, 0);
+	soisdisconnected(so);
+	sco_detach(so);
+	return 0;
+}
+
+static int
+sco_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
+{
+	return EOPNOTSUPP;
+}
+
+static int
+sco_stat(struct socket *so, struct stat *ub)
+{
+	KASSERT(solocked(so));
+
+	return 0;
+}
+
+static int
+sco_peeraddr(struct socket *so, struct mbuf *nam)
+{
+	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	nam->m_len = sizeof(struct sockaddr_bt);
+	return sco_peeraddr_pcb(pcb, sa);
+}
+
+static int
+sco_sockaddr(struct socket *so, struct mbuf *nam)
+{
+	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
+	struct sockaddr_bt *sa;
+
+	KASSERT(solocked(so));
+	KASSERT(pcb != NULL);
+	KASSERT(nam != NULL);
+
+	sa = mtod(nam, struct sockaddr_bt *);
+	nam->m_len = sizeof(struct sockaddr_bt);
+	return sco_sockaddr_pcb(pcb, sa);
+}
+
+static int
+sco_rcvd(struct socket *so, int flags, struct lwp *l)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+sco_recvoob(struct socket *so, struct mbuf *m, int flags)
+{
+	KASSERT(solocked(so));
+
+	return EOPNOTSUPP;
+}
+
+static int
+sco_send(struct socket *so, struct mbuf *m, struct mbuf *nam,
+    struct mbuf *control, struct lwp *l)
+{
+	struct sco_pcb *pcb = so->so_pcb;
+	int err = 0;
+	struct mbuf *m0;
+
+	KASSERT(solocked(so));
+	KASSERT(m != NULL);
+
+	if (control) /* no use for that */
+		m_freem(control);
+
+	if (pcb == NULL) {
+		err = EINVAL;
+		goto release;
+	}
+
+	if (m->m_pkthdr.len == 0)
+		goto release;
+
+	if (m->m_pkthdr.len > pcb->sp_mtu) {
+		err = EMSGSIZE;
+		goto release;
+	}
+
+	m0 = m_copypacket(m, M_DONTWAIT);
+	if (m0 == NULL) {
+		err = ENOMEM;
+		goto release;
+	}
+
+	sbappendrecord(&so->so_snd, m);
+	return sco_send_pcb(pcb, m0);
+
+release:
+	m_freem(m);
+	return err;
+}
+
+static int
+sco_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
+{
+	KASSERT(solocked(so));
+
+	if (m)
+		m_freem(m);
+	if (control)
+		m_freem(control);
+
+	return EOPNOTSUPP;
+}
+
+static int
+sco_purgeif(struct socket *so, struct ifnet *ifp)
+{
+
+	return EOPNOTSUPP;
+}
+
 /*
  * User Request.
  * up is socket
- * m is either
- *	optional mbuf chain containing message
- *	ioctl command (PRU_CONTROL)
- * nam is either
- *	optional mbuf chain containing an address
- *	ioctl data (PRU_CONTROL)
- *      optionally, protocol number (PRU_ATTACH)
+ * m is optional mbuf chain containing message
+ * nam is optional mbuf chain containing an address
  * ctl is optional mbuf chain containing socket options
  * l is pointer to process requesting action (if any)
  *
  * we are responsible for disposing of m and ctl if
  * they are mbuf chains
  */
-int
+static int
 sco_usrreq(struct socket *up, int req, struct mbuf *m,
     struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
 {
-	struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb;
-	struct sockaddr_bt *sa;
-	struct mbuf *m0;
+	struct sco_pcb *pcb = up->so_pcb;
 	int err = 0;
 
 	DPRINTFN(2, "%s\n", prurequests[req]);
-
-	switch(req) {
-	case PRU_CONTROL:
-		return EOPNOTSUPP;
-
-	case PRU_PURGEIF:
-		return EOPNOTSUPP;
-
-	case PRU_ATTACH:
-		if (up->so_lock == NULL) {
-			mutex_obj_hold(bt_lock);
-			up->so_lock = bt_lock;
-			solock(up);
-		}
-		KASSERT(solocked(up));
-		if (pcb)
-			return EINVAL;
-		err = soreserve(up, sco_sendspace, sco_recvspace);
-		if (err)
-			return err;
-
-		return sco_attach((struct sco_pcb **)&up->so_pcb,
-					&sco_proto, up);
-	}
+	KASSERT(req != PRU_ATTACH);
+	KASSERT(req != PRU_DETACH);
+	KASSERT(req != PRU_ACCEPT);
+	KASSERT(req != PRU_BIND);
+	KASSERT(req != PRU_LISTEN);
+	KASSERT(req != PRU_CONNECT);
+	KASSERT(req != PRU_CONNECT2);
+	KASSERT(req != PRU_DISCONNECT);
+	KASSERT(req != PRU_SHUTDOWN);
+	KASSERT(req != PRU_ABORT);
+	KASSERT(req != PRU_CONTROL);
+	KASSERT(req != PRU_SENSE);
+	KASSERT(req != PRU_PEERADDR);
+	KASSERT(req != PRU_SOCKADDR);
+	KASSERT(req != PRU_RCVD);
+	KASSERT(req != PRU_RCVOOB);
+	KASSERT(req != PRU_SEND);
+	KASSERT(req != PRU_SENDOOB);
+	KASSERT(req != PRU_PURGEIF);
 
 	/* anything after here *requires* a pcb */
 	if (pcb == NULL) {
@@ -136,98 +401,6 @@ sco_usrreq(struct socket *up, int req, s
 	}
 
 	switch(req) {
-	case PRU_DISCONNECT:
-		soisdisconnecting(up);
-		return sco_disconnect(pcb, up->so_linger);
-
-	case PRU_ABORT:
-		sco_disconnect(pcb, 0);
-		soisdisconnected(up);
-		/* fall through to */
-	case PRU_DETACH:
-		return sco_detach((struct sco_pcb **)&up->so_pcb);
-
-	case PRU_BIND:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-
-		if (sa->bt_len != sizeof(struct sockaddr_bt))
-			return EINVAL;
-
-		if (sa->bt_family != AF_BLUETOOTH)
-			return EAFNOSUPPORT;
-
-		return sco_bind(pcb, sa);
-
-	case PRU_CONNECT:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-
-		if (sa->bt_len != sizeof(struct sockaddr_bt))
-			return EINVAL;
-
-		if (sa->bt_family != AF_BLUETOOTH)
-			return EAFNOSUPPORT;
-
-		soisconnecting(up);
-		return sco_connect(pcb, sa);
-
-	case PRU_PEERADDR:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-		nam->m_len = sizeof(struct sockaddr_bt);
-		return sco_peeraddr(pcb, sa);
-
-	case PRU_SOCKADDR:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-		nam->m_len = sizeof(struct sockaddr_bt);
-		return sco_sockaddr(pcb, sa);
-
-	case PRU_SHUTDOWN:
-		socantsendmore(up);
-		break;
-
-	case PRU_SEND:
-		KASSERT(m != NULL);
-		if (m->m_pkthdr.len == 0)
-			break;
-
-		if (m->m_pkthdr.len > pcb->sp_mtu) {
-			err = EMSGSIZE;
-			break;
-		}
-
-		m0 = m_copypacket(m, M_DONTWAIT);
-		if (m0 == NULL) {
-			err = ENOMEM;
-			break;
-		}
-
-		if (ctl) /* no use for that */
-			m_freem(ctl);
-
-		sbappendrecord(&up->so_snd, m);
-		return sco_send(pcb, m0);
-
-	case PRU_SENSE:
-		return 0;		/* (no sense - Doh!) */
-
-	case PRU_RCVD:
-	case PRU_RCVOOB:
-		return EOPNOTSUPP;	/* (no release) */
-
-	case PRU_LISTEN:
-		return sco_listen(pcb);
-
-	case PRU_ACCEPT:
-		KASSERT(nam != NULL);
-		sa = mtod(nam, struct sockaddr_bt *);
-		nam->m_len = sizeof(struct sockaddr_bt);
-		return sco_peeraddr(pcb, sa);
-
-	case PRU_CONNECT2:
-	case PRU_SENDOOB:
 	case PRU_FASTTIMO:
 	case PRU_SLOWTIMO:
 	case PRU_PROTORCV:
@@ -365,3 +538,49 @@ sco_input(void *arg, struct mbuf *m)
 	sbappendrecord(&so->so_rcv, m);
 	sorwakeup(so);
 }
+
+PR_WRAP_USRREQS(sco)
+
+#define	sco_attach		sco_attach_wrapper
+#define	sco_detach		sco_detach_wrapper
+#define	sco_accept		sco_accept_wrapper
+#define	sco_bind		sco_bind_wrapper
+#define	sco_listen		sco_listen_wrapper
+#define	sco_connect		sco_connect_wrapper
+#define	sco_connect2		sco_connect2_wrapper
+#define	sco_disconnect		sco_disconnect_wrapper
+#define	sco_shutdown		sco_shutdown_wrapper
+#define	sco_abort		sco_abort_wrapper
+#define	sco_ioctl		sco_ioctl_wrapper
+#define	sco_stat		sco_stat_wrapper
+#define	sco_peeraddr		sco_peeraddr_wrapper
+#define	sco_sockaddr		sco_sockaddr_wrapper
+#define	sco_rcvd		sco_rcvd_wrapper
+#define	sco_recvoob		sco_recvoob_wrapper
+#define	sco_send		sco_send_wrapper
+#define	sco_sendoob		sco_sendoob_wrapper
+#define	sco_purgeif		sco_purgeif_wrapper
+#define	sco_usrreq		sco_usrreq_wrapper
+
+const struct pr_usrreqs sco_usrreqs = {
+	.pr_attach	= sco_attach,
+	.pr_detach	= sco_detach,
+	.pr_accept	= sco_accept,
+	.pr_bind	= sco_bind,
+	.pr_listen	= sco_listen,
+	.pr_connect	= sco_connect,
+	.pr_connect2	= sco_connect2,
+	.pr_disconnect	= sco_disconnect,
+	.pr_shutdown	= sco_shutdown,
+	.pr_abort	= sco_abort,
+	.pr_ioctl	= sco_ioctl,
+	.pr_stat	= sco_stat,
+	.pr_peeraddr	= sco_peeraddr,
+	.pr_sockaddr	= sco_sockaddr,
+	.pr_rcvd	= sco_rcvd,
+	.pr_recvoob	= sco_recvoob,
+	.pr_send	= sco_send,
+	.pr_sendoob	= sco_sendoob,
+	.pr_purgeif	= sco_purgeif,
+	.pr_generic	= sco_usrreq,
+};

Reply via email to