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