1 /* $DragonFly: src/sys/netbt/l2cap_socket.c,v 1.3 2008/06/20 20:52:29 aggelos Exp $ */ 2 /* $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */ 3 /* $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $ */ 4 5 /*- 6 * Copyright (c) 2005 Iain Hibbert. 7 * Copyright (c) 2006 Itronix Inc. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. The name of Itronix Inc. may not be used to endorse 19 * or promote products derived from this software without specific 20 * prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 26 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 * ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 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 #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 int 95 l2cap_ctloutput(struct socket *so, struct sockopt *sopt) 96 { 97 struct l2cap_channel *pcb = (struct l2cap_channel *) so->so_pcb; 98 struct mbuf *m; 99 int err = 0; 100 101 #ifdef notyet /* XXX */ 102 DPRINTFN(2, "%s\n", prcorequests[req]); 103 #endif 104 105 if (pcb == NULL) 106 return EINVAL; 107 108 if (sopt->sopt_level != BTPROTO_L2CAP) 109 return ENOPROTOOPT; 110 111 switch(sopt->sopt_dir) { 112 case PRCO_GETOPT: 113 m = m_get(M_NOWAIT, MT_DATA); 114 if (m == NULL) { 115 err = ENOMEM; 116 break; 117 } 118 m->m_len = l2cap_getopt(pcb, sopt->sopt_name, mtod(m, void *)); 119 if (m->m_len == 0) { 120 m_freem(m); 121 m = NULL; 122 err = ENOPROTOOPT; 123 } 124 soopt_from_kbuf(sopt, mtod(m, void *), m->m_len); 125 break; 126 127 case PRCO_SETOPT: 128 err = l2cap_setopt2(pcb, sopt->sopt_name, so, sopt); 129 break; 130 131 default: 132 err = ENOPROTOOPT; 133 break; 134 } 135 136 return err; 137 } 138 139 /********************************************************************** 140 * 141 * L2CAP Protocol socket callbacks 142 * 143 */ 144 145 static void 146 l2cap_connecting(void *arg) 147 { 148 struct socket *so = arg; 149 150 DPRINTF("Connecting\n"); 151 soisconnecting(so); 152 } 153 154 static void 155 l2cap_connected(void *arg) 156 { 157 struct socket *so = arg; 158 159 DPRINTF("Connected\n"); 160 soisconnected(so); 161 } 162 163 static void 164 l2cap_disconnected(void *arg, int err) 165 { 166 struct socket *so = arg; 167 168 DPRINTF("Disconnected (%d)\n", err); 169 170 so->so_error = err; 171 soisdisconnected(so); 172 } 173 174 static void * 175 l2cap_newconn(void *arg, struct sockaddr_bt *laddr, 176 struct sockaddr_bt *raddr) 177 { 178 struct socket *so = arg; 179 180 DPRINTF("New Connection\n"); 181 so = sonewconn(so, 0); 182 if (so == NULL) 183 return NULL; 184 185 soisconnecting(so); 186 187 return so->so_pcb; 188 } 189 190 static void 191 l2cap_complete(void *arg, int count) 192 { 193 struct socket *so = arg; 194 195 while (count-- > 0) 196 sbdroprecord(&so->so_snd.sb); 197 198 sowwakeup(so); 199 } 200 201 static void 202 l2cap_linkmode(void *arg, int new) 203 { 204 struct socket *so = arg; 205 int mode; 206 207 DPRINTF("auth %s, encrypt %s, secure %s\n", 208 (new & L2CAP_LM_AUTH ? "on" : "off"), 209 (new & L2CAP_LM_ENCRYPT ? "on" : "off"), 210 (new & L2CAP_LM_SECURE ? "on" : "off")); 211 212 (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode); 213 if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH)) 214 || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT)) 215 || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE))) 216 l2cap_disconnect(so->so_pcb, 0); 217 } 218 219 static void 220 l2cap_input(void *arg, struct mbuf *m) 221 { 222 struct socket *so = arg; 223 224 if (m->m_pkthdr.len > sbspace(&so->so_rcv)) { 225 kprintf("%s: packet (%d bytes) dropped (socket buffer full)\n", 226 __func__, m->m_pkthdr.len); 227 m_freem(m); 228 return; 229 } 230 231 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 232 233 sbappendrecord(&so->so_rcv.sb, m); 234 sorwakeup(so); 235 } 236 237 238 /* 239 * Implementation of usrreqs. 240 */ 241 static int 242 l2cap_sdetach(struct socket *so) 243 { 244 return l2cap_detach((struct l2cap_channel **)&so->so_pcb); 245 } 246 247 static int 248 l2cap_sabort (struct socket *so) 249 { 250 struct l2cap_channel *pcb = so->so_pcb; 251 252 l2cap_disconnect(pcb, 0); 253 soisdisconnected(so); 254 255 return l2cap_sdetach(so); 256 } 257 258 static int 259 l2cap_sdisconnect (struct socket *so) 260 { 261 struct l2cap_channel *pcb = so->so_pcb; 262 263 soisdisconnecting(so); 264 265 return l2cap_disconnect(pcb, so->so_linger); 266 } 267 268 static int 269 l2cap_scontrol (struct socket *so, u_long cmd, caddr_t data, 270 struct ifnet *ifp, struct thread *td) 271 { 272 return EPASSTHROUGH; 273 } 274 275 static int 276 l2cap_sattach (struct socket *so, int proto, 277 struct pru_attach_info *ai) 278 { 279 struct l2cap_channel *pcb = so->so_pcb; 280 int err = 0; 281 282 if (pcb != NULL) 283 return EINVAL; 284 285 /* 286 * For L2CAP socket PCB we just use an l2cap_channel structure 287 * since we have nothing to add.. 288 */ 289 err = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL); 290 if (err) 291 return err; 292 293 return l2cap_attach((struct l2cap_channel **)&so->so_pcb, 294 &l2cap_proto, so); 295 } 296 297 static int 298 l2cap_sbind (struct socket *so, struct sockaddr *nam, 299 struct thread *td) 300 { 301 struct l2cap_channel *pcb = so->so_pcb; 302 struct sockaddr_bt *sa; 303 304 KKASSERT(nam != NULL); 305 sa = (struct sockaddr_bt *)nam; 306 307 if (sa->bt_len != sizeof(struct sockaddr_bt)) 308 return EINVAL; 309 310 if (sa->bt_family != AF_BLUETOOTH) 311 return EAFNOSUPPORT; 312 313 return l2cap_bind(pcb, sa); 314 } 315 316 static int 317 l2cap_sconnect (struct socket *so, struct sockaddr *nam, 318 struct thread *td) 319 { 320 struct l2cap_channel *pcb = so->so_pcb; 321 struct sockaddr_bt *sa; 322 323 KKASSERT(nam != NULL); 324 sa = (struct sockaddr_bt *)nam; 325 326 if (sa->bt_len != sizeof(struct sockaddr_bt)) 327 return EINVAL; 328 329 if (sa->bt_family != AF_BLUETOOTH) 330 return EAFNOSUPPORT; 331 332 soisconnecting(so); 333 return l2cap_connect(pcb, sa); 334 } 335 336 static int 337 l2cap_speeraddr (struct socket *so, struct sockaddr **nam) 338 { 339 struct l2cap_channel *pcb = so->so_pcb; 340 struct sockaddr_bt *sa, ssa; 341 int e; 342 343 sa = &ssa; 344 bzero(sa, sizeof *sa); 345 sa->bt_len = sizeof(struct sockaddr_bt); 346 sa->bt_family = AF_BLUETOOTH; 347 e = l2cap_peeraddr(pcb, sa); 348 *nam = dup_sockaddr((struct sockaddr *)sa); 349 350 return (e); 351 } 352 353 static int 354 l2cap_ssockaddr (struct socket *so, struct sockaddr **nam) 355 { 356 struct l2cap_channel *pcb = so->so_pcb; 357 struct sockaddr_bt *sa, ssa; 358 int e; 359 360 sa = &ssa; 361 bzero(sa, sizeof *sa); 362 sa->bt_len = sizeof(struct sockaddr_bt); 363 sa->bt_family = AF_BLUETOOTH; 364 e = l2cap_sockaddr(pcb, sa); 365 *nam = dup_sockaddr((struct sockaddr *)sa); 366 367 return (e); 368 } 369 370 static int 371 l2cap_sshutdown (struct socket *so) 372 { 373 socantsendmore(so); 374 return 0; 375 } 376 377 static int 378 l2cap_ssend (struct socket *so, int flags, struct mbuf *m, 379 struct sockaddr *addr, struct mbuf *control, struct thread *td) 380 { 381 struct l2cap_channel *pcb = so->so_pcb; 382 struct mbuf *m0; 383 384 int err = 0; 385 386 KKASSERT(m != NULL); 387 if (m->m_pkthdr.len == 0) 388 goto error; 389 390 if (m->m_pkthdr.len > pcb->lc_omtu) { 391 err = EMSGSIZE; 392 goto error; 393 } 394 395 m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT); 396 if (m0 == NULL) { 397 err = ENOMEM; 398 goto error; 399 } 400 401 if (control) /* no use for that */ 402 m_freem(control); 403 404 sbappendrecord(&so->so_snd.sb, m); 405 return l2cap_send(pcb, m0); 406 407 error: 408 if (m) 409 m_freem(m); 410 if (control) 411 m_freem(control); 412 413 return err; 414 } 415 416 static int 417 l2cap_saccept(struct socket *so, struct sockaddr **nam) 418 { 419 struct l2cap_channel *pcb = so->so_pcb; 420 struct sockaddr_bt sa; 421 int e; 422 423 KKASSERT(nam != NULL); 424 425 bzero(&sa, sizeof (sa) ); 426 sa.bt_len = sizeof(struct sockaddr_bt); 427 sa.bt_family = AF_BLUETOOTH; 428 429 e = l2cap_peeraddr(pcb, &sa); 430 *nam = dup_sockaddr((struct sockaddr *)&sa); 431 432 return e; 433 } 434 435 static int 436 l2cap_slisten(struct socket *so, struct thread *td) 437 { 438 struct l2cap_channel *pcb = so->so_pcb; 439 return l2cap_listen(pcb); 440 } 441 442 443 struct pr_usrreqs l2cap_usrreqs = { 444 .pru_abort = l2cap_sabort, 445 .pru_accept = l2cap_saccept, 446 .pru_attach = l2cap_sattach, 447 .pru_bind = l2cap_sbind, 448 .pru_connect = l2cap_sconnect, 449 .pru_connect2 = pru_connect2_notsupp, 450 .pru_control = l2cap_scontrol, 451 .pru_detach = l2cap_sdetach, 452 .pru_disconnect = l2cap_sdisconnect, 453 .pru_listen = l2cap_slisten, 454 .pru_peeraddr = l2cap_speeraddr, 455 .pru_rcvd = pru_rcvd_notsupp, 456 .pru_rcvoob = pru_rcvoob_notsupp, 457 .pru_send = l2cap_ssend, 458 .pru_sense = pru_sense_null, 459 .pru_shutdown = l2cap_sshutdown, 460 .pru_sockaddr = l2cap_ssockaddr, 461 .pru_sosend = sosend, 462 .pru_soreceive = soreceive, 463 .pru_sopoll = sopoll 464 }; 465