xref: /dflybsd-src/sys/netbt/sco_socket.c (revision 93bffecadc0caefc46f12b736eab0e62c2b6f42e)
1 /* $OpenBSD: sco_socket.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ */
2 /* $NetBSD: sco_socket.c,v 1.9 2007/04/21 06:15:23 plunky Exp $ */
3 
4 /*-
5  * Copyright (c) 2006 Itronix Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of Itronix Inc. may not be used to endorse
17  *    or promote products derived from this software without specific
18  *    prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27  * ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /* load symbolic names */
34 #ifdef BLUETOOTH_DEBUG
35 #define PRUREQUESTS
36 #define PRCOREQUESTS
37 #endif
38 
39 #include <sys/param.h>
40 #include <sys/domain.h>
41 #include <sys/kernel.h>
42 #include <sys/mbuf.h>
43 #include <sys/proc.h>
44 #include <sys/protosw.h>
45 #include <sys/socket.h>
46 #include <sys/socketvar.h>
47 #include <sys/systm.h>
48 #include <sys/bus.h>
49 
50 #include <netbt/bluetooth.h>
51 #include <netbt/hci.h>
52 #include <netbt/sco.h>
53 
54 /*******************************************************************************
55  *
56  * SCO SOCK_SEQPACKET sockets - low latency audio data
57  */
58 
59 static void sco_connecting(void *);
60 static void sco_connected(void *);
61 static void sco_disconnected(void *, int);
62 static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
63 static void sco_complete(void *, int);
64 static void sco_linkmode(void *, int);
65 static void sco_input(void *, struct mbuf *);
66 
67 static const struct btproto sco_proto = {
68 	sco_connecting,
69 	sco_connected,
70 	sco_disconnected,
71 	sco_newconn,
72 	sco_complete,
73 	sco_linkmode,
74 	sco_input,
75 };
76 
77 int sco_sendspace = 4096;
78 int sco_recvspace = 4096;
79 
80 /*
81  * get/set socket options
82  */
83 int
84 sco_ctloutput(struct socket *so, struct sockopt *sopt)
85 {
86 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
87 	struct mbuf *m;
88 	int err = 0;
89 
90 #ifdef notyet			/* XXX */
91 	DPRINTFN(2, "req %s\n", prcorequests[req]);
92 #endif
93 
94 	if (pcb == NULL)
95 		return EINVAL;
96 
97 	if (sopt->sopt_level != BTPROTO_SCO)
98 		return ENOPROTOOPT;
99 
100 	switch(sopt->sopt_dir) {
101 	case PRCO_GETOPT:
102 		m = m_get(MB_WAIT, MT_DATA);
103 		m->m_len = sco_getopt(pcb, sopt->sopt_name, mtod(m, uint8_t *));
104 		if (m->m_len == 0) {
105 			m_freem(m);
106 			m = NULL;
107 			err = ENOPROTOOPT;
108 		}
109 		/* *opt = m; */
110 		/* XXX There are possible memory leaks (Griffin) */
111 		soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
112 		break;
113 
114 	case PRCO_SETOPT:
115 		m = m_get(M_WAITOK, MT_DATA);
116 		KKASSERT(m != NULL);
117 		err = soopt_to_kbuf(sopt, mtod(m,void*), m->m_len, m->m_len);
118 
119 		if (m->m_len == 0) {
120 			m_freem(m);
121 			m = NULL;
122 			err = EIO;
123 		}
124 
125 		err = sco_setopt(pcb, sopt->sopt_name, mtod(m, uint8_t *));
126 		m_freem(m);
127 		break;
128 
129 	default:
130 		err = ENOPROTOOPT;
131 		break;
132 	}
133 
134 	return err;
135 }
136 
137 /*****************************************************************************
138  *
139  *	SCO Protocol socket callbacks
140  *
141  */
142 static void
143 sco_connecting(void *arg)
144 {
145 	struct socket *so = arg;
146 
147 	DPRINTF("Connecting\n");
148 	soisconnecting(so);
149 }
150 
151 static void
152 sco_connected(void *arg)
153 {
154 	struct socket *so = arg;
155 
156 	DPRINTF("Connected\n");
157 	soisconnected(so);
158 }
159 
160 static void
161 sco_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 sco_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 	return so->so_pcb;
184 }
185 
186 static void
187 sco_complete(void *arg, int num)
188 {
189 	struct socket *so = arg;
190 
191 	while (num-- > 0)
192 		sbdroprecord(&so->so_snd.sb);
193 
194 	sowwakeup(so);
195 }
196 
197 static void
198 sco_linkmode(void *arg, int mode)
199 {
200 }
201 
202 static void
203 sco_input(void *arg, struct mbuf *m)
204 {
205 	struct socket *so = arg;
206 
207 	/*
208 	 * since this data is time sensitive, if the buffer
209 	 * is full we just dump data until the latest one
210 	 * will fit.
211 	 */
212 
213 	while (m->m_pkthdr.len > sbspace(&so->so_rcv))
214 		sbdroprecord(&so->so_rcv.sb);
215 
216 	DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
217 
218 	sbappendrecord(&so->so_rcv.sb, m);
219 	sorwakeup(so);
220 }
221 
222 /*
223  * Implementation of usrreqs.
224  */
225 static int
226 sco_sdetach(struct socket *so)
227 {
228 	return sco_detach((struct sco_pcb **)&so->so_pcb);
229 }
230 
231 /*
232  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
233  *	 will sofree() it when we return.
234  */
235 static int
236 sco_sabort (struct socket *so)
237 {
238 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
239 	int error;
240 
241 	sco_disconnect(pcb, 0);
242 	soisdisconnected(so);
243 	error = sco_sdetach(so);
244 
245 	return error;
246 }
247 
248 static int
249 sco_sdisconnect (struct socket *so)
250 {
251  	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
252 
253 	soisdisconnecting(so);
254 
255 	return sco_disconnect(pcb, so->so_linger);
256 }
257 
258 static int
259 sco_sattach (struct socket *so, int proto,
260     struct pru_attach_info *ai)
261 {
262 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
263 	int err=0;
264 
265 	if (pcb)
266 		return EINVAL;
267 
268 	err = soreserve(so, sco_sendspace, sco_recvspace,NULL);
269 	if (err)
270 		return err;
271 
272 	return sco_attach((struct sco_pcb **)&so->so_pcb,
273 	    &sco_proto, so);
274 }
275 
276 static int
277 sco_sbind (struct socket *so, struct sockaddr *nam,
278 				 struct thread *td)
279 {
280 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
281 	struct sockaddr_bt *sa;
282 
283 	KKASSERT(nam != NULL);
284 	sa = (struct sockaddr_bt *)nam;
285 
286 	if (sa->bt_len != sizeof(struct sockaddr_bt))
287 		return EINVAL;
288 
289 	if (sa->bt_family != AF_BLUETOOTH)
290 		return EAFNOSUPPORT;
291 
292 	return sco_bind(pcb, sa);
293 }
294 
295 static int
296 sco_sconnect (struct socket *so, struct sockaddr *nam,
297 				    struct thread *td)
298 {
299 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
300 	struct sockaddr_bt *sa;
301 
302 	KKASSERT(nam != NULL);
303 	sa = (struct sockaddr_bt *)nam;
304 
305 	if (sa->bt_len != sizeof(struct sockaddr_bt))
306 		return EINVAL;
307 
308 	if (sa->bt_family != AF_BLUETOOTH)
309 		return EAFNOSUPPORT;
310 
311 	soisconnecting(so);
312 	return sco_connect(pcb, sa);
313 }
314 
315 static int
316 sco_speeraddr (struct socket *so, struct sockaddr **nam)
317 {
318 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
319 	struct sockaddr_bt *sa, ssa;
320 	int e;
321 
322 	sa = &ssa;
323 	bzero(sa, sizeof *sa);
324 	sa->bt_len = sizeof(struct sockaddr_bt);
325 	sa->bt_family = AF_BLUETOOTH;
326 	e = sco_peeraddr(pcb, sa);
327 	*nam = dup_sockaddr((struct sockaddr *)sa);
328 
329 	return (e);
330 }
331 
332 static int
333 sco_ssockaddr (struct socket *so, struct sockaddr **nam)
334 {
335 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
336 	struct sockaddr_bt *sa, ssa;
337 	int e;
338 
339 	sa = &ssa;
340 	bzero(sa, sizeof *sa);
341 	sa->bt_len = sizeof(struct sockaddr_bt);
342 	sa->bt_family = AF_BLUETOOTH;
343 	e = sco_sockaddr(pcb, sa);
344 	*nam = dup_sockaddr((struct sockaddr *)sa);
345 
346 	return (e);
347 }
348 
349 static int
350 sco_sshutdown (struct socket *so)
351 {
352 	socantsendmore(so);
353 	return 0;
354 }
355 
356 static int
357 sco_ssend (struct socket *so, int flags, struct mbuf *m,
358     struct sockaddr *addr, struct mbuf *control, struct thread *td)
359 {
360 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
361 	struct mbuf *m0;
362 	int err = 0;
363 
364 	KKASSERT(m != NULL);
365 	if (m->m_pkthdr.len == 0)
366 		goto error;
367 
368 	if (m->m_pkthdr.len > pcb->sp_mtu) {
369 		err = EMSGSIZE;
370 		goto error;
371 	}
372 
373 	m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
374 	if (m0 == NULL) {
375 		err = ENOMEM;
376 		goto error;
377 	}
378 
379 	if (control) /* no use for that */
380 		m_freem(control);
381 
382 	sbappendrecord(&so->so_snd.sb, m);
383 	return sco_send(pcb, m0);
384 
385 error:
386 	if (m) m_freem(m);
387 	if (control) m_freem(control);
388 	return err;
389 }
390 
391 static int
392 sco_saccept(struct socket *so, struct sockaddr **nam)
393 {
394 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
395 	struct sockaddr_bt *sa, ssa;
396 	int e;
397 
398 	sa = &ssa;
399 	bzero(sa, sizeof *sa);
400 	sa->bt_len = sizeof(struct sockaddr_bt);
401 	sa->bt_family = AF_BLUETOOTH;
402 	e = sco_peeraddr(pcb, sa);
403 	*nam = dup_sockaddr((struct sockaddr *)sa);
404 
405 	return (e);
406 }
407 
408 static int
409 sco_slisten(struct socket *so, struct thread *td)
410 {
411 	struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
412 	return sco_listen(pcb);
413 }
414 
415 
416 struct pr_usrreqs sco_usrreqs = {
417         .pru_abort = sco_sabort,
418         .pru_accept = sco_saccept,
419         .pru_attach = sco_sattach,
420         .pru_bind = sco_sbind,
421         .pru_connect = sco_sconnect,
422         .pru_connect2 = pru_connect2_notsupp,
423         .pru_control = pru_control_notsupp,
424         .pru_detach = sco_sdetach,
425         .pru_disconnect = sco_sdisconnect,
426         .pru_listen = sco_slisten,
427         .pru_peeraddr = sco_speeraddr,
428         .pru_rcvd = pru_rcvd_notsupp,
429         .pru_rcvoob = pru_rcvoob_notsupp,
430         .pru_send = sco_ssend,
431         .pru_sense = pru_sense_null,
432         .pru_shutdown = sco_sshutdown,
433         .pru_sockaddr = sco_ssockaddr,
434         .pru_sosend = sosend,
435         .pru_soreceive = soreceive
436 };
437