Annotation of sys/netbt/sco_upper.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: sco_upper.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ */
! 2: /* $NetBSD: sco_upper.c,v 1.6 2007/03/30 20:47:03 plunky Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2006 Itronix Inc.
! 6: * All rights reserved.
! 7: *
! 8: * Written by Iain Hibbert for Itronix Inc.
! 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: #include <sys/param.h>
! 38: #include <sys/kernel.h>
! 39: #include <sys/mbuf.h>
! 40: #include <sys/proc.h>
! 41: #include <sys/systm.h>
! 42:
! 43: #include <netbt/bluetooth.h>
! 44: #include <netbt/hci.h>
! 45: #include <netbt/sco.h>
! 46:
! 47: /****************************************************************************
! 48: *
! 49: * SCO - Upper Protocol API
! 50: */
! 51:
! 52: struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb);
! 53:
! 54: /*
! 55: * sco_attach(handle, proto, upper)
! 56: *
! 57: * Attach a new instance of SCO pcb to handle
! 58: */
! 59: int
! 60: sco_attach(struct sco_pcb **handle,
! 61: const struct btproto *proto, void *upper)
! 62: {
! 63: struct sco_pcb *pcb;
! 64:
! 65: KASSERT(handle != NULL);
! 66: KASSERT(proto != NULL);
! 67: KASSERT(upper != NULL);
! 68:
! 69: pcb = malloc(sizeof(struct sco_pcb), M_BLUETOOTH, M_NOWAIT);
! 70: if (pcb == NULL)
! 71: return ENOMEM;
! 72: bzero(pcb, sizeof *pcb);
! 73:
! 74: pcb->sp_proto = proto;
! 75: pcb->sp_upper = upper;
! 76:
! 77: LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next);
! 78:
! 79: *handle = pcb;
! 80: return 0;
! 81: }
! 82:
! 83: /*
! 84: * sco_bind(pcb, sockaddr)
! 85: *
! 86: * Bind SCO pcb to local address
! 87: */
! 88: int
! 89: sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr)
! 90: {
! 91:
! 92: bdaddr_copy(&pcb->sp_laddr, &addr->bt_bdaddr);
! 93: return 0;
! 94: }
! 95:
! 96: /*
! 97: * sco_sockaddr(pcb, sockaddr)
! 98: *
! 99: * Copy local address of PCB to sockaddr
! 100: */
! 101: int
! 102: sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
! 103: {
! 104:
! 105: memset(addr, 0, sizeof(struct sockaddr_bt));
! 106: addr->bt_len = sizeof(struct sockaddr_bt);
! 107: addr->bt_family = AF_BLUETOOTH;
! 108: bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_laddr);
! 109: return 0;
! 110: }
! 111:
! 112: /*
! 113: * sco_connect(pcb, sockaddr)
! 114: *
! 115: * Initiate a SCO connection to the destination address.
! 116: */
! 117: int
! 118: sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest)
! 119: {
! 120: hci_add_sco_con_cp cp;
! 121: struct hci_unit *unit;
! 122: struct hci_link *acl, *sco;
! 123: int err;
! 124:
! 125: if (pcb->sp_flags & SP_LISTENING)
! 126: return EINVAL;
! 127:
! 128: bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr);
! 129:
! 130: if (bdaddr_any(&pcb->sp_raddr))
! 131: return EDESTADDRREQ;
! 132:
! 133: if (bdaddr_any(&pcb->sp_laddr)) {
! 134: err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr);
! 135: if (err)
! 136: return err;
! 137: }
! 138:
! 139: unit = hci_unit_lookup(&pcb->sp_laddr);
! 140: if (unit == NULL)
! 141: return ENETDOWN;
! 142:
! 143: /*
! 144: * We must have an already open ACL connection before we open the SCO
! 145: * connection, and since SCO connections dont happen on their own we
! 146: * will not open one, the application wanting this should have opened
! 147: * it previously.
! 148: */
! 149: acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL);
! 150: if (acl == NULL || acl->hl_state != HCI_LINK_OPEN)
! 151: return EHOSTUNREACH;
! 152:
! 153: sco = hci_link_alloc(unit);
! 154: if (sco == NULL)
! 155: return ENOMEM;
! 156:
! 157: sco->hl_type = HCI_LINK_SCO;
! 158: bdaddr_copy(&sco->hl_bdaddr, &pcb->sp_raddr);
! 159:
! 160: sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr);
! 161: KASSERT(sco->hl_link == acl);
! 162:
! 163: cp.con_handle = htole16(acl->hl_handle);
! 164: cp.pkt_type = htole16(0x00e0); /* HV1, HV2, HV3 */
! 165: err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp));
! 166: if (err) {
! 167: hci_link_free(sco, err);
! 168: return err;
! 169: }
! 170:
! 171: sco->hl_sco = pcb;
! 172: pcb->sp_link = sco;
! 173:
! 174: pcb->sp_mtu = unit->hci_max_sco_size;
! 175: return 0;
! 176: }
! 177:
! 178: /*
! 179: * sco_peeraddr(pcb, sockaddr)
! 180: *
! 181: * Copy remote address of SCO pcb to sockaddr
! 182: */
! 183: int
! 184: sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
! 185: {
! 186:
! 187: memset(addr, 0, sizeof(struct sockaddr_bt));
! 188: addr->bt_len = sizeof(struct sockaddr_bt);
! 189: addr->bt_family = AF_BLUETOOTH;
! 190: bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_raddr);
! 191: return 0;
! 192: }
! 193:
! 194: /*
! 195: * sco_disconnect(pcb, linger)
! 196: *
! 197: * Initiate disconnection of connected SCO pcb
! 198: */
! 199: int
! 200: sco_disconnect(struct sco_pcb *pcb, int linger)
! 201: {
! 202: hci_discon_cp cp;
! 203: struct hci_link *sco;
! 204: int err;
! 205:
! 206: sco = pcb->sp_link;
! 207: if (sco == NULL)
! 208: return EINVAL;
! 209:
! 210: cp.con_handle = htole16(sco->hl_handle);
! 211: cp.reason = 0x13; /* "Remote User Terminated Connection" */
! 212:
! 213: err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp));
! 214: if (err || linger == 0) {
! 215: sco->hl_sco = NULL;
! 216: pcb->sp_link = NULL;
! 217: hci_link_free(sco, err);
! 218: }
! 219:
! 220: return err;
! 221: }
! 222:
! 223: /*
! 224: * sco_detach(handle)
! 225: *
! 226: * Detach SCO pcb from handle and clear up
! 227: */
! 228: int
! 229: sco_detach(struct sco_pcb **handle)
! 230: {
! 231: struct sco_pcb *pcb;
! 232:
! 233: KASSERT(handle != NULL);
! 234: pcb = *handle;
! 235: *handle = NULL;
! 236:
! 237: if (pcb == NULL)
! 238: return EINVAL;
! 239:
! 240: if (pcb->sp_link != NULL) {
! 241: sco_disconnect(pcb, 0);
! 242: pcb->sp_link = NULL;
! 243: }
! 244:
! 245: LIST_REMOVE(pcb, sp_next);
! 246: free(pcb, M_BLUETOOTH);
! 247: return 0;
! 248: }
! 249:
! 250: /*
! 251: * sco_listen(pcb)
! 252: *
! 253: * Mark pcb as a listener.
! 254: */
! 255: int
! 256: sco_listen(struct sco_pcb *pcb)
! 257: {
! 258:
! 259: if (pcb->sp_link != NULL)
! 260: return EINVAL;
! 261:
! 262: pcb->sp_flags |= SP_LISTENING;
! 263: return 0;
! 264: }
! 265:
! 266: /*
! 267: * sco_send(pcb, mbuf)
! 268: *
! 269: * Send data on SCO pcb.
! 270: *
! 271: * Gross hackage, we just output the packet directly onto the unit queue.
! 272: * This will work fine for one channel per unit, but for more channels it
! 273: * really needs fixing. We set the context so that when the packet is sent,
! 274: * we can drop a record from the socket buffer.
! 275: */
! 276: int
! 277: sco_send(struct sco_pcb *pcb, struct mbuf *m)
! 278: {
! 279: hci_scodata_hdr_t *hdr;
! 280: int plen;
! 281:
! 282: if (pcb->sp_link == NULL) {
! 283: m_freem(m);
! 284: return EINVAL;
! 285: }
! 286:
! 287: plen = m->m_pkthdr.len;
! 288: DPRINTFN(10, "%d bytes\n", plen);
! 289:
! 290: /*
! 291: * This is a temporary limitation, as USB devices cannot
! 292: * handle SCO packet sizes that are not an integer number
! 293: * of Isochronous frames. See ubt(4)
! 294: */
! 295: if (plen != pcb->sp_mtu) {
! 296: m_freem(m);
! 297: return EMSGSIZE;
! 298: }
! 299:
! 300: M_PREPEND(m, sizeof(hci_scodata_hdr_t), M_DONTWAIT);
! 301: if (m == NULL)
! 302: return ENOMEM;
! 303:
! 304: hdr = mtod(m, hci_scodata_hdr_t *);
! 305: hdr->type = HCI_SCO_DATA_PKT;
! 306: hdr->con_handle = htole16(pcb->sp_link->hl_handle);
! 307: hdr->length = plen;
! 308:
! 309: pcb->sp_pending++;
! 310: M_SETCTX(m, pcb->sp_link);
! 311: hci_output_sco(pcb->sp_link->hl_unit, m);
! 312:
! 313: return 0;
! 314: }
! 315:
! 316: /*
! 317: * sco_setopt(pcb, option, addr)
! 318: *
! 319: * Set SCO pcb options
! 320: */
! 321: int
! 322: sco_setopt(struct sco_pcb *pcb, int opt, void *addr)
! 323: {
! 324: int err = 0;
! 325:
! 326: switch (opt) {
! 327: default:
! 328: err = ENOPROTOOPT;
! 329: break;
! 330: }
! 331:
! 332: return err;
! 333: }
! 334:
! 335: /*
! 336: * sco_getopt(pcb, option, addr)
! 337: *
! 338: * Get SCO pcb options
! 339: */
! 340: int
! 341: sco_getopt(struct sco_pcb *pcb, int opt, void *addr)
! 342: {
! 343:
! 344: switch (opt) {
! 345: case SO_SCO_MTU:
! 346: *(uint16_t *)addr = pcb->sp_mtu;
! 347: return sizeof(uint16_t);
! 348:
! 349: case SO_SCO_HANDLE:
! 350: if (pcb->sp_link) {
! 351: *(uint16_t *)addr = pcb->sp_link->hl_handle;
! 352: return sizeof(uint16_t);
! 353: }
! 354: break;
! 355:
! 356: default:
! 357: break;
! 358: }
! 359: return 0;
! 360: }
CVSweb