1 /* $DragonFly: src/sys/netbt/l2cap_socket.c,v 1.2 2008/03/18 13:41:42 hasso Exp $ */
2 /* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
3 /* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
6 * Copyright (c) 2005 Iain Hibbert.
7 * Copyright (c) 2006 Itronix Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of Itronix Inc. may not be used to endorse
19 * or promote products derived from this software without specific
20 * prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
26 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 * ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
37 /* load symbolic names */
38 #ifdef BLUETOOTH_DEBUG
43 #include <sys/param.h>
44 #include <sys/domain.h>
45 #include <sys/kernel.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 #include <sys/socketvar.h>
51 #include <sys/systm.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(struct socket
*so
, struct sockopt
*sopt
)
97 struct l2cap_channel
*pcb
= (struct l2cap_channel
*) so
->so_pcb
;
101 #ifdef notyet /* XXX */
102 DPRINTFN(2, "%s\n", prcorequests
[req
]);
108 if (sopt
->sopt_level
!= BTPROTO_L2CAP
)
111 switch(sopt
->sopt_dir
) {
113 m
= m_get(M_NOWAIT
, MT_DATA
);
118 m
->m_len
= l2cap_getopt(pcb
, sopt
->sopt_name
, mtod(m
, void *));
124 err
= sooptcopyout(sopt
, mtod(m
, void *), m
->m_len
);
128 err
= l2cap_setopt2(pcb
, sopt
->sopt_name
, so
, sopt
);
139 /**********************************************************************
141 * L2CAP Protocol socket callbacks
146 l2cap_connecting(void *arg
)
148 struct socket
*so
= arg
;
150 DPRINTF("Connecting\n");
155 l2cap_connected(void *arg
)
157 struct socket
*so
= arg
;
159 DPRINTF("Connected\n");
164 l2cap_disconnected(void *arg
, int err
)
166 struct socket
*so
= arg
;
168 DPRINTF("Disconnected (%d)\n", err
);
171 soisdisconnected(so
);
175 l2cap_newconn(void *arg
, struct sockaddr_bt
*laddr
,
176 struct sockaddr_bt
*raddr
)
178 struct socket
*so
= arg
;
180 DPRINTF("New Connection\n");
181 so
= sonewconn(so
, 0);
191 l2cap_complete(void *arg
, int count
)
193 struct socket
*so
= arg
;
196 sbdroprecord(&so
->so_snd
.sb
);
202 l2cap_linkmode(void *arg
, int new)
204 struct socket
*so
= arg
;
207 DPRINTF("auth %s, encrypt %s, secure %s\n",
208 (new & L2CAP_LM_AUTH
? "on" : "off"),
209 (new & L2CAP_LM_ENCRYPT
? "on" : "off"),
210 (new & L2CAP_LM_SECURE
? "on" : "off"));
212 (void)l2cap_getopt(so
->so_pcb
, SO_L2CAP_LM
, &mode
);
213 if (((mode
& L2CAP_LM_AUTH
) && !(new & L2CAP_LM_AUTH
))
214 || ((mode
& L2CAP_LM_ENCRYPT
) && !(new & L2CAP_LM_ENCRYPT
))
215 || ((mode
& L2CAP_LM_SECURE
) && !(new & L2CAP_LM_SECURE
)))
216 l2cap_disconnect(so
->so_pcb
, 0);
220 l2cap_input(void *arg
, struct mbuf
*m
)
222 struct socket
*so
= arg
;
224 if (m
->m_pkthdr
.len
> sbspace(&so
->so_rcv
)) {
225 kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
226 __func__
, m
->m_pkthdr
.len
);
231 DPRINTFN(10, "received %d bytes\n", m
->m_pkthdr
.len
);
233 sbappendrecord(&so
->so_rcv
.sb
, m
);
239 * Implementation of usrreqs.
242 l2cap_sdetach(struct socket
*so
)
244 return l2cap_detach((struct l2cap_channel
**)&so
->so_pcb
);
248 l2cap_sabort (struct socket
*so
)
250 struct l2cap_channel
*pcb
= so
->so_pcb
;
252 l2cap_disconnect(pcb
, 0);
253 soisdisconnected(so
);
255 return l2cap_sdetach(so
);
259 l2cap_sdisconnect (struct socket
*so
)
261 struct l2cap_channel
*pcb
= so
->so_pcb
;
263 soisdisconnecting(so
);
265 return l2cap_disconnect(pcb
, so
->so_linger
);
269 l2cap_scontrol (struct socket
*so
, u_long cmd
, caddr_t data
,
270 struct ifnet
*ifp
, struct thread
*td
)
276 l2cap_sattach (struct socket
*so
, int proto
,
277 struct pru_attach_info
*ai
)
279 struct l2cap_channel
*pcb
= so
->so_pcb
;
286 * For L2CAP socket PCB we just use an l2cap_channel structure
287 * since we have nothing to add..
289 err
= soreserve(so
, l2cap_sendspace
, l2cap_recvspace
, NULL
);
293 return l2cap_attach((struct l2cap_channel
**)&so
->so_pcb
,
298 l2cap_sbind (struct socket
*so
, struct sockaddr
*nam
,
301 struct l2cap_channel
*pcb
= so
->so_pcb
;
302 struct sockaddr_bt
*sa
;
304 KKASSERT(nam
!= NULL
);
305 sa
= (struct sockaddr_bt
*)nam
;
307 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
))
310 if (sa
->bt_family
!= AF_BLUETOOTH
)
313 return l2cap_bind(pcb
, sa
);
317 l2cap_sconnect (struct socket
*so
, struct sockaddr
*nam
,
320 struct l2cap_channel
*pcb
= so
->so_pcb
;
321 struct sockaddr_bt
*sa
;
323 KKASSERT(nam
!= NULL
);
324 sa
= (struct sockaddr_bt
*)nam
;
326 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
))
329 if (sa
->bt_family
!= AF_BLUETOOTH
)
333 return l2cap_connect(pcb
, sa
);
337 l2cap_speeraddr (struct socket
*so
, struct sockaddr
**nam
)
339 struct l2cap_channel
*pcb
= so
->so_pcb
;
340 struct sockaddr_bt
*sa
, ssa
;
344 bzero(sa
, sizeof *sa
);
345 sa
->bt_len
= sizeof(struct sockaddr_bt
);
346 sa
->bt_family
= AF_BLUETOOTH
;
347 e
= l2cap_peeraddr(pcb
, sa
);
348 *nam
= dup_sockaddr((struct sockaddr
*)sa
);
354 l2cap_ssockaddr (struct socket
*so
, struct sockaddr
**nam
)
356 struct l2cap_channel
*pcb
= so
->so_pcb
;
357 struct sockaddr_bt
*sa
, ssa
;
361 bzero(sa
, sizeof *sa
);
362 sa
->bt_len
= sizeof(struct sockaddr_bt
);
363 sa
->bt_family
= AF_BLUETOOTH
;
364 e
= l2cap_sockaddr(pcb
, sa
);
365 *nam
= dup_sockaddr((struct sockaddr
*)sa
);
371 l2cap_sshutdown (struct socket
*so
)
378 l2cap_ssend (struct socket
*so
, int flags
, struct mbuf
*m
,
379 struct sockaddr
*addr
, struct mbuf
*control
, struct thread
*td
)
381 struct l2cap_channel
*pcb
= so
->so_pcb
;
387 if (m
->m_pkthdr
.len
== 0)
390 if (m
->m_pkthdr
.len
> pcb
->lc_omtu
) {
395 m0
= m_copym(m
, 0, M_COPYALL
, MB_DONTWAIT
);
401 if (control
) /* no use for that */
404 sbappendrecord(&so
->so_snd
.sb
, m
);
405 return l2cap_send(pcb
, m0
);
417 l2cap_saccept(struct socket
*so
, struct sockaddr
**nam
)
419 struct l2cap_channel
*pcb
= so
->so_pcb
;
420 struct sockaddr_bt sa
;
423 KKASSERT(nam
!= NULL
);
425 bzero(&sa
, sizeof (sa
) );
426 sa
.bt_len
= sizeof(struct sockaddr_bt
);
427 sa
.bt_family
= AF_BLUETOOTH
;
429 e
= l2cap_peeraddr(pcb
, &sa
);
430 *nam
= dup_sockaddr((struct sockaddr
*)&sa
);
436 l2cap_slisten(struct socket
*so
, struct thread
*td
)
438 struct l2cap_channel
*pcb
= so
->so_pcb
;
439 return l2cap_listen(pcb
);
443 struct pr_usrreqs l2cap_usrreqs
= {
444 .pru_abort
= l2cap_sabort
,
445 .pru_accept
= l2cap_saccept
,
446 .pru_attach
= l2cap_sattach
,
447 .pru_bind
= l2cap_sbind
,
448 .pru_connect
= l2cap_sconnect
,
449 .pru_connect2
= pru_connect2_notsupp
,
450 .pru_control
= l2cap_scontrol
,
451 .pru_detach
= l2cap_sdetach
,
452 .pru_disconnect
= l2cap_sdisconnect
,
453 .pru_listen
= l2cap_slisten
,
454 .pru_peeraddr
= l2cap_speeraddr
,
455 .pru_rcvd
= pru_rcvd_notsupp
,
456 .pru_rcvoob
= pru_rcvoob_notsupp
,
457 .pru_send
= l2cap_ssend
,
458 .pru_sense
= pru_sense_null
,
459 .pru_shutdown
= l2cap_sshutdown
,
460 .pru_sockaddr
= l2cap_ssockaddr
,
461 .pru_sosend
= sosend
,
462 .pru_soreceive
= soreceive
,