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