Remove inclusion of <sys/cdefs.h> from kernel .c files.
[dragonfly.git] / sys / netbt / l2cap_socket.c
CommitLineData
0a9108eb
HT
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 $ */
0a9108eb
HT
3
4/*-
5 * Copyright (c) 2005 Iain Hibbert.
6 * Copyright (c) 2006 Itronix Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
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.
20 *
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.
32 */
33
0a9108eb
HT
34/* load symbolic names */
35#ifdef BLUETOOTH_DEBUG
36#define PRUREQUESTS
37#define PRCOREQUESTS
38#endif
39
40#include <sys/param.h>
41#include <sys/domain.h>
42#include <sys/kernel.h>
43#include <sys/mbuf.h>
44#include <sys/proc.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>
50
51#include <netbt/bluetooth.h>
52#include <netbt/hci.h> /* XXX for EPASSTHROUGH */
53#include <netbt/l2cap.h>
54
55/*
56 * L2CAP Sockets
57 *
58 * SOCK_SEQPACKET - normal L2CAP connection
59 *
60 * SOCK_DGRAM - connectionless L2CAP - XXX not yet
61 */
62
63static void l2cap_connecting(void *);
64static void l2cap_connected(void *);
65static void l2cap_disconnected(void *, int);
66static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
67static void l2cap_complete(void *, int);
68static void l2cap_linkmode(void *, int);
69static void l2cap_input(void *, struct mbuf *);
70
71static const struct btproto l2cap_proto = {
72 l2cap_connecting,
73 l2cap_connected,
74 l2cap_disconnected,
75 l2cap_newconn,
76 l2cap_complete,
77 l2cap_linkmode,
78 l2cap_input,
79};
80
81/* sysctl variables */
82int l2cap_sendspace = 4096;
83int l2cap_recvspace = 4096;
84
85/*
86 * l2cap_ctloutput(request, socket, level, optname, opt)
87 *
88 * Apply configuration commands to channel. This corresponds to
89 * "Reconfigure Channel Request" in the L2CAP specification.
90 */
91int
92l2cap_ctloutput(struct socket *so, struct sockopt *sopt)
93{
94 struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb;
95 struct mbuf *m;
96 int err = 0;
97
98#ifdef notyet /* XXX */
99 DPRINTFN(2, "%s\n", prcorequests[req]);
100#endif
101
102 if (pcb == NULL)
103 return EINVAL;
104
105 if (sopt->sopt_level != BTPROTO_L2CAP)
106 return ENOPROTOOPT;
107
108 switch(sopt->sopt_dir) {
109 case PRCO_GETOPT:
110 m = m_get(M_NOWAIT, MT_DATA);
111 if (m == NULL) {
112 err = ENOMEM;
113 break;
114 }
115 m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *));
116 if (m->m_len == 0) {
117 m_freem(m);
118 m = NULL;
119 err = ENOPROTOOPT;
120 }
d82b71f8 121 soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
0a9108eb
HT
122 break;
123
124 case PRCO_SETOPT:
125 err = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt);
126 break;
127
128 default:
129 err = ENOPROTOOPT;
130 break;
131 }
132
133 return err;
134}
135
136/**********************************************************************
137 *
138 * L2CAP Protocol socket callbacks
139 *
140 */
141
142static void
143l2cap_connecting(void *arg)
144{
145 struct socket *so = arg;
146
147 DPRINTF("Connecting\n");
148 soisconnecting(so);
149}
150
151static void
152l2cap_connected(void *arg)
153{
154 struct socket *so = arg;
155
156 DPRINTF("Connected\n");
157 soisconnected(so);
158}
159
160static void
161l2cap_disconnected(void *arg, int err)
162{
163 struct socket *so = arg;
164
165 DPRINTF("Disconnected (%d)\n", err);
166
167 so->so_error = err;
168 soisdisconnected(so);
169}
170
171static void *
172l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
173 struct sockaddr_bt *raddr)
174{
175 struct socket *so = arg;
176
177 DPRINTF("New Connection\n");
178 so = sonewconn(so, 0);
179 if (so == NULL)
180 return NULL;
181
182 soisconnecting(so);
183
184 return so->so_pcb;
185}
186
187static void
188l2cap_complete(void *arg, int count)
189{
190 struct socket *so = arg;
191
192 while (count-- > 0)
193 sbdroprecord(&so->so_snd.sb);
194
195 sowwakeup(so);
196}
197
198static void
199l2cap_linkmode(void *arg, int new)
200{
201 struct socket *so = arg;
202 int mode;
203
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"));
208
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);
214}
215
216static void
217l2cap_input(void *arg, struct mbuf *m)
218{
219 struct socket *so = arg;
220
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);
224 m_freem(m);
225 return;
226 }
227
228 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
229
230 sbappendrecord(&so->so_rcv.sb, m);
231 sorwakeup(so);
232}
233
234
235/*
236 * Implementation of usrreqs.
237 */
238static int
239l2cap_sdetach(struct socket *so)
240{
241 return l2cap_detach((struct l2cap_channel **)&so->so_pcb);
242}
243
244static int
245l2cap_sabort (struct socket *so)
246{
247 struct l2cap_channel *pcb = so->so_pcb;
248
249 l2cap_disconnect(pcb, 0);
250 soisdisconnected(so);
251
252 return l2cap_sdetach(so);
253}
254
255static int
256l2cap_sdisconnect (struct socket *so)
257{
258 struct l2cap_channel *pcb = so->so_pcb;
259
260 soisdisconnecting(so);
261
262 return l2cap_disconnect(pcb, so->so_linger);
263}
264
265static int
266l2cap_scontrol (struct socket *so, u_long cmd, caddr_t data,
267 struct ifnet *ifp, struct thread *td)
268{
269 return EPASSTHROUGH;
270}
271
272static int
273l2cap_sattach (struct socket *so, int proto,
274 struct pru_attach_info *ai)
275{
276 struct l2cap_channel *pcb = so->so_pcb;
277 int err = 0;
278
279 if (pcb != NULL)
280 return EINVAL;
281
282 /*
283 * For L2CAP socket PCB we just use an l2cap_channel structure
284 * since we have nothing to add..
285 */
286 err = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL);
287 if (err)
288 return err;
289
290 return l2cap_attach((struct l2cap_channel **)&so->so_pcb,
291 &l2cap_proto, so);
292}
293
294static int
295l2cap_sbind (struct socket *so, struct sockaddr *nam,
296 struct thread *td)
297{
298 struct l2cap_channel *pcb = so->so_pcb;
299 struct sockaddr_bt *sa;
300
301 KKASSERT(nam != NULL);
302 sa = (struct sockaddr_bt *)nam;
303
304 if (sa->bt_len != sizeof(struct sockaddr_bt))
305 return EINVAL;
306
307 if (sa->bt_family != AF_BLUETOOTH)
308 return EAFNOSUPPORT;
309
310 return l2cap_bind(pcb, sa);
311}
312
313static int
314l2cap_sconnect (struct socket *so, struct sockaddr *nam,
315 struct thread *td)
316{
317 struct l2cap_channel *pcb = so->so_pcb;
318 struct sockaddr_bt *sa;
319
320 KKASSERT(nam != NULL);
321 sa = (struct sockaddr_bt *)nam;
322
323 if (sa->bt_len != sizeof(struct sockaddr_bt))
324 return EINVAL;
325
326 if (sa->bt_family != AF_BLUETOOTH)
327 return EAFNOSUPPORT;
328
329 soisconnecting(so);
330 return l2cap_connect(pcb, sa);
331}
332
333static int
334l2cap_speeraddr (struct socket *so, struct sockaddr **nam)
335{
336 struct l2cap_channel *pcb = so->so_pcb;
337 struct sockaddr_bt *sa, ssa;
338 int e;
339
340 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);
346
347 return (e);
348}
349
350static int
351l2cap_ssockaddr (struct socket *so, struct sockaddr **nam)
352{
353 struct l2cap_channel *pcb = so->so_pcb;
354 struct sockaddr_bt *sa, ssa;
355 int e;
356
357 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);
363
364 return (e);
365}
366
367static int
368l2cap_sshutdown (struct socket *so)
369{
370 socantsendmore(so);
371 return 0;
372}
373
374static int
375l2cap_ssend (struct socket *so, int flags, struct mbuf *m,
376 struct sockaddr *addr, struct mbuf *control, struct thread *td)
377{
378 struct l2cap_channel *pcb = so->so_pcb;
379 struct mbuf *m0;
380
381 int err = 0;
382
383 KKASSERT(m != NULL);
384 if (m->m_pkthdr.len == 0)
385 goto error;
386
387 if (m->m_pkthdr.len > pcb->lc_omtu) {
388 err = EMSGSIZE;
389 goto error;
390 }
391
392 m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
393 if (m0 == NULL) {
394 err = ENOMEM;
395 goto error;
396 }
397
398 if (control) /* no use for that */
399 m_freem(control);
400
401 sbappendrecord(&so->so_snd.sb, m);
402 return l2cap_send(pcb, m0);
403
404error:
405 if (m)
406 m_freem(m);
407 if (control)
408 m_freem(control);
409
410 return err;
411}
412
413static int
414l2cap_saccept(struct socket *so, struct sockaddr **nam)
415{
416 struct l2cap_channel *pcb = so->so_pcb;
417 struct sockaddr_bt sa;
418 int e;
419
420 KKASSERT(nam != NULL);
421
422 bzero(&sa, sizeof (sa) );
423 sa.bt_len = sizeof(struct sockaddr_bt);
424 sa.bt_family = AF_BLUETOOTH;
425
426 e = l2cap_peeraddr(pcb, &sa);
427 *nam = dup_sockaddr((struct sockaddr *)&sa);
428
429 return e;
430}
431
432static int
433l2cap_slisten(struct socket *so, struct thread *td)
434{
435 struct l2cap_channel *pcb = so->so_pcb;
436 return l2cap_listen(pcb);
437}
438
439
440struct 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,
460 .pru_sopoll = sopoll
461};