10a9108ebSHasso Tepper /* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
20a9108ebSHasso Tepper /* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
30a9108ebSHasso Tepper
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper * Copyright (c) 2005 Iain Hibbert.
60a9108ebSHasso Tepper * Copyright (c) 2006 Itronix Inc.
70a9108ebSHasso Tepper * All rights reserved.
80a9108ebSHasso Tepper *
90a9108ebSHasso Tepper * Redistribution and use in source and binary forms, with or without
100a9108ebSHasso Tepper * modification, are permitted provided that the following conditions
110a9108ebSHasso Tepper * are met:
120a9108ebSHasso Tepper * 1. Redistributions of source code must retain the above copyright
130a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer.
140a9108ebSHasso Tepper * 2. Redistributions in binary form must reproduce the above copyright
150a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer in the
160a9108ebSHasso Tepper * documentation and/or other materials provided with the distribution.
170a9108ebSHasso Tepper * 3. The name of Itronix Inc. may not be used to endorse
180a9108ebSHasso Tepper * or promote products derived from this software without specific
190a9108ebSHasso Tepper * prior written permission.
200a9108ebSHasso Tepper *
210a9108ebSHasso Tepper * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
220a9108ebSHasso Tepper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
230a9108ebSHasso Tepper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
240a9108ebSHasso Tepper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
250a9108ebSHasso Tepper * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
260a9108ebSHasso Tepper * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
270a9108ebSHasso Tepper * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
280a9108ebSHasso Tepper * ON ANY THEORY OF LIABILITY, WHETHER IN
290a9108ebSHasso Tepper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300a9108ebSHasso Tepper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
310a9108ebSHasso Tepper * POSSIBILITY OF SUCH DAMAGE.
320a9108ebSHasso Tepper */
330a9108ebSHasso Tepper
340a9108ebSHasso Tepper /* load symbolic names */
350a9108ebSHasso Tepper #ifdef BLUETOOTH_DEBUG
360a9108ebSHasso Tepper #define PRUREQUESTS
370a9108ebSHasso Tepper #define PRCOREQUESTS
380a9108ebSHasso Tepper #endif
390a9108ebSHasso Tepper
400a9108ebSHasso Tepper #include <sys/param.h>
410a9108ebSHasso Tepper #include <sys/domain.h>
420a9108ebSHasso Tepper #include <sys/kernel.h>
43*c443c74fSzrj #include <sys/malloc.h> /* for M_NOWAIT */
440a9108ebSHasso Tepper #include <sys/mbuf.h>
450a9108ebSHasso Tepper #include <sys/proc.h>
460a9108ebSHasso Tepper #include <sys/protosw.h>
470a9108ebSHasso Tepper #include <sys/socket.h>
480a9108ebSHasso Tepper #include <sys/socketvar.h>
490a9108ebSHasso Tepper #include <sys/systm.h>
50002c1265SMatthew Dillon
51002c1265SMatthew Dillon #include <sys/msgport2.h>
52002c1265SMatthew Dillon
530a9108ebSHasso Tepper #include <vm/vm_zone.h>
540a9108ebSHasso Tepper
550a9108ebSHasso Tepper #include <netbt/bluetooth.h>
560a9108ebSHasso Tepper #include <netbt/hci.h> /* XXX for EPASSTHROUGH */
570a9108ebSHasso Tepper #include <netbt/l2cap.h>
580a9108ebSHasso Tepper
590a9108ebSHasso Tepper /*
600a9108ebSHasso Tepper * L2CAP Sockets
610a9108ebSHasso Tepper *
620a9108ebSHasso Tepper * SOCK_SEQPACKET - normal L2CAP connection
630a9108ebSHasso Tepper *
640a9108ebSHasso Tepper * SOCK_DGRAM - connectionless L2CAP - XXX not yet
650a9108ebSHasso Tepper */
660a9108ebSHasso Tepper
670a9108ebSHasso Tepper static void l2cap_connecting(void *);
680a9108ebSHasso Tepper static void l2cap_connected(void *);
690a9108ebSHasso Tepper static void l2cap_disconnected(void *, int);
700a9108ebSHasso Tepper static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
710a9108ebSHasso Tepper static void l2cap_complete(void *, int);
720a9108ebSHasso Tepper static void l2cap_linkmode(void *, int);
730a9108ebSHasso Tepper static void l2cap_input(void *, struct mbuf *);
740a9108ebSHasso Tepper
750a9108ebSHasso Tepper static const struct btproto l2cap_proto = {
760a9108ebSHasso Tepper l2cap_connecting,
770a9108ebSHasso Tepper l2cap_connected,
780a9108ebSHasso Tepper l2cap_disconnected,
790a9108ebSHasso Tepper l2cap_newconn,
800a9108ebSHasso Tepper l2cap_complete,
810a9108ebSHasso Tepper l2cap_linkmode,
820a9108ebSHasso Tepper l2cap_input,
830a9108ebSHasso Tepper };
840a9108ebSHasso Tepper
850a9108ebSHasso Tepper /* sysctl variables */
860a9108ebSHasso Tepper int l2cap_sendspace = 4096;
870a9108ebSHasso Tepper int l2cap_recvspace = 4096;
880a9108ebSHasso Tepper
890a9108ebSHasso Tepper /*
900a9108ebSHasso Tepper * l2cap_ctloutput(request, socket, level, optname, opt)
910a9108ebSHasso Tepper *
920a9108ebSHasso Tepper * Apply configuration commands to channel. This corresponds to
930a9108ebSHasso Tepper * "Reconfigure Channel Request" in the L2CAP specification.
940a9108ebSHasso Tepper */
95002c1265SMatthew Dillon void
l2cap_ctloutput(netmsg_t msg)96002c1265SMatthew Dillon l2cap_ctloutput(netmsg_t msg)
970a9108ebSHasso Tepper {
98002c1265SMatthew Dillon struct socket *so = msg->ctloutput.base.nm_so;
99002c1265SMatthew Dillon struct sockopt *sopt = msg->ctloutput.nm_sopt;
1000a9108ebSHasso Tepper struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb;
1010a9108ebSHasso Tepper struct mbuf *m;
102002c1265SMatthew Dillon int error = 0;
1030a9108ebSHasso Tepper
1040a9108ebSHasso Tepper #ifdef notyet /* XXX */
1050a9108ebSHasso Tepper DPRINTFN(2, "%s\n", prcorequests[req]);
1060a9108ebSHasso Tepper #endif
1070a9108ebSHasso Tepper
108002c1265SMatthew Dillon if (pcb == NULL) {
109002c1265SMatthew Dillon error = EINVAL;
110002c1265SMatthew Dillon goto out;
111002c1265SMatthew Dillon }
1120a9108ebSHasso Tepper
113002c1265SMatthew Dillon if (sopt->sopt_level != BTPROTO_L2CAP) {
114002c1265SMatthew Dillon error = ENOPROTOOPT;
115002c1265SMatthew Dillon goto out;
116002c1265SMatthew Dillon }
1170a9108ebSHasso Tepper
1180a9108ebSHasso Tepper switch(sopt->sopt_dir) {
1190a9108ebSHasso Tepper case PRCO_GETOPT:
120b5523eacSSascha Wildner m = m_get(M_NOWAIT, MT_DATA);
1210a9108ebSHasso Tepper if (m == NULL) {
122002c1265SMatthew Dillon error = ENOMEM;
1230a9108ebSHasso Tepper break;
1240a9108ebSHasso Tepper }
1250a9108ebSHasso Tepper m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *));
1260a9108ebSHasso Tepper if (m->m_len == 0) {
1270a9108ebSHasso Tepper m_freem(m);
1280a9108ebSHasso Tepper m = NULL;
129002c1265SMatthew Dillon error = ENOPROTOOPT;
1300a9108ebSHasso Tepper }
131d82b71f8SAggelos Economopoulos soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
1320a9108ebSHasso Tepper break;
1330a9108ebSHasso Tepper
1340a9108ebSHasso Tepper case PRCO_SETOPT:
135002c1265SMatthew Dillon error = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt);
1360a9108ebSHasso Tepper break;
1370a9108ebSHasso Tepper
1380a9108ebSHasso Tepper default:
139002c1265SMatthew Dillon error = ENOPROTOOPT;
1400a9108ebSHasso Tepper break;
1410a9108ebSHasso Tepper }
142002c1265SMatthew Dillon out:
143002c1265SMatthew Dillon lwkt_replymsg(&msg->ctloutput.base.lmsg, error);
1440a9108ebSHasso Tepper }
1450a9108ebSHasso Tepper
1460a9108ebSHasso Tepper /**********************************************************************
1470a9108ebSHasso Tepper *
1480a9108ebSHasso Tepper * L2CAP Protocol socket callbacks
1490a9108ebSHasso Tepper *
1500a9108ebSHasso Tepper */
1510a9108ebSHasso Tepper
1520a9108ebSHasso Tepper static void
l2cap_connecting(void * arg)1530a9108ebSHasso Tepper l2cap_connecting(void *arg)
1540a9108ebSHasso Tepper {
1550a9108ebSHasso Tepper struct socket *so = arg;
1560a9108ebSHasso Tepper
1570a9108ebSHasso Tepper DPRINTF("Connecting\n");
1580a9108ebSHasso Tepper soisconnecting(so);
1590a9108ebSHasso Tepper }
1600a9108ebSHasso Tepper
1610a9108ebSHasso Tepper static void
l2cap_connected(void * arg)1620a9108ebSHasso Tepper l2cap_connected(void *arg)
1630a9108ebSHasso Tepper {
1640a9108ebSHasso Tepper struct socket *so = arg;
1650a9108ebSHasso Tepper
1660a9108ebSHasso Tepper DPRINTF("Connected\n");
1670a9108ebSHasso Tepper soisconnected(so);
1680a9108ebSHasso Tepper }
1690a9108ebSHasso Tepper
1700a9108ebSHasso Tepper static void
l2cap_disconnected(void * arg,int err)1710a9108ebSHasso Tepper l2cap_disconnected(void *arg, int err)
1720a9108ebSHasso Tepper {
1730a9108ebSHasso Tepper struct socket *so = arg;
1740a9108ebSHasso Tepper
1750a9108ebSHasso Tepper DPRINTF("Disconnected (%d)\n", err);
1760a9108ebSHasso Tepper
1770a9108ebSHasso Tepper so->so_error = err;
1780a9108ebSHasso Tepper soisdisconnected(so);
1790a9108ebSHasso Tepper }
1800a9108ebSHasso Tepper
1810a9108ebSHasso Tepper static void *
l2cap_newconn(void * arg,struct sockaddr_bt * laddr,struct sockaddr_bt * raddr)1820a9108ebSHasso Tepper l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
1830a9108ebSHasso Tepper struct sockaddr_bt *raddr)
1840a9108ebSHasso Tepper {
1850a9108ebSHasso Tepper struct socket *so = arg;
1860a9108ebSHasso Tepper
1870a9108ebSHasso Tepper DPRINTF("New Connection\n");
1880a9108ebSHasso Tepper so = sonewconn(so, 0);
1890a9108ebSHasso Tepper if (so == NULL)
1900a9108ebSHasso Tepper return NULL;
1910a9108ebSHasso Tepper
1920a9108ebSHasso Tepper soisconnecting(so);
1930a9108ebSHasso Tepper
1940a9108ebSHasso Tepper return so->so_pcb;
1950a9108ebSHasso Tepper }
1960a9108ebSHasso Tepper
1970a9108ebSHasso Tepper static void
l2cap_complete(void * arg,int count)1980a9108ebSHasso Tepper l2cap_complete(void *arg, int count)
1990a9108ebSHasso Tepper {
2000a9108ebSHasso Tepper struct socket *so = arg;
2010a9108ebSHasso Tepper
2020a9108ebSHasso Tepper while (count-- > 0)
2030a9108ebSHasso Tepper sbdroprecord(&so->so_snd.sb);
2040a9108ebSHasso Tepper
2050a9108ebSHasso Tepper sowwakeup(so);
2060a9108ebSHasso Tepper }
2070a9108ebSHasso Tepper
2080a9108ebSHasso Tepper static void
l2cap_linkmode(void * arg,int new)2090a9108ebSHasso Tepper l2cap_linkmode(void *arg, int new)
2100a9108ebSHasso Tepper {
2110a9108ebSHasso Tepper struct socket *so = arg;
2120a9108ebSHasso Tepper int mode;
2130a9108ebSHasso Tepper
2140a9108ebSHasso Tepper DPRINTF("auth %s, encrypt %s, secure %s\n",
2150a9108ebSHasso Tepper (new & L2CAP_LM_AUTH ? "on" : "off"),
2160a9108ebSHasso Tepper (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
2170a9108ebSHasso Tepper (new & L2CAP_LM_SECURE ? "on" : "off"));
2180a9108ebSHasso Tepper
2190a9108ebSHasso Tepper (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
2200a9108ebSHasso Tepper if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
2210a9108ebSHasso Tepper || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
2220a9108ebSHasso Tepper || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
2230a9108ebSHasso Tepper l2cap_disconnect(so->so_pcb, 0);
2240a9108ebSHasso Tepper }
2250a9108ebSHasso Tepper
2260a9108ebSHasso Tepper static void
l2cap_input(void * arg,struct mbuf * m)2270a9108ebSHasso Tepper l2cap_input(void *arg, struct mbuf *m)
2280a9108ebSHasso Tepper {
2290a9108ebSHasso Tepper struct socket *so = arg;
2300a9108ebSHasso Tepper
2310a9108ebSHasso Tepper if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
2320a9108ebSHasso Tepper kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n",
2330a9108ebSHasso Tepper __func__, m->m_pkthdr.len);
2340a9108ebSHasso Tepper m_freem(m);
2350a9108ebSHasso Tepper return;
2360a9108ebSHasso Tepper }
2370a9108ebSHasso Tepper
2380a9108ebSHasso Tepper DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
2390a9108ebSHasso Tepper
2400a9108ebSHasso Tepper sbappendrecord(&so->so_rcv.sb, m);
2410a9108ebSHasso Tepper sorwakeup(so);
2420a9108ebSHasso Tepper }
2430a9108ebSHasso Tepper
2440a9108ebSHasso Tepper
2450a9108ebSHasso Tepper /*
2460a9108ebSHasso Tepper * Implementation of usrreqs.
2470a9108ebSHasso Tepper */
248002c1265SMatthew Dillon static void
l2cap_sdetach(netmsg_t msg)249002c1265SMatthew Dillon l2cap_sdetach(netmsg_t msg)
2500a9108ebSHasso Tepper {
251002c1265SMatthew Dillon struct socket *so = msg->detach.base.nm_so;
252002c1265SMatthew Dillon int error;
253002c1265SMatthew Dillon
254002c1265SMatthew Dillon error = l2cap_detach((struct l2cap_channel **)&so->so_pcb);
255002c1265SMatthew Dillon lwkt_replymsg(&msg->detach.base.lmsg, error);
2560a9108ebSHasso Tepper }
2570a9108ebSHasso Tepper
2586cef7136SMatthew Dillon /*
2596cef7136SMatthew Dillon * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
2606cef7136SMatthew Dillon * will sofree() it when we return.
2616cef7136SMatthew Dillon */
262002c1265SMatthew Dillon static void
l2cap_sabort(netmsg_t msg)263002c1265SMatthew Dillon l2cap_sabort(netmsg_t msg)
2640a9108ebSHasso Tepper {
265002c1265SMatthew Dillon struct socket *so = msg->abort.base.nm_so;
2660a9108ebSHasso Tepper struct l2cap_channel *pcb = so->so_pcb;
2670a9108ebSHasso Tepper
2680a9108ebSHasso Tepper l2cap_disconnect(pcb, 0);
2690a9108ebSHasso Tepper soisdisconnected(so);
2700a9108ebSHasso Tepper
271002c1265SMatthew Dillon l2cap_sdetach(msg);
272002c1265SMatthew Dillon /* msg invalid now */
2730a9108ebSHasso Tepper }
2740a9108ebSHasso Tepper
275002c1265SMatthew Dillon static void
l2cap_sdisconnect(netmsg_t msg)276002c1265SMatthew Dillon l2cap_sdisconnect(netmsg_t msg)
2770a9108ebSHasso Tepper {
278002c1265SMatthew Dillon struct socket *so = msg->disconnect.base.nm_so;
2790a9108ebSHasso Tepper struct l2cap_channel *pcb = so->so_pcb;
280002c1265SMatthew Dillon int error;
2810a9108ebSHasso Tepper
2820a9108ebSHasso Tepper soisdisconnecting(so);
2830a9108ebSHasso Tepper
284002c1265SMatthew Dillon error = l2cap_disconnect(pcb, so->so_linger);
285002c1265SMatthew Dillon lwkt_replymsg(&msg->disconnect.base.lmsg, error);
2860a9108ebSHasso Tepper }
2870a9108ebSHasso Tepper
288002c1265SMatthew Dillon static void
l2cap_scontrol(netmsg_t msg)289002c1265SMatthew Dillon l2cap_scontrol(netmsg_t msg)
2900a9108ebSHasso Tepper {
291002c1265SMatthew Dillon lwkt_replymsg(&msg->control.base.lmsg, EPASSTHROUGH);
2920a9108ebSHasso Tepper }
2930a9108ebSHasso Tepper
294002c1265SMatthew Dillon static void
l2cap_sattach(netmsg_t msg)295002c1265SMatthew Dillon l2cap_sattach(netmsg_t msg)
2960a9108ebSHasso Tepper {
297002c1265SMatthew Dillon struct socket *so = msg->attach.base.nm_so;
2980a9108ebSHasso Tepper struct l2cap_channel *pcb = so->so_pcb;
299002c1265SMatthew Dillon int error;
3000a9108ebSHasso Tepper
301002c1265SMatthew Dillon if (pcb != NULL) {
302002c1265SMatthew Dillon error = EINVAL;
303002c1265SMatthew Dillon goto out;
304002c1265SMatthew Dillon }
3050a9108ebSHasso Tepper
3060a9108ebSHasso Tepper /*
3070a9108ebSHasso Tepper * For L2CAP socket PCB we just use an l2cap_channel structure
3080a9108ebSHasso Tepper * since we have nothing to add..
3090a9108ebSHasso Tepper */
310002c1265SMatthew Dillon error = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL);
311002c1265SMatthew Dillon if (error == 0) {
312002c1265SMatthew Dillon error = l2cap_attach((struct l2cap_channel **)&so->so_pcb,
3130a9108ebSHasso Tepper &l2cap_proto, so);
3140a9108ebSHasso Tepper }
315002c1265SMatthew Dillon out:
316002c1265SMatthew Dillon lwkt_replymsg(&msg->attach.base.lmsg, error);
3170a9108ebSHasso Tepper }
3180a9108ebSHasso Tepper
319002c1265SMatthew Dillon static void
l2cap_sbind(netmsg_t msg)320002c1265SMatthew Dillon l2cap_sbind (netmsg_t msg)
3210a9108ebSHasso Tepper {
322002c1265SMatthew Dillon struct socket *so = msg->bind.base.nm_so;
323002c1265SMatthew Dillon struct sockaddr *nam = msg->bind.nm_nam;
3240a9108ebSHasso Tepper struct l2cap_channel *pcb = so->so_pcb;
3250a9108ebSHasso Tepper struct sockaddr_bt *sa;
326002c1265SMatthew Dillon int error;
3270a9108ebSHasso Tepper
3280a9108ebSHasso Tepper KKASSERT(nam != NULL);
3290a9108ebSHasso Tepper sa = (struct sockaddr_bt *)nam;
3300a9108ebSHasso Tepper
331002c1265SMatthew Dillon if (sa->bt_len != sizeof(struct sockaddr_bt)) {
332002c1265SMatthew Dillon error = EINVAL;
333002c1265SMatthew Dillon } else if (sa->bt_family != AF_BLUETOOTH) {
334002c1265SMatthew Dillon error = EAFNOSUPPORT;
335002c1265SMatthew Dillon } else {
336002c1265SMatthew Dillon error = l2cap_bind(pcb, sa);
337002c1265SMatthew Dillon }
338002c1265SMatthew Dillon lwkt_replymsg(&msg->bind.base.lmsg, error);
339002c1265SMatthew Dillon }
3400a9108ebSHasso Tepper
341002c1265SMatthew Dillon static void
l2cap_sconnect(netmsg_t msg)342002c1265SMatthew Dillon l2cap_sconnect(netmsg_t msg)
343002c1265SMatthew Dillon {
344002c1265SMatthew Dillon struct socket *so = msg->connect.base.nm_so;
345002c1265SMatthew Dillon struct sockaddr *nam = msg->connect.nm_nam;
346002c1265SMatthew Dillon struct l2cap_channel *pcb = so->so_pcb;
347002c1265SMatthew Dillon struct sockaddr_bt *sa;
348002c1265SMatthew Dillon int error;
3490a9108ebSHasso Tepper
350002c1265SMatthew Dillon KKASSERT(nam != NULL);
351002c1265SMatthew Dillon sa = (struct sockaddr_bt *)nam;
352002c1265SMatthew Dillon
353002c1265SMatthew Dillon if (sa->bt_len != sizeof(struct sockaddr_bt)) {
354002c1265SMatthew Dillon error = EINVAL;
355002c1265SMatthew Dillon } else if (sa->bt_family != AF_BLUETOOTH) {
356002c1265SMatthew Dillon error = EAFNOSUPPORT;
357002c1265SMatthew Dillon } else {
3580a9108ebSHasso Tepper soisconnecting(so);
359002c1265SMatthew Dillon error = l2cap_connect(pcb, sa);
360002c1265SMatthew Dillon }
361002c1265SMatthew Dillon lwkt_replymsg(&msg->connect.base.lmsg, error);
3620a9108ebSHasso Tepper }
3630a9108ebSHasso Tepper
364002c1265SMatthew Dillon static void
l2cap_speeraddr(netmsg_t msg)365002c1265SMatthew Dillon l2cap_speeraddr(netmsg_t msg)
3660a9108ebSHasso Tepper {
367002c1265SMatthew Dillon struct socket *so = msg->peeraddr.base.nm_so;
368002c1265SMatthew Dillon struct sockaddr **nam = msg->peeraddr.nm_nam;
3690a9108ebSHasso Tepper struct l2cap_channel *pcb = so->so_pcb;
3700a9108ebSHasso Tepper struct sockaddr_bt *sa, ssa;
371002c1265SMatthew Dillon int error;
3720a9108ebSHasso Tepper
3730a9108ebSHasso Tepper sa = &ssa;
3740a9108ebSHasso Tepper bzero(sa, sizeof *sa);
3750a9108ebSHasso Tepper sa->bt_len = sizeof(struct sockaddr_bt);
3760a9108ebSHasso Tepper sa->bt_family = AF_BLUETOOTH;
377002c1265SMatthew Dillon error = l2cap_peeraddr(pcb, sa);
3780a9108ebSHasso Tepper *nam = dup_sockaddr((struct sockaddr *)sa);
3790a9108ebSHasso Tepper
380002c1265SMatthew Dillon lwkt_replymsg(&msg->peeraddr.base.lmsg, error);
3810a9108ebSHasso Tepper }
3820a9108ebSHasso Tepper
383002c1265SMatthew Dillon static void
l2cap_ssockaddr(netmsg_t msg)384002c1265SMatthew Dillon l2cap_ssockaddr(netmsg_t msg)
3850a9108ebSHasso Tepper {
386002c1265SMatthew Dillon struct socket *so = msg->sockaddr.base.nm_so;
387002c1265SMatthew Dillon struct sockaddr **nam = msg->sockaddr.nm_nam;
3880a9108ebSHasso Tepper struct l2cap_channel *pcb = so->so_pcb;
3890a9108ebSHasso Tepper struct sockaddr_bt *sa, ssa;
390002c1265SMatthew Dillon int error;
3910a9108ebSHasso Tepper
3920a9108ebSHasso Tepper sa = &ssa;
3930a9108ebSHasso Tepper bzero(sa, sizeof *sa);
3940a9108ebSHasso Tepper sa->bt_len = sizeof(struct sockaddr_bt);
3950a9108ebSHasso Tepper sa->bt_family = AF_BLUETOOTH;
396002c1265SMatthew Dillon error = l2cap_sockaddr(pcb, sa);
3970a9108ebSHasso Tepper *nam = dup_sockaddr((struct sockaddr *)sa);
3980a9108ebSHasso Tepper
399002c1265SMatthew Dillon lwkt_replymsg(&msg->sockaddr.base.lmsg, error);
4000a9108ebSHasso Tepper }
4010a9108ebSHasso Tepper
402002c1265SMatthew Dillon static void
l2cap_sshutdown(netmsg_t msg)403002c1265SMatthew Dillon l2cap_sshutdown(netmsg_t msg)
4040a9108ebSHasso Tepper {
405002c1265SMatthew Dillon struct socket *so = msg->shutdown.base.nm_so;
406002c1265SMatthew Dillon
4070a9108ebSHasso Tepper socantsendmore(so);
408002c1265SMatthew Dillon
409002c1265SMatthew Dillon lwkt_replymsg(&msg->shutdown.base.lmsg, 0);
4100a9108ebSHasso Tepper }
4110a9108ebSHasso Tepper
412002c1265SMatthew Dillon static void
l2cap_ssend(netmsg_t msg)413002c1265SMatthew Dillon l2cap_ssend(netmsg_t msg)
4140a9108ebSHasso Tepper {
415002c1265SMatthew Dillon struct socket *so = msg->send.base.nm_so;
416002c1265SMatthew Dillon struct mbuf *m = msg->send.nm_m;
417002c1265SMatthew Dillon struct mbuf *control = msg->send.nm_control;
4180a9108ebSHasso Tepper struct l2cap_channel *pcb = so->so_pcb;
4190a9108ebSHasso Tepper struct mbuf *m0;
420002c1265SMatthew Dillon int error;
4210a9108ebSHasso Tepper
4220a9108ebSHasso Tepper KKASSERT(m != NULL);
423002c1265SMatthew Dillon if (m->m_pkthdr.len == 0) {
424002c1265SMatthew Dillon error = 0;
425002c1265SMatthew Dillon goto out;
426002c1265SMatthew Dillon }
4270a9108ebSHasso Tepper
4280a9108ebSHasso Tepper if (m->m_pkthdr.len > pcb->lc_omtu) {
429002c1265SMatthew Dillon error = EMSGSIZE;
430002c1265SMatthew Dillon goto out;
4310a9108ebSHasso Tepper }
4320a9108ebSHasso Tepper
433b5523eacSSascha Wildner m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
4340a9108ebSHasso Tepper if (m0 == NULL) {
435002c1265SMatthew Dillon error = ENOMEM;
436002c1265SMatthew Dillon goto out;
4370a9108ebSHasso Tepper }
4380a9108ebSHasso Tepper
439b5523eacSSascha Wildner m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
440002c1265SMatthew Dillon if (m0 == NULL) {
441002c1265SMatthew Dillon error = ENOMEM;
442002c1265SMatthew Dillon goto out;
443002c1265SMatthew Dillon }
444002c1265SMatthew Dillon
445002c1265SMatthew Dillon /* no use for that */
446002c1265SMatthew Dillon if (control) {
4470a9108ebSHasso Tepper m_freem(control);
448002c1265SMatthew Dillon control = NULL;
449002c1265SMatthew Dillon }
4500a9108ebSHasso Tepper sbappendrecord(&so->so_snd.sb, m);
451002c1265SMatthew Dillon error = l2cap_send(pcb, m0);
452002c1265SMatthew Dillon m = NULL;
453002c1265SMatthew Dillon out:
4540a9108ebSHasso Tepper if (m)
4550a9108ebSHasso Tepper m_freem(m);
4560a9108ebSHasso Tepper if (control)
4570a9108ebSHasso Tepper m_freem(control);
4580a9108ebSHasso Tepper
459002c1265SMatthew Dillon lwkt_replymsg(&msg->send.base.lmsg, error);
4600a9108ebSHasso Tepper }
4610a9108ebSHasso Tepper
462002c1265SMatthew Dillon static void
l2cap_saccept(netmsg_t msg)463002c1265SMatthew Dillon l2cap_saccept(netmsg_t msg)
4640a9108ebSHasso Tepper {
465002c1265SMatthew Dillon struct socket *so = msg->accept.base.nm_so;
466002c1265SMatthew Dillon struct sockaddr **nam = msg->accept.nm_nam;
4670a9108ebSHasso Tepper struct l2cap_channel *pcb = so->so_pcb;
4680a9108ebSHasso Tepper struct sockaddr_bt sa;
469002c1265SMatthew Dillon int error;
4700a9108ebSHasso Tepper
4710a9108ebSHasso Tepper KKASSERT(nam != NULL);
4720a9108ebSHasso Tepper
4730a9108ebSHasso Tepper bzero(&sa, sizeof (sa) );
4740a9108ebSHasso Tepper sa.bt_len = sizeof(struct sockaddr_bt);
4750a9108ebSHasso Tepper sa.bt_family = AF_BLUETOOTH;
4760a9108ebSHasso Tepper
477002c1265SMatthew Dillon error = l2cap_peeraddr(pcb, &sa);
4780a9108ebSHasso Tepper *nam = dup_sockaddr((struct sockaddr *)&sa);
4790a9108ebSHasso Tepper
480002c1265SMatthew Dillon lwkt_replymsg(&msg->accept.base.lmsg, error);
4810a9108ebSHasso Tepper }
4820a9108ebSHasso Tepper
48308764bdcSMatthew Dillon static void
l2cap_slisten(netmsg_t msg)48408764bdcSMatthew Dillon l2cap_slisten(netmsg_t msg)
4850a9108ebSHasso Tepper {
48608764bdcSMatthew Dillon struct socket *so = msg->listen.base.nm_so;
4870a9108ebSHasso Tepper struct l2cap_channel *pcb = so->so_pcb;
48808764bdcSMatthew Dillon int error;
48908764bdcSMatthew Dillon
49008764bdcSMatthew Dillon error = l2cap_listen(pcb);
49108764bdcSMatthew Dillon lwkt_replymsg(&msg->accept.base.lmsg, error);
4920a9108ebSHasso Tepper }
4930a9108ebSHasso Tepper
4940a9108ebSHasso Tepper
4950a9108ebSHasso Tepper struct pr_usrreqs l2cap_usrreqs = {
4960a9108ebSHasso Tepper .pru_abort = l2cap_sabort,
4970a9108ebSHasso Tepper .pru_accept = l2cap_saccept,
4980a9108ebSHasso Tepper .pru_attach = l2cap_sattach,
4990a9108ebSHasso Tepper .pru_bind = l2cap_sbind,
5000a9108ebSHasso Tepper .pru_connect = l2cap_sconnect,
501002c1265SMatthew Dillon .pru_connect2 = pr_generic_notsupp,
5020a9108ebSHasso Tepper .pru_control = l2cap_scontrol,
5030a9108ebSHasso Tepper .pru_detach = l2cap_sdetach,
5040a9108ebSHasso Tepper .pru_disconnect = l2cap_sdisconnect,
5050a9108ebSHasso Tepper .pru_listen = l2cap_slisten,
5060a9108ebSHasso Tepper .pru_peeraddr = l2cap_speeraddr,
507002c1265SMatthew Dillon .pru_rcvd = pr_generic_notsupp,
508002c1265SMatthew Dillon .pru_rcvoob = pr_generic_notsupp,
5090a9108ebSHasso Tepper .pru_send = l2cap_ssend,
5100a9108ebSHasso Tepper .pru_sense = pru_sense_null,
5110a9108ebSHasso Tepper .pru_shutdown = l2cap_sshutdown,
5120a9108ebSHasso Tepper .pru_sockaddr = l2cap_ssockaddr,
5130a9108ebSHasso Tepper .pru_sosend = sosend,
5148b5c39bbSSamuel J. Greear .pru_soreceive = soreceive
5150a9108ebSHasso Tepper };
516