1 /* $NetBSD: l2cap_socket.c,v 1.8 2008/04/24 11:38:37 ad Exp $ */
4 * Copyright (c) 2005 Iain Hibbert.
5 * Copyright (c) 2006 Itronix Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of Itronix Inc. may not be used to endorse
17 * or promote products derived from this software without specific
18 * prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.8 2008/04/24 11:38:37 ad Exp $");
36 /* load symbolic names */
37 #ifdef BLUETOOTH_DEBUG
42 #include <sys/param.h>
43 #include <sys/domain.h>
44 #include <sys/kernel.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/systm.h>
52 #include <netbt/bluetooth.h>
53 #include <netbt/l2cap.h>
58 * SOCK_SEQPACKET - normal L2CAP connection
60 * SOCK_DGRAM - connectionless L2CAP - XXX not yet
63 static void l2cap_connecting(void *);
64 static void l2cap_connected(void *);
65 static void l2cap_disconnected(void *, int);
66 static void *l2cap_newconn(void *, struct sockaddr_bt
*, struct sockaddr_bt
*);
67 static void l2cap_complete(void *, int);
68 static void l2cap_linkmode(void *, int);
69 static void l2cap_input(void *, struct mbuf
*);
71 static const struct btproto l2cap_proto
= {
81 /* sysctl variables */
82 int l2cap_sendspace
= 4096;
83 int l2cap_recvspace
= 4096;
89 * optional mbuf chain containing message
90 * ioctl command (PRU_CONTROL)
92 * optional mbuf chain containing an address
93 * ioctl data (PRU_CONTROL)
94 * optionally protocol number (PRU_ATTACH)
95 * message flags (PRU_RCVD)
97 * optional mbuf chain containing socket options
98 * optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
99 * l is pointer to process requesting action (if any)
101 * we are responsible for disposing of m and ctl if
102 * they are mbuf chains
105 l2cap_usrreq(struct socket
*up
, int req
, struct mbuf
*m
,
106 struct mbuf
*nam
, struct mbuf
*ctl
, struct lwp
*l
)
108 struct l2cap_channel
*pcb
= up
->so_pcb
;
109 struct sockaddr_bt
*sa
;
113 DPRINTFN(2, "%s\n", prurequests
[req
]);
123 if (up
->so_lock
== NULL
) {
124 mutex_obj_hold(bt_lock
);
125 up
->so_lock
= bt_lock
;
128 KASSERT(solocked(up
));
132 * For L2CAP socket PCB we just use an l2cap_channel structure
133 * since we have nothing to add..
135 err
= soreserve(up
, l2cap_sendspace
, l2cap_recvspace
);
139 return l2cap_attach((struct l2cap_channel
**)&up
->so_pcb
,
150 soisdisconnecting(up
);
151 return l2cap_disconnect(pcb
, up
->so_linger
);
154 l2cap_disconnect(pcb
, 0);
155 soisdisconnected(up
);
156 /* fall through to */
158 return l2cap_detach((struct l2cap_channel
**)&up
->so_pcb
);
161 KASSERT(nam
!= NULL
);
162 sa
= mtod(nam
, struct sockaddr_bt
*);
164 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
))
167 if (sa
->bt_family
!= AF_BLUETOOTH
)
170 return l2cap_bind(pcb
, sa
);
173 KASSERT(nam
!= NULL
);
174 sa
= mtod(nam
, struct sockaddr_bt
*);
176 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
))
179 if (sa
->bt_family
!= AF_BLUETOOTH
)
183 return l2cap_connect(pcb
, sa
);
186 KASSERT(nam
!= NULL
);
187 sa
= mtod(nam
, struct sockaddr_bt
*);
188 nam
->m_len
= sizeof(struct sockaddr_bt
);
189 return l2cap_peeraddr(pcb
, sa
);
192 KASSERT(nam
!= NULL
);
193 sa
= mtod(nam
, struct sockaddr_bt
*);
194 nam
->m_len
= sizeof(struct sockaddr_bt
);
195 return l2cap_sockaddr(pcb
, sa
);
203 if (m
->m_pkthdr
.len
== 0)
206 if (m
->m_pkthdr
.len
> pcb
->lc_omtu
) {
211 m0
= m_copypacket(m
, M_DONTWAIT
);
217 if (ctl
) /* no use for that */
220 sbappendrecord(&up
->so_snd
, m
);
221 return l2cap_send(pcb
, m0
);
224 return 0; /* (no release) */
228 return EOPNOTSUPP
; /* (no release) */
231 return l2cap_listen(pcb
);
234 KASSERT(nam
!= NULL
);
235 sa
= mtod(nam
, struct sockaddr_bt
*);
236 nam
->m_len
= sizeof(struct sockaddr_bt
);
237 return l2cap_peeraddr(pcb
, sa
);
256 if (ctl
) m_freem(ctl
);
261 * l2cap_ctloutput(req, socket, sockopt)
263 * Apply configuration commands to channel. This corresponds to
264 * "Reconfigure Channel Request" in the L2CAP specification.
267 l2cap_ctloutput(int req
, struct socket
*so
, struct sockopt
*sopt
)
269 struct l2cap_channel
*pcb
= so
->so_pcb
;
272 DPRINTFN(2, "%s\n", prcorequests
[req
]);
277 if (sopt
->sopt_level
!= BTPROTO_L2CAP
)
282 err
= l2cap_getopt(pcb
, sopt
);
286 err
= l2cap_setopt(pcb
, sopt
);
297 /**********************************************************************
299 * L2CAP Protocol socket callbacks
304 l2cap_connecting(void *arg
)
306 struct socket
*so
= arg
;
308 DPRINTF("Connecting\n");
313 l2cap_connected(void *arg
)
315 struct socket
*so
= arg
;
317 DPRINTF("Connected\n");
322 l2cap_disconnected(void *arg
, int err
)
324 struct socket
*so
= arg
;
326 DPRINTF("Disconnected (%d)\n", err
);
329 soisdisconnected(so
);
333 l2cap_newconn(void *arg
, struct sockaddr_bt
*laddr
,
334 struct sockaddr_bt
*raddr
)
336 struct socket
*so
= arg
;
338 DPRINTF("New Connection\n");
339 so
= sonewconn(so
, 0);
349 l2cap_complete(void *arg
, int count
)
351 struct socket
*so
= arg
;
354 sbdroprecord(&so
->so_snd
);
360 l2cap_linkmode(void *arg
, int new)
362 struct socket
*so
= arg
;
366 DPRINTF("auth %s, encrypt %s, secure %s\n",
367 (new & L2CAP_LM_AUTH
? "on" : "off"),
368 (new & L2CAP_LM_ENCRYPT
? "on" : "off"),
369 (new & L2CAP_LM_SECURE
? "on" : "off"));
371 sockopt_init(&sopt
, BTPROTO_L2CAP
, SO_L2CAP_LM
, 0);
372 (void)l2cap_getopt(so
->so_pcb
, &sopt
);
373 (void)sockopt_getint(&sopt
, &mode
);
374 sockopt_destroy(&sopt
);
376 if (((mode
& L2CAP_LM_AUTH
) && !(new & L2CAP_LM_AUTH
))
377 || ((mode
& L2CAP_LM_ENCRYPT
) && !(new & L2CAP_LM_ENCRYPT
))
378 || ((mode
& L2CAP_LM_SECURE
) && !(new & L2CAP_LM_SECURE
)))
379 l2cap_disconnect(so
->so_pcb
, 0);
383 l2cap_input(void *arg
, struct mbuf
*m
)
385 struct socket
*so
= arg
;
387 if (m
->m_pkthdr
.len
> sbspace(&so
->so_rcv
)) {
388 printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
389 __func__
, m
->m_pkthdr
.len
);
394 DPRINTFN(10, "received %d bytes\n", m
->m_pkthdr
.len
);
396 sbappendrecord(&so
->so_rcv
, m
);