1 /* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
2 /* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
5 * Copyright (c) 2005 Iain Hibbert.
6 * Copyright (c) 2006 Itronix Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of Itronix Inc. may not be used to endorse
18 * or promote products derived from this software without specific
19 * prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 /* load symbolic names */
35 #ifdef BLUETOOTH_DEBUG
40 #include <sys/param.h>
41 #include <sys/domain.h>
42 #include <sys/kernel.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/systm.h>
49 #include <vm/vm_zone.h>
51 #include <netbt/bluetooth.h>
52 #include <netbt/hci.h> /* XXX for EPASSTHROUGH */
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;
86 * l2cap_ctloutput(request, socket, level, optname, opt)
88 * Apply configuration commands to channel. This corresponds to
89 * "Reconfigure Channel Request" in the L2CAP specification.
92 l2cap_ctloutput(struct socket *so, struct sockopt *sopt)
94 struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb;
98 #ifdef notyet /* XXX */
99 DPRINTFN(2, "%s\n", prcorequests[req]);
105 if (sopt->sopt_level != BTPROTO_L2CAP)
108 switch(sopt->sopt_dir) {
110 m = m_get(M_NOWAIT, MT_DATA);
115 m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *));
121 soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
125 err = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt);
136 /**********************************************************************
138 * L2CAP Protocol socket callbacks
143 l2cap_connecting(void *arg)
145 struct socket *so = arg;
147 DPRINTF("Connecting\n");
152 l2cap_connected(void *arg)
154 struct socket *so = arg;
156 DPRINTF("Connected\n");
161 l2cap_disconnected(void *arg, int err)
163 struct socket *so = arg;
165 DPRINTF("Disconnected (%d)\n", err);
168 soisdisconnected(so);
172 l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
173 struct sockaddr_bt *raddr)
175 struct socket *so = arg;
177 DPRINTF("New Connection\n");
178 so = sonewconn(so, 0);
188 l2cap_complete(void *arg, int count)
190 struct socket *so = arg;
193 sbdroprecord(&so->so_snd.sb);
199 l2cap_linkmode(void *arg, int new)
201 struct socket *so = arg;
204 DPRINTF("auth %s, encrypt %s, secure %s\n",
205 (new & L2CAP_LM_AUTH ? "on" : "off"),
206 (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
207 (new & L2CAP_LM_SECURE ? "on" : "off"));
209 (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
210 if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
211 || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
212 || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
213 l2cap_disconnect(so->so_pcb, 0);
217 l2cap_input(void *arg, struct mbuf *m)
219 struct socket *so = arg;
221 if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
222 kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
223 __func__, m->m_pkthdr.len);
228 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
230 sbappendrecord(&so->so_rcv.sb, m);
236 * Implementation of usrreqs.
239 l2cap_sdetach(struct socket *so)
241 return l2cap_detach((struct l2cap_channel **)&so->so_pcb);
245 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
246 * will sofree() it when we return.
249 l2cap_sabort (struct socket *so)
251 struct l2cap_channel *pcb = so->so_pcb;
254 l2cap_disconnect(pcb, 0);
255 soisdisconnected(so);
257 error = l2cap_sdetach(so);
262 l2cap_sdisconnect (struct socket *so)
264 struct l2cap_channel *pcb = so->so_pcb;
266 soisdisconnecting(so);
268 return l2cap_disconnect(pcb, so->so_linger);
272 l2cap_scontrol (struct socket *so, u_long cmd, caddr_t data,
273 struct ifnet *ifp, struct thread *td)
279 l2cap_sattach (struct socket *so, int proto,
280 struct pru_attach_info *ai)
282 struct l2cap_channel *pcb = so->so_pcb;
289 * For L2CAP socket PCB we just use an l2cap_channel structure
290 * since we have nothing to add..
292 err = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL);
296 return l2cap_attach((struct l2cap_channel **)&so->so_pcb,
301 l2cap_sbind (struct socket *so, struct sockaddr *nam,
304 struct l2cap_channel *pcb = so->so_pcb;
305 struct sockaddr_bt *sa;
307 KKASSERT(nam != NULL);
308 sa = (struct sockaddr_bt *)nam;
310 if (sa->bt_len != sizeof(struct sockaddr_bt))
313 if (sa->bt_family != AF_BLUETOOTH)
316 return l2cap_bind(pcb, sa);
320 l2cap_sconnect (struct socket *so, struct sockaddr *nam,
323 struct l2cap_channel *pcb = so->so_pcb;
324 struct sockaddr_bt *sa;
326 KKASSERT(nam != NULL);
327 sa = (struct sockaddr_bt *)nam;
329 if (sa->bt_len != sizeof(struct sockaddr_bt))
332 if (sa->bt_family != AF_BLUETOOTH)
336 return l2cap_connect(pcb, sa);
340 l2cap_speeraddr (struct socket *so, struct sockaddr **nam)
342 struct l2cap_channel *pcb = so->so_pcb;
343 struct sockaddr_bt *sa, ssa;
347 bzero(sa, sizeof *sa);
348 sa->bt_len = sizeof(struct sockaddr_bt);
349 sa->bt_family = AF_BLUETOOTH;
350 e = l2cap_peeraddr(pcb, sa);
351 *nam = dup_sockaddr((struct sockaddr *)sa);
357 l2cap_ssockaddr (struct socket *so, struct sockaddr **nam)
359 struct l2cap_channel *pcb = so->so_pcb;
360 struct sockaddr_bt *sa, ssa;
364 bzero(sa, sizeof *sa);
365 sa->bt_len = sizeof(struct sockaddr_bt);
366 sa->bt_family = AF_BLUETOOTH;
367 e = l2cap_sockaddr(pcb, sa);
368 *nam = dup_sockaddr((struct sockaddr *)sa);
374 l2cap_sshutdown (struct socket *so)
381 l2cap_ssend (struct socket *so, int flags, struct mbuf *m,
382 struct sockaddr *addr, struct mbuf *control, struct thread *td)
384 struct l2cap_channel *pcb = so->so_pcb;
390 if (m->m_pkthdr.len == 0)
393 if (m->m_pkthdr.len > pcb->lc_omtu) {
398 m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
404 if (control) /* no use for that */
407 sbappendrecord(&so->so_snd.sb, m);
408 return l2cap_send(pcb, m0);
420 l2cap_saccept(struct socket *so, struct sockaddr **nam)
422 struct l2cap_channel *pcb = so->so_pcb;
423 struct sockaddr_bt sa;
426 KKASSERT(nam != NULL);
428 bzero(&sa, sizeof (sa) );
429 sa.bt_len = sizeof(struct sockaddr_bt);
430 sa.bt_family = AF_BLUETOOTH;
432 e = l2cap_peeraddr(pcb, &sa);
433 *nam = dup_sockaddr((struct sockaddr *)&sa);
439 l2cap_slisten(struct socket *so, struct thread *td)
441 struct l2cap_channel *pcb = so->so_pcb;
442 return l2cap_listen(pcb);
446 struct pr_usrreqs l2cap_usrreqs = {
447 .pru_abort = l2cap_sabort,
448 .pru_accept = l2cap_saccept,
449 .pru_attach = l2cap_sattach,
450 .pru_bind = l2cap_sbind,
451 .pru_connect = l2cap_sconnect,
452 .pru_connect2 = pru_connect2_notsupp,
453 .pru_control = l2cap_scontrol,
454 .pru_detach = l2cap_sdetach,
455 .pru_disconnect = l2cap_sdisconnect,
456 .pru_listen = l2cap_slisten,
457 .pru_peeraddr = l2cap_speeraddr,
458 .pru_rcvd = pru_rcvd_notsupp,
459 .pru_rcvoob = pru_rcvoob_notsupp,
460 .pru_send = l2cap_ssend,
461 .pru_sense = pru_sense_null,
462 .pru_shutdown = l2cap_sshutdown,
463 .pru_sockaddr = l2cap_ssockaddr,
464 .pru_sosend = sosend,
465 .pru_soreceive = soreceive