1 | /* $NetBSD: rfcomm_socket.c,v 1.37 2015/05/02 17:18:03 rtr Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2006 Itronix Inc. |
5 | * All rights reserved. |
6 | * |
7 | * Written by Iain Hibbert for Itronix Inc. |
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 | __KERNEL_RCSID(0, "$NetBSD: rfcomm_socket.c,v 1.37 2015/05/02 17:18:03 rtr Exp $" ); |
36 | |
37 | /* load symbolic names */ |
38 | #ifdef BLUETOOTH_DEBUG |
39 | #define PRUREQUESTS |
40 | #define PRCOREQUESTS |
41 | #endif |
42 | |
43 | #include <sys/param.h> |
44 | #include <sys/domain.h> |
45 | #include <sys/kernel.h> |
46 | #include <sys/mbuf.h> |
47 | #include <sys/proc.h> |
48 | #include <sys/protosw.h> |
49 | #include <sys/socket.h> |
50 | #include <sys/socketvar.h> |
51 | #include <sys/systm.h> |
52 | |
53 | #include <netbt/bluetooth.h> |
54 | #include <netbt/rfcomm.h> |
55 | |
56 | /**************************************************************************** |
57 | * |
58 | * RFCOMM SOCK_STREAM Sockets - serial line emulation |
59 | * |
60 | */ |
61 | |
62 | static void rfcomm_connecting(void *); |
63 | static void rfcomm_connected(void *); |
64 | static void rfcomm_disconnected(void *, int); |
65 | static void *rfcomm_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); |
66 | static void rfcomm_complete(void *, int); |
67 | static void rfcomm_linkmode(void *, int); |
68 | static void rfcomm_input(void *, struct mbuf *); |
69 | |
70 | static const struct btproto rfcomm_proto = { |
71 | rfcomm_connecting, |
72 | rfcomm_connected, |
73 | rfcomm_disconnected, |
74 | rfcomm_newconn, |
75 | rfcomm_complete, |
76 | rfcomm_linkmode, |
77 | rfcomm_input, |
78 | }; |
79 | |
80 | /* sysctl variables */ |
81 | int rfcomm_sendspace = 4096; |
82 | int rfcomm_recvspace = 4096; |
83 | |
84 | static int |
85 | rfcomm_attach(struct socket *so, int proto) |
86 | { |
87 | int error; |
88 | |
89 | KASSERT(so->so_pcb == NULL); |
90 | |
91 | if (so->so_lock == NULL) { |
92 | mutex_obj_hold(bt_lock); |
93 | so->so_lock = bt_lock; |
94 | solock(so); |
95 | } |
96 | KASSERT(solocked(so)); |
97 | |
98 | /* |
99 | * Since we have nothing to add, we attach the DLC |
100 | * structure directly to our PCB pointer. |
101 | */ |
102 | error = soreserve(so, rfcomm_sendspace, rfcomm_recvspace); |
103 | if (error) |
104 | return error; |
105 | |
106 | error = rfcomm_attach_pcb((struct rfcomm_dlc **)&so->so_pcb, |
107 | &rfcomm_proto, so); |
108 | if (error) |
109 | return error; |
110 | |
111 | error = rfcomm_rcvd_pcb(so->so_pcb, sbspace(&so->so_rcv)); |
112 | if (error) { |
113 | rfcomm_detach_pcb((struct rfcomm_dlc **)&so->so_pcb); |
114 | return error; |
115 | } |
116 | return 0; |
117 | } |
118 | |
119 | static void |
120 | rfcomm_detach(struct socket *so) |
121 | { |
122 | KASSERT(so->so_pcb != NULL); |
123 | rfcomm_detach_pcb((struct rfcomm_dlc **)&so->so_pcb); |
124 | KASSERT(so->so_pcb == NULL); |
125 | } |
126 | |
127 | static int |
128 | rfcomm_accept(struct socket *so, struct sockaddr *nam) |
129 | { |
130 | struct rfcomm_dlc *pcb = so->so_pcb; |
131 | |
132 | KASSERT(solocked(so)); |
133 | KASSERT(nam != NULL); |
134 | |
135 | if (pcb == NULL) |
136 | return EINVAL; |
137 | |
138 | return rfcomm_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam); |
139 | } |
140 | |
141 | static int |
142 | rfcomm_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) |
143 | { |
144 | struct rfcomm_dlc *pcb = so->so_pcb; |
145 | struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; |
146 | |
147 | KASSERT(solocked(so)); |
148 | KASSERT(nam != NULL); |
149 | |
150 | if (pcb == NULL) |
151 | return EINVAL; |
152 | |
153 | if (sa->bt_len != sizeof(struct sockaddr_bt)) |
154 | return EINVAL; |
155 | |
156 | if (sa->bt_family != AF_BLUETOOTH) |
157 | return EAFNOSUPPORT; |
158 | |
159 | return rfcomm_bind_pcb(pcb, sa); |
160 | } |
161 | |
162 | static int |
163 | rfcomm_listen(struct socket *so, struct lwp *l) |
164 | { |
165 | struct rfcomm_dlc *pcb = so->so_pcb; |
166 | |
167 | KASSERT(solocked(so)); |
168 | |
169 | if (pcb == NULL) |
170 | return EINVAL; |
171 | |
172 | return rfcomm_listen_pcb(pcb); |
173 | } |
174 | |
175 | static int |
176 | rfcomm_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) |
177 | { |
178 | struct rfcomm_dlc *pcb = so->so_pcb; |
179 | struct sockaddr_bt *sa = (struct sockaddr_bt *)nam; |
180 | |
181 | KASSERT(solocked(so)); |
182 | KASSERT(nam != NULL); |
183 | |
184 | if (pcb == NULL) |
185 | return EINVAL; |
186 | |
187 | if (sa->bt_len != sizeof(struct sockaddr_bt)) |
188 | return EINVAL; |
189 | |
190 | if (sa->bt_family != AF_BLUETOOTH) |
191 | return EAFNOSUPPORT; |
192 | |
193 | soisconnecting(so); |
194 | return rfcomm_connect_pcb(pcb, sa); |
195 | } |
196 | |
197 | static int |
198 | rfcomm_connect2(struct socket *so, struct socket *so2) |
199 | { |
200 | struct rfcomm_dlc *pcb = so->so_pcb; |
201 | |
202 | KASSERT(solocked(so)); |
203 | |
204 | if (pcb == NULL) |
205 | return EINVAL; |
206 | |
207 | return EOPNOTSUPP; |
208 | } |
209 | |
210 | static int |
211 | rfcomm_disconnect(struct socket *so) |
212 | { |
213 | struct rfcomm_dlc *pcb = so->so_pcb; |
214 | |
215 | KASSERT(solocked(so)); |
216 | |
217 | if (pcb == NULL) |
218 | return EINVAL; |
219 | |
220 | soisdisconnecting(so); |
221 | return rfcomm_disconnect_pcb(pcb, so->so_linger); |
222 | } |
223 | |
224 | static int |
225 | rfcomm_shutdown(struct socket *so) |
226 | { |
227 | KASSERT(solocked(so)); |
228 | |
229 | socantsendmore(so); |
230 | return 0; |
231 | } |
232 | |
233 | static int |
234 | rfcomm_abort(struct socket *so) |
235 | { |
236 | struct rfcomm_dlc *pcb = so->so_pcb; |
237 | |
238 | KASSERT(solocked(so)); |
239 | |
240 | if (pcb == NULL) |
241 | return EINVAL; |
242 | |
243 | rfcomm_disconnect_pcb(pcb, 0); |
244 | soisdisconnected(so); |
245 | rfcomm_detach(so); |
246 | return 0; |
247 | } |
248 | |
249 | static int |
250 | rfcomm_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) |
251 | { |
252 | return EPASSTHROUGH; |
253 | } |
254 | |
255 | static int |
256 | rfcomm_stat(struct socket *so, struct stat *ub) |
257 | { |
258 | KASSERT(solocked(so)); |
259 | |
260 | return 0; |
261 | } |
262 | |
263 | static int |
264 | rfcomm_peeraddr(struct socket *so, struct sockaddr *nam) |
265 | { |
266 | struct rfcomm_dlc *pcb = so->so_pcb; |
267 | |
268 | KASSERT(solocked(so)); |
269 | KASSERT(pcb != NULL); |
270 | KASSERT(nam != NULL); |
271 | |
272 | return rfcomm_peeraddr_pcb(pcb, (struct sockaddr_bt *)nam); |
273 | } |
274 | |
275 | static int |
276 | rfcomm_sockaddr(struct socket *so, struct sockaddr *nam) |
277 | { |
278 | struct rfcomm_dlc *pcb = so->so_pcb; |
279 | |
280 | KASSERT(solocked(so)); |
281 | KASSERT(pcb != NULL); |
282 | KASSERT(nam != NULL); |
283 | |
284 | return rfcomm_sockaddr_pcb(pcb, (struct sockaddr_bt *)nam); |
285 | } |
286 | |
287 | static int |
288 | rfcomm_rcvd(struct socket *so, int flags, struct lwp *l) |
289 | { |
290 | struct rfcomm_dlc *pcb = so->so_pcb; |
291 | |
292 | KASSERT(solocked(so)); |
293 | |
294 | if (pcb == NULL) |
295 | return EINVAL; |
296 | |
297 | return rfcomm_rcvd_pcb(pcb, sbspace(&so->so_rcv)); |
298 | } |
299 | |
300 | static int |
301 | rfcomm_recvoob(struct socket *so, struct mbuf *m, int flags) |
302 | { |
303 | KASSERT(solocked(so)); |
304 | |
305 | return EOPNOTSUPP; |
306 | } |
307 | |
308 | static int |
309 | rfcomm_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, |
310 | struct mbuf *control, struct lwp *l) |
311 | { |
312 | struct rfcomm_dlc *pcb = so->so_pcb; |
313 | int err = 0; |
314 | struct mbuf *m0; |
315 | |
316 | KASSERT(solocked(so)); |
317 | KASSERT(m != NULL); |
318 | |
319 | if (control) /* no use for that */ |
320 | m_freem(control); |
321 | |
322 | if (pcb == NULL) { |
323 | err = EINVAL; |
324 | goto release; |
325 | } |
326 | |
327 | m0 = m_copypacket(m, M_DONTWAIT); |
328 | if (m0 == NULL) { |
329 | err = ENOMEM; |
330 | goto release; |
331 | } |
332 | |
333 | sbappendstream(&so->so_snd, m); |
334 | return rfcomm_send_pcb(pcb, m0); |
335 | |
336 | release: |
337 | m_freem(m); |
338 | return err; |
339 | } |
340 | |
341 | static int |
342 | rfcomm_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) |
343 | { |
344 | KASSERT(solocked(so)); |
345 | |
346 | if (m) |
347 | m_freem(m); |
348 | if (control) |
349 | m_freem(control); |
350 | |
351 | return EOPNOTSUPP; |
352 | } |
353 | |
354 | static int |
355 | rfcomm_purgeif(struct socket *so, struct ifnet *ifp) |
356 | { |
357 | |
358 | return EOPNOTSUPP; |
359 | } |
360 | |
361 | /* |
362 | * rfcomm_ctloutput(req, socket, sockopt) |
363 | * |
364 | */ |
365 | int |
366 | rfcomm_ctloutput(int req, struct socket *so, struct sockopt *sopt) |
367 | { |
368 | struct rfcomm_dlc *pcb = so->so_pcb; |
369 | int err = 0; |
370 | |
371 | DPRINTFN(2, "%s\n" , prcorequests[req]); |
372 | |
373 | if (pcb == NULL) |
374 | return EINVAL; |
375 | |
376 | if (sopt->sopt_level != BTPROTO_RFCOMM) |
377 | return ENOPROTOOPT; |
378 | |
379 | switch(req) { |
380 | case PRCO_GETOPT: |
381 | err = rfcomm_getopt(pcb, sopt); |
382 | break; |
383 | |
384 | case PRCO_SETOPT: |
385 | err = rfcomm_setopt(pcb, sopt); |
386 | break; |
387 | |
388 | default: |
389 | err = ENOPROTOOPT; |
390 | break; |
391 | } |
392 | |
393 | return err; |
394 | } |
395 | |
396 | /********************************************************************** |
397 | * |
398 | * RFCOMM callbacks |
399 | */ |
400 | |
401 | static void |
402 | rfcomm_connecting(void *arg) |
403 | { |
404 | /* struct socket *so = arg; */ |
405 | |
406 | KASSERT(arg != NULL); |
407 | DPRINTF("Connecting\n" ); |
408 | } |
409 | |
410 | static void |
411 | rfcomm_connected(void *arg) |
412 | { |
413 | struct socket *so = arg; |
414 | |
415 | KASSERT(so != NULL); |
416 | DPRINTF("Connected\n" ); |
417 | soisconnected(so); |
418 | } |
419 | |
420 | static void |
421 | rfcomm_disconnected(void *arg, int err) |
422 | { |
423 | struct socket *so = arg; |
424 | |
425 | KASSERT(so != NULL); |
426 | DPRINTF("Disconnected\n" ); |
427 | |
428 | so->so_error = err; |
429 | soisdisconnected(so); |
430 | } |
431 | |
432 | static void * |
433 | rfcomm_newconn(void *arg, struct sockaddr_bt *laddr, |
434 | struct sockaddr_bt *raddr) |
435 | { |
436 | struct socket *so = arg; |
437 | |
438 | DPRINTF("New Connection\n" ); |
439 | so = sonewconn(so, false); |
440 | if (so == NULL) |
441 | return NULL; |
442 | |
443 | soisconnecting(so); |
444 | |
445 | return so->so_pcb; |
446 | } |
447 | |
448 | /* |
449 | * rfcomm_complete(rfcomm_dlc, length) |
450 | * |
451 | * length bytes are sent and may be removed from socket buffer |
452 | */ |
453 | static void |
454 | rfcomm_complete(void *arg, int length) |
455 | { |
456 | struct socket *so = arg; |
457 | |
458 | sbdrop(&so->so_snd, length); |
459 | sowwakeup(so); |
460 | } |
461 | |
462 | /* |
463 | * rfcomm_linkmode(rfcomm_dlc, new) |
464 | * |
465 | * link mode change notification. |
466 | */ |
467 | static void |
468 | rfcomm_linkmode(void *arg, int new) |
469 | { |
470 | struct socket *so = arg; |
471 | struct sockopt sopt; |
472 | int mode; |
473 | |
474 | DPRINTF("auth %s, encrypt %s, secure %s\n" , |
475 | (new & RFCOMM_LM_AUTH ? "on" : "off" ), |
476 | (new & RFCOMM_LM_ENCRYPT ? "on" : "off" ), |
477 | (new & RFCOMM_LM_SECURE ? "on" : "off" )); |
478 | |
479 | sockopt_init(&sopt, BTPROTO_RFCOMM, SO_RFCOMM_LM, 0); |
480 | (void)rfcomm_getopt(so->so_pcb, &sopt); |
481 | (void)sockopt_getint(&sopt, &mode); |
482 | sockopt_destroy(&sopt); |
483 | |
484 | if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH)) |
485 | || ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT)) |
486 | || ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE))) |
487 | rfcomm_disconnect_pcb(so->so_pcb, 0); |
488 | } |
489 | |
490 | /* |
491 | * rfcomm_input(rfcomm_dlc, mbuf) |
492 | */ |
493 | static void |
494 | rfcomm_input(void *arg, struct mbuf *m) |
495 | { |
496 | struct socket *so = arg; |
497 | |
498 | KASSERT(so != NULL); |
499 | |
500 | if (m->m_pkthdr.len > sbspace(&so->so_rcv)) { |
501 | printf("%s: %d bytes dropped (socket buffer full)\n" , |
502 | __func__, m->m_pkthdr.len); |
503 | m_freem(m); |
504 | return; |
505 | } |
506 | |
507 | DPRINTFN(10, "received %d bytes\n" , m->m_pkthdr.len); |
508 | |
509 | sbappendstream(&so->so_rcv, m); |
510 | sorwakeup(so); |
511 | } |
512 | |
513 | PR_WRAP_USRREQS(rfcomm) |
514 | |
515 | #define rfcomm_attach rfcomm_attach_wrapper |
516 | #define rfcomm_detach rfcomm_detach_wrapper |
517 | #define rfcomm_accept rfcomm_accept_wrapper |
518 | #define rfcomm_bind rfcomm_bind_wrapper |
519 | #define rfcomm_listen rfcomm_listen_wrapper |
520 | #define rfcomm_connect rfcomm_connect_wrapper |
521 | #define rfcomm_connect2 rfcomm_connect2_wrapper |
522 | #define rfcomm_disconnect rfcomm_disconnect_wrapper |
523 | #define rfcomm_shutdown rfcomm_shutdown_wrapper |
524 | #define rfcomm_abort rfcomm_abort_wrapper |
525 | #define rfcomm_ioctl rfcomm_ioctl_wrapper |
526 | #define rfcomm_stat rfcomm_stat_wrapper |
527 | #define rfcomm_peeraddr rfcomm_peeraddr_wrapper |
528 | #define rfcomm_sockaddr rfcomm_sockaddr_wrapper |
529 | #define rfcomm_rcvd rfcomm_rcvd_wrapper |
530 | #define rfcomm_recvoob rfcomm_recvoob_wrapper |
531 | #define rfcomm_send rfcomm_send_wrapper |
532 | #define rfcomm_sendoob rfcomm_sendoob_wrapper |
533 | #define rfcomm_purgeif rfcomm_purgeif_wrapper |
534 | |
535 | const struct pr_usrreqs rfcomm_usrreqs = { |
536 | .pr_attach = rfcomm_attach, |
537 | .pr_detach = rfcomm_detach, |
538 | .pr_accept = rfcomm_accept, |
539 | .pr_bind = rfcomm_bind, |
540 | .pr_listen = rfcomm_listen, |
541 | .pr_connect = rfcomm_connect, |
542 | .pr_connect2 = rfcomm_connect2, |
543 | .pr_disconnect = rfcomm_disconnect, |
544 | .pr_shutdown = rfcomm_shutdown, |
545 | .pr_abort = rfcomm_abort, |
546 | .pr_ioctl = rfcomm_ioctl, |
547 | .pr_stat = rfcomm_stat, |
548 | .pr_peeraddr = rfcomm_peeraddr, |
549 | .pr_sockaddr = rfcomm_sockaddr, |
550 | .pr_rcvd = rfcomm_rcvd, |
551 | .pr_recvoob = rfcomm_recvoob, |
552 | .pr_send = rfcomm_send, |
553 | .pr_sendoob = rfcomm_sendoob, |
554 | .pr_purgeif = rfcomm_purgeif, |
555 | }; |
556 | |