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 l2cap_sabort (struct socket
*so
)
247 struct l2cap_channel
*pcb
= so
->so_pcb
;
249 l2cap_disconnect(pcb
, 0);
250 soisdisconnected(so
);
252 return l2cap_sdetach(so
);
256 l2cap_sdisconnect (struct socket
*so
)
258 struct l2cap_channel
*pcb
= so
->so_pcb
;
260 soisdisconnecting(so
);
262 return l2cap_disconnect(pcb
, so
->so_linger
);
266 l2cap_scontrol (struct socket
*so
, u_long cmd
, caddr_t data
,
267 struct ifnet
*ifp
, struct thread
*td
)
273 l2cap_sattach (struct socket
*so
, int proto
,
274 struct pru_attach_info
*ai
)
276 struct l2cap_channel
*pcb
= so
->so_pcb
;
283 * For L2CAP socket PCB we just use an l2cap_channel structure
284 * since we have nothing to add..
286 err
= soreserve(so
, l2cap_sendspace
, l2cap_recvspace
, NULL
);
290 return l2cap_attach((struct l2cap_channel
**)&so
->so_pcb
,
295 l2cap_sbind (struct socket
*so
, struct sockaddr
*nam
,
298 struct l2cap_channel
*pcb
= so
->so_pcb
;
299 struct sockaddr_bt
*sa
;
301 KKASSERT(nam
!= NULL
);
302 sa
= (struct sockaddr_bt
*)nam
;
304 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
))
307 if (sa
->bt_family
!= AF_BLUETOOTH
)
310 return l2cap_bind(pcb
, sa
);
314 l2cap_sconnect (struct socket
*so
, struct sockaddr
*nam
,
317 struct l2cap_channel
*pcb
= so
->so_pcb
;
318 struct sockaddr_bt
*sa
;
320 KKASSERT(nam
!= NULL
);
321 sa
= (struct sockaddr_bt
*)nam
;
323 if (sa
->bt_len
!= sizeof(struct sockaddr_bt
))
326 if (sa
->bt_family
!= AF_BLUETOOTH
)
330 return l2cap_connect(pcb
, sa
);
334 l2cap_speeraddr (struct socket
*so
, struct sockaddr
**nam
)
336 struct l2cap_channel
*pcb
= so
->so_pcb
;
337 struct sockaddr_bt
*sa
, ssa
;
341 bzero(sa
, sizeof *sa
);
342 sa
->bt_len
= sizeof(struct sockaddr_bt
);
343 sa
->bt_family
= AF_BLUETOOTH
;
344 e
= l2cap_peeraddr(pcb
, sa
);
345 *nam
= dup_sockaddr((struct sockaddr
*)sa
);
351 l2cap_ssockaddr (struct socket
*so
, struct sockaddr
**nam
)
353 struct l2cap_channel
*pcb
= so
->so_pcb
;
354 struct sockaddr_bt
*sa
, ssa
;
358 bzero(sa
, sizeof *sa
);
359 sa
->bt_len
= sizeof(struct sockaddr_bt
);
360 sa
->bt_family
= AF_BLUETOOTH
;
361 e
= l2cap_sockaddr(pcb
, sa
);
362 *nam
= dup_sockaddr((struct sockaddr
*)sa
);
368 l2cap_sshutdown (struct socket
*so
)
375 l2cap_ssend (struct socket
*so
, int flags
, struct mbuf
*m
,
376 struct sockaddr
*addr
, struct mbuf
*control
, struct thread
*td
)
378 struct l2cap_channel
*pcb
= so
->so_pcb
;
384 if (m
->m_pkthdr
.len
== 0)
387 if (m
->m_pkthdr
.len
> pcb
->lc_omtu
) {
392 m0
= m_copym(m
, 0, M_COPYALL
, MB_DONTWAIT
);
398 if (control
) /* no use for that */
401 sbappendrecord(&so
->so_snd
.sb
, m
);
402 return l2cap_send(pcb
, m0
);
414 l2cap_saccept(struct socket
*so
, struct sockaddr
**nam
)
416 struct l2cap_channel
*pcb
= so
->so_pcb
;
417 struct sockaddr_bt sa
;
420 KKASSERT(nam
!= NULL
);
422 bzero(&sa
, sizeof (sa
) );
423 sa
.bt_len
= sizeof(struct sockaddr_bt
);
424 sa
.bt_family
= AF_BLUETOOTH
;
426 e
= l2cap_peeraddr(pcb
, &sa
);
427 *nam
= dup_sockaddr((struct sockaddr
*)&sa
);
433 l2cap_slisten(struct socket
*so
, struct thread
*td
)
435 struct l2cap_channel
*pcb
= so
->so_pcb
;
436 return l2cap_listen(pcb
);
440 struct pr_usrreqs l2cap_usrreqs
= {
441 .pru_abort
= l2cap_sabort
,
442 .pru_accept
= l2cap_saccept
,
443 .pru_attach
= l2cap_sattach
,
444 .pru_bind
= l2cap_sbind
,
445 .pru_connect
= l2cap_sconnect
,
446 .pru_connect2
= pru_connect2_notsupp
,
447 .pru_control
= l2cap_scontrol
,
448 .pru_detach
= l2cap_sdetach
,
449 .pru_disconnect
= l2cap_sdisconnect
,
450 .pru_listen
= l2cap_slisten
,
451 .pru_peeraddr
= l2cap_speeraddr
,
452 .pru_rcvd
= pru_rcvd_notsupp
,
453 .pru_rcvoob
= pru_rcvoob_notsupp
,
454 .pru_send
= l2cap_ssend
,
455 .pru_sense
= pru_sense_null
,
456 .pru_shutdown
= l2cap_sshutdown
,
457 .pru_sockaddr
= l2cap_ssockaddr
,
458 .pru_sosend
= sosend
,
459 .pru_soreceive
= soreceive
,