Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / sys / netbt / l2cap_socket.c
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 $ */
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
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
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 *);
70
71 static 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 */
82 int l2cap_sendspace = 4096;
83 int 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  */
91 int
92 l2cap_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                 }
121                 soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
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
142 static void
143 l2cap_connecting(void *arg)
144 {
145         struct socket *so = arg;
146
147         DPRINTF("Connecting\n");
148         soisconnecting(so);
149 }
150
151 static void
152 l2cap_connected(void *arg)
153 {
154         struct socket *so = arg;
155
156         DPRINTF("Connected\n");
157         soisconnected(so);
158 }
159
160 static void
161 l2cap_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
171 static void *
172 l2cap_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
187 static void
188 l2cap_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
198 static void
199 l2cap_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
216 static void
217 l2cap_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  */
238 static int
239 l2cap_sdetach(struct socket *so)
240 {
241         return l2cap_detach((struct l2cap_channel **)&so->so_pcb);
242 }
243
244 /*
245  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
246  *       will sofree() it when we return.
247  */
248 static int
249 l2cap_sabort (struct socket *so)
250 {
251         struct l2cap_channel *pcb = so->so_pcb;
252         int error;
253         
254         l2cap_disconnect(pcb, 0);
255         soisdisconnected(so);
256         
257         error = l2cap_sdetach(so);
258         return error;
259 }
260
261 static int
262 l2cap_sdisconnect (struct socket *so)
263 {
264         struct l2cap_channel *pcb = so->so_pcb;
265         
266         soisdisconnecting(so);
267         
268         return l2cap_disconnect(pcb, so->so_linger);
269 }
270
271 static int
272 l2cap_scontrol (struct socket *so, u_long cmd, caddr_t data,
273     struct ifnet *ifp, struct thread *td)
274 {
275         return EPASSTHROUGH;
276 }
277
278 static int
279 l2cap_sattach (struct socket *so, int proto,
280                                struct pru_attach_info *ai)
281 {
282         struct l2cap_channel *pcb = so->so_pcb;
283         int err = 0;
284
285         if (pcb != NULL)
286                 return EINVAL;
287
288         /*
289          * For L2CAP socket PCB we just use an l2cap_channel structure
290          * since we have nothing to add..
291          */
292         err = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL);
293         if (err)
294                 return err;
295
296         return l2cap_attach((struct l2cap_channel **)&so->so_pcb,
297             &l2cap_proto, so);
298 }
299
300 static int
301 l2cap_sbind (struct socket *so, struct sockaddr *nam,
302                                  struct thread *td)
303 {
304         struct l2cap_channel *pcb = so->so_pcb;
305         struct sockaddr_bt *sa;
306
307         KKASSERT(nam != NULL);
308         sa = (struct sockaddr_bt *)nam;
309
310         if (sa->bt_len != sizeof(struct sockaddr_bt))
311                 return EINVAL;
312
313         if (sa->bt_family != AF_BLUETOOTH)
314                 return EAFNOSUPPORT;
315
316         return l2cap_bind(pcb, sa);
317 }
318
319 static int
320 l2cap_sconnect (struct socket *so, struct sockaddr *nam,
321                                     struct thread *td)
322 {
323         struct l2cap_channel *pcb = so->so_pcb;
324         struct sockaddr_bt *sa;
325
326         KKASSERT(nam != NULL);
327         sa = (struct sockaddr_bt *)nam;
328
329         if (sa->bt_len != sizeof(struct sockaddr_bt))
330                 return EINVAL;
331
332         if (sa->bt_family != AF_BLUETOOTH)
333                 return EAFNOSUPPORT;
334
335         soisconnecting(so);
336         return l2cap_connect(pcb, sa);
337 }
338
339 static int
340 l2cap_speeraddr (struct socket *so, struct sockaddr **nam)
341 {
342         struct l2cap_channel *pcb = so->so_pcb;
343         struct sockaddr_bt *sa, ssa;
344         int e;
345
346         sa = &ssa;
347         bzero(sa, sizeof *sa);
348         sa->bt_len = sizeof(struct sockaddr_bt);
349         sa->bt_family = AF_BLUETOOTH;
350         e = l2cap_peeraddr(pcb, sa);
351         *nam = dup_sockaddr((struct sockaddr *)sa);
352
353         return (e);     
354 }
355
356 static int
357 l2cap_ssockaddr (struct socket *so, struct sockaddr **nam)
358 {
359         struct l2cap_channel *pcb = so->so_pcb;
360         struct sockaddr_bt *sa, ssa;
361         int e;
362
363         sa = &ssa;
364         bzero(sa, sizeof *sa);
365         sa->bt_len = sizeof(struct sockaddr_bt);
366         sa->bt_family = AF_BLUETOOTH;
367         e = l2cap_sockaddr(pcb, sa);
368         *nam = dup_sockaddr((struct sockaddr *)sa);
369
370         return (e);
371 }
372
373 static int
374 l2cap_sshutdown (struct socket *so)
375 {
376         socantsendmore(so);
377         return 0;
378 }
379
380 static int
381 l2cap_ssend (struct socket *so, int flags, struct mbuf *m,
382     struct sockaddr *addr, struct mbuf *control, struct thread *td)
383 {
384         struct l2cap_channel *pcb = so->so_pcb;
385         struct mbuf *m0;
386
387         int err = 0;
388
389         KKASSERT(m != NULL);
390         if (m->m_pkthdr.len == 0)
391                 goto error;
392
393         if (m->m_pkthdr.len > pcb->lc_omtu) {
394                 err = EMSGSIZE;
395                 goto error;
396         }
397
398         m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
399         if (m0 == NULL) {
400                 err = ENOMEM;
401                 goto error;
402         }
403
404         if (control)    /* no use for that */
405                 m_freem(control);
406
407         sbappendrecord(&so->so_snd.sb, m);
408         return l2cap_send(pcb, m0);
409
410 error:
411         if (m)
412                 m_freem(m);
413         if (control)
414                 m_freem(control);
415
416         return err;
417 }
418
419 static int
420 l2cap_saccept(struct socket *so, struct sockaddr **nam)
421 {
422         struct l2cap_channel *pcb = so->so_pcb;
423         struct sockaddr_bt sa;
424         int e;
425                 
426         KKASSERT(nam != NULL);
427         
428         bzero(&sa, sizeof (sa) );
429         sa.bt_len = sizeof(struct sockaddr_bt);
430         sa.bt_family = AF_BLUETOOTH;
431
432         e = l2cap_peeraddr(pcb, &sa);
433         *nam = dup_sockaddr((struct sockaddr *)&sa);
434
435         return e;       
436 }
437
438 static int
439 l2cap_slisten(struct socket *so, struct thread *td)
440 {
441         struct l2cap_channel *pcb = so->so_pcb;
442         return l2cap_listen(pcb);
443 }
444
445
446 struct pr_usrreqs l2cap_usrreqs = {
447         .pru_abort = l2cap_sabort,
448         .pru_accept = l2cap_saccept,
449         .pru_attach = l2cap_sattach,
450         .pru_bind = l2cap_sbind,
451         .pru_connect = l2cap_sconnect,
452         .pru_connect2 = pru_connect2_notsupp,
453         .pru_control = l2cap_scontrol,
454         .pru_detach = l2cap_sdetach,
455         .pru_disconnect = l2cap_sdisconnect,
456         .pru_listen = l2cap_slisten,
457         .pru_peeraddr = l2cap_speeraddr,
458         .pru_rcvd = pru_rcvd_notsupp,
459         .pru_rcvoob = pru_rcvoob_notsupp,
460         .pru_send = l2cap_ssend,
461         .pru_sense = pru_sense_null,
462         .pru_shutdown = l2cap_sshutdown,
463         .pru_sockaddr = l2cap_ssockaddr,
464         .pru_sosend = sosend,
465         .pru_soreceive = soreceive
466 };