xref: /netbsd-src/sys/netbt/l2cap_socket.c (revision 481d3881954fd794ca5f2d880b68c53a5db8620e)
1*481d3881Srin /*	$NetBSD: l2cap_socket.c,v 1.37 2024/07/05 04:31:53 rin Exp $	*/
2a5c89047Sgdamore 
3a5c89047Sgdamore /*-
4a5c89047Sgdamore  * Copyright (c) 2005 Iain Hibbert.
5a5c89047Sgdamore  * Copyright (c) 2006 Itronix Inc.
6a5c89047Sgdamore  * All rights reserved.
7a5c89047Sgdamore  *
8a5c89047Sgdamore  * Redistribution and use in source and binary forms, with or without
9a5c89047Sgdamore  * modification, are permitted provided that the following conditions
10a5c89047Sgdamore  * are met:
11a5c89047Sgdamore  * 1. Redistributions of source code must retain the above copyright
12a5c89047Sgdamore  *    notice, this list of conditions and the following disclaimer.
13a5c89047Sgdamore  * 2. Redistributions in binary form must reproduce the above copyright
14a5c89047Sgdamore  *    notice, this list of conditions and the following disclaimer in the
15a5c89047Sgdamore  *    documentation and/or other materials provided with the distribution.
16a5c89047Sgdamore  * 3. The name of Itronix Inc. may not be used to endorse
17a5c89047Sgdamore  *    or promote products derived from this software without specific
18a5c89047Sgdamore  *    prior written permission.
19a5c89047Sgdamore  *
20a5c89047Sgdamore  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21a5c89047Sgdamore  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22a5c89047Sgdamore  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23a5c89047Sgdamore  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24a5c89047Sgdamore  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25a5c89047Sgdamore  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26a5c89047Sgdamore  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27a5c89047Sgdamore  * ON ANY THEORY OF LIABILITY, WHETHER IN
28a5c89047Sgdamore  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29a5c89047Sgdamore  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30a5c89047Sgdamore  * POSSIBILITY OF SUCH DAMAGE.
31a5c89047Sgdamore  */
32a5c89047Sgdamore 
33a5c89047Sgdamore #include <sys/cdefs.h>
34*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.37 2024/07/05 04:31:53 rin Exp $");
35fb76dbd4Splunky 
36fb76dbd4Splunky /* load symbolic names */
37fb76dbd4Splunky #ifdef BLUETOOTH_DEBUG
38fb76dbd4Splunky #define PRUREQUESTS
39fb76dbd4Splunky #define PRCOREQUESTS
40fb76dbd4Splunky #endif
41a5c89047Sgdamore 
42a5c89047Sgdamore #include <sys/param.h>
43a5c89047Sgdamore #include <sys/domain.h>
44a5c89047Sgdamore #include <sys/kernel.h>
45a5c89047Sgdamore #include <sys/mbuf.h>
46a5c89047Sgdamore #include <sys/proc.h>
47a5c89047Sgdamore #include <sys/protosw.h>
48a5c89047Sgdamore #include <sys/socket.h>
49a5c89047Sgdamore #include <sys/socketvar.h>
50a5c89047Sgdamore #include <sys/systm.h>
51a5c89047Sgdamore 
52a5c89047Sgdamore #include <netbt/bluetooth.h>
53a5c89047Sgdamore #include <netbt/l2cap.h>
54a5c89047Sgdamore 
55a5c89047Sgdamore /*
56a5c89047Sgdamore  * L2CAP Sockets
57a5c89047Sgdamore  *
58a5c89047Sgdamore  *	SOCK_SEQPACKET - normal L2CAP connection
59a5c89047Sgdamore  *
60a5c89047Sgdamore  *	SOCK_DGRAM - connectionless L2CAP - XXX not yet
61a5c89047Sgdamore  */
62a5c89047Sgdamore 
63a5c89047Sgdamore static void l2cap_connecting(void *);
64a5c89047Sgdamore static void l2cap_connected(void *);
65a5c89047Sgdamore static void l2cap_disconnected(void *, int);
66a5c89047Sgdamore static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
67a5c89047Sgdamore static void l2cap_complete(void *, int);
68f5db72e7Splunky static void l2cap_linkmode(void *, int);
69a5c89047Sgdamore static void l2cap_input(void *, struct mbuf *);
70a5c89047Sgdamore 
71a5c89047Sgdamore static const struct btproto l2cap_proto = {
72a5c89047Sgdamore 	l2cap_connecting,
73a5c89047Sgdamore 	l2cap_connected,
74a5c89047Sgdamore 	l2cap_disconnected,
75a5c89047Sgdamore 	l2cap_newconn,
76a5c89047Sgdamore 	l2cap_complete,
77f5db72e7Splunky 	l2cap_linkmode,
78f5db72e7Splunky 	l2cap_input,
79a5c89047Sgdamore };
80a5c89047Sgdamore 
81a5c89047Sgdamore /* sysctl variables */
82a5c89047Sgdamore int l2cap_sendspace = 4096;
83a5c89047Sgdamore int l2cap_recvspace = 4096;
84a5c89047Sgdamore 
854ae03c18Srmind static int
l2cap_attach(struct socket * so,int proto)8656a73a7dSrmind l2cap_attach(struct socket *so, int proto)
874ae03c18Srmind {
884ae03c18Srmind 	int error;
894ae03c18Srmind 
904ae03c18Srmind 	KASSERT(so->so_pcb == NULL);
914ae03c18Srmind 
924ae03c18Srmind 	if (so->so_lock == NULL) {
934ae03c18Srmind 		mutex_obj_hold(bt_lock);
944ae03c18Srmind 		so->so_lock = bt_lock;
954ae03c18Srmind 		solock(so);
964ae03c18Srmind 	}
974ae03c18Srmind 	KASSERT(solocked(so));
984ae03c18Srmind 
994ae03c18Srmind 	/*
1004ae03c18Srmind 	 * For L2CAP socket PCB we just use an l2cap_channel structure
1014ae03c18Srmind 	 * since we have nothing to add..
1024ae03c18Srmind 	 */
1034ae03c18Srmind 	error = soreserve(so, l2cap_sendspace, l2cap_recvspace);
1044ae03c18Srmind 	if (error)
1054ae03c18Srmind 		return error;
1064ae03c18Srmind 
10756a73a7dSrmind 	return l2cap_attach_pcb((struct l2cap_channel **)&so->so_pcb,
1084ae03c18Srmind 				&l2cap_proto, so);
1094ae03c18Srmind }
1104ae03c18Srmind 
1114ae03c18Srmind static void
l2cap_detach(struct socket * so)11256a73a7dSrmind l2cap_detach(struct socket *so)
1134ae03c18Srmind {
11419429f51Srmind 	KASSERT(so->so_pcb != NULL);
11556a73a7dSrmind 	l2cap_detach_pcb((struct l2cap_channel **)&so->so_pcb);
1164ae03c18Srmind 	KASSERT(so->so_pcb == NULL);
1174ae03c18Srmind }
1184ae03c18Srmind 
119d54d7ab2Srtr static int
l2cap_accept(struct socket * so,struct sockaddr * nam)120eddf3af3Srtr l2cap_accept(struct socket *so, struct sockaddr *nam)
121d27b133dSrtr {
122d27b133dSrtr 	struct l2cap_channel *pcb = so->so_pcb;
123d27b133dSrtr 
124d27b133dSrtr 	KASSERT(solocked(so));
125d27b133dSrtr 	KASSERT(nam != NULL);
126d27b133dSrtr 
127d27b133dSrtr 	if (pcb == NULL)
128d27b133dSrtr 		return EINVAL;
129d27b133dSrtr 
130eddf3af3Srtr 	return l2cap_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam);
131d27b133dSrtr }
132d27b133dSrtr 
133d27b133dSrtr static int
l2cap_bind(struct socket * so,struct sockaddr * nam,struct lwp * l)134a2ba5e69Srtr l2cap_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
1356dd8eef0Srtr {
1366dd8eef0Srtr 	struct l2cap_channel *pcb = so->so_pcb;
137a2ba5e69Srtr 	struct sockaddr_bt *sa = (struct sockaddr_bt *)nam;
1386dd8eef0Srtr 
1396dd8eef0Srtr 	KASSERT(solocked(so));
1406dd8eef0Srtr 	KASSERT(nam != NULL);
1416dd8eef0Srtr 
1426dd8eef0Srtr 	if (pcb == NULL)
1436dd8eef0Srtr 		return EINVAL;
1446dd8eef0Srtr 
1456dd8eef0Srtr 	if (sa->bt_len != sizeof(struct sockaddr_bt))
1466dd8eef0Srtr 		return EINVAL;
1476dd8eef0Srtr 
1486dd8eef0Srtr 	if (sa->bt_family != AF_BLUETOOTH)
1496dd8eef0Srtr 		return EAFNOSUPPORT;
1506dd8eef0Srtr 
1516dd8eef0Srtr 	return l2cap_bind_pcb(pcb, sa);
1526dd8eef0Srtr }
1536dd8eef0Srtr 
1546dd8eef0Srtr static int
l2cap_listen(struct socket * so,struct lwp * l)155ce6a5ff6Srtr l2cap_listen(struct socket *so, struct lwp *l)
1566dd8eef0Srtr {
1576dd8eef0Srtr 	struct l2cap_channel *pcb = so->so_pcb;
1586dd8eef0Srtr 
1596dd8eef0Srtr 	KASSERT(solocked(so));
1606dd8eef0Srtr 
1616dd8eef0Srtr 	if (pcb == NULL)
1626dd8eef0Srtr 		return EINVAL;
1636dd8eef0Srtr 
1646dd8eef0Srtr 	return l2cap_listen_pcb(pcb);
1656dd8eef0Srtr }
1666dd8eef0Srtr 
1676dd8eef0Srtr static int
l2cap_connect(struct socket * so,struct sockaddr * nam,struct lwp * l)168fd12cf39Srtr l2cap_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
169ad6ae402Srtr {
170ad6ae402Srtr 	struct l2cap_channel *pcb = so->so_pcb;
171fd12cf39Srtr 	struct sockaddr_bt *sa = (struct sockaddr_bt *)nam;
172ad6ae402Srtr 
173ad6ae402Srtr 	KASSERT(solocked(so));
174ad6ae402Srtr 	KASSERT(nam != NULL);
175ad6ae402Srtr 
176ad6ae402Srtr 	if (pcb == NULL)
177ad6ae402Srtr 		return EINVAL;
178ad6ae402Srtr 
179ad6ae402Srtr 	if (sa->bt_len != sizeof(struct sockaddr_bt))
180ad6ae402Srtr 		return EINVAL;
181ad6ae402Srtr 
182ad6ae402Srtr 	if (sa->bt_family != AF_BLUETOOTH)
183ad6ae402Srtr 		return EAFNOSUPPORT;
184ad6ae402Srtr 
185ad6ae402Srtr 	soisconnecting(so);
186ad6ae402Srtr 	return l2cap_connect_pcb(pcb, sa);
187ad6ae402Srtr }
188ad6ae402Srtr 
189ad6ae402Srtr static int
l2cap_connect2(struct socket * so,struct socket * so2)1908cf67cc6Srtr l2cap_connect2(struct socket *so, struct socket *so2)
1918cf67cc6Srtr {
1928cf67cc6Srtr 	KASSERT(solocked(so));
1938cf67cc6Srtr 
1948cf67cc6Srtr 	if (so->so_pcb == NULL)
1958cf67cc6Srtr 		return EINVAL;
1968cf67cc6Srtr 
1978cf67cc6Srtr 	return EOPNOTSUPP;
1988cf67cc6Srtr }
1998cf67cc6Srtr 
2008cf67cc6Srtr static int
l2cap_disconnect(struct socket * so)201892163b8Srtr l2cap_disconnect(struct socket *so)
202892163b8Srtr {
203892163b8Srtr 	struct l2cap_channel *pcb = so->so_pcb;
204892163b8Srtr 
205892163b8Srtr 	KASSERT(solocked(so));
206892163b8Srtr 
207892163b8Srtr 	if (pcb == NULL)
208892163b8Srtr 		return EINVAL;
209892163b8Srtr 
210892163b8Srtr 	soisdisconnecting(so);
211892163b8Srtr 	return l2cap_disconnect_pcb(pcb, so->so_linger);
212892163b8Srtr }
213892163b8Srtr 
214892163b8Srtr static int
l2cap_shutdown(struct socket * so)215892163b8Srtr l2cap_shutdown(struct socket *so)
216892163b8Srtr {
217892163b8Srtr 	KASSERT(solocked(so));
218892163b8Srtr 
219892163b8Srtr 	socantsendmore(so);
220892163b8Srtr 	return 0;
221892163b8Srtr }
222892163b8Srtr 
223892163b8Srtr static int
l2cap_abort(struct socket * so)224892163b8Srtr l2cap_abort(struct socket *so)
225892163b8Srtr {
226892163b8Srtr 	struct l2cap_channel *pcb = so->so_pcb;
227892163b8Srtr 
228892163b8Srtr 	KASSERT(solocked(so));
229892163b8Srtr 
230892163b8Srtr 	if (pcb == NULL)
231892163b8Srtr 		return EINVAL;
232892163b8Srtr 
233892163b8Srtr 	l2cap_disconnect_pcb(pcb, 0);
234892163b8Srtr 	soisdisconnected(so);
235892163b8Srtr 	l2cap_detach(so);
236892163b8Srtr 	return 0;
237892163b8Srtr }
238892163b8Srtr 
239892163b8Srtr static int
l2cap_ioctl(struct socket * so,u_long cmd,void * nam,struct ifnet * ifp)240ff90c29dSrtr l2cap_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
241d54d7ab2Srtr {
242d54d7ab2Srtr 	return EPASSTHROUGH;
243d54d7ab2Srtr }
244d54d7ab2Srtr 
245a60320caSrtr static int
l2cap_stat(struct socket * so,struct stat * ub)246a60320caSrtr l2cap_stat(struct socket *so, struct stat *ub)
247a60320caSrtr {
248ff90c29dSrtr 	KASSERT(solocked(so));
249ff90c29dSrtr 
250909a1fc6Srtr 	return 0;
251a60320caSrtr }
252a60320caSrtr 
253d575eb54Srtr static int
l2cap_peeraddr(struct socket * so,struct sockaddr * nam)254eddf3af3Srtr l2cap_peeraddr(struct socket *so, struct sockaddr *nam)
255d575eb54Srtr {
256d575eb54Srtr 	struct l2cap_channel *pcb = so->so_pcb;
257d575eb54Srtr 
258d575eb54Srtr 	KASSERT(solocked(so));
259d575eb54Srtr 	KASSERT(pcb != NULL);
260d575eb54Srtr 	KASSERT(nam != NULL);
261d575eb54Srtr 
262eddf3af3Srtr 	return l2cap_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam);
263d575eb54Srtr }
264d575eb54Srtr 
265d575eb54Srtr static int
l2cap_sockaddr(struct socket * so,struct sockaddr * nam)266eddf3af3Srtr l2cap_sockaddr(struct socket *so, struct sockaddr *nam)
267d575eb54Srtr {
268d575eb54Srtr 	struct l2cap_channel *pcb = so->so_pcb;
269d575eb54Srtr 
270d575eb54Srtr 	KASSERT(solocked(so));
271d575eb54Srtr 	KASSERT(pcb != NULL);
272d575eb54Srtr 	KASSERT(nam != NULL);
273d575eb54Srtr 
274eddf3af3Srtr 	return l2cap_sockaddr_pcb(pcb, (struct sockaddr_bt *)nam);
275d575eb54Srtr }
276d575eb54Srtr 
27735b22fa9Srtr static int
l2cap_rcvd(struct socket * so,int flags,struct lwp * l)278822872eaSrtr l2cap_rcvd(struct socket *so, int flags, struct lwp *l)
279822872eaSrtr {
280822872eaSrtr 	KASSERT(solocked(so));
281822872eaSrtr 
282822872eaSrtr 	return EOPNOTSUPP;
283822872eaSrtr }
284822872eaSrtr 
285822872eaSrtr static int
l2cap_recvoob(struct socket * so,struct mbuf * m,int flags)28635b22fa9Srtr l2cap_recvoob(struct socket *so, struct mbuf *m, int flags)
28735b22fa9Srtr {
28835b22fa9Srtr 	KASSERT(solocked(so));
28935b22fa9Srtr 
29035b22fa9Srtr 	return EOPNOTSUPP;
29135b22fa9Srtr }
29235b22fa9Srtr 
29335b22fa9Srtr static int
l2cap_send(struct socket * so,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,struct lwp * l)294fd12cf39Srtr l2cap_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
295651e5bd3Srtr     struct mbuf *control, struct lwp *l)
296651e5bd3Srtr {
297651e5bd3Srtr 	struct l2cap_channel *pcb = so->so_pcb;
298651e5bd3Srtr 	struct mbuf *m0;
299651e5bd3Srtr 	int error = 0;
300651e5bd3Srtr 
301651e5bd3Srtr 	KASSERT(solocked(so));
302651e5bd3Srtr 	KASSERT(m != NULL);
303651e5bd3Srtr 
304651e5bd3Srtr 	m_freem(control);
305651e5bd3Srtr 
306651e5bd3Srtr 	if (pcb == NULL) {
307651e5bd3Srtr 		error = EINVAL;
308651e5bd3Srtr 		goto release;
309651e5bd3Srtr 	}
310651e5bd3Srtr 
311651e5bd3Srtr 	if (m->m_pkthdr.len == 0)
312651e5bd3Srtr 		goto release;
313651e5bd3Srtr 
314651e5bd3Srtr 	if (m->m_pkthdr.len > pcb->lc_omtu) {
315651e5bd3Srtr 		error = EMSGSIZE;
316651e5bd3Srtr 		goto release;
317651e5bd3Srtr 	}
318651e5bd3Srtr 
319651e5bd3Srtr 	m0 = m_copypacket(m, M_DONTWAIT);
320651e5bd3Srtr 	if (m0 == NULL) {
321651e5bd3Srtr 		error = ENOMEM;
322651e5bd3Srtr 		goto release;
323651e5bd3Srtr 	}
324651e5bd3Srtr 
325651e5bd3Srtr 	sbappendrecord(&so->so_snd, m);
326651e5bd3Srtr 	return l2cap_send_pcb(pcb, m0);
327651e5bd3Srtr 
328651e5bd3Srtr release:
329651e5bd3Srtr 	m_freem(m);
330651e5bd3Srtr 
331651e5bd3Srtr 	return error;
332651e5bd3Srtr }
333651e5bd3Srtr 
334651e5bd3Srtr static int
l2cap_sendoob(struct socket * so,struct mbuf * m,struct mbuf * control)33535b22fa9Srtr l2cap_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
33635b22fa9Srtr {
33735b22fa9Srtr 	KASSERT(solocked(so));
33835b22fa9Srtr 
33935b22fa9Srtr 	m_freem(m);
34035b22fa9Srtr 	m_freem(control);
34135b22fa9Srtr 
34235b22fa9Srtr 	return EOPNOTSUPP;
34335b22fa9Srtr }
34435b22fa9Srtr 
3458cf67cc6Srtr static int
l2cap_purgeif(struct socket * so,struct ifnet * ifp)3468cf67cc6Srtr l2cap_purgeif(struct socket *so, struct ifnet *ifp)
3478cf67cc6Srtr {
3488cf67cc6Srtr 
3498cf67cc6Srtr 	return EOPNOTSUPP;
3508cf67cc6Srtr }
3518cf67cc6Srtr 
352a5c89047Sgdamore /*
353fd7356a9Splunky  * l2cap_ctloutput(req, socket, sockopt)
354a5c89047Sgdamore  *
355a5c89047Sgdamore  *	Apply configuration commands to channel. This corresponds to
356a5c89047Sgdamore  *	"Reconfigure Channel Request" in the L2CAP specification.
357a5c89047Sgdamore  */
358a5c89047Sgdamore int
l2cap_ctloutput(int req,struct socket * so,struct sockopt * sopt)359fd7356a9Splunky l2cap_ctloutput(int req, struct socket *so, struct sockopt *sopt)
360a5c89047Sgdamore {
361a5c89047Sgdamore 	struct l2cap_channel *pcb = so->so_pcb;
362a5c89047Sgdamore 	int err = 0;
363a5c89047Sgdamore 
364a5c89047Sgdamore 	DPRINTFN(2, "%s\n", prcorequests[req]);
365a5c89047Sgdamore 
366162ec756Splunky 	if (pcb == NULL)
367162ec756Splunky 		return EINVAL;
368162ec756Splunky 
369fd7356a9Splunky 	if (sopt->sopt_level != BTPROTO_L2CAP)
370162ec756Splunky 		return ENOPROTOOPT;
371a5c89047Sgdamore 
372a5c89047Sgdamore 	switch(req) {
373a5c89047Sgdamore 	case PRCO_GETOPT:
374fd7356a9Splunky 		err = l2cap_getopt(pcb, sopt);
375a5c89047Sgdamore 		break;
376a5c89047Sgdamore 
377a5c89047Sgdamore 	case PRCO_SETOPT:
378fd7356a9Splunky 		err = l2cap_setopt(pcb, sopt);
379a5c89047Sgdamore 		break;
380a5c89047Sgdamore 
381a5c89047Sgdamore 	default:
382162ec756Splunky 		err = ENOPROTOOPT;
383a5c89047Sgdamore 		break;
384a5c89047Sgdamore 	}
385a5c89047Sgdamore 
386a5c89047Sgdamore 	return err;
387a5c89047Sgdamore }
388a5c89047Sgdamore 
389a5c89047Sgdamore /**********************************************************************
390a5c89047Sgdamore  *
391a5c89047Sgdamore  *	L2CAP Protocol socket callbacks
392a5c89047Sgdamore  *
393a5c89047Sgdamore  */
394a5c89047Sgdamore 
395a5c89047Sgdamore static void
l2cap_connecting(void * arg)396a5c89047Sgdamore l2cap_connecting(void *arg)
397a5c89047Sgdamore {
398a5c89047Sgdamore 	struct socket *so = arg;
399a5c89047Sgdamore 
400a5c89047Sgdamore 	DPRINTF("Connecting\n");
401a5c89047Sgdamore 	soisconnecting(so);
402a5c89047Sgdamore }
403a5c89047Sgdamore 
404a5c89047Sgdamore static void
l2cap_connected(void * arg)405a5c89047Sgdamore l2cap_connected(void *arg)
406a5c89047Sgdamore {
407a5c89047Sgdamore 	struct socket *so = arg;
408a5c89047Sgdamore 
409a5c89047Sgdamore 	DPRINTF("Connected\n");
410a5c89047Sgdamore 	soisconnected(so);
411a5c89047Sgdamore }
412a5c89047Sgdamore 
413a5c89047Sgdamore static void
l2cap_disconnected(void * arg,int err)414a5c89047Sgdamore l2cap_disconnected(void *arg, int err)
415a5c89047Sgdamore {
416a5c89047Sgdamore 	struct socket *so = arg;
417a5c89047Sgdamore 
418a5c89047Sgdamore 	DPRINTF("Disconnected (%d)\n", err);
419a5c89047Sgdamore 
420a5c89047Sgdamore 	so->so_error = err;
421a5c89047Sgdamore 	soisdisconnected(so);
422a5c89047Sgdamore }
423a5c89047Sgdamore 
424a5c89047Sgdamore static void *
l2cap_newconn(void * arg,struct sockaddr_bt * laddr,struct sockaddr_bt * raddr)425168cd830Schristos l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
426168cd830Schristos     struct sockaddr_bt *raddr)
427a5c89047Sgdamore {
428a5c89047Sgdamore 	struct socket *so = arg;
429a5c89047Sgdamore 
430a5c89047Sgdamore 	DPRINTF("New Connection\n");
4318088e729Srmind 	so = sonewconn(so, false);
432a5c89047Sgdamore 	if (so == NULL)
433a5c89047Sgdamore 		return NULL;
434a5c89047Sgdamore 
435a5c89047Sgdamore 	soisconnecting(so);
436a5c89047Sgdamore 
437a5c89047Sgdamore 	return so->so_pcb;
438a5c89047Sgdamore }
439a5c89047Sgdamore 
440a5c89047Sgdamore static void
l2cap_complete(void * arg,int count)441a5c89047Sgdamore l2cap_complete(void *arg, int count)
442a5c89047Sgdamore {
443a5c89047Sgdamore 	struct socket *so = arg;
444a5c89047Sgdamore 
445a5c89047Sgdamore 	while (count-- > 0)
446a5c89047Sgdamore 		sbdroprecord(&so->so_snd);
447a5c89047Sgdamore 
448a5c89047Sgdamore 	sowwakeup(so);
449a5c89047Sgdamore }
450a5c89047Sgdamore 
451a5c89047Sgdamore static void
l2cap_linkmode(void * arg,int new)452f5db72e7Splunky l2cap_linkmode(void *arg, int new)
453f5db72e7Splunky {
454f5db72e7Splunky 	struct socket *so = arg;
455fd7356a9Splunky 	struct sockopt sopt;
456f5db72e7Splunky 	int mode;
457f5db72e7Splunky 
458f5db72e7Splunky 	DPRINTF("auth %s, encrypt %s, secure %s\n",
459f5db72e7Splunky 		(new & L2CAP_LM_AUTH ? "on" : "off"),
460f5db72e7Splunky 		(new & L2CAP_LM_ENCRYPT ? "on" : "off"),
461f5db72e7Splunky 		(new & L2CAP_LM_SECURE ? "on" : "off"));
462f5db72e7Splunky 
463fd7356a9Splunky 	sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_LM, 0);
464fd7356a9Splunky 	(void)l2cap_getopt(so->so_pcb, &sopt);
465fd7356a9Splunky 	(void)sockopt_getint(&sopt, &mode);
466fd7356a9Splunky 	sockopt_destroy(&sopt);
467fd7356a9Splunky 
468f5db72e7Splunky 	if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
469f5db72e7Splunky 	    || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
470f5db72e7Splunky 	    || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
471892163b8Srtr 		l2cap_disconnect_pcb(so->so_pcb, 0);
472f5db72e7Splunky }
473f5db72e7Splunky 
474f5db72e7Splunky static void
l2cap_input(void * arg,struct mbuf * m)475a5c89047Sgdamore l2cap_input(void *arg, struct mbuf *m)
476a5c89047Sgdamore {
477a5c89047Sgdamore 	struct socket *so = arg;
478a5c89047Sgdamore 
479a5c89047Sgdamore 	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
480a5c89047Sgdamore 		printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
481a5c89047Sgdamore 			__func__, m->m_pkthdr.len);
482a5c89047Sgdamore 		m_freem(m);
483a5c89047Sgdamore 		return;
484a5c89047Sgdamore 	}
485a5c89047Sgdamore 
486a5c89047Sgdamore 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
487a5c89047Sgdamore 
488a5c89047Sgdamore 	sbappendrecord(&so->so_rcv, m);
489a5c89047Sgdamore 	sorwakeup(so);
490a5c89047Sgdamore }
49139bd8deeSrmind 
492e401453fSrmind PR_WRAP_USRREQS(l2cap)
49339bd8deeSrmind 
494e401453fSrmind #define	l2cap_attach		l2cap_attach_wrapper
495e401453fSrmind #define	l2cap_detach		l2cap_detach_wrapper
496d27b133dSrtr #define	l2cap_accept		l2cap_accept_wrapper
4976dd8eef0Srtr #define	l2cap_bind		l2cap_bind_wrapper
4986dd8eef0Srtr #define	l2cap_listen		l2cap_listen_wrapper
499ad6ae402Srtr #define	l2cap_connect		l2cap_connect_wrapper
5008cf67cc6Srtr #define	l2cap_connect2		l2cap_connect2_wrapper
501892163b8Srtr #define	l2cap_disconnect	l2cap_disconnect_wrapper
502892163b8Srtr #define	l2cap_shutdown		l2cap_shutdown_wrapper
503892163b8Srtr #define	l2cap_abort		l2cap_abort_wrapper
504d54d7ab2Srtr #define	l2cap_ioctl		l2cap_ioctl_wrapper
505a60320caSrtr #define	l2cap_stat		l2cap_stat_wrapper
506d575eb54Srtr #define	l2cap_peeraddr		l2cap_peeraddr_wrapper
507d575eb54Srtr #define	l2cap_sockaddr		l2cap_sockaddr_wrapper
508822872eaSrtr #define	l2cap_rcvd		l2cap_rcvd_wrapper
50935b22fa9Srtr #define	l2cap_recvoob		l2cap_recvoob_wrapper
510651e5bd3Srtr #define	l2cap_send		l2cap_send_wrapper
51135b22fa9Srtr #define	l2cap_sendoob		l2cap_sendoob_wrapper
5128cf67cc6Srtr #define	l2cap_purgeif		l2cap_purgeif_wrapper
51339bd8deeSrmind 
51439bd8deeSrmind const struct pr_usrreqs l2cap_usrreqs = {
51556a73a7dSrmind 	.pr_attach	= l2cap_attach,
51656a73a7dSrmind 	.pr_detach	= l2cap_detach,
517d27b133dSrtr 	.pr_accept	= l2cap_accept,
5186dd8eef0Srtr 	.pr_bind	= l2cap_bind,
5196dd8eef0Srtr 	.pr_listen	= l2cap_listen,
520ad6ae402Srtr 	.pr_connect	= l2cap_connect,
5218cf67cc6Srtr 	.pr_connect2	= l2cap_connect2,
522892163b8Srtr 	.pr_disconnect	= l2cap_disconnect,
523892163b8Srtr 	.pr_shutdown	= l2cap_shutdown,
524892163b8Srtr 	.pr_abort	= l2cap_abort,
525d54d7ab2Srtr 	.pr_ioctl	= l2cap_ioctl,
526a60320caSrtr 	.pr_stat	= l2cap_stat,
527d575eb54Srtr 	.pr_peeraddr	= l2cap_peeraddr,
528d575eb54Srtr 	.pr_sockaddr	= l2cap_sockaddr,
529822872eaSrtr 	.pr_rcvd	= l2cap_rcvd,
53035b22fa9Srtr 	.pr_recvoob	= l2cap_recvoob,
531651e5bd3Srtr 	.pr_send	= l2cap_send,
53235b22fa9Srtr 	.pr_sendoob	= l2cap_sendoob,
5338cf67cc6Srtr 	.pr_purgeif	= l2cap_purgeif,
53439bd8deeSrmind };
535