1 /* $NetBSD: l2cap_socket.c,v 1.17 2014/07/01 05:49:18 rtr Exp $ */ 2 3 /*- 4 * Copyright (c) 2005 Iain Hibbert. 5 * Copyright (c) 2006 Itronix Inc. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of Itronix Inc. may not be used to endorse 17 * or promote products derived from this software without specific 18 * prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27 * ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: l2cap_socket.c,v 1.17 2014/07/01 05:49:18 rtr Exp $"); 35 36 /* load symbolic names */ 37 #ifdef BLUETOOTH_DEBUG 38 #define PRUREQUESTS 39 #define PRCOREQUESTS 40 #endif 41 42 #include <sys/param.h> 43 #include <sys/domain.h> 44 #include <sys/kernel.h> 45 #include <sys/mbuf.h> 46 #include <sys/proc.h> 47 #include <sys/protosw.h> 48 #include <sys/socket.h> 49 #include <sys/socketvar.h> 50 #include <sys/systm.h> 51 52 #include <netbt/bluetooth.h> 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 static int 86 l2cap_attach(struct socket *so, int proto) 87 { 88 int error; 89 90 KASSERT(so->so_pcb == NULL); 91 92 if (so->so_lock == NULL) { 93 mutex_obj_hold(bt_lock); 94 so->so_lock = bt_lock; 95 solock(so); 96 } 97 KASSERT(solocked(so)); 98 99 /* 100 * For L2CAP socket PCB we just use an l2cap_channel structure 101 * since we have nothing to add.. 102 */ 103 error = soreserve(so, l2cap_sendspace, l2cap_recvspace); 104 if (error) 105 return error; 106 107 return l2cap_attach_pcb((struct l2cap_channel **)&so->so_pcb, 108 &l2cap_proto, so); 109 } 110 111 static void 112 l2cap_detach(struct socket *so) 113 { 114 KASSERT(so->so_pcb != NULL); 115 l2cap_detach_pcb((struct l2cap_channel **)&so->so_pcb); 116 KASSERT(so->so_pcb == NULL); 117 } 118 119 static int 120 l2cap_ioctl(struct socket *up, u_long cmd, void *nam, struct ifnet *ifp) 121 { 122 return EPASSTHROUGH; 123 } 124 125 /* 126 * User Request. 127 * up is socket 128 * m is optional mbuf chain containing message 129 * nam is either 130 * optional mbuf chain containing an address 131 * message flags (PRU_RCVD) 132 * ctl is either 133 * optional mbuf chain containing socket options 134 * optional interface pointer PRU_PURGEIF 135 * l is pointer to process requesting action (if any) 136 * 137 * we are responsible for disposing of m and ctl if 138 * they are mbuf chains 139 */ 140 static int 141 l2cap_usrreq(struct socket *up, int req, struct mbuf *m, 142 struct mbuf *nam, struct mbuf *ctl, struct lwp *l) 143 { 144 struct l2cap_channel *pcb = up->so_pcb; 145 struct sockaddr_bt *sa; 146 struct mbuf *m0; 147 int err = 0; 148 149 DPRINTFN(2, "%s\n", prurequests[req]); 150 KASSERT(req != PRU_ATTACH); 151 KASSERT(req != PRU_DETACH); 152 KASSERT(req != PRU_CONTROL); 153 154 switch (req) { 155 case PRU_PURGEIF: 156 return EOPNOTSUPP; 157 } 158 159 if (pcb == NULL) { 160 err = EINVAL; 161 goto release; 162 } 163 164 switch(req) { 165 case PRU_DISCONNECT: 166 soisdisconnecting(up); 167 return l2cap_disconnect(pcb, up->so_linger); 168 169 case PRU_ABORT: 170 l2cap_disconnect(pcb, 0); 171 soisdisconnected(up); 172 l2cap_detach(up); 173 return 0; 174 175 case PRU_BIND: 176 KASSERT(nam != NULL); 177 sa = mtod(nam, struct sockaddr_bt *); 178 179 if (sa->bt_len != sizeof(struct sockaddr_bt)) 180 return EINVAL; 181 182 if (sa->bt_family != AF_BLUETOOTH) 183 return EAFNOSUPPORT; 184 185 return l2cap_bind(pcb, sa); 186 187 case PRU_CONNECT: 188 KASSERT(nam != NULL); 189 sa = mtod(nam, struct sockaddr_bt *); 190 191 if (sa->bt_len != sizeof(struct sockaddr_bt)) 192 return EINVAL; 193 194 if (sa->bt_family != AF_BLUETOOTH) 195 return EAFNOSUPPORT; 196 197 soisconnecting(up); 198 return l2cap_connect(pcb, sa); 199 200 case PRU_PEERADDR: 201 KASSERT(nam != NULL); 202 sa = mtod(nam, struct sockaddr_bt *); 203 nam->m_len = sizeof(struct sockaddr_bt); 204 return l2cap_peeraddr(pcb, sa); 205 206 case PRU_SOCKADDR: 207 KASSERT(nam != NULL); 208 sa = mtod(nam, struct sockaddr_bt *); 209 nam->m_len = sizeof(struct sockaddr_bt); 210 return l2cap_sockaddr(pcb, sa); 211 212 case PRU_SHUTDOWN: 213 socantsendmore(up); 214 break; 215 216 case PRU_SEND: 217 KASSERT(m != NULL); 218 if (m->m_pkthdr.len == 0) 219 break; 220 221 if (m->m_pkthdr.len > pcb->lc_omtu) { 222 err = EMSGSIZE; 223 break; 224 } 225 226 m0 = m_copypacket(m, M_DONTWAIT); 227 if (m0 == NULL) { 228 err = ENOMEM; 229 break; 230 } 231 232 if (ctl) /* no use for that */ 233 m_freem(ctl); 234 235 sbappendrecord(&up->so_snd, m); 236 return l2cap_send(pcb, m0); 237 238 case PRU_SENSE: 239 return 0; /* (no release) */ 240 241 case PRU_RCVD: 242 case PRU_RCVOOB: 243 return EOPNOTSUPP; /* (no release) */ 244 245 case PRU_LISTEN: 246 return l2cap_listen(pcb); 247 248 case PRU_ACCEPT: 249 KASSERT(nam != NULL); 250 sa = mtod(nam, struct sockaddr_bt *); 251 nam->m_len = sizeof(struct sockaddr_bt); 252 return l2cap_peeraddr(pcb, sa); 253 254 case PRU_CONNECT2: 255 case PRU_SENDOOB: 256 case PRU_FASTTIMO: 257 case PRU_SLOWTIMO: 258 case PRU_PROTORCV: 259 case PRU_PROTOSEND: 260 err = EOPNOTSUPP; 261 break; 262 263 default: 264 UNKNOWN(req); 265 err = EOPNOTSUPP; 266 break; 267 } 268 269 release: 270 if (m) m_freem(m); 271 if (ctl) m_freem(ctl); 272 return err; 273 } 274 275 /* 276 * l2cap_ctloutput(req, socket, sockopt) 277 * 278 * Apply configuration commands to channel. This corresponds to 279 * "Reconfigure Channel Request" in the L2CAP specification. 280 */ 281 int 282 l2cap_ctloutput(int req, struct socket *so, struct sockopt *sopt) 283 { 284 struct l2cap_channel *pcb = so->so_pcb; 285 int err = 0; 286 287 DPRINTFN(2, "%s\n", prcorequests[req]); 288 289 if (pcb == NULL) 290 return EINVAL; 291 292 if (sopt->sopt_level != BTPROTO_L2CAP) 293 return ENOPROTOOPT; 294 295 switch(req) { 296 case PRCO_GETOPT: 297 err = l2cap_getopt(pcb, sopt); 298 break; 299 300 case PRCO_SETOPT: 301 err = l2cap_setopt(pcb, sopt); 302 break; 303 304 default: 305 err = ENOPROTOOPT; 306 break; 307 } 308 309 return err; 310 } 311 312 /********************************************************************** 313 * 314 * L2CAP Protocol socket callbacks 315 * 316 */ 317 318 static void 319 l2cap_connecting(void *arg) 320 { 321 struct socket *so = arg; 322 323 DPRINTF("Connecting\n"); 324 soisconnecting(so); 325 } 326 327 static void 328 l2cap_connected(void *arg) 329 { 330 struct socket *so = arg; 331 332 DPRINTF("Connected\n"); 333 soisconnected(so); 334 } 335 336 static void 337 l2cap_disconnected(void *arg, int err) 338 { 339 struct socket *so = arg; 340 341 DPRINTF("Disconnected (%d)\n", err); 342 343 so->so_error = err; 344 soisdisconnected(so); 345 } 346 347 static void * 348 l2cap_newconn(void *arg, struct sockaddr_bt *laddr, 349 struct sockaddr_bt *raddr) 350 { 351 struct socket *so = arg; 352 353 DPRINTF("New Connection\n"); 354 so = sonewconn(so, false); 355 if (so == NULL) 356 return NULL; 357 358 soisconnecting(so); 359 360 return so->so_pcb; 361 } 362 363 static void 364 l2cap_complete(void *arg, int count) 365 { 366 struct socket *so = arg; 367 368 while (count-- > 0) 369 sbdroprecord(&so->so_snd); 370 371 sowwakeup(so); 372 } 373 374 static void 375 l2cap_linkmode(void *arg, int new) 376 { 377 struct socket *so = arg; 378 struct sockopt sopt; 379 int mode; 380 381 DPRINTF("auth %s, encrypt %s, secure %s\n", 382 (new & L2CAP_LM_AUTH ? "on" : "off"), 383 (new & L2CAP_LM_ENCRYPT ? "on" : "off"), 384 (new & L2CAP_LM_SECURE ? "on" : "off")); 385 386 sockopt_init(&sopt, BTPROTO_L2CAP, SO_L2CAP_LM, 0); 387 (void)l2cap_getopt(so->so_pcb, &sopt); 388 (void)sockopt_getint(&sopt, &mode); 389 sockopt_destroy(&sopt); 390 391 if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH)) 392 || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT)) 393 || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE))) 394 l2cap_disconnect(so->so_pcb, 0); 395 } 396 397 static void 398 l2cap_input(void *arg, struct mbuf *m) 399 { 400 struct socket *so = arg; 401 402 if (m->m_pkthdr.len > sbspace(&so->so_rcv)) { 403 printf("%s: packet (%d bytes) dropped (socket buffer full)\n", 404 __func__, m->m_pkthdr.len); 405 m_freem(m); 406 return; 407 } 408 409 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len); 410 411 sbappendrecord(&so->so_rcv, m); 412 sorwakeup(so); 413 } 414 415 PR_WRAP_USRREQS(l2cap) 416 417 #define l2cap_attach l2cap_attach_wrapper 418 #define l2cap_detach l2cap_detach_wrapper 419 #define l2cap_ioctl l2cap_ioctl_wrapper 420 #define l2cap_usrreq l2cap_usrreq_wrapper 421 422 const struct pr_usrreqs l2cap_usrreqs = { 423 .pr_attach = l2cap_attach, 424 .pr_detach = l2cap_detach, 425 .pr_ioctl = l2cap_ioctl, 426 .pr_generic = l2cap_usrreq, 427 }; 428