Annotation of sys/netbt/l2cap_socket.c, Revision 1.1
1.1 ! nbrk 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: #include <sys/cdefs.h>
! 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/hci.h> /* XXX for EPASSTHROUGH */
! 54: #include <netbt/l2cap.h>
! 55:
! 56: /*
! 57: * L2CAP Sockets
! 58: *
! 59: * SOCK_SEQPACKET - normal L2CAP connection
! 60: *
! 61: * SOCK_DGRAM - connectionless L2CAP - XXX not yet
! 62: */
! 63:
! 64: static void l2cap_connecting(void *);
! 65: static void l2cap_connected(void *);
! 66: static void l2cap_disconnected(void *, int);
! 67: static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
! 68: static void l2cap_complete(void *, int);
! 69: static void l2cap_linkmode(void *, int);
! 70: static void l2cap_input(void *, struct mbuf *);
! 71:
! 72: static const struct btproto l2cap_proto = {
! 73: l2cap_connecting,
! 74: l2cap_connected,
! 75: l2cap_disconnected,
! 76: l2cap_newconn,
! 77: l2cap_complete,
! 78: l2cap_linkmode,
! 79: l2cap_input,
! 80: };
! 81:
! 82: /* sysctl variables */
! 83: int l2cap_sendspace = 4096;
! 84: int l2cap_recvspace = 4096;
! 85:
! 86: /*
! 87: * User Request.
! 88: * up is socket
! 89: * m is either
! 90: * optional mbuf chain containing message
! 91: * ioctl command (PRU_CONTROL)
! 92: * nam is either
! 93: * optional mbuf chain containing an address
! 94: * ioctl data (PRU_CONTROL)
! 95: * optionally protocol number (PRU_ATTACH)
! 96: * message flags (PRU_RCVD)
! 97: * ctl is either
! 98: * optional mbuf chain containing socket options
! 99: * optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
! 100: * l is pointer to process requesting action (if any)
! 101: *
! 102: * we are responsible for disposing of m and ctl if
! 103: * they are mbuf chains
! 104: */
! 105: int
! 106: l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
! 107: struct mbuf *nam, struct mbuf *ctl)
! 108: {
! 109: struct l2cap_channel *pcb = up->so_pcb;
! 110: struct sockaddr_bt *sa;
! 111: struct mbuf *m0;
! 112: int err = 0;
! 113:
! 114: #ifdef notyet /* XXX */
! 115: DPRINTFN(2, "%s\n", prurequests[req]);
! 116: #endif
! 117:
! 118: switch (req) {
! 119: case PRU_CONTROL:
! 120: return EPASSTHROUGH;
! 121:
! 122: #ifdef notyet /* XXX */
! 123: case PRU_PURGEIF:
! 124: return EOPNOTSUPP;
! 125: #endif
! 126:
! 127: case PRU_ATTACH:
! 128: if (pcb != NULL)
! 129: return EINVAL;
! 130:
! 131: /*
! 132: * For L2CAP socket PCB we just use an l2cap_channel structure
! 133: * since we have nothing to add..
! 134: */
! 135: err = soreserve(up, l2cap_sendspace, l2cap_recvspace);
! 136: if (err)
! 137: return err;
! 138:
! 139: return l2cap_attach((struct l2cap_channel **)&up->so_pcb,
! 140: &l2cap_proto, up);
! 141: }
! 142:
! 143: if (pcb == NULL) {
! 144: err = EINVAL;
! 145: goto release;
! 146: }
! 147:
! 148: switch(req) {
! 149: case PRU_DISCONNECT:
! 150: soisdisconnecting(up);
! 151: return l2cap_disconnect(pcb, up->so_linger);
! 152:
! 153: case PRU_ABORT:
! 154: l2cap_disconnect(pcb, 0);
! 155: soisdisconnected(up);
! 156: /* fall through to */
! 157: case PRU_DETACH:
! 158: return l2cap_detach((struct l2cap_channel **)&up->so_pcb);
! 159:
! 160: case PRU_BIND:
! 161: KASSERT(nam != NULL);
! 162: sa = mtod(nam, struct sockaddr_bt *);
! 163:
! 164: if (sa->bt_len != sizeof(struct sockaddr_bt))
! 165: return EINVAL;
! 166:
! 167: if (sa->bt_family != AF_BLUETOOTH)
! 168: return EAFNOSUPPORT;
! 169:
! 170: return l2cap_bind(pcb, sa);
! 171:
! 172: case PRU_CONNECT:
! 173: KASSERT(nam != NULL);
! 174: sa = mtod(nam, struct sockaddr_bt *);
! 175:
! 176: if (sa->bt_len != sizeof(struct sockaddr_bt))
! 177: return EINVAL;
! 178:
! 179: if (sa->bt_family != AF_BLUETOOTH)
! 180: return EAFNOSUPPORT;
! 181:
! 182: soisconnecting(up);
! 183: return l2cap_connect(pcb, sa);
! 184:
! 185: case PRU_PEERADDR:
! 186: KASSERT(nam != NULL);
! 187: sa = mtod(nam, struct sockaddr_bt *);
! 188: nam->m_len = sizeof(struct sockaddr_bt);
! 189: return l2cap_peeraddr(pcb, sa);
! 190:
! 191: case PRU_SOCKADDR:
! 192: KASSERT(nam != NULL);
! 193: sa = mtod(nam, struct sockaddr_bt *);
! 194: nam->m_len = sizeof(struct sockaddr_bt);
! 195: return l2cap_sockaddr(pcb, sa);
! 196:
! 197: case PRU_SHUTDOWN:
! 198: socantsendmore(up);
! 199: break;
! 200:
! 201: case PRU_SEND:
! 202: KASSERT(m != NULL);
! 203: if (m->m_pkthdr.len == 0)
! 204: break;
! 205:
! 206: if (m->m_pkthdr.len > pcb->lc_omtu) {
! 207: err = EMSGSIZE;
! 208: break;
! 209: }
! 210:
! 211: m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
! 212: if (m0 == NULL) {
! 213: err = ENOMEM;
! 214: break;
! 215: }
! 216:
! 217: if (ctl) /* no use for that */
! 218: m_freem(ctl);
! 219:
! 220: sbappendrecord(&up->so_snd, m);
! 221: return l2cap_send(pcb, m0);
! 222:
! 223: case PRU_SENSE:
! 224: return 0; /* (no release) */
! 225:
! 226: case PRU_RCVD:
! 227: case PRU_RCVOOB:
! 228: return EOPNOTSUPP; /* (no release) */
! 229:
! 230: case PRU_LISTEN:
! 231: return l2cap_listen(pcb);
! 232:
! 233: case PRU_ACCEPT:
! 234: KASSERT(nam != NULL);
! 235: sa = mtod(nam, struct sockaddr_bt *);
! 236: nam->m_len = sizeof(struct sockaddr_bt);
! 237: return l2cap_peeraddr(pcb, sa);
! 238:
! 239: case PRU_CONNECT2:
! 240: case PRU_SENDOOB:
! 241: case PRU_FASTTIMO:
! 242: case PRU_SLOWTIMO:
! 243: case PRU_PROTORCV:
! 244: case PRU_PROTOSEND:
! 245: err = EOPNOTSUPP;
! 246: break;
! 247:
! 248: default:
! 249: UNKNOWN(req);
! 250: err = EOPNOTSUPP;
! 251: break;
! 252: }
! 253:
! 254: release:
! 255: if (m) m_freem(m);
! 256: if (ctl) m_freem(ctl);
! 257: return err;
! 258: }
! 259:
! 260: /*
! 261: * l2cap_ctloutput(request, socket, level, optname, opt)
! 262: *
! 263: * Apply configuration commands to channel. This corresponds to
! 264: * "Reconfigure Channel Request" in the L2CAP specification.
! 265: */
! 266: int
! 267: l2cap_ctloutput(int req, struct socket *so, int level,
! 268: int optname, struct mbuf **opt)
! 269: {
! 270: struct l2cap_channel *pcb = so->so_pcb;
! 271: struct mbuf *m;
! 272: int err = 0;
! 273:
! 274: #ifdef notyet /* XXX */
! 275: DPRINTFN(2, "%s\n", prcorequests[req]);
! 276: #endif
! 277:
! 278: if (pcb == NULL)
! 279: return EINVAL;
! 280:
! 281: if (level != BTPROTO_L2CAP)
! 282: return ENOPROTOOPT;
! 283:
! 284: switch(req) {
! 285: case PRCO_GETOPT:
! 286: m = m_get(M_WAIT, MT_SOOPTS);
! 287: m->m_len = l2cap_getopt(pcb, optname, mtod(m, void *));
! 288: if (m->m_len == 0) {
! 289: m_freem(m);
! 290: m = NULL;
! 291: err = ENOPROTOOPT;
! 292: }
! 293: *opt = m;
! 294: break;
! 295:
! 296: case PRCO_SETOPT:
! 297: m = *opt;
! 298: KASSERT(m != NULL);
! 299: err = l2cap_setopt(pcb, optname, mtod(m, void *));
! 300: m_freem(m);
! 301: break;
! 302:
! 303: default:
! 304: err = ENOPROTOOPT;
! 305: break;
! 306: }
! 307:
! 308: return err;
! 309: }
! 310:
! 311: /**********************************************************************
! 312: *
! 313: * L2CAP Protocol socket callbacks
! 314: *
! 315: */
! 316:
! 317: static void
! 318: l2cap_connecting(void *arg)
! 319: {
! 320: struct socket *so = arg;
! 321:
! 322: DPRINTF("Connecting\n");
! 323: soisconnecting(so);
! 324: }
! 325:
! 326: static void
! 327: l2cap_connected(void *arg)
! 328: {
! 329: struct socket *so = arg;
! 330:
! 331: DPRINTF("Connected\n");
! 332: soisconnected(so);
! 333: }
! 334:
! 335: static void
! 336: l2cap_disconnected(void *arg, int err)
! 337: {
! 338: struct socket *so = arg;
! 339:
! 340: DPRINTF("Disconnected (%d)\n", err);
! 341:
! 342: so->so_error = err;
! 343: soisdisconnected(so);
! 344: }
! 345:
! 346: static void *
! 347: l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
! 348: struct sockaddr_bt *raddr)
! 349: {
! 350: struct socket *so = arg;
! 351:
! 352: DPRINTF("New Connection\n");
! 353: so = sonewconn(so, 0);
! 354: if (so == NULL)
! 355: return NULL;
! 356:
! 357: soisconnecting(so);
! 358:
! 359: return so->so_pcb;
! 360: }
! 361:
! 362: static void
! 363: l2cap_complete(void *arg, int count)
! 364: {
! 365: struct socket *so = arg;
! 366:
! 367: while (count-- > 0)
! 368: sbdroprecord(&so->so_snd);
! 369:
! 370: sowwakeup(so);
! 371: }
! 372:
! 373: static void
! 374: l2cap_linkmode(void *arg, int new)
! 375: {
! 376: struct socket *so = arg;
! 377: int mode;
! 378:
! 379: DPRINTF("auth %s, encrypt %s, secure %s\n",
! 380: (new & L2CAP_LM_AUTH ? "on" : "off"),
! 381: (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
! 382: (new & L2CAP_LM_SECURE ? "on" : "off"));
! 383:
! 384: (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
! 385: if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
! 386: || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
! 387: || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
! 388: l2cap_disconnect(so->so_pcb, 0);
! 389: }
! 390:
! 391: static void
! 392: l2cap_input(void *arg, struct mbuf *m)
! 393: {
! 394: struct socket *so = arg;
! 395:
! 396: if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
! 397: printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
! 398: __func__, m->m_pkthdr.len);
! 399: m_freem(m);
! 400: return;
! 401: }
! 402:
! 403: DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
! 404:
! 405: sbappendrecord(&so->so_rcv, m);
! 406: sorwakeup(so);
! 407: }
CVSweb