1 /* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */ 2 /* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */ 3 4 /*- 5 * Copyright (c) 2005 Iain Hibbert. 6 * Copyright (c) 2006 Itronix Inc. 7 * All rights reserved. 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 /* load symbolic names */ 35 #ifdef BLUETOOTH_DEBUG 36 #define PRUREQUESTS 37 #define PRCOREQUESTS 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/domain.h> 42 #include <sys/kernel.h> 43 #include <sys/malloc.h> /* for M_NOWAIT */ 44 #include <sys/mbuf.h> 45 #include <sys/proc.h> 46 #include <sys/protosw.h> 47 #include <sys/socket.h> 48 #include <sys/socketvar.h> 49 #include <sys/systm.h> 50 51 #include <sys/msgport2.h> 52 53 #include <vm/vm_zone.h> 54 55 #include <netbt/bluetooth.h> 56 #include <netbt/hci.h> /* XXX for EPASSTHROUGH */ 57 #include <netbt/l2cap.h> 58 59 /* 60 * L2CAP Sockets 61 * 62 * SOCK_SEQPACKET - normal L2CAP connection 63 * 64 * SOCK_DGRAM - connectionless L2CAP - XXX not yet 65 */ 66 67 static void l2cap_connecting(void *); 68 static void l2cap_connected(void *); 69 static void l2cap_disconnected(void *, int); 70 static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *); 71 static void l2cap_complete(void *, int); 72 static void l2cap_linkmode(void *, int); 73 static void l2cap_input(void *, struct mbuf *); 74 75 static const struct btproto l2cap_proto = { 76 l2cap_connecting, 77 l2cap_connected, 78 l2cap_disconnected, 79 l2cap_newconn, 80 l2cap_complete, 81 l2cap_linkmode, 82 l2cap_input, 83 }; 84 85 /* sysctl variables */ 86 int l2cap_sendspace = 4096; 87 int l2cap_recvspace = 4096; 88 89 /* 90 * l2cap_ctloutput(request, socket, level, optname, opt) 91 * 92 * Apply configuration commands to channel. This corresponds to 93 * "Reconfigure Channel Request" in the L2CAP specification. 94 */ 95 void 96 l2cap_ctloutput(netmsg_t msg) 97 { 98 struct socket *so = msg->ctloutput.base.nm_so; 99 struct sockopt *sopt = msg->ctloutput.nm_sopt; 100 struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb; 101 struct mbuf *m; 102 int error = 0; 103 104 #ifdef notyet /* XXX */ 105 DPRINTFN(2, "%s\n", prcorequests[req]); 106 #endif 107 108 if (pcb == NULL) { 109 error = EINVAL; 110 goto out; 111 } 112 113 if (sopt->sopt_level != BTPROTO_L2CAP) { 114 error = ENOPROTOOPT; 115 goto out; 116 } 117 118 switch(sopt->sopt_dir) { 119 case PRCO_GETOPT: 120 m = m_get(M_NOWAIT, MT_DATA); 121 if (m == NULL) { 122 error = ENOMEM; 123 break; 124 } 125 m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *)); 126 if (m->m_len == 0) { 127 m_freem(m); 128 m = NULL; 129 error = ENOPROTOOPT; 130 } 131 soopt_from_kbuf(sopt, mtod(m, void *), m->m_len); 132 break; 133 134 case PRCO_SETOPT: 135 error = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt); 136 break; 137 138 default: 139 error = ENOPROTOOPT; 140 break; 141 } 142 out: 143 lwkt_replymsg(&msg->ctloutput.base.lmsg, error); 144 } 145 146 /********************************************************************** 147 * 148 * L2CAP Protocol socket callbacks 149 * 150 */ 151 152 static void 153 l2cap_connecting(void *arg) 154 { 155 struct socket *so = arg; 156 157 DPRINTF("Connecting\n"); 158 soisconnecting(so); 159 } 160 161 static void 162 l2cap_connected(void *arg) 163 { 164 struct socket *so = arg; 165 166 DPRINTF("Connected\n"); 167 soisconnected(so); 168 } 169 170 static void 171 l2cap_disconnected(void *arg, int err) 172 { 173 struct socket *so = arg; 174 175 DPRINTF("Disconnected (%d)\n", err); 176 177 so->so_error = err; 178 soisdisconnected(so); 179 } 180 181 static void * 182 l2cap_newconn(void *arg, struct sockaddr_bt *laddr, 183 struct sockaddr_bt *raddr) 184 { 185 struct socket *so = arg; 186 187 DPRINTF("New Connection\n"); 188 so = sonewconn(so, 0); 189 if (so == NULL) 190 return NULL; 191 192 soisconnecting(so); 193 194 return so->so_pcb; 195 } 196 197 static void 198 l2cap_complete(void *arg, int count) 199 { 200 struct socket *so = arg; 201 202 while (count-- > 0) 203 sbdroprecord(&so->so_snd.sb); 204 205 sowwakeup(so); 206 } 207 208 static void 209 l2cap_linkmode(void *arg, int new) 210 { 211 struct socket *so = arg; 212 int mode; 213 214 DPRINTF("auth %s, encrypt %s, secure %s\n", 215 (new & L2CAP_LM_AUTH ? "on" : "off"), 216 (new & L2CAP_LM_ENCRYPT ? "on" : "off"), 217 (new & L2CAP_LM_SECURE ? "on" : "off")); 218 219 (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode); 220 if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH)) 221 || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT)) 222 || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE))) 223 l2cap_disconnect(so->so_pcb, 0); 224 } 225 226 static void 227 l2cap_input(void *arg, struct mbuf *m) 228 { 229 struct socket *so = arg; 230 231 if (m->m_pkthdr.len > sbspace(&so->so_rcv)) { 232 kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n", 233 __func__, m->m_pkthdr.len); 234 m_freem(m); 235 return; 236 } 237 238 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 239 240 sbappendrecord(&so->so_rcv.sb, m); 241 sorwakeup(so); 242 } 243 244 245 /* 246 * Implementation of usrreqs. 247 */ 248 static void 249 l2cap_sdetach(netmsg_t msg) 250 { 251 struct socket *so = msg->detach.base.nm_so; 252 int error; 253 254 error = l2cap_detach((struct l2cap_channel **)&so->so_pcb); 255 lwkt_replymsg(&msg->detach.base.lmsg, error); 256 } 257 258 /* 259 * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort() 260 * will sofree() it when we return. 261 */ 262 static void 263 l2cap_sabort(netmsg_t msg) 264 { 265 struct socket *so = msg->abort.base.nm_so; 266 struct l2cap_channel *pcb = so->so_pcb; 267 268 l2cap_disconnect(pcb, 0); 269 soisdisconnected(so); 270 271 l2cap_sdetach(msg); 272 /* msg invalid now */ 273 } 274 275 static void 276 l2cap_sdisconnect(netmsg_t msg) 277 { 278 struct socket *so = msg->disconnect.base.nm_so; 279 struct l2cap_channel *pcb = so->so_pcb; 280 int error; 281 282 soisdisconnecting(so); 283 284 error = l2cap_disconnect(pcb, so->so_linger); 285 lwkt_replymsg(&msg->disconnect.base.lmsg, error); 286 } 287 288 static void 289 l2cap_scontrol(netmsg_t msg) 290 { 291 lwkt_replymsg(&msg->control.base.lmsg, EPASSTHROUGH); 292 } 293 294 static void 295 l2cap_sattach(netmsg_t msg) 296 { 297 struct socket *so = msg->attach.base.nm_so; 298 struct l2cap_channel *pcb = so->so_pcb; 299 int error; 300 301 if (pcb != NULL) { 302 error = EINVAL; 303 goto out; 304 } 305 306 /* 307 * For L2CAP socket PCB we just use an l2cap_channel structure 308 * since we have nothing to add.. 309 */ 310 error = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL); 311 if (error == 0) { 312 error = l2cap_attach((struct l2cap_channel **)&so->so_pcb, 313 &l2cap_proto, so); 314 } 315 out: 316 lwkt_replymsg(&msg->attach.base.lmsg, error); 317 } 318 319 static void 320 l2cap_sbind (netmsg_t msg) 321 { 322 struct socket *so = msg->bind.base.nm_so; 323 struct sockaddr *nam = msg->bind.nm_nam; 324 struct l2cap_channel *pcb = so->so_pcb; 325 struct sockaddr_bt *sa; 326 int error; 327 328 KKASSERT(nam != NULL); 329 sa = (struct sockaddr_bt *)nam; 330 331 if (sa->bt_len != sizeof(struct sockaddr_bt)) { 332 error = EINVAL; 333 } else if (sa->bt_family != AF_BLUETOOTH) { 334 error = EAFNOSUPPORT; 335 } else { 336 error = l2cap_bind(pcb, sa); 337 } 338 lwkt_replymsg(&msg->bind.base.lmsg, error); 339 } 340 341 static void 342 l2cap_sconnect(netmsg_t msg) 343 { 344 struct socket *so = msg->connect.base.nm_so; 345 struct sockaddr *nam = msg->connect.nm_nam; 346 struct l2cap_channel *pcb = so->so_pcb; 347 struct sockaddr_bt *sa; 348 int error; 349 350 KKASSERT(nam != NULL); 351 sa = (struct sockaddr_bt *)nam; 352 353 if (sa->bt_len != sizeof(struct sockaddr_bt)) { 354 error = EINVAL; 355 } else if (sa->bt_family != AF_BLUETOOTH) { 356 error = EAFNOSUPPORT; 357 } else { 358 soisconnecting(so); 359 error = l2cap_connect(pcb, sa); 360 } 361 lwkt_replymsg(&msg->connect.base.lmsg, error); 362 } 363 364 static void 365 l2cap_speeraddr(netmsg_t msg) 366 { 367 struct socket *so = msg->peeraddr.base.nm_so; 368 struct sockaddr **nam = msg->peeraddr.nm_nam; 369 struct l2cap_channel *pcb = so->so_pcb; 370 struct sockaddr_bt *sa, ssa; 371 int error; 372 373 sa = &ssa; 374 bzero(sa, sizeof *sa); 375 sa->bt_len = sizeof(struct sockaddr_bt); 376 sa->bt_family = AF_BLUETOOTH; 377 error = l2cap_peeraddr(pcb, sa); 378 *nam = dup_sockaddr((struct sockaddr *)sa); 379 380 lwkt_replymsg(&msg->peeraddr.base.lmsg, error); 381 } 382 383 static void 384 l2cap_ssockaddr(netmsg_t msg) 385 { 386 struct socket *so = msg->sockaddr.base.nm_so; 387 struct sockaddr **nam = msg->sockaddr.nm_nam; 388 struct l2cap_channel *pcb = so->so_pcb; 389 struct sockaddr_bt *sa, ssa; 390 int error; 391 392 sa = &ssa; 393 bzero(sa, sizeof *sa); 394 sa->bt_len = sizeof(struct sockaddr_bt); 395 sa->bt_family = AF_BLUETOOTH; 396 error = l2cap_sockaddr(pcb, sa); 397 *nam = dup_sockaddr((struct sockaddr *)sa); 398 399 lwkt_replymsg(&msg->sockaddr.base.lmsg, error); 400 } 401 402 static void 403 l2cap_sshutdown(netmsg_t msg) 404 { 405 struct socket *so = msg->shutdown.base.nm_so; 406 407 socantsendmore(so); 408 409 lwkt_replymsg(&msg->shutdown.base.lmsg, 0); 410 } 411 412 static void 413 l2cap_ssend(netmsg_t msg) 414 { 415 struct socket *so = msg->send.base.nm_so; 416 struct mbuf *m = msg->send.nm_m; 417 struct mbuf *control = msg->send.nm_control; 418 struct l2cap_channel *pcb = so->so_pcb; 419 struct mbuf *m0; 420 int error; 421 422 KKASSERT(m != NULL); 423 if (m->m_pkthdr.len == 0) { 424 error = 0; 425 goto out; 426 } 427 428 if (m->m_pkthdr.len > pcb->lc_omtu) { 429 error = EMSGSIZE; 430 goto out; 431 } 432 433 m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT); 434 if (m0 == NULL) { 435 error = ENOMEM; 436 goto out; 437 } 438 439 m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT); 440 if (m0 == NULL) { 441 error = ENOMEM; 442 goto out; 443 } 444 445 /* no use for that */ 446 if (control) { 447 m_freem(control); 448 control = NULL; 449 } 450 sbappendrecord(&so->so_snd.sb, m); 451 error = l2cap_send(pcb, m0); 452 m = NULL; 453 out: 454 if (m) 455 m_freem(m); 456 if (control) 457 m_freem(control); 458 459 lwkt_replymsg(&msg->send.base.lmsg, error); 460 } 461 462 static void 463 l2cap_saccept(netmsg_t msg) 464 { 465 struct socket *so = msg->accept.base.nm_so; 466 struct sockaddr **nam = msg->accept.nm_nam; 467 struct l2cap_channel *pcb = so->so_pcb; 468 struct sockaddr_bt sa; 469 int error; 470 471 KKASSERT(nam != NULL); 472 473 bzero(&sa, sizeof (sa) ); 474 sa.bt_len = sizeof(struct sockaddr_bt); 475 sa.bt_family = AF_BLUETOOTH; 476 477 error = l2cap_peeraddr(pcb, &sa); 478 *nam = dup_sockaddr((struct sockaddr *)&sa); 479 480 lwkt_replymsg(&msg->accept.base.lmsg, error); 481 } 482 483 static void 484 l2cap_slisten(netmsg_t msg) 485 { 486 struct socket *so = msg->listen.base.nm_so; 487 struct l2cap_channel *pcb = so->so_pcb; 488 int error; 489 490 error = l2cap_listen(pcb); 491 lwkt_replymsg(&msg->accept.base.lmsg, error); 492 } 493 494 495 struct pr_usrreqs l2cap_usrreqs = { 496 .pru_abort = l2cap_sabort, 497 .pru_accept = l2cap_saccept, 498 .pru_attach = l2cap_sattach, 499 .pru_bind = l2cap_sbind, 500 .pru_connect = l2cap_sconnect, 501 .pru_connect2 = pr_generic_notsupp, 502 .pru_control = l2cap_scontrol, 503 .pru_detach = l2cap_sdetach, 504 .pru_disconnect = l2cap_sdisconnect, 505 .pru_listen = l2cap_slisten, 506 .pru_peeraddr = l2cap_speeraddr, 507 .pru_rcvd = pr_generic_notsupp, 508 .pru_rcvoob = pr_generic_notsupp, 509 .pru_send = l2cap_ssend, 510 .pru_sense = pru_sense_null, 511 .pru_shutdown = l2cap_sshutdown, 512 .pru_sockaddr = l2cap_ssockaddr, 513 .pru_sosend = sosend, 514 .pru_soreceive = soreceive 515 }; 516