sco_socket.c revision 1.25 1 /* $NetBSD: sco_socket.c,v 1.25 2014/07/09 14:41:42 rtr Exp $ */
2
3 /*-
4 * Copyright (c) 2006 Itronix Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of Itronix Inc. may not be used to endorse
16 * or promote products derived from this software without specific
17 * prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: sco_socket.c,v 1.25 2014/07/09 14:41:42 rtr Exp $");
34
35 /* load symbolic names */
36 #ifdef BLUETOOTH_DEBUG
37 #define PRUREQUESTS
38 #define PRCOREQUESTS
39 #endif
40
41 #include <sys/param.h>
42 #include <sys/domain.h>
43 #include <sys/kernel.h>
44 #include <sys/mbuf.h>
45 #include <sys/proc.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/systm.h>
50
51 #include <netbt/bluetooth.h>
52 #include <netbt/hci.h>
53 #include <netbt/sco.h>
54
55 /*******************************************************************************
56 *
57 * SCO SOCK_SEQPACKET sockets - low latency audio data
58 */
59
60 static void sco_connecting(void *);
61 static void sco_connected(void *);
62 static void sco_disconnected(void *, int);
63 static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
64 static void sco_complete(void *, int);
65 static void sco_linkmode(void *, int);
66 static void sco_input(void *, struct mbuf *);
67
68 static const struct btproto sco_proto = {
69 sco_connecting,
70 sco_connected,
71 sco_disconnected,
72 sco_newconn,
73 sco_complete,
74 sco_linkmode,
75 sco_input,
76 };
77
78 int sco_sendspace = 4096;
79 int sco_recvspace = 4096;
80
81 static int
82 sco_attach(struct socket *so, int proto)
83 {
84 int error;
85
86 KASSERT(so->so_pcb == NULL);
87
88 if (so->so_lock == NULL) {
89 mutex_obj_hold(bt_lock);
90 so->so_lock = bt_lock;
91 solock(so);
92 }
93 KASSERT(solocked(so));
94
95 error = soreserve(so, sco_sendspace, sco_recvspace);
96 if (error) {
97 return error;
98 }
99 return sco_attach_pcb((struct sco_pcb **)&so->so_pcb, &sco_proto, so);
100 }
101
102 static void
103 sco_detach(struct socket *so)
104 {
105 KASSERT(so->so_pcb != NULL);
106 sco_detach_pcb((struct sco_pcb **)&so->so_pcb);
107 KASSERT(so->so_pcb == NULL);
108 }
109
110 static int
111 sco_accept(struct socket *so, struct mbuf *nam)
112 {
113 struct sco_pcb *pcb = so->so_pcb;
114 struct sockaddr_bt *sa;
115
116 KASSERT(solocked(so));
117 KASSERT(nam != NULL);
118
119 if (pcb == NULL)
120 return EINVAL;
121
122 sa = mtod(nam, struct sockaddr_bt *);
123 nam->m_len = sizeof(struct sockaddr_bt);
124 return sco_peeraddr_pcb(pcb, sa);
125 }
126
127 static int
128 sco_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
129 {
130 return EOPNOTSUPP;
131 }
132
133 static int
134 sco_stat(struct socket *so, struct stat *ub)
135 {
136 KASSERT(solocked(so));
137
138 return 0;
139 }
140
141 static int
142 sco_peeraddr(struct socket *so, struct mbuf *nam)
143 {
144 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
145 struct sockaddr_bt *sa;
146
147 KASSERT(solocked(so));
148 KASSERT(pcb != NULL);
149 KASSERT(nam != NULL);
150
151 sa = mtod(nam, struct sockaddr_bt *);
152 nam->m_len = sizeof(struct sockaddr_bt);
153 return sco_peeraddr_pcb(pcb, sa);
154 }
155
156 static int
157 sco_sockaddr(struct socket *so, struct mbuf *nam)
158 {
159 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
160 struct sockaddr_bt *sa;
161
162 KASSERT(solocked(so));
163 KASSERT(pcb != NULL);
164 KASSERT(nam != NULL);
165
166 sa = mtod(nam, struct sockaddr_bt *);
167 nam->m_len = sizeof(struct sockaddr_bt);
168 return sco_sockaddr_pcb(pcb, sa);
169 }
170
171 /*
172 * User Request.
173 * up is socket
174 * m is optional mbuf chain containing message
175 * nam is optional mbuf chain containing an address
176 * ctl is optional mbuf chain containing socket options
177 * l is pointer to process requesting action (if any)
178 *
179 * we are responsible for disposing of m and ctl if
180 * they are mbuf chains
181 */
182 static int
183 sco_usrreq(struct socket *up, int req, struct mbuf *m,
184 struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
185 {
186 struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb;
187 struct sockaddr_bt *sa;
188 struct mbuf *m0;
189 int err = 0;
190
191 DPRINTFN(2, "%s\n", prurequests[req]);
192 KASSERT(req != PRU_ATTACH);
193 KASSERT(req != PRU_DETACH);
194 KASSERT(req != PRU_ACCEPT);
195 KASSERT(req != PRU_CONTROL);
196 KASSERT(req != PRU_SENSE);
197 KASSERT(req != PRU_PEERADDR);
198 KASSERT(req != PRU_SOCKADDR);
199
200 switch(req) {
201 case PRU_PURGEIF:
202 return EOPNOTSUPP;
203 }
204
205 /* anything after here *requires* a pcb */
206 if (pcb == NULL) {
207 err = EINVAL;
208 goto release;
209 }
210
211 switch(req) {
212 case PRU_DISCONNECT:
213 soisdisconnecting(up);
214 return sco_disconnect(pcb, up->so_linger);
215
216 case PRU_ABORT:
217 sco_disconnect(pcb, 0);
218 soisdisconnected(up);
219 sco_detach(up);
220 return 0;
221
222 case PRU_BIND:
223 KASSERT(nam != NULL);
224 sa = mtod(nam, struct sockaddr_bt *);
225
226 if (sa->bt_len != sizeof(struct sockaddr_bt))
227 return EINVAL;
228
229 if (sa->bt_family != AF_BLUETOOTH)
230 return EAFNOSUPPORT;
231
232 return sco_bind(pcb, sa);
233
234 case PRU_CONNECT:
235 KASSERT(nam != NULL);
236 sa = mtod(nam, struct sockaddr_bt *);
237
238 if (sa->bt_len != sizeof(struct sockaddr_bt))
239 return EINVAL;
240
241 if (sa->bt_family != AF_BLUETOOTH)
242 return EAFNOSUPPORT;
243
244 soisconnecting(up);
245 return sco_connect(pcb, sa);
246
247 case PRU_SHUTDOWN:
248 socantsendmore(up);
249 break;
250
251 case PRU_SEND:
252 KASSERT(m != NULL);
253 if (m->m_pkthdr.len == 0)
254 break;
255
256 if (m->m_pkthdr.len > pcb->sp_mtu) {
257 err = EMSGSIZE;
258 break;
259 }
260
261 m0 = m_copypacket(m, M_DONTWAIT);
262 if (m0 == NULL) {
263 err = ENOMEM;
264 break;
265 }
266
267 if (ctl) /* no use for that */
268 m_freem(ctl);
269
270 sbappendrecord(&up->so_snd, m);
271 return sco_send(pcb, m0);
272
273 case PRU_RCVD:
274 case PRU_RCVOOB:
275 return EOPNOTSUPP; /* (no release) */
276
277 case PRU_LISTEN:
278 return sco_listen(pcb);
279
280 case PRU_CONNECT2:
281 case PRU_SENDOOB:
282 case PRU_FASTTIMO:
283 case PRU_SLOWTIMO:
284 case PRU_PROTORCV:
285 case PRU_PROTOSEND:
286 err = EOPNOTSUPP;
287 break;
288
289 default:
290 UNKNOWN(req);
291 err = EOPNOTSUPP;
292 break;
293 }
294
295 release:
296 if (m) m_freem(m);
297 if (ctl) m_freem(ctl);
298 return err;
299 }
300
301 /*
302 * get/set socket options
303 */
304 int
305 sco_ctloutput(int req, struct socket *so, struct sockopt *sopt)
306 {
307 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
308 int err = 0;
309
310 DPRINTFN(2, "req %s\n", prcorequests[req]);
311
312 if (pcb == NULL)
313 return EINVAL;
314
315 if (sopt->sopt_level != BTPROTO_SCO)
316 return ENOPROTOOPT;
317
318 switch(req) {
319 case PRCO_GETOPT:
320 err = sco_getopt(pcb, sopt);
321 break;
322
323 case PRCO_SETOPT:
324 err = sco_setopt(pcb, sopt);
325 break;
326
327 default:
328 err = ENOPROTOOPT;
329 break;
330 }
331
332 return err;
333 }
334
335 /*****************************************************************************
336 *
337 * SCO Protocol socket callbacks
338 *
339 */
340 static void
341 sco_connecting(void *arg)
342 {
343 struct socket *so = arg;
344
345 DPRINTF("Connecting\n");
346 soisconnecting(so);
347 }
348
349 static void
350 sco_connected(void *arg)
351 {
352 struct socket *so = arg;
353
354 DPRINTF("Connected\n");
355 soisconnected(so);
356 }
357
358 static void
359 sco_disconnected(void *arg, int err)
360 {
361 struct socket *so = arg;
362
363 DPRINTF("Disconnected (%d)\n", err);
364
365 so->so_error = err;
366 soisdisconnected(so);
367 }
368
369 static void *
370 sco_newconn(void *arg, struct sockaddr_bt *laddr,
371 struct sockaddr_bt *raddr)
372 {
373 struct socket *so = arg;
374
375 DPRINTF("New Connection\n");
376 so = sonewconn(so, false);
377 if (so == NULL)
378 return NULL;
379
380 soisconnecting(so);
381 return so->so_pcb;
382 }
383
384 static void
385 sco_complete(void *arg, int num)
386 {
387 struct socket *so = arg;
388
389 while (num-- > 0)
390 sbdroprecord(&so->so_snd);
391
392 sowwakeup(so);
393 }
394
395 static void
396 sco_linkmode(void *arg, int mode)
397 {
398 }
399
400 static void
401 sco_input(void *arg, struct mbuf *m)
402 {
403 struct socket *so = arg;
404
405 /*
406 * since this data is time sensitive, if the buffer
407 * is full we just dump data until the latest one
408 * will fit.
409 */
410
411 while (m->m_pkthdr.len > sbspace(&so->so_rcv))
412 sbdroprecord(&so->so_rcv);
413
414 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
415
416 sbappendrecord(&so->so_rcv, m);
417 sorwakeup(so);
418 }
419
420 PR_WRAP_USRREQS(sco)
421
422 #define sco_attach sco_attach_wrapper
423 #define sco_detach sco_detach_wrapper
424 #define sco_accept sco_accept_wrapper
425 #define sco_ioctl sco_ioctl_wrapper
426 #define sco_stat sco_stat_wrapper
427 #define sco_peeraddr sco_peeraddr_wrapper
428 #define sco_sockaddr sco_sockaddr_wrapper
429 #define sco_usrreq sco_usrreq_wrapper
430
431 const struct pr_usrreqs sco_usrreqs = {
432 .pr_attach = sco_attach,
433 .pr_detach = sco_detach,
434 .pr_accept = sco_accept,
435 .pr_ioctl = sco_ioctl,
436 .pr_stat = sco_stat,
437 .pr_peeraddr = sco_peeraddr,
438 .pr_sockaddr = sco_sockaddr,
439 .pr_generic = sco_usrreq,
440 };
441