xref: /dflybsd-src/sys/netbt/rfcomm_socket.c (revision 93bffecadc0caefc46f12b736eab0e62c2b6f42e)
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 /*
255  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
256  *	 will sofree() it when we return.
257  */
258 static int
259 rfcomm_sabort (struct socket *so)
260 {
261 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
262 	int error;
263 
264 	rfcomm_disconnect(pcb, 0);
265 	soisdisconnected(so);
266 	error = rfcomm_sdetach(so);
267 	return error;
268 }
269 
270 static int
271 rfcomm_sdisconnect (struct socket *so)
272 {
273 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
274 
275 	soisdisconnecting(so);
276 	return rfcomm_disconnect(pcb, so->so_linger);
277 }
278 
279 static int
280 rfcomm_scontrol (struct socket *so, u_long cmd, caddr_t data,
281 				    struct ifnet *ifp, struct thread *td)
282 {
283 	return EPASSTHROUGH;
284 }
285 
286 static int
287 rfcomm_sattach (struct socket *so, int proto,
288 			       struct pru_attach_info *ai)
289 {
290 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
291 
292 	int err=0;
293 	if (pcb != NULL)
294 		return EINVAL;
295 
296 	/*
297 	 * Since we have nothing to add, we attach the DLC
298 	 * structure directly to our PCB pointer.
299 	 */
300 	err = soreserve(so, rfcomm_sendspace, rfcomm_recvspace, NULL);
301 	if (err)
302 		return err;
303 
304 	err = rfcomm_attach((struct rfcomm_dlc **)&so->so_pcb,
305 	    &rfcomm_proto, so);
306 	if (err)
307 		return err;
308 
309 	err = rfcomm_rcvd(so->so_pcb, sbspace(&so->so_rcv));
310 	if (err) {
311 		rfcomm_detach((struct rfcomm_dlc **)&so->so_pcb);
312 		return err;
313 	}
314 
315 	return 0;
316 }
317 
318 static int
319 rfcomm_sbind (struct socket *so, struct sockaddr *nam,
320 				 struct thread *td)
321 {
322 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
323 	struct sockaddr_bt *sa;
324 
325 	KKASSERT(nam != NULL);
326 	sa = (struct sockaddr_bt *)nam;
327 
328 	if (sa->bt_len != sizeof(struct sockaddr_bt))
329 		return EINVAL;
330 
331 	if (sa->bt_family != AF_BLUETOOTH)
332 		return EAFNOSUPPORT;
333 
334 	return rfcomm_bind(pcb, sa);
335 }
336 
337 static int
338 rfcomm_sconnect (struct socket *so, struct sockaddr *nam,
339 				    struct thread *td)
340 {
341 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
342 	struct sockaddr_bt *sa;
343 
344 	KKASSERT(nam != NULL);
345 	sa = (struct sockaddr_bt *)nam;
346 
347 	if (sa->bt_len != sizeof(struct sockaddr_bt))
348 		return EINVAL;
349 
350 	if (sa->bt_family != AF_BLUETOOTH)
351 		return EAFNOSUPPORT;
352 
353 	soisconnecting(so);
354 	return rfcomm_connect(pcb, sa);
355 }
356 
357 static int
358 rfcomm_speeraddr (struct socket *so, struct sockaddr **nam)
359 {
360 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
361 	struct sockaddr_bt *sa, ssa;
362 	int e;
363 
364 	sa = &ssa;
365 	bzero(sa, sizeof *sa);
366 	sa->bt_len = sizeof(struct sockaddr_bt);
367 	sa->bt_family = AF_BLUETOOTH;
368 	e = rfcomm_peeraddr(pcb, sa);;
369 	*nam = dup_sockaddr((struct sockaddr *)sa);
370 	return (e);
371 }
372 
373 static int
374 rfcomm_ssockaddr (struct socket *so, struct sockaddr **nam)
375 {
376 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
377 	struct sockaddr_bt *sa, ssa;
378 	int e;
379 
380 	sa = &ssa;
381 	bzero(sa, sizeof *sa);
382 	sa->bt_len = sizeof(struct sockaddr_bt);
383 	sa->bt_family = AF_BLUETOOTH;
384 	e = rfcomm_sockaddr(pcb, sa);;
385 	*nam = dup_sockaddr((struct sockaddr *)sa);
386 	return (e);
387 }
388 
389 static int
390 rfcomm_sshutdown (struct socket *so)
391 {
392 	socantsendmore(so);
393 	return 0;
394 }
395 
396 static int
397 rfcomm_ssend (struct socket *so, int flags, struct mbuf *m,
398     struct sockaddr *addr, struct mbuf *control, struct thread *td)
399 {
400 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
401 	struct mbuf *m0;
402 
403 	KKASSERT(m != NULL);
404 
405 	if (control)	/* no use for that */
406 		m_freem(control);
407 
408 	m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
409 	if (m0 == NULL)
410 		return ENOMEM;
411 
412 	sbappendstream(&so->so_snd.sb, m);
413 
414 	return rfcomm_send(pcb, m0);
415 }
416 
417 static int
418 rfcomm_saccept(struct socket *so, struct sockaddr **nam)
419 {
420 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
421 	struct sockaddr_bt *sa, ssa;
422 	int e;
423 
424 	sa = &ssa;
425 	bzero(sa, sizeof *sa);
426 	sa->bt_len = sizeof(struct sockaddr_bt);
427 	sa->bt_family = AF_BLUETOOTH;
428 	e = rfcomm_peeraddr(pcb, sa);;
429 	*nam = dup_sockaddr((struct sockaddr *)sa);
430 	return (e);
431 }
432 
433 static int
434 rfcomm_slisten(struct socket *so, struct thread *td)
435 {
436 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
437 	return rfcomm_listen(pcb);
438 }
439 
440 static int
441 rfcomm_srcvd(struct socket *so, int flags)
442 {
443 	struct rfcomm_dlc *pcb = (struct rfcomm_dlc *) so->so_pcb;
444 	return rfcomm_rcvd(pcb, sbspace(&so->so_rcv));
445 }
446 
447 struct pr_usrreqs rfcomm_usrreqs = {
448         .pru_abort = rfcomm_sabort,
449         .pru_accept = rfcomm_saccept,
450         .pru_attach = rfcomm_sattach,
451         .pru_bind = rfcomm_sbind,
452         .pru_connect = rfcomm_sconnect,
453         .pru_connect2 = pru_connect2_notsupp,
454         .pru_control = rfcomm_scontrol,
455         .pru_detach = rfcomm_sdetach,
456         .pru_disconnect = rfcomm_sdisconnect,
457         .pru_listen = rfcomm_slisten,
458         .pru_peeraddr = rfcomm_speeraddr,
459         .pru_rcvd = rfcomm_srcvd,
460         .pru_rcvoob = pru_rcvoob_notsupp,
461         .pru_send = rfcomm_ssend,
462         .pru_sense = pru_sense_null,
463         .pru_shutdown = rfcomm_sshutdown,
464         .pru_sockaddr = rfcomm_ssockaddr,
465         .pru_sosend = sosend,
466         .pru_soreceive = soreceive
467 };
468