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