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>
50 #include <sys/msgport2.h>
52 #include <vm/vm_zone.h>
54 #include <netbt/bluetooth.h>
55 #include <netbt/hci.h> /* XXX for EPASSTHROUGH */
56 #include <netbt/l2cap.h>
61 * SOCK_SEQPACKET - normal L2CAP connection
63 * SOCK_DGRAM - connectionless L2CAP - XXX not yet
66 static void l2cap_connecting(void *);
67 static void l2cap_connected(void *);
68 static void l2cap_disconnected(void *, int);
69 static void *l2cap_newconn(void *, struct sockaddr_bt
*, struct sockaddr_bt
*);
70 static void l2cap_complete(void *, int);
71 static void l2cap_linkmode(void *, int);
72 static void l2cap_input(void *, struct mbuf
*);
74 static const struct btproto l2cap_proto
= {
84 /* sysctl variables */
85 int l2cap_sendspace
= 4096;
86 int l2cap_recvspace
= 4096;
89 * l2cap_ctloutput(request, socket, level, optname, opt)
91 * Apply configuration commands to channel. This corresponds to
92 * "Reconfigure Channel Request" in the L2CAP specification.
95 l2cap_ctloutput(netmsg_t msg
)
97 struct socket
*so
= msg
->ctloutput
.base
.nm_so
;
98 struct sockopt
*sopt
= msg
->ctloutput
.nm_sopt
;
99 struct l2cap_channel
*pcb
= (struct l2cap_channel
*) so
->so_pcb
;
103 #ifdef notyet /* XXX */
104 DPRINTFN(2, "%s\n", prcorequests
[req
]);
112 if (sopt
->sopt_level
!= BTPROTO_L2CAP
) {
117 switch(sopt
->sopt_dir
) {
119 m
= m_get(M_NOWAIT
, MT_DATA
);
124 m
->m_len
= l2cap_getopt(pcb
, sopt
->sopt_name
, mtod(m
, void *));
130 soopt_from_kbuf(sopt
, mtod(m
, void *), m
->m_len
);
134 error
= l2cap_setopt2(pcb
, sopt
->sopt_name
, so
, sopt
);
142 lwkt_replymsg(&msg
->ctloutput
.base
.lmsg
, error
);
145 /**********************************************************************
147 * L2CAP Protocol socket callbacks
152 l2cap_connecting(void *arg
)
154 struct socket
*so
= arg
;
156 DPRINTF("Connecting\n");
161 l2cap_connected(void *arg
)
163 struct socket
*so
= arg
;
165 DPRINTF("Connected\n");
170 l2cap_disconnected(void *arg
, int err
)
172 struct socket
*so
= arg
;
174 DPRINTF("Disconnected (%d)\n", err
);
177 soisdisconnected(so
);
181 l2cap_newconn(void *arg
, struct sockaddr_bt
*laddr
,
182 struct sockaddr_bt
*raddr
)
184 struct socket
*so
= arg
;
186 DPRINTF("New Connection\n");
187 so
= sonewconn(so
, 0);
197 l2cap_complete(void *arg
, int count
)
199 struct socket
*so
= arg
;
202 sbdroprecord(&so
->so_snd
.sb
);
208 l2cap_linkmode(void *arg
, int new)
210 struct socket
*so
= arg
;
213 DPRINTF("auth %s, encrypt %s, secure %s\n",
214 (new & L2CAP_LM_AUTH
? "on" : "off"),
215 (new & L2CAP_LM_ENCRYPT
? "on" : "off"),
216 (new & L2CAP_LM_SECURE
? "on" : "off"));
218 (void)l2cap_getopt(so
->so_pcb
, SO_L2CAP_LM
, &mode
);
219 if (((mode
& L2CAP_LM_AUTH
) && !(new & L2CAP_LM_AUTH
))
220 || ((mode
& L2CAP_LM_ENCRYPT
) && !(new & L2CAP_LM_ENCRYPT
))
221 || ((mode
& L2CAP_LM_SECURE
) && !(new & L2CAP_LM_SECURE
)))
222 l2cap_disconnect(so
->so_pcb
, 0);
226 l2cap_input(void *arg
, struct mbuf
*m
)
228 struct socket
*so
= arg
;
230 if (m
->m_pkthdr
.len
> sbspace(&so
->so_rcv
)) {
231 kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
232 __func__
, m
->m_pkthdr
.len
);
237 DPRINTFN(10, "received %d bytes\n", m
->m_pkthdr
.len
);
239 sbappendrecord(&so
->so_rcv
.sb
, m
);
245 * Implementation of usrreqs.
248 l2cap_sdetach(netmsg_t msg
)
250 struct socket
*so
= msg
->detach
.base
.nm_so
;
253 error
= l2cap_detach((struct l2cap_channel
**)&so
->so_pcb
);
254 lwkt_replymsg(&msg
->detach
.base
.lmsg
, error
);
258 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
259 * will sofree() it when we return.
262 l2cap_sabort(netmsg_t msg
)
264 struct socket
*so
= msg
->abort
.base
.nm_so
;
265 struct l2cap_channel
*pcb
= so
->so_pcb
;
267 l2cap_disconnect(pcb
, 0);
268 soisdisconnected(so
);
271 /* msg invalid now */
275 l2cap_sdisconnect(netmsg_t msg
)
277 struct socket
*so
= msg
->disconnect
.base
.nm_so
;
278 struct l2cap_channel
*pcb
= so
->so_pcb
;
281 soisdisconnecting(so
);
283 error
= l2cap_disconnect(pcb
, so
->so_linger
);
284 lwkt_replymsg(&msg
->disconnect
.base
.lmsg
, error
);
288 l2cap_scontrol(netmsg_t msg
)
290 lwkt_replymsg(&msg
->control
.base
.lmsg
, EPASSTHROUGH
);
294 l2cap_sattach(netmsg_t msg
)
296 struct socket
*so
= msg
->attach
.base
.nm_so
;
297 struct l2cap_channel
*pcb
= so
->so_pcb
;
306 * For L2CAP socket PCB we just use an l2cap_channel structure
307 * since we have nothing to add..
309 error
= soreserve(so
, l2cap_sendspace
, l2cap_recvspace
, NULL
);
311 error
= l2cap_attach((struct l2cap_channel
**)&so
->so_pcb
,
315 lwkt_replymsg(&msg
->attach
.base
.lmsg
, error
);
319 l2cap_sbind (netmsg_t msg
)
321 struct socket
*so
= msg
->bind
.base
.nm_so
;
322 struct sockaddr
*nam
= msg
->bind
.nm_nam
;
323 struct l2cap_channel
*pcb
= so
->so_pcb
;
324 struct sockaddr_bt
*sa
;
327 KKASSERT(nam
!= NULL
);
328 sa
= (struct sockaddr_bt
*)nam
;
330 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
)) {
332 } else if (sa
->bt_family
!= AF_BLUETOOTH
) {
333 error
= EAFNOSUPPORT
;
335 error
= l2cap_bind(pcb
, sa
);
337 lwkt_replymsg(&msg
->bind
.base
.lmsg
, error
);
341 l2cap_sconnect(netmsg_t msg
)
343 struct socket
*so
= msg
->connect
.base
.nm_so
;
344 struct sockaddr
*nam
= msg
->connect
.nm_nam
;
345 struct l2cap_channel
*pcb
= so
->so_pcb
;
346 struct sockaddr_bt
*sa
;
349 KKASSERT(nam
!= NULL
);
350 sa
= (struct sockaddr_bt
*)nam
;
352 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
)) {
354 } else if (sa
->bt_family
!= AF_BLUETOOTH
) {
355 error
= EAFNOSUPPORT
;
358 error
= l2cap_connect(pcb
, sa
);
360 lwkt_replymsg(&msg
->connect
.base
.lmsg
, error
);
364 l2cap_speeraddr(netmsg_t msg
)
366 struct socket
*so
= msg
->peeraddr
.base
.nm_so
;
367 struct sockaddr
**nam
= msg
->peeraddr
.nm_nam
;
368 struct l2cap_channel
*pcb
= so
->so_pcb
;
369 struct sockaddr_bt
*sa
, ssa
;
373 bzero(sa
, sizeof *sa
);
374 sa
->bt_len
= sizeof(struct sockaddr_bt
);
375 sa
->bt_family
= AF_BLUETOOTH
;
376 error
= l2cap_peeraddr(pcb
, sa
);
377 *nam
= dup_sockaddr((struct sockaddr
*)sa
);
379 lwkt_replymsg(&msg
->peeraddr
.base
.lmsg
, error
);
383 l2cap_ssockaddr(netmsg_t msg
)
385 struct socket
*so
= msg
->sockaddr
.base
.nm_so
;
386 struct sockaddr
**nam
= msg
->sockaddr
.nm_nam
;
387 struct l2cap_channel
*pcb
= so
->so_pcb
;
388 struct sockaddr_bt
*sa
, ssa
;
392 bzero(sa
, sizeof *sa
);
393 sa
->bt_len
= sizeof(struct sockaddr_bt
);
394 sa
->bt_family
= AF_BLUETOOTH
;
395 error
= l2cap_sockaddr(pcb
, sa
);
396 *nam
= dup_sockaddr((struct sockaddr
*)sa
);
398 lwkt_replymsg(&msg
->sockaddr
.base
.lmsg
, error
);
402 l2cap_sshutdown(netmsg_t msg
)
404 struct socket
*so
= msg
->shutdown
.base
.nm_so
;
408 lwkt_replymsg(&msg
->shutdown
.base
.lmsg
, 0);
412 l2cap_ssend(netmsg_t msg
)
414 struct socket
*so
= msg
->send
.base
.nm_so
;
415 struct mbuf
*m
= msg
->send
.nm_m
;
416 struct mbuf
*control
= msg
->send
.nm_control
;
417 struct l2cap_channel
*pcb
= so
->so_pcb
;
422 if (m
->m_pkthdr
.len
== 0) {
427 if (m
->m_pkthdr
.len
> pcb
->lc_omtu
) {
432 m0
= m_copym(m
, 0, M_COPYALL
, M_NOWAIT
);
438 m0
= m_copym(m
, 0, M_COPYALL
, M_NOWAIT
);
444 /* no use for that */
449 sbappendrecord(&so
->so_snd
.sb
, m
);
450 error
= l2cap_send(pcb
, m0
);
458 lwkt_replymsg(&msg
->send
.base
.lmsg
, error
);
462 l2cap_saccept(netmsg_t msg
)
464 struct socket
*so
= msg
->accept
.base
.nm_so
;
465 struct sockaddr
**nam
= msg
->accept
.nm_nam
;
466 struct l2cap_channel
*pcb
= so
->so_pcb
;
467 struct sockaddr_bt sa
;
470 KKASSERT(nam
!= NULL
);
472 bzero(&sa
, sizeof (sa
) );
473 sa
.bt_len
= sizeof(struct sockaddr_bt
);
474 sa
.bt_family
= AF_BLUETOOTH
;
476 error
= l2cap_peeraddr(pcb
, &sa
);
477 *nam
= dup_sockaddr((struct sockaddr
*)&sa
);
479 lwkt_replymsg(&msg
->accept
.base
.lmsg
, error
);
483 l2cap_slisten(netmsg_t msg
)
485 struct socket
*so
= msg
->listen
.base
.nm_so
;
486 struct l2cap_channel
*pcb
= so
->so_pcb
;
489 error
= l2cap_listen(pcb
);
490 lwkt_replymsg(&msg
->accept
.base
.lmsg
, error
);
494 struct pr_usrreqs l2cap_usrreqs
= {
495 .pru_abort
= l2cap_sabort
,
496 .pru_accept
= l2cap_saccept
,
497 .pru_attach
= l2cap_sattach
,
498 .pru_bind
= l2cap_sbind
,
499 .pru_connect
= l2cap_sconnect
,
500 .pru_connect2
= pr_generic_notsupp
,
501 .pru_control
= l2cap_scontrol
,
502 .pru_detach
= l2cap_sdetach
,
503 .pru_disconnect
= l2cap_sdisconnect
,
504 .pru_listen
= l2cap_slisten
,
505 .pru_peeraddr
= l2cap_speeraddr
,
506 .pru_rcvd
= pr_generic_notsupp
,
507 .pru_rcvoob
= pr_generic_notsupp
,
508 .pru_send
= l2cap_ssend
,
509 .pru_sense
= pru_sense_null
,
510 .pru_shutdown
= l2cap_sshutdown
,
511 .pru_sockaddr
= l2cap_ssockaddr
,
512 .pru_sosend
= sosend
,
513 .pru_soreceive
= soreceive