If the current thread is not a network thread then rejecting the packet back
[dragonfly.git] / sys / netbt / rfcomm_socket.c
1 /* $DragonFly: src/sys/netbt/rfcomm_socket.c,v 1.3 2008/06/20 20:52:29 aggelos Exp $ */
2 /* $OpenBSD: src/sys/netbt/rfcomm_socket.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
3 /* $NetBSD: rfcomm_socket.c,v 1.8 2007/10/15 18:04:34 plunky Exp $ */
4
5 /*-
6  * Copyright (c) 2006 Itronix Inc.
7  * All rights reserved.
8  *
9  * Written by Iain Hibbert for Itronix Inc.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of Itronix Inc. may not be used to endorse
20  *    or promote products derived from this software without specific
21  *    prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
27  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30  * ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 /* load symbolic names */
37 #ifdef BLUETOOTH_DEBUG
38 #define PRUREQUESTS
39 #define PRCOREQUESTS
40 #endif
41
42 #include <sys/param.h>
43 #include <sys/domain.h>
44 #include <sys/kernel.h>
45 #include <sys/mbuf.h>
46 #include <sys/proc.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/systm.h>
51 #include <vm/vm_zone.h>
52
53 #include <netbt/bluetooth.h>
54 #include <netbt/hci.h>          /* XXX for EPASSTHROUGH */
55 #include <netbt/rfcomm.h>
56
57 /****************************************************************************
58  *
59  *      RFCOMM SOCK_STREAM Sockets - serial line emulation
60  *
61  */
62
63 static void rfcomm_connecting(void *);
64 static void rfcomm_connected(void *);
65 static void rfcomm_disconnected(void *, int);
66 static void *rfcomm_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
67 static void rfcomm_complete(void *, int);
68 static void rfcomm_linkmode(void *, int);
69 static void rfcomm_input(void *, struct mbuf *);
70
71 static const struct btproto rfcomm_proto = {
72         rfcomm_connecting,
73         rfcomm_connected,
74         rfcomm_disconnected,
75         rfcomm_newconn,
76         rfcomm_complete,
77         rfcomm_linkmode,
78         rfcomm_input,
79 };
80
81 /* sysctl variables */
82 int rfcomm_sendspace = 4096;
83 int rfcomm_recvspace = 4096;
84
85 /*
86  * rfcomm_ctloutput(request, socket, level, optname, opt)
87  *
88  */
89 int
90 rfcomm_ctloutput(struct socket *so, struct sockopt *sopt)
91 {
92         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
93         struct mbuf *m;
94         int err = 0;
95
96 #ifdef notyet                   /* XXX */
97         DPRINTFN(2, "%s\n", prcorequests[sopt->sopt_dir]);
98 #endif
99
100         if (pcb == NULL)
101                 return EINVAL;
102
103         if (sopt->sopt_level != BTPROTO_RFCOMM)
104                 return ENOPROTOOPT;
105
106         switch(sopt->sopt_dir) {
107         case PRCO_GETOPT:
108                 m = m_get(M_WAITOK, MT_DATA);
109                 crit_enter();
110                 m->m_len = rfcomm_getopt(pcb, sopt->sopt_name, mtod(m, void *));
111                 crit_exit();            
112                 if (m->m_len == 0) {
113                         m_freem(m);
114                         m = NULL;
115                         err = ENOPROTOOPT;
116                 }
117                 soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
118                 break;
119
120         case PRCO_SETOPT:
121                 err = rfcomm_setopt2(pcb, sopt->sopt_name, so, sopt);
122
123                 break;
124
125         default:
126                 err = ENOPROTOOPT;
127                 break;
128         }
129
130         return err;
131 }
132
133 /**********************************************************************
134  *
135  * RFCOMM callbacks
136  */
137
138 static void
139 rfcomm_connecting(void *arg)
140 {
141         /* struct socket *so = arg; */
142
143         KKASSERT(arg != NULL);
144         DPRINTF("Connecting\n");
145 }
146
147 static void
148 rfcomm_connected(void *arg)
149 {
150         struct socket *so = arg;
151
152         KKASSERT(so != NULL);
153         DPRINTF("Connected\n");
154         soisconnected(so);
155 }
156
157 static void
158 rfcomm_disconnected(void *arg, int err)
159 {
160         struct socket *so = arg;
161
162         KKASSERT(so != NULL);
163         DPRINTF("Disconnected\n");
164
165         so->so_error = err;
166         soisdisconnected(so);
167 }
168
169 static void *
170 rfcomm_newconn(void *arg, struct sockaddr_bt *laddr,
171     struct sockaddr_bt *raddr)
172 {
173         struct socket *so = arg;
174
175         DPRINTF("New Connection\n");
176         so = sonewconn(so, 0);
177         if (so == NULL)
178                 return NULL;
179
180         soisconnecting(so);
181
182         return so->so_pcb;
183 }
184
185 /*
186  * rfcomm_complete(rfcomm_dlc, length)
187  *
188  * length bytes are sent and may be removed from socket buffer
189  */
190 static void
191 rfcomm_complete(void *arg, int length)
192 {
193         struct socket *so = arg;
194
195         sbdrop(&so->so_snd.sb, length);
196         sowwakeup(so);
197 }
198
199 /*
200  * rfcomm_linkmode(rfcomm_dlc, new)
201  *
202  * link mode change notification.
203  */
204 static void
205 rfcomm_linkmode(void *arg, int new)
206 {
207         struct socket *so = arg;
208         int mode;
209
210         DPRINTF("auth %s, encrypt %s, secure %s\n",
211                 (new & RFCOMM_LM_AUTH ? "on" : "off"),
212                 (new & RFCOMM_LM_ENCRYPT ? "on" : "off"),
213                 (new & RFCOMM_LM_SECURE ? "on" : "off"));
214
215         (void)rfcomm_getopt(so->so_pcb, SO_RFCOMM_LM, &mode);
216         if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH))
217             || ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT))
218             || ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE)))
219                 rfcomm_disconnect(so->so_pcb, 0);
220 }
221
222 /*
223  * rfcomm_input(rfcomm_dlc, mbuf)
224  */
225 static void
226 rfcomm_input(void *arg, struct mbuf *m)
227 {
228         struct socket *so = arg;
229
230         KKASSERT(so != NULL);
231
232         if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
233                 kprintf("%s: %d bytes dropped (socket buffer full)\n",
234                         __func__, m->m_pkthdr.len);
235                 m_freem(m);
236                 return;
237         }
238
239         DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
240
241         sbappendstream(&so->so_rcv.sb, m);
242         sorwakeup(so);
243 }
244
245 /*
246  * Implementation of usrreqs.
247  */
248 static int
249 rfcomm_sdetach(struct socket *so)
250 {
251         return rfcomm_detach((struct rfcomm_dlc **)&so->so_pcb);
252 }
253
254 static int
255 rfcomm_sabort (struct socket *so)
256 {
257         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
258
259         rfcomm_disconnect(pcb, 0);
260         soisdisconnected(so);
261         return rfcomm_sdetach(so);
262 }
263
264 static int
265 rfcomm_sdisconnect (struct socket *so)
266 {
267         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
268
269         soisdisconnecting(so);
270         return rfcomm_disconnect(pcb, so->so_linger);
271 }
272
273 static int
274 rfcomm_scontrol (struct socket *so, u_long cmd, caddr_t data,
275                                     struct ifnet *ifp, struct thread *td)
276 {
277         return EPASSTHROUGH;
278 }
279
280 static int
281 rfcomm_sattach (struct socket *so, int proto,
282                                struct pru_attach_info *ai)
283 {
284         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
285
286         int err=0;
287         if (pcb != NULL)
288                 return EINVAL;
289
290         /*
291          * Since we have nothing to add, we attach the DLC
292          * structure directly to our PCB pointer.
293          */
294         err = soreserve(so, rfcomm_sendspace, rfcomm_recvspace, NULL);
295         if (err)
296                 return err;
297
298         err = rfcomm_attach((struct rfcomm_dlc **)&so->so_pcb,
299             &rfcomm_proto, so);
300         if (err)
301                 return err;
302
303         err = rfcomm_rcvd(so->so_pcb, sbspace(&so->so_rcv));
304         if (err) {
305                 rfcomm_detach((struct rfcomm_dlc **)&so->so_pcb);
306                 return err;
307         }
308
309         return 0;
310 }
311
312 static int
313 rfcomm_sbind (struct socket *so, struct sockaddr *nam,
314                                  struct thread *td)
315 {
316         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
317         struct sockaddr_bt *sa;
318
319         KKASSERT(nam != NULL);
320         sa = (struct sockaddr_bt *)nam;
321
322         if (sa->bt_len != sizeof(struct sockaddr_bt))
323                 return EINVAL;
324
325         if (sa->bt_family != AF_BLUETOOTH)
326                 return EAFNOSUPPORT;
327
328         return rfcomm_bind(pcb, sa);
329 }
330
331 static int
332 rfcomm_sconnect (struct socket *so, struct sockaddr *nam,
333                                     struct thread *td)
334 {
335         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
336         struct sockaddr_bt *sa;
337
338         KKASSERT(nam != NULL);
339         sa = (struct sockaddr_bt *)nam;
340
341         if (sa->bt_len != sizeof(struct sockaddr_bt))
342                 return EINVAL;
343
344         if (sa->bt_family != AF_BLUETOOTH)
345                 return EAFNOSUPPORT;
346
347         soisconnecting(so);
348         return rfcomm_connect(pcb, sa);
349 }
350
351 static int
352 rfcomm_speeraddr (struct socket *so, struct sockaddr **nam)
353 {
354         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
355         struct sockaddr_bt *sa, ssa;
356         int e;
357
358         sa = &ssa;
359         bzero(sa, sizeof *sa);
360         sa->bt_len = sizeof(struct sockaddr_bt);
361         sa->bt_family = AF_BLUETOOTH;
362         e = rfcomm_peeraddr(pcb, sa);;
363         *nam = dup_sockaddr((struct sockaddr *)sa);
364         return (e);
365 }
366
367 static int
368 rfcomm_ssockaddr (struct socket *so, struct sockaddr **nam)
369 {
370         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
371         struct sockaddr_bt *sa, ssa;
372         int e;
373
374         sa = &ssa;
375         bzero(sa, sizeof *sa);
376         sa->bt_len = sizeof(struct sockaddr_bt);
377         sa->bt_family = AF_BLUETOOTH;
378         e = rfcomm_sockaddr(pcb, sa);;
379         *nam = dup_sockaddr((struct sockaddr *)sa);
380         return (e);
381 }
382
383 static int
384 rfcomm_sshutdown (struct socket *so)
385 {
386         socantsendmore(so);
387         return 0;
388 }
389
390 static int
391 rfcomm_ssend (struct socket *so, int flags, struct mbuf *m,
392     struct sockaddr *addr, struct mbuf *control, struct thread *td)
393 {
394         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
395         struct mbuf *m0;
396
397         KKASSERT(m != NULL);
398
399         if (control)    /* no use for that */
400                 m_freem(control);
401
402         m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
403         if (m0 == NULL)
404                 return ENOMEM;
405
406         sbappendstream(&so->so_snd.sb, m);
407
408         return rfcomm_send(pcb, m0);
409 }
410
411 static int
412 rfcomm_saccept(struct socket *so, struct sockaddr **nam)
413 {
414         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
415         struct sockaddr_bt *sa, ssa;
416         int e;
417
418         sa = &ssa;
419         bzero(sa, sizeof *sa);
420         sa->bt_len = sizeof(struct sockaddr_bt);
421         sa->bt_family = AF_BLUETOOTH;
422         e = rfcomm_peeraddr(pcb, sa);;
423         *nam = dup_sockaddr((struct sockaddr *)sa);
424         return (e);
425 }
426
427 static int
428 rfcomm_slisten(struct socket *so, struct thread *td)
429 {
430         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
431         return rfcomm_listen(pcb);
432 }
433
434 static int
435 rfcomm_srcvd(struct socket *so, int flags)
436 {
437         struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb; 
438         return rfcomm_rcvd(pcb, sbspace(&so->so_rcv));
439 }
440
441 struct pr_usrreqs rfcomm_usrreqs = {
442         .pru_abort = rfcomm_sabort,
443         .pru_accept = rfcomm_saccept,
444         .pru_attach = rfcomm_sattach,
445         .pru_bind = rfcomm_sbind,
446         .pru_connect = rfcomm_sconnect,
447         .pru_connect2 = pru_connect2_notsupp,
448         .pru_control = rfcomm_scontrol,
449         .pru_detach = rfcomm_sdetach,
450         .pru_disconnect = rfcomm_sdisconnect,
451         .pru_listen = rfcomm_slisten,
452         .pru_peeraddr = rfcomm_speeraddr,
453         .pru_rcvd = rfcomm_srcvd,
454         .pru_rcvoob = pru_rcvoob_notsupp,
455         .pru_send = rfcomm_ssend,
456         .pru_sense = pru_sense_null,
457         .pru_shutdown = rfcomm_sshutdown,
458         .pru_sockaddr = rfcomm_ssockaddr,
459         .pru_sosend = sosend,
460         .pru_soreceive = soreceive,
461         .pru_sopoll = sopoll
462 };