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