sco_socket.c revision 1.21 1 /* $NetBSD: sco_socket.c,v 1.21 2014/07/07 07:09:58 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.21 2014/07/07 07:09:58 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_ioctl(struct socket *up, u_long cmd, void *nam, struct ifnet *ifp)
112 {
113 return EOPNOTSUPP;
114 }
115
116 static int
117 sco_stat(struct socket *so, struct stat *ub)
118 {
119 return EOPNOTSUPP;
120 }
121
122 /*
123 * User Request.
124 * up is socket
125 * m is optional mbuf chain containing message
126 * nam is optional mbuf chain containing an address
127 * ctl is optional mbuf chain containing socket options
128 * l is pointer to process requesting action (if any)
129 *
130 * we are responsible for disposing of m and ctl if
131 * they are mbuf chains
132 */
133 static int
134 sco_usrreq(struct socket *up, int req, struct mbuf *m,
135 struct mbuf *nam, struct mbuf *ctl, struct lwp *l)
136 {
137 struct sco_pcb *pcb = (struct sco_pcb *)up->so_pcb;
138 struct sockaddr_bt *sa;
139 struct mbuf *m0;
140 int err = 0;
141
142 DPRINTFN(2, "%s\n", prurequests[req]);
143 KASSERT(req != PRU_ATTACH);
144 KASSERT(req != PRU_DETACH);
145 KASSERT(req != PRU_CONTROL);
146 KASSERT(req != PRU_SENSE);
147
148 switch(req) {
149 case PRU_PURGEIF:
150 return EOPNOTSUPP;
151 }
152
153 /* anything after here *requires* a pcb */
154 if (pcb == NULL) {
155 err = EINVAL;
156 goto release;
157 }
158
159 switch(req) {
160 case PRU_DISCONNECT:
161 soisdisconnecting(up);
162 return sco_disconnect(pcb, up->so_linger);
163
164 case PRU_ABORT:
165 sco_disconnect(pcb, 0);
166 soisdisconnected(up);
167 sco_detach(up);
168 return 0;
169
170 case PRU_BIND:
171 KASSERT(nam != NULL);
172 sa = mtod(nam, struct sockaddr_bt *);
173
174 if (sa->bt_len != sizeof(struct sockaddr_bt))
175 return EINVAL;
176
177 if (sa->bt_family != AF_BLUETOOTH)
178 return EAFNOSUPPORT;
179
180 return sco_bind(pcb, sa);
181
182 case PRU_CONNECT:
183 KASSERT(nam != NULL);
184 sa = mtod(nam, struct sockaddr_bt *);
185
186 if (sa->bt_len != sizeof(struct sockaddr_bt))
187 return EINVAL;
188
189 if (sa->bt_family != AF_BLUETOOTH)
190 return EAFNOSUPPORT;
191
192 soisconnecting(up);
193 return sco_connect(pcb, sa);
194
195 case PRU_PEERADDR:
196 KASSERT(nam != NULL);
197 sa = mtod(nam, struct sockaddr_bt *);
198 nam->m_len = sizeof(struct sockaddr_bt);
199 return sco_peeraddr(pcb, sa);
200
201 case PRU_SOCKADDR:
202 KASSERT(nam != NULL);
203 sa = mtod(nam, struct sockaddr_bt *);
204 nam->m_len = sizeof(struct sockaddr_bt);
205 return sco_sockaddr(pcb, sa);
206
207 case PRU_SHUTDOWN:
208 socantsendmore(up);
209 break;
210
211 case PRU_SEND:
212 KASSERT(m != NULL);
213 if (m->m_pkthdr.len == 0)
214 break;
215
216 if (m->m_pkthdr.len > pcb->sp_mtu) {
217 err = EMSGSIZE;
218 break;
219 }
220
221 m0 = m_copypacket(m, M_DONTWAIT);
222 if (m0 == NULL) {
223 err = ENOMEM;
224 break;
225 }
226
227 if (ctl) /* no use for that */
228 m_freem(ctl);
229
230 sbappendrecord(&up->so_snd, m);
231 return sco_send(pcb, m0);
232
233 case PRU_RCVD:
234 case PRU_RCVOOB:
235 return EOPNOTSUPP; /* (no release) */
236
237 case PRU_LISTEN:
238 return sco_listen(pcb);
239
240 case PRU_ACCEPT:
241 KASSERT(nam != NULL);
242 sa = mtod(nam, struct sockaddr_bt *);
243 nam->m_len = sizeof(struct sockaddr_bt);
244 return sco_peeraddr(pcb, sa);
245
246 case PRU_CONNECT2:
247 case PRU_SENDOOB:
248 case PRU_FASTTIMO:
249 case PRU_SLOWTIMO:
250 case PRU_PROTORCV:
251 case PRU_PROTOSEND:
252 err = EOPNOTSUPP;
253 break;
254
255 default:
256 UNKNOWN(req);
257 err = EOPNOTSUPP;
258 break;
259 }
260
261 release:
262 if (m) m_freem(m);
263 if (ctl) m_freem(ctl);
264 return err;
265 }
266
267 /*
268 * get/set socket options
269 */
270 int
271 sco_ctloutput(int req, struct socket *so, struct sockopt *sopt)
272 {
273 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
274 int err = 0;
275
276 DPRINTFN(2, "req %s\n", prcorequests[req]);
277
278 if (pcb == NULL)
279 return EINVAL;
280
281 if (sopt->sopt_level != BTPROTO_SCO)
282 return ENOPROTOOPT;
283
284 switch(req) {
285 case PRCO_GETOPT:
286 err = sco_getopt(pcb, sopt);
287 break;
288
289 case PRCO_SETOPT:
290 err = sco_setopt(pcb, sopt);
291 break;
292
293 default:
294 err = ENOPROTOOPT;
295 break;
296 }
297
298 return err;
299 }
300
301 /*****************************************************************************
302 *
303 * SCO Protocol socket callbacks
304 *
305 */
306 static void
307 sco_connecting(void *arg)
308 {
309 struct socket *so = arg;
310
311 DPRINTF("Connecting\n");
312 soisconnecting(so);
313 }
314
315 static void
316 sco_connected(void *arg)
317 {
318 struct socket *so = arg;
319
320 DPRINTF("Connected\n");
321 soisconnected(so);
322 }
323
324 static void
325 sco_disconnected(void *arg, int err)
326 {
327 struct socket *so = arg;
328
329 DPRINTF("Disconnected (%d)\n", err);
330
331 so->so_error = err;
332 soisdisconnected(so);
333 }
334
335 static void *
336 sco_newconn(void *arg, struct sockaddr_bt *laddr,
337 struct sockaddr_bt *raddr)
338 {
339 struct socket *so = arg;
340
341 DPRINTF("New Connection\n");
342 so = sonewconn(so, false);
343 if (so == NULL)
344 return NULL;
345
346 soisconnecting(so);
347 return so->so_pcb;
348 }
349
350 static void
351 sco_complete(void *arg, int num)
352 {
353 struct socket *so = arg;
354
355 while (num-- > 0)
356 sbdroprecord(&so->so_snd);
357
358 sowwakeup(so);
359 }
360
361 static void
362 sco_linkmode(void *arg, int mode)
363 {
364 }
365
366 static void
367 sco_input(void *arg, struct mbuf *m)
368 {
369 struct socket *so = arg;
370
371 /*
372 * since this data is time sensitive, if the buffer
373 * is full we just dump data until the latest one
374 * will fit.
375 */
376
377 while (m->m_pkthdr.len > sbspace(&so->so_rcv))
378 sbdroprecord(&so->so_rcv);
379
380 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
381
382 sbappendrecord(&so->so_rcv, m);
383 sorwakeup(so);
384 }
385
386 PR_WRAP_USRREQS(sco)
387
388 #define sco_attach sco_attach_wrapper
389 #define sco_detach sco_detach_wrapper
390 #define sco_ioctl sco_ioctl_wrapper
391 #define sco_stat sco_stat_wrapper
392 #define sco_usrreq sco_usrreq_wrapper
393
394 const struct pr_usrreqs sco_usrreqs = {
395 .pr_attach = sco_attach,
396 .pr_detach = sco_detach,
397 .pr_ioctl = sco_ioctl,
398 .pr_stat = sco_stat,
399 .pr_generic = sco_usrreq,
400 };
401