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