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>
43 #include <sys/malloc.h> /* for M_NOWAIT */
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/systm.h>
51 #include <sys/msgport2.h>
53 #include <vm/vm_zone.h>
55 #include <netbt/bluetooth.h>
56 #include <netbt/hci.h> /* XXX for EPASSTHROUGH */
57 #include <netbt/l2cap.h>
62 * SOCK_SEQPACKET - normal L2CAP connection
64 * SOCK_DGRAM - connectionless L2CAP - XXX not yet
67 static void l2cap_connecting(void *);
68 static void l2cap_connected(void *);
69 static void l2cap_disconnected(void *, int);
70 static void *l2cap_newconn(void *, struct sockaddr_bt
*, struct sockaddr_bt
*);
71 static void l2cap_complete(void *, int);
72 static void l2cap_linkmode(void *, int);
73 static void l2cap_input(void *, struct mbuf
*);
75 static const struct btproto l2cap_proto
= {
85 /* sysctl variables */
86 int l2cap_sendspace
= 4096;
87 int l2cap_recvspace
= 4096;
90 * l2cap_ctloutput(request, socket, level, optname, opt)
92 * Apply configuration commands to channel. This corresponds to
93 * "Reconfigure Channel Request" in the L2CAP specification.
96 l2cap_ctloutput(netmsg_t msg
)
98 struct socket
*so
= msg
->ctloutput
.base
.nm_so
;
99 struct sockopt
*sopt
= msg
->ctloutput
.nm_sopt
;
100 struct l2cap_channel
*pcb
= (struct l2cap_channel
*) so
->so_pcb
;
104 #ifdef notyet /* XXX */
105 DPRINTFN(2, "%s\n", prcorequests
[req
]);
113 if (sopt
->sopt_level
!= BTPROTO_L2CAP
) {
118 switch(sopt
->sopt_dir
) {
120 m
= m_get(M_NOWAIT
, MT_DATA
);
125 m
->m_len
= l2cap_getopt(pcb
, sopt
->sopt_name
, mtod(m
, void *));
131 soopt_from_kbuf(sopt
, mtod(m
, void *), m
->m_len
);
135 error
= l2cap_setopt2(pcb
, sopt
->sopt_name
, so
, sopt
);
143 lwkt_replymsg(&msg
->ctloutput
.base
.lmsg
, error
);
146 /**********************************************************************
148 * L2CAP Protocol socket callbacks
153 l2cap_connecting(void *arg
)
155 struct socket
*so
= arg
;
157 DPRINTF("Connecting\n");
162 l2cap_connected(void *arg
)
164 struct socket
*so
= arg
;
166 DPRINTF("Connected\n");
171 l2cap_disconnected(void *arg
, int err
)
173 struct socket
*so
= arg
;
175 DPRINTF("Disconnected (%d)\n", err
);
178 soisdisconnected(so
);
182 l2cap_newconn(void *arg
, struct sockaddr_bt
*laddr
,
183 struct sockaddr_bt
*raddr
)
185 struct socket
*so
= arg
;
187 DPRINTF("New Connection\n");
188 so
= sonewconn(so
, 0);
198 l2cap_complete(void *arg
, int count
)
200 struct socket
*so
= arg
;
203 sbdroprecord(&so
->so_snd
.sb
);
209 l2cap_linkmode(void *arg
, int new)
211 struct socket
*so
= arg
;
214 DPRINTF("auth %s, encrypt %s, secure %s\n",
215 (new & L2CAP_LM_AUTH
? "on" : "off"),
216 (new & L2CAP_LM_ENCRYPT
? "on" : "off"),
217 (new & L2CAP_LM_SECURE
? "on" : "off"));
219 (void)l2cap_getopt(so
->so_pcb
, SO_L2CAP_LM
, &mode
);
220 if (((mode
& L2CAP_LM_AUTH
) && !(new & L2CAP_LM_AUTH
))
221 || ((mode
& L2CAP_LM_ENCRYPT
) && !(new & L2CAP_LM_ENCRYPT
))
222 || ((mode
& L2CAP_LM_SECURE
) && !(new & L2CAP_LM_SECURE
)))
223 l2cap_disconnect(so
->so_pcb
, 0);
227 l2cap_input(void *arg
, struct mbuf
*m
)
229 struct socket
*so
= arg
;
231 if (m
->m_pkthdr
.len
> sbspace(&so
->so_rcv
)) {
232 kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
233 __func__
, m
->m_pkthdr
.len
);
238 DPRINTFN(10, "received %d bytes\n", m
->m_pkthdr
.len
);
240 sbappendrecord(&so
->so_rcv
.sb
, m
);
246 * Implementation of usrreqs.
249 l2cap_sdetach(netmsg_t msg
)
251 struct socket
*so
= msg
->detach
.base
.nm_so
;
254 error
= l2cap_detach((struct l2cap_channel
**)&so
->so_pcb
);
255 lwkt_replymsg(&msg
->detach
.base
.lmsg
, error
);
259 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
260 * will sofree() it when we return.
263 l2cap_sabort(netmsg_t msg
)
265 struct socket
*so
= msg
->abort
.base
.nm_so
;
266 struct l2cap_channel
*pcb
= so
->so_pcb
;
268 l2cap_disconnect(pcb
, 0);
269 soisdisconnected(so
);
272 /* msg invalid now */
276 l2cap_sdisconnect(netmsg_t msg
)
278 struct socket
*so
= msg
->disconnect
.base
.nm_so
;
279 struct l2cap_channel
*pcb
= so
->so_pcb
;
282 soisdisconnecting(so
);
284 error
= l2cap_disconnect(pcb
, so
->so_linger
);
285 lwkt_replymsg(&msg
->disconnect
.base
.lmsg
, error
);
289 l2cap_scontrol(netmsg_t msg
)
291 lwkt_replymsg(&msg
->control
.base
.lmsg
, EPASSTHROUGH
);
295 l2cap_sattach(netmsg_t msg
)
297 struct socket
*so
= msg
->attach
.base
.nm_so
;
298 struct l2cap_channel
*pcb
= so
->so_pcb
;
307 * For L2CAP socket PCB we just use an l2cap_channel structure
308 * since we have nothing to add..
310 error
= soreserve(so
, l2cap_sendspace
, l2cap_recvspace
, NULL
);
312 error
= l2cap_attach((struct l2cap_channel
**)&so
->so_pcb
,
316 lwkt_replymsg(&msg
->attach
.base
.lmsg
, error
);
320 l2cap_sbind (netmsg_t msg
)
322 struct socket
*so
= msg
->bind
.base
.nm_so
;
323 struct sockaddr
*nam
= msg
->bind
.nm_nam
;
324 struct l2cap_channel
*pcb
= so
->so_pcb
;
325 struct sockaddr_bt
*sa
;
328 KKASSERT(nam
!= NULL
);
329 sa
= (struct sockaddr_bt
*)nam
;
331 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
)) {
333 } else if (sa
->bt_family
!= AF_BLUETOOTH
) {
334 error
= EAFNOSUPPORT
;
336 error
= l2cap_bind(pcb
, sa
);
338 lwkt_replymsg(&msg
->bind
.base
.lmsg
, error
);
342 l2cap_sconnect(netmsg_t msg
)
344 struct socket
*so
= msg
->connect
.base
.nm_so
;
345 struct sockaddr
*nam
= msg
->connect
.nm_nam
;
346 struct l2cap_channel
*pcb
= so
->so_pcb
;
347 struct sockaddr_bt
*sa
;
350 KKASSERT(nam
!= NULL
);
351 sa
= (struct sockaddr_bt
*)nam
;
353 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
)) {
355 } else if (sa
->bt_family
!= AF_BLUETOOTH
) {
356 error
= EAFNOSUPPORT
;
359 error
= l2cap_connect(pcb
, sa
);
361 lwkt_replymsg(&msg
->connect
.base
.lmsg
, error
);
365 l2cap_speeraddr(netmsg_t msg
)
367 struct socket
*so
= msg
->peeraddr
.base
.nm_so
;
368 struct sockaddr
**nam
= msg
->peeraddr
.nm_nam
;
369 struct l2cap_channel
*pcb
= so
->so_pcb
;
370 struct sockaddr_bt
*sa
, ssa
;
374 bzero(sa
, sizeof *sa
);
375 sa
->bt_len
= sizeof(struct sockaddr_bt
);
376 sa
->bt_family
= AF_BLUETOOTH
;
377 error
= l2cap_peeraddr(pcb
, sa
);
378 *nam
= dup_sockaddr((struct sockaddr
*)sa
);
380 lwkt_replymsg(&msg
->peeraddr
.base
.lmsg
, error
);
384 l2cap_ssockaddr(netmsg_t msg
)
386 struct socket
*so
= msg
->sockaddr
.base
.nm_so
;
387 struct sockaddr
**nam
= msg
->sockaddr
.nm_nam
;
388 struct l2cap_channel
*pcb
= so
->so_pcb
;
389 struct sockaddr_bt
*sa
, ssa
;
393 bzero(sa
, sizeof *sa
);
394 sa
->bt_len
= sizeof(struct sockaddr_bt
);
395 sa
->bt_family
= AF_BLUETOOTH
;
396 error
= l2cap_sockaddr(pcb
, sa
);
397 *nam
= dup_sockaddr((struct sockaddr
*)sa
);
399 lwkt_replymsg(&msg
->sockaddr
.base
.lmsg
, error
);
403 l2cap_sshutdown(netmsg_t msg
)
405 struct socket
*so
= msg
->shutdown
.base
.nm_so
;
409 lwkt_replymsg(&msg
->shutdown
.base
.lmsg
, 0);
413 l2cap_ssend(netmsg_t msg
)
415 struct socket
*so
= msg
->send
.base
.nm_so
;
416 struct mbuf
*m
= msg
->send
.nm_m
;
417 struct mbuf
*control
= msg
->send
.nm_control
;
418 struct l2cap_channel
*pcb
= so
->so_pcb
;
423 if (m
->m_pkthdr
.len
== 0) {
428 if (m
->m_pkthdr
.len
> pcb
->lc_omtu
) {
433 m0
= m_copym(m
, 0, M_COPYALL
, M_NOWAIT
);
439 m0
= m_copym(m
, 0, M_COPYALL
, M_NOWAIT
);
445 /* no use for that */
450 sbappendrecord(&so
->so_snd
.sb
, m
);
451 error
= l2cap_send(pcb
, m0
);
459 lwkt_replymsg(&msg
->send
.base
.lmsg
, error
);
463 l2cap_saccept(netmsg_t msg
)
465 struct socket
*so
= msg
->accept
.base
.nm_so
;
466 struct sockaddr
**nam
= msg
->accept
.nm_nam
;
467 struct l2cap_channel
*pcb
= so
->so_pcb
;
468 struct sockaddr_bt sa
;
471 KKASSERT(nam
!= NULL
);
473 bzero(&sa
, sizeof (sa
) );
474 sa
.bt_len
= sizeof(struct sockaddr_bt
);
475 sa
.bt_family
= AF_BLUETOOTH
;
477 error
= l2cap_peeraddr(pcb
, &sa
);
478 *nam
= dup_sockaddr((struct sockaddr
*)&sa
);
480 lwkt_replymsg(&msg
->accept
.base
.lmsg
, error
);
484 l2cap_slisten(netmsg_t msg
)
486 struct socket
*so
= msg
->listen
.base
.nm_so
;
487 struct l2cap_channel
*pcb
= so
->so_pcb
;
490 error
= l2cap_listen(pcb
);
491 lwkt_replymsg(&msg
->accept
.base
.lmsg
, error
);
495 struct pr_usrreqs l2cap_usrreqs
= {
496 .pru_abort
= l2cap_sabort
,
497 .pru_accept
= l2cap_saccept
,
498 .pru_attach
= l2cap_sattach
,
499 .pru_bind
= l2cap_sbind
,
500 .pru_connect
= l2cap_sconnect
,
501 .pru_connect2
= pr_generic_notsupp
,
502 .pru_control
= l2cap_scontrol
,
503 .pru_detach
= l2cap_sdetach
,
504 .pru_disconnect
= l2cap_sdisconnect
,
505 .pru_listen
= l2cap_slisten
,
506 .pru_peeraddr
= l2cap_speeraddr
,
507 .pru_rcvd
= pr_generic_notsupp
,
508 .pru_rcvoob
= pr_generic_notsupp
,
509 .pru_send
= l2cap_ssend
,
510 .pru_sense
= pru_sense_null
,
511 .pru_shutdown
= l2cap_sshutdown
,
512 .pru_sockaddr
= l2cap_ssockaddr
,
513 .pru_sosend
= sosend
,
514 .pru_soreceive
= soreceive