rfcomm_socket.c revision 1.24
1/* $NetBSD: rfcomm_socket.c,v 1.24 2014/07/09 14:41:42 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.24 2014/07/09 14:41:42 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 62static void rfcomm_connecting(void *); 63static void rfcomm_connected(void *); 64static void rfcomm_disconnected(void *, int); 65static void *rfcomm_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 66static void rfcomm_complete(void *, int); 67static void rfcomm_linkmode(void *, int); 68static void rfcomm_input(void *, struct mbuf *); 69 70static 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 */ 81int rfcomm_sendspace = 4096; 82int rfcomm_recvspace = 4096; 83 84static int 85rfcomm_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(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 119static void 120rfcomm_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 127static int 128rfcomm_accept(struct socket *so, struct mbuf *nam) 129{ 130 struct rfcomm_dlc *pcb = so->so_pcb; 131 struct sockaddr_bt *sa; 132 133 KASSERT(solocked(so)); 134 KASSERT(nam != NULL); 135 136 if (pcb == NULL) 137 return EINVAL; 138 139 sa = mtod(nam, struct sockaddr_bt *); 140 nam->m_len = sizeof(struct sockaddr_bt); 141 return rfcomm_peeraddr_pcb(pcb, sa); 142} 143 144static int 145rfcomm_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 146{ 147 return EPASSTHROUGH; 148} 149 150static int 151rfcomm_stat(struct socket *so, struct stat *ub) 152{ 153 KASSERT(solocked(so)); 154 155 return 0; 156} 157 158static int 159rfcomm_peeraddr(struct socket *so, struct mbuf *nam) 160{ 161 struct rfcomm_dlc *pcb = so->so_pcb; 162 struct sockaddr_bt *sa; 163 164 KASSERT(solocked(so)); 165 KASSERT(pcb != NULL); 166 KASSERT(nam != NULL); 167 168 sa = mtod(nam, struct sockaddr_bt *); 169 nam->m_len = sizeof(struct sockaddr_bt); 170 return rfcomm_peeraddr_pcb(pcb, sa); 171} 172 173static int 174rfcomm_sockaddr(struct socket *so, struct mbuf *nam) 175{ 176 struct rfcomm_dlc *pcb = so->so_pcb; 177 struct sockaddr_bt *sa; 178 179 KASSERT(solocked(so)); 180 KASSERT(pcb != NULL); 181 KASSERT(nam != NULL); 182 183 sa = mtod(nam, struct sockaddr_bt *); 184 nam->m_len = sizeof(struct sockaddr_bt); 185 return rfcomm_sockaddr_pcb(pcb, sa); 186} 187 188/* 189 * User Request. 190 * up is socket 191 * m is optional mbuf chain containing message 192 * nam is either 193 * optional mbuf chain containing an address 194 * message flags (PRU_RCVD) 195 * ctl is either 196 * optional mbuf chain containing socket options 197 * optional interface pointer PRU_PURGEIF 198 * l is pointer to process requesting action (if any) 199 * 200 * we are responsible for disposing of m and ctl if 201 * they are mbuf chains 202 */ 203static int 204rfcomm_usrreq(struct socket *up, int req, struct mbuf *m, 205 struct mbuf *nam, struct mbuf *ctl, struct lwp *l) 206{ 207 struct rfcomm_dlc *pcb = up->so_pcb; 208 struct sockaddr_bt *sa; 209 struct mbuf *m0; 210 int err = 0; 211 212 DPRINTFN(2, "%s\n", prurequests[req]); 213 KASSERT(req != PRU_ATTACH); 214 KASSERT(req != PRU_DETACH); 215 KASSERT(req != PRU_ACCEPT); 216 KASSERT(req != PRU_CONTROL); 217 KASSERT(req != PRU_SENSE); 218 KASSERT(req != PRU_PEERADDR); 219 KASSERT(req != PRU_SOCKADDR); 220 221 switch (req) { 222 case PRU_PURGEIF: 223 return EOPNOTSUPP; 224 } 225 if (pcb == NULL) { 226 err = EINVAL; 227 goto release; 228 } 229 230 switch(req) { 231 case PRU_DISCONNECT: 232 soisdisconnecting(up); 233 return rfcomm_disconnect(pcb, up->so_linger); 234 235 case PRU_ABORT: 236 rfcomm_disconnect(pcb, 0); 237 soisdisconnected(up); 238 rfcomm_detach(up); 239 return 0; 240 241 case PRU_BIND: 242 KASSERT(nam != NULL); 243 sa = mtod(nam, struct sockaddr_bt *); 244 245 if (sa->bt_len != sizeof(struct sockaddr_bt)) 246 return EINVAL; 247 248 if (sa->bt_family != AF_BLUETOOTH) 249 return EAFNOSUPPORT; 250 251 return rfcomm_bind(pcb, sa); 252 253 case PRU_CONNECT: 254 KASSERT(nam != NULL); 255 sa = mtod(nam, struct sockaddr_bt *); 256 257 if (sa->bt_len != sizeof(struct sockaddr_bt)) 258 return EINVAL; 259 260 if (sa->bt_family != AF_BLUETOOTH) 261 return EAFNOSUPPORT; 262 263 soisconnecting(up); 264 return rfcomm_connect(pcb, sa); 265 266 case PRU_SHUTDOWN: 267 socantsendmore(up); 268 break; 269 270 case PRU_SEND: 271 KASSERT(m != NULL); 272 273 if (ctl) /* no use for that */ 274 m_freem(ctl); 275 276 m0 = m_copypacket(m, M_DONTWAIT); 277 if (m0 == NULL) 278 return ENOMEM; 279 280 sbappendstream(&up->so_snd, m); 281 282 return rfcomm_send(pcb, m0); 283 284 case PRU_RCVD: 285 return rfcomm_rcvd(pcb, sbspace(&up->so_rcv)); 286 287 case PRU_RCVOOB: 288 return EOPNOTSUPP; /* (no release) */ 289 290 case PRU_LISTEN: 291 return rfcomm_listen(pcb); 292 293 case PRU_CONNECT2: 294 case PRU_SENDOOB: 295 case PRU_FASTTIMO: 296 case PRU_SLOWTIMO: 297 case PRU_PROTORCV: 298 case PRU_PROTOSEND: 299 err = EOPNOTSUPP; 300 break; 301 302 default: 303 UNKNOWN(req); 304 err = EOPNOTSUPP; 305 break; 306 } 307 308release: 309 if (m) m_freem(m); 310 if (ctl) m_freem(ctl); 311 return err; 312} 313 314/* 315 * rfcomm_ctloutput(req, socket, sockopt) 316 * 317 */ 318int 319rfcomm_ctloutput(int req, struct socket *so, struct sockopt *sopt) 320{ 321 struct rfcomm_dlc *pcb = so->so_pcb; 322 int err = 0; 323 324 DPRINTFN(2, "%s\n", prcorequests[req]); 325 326 if (pcb == NULL) 327 return EINVAL; 328 329 if (sopt->sopt_level != BTPROTO_RFCOMM) 330 return ENOPROTOOPT; 331 332 switch(req) { 333 case PRCO_GETOPT: 334 err = rfcomm_getopt(pcb, sopt); 335 break; 336 337 case PRCO_SETOPT: 338 err = rfcomm_setopt(pcb, sopt); 339 break; 340 341 default: 342 err = ENOPROTOOPT; 343 break; 344 } 345 346 return err; 347} 348 349/********************************************************************** 350 * 351 * RFCOMM callbacks 352 */ 353 354static void 355rfcomm_connecting(void *arg) 356{ 357 /* struct socket *so = arg; */ 358 359 KASSERT(arg != NULL); 360 DPRINTF("Connecting\n"); 361} 362 363static void 364rfcomm_connected(void *arg) 365{ 366 struct socket *so = arg; 367 368 KASSERT(so != NULL); 369 DPRINTF("Connected\n"); 370 soisconnected(so); 371} 372 373static void 374rfcomm_disconnected(void *arg, int err) 375{ 376 struct socket *so = arg; 377 378 KASSERT(so != NULL); 379 DPRINTF("Disconnected\n"); 380 381 so->so_error = err; 382 soisdisconnected(so); 383} 384 385static void * 386rfcomm_newconn(void *arg, struct sockaddr_bt *laddr, 387 struct sockaddr_bt *raddr) 388{ 389 struct socket *so = arg; 390 391 DPRINTF("New Connection\n"); 392 so = sonewconn(so, false); 393 if (so == NULL) 394 return NULL; 395 396 soisconnecting(so); 397 398 return so->so_pcb; 399} 400 401/* 402 * rfcomm_complete(rfcomm_dlc, length) 403 * 404 * length bytes are sent and may be removed from socket buffer 405 */ 406static void 407rfcomm_complete(void *arg, int length) 408{ 409 struct socket *so = arg; 410 411 sbdrop(&so->so_snd, length); 412 sowwakeup(so); 413} 414 415/* 416 * rfcomm_linkmode(rfcomm_dlc, new) 417 * 418 * link mode change notification. 419 */ 420static void 421rfcomm_linkmode(void *arg, int new) 422{ 423 struct socket *so = arg; 424 struct sockopt sopt; 425 int mode; 426 427 DPRINTF("auth %s, encrypt %s, secure %s\n", 428 (new & RFCOMM_LM_AUTH ? "on" : "off"), 429 (new & RFCOMM_LM_ENCRYPT ? "on" : "off"), 430 (new & RFCOMM_LM_SECURE ? "on" : "off")); 431 432 sockopt_init(&sopt, BTPROTO_RFCOMM, SO_RFCOMM_LM, 0); 433 (void)rfcomm_getopt(so->so_pcb, &sopt); 434 (void)sockopt_getint(&sopt, &mode); 435 sockopt_destroy(&sopt); 436 437 if (((mode & RFCOMM_LM_AUTH) && !(new & RFCOMM_LM_AUTH)) 438 || ((mode & RFCOMM_LM_ENCRYPT) && !(new & RFCOMM_LM_ENCRYPT)) 439 || ((mode & RFCOMM_LM_SECURE) && !(new & RFCOMM_LM_SECURE))) 440 rfcomm_disconnect(so->so_pcb, 0); 441} 442 443/* 444 * rfcomm_input(rfcomm_dlc, mbuf) 445 */ 446static void 447rfcomm_input(void *arg, struct mbuf *m) 448{ 449 struct socket *so = arg; 450 451 KASSERT(so != NULL); 452 453 if (m->m_pkthdr.len > sbspace(&so->so_rcv)) { 454 printf("%s: %d bytes dropped (socket buffer full)\n", 455 __func__, m->m_pkthdr.len); 456 m_freem(m); 457 return; 458 } 459 460 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 461 462 sbappendstream(&so->so_rcv, m); 463 sorwakeup(so); 464} 465 466PR_WRAP_USRREQS(rfcomm) 467 468#define rfcomm_attach rfcomm_attach_wrapper 469#define rfcomm_detach rfcomm_detach_wrapper 470#define rfcomm_accept rfcomm_accept_wrapper 471#define rfcomm_ioctl rfcomm_ioctl_wrapper 472#define rfcomm_stat rfcomm_stat_wrapper 473#define rfcomm_peeraddr rfcomm_peeraddr_wrapper 474#define rfcomm_sockaddr rfcomm_sockaddr_wrapper 475#define rfcomm_usrreq rfcomm_usrreq_wrapper 476 477const struct pr_usrreqs rfcomm_usrreqs = { 478 .pr_attach = rfcomm_attach, 479 .pr_detach = rfcomm_detach, 480 .pr_accept = rfcomm_accept, 481 .pr_ioctl = rfcomm_ioctl, 482 .pr_stat = rfcomm_stat, 483 .pr_peeraddr = rfcomm_peeraddr, 484 .pr_sockaddr = rfcomm_sockaddr, 485 .pr_generic = rfcomm_usrreq, 486}; 487