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 static int 245 l2cap_sabort (struct socket *so) 246 { 247 struct l2cap_channel *pcb = so->so_pcb; 248 249 l2cap_disconnect(pcb, 0); 250 soisdisconnected(so); 251 252 return l2cap_sdetach(so); 253 } 254 255 static int 256 l2cap_sdisconnect (struct socket *so) 257 { 258 struct l2cap_channel *pcb = so->so_pcb; 259 260 soisdisconnecting(so); 261 262 return l2cap_disconnect(pcb, so->so_linger); 263 } 264 265 static int 266 l2cap_scontrol (struct socket *so, u_long cmd, caddr_t data, 267 struct ifnet *ifp, struct thread *td) 268 { 269 return EPASSTHROUGH; 270 } 271 272 static int 273 l2cap_sattach (struct socket *so, int proto, 274 struct pru_attach_info *ai) 275 { 276 struct l2cap_channel *pcb = so->so_pcb; 277 int err = 0; 278 279 if (pcb != NULL) 280 return EINVAL; 281 282 /* 283 * For L2CAP socket PCB we just use an l2cap_channel structure 284 * since we have nothing to add.. 285 */ 286 err = soreserve(so, l2cap_sendspace, l2cap_recvspace, NULL); 287 if (err) 288 return err; 289 290 return l2cap_attach((struct l2cap_channel **)&so->so_pcb, 291 &l2cap_proto, so); 292 } 293 294 static int 295 l2cap_sbind (struct socket *so, struct sockaddr *nam, 296 struct thread *td) 297 { 298 struct l2cap_channel *pcb = so->so_pcb; 299 struct sockaddr_bt *sa; 300 301 KKASSERT(nam != NULL); 302 sa = (struct sockaddr_bt *)nam; 303 304 if (sa->bt_len != sizeof(struct sockaddr_bt)) 305 return EINVAL; 306 307 if (sa->bt_family != AF_BLUETOOTH) 308 return EAFNOSUPPORT; 309 310 return l2cap_bind(pcb, sa); 311 } 312 313 static int 314 l2cap_sconnect (struct socket *so, struct sockaddr *nam, 315 struct thread *td) 316 { 317 struct l2cap_channel *pcb = so->so_pcb; 318 struct sockaddr_bt *sa; 319 320 KKASSERT(nam != NULL); 321 sa = (struct sockaddr_bt *)nam; 322 323 if (sa->bt_len != sizeof(struct sockaddr_bt)) 324 return EINVAL; 325 326 if (sa->bt_family != AF_BLUETOOTH) 327 return EAFNOSUPPORT; 328 329 soisconnecting(so); 330 return l2cap_connect(pcb, sa); 331 } 332 333 static int 334 l2cap_speeraddr (struct socket *so, struct sockaddr **nam) 335 { 336 struct l2cap_channel *pcb = so->so_pcb; 337 struct sockaddr_bt *sa, ssa; 338 int e; 339 340 sa = &ssa; 341 bzero(sa, sizeof *sa); 342 sa->bt_len = sizeof(struct sockaddr_bt); 343 sa->bt_family = AF_BLUETOOTH; 344 e = l2cap_peeraddr(pcb, sa); 345 *nam = dup_sockaddr((struct sockaddr *)sa); 346 347 return (e); 348 } 349 350 static int 351 l2cap_ssockaddr (struct socket *so, struct sockaddr **nam) 352 { 353 struct l2cap_channel *pcb = so->so_pcb; 354 struct sockaddr_bt *sa, ssa; 355 int e; 356 357 sa = &ssa; 358 bzero(sa, sizeof *sa); 359 sa->bt_len = sizeof(struct sockaddr_bt); 360 sa->bt_family = AF_BLUETOOTH; 361 e = l2cap_sockaddr(pcb, sa); 362 *nam = dup_sockaddr((struct sockaddr *)sa); 363 364 return (e); 365 } 366 367 static int 368 l2cap_sshutdown (struct socket *so) 369 { 370 socantsendmore(so); 371 return 0; 372 } 373 374 static int 375 l2cap_ssend (struct socket *so, int flags, struct mbuf *m, 376 struct sockaddr *addr, struct mbuf *control, struct thread *td) 377 { 378 struct l2cap_channel *pcb = so->so_pcb; 379 struct mbuf *m0; 380 381 int err = 0; 382 383 KKASSERT(m != NULL); 384 if (m->m_pkthdr.len == 0) 385 goto error; 386 387 if (m->m_pkthdr.len > pcb->lc_omtu) { 388 err = EMSGSIZE; 389 goto error; 390 } 391 392 m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT); 393 if (m0 == NULL) { 394 err = ENOMEM; 395 goto error; 396 } 397 398 if (control) /* no use for that */ 399 m_freem(control); 400 401 sbappendrecord(&so->so_snd.sb, m); 402 return l2cap_send(pcb, m0); 403 404 error: 405 if (m) 406 m_freem(m); 407 if (control) 408 m_freem(control); 409 410 return err; 411 } 412 413 static int 414 l2cap_saccept(struct socket *so, struct sockaddr **nam) 415 { 416 struct l2cap_channel *pcb = so->so_pcb; 417 struct sockaddr_bt sa; 418 int e; 419 420 KKASSERT(nam != NULL); 421 422 bzero(&sa, sizeof (sa) ); 423 sa.bt_len = sizeof(struct sockaddr_bt); 424 sa.bt_family = AF_BLUETOOTH; 425 426 e = l2cap_peeraddr(pcb, &sa); 427 *nam = dup_sockaddr((struct sockaddr *)&sa); 428 429 return e; 430 } 431 432 static int 433 l2cap_slisten(struct socket *so, struct thread *td) 434 { 435 struct l2cap_channel *pcb = so->so_pcb; 436 return l2cap_listen(pcb); 437 } 438 439 440 struct pr_usrreqs l2cap_usrreqs = { 441 .pru_abort = l2cap_sabort, 442 .pru_accept = l2cap_saccept, 443 .pru_attach = l2cap_sattach, 444 .pru_bind = l2cap_sbind, 445 .pru_connect = l2cap_sconnect, 446 .pru_connect2 = pru_connect2_notsupp, 447 .pru_control = l2cap_scontrol, 448 .pru_detach = l2cap_sdetach, 449 .pru_disconnect = l2cap_sdisconnect, 450 .pru_listen = l2cap_slisten, 451 .pru_peeraddr = l2cap_speeraddr, 452 .pru_rcvd = pru_rcvd_notsupp, 453 .pru_rcvoob = pru_rcvoob_notsupp, 454 .pru_send = l2cap_ssend, 455 .pru_sense = pru_sense_null, 456 .pru_shutdown = l2cap_sshutdown, 457 .pru_sockaddr = l2cap_ssockaddr, 458 .pru_sosend = sosend, 459 .pru_soreceive = soreceive 460 }; 461