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