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