Annotation of sys/netbt/hci_ioctl.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: hci_ioctl.c,v 1.1 2007/06/01 02:46:11 uwe Exp $ */
! 2: /* $NetBSD: hci_ioctl.c,v 1.5 2007/01/04 19:07:03 elad 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: #include <sys/param.h>
! 37: #include <sys/domain.h>
! 38: #include <sys/ioctl.h>
! 39: #include <sys/kernel.h>
! 40: #include <sys/mbuf.h>
! 41: #include <sys/proc.h>
! 42: #include <sys/systm.h>
! 43:
! 44: #include <netbt/bluetooth.h>
! 45: #include <netbt/hci.h>
! 46: #include <netbt/l2cap.h>
! 47: #include <netbt/rfcomm.h>
! 48:
! 49: #ifdef BLUETOOTH_DEBUG
! 50: #define BDADDR(bd) (bd).b[5], (bd).b[4], (bd).b[3], \
! 51: (bd).b[2], (bd).b[1], (bd).b[0]
! 52:
! 53: static void
! 54: hci_dump(void)
! 55: {
! 56: struct hci_unit *unit;
! 57: struct hci_link *link;
! 58: struct l2cap_channel *chan;
! 59: struct rfcomm_session *rs;
! 60: struct rfcomm_dlc *dlc;
! 61:
! 62: printf("HCI:\n");
! 63: TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
! 64: printf("UNIT %s: flags 0x%4.4x, "
! 65: "num_cmd=%d, num_acl=%d, num_sco=%d\n",
! 66: unit->hci_devname, unit->hci_flags,
! 67: unit->hci_num_cmd_pkts,
! 68: unit->hci_num_acl_pkts,
! 69: unit->hci_num_sco_pkts);
! 70: TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
! 71: printf("+HANDLE #%d: %s "
! 72: "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
! 73: "state %d, refcnt %d\n",
! 74: link->hl_handle,
! 75: (link->hl_type == HCI_LINK_ACL ? "ACL":"SCO"),
! 76: BDADDR(link->hl_bdaddr),
! 77: link->hl_state, link->hl_refcnt);
! 78: }
! 79: }
! 80:
! 81: printf("L2CAP:\n");
! 82: LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
! 83: printf("CID #%d state %d, psm=0x%4.4x, "
! 84: "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
! 85: "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
! 86: chan->lc_lcid, chan->lc_state, chan->lc_raddr.bt_psm,
! 87: BDADDR(chan->lc_laddr.bt_bdaddr),
! 88: BDADDR(chan->lc_raddr.bt_bdaddr));
! 89: }
! 90:
! 91: LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
! 92: printf("LISTEN psm=0x%4.4x, "
! 93: "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
! 94: chan->lc_laddr.bt_psm,
! 95: BDADDR(chan->lc_laddr.bt_bdaddr));
! 96: }
! 97:
! 98: printf("RFCOMM:\n");
! 99: LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
! 100: chan = rs->rs_l2cap;
! 101: printf("SESSION: state=%d, flags=0x%4.4x, psm 0x%4.4x "
! 102: "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
! 103: "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
! 104: rs->rs_state, rs->rs_flags, chan->lc_raddr.bt_psm,
! 105: BDADDR(chan->lc_laddr.bt_bdaddr),
! 106: BDADDR(chan->lc_raddr.bt_bdaddr));
! 107: LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
! 108: printf("+DLC channel=%d, dlci=%d, "
! 109: "state=%d, flags=0x%4.4x, rxcred=%d, rxsize=%ld, "
! 110: "txcred=%d, pending=%d, txqlen=%d\n",
! 111: dlc->rd_raddr.bt_channel, dlc->rd_dlci,
! 112: dlc->rd_state, dlc->rd_flags,
! 113: dlc->rd_rxcred, (unsigned long)dlc->rd_rxsize,
! 114: dlc->rd_txcred, dlc->rd_pending,
! 115: (dlc->rd_txbuf ? dlc->rd_txbuf->m_pkthdr.len : 0));
! 116: }
! 117: }
! 118:
! 119: LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
! 120: chan = rs->rs_l2cap;
! 121: printf("LISTEN: psm 0x%4.4x, "
! 122: "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
! 123: chan->lc_laddr.bt_psm,
! 124: BDADDR(chan->lc_laddr.bt_bdaddr));
! 125: LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next)
! 126: printf("+DLC channel=%d\n", dlc->rd_laddr.bt_channel);
! 127: }
! 128: }
! 129:
! 130: #undef BDADDR
! 131: #endif
! 132:
! 133: int
! 134: hci_ioctl(unsigned long cmd, void *data, struct proc *p)
! 135: {
! 136: struct btreq *btr = data;
! 137: struct hci_unit *unit;
! 138: int s, err = 0;
! 139:
! 140: DPRINTFN(1, "cmd %#lx\n", cmd);
! 141:
! 142: switch(cmd) {
! 143: #ifdef BLUETOOTH_DEBUG
! 144: case SIOCBTDUMP:
! 145: hci_dump();
! 146: return 0;
! 147: #endif
! 148: /*
! 149: * Get unit info based on address rather than name
! 150: */
! 151: case SIOCGBTINFOA:
! 152: unit = hci_unit_lookup(&btr->btr_bdaddr);
! 153: if (unit == NULL)
! 154: return ENXIO;
! 155:
! 156: break;
! 157:
! 158: /*
! 159: * The remaining ioctl's all use the same btreq structure and
! 160: * index on the name of the device, so we look that up first.
! 161: */
! 162: case SIOCNBTINFO:
! 163: /* empty name means give the first unit */
! 164: if (btr->btr_name[0] == '\0') {
! 165: unit = NULL;
! 166: break;
! 167: }
! 168:
! 169: /* else fall through and look it up */
! 170: case SIOCGBTINFO:
! 171: case SIOCSBTFLAGS:
! 172: case SIOCSBTPOLICY:
! 173: case SIOCSBTPTYPE:
! 174: case SIOCGBTSTATS:
! 175: case SIOCZBTSTATS:
! 176: case SIOCSBTSCOMTU:
! 177: TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
! 178: if (strncmp(unit->hci_devname, btr->btr_name,
! 179: HCI_DEVNAME_SIZE) == 0)
! 180: break;
! 181: }
! 182:
! 183: if (unit == NULL)
! 184: return ENXIO;
! 185:
! 186: break;
! 187:
! 188: default: /* not one of mine */
! 189: return EPASSTHROUGH;
! 190: }
! 191:
! 192: switch(cmd) {
! 193: case SIOCNBTINFO: /* get next info */
! 194: if (unit)
! 195: unit = TAILQ_NEXT(unit, hci_next);
! 196: else
! 197: unit = TAILQ_FIRST(&hci_unit_list);
! 198:
! 199: if (unit == NULL) {
! 200: err = ENXIO;
! 201: break;
! 202: }
! 203:
! 204: /* and fall through to */
! 205: case SIOCGBTINFO: /* get unit info */
! 206: case SIOCGBTINFOA: /* get info by address */
! 207: memset(btr, 0, sizeof(struct btreq));
! 208: strlcpy(btr->btr_name, unit->hci_devname, HCI_DEVNAME_SIZE);
! 209: bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr);
! 210:
! 211: btr->btr_flags = unit->hci_flags;
! 212:
! 213: btr->btr_num_cmd = unit->hci_num_cmd_pkts;
! 214: btr->btr_num_acl = unit->hci_num_acl_pkts;
! 215: btr->btr_num_sco = unit->hci_num_sco_pkts;
! 216: btr->btr_acl_mtu = unit->hci_max_acl_size;
! 217: btr->btr_sco_mtu = unit->hci_max_sco_size;
! 218:
! 219: btr->btr_packet_type = unit->hci_packet_type;
! 220: btr->btr_link_policy = unit->hci_link_policy;
! 221: break;
! 222:
! 223: case SIOCSBTFLAGS: /* set unit flags (privileged) */
! 224: err = suser(p, 0);
! 225: if (err)
! 226: break;
! 227:
! 228: if ((unit->hci_flags & BTF_UP)
! 229: && (btr->btr_flags & BTF_UP) == 0) {
! 230: hci_disable(unit);
! 231: unit->hci_flags &= ~BTF_UP;
! 232: }
! 233:
! 234: s = splraiseipl(unit->hci_ipl);
! 235: unit->hci_flags |= (btr->btr_flags & BTF_INIT);
! 236: splx(s);
! 237:
! 238: if ((unit->hci_flags & BTF_UP) == 0
! 239: && (btr->btr_flags & BTF_UP)) {
! 240: err = hci_enable(unit);
! 241: if (err)
! 242: break;
! 243:
! 244: s = splraiseipl(unit->hci_ipl);
! 245: unit->hci_flags |= BTF_UP;
! 246: splx(s);
! 247: }
! 248:
! 249: btr->btr_flags = unit->hci_flags;
! 250: break;
! 251:
! 252: case SIOCSBTPOLICY: /* set unit link policy (privileged) */
! 253: err = suser(p, 0);
! 254: if (err)
! 255: break;
! 256:
! 257: unit->hci_link_policy = btr->btr_link_policy;
! 258: unit->hci_link_policy &= unit->hci_lmp_mask;
! 259: btr->btr_link_policy = unit->hci_link_policy;
! 260: break;
! 261:
! 262: case SIOCSBTPTYPE: /* set unit packet types (privileged) */
! 263: err = suser(p, 0);
! 264: if (err)
! 265: break;
! 266:
! 267: unit->hci_packet_type = btr->btr_packet_type;
! 268: unit->hci_packet_type &= unit->hci_acl_mask;
! 269: btr->btr_packet_type = unit->hci_packet_type;
! 270: break;
! 271:
! 272: case SIOCGBTSTATS: /* get unit statistics */
! 273: s = splraiseipl(unit->hci_ipl);
! 274: memcpy(&btr->btr_stats, &unit->hci_stats,
! 275: sizeof(struct bt_stats));
! 276: splx(s);
! 277: break;
! 278:
! 279: case SIOCZBTSTATS: /* get & reset unit statistics */
! 280: err = suser(p, 0);
! 281: if (err)
! 282: break;
! 283:
! 284: s = splraiseipl(unit->hci_ipl);
! 285: memcpy(&btr->btr_stats, &unit->hci_stats,
! 286: sizeof(struct bt_stats));
! 287: memset(&unit->hci_stats, 0, sizeof(struct bt_stats));
! 288: splx(s);
! 289:
! 290: break;
! 291:
! 292: case SIOCSBTSCOMTU: /* set sco_mtu value for unit */
! 293: /*
! 294: * This is a temporary ioctl and may not be supported
! 295: * in the future. The need is that if SCO packets are
! 296: * sent to USB bluetooth controllers that are not an
! 297: * integer number of frame sizes, the USB bus locks up.
! 298: */
! 299: err = suser(p, 0);
! 300: if (err)
! 301: break;
! 302:
! 303: unit->hci_max_sco_size = btr->btr_sco_mtu;
! 304: break;
! 305:
! 306: default:
! 307: err = EFAULT;
! 308: break;
! 309: }
! 310:
! 311: return err;
! 312: }
CVSweb