Sync Bluetooth stack with NetBSD.
[dragonfly.git] / sys / netbt / l2cap_socket.c
blobd1f56fc10a257af0974dacad8ff4d8b972d0d335
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 $ */
5 /*-
6 * Copyright (c) 2005 Iain Hibbert.
7 * Copyright (c) 2006 Itronix Inc.
8 * All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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
39 #define PRUREQUESTS
40 #define PRCOREQUESTS
41 #endif
43 #include <sys/param.h>
44 #include <sys/domain.h>
45 #include <sys/kernel.h>
46 #include <sys/mbuf.h>
47 #include <sys/proc.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>
59 * L2CAP Sockets
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 = {
75 l2cap_connecting,
76 l2cap_connected,
77 l2cap_disconnected,
78 l2cap_newconn,
79 l2cap_complete,
80 l2cap_linkmode,
81 l2cap_input,
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.
94 int
95 l2cap_ctloutput(struct socket *so, struct sockopt *sopt)
97 struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb;
98 struct mbuf *m;
99 int err = 0;
101 #ifdef notyet /* XXX */
102 DPRINTFN(2, "%s\n", prcorequests[req]);
103 #endif
105 if (pcb == NULL)
106 return EINVAL;
108 if (sopt->sopt_level != BTPROTO_L2CAP)
109 return ENOPROTOOPT;
111 switch(sopt->sopt_dir) {
112 case PRCO_GETOPT:
113 m = m_get(M_NOWAIT, MT_DATA);
114 if (m == NULL) {
115 err = ENOMEM;
116 break;
118 m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *));
119 if (m->m_len == 0) {
120 m_freem(m);
121 m = NULL;
122 err = ENOPROTOOPT;
124 err = sooptcopyout(sopt, mtod(m, void *), m->m_len);
125 break;
127 case PRCO_SETOPT:
128 err = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt);
129 break;
131 default:
132 err = ENOPROTOOPT;
133 break;
136 return err;
139 /**********************************************************************
141 * L2CAP Protocol socket callbacks
145 static void
146 l2cap_connecting(void *arg)
148 struct socket *so = arg;
150 DPRINTF("Connecting\n");
151 soisconnecting(so);
154 static void
155 l2cap_connected(void *arg)
157 struct socket *so = arg;
159 DPRINTF("Connected\n");
160 soisconnected(so);
163 static void
164 l2cap_disconnected(void *arg, int err)
166 struct socket *so = arg;
168 DPRINTF("Disconnected (%d)\n", err);
170 so->so_error = err;
171 soisdisconnected(so);
174 static void *
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);
182 if (so == NULL)
183 return NULL;
185 soisconnecting(so);
187 return so->so_pcb;
190 static void
191 l2cap_complete(void *arg, int count)
193 struct socket *so = arg;
195 while (count-- > 0)
196 sbdroprecord(&so->so_snd.sb);
198 sowwakeup(so);
201 static void
202 l2cap_linkmode(void *arg, int new)
204 struct socket *so = arg;
205 int mode;
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);
219 static void
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);
227 m_freem(m);
228 return;
231 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
233 sbappendrecord(&so->so_rcv.sb, m);
234 sorwakeup(so);
239 * Implementation of usrreqs.
241 static int
242 l2cap_sdetach(struct socket *so)
244 return l2cap_detach((struct l2cap_channel **)&so->so_pcb);
247 static int
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);
258 static int
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);
268 static int
269 l2cap_scontrol (struct socket *so, u_long cmd, caddr_t data,
270 struct ifnet *ifp, struct thread *td)
272 return EPASSTHROUGH;
275 static int
276 l2cap_sattach (struct socket *so, int proto,
277 struct pru_attach_info *ai)
279 struct l2cap_channel *pcb = so->so_pcb;
280 int err = 0;
282 if (pcb != NULL)
283 return EINVAL;
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);
290 if (err)
291 return err;
293 return l2cap_attach((struct l2cap_channel **)&so->so_pcb,
294 &l2cap_proto, so);
297 static int
298 l2cap_sbind (struct socket *so, struct sockaddr *nam,
299 struct thread *td)
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))
308 return EINVAL;
310 if (sa->bt_family != AF_BLUETOOTH)
311 return EAFNOSUPPORT;
313 return l2cap_bind(pcb, sa);
316 static int
317 l2cap_sconnect (struct socket *so, struct sockaddr *nam,
318 struct thread *td)
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))
327 return EINVAL;
329 if (sa->bt_family != AF_BLUETOOTH)
330 return EAFNOSUPPORT;
332 soisconnecting(so);
333 return l2cap_connect(pcb, sa);
336 static int
337 l2cap_speeraddr (struct socket *so, struct sockaddr **nam)
339 struct l2cap_channel *pcb = so->so_pcb;
340 struct sockaddr_bt *sa, ssa;
341 int e;
343 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);
350 return (e);
353 static int
354 l2cap_ssockaddr (struct socket *so, struct sockaddr **nam)
356 struct l2cap_channel *pcb = so->so_pcb;
357 struct sockaddr_bt *sa, ssa;
358 int e;
360 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);
367 return (e);
370 static int
371 l2cap_sshutdown (struct socket *so)
373 socantsendmore(so);
374 return 0;
377 static int
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;
382 struct mbuf *m0;
384 int err = 0;
386 KKASSERT(m != NULL);
387 if (m->m_pkthdr.len == 0)
388 goto error;
390 if (m->m_pkthdr.len > pcb->lc_omtu) {
391 err = EMSGSIZE;
392 goto error;
395 m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
396 if (m0 == NULL) {
397 err = ENOMEM;
398 goto error;
401 if (control) /* no use for that */
402 m_freem(control);
404 sbappendrecord(&so->so_snd.sb, m);
405 return l2cap_send(pcb, m0);
407 error:
408 if (m)
409 m_freem(m);
410 if (control)
411 m_freem(control);
413 return err;
416 static int
417 l2cap_saccept(struct socket *so, struct sockaddr **nam)
419 struct l2cap_channel *pcb = so->so_pcb;
420 struct sockaddr_bt sa;
421 int e;
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);
432 return e;
435 static int
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,
463 .pru_sopoll = sopoll