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