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