xref: /dflybsd-src/sys/netbt/rfcomm_socket.c (revision 978400d3b04daf8f91ba8bb2dcc382a37ef632f4)
1 /* $OpenBSD: rfcomm_socket.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ */
2 /* $NetBSD: rfcomm_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */
3 /* $DragonFly: src/sys/netbt/rfcomm_socket.c,v 1.1 2007/12/30 20:02:56 hasso 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 #include <sys/cdefs.h>
37 
38 /* load symbolic names */
39 #ifdef BLUETOOTH_DEBUG
40 #define PRUREQUESTS
41 #define PRCOREQUESTS
42 #endif
43 
44 #include <sys/param.h>
45 #include <sys/domain.h>
46 #include <sys/kernel.h>
47 #include <sys/mbuf.h>
48 #include <sys/proc.h>
49 #include <sys/protosw.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/systm.h>
53 #include <vm/vm_zone.h>
54 
55 #include <netbt/bluetooth.h>
56 #include <netbt/hci.h>		/* XXX for EPASSTHROUGH */
57 #include <netbt/rfcomm.h>
58 
59 /****************************************************************************
60  *
61  *	RFCOMM SOCK_STREAM Sockets - serial line emulation
62  *
63  */
64 
65 static void rfcomm_connecting(void *);
66 static void rfcomm_connected(void *);
67 static void rfcomm_disconnected(void *, int);
68 static void *rfcomm_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
69 static void rfcomm_complete(void *, int);
70 static void rfcomm_linkmode(void *, int);
71 static void rfcomm_input(void *, struct mbuf *);
72 
73 static const struct btproto rfcomm_proto = {
74 	rfcomm_connecting,
75 	rfcomm_connected,
76 	rfcomm_disconnected,
77 	rfcomm_newconn,
78 	rfcomm_complete,
79 	rfcomm_linkmode,
80 	rfcomm_input,
81 };
82 
83 /* sysctl variables */
84 int rfcomm_sendspace = 4096;
85 int rfcomm_recvspace = 4096;
86 
87 /*
88  * rfcomm_ctloutput(request, socket, level, optname, opt)
89  *
90  */
91 int
92 rfcomm_ctloutput(struct socket *so, struct sockopt *sopt)
93 {
94 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
95 	struct mbuf *m;
96 	int err = 0;
97 
98 #ifdef notyet			/* XXX */
99 	DPRINTFN(2, "%s\n", prcorequests[sopt->sopt_dir]);
100 #endif
101 
102 	if (pcb == NULL)
103 		return EINVAL;
104 
105 	if (sopt->sopt_level != BTPROTO_RFCOMM)
106 		return ENOPROTOOPT;
107 
108 	switch(sopt->sopt_dir) {
109 	case PRCO_GETOPT:
110 		m = m_get(M_WAITOK, MT_DATA);
111 		crit_enter();
112 		m->m_len = rfcomm_getopt(pcb, sopt->sopt_name, mtod(m, void *));
113 		crit_exit();
114 		if (m->m_len == 0) {
115 			m_freem(m);
116 			m = NULL;
117 			err = ENOPROTOOPT;
118 		}
119 		err = sooptcopyout(sopt, mtod(m, void *), m->m_len);
120 		break;
121 
122 	case PRCO_SETOPT:
123 		err = rfcomm_setopt2(pcb, sopt->sopt_name, so, sopt);
124 
125 		break;
126 
127 	default:
128 		err = ENOPROTOOPT;
129 		break;
130 	}
131 
132 	return err;
133 }
134 
135 /**********************************************************************
136  *
137  * RFCOMM callbacks
138  */
139 
140 static void
141 rfcomm_connecting(void *arg)
142 {
143 	/* struct socket *so = arg; */
144 
145 	KKASSERT(arg != NULL);
146 	DPRINTF("Connecting\n");
147 }
148 
149 static void
150 rfcomm_connected(void *arg)
151 {
152 	struct socket *so = arg;
153 
154 	KKASSERT(so != NULL);
155 	DPRINTF("Connected\n");
156 	soisconnected(so);
157 }
158 
159 static void
160 rfcomm_disconnected(void *arg, int err)
161 {
162 	struct socket *so = arg;
163 
164 	KKASSERT(so != NULL);
165 	DPRINTF("Disconnected\n");
166 
167 	so->so_error = err;
168 	soisdisconnected(so);
169 }
170 
171 static void *
172 rfcomm_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 /*
188  * rfcomm_complete(rfcomm_dlc, length)
189  *
190  * length bytes are sent and may be removed from socket buffer
191  */
192 static void
193 rfcomm_complete(void *arg, int length)
194 {
195 	struct socket *so = arg;
196 
197 	sbdrop(&so->so_snd.sb, length);
198 	sowwakeup(so);
199 }
200 
201 /*
202  * rfcomm_linkmode(rfcomm_dlc, new)
203  *
204  * link mode change notification.
205  */
206 static void
207 rfcomm_linkmode(void *arg, int new)
208 {
209 	struct socket *so = arg;
210 	int mode;
211 
212 	DPRINTF("auth %s, encrypt %s, secure %s\n",
213 		(new & RFCOMM_LM_AUTH ? "on" : "off"),
214 		(new & RFCOMM_LM_ENCRYPT ? "on" : "off"),
215 		(new & RFCOMM_LM_SECURE ? "on" : "off"));
216 
217 	(void)rfcomm_getopt(so->so_pcb, SO_RFCOMM_LM, &mode);
218 	if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH))
219 	    || ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT))
220 	    || ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE)))
221 		rfcomm_disconnect(so->so_pcb, 0);
222 }
223 
224 /*
225  * rfcomm_input(rfcomm_dlc, mbuf)
226  */
227 static void
228 rfcomm_input(void *arg, struct mbuf *m)
229 {
230 	struct socket *so = arg;
231 
232 	KKASSERT(so != NULL);
233 
234 	if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
235 		kprintf("%s: %d bytes dropped (socket buffer full)\n",
236 			__func__, m->m_pkthdr.len);
237 		m_freem(m);
238 		return;
239 	}
240 
241 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
242 
243 	sbappendstream(&so->so_rcv.sb, m);
244 	sorwakeup(so);
245 }
246 
247 /*
248  * Implementation of usrreqs.
249  */
250 static int
251 rfcomm_sdetach(struct socket *so)
252 {
253 	return rfcomm_detach((struct rfcomm_dlc **)&so->so_pcb);
254 }
255 
256 static int
257 rfcomm_sabort (struct socket *so)
258 {
259 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
260 
261 	rfcomm_disconnect(pcb, 0);
262 	soisdisconnected(so);
263 	return rfcomm_sdetach(so);
264 }
265 
266 static int
267 rfcomm_sdisconnect (struct socket *so)
268 {
269 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
270 
271 	soisdisconnecting(so);
272 	return rfcomm_disconnect(pcb, so->so_linger);
273 }
274 
275 static int
276 rfcomm_scontrol (struct socket *so, u_long cmd, caddr_t data,
277 				    struct ifnet *ifp, struct thread *td)
278 {
279 	return EPASSTHROUGH;
280 }
281 
282 static int
283 rfcomm_sattach (struct socket *so, int proto,
284 			       struct pru_attach_info *ai)
285 {
286 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
287 
288 	int err=0;
289 	if (pcb != NULL)
290 		return EINVAL;
291 
292 	/*
293 	 * Since we have nothing to add, we attach the DLC
294 	 * structure directly to our PCB pointer.
295 	 */
296 	err = rfcomm_attach((struct rfcomm_dlc **)&so->so_pcb,
297 	    &rfcomm_proto, so);
298 	if (err)
299 		return err;
300 
301 	err = soreserve(so, rfcomm_sendspace, rfcomm_recvspace,NULL);
302 	if (err)
303 		return err;
304 
305 	err = rfcomm_rcvd(so->so_pcb, sbspace(&so->so_rcv));
306 	if (err)
307 		return err;
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 };
463