183aacedeSHasso Tepper /* $OpenBSD: src/sys/netbt/hci_ioctl.c,v 1.2 2008/02/24 21:34:48 uwe Exp $ */
283aacedeSHasso Tepper /* $NetBSD: hci_ioctl.c,v 1.7 2007/11/28 20:16:12 plunky Exp $ */
30a9108ebSHasso Tepper
40a9108ebSHasso Tepper /*-
50a9108ebSHasso Tepper * Copyright (c) 2005 Iain Hibbert.
60a9108ebSHasso Tepper * Copyright (c) 2006 Itronix Inc.
70a9108ebSHasso Tepper * All rights reserved.
80a9108ebSHasso Tepper *
90a9108ebSHasso Tepper * Redistribution and use in source and binary forms, with or without
100a9108ebSHasso Tepper * modification, are permitted provided that the following conditions
110a9108ebSHasso Tepper * are met:
120a9108ebSHasso Tepper * 1. Redistributions of source code must retain the above copyright
130a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer.
140a9108ebSHasso Tepper * 2. Redistributions in binary form must reproduce the above copyright
150a9108ebSHasso Tepper * notice, this list of conditions and the following disclaimer in the
160a9108ebSHasso Tepper * documentation and/or other materials provided with the distribution.
170a9108ebSHasso Tepper * 3. The name of Itronix Inc. may not be used to endorse
180a9108ebSHasso Tepper * or promote products derived from this software without specific
190a9108ebSHasso Tepper * prior written permission.
200a9108ebSHasso Tepper *
210a9108ebSHasso Tepper * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
220a9108ebSHasso Tepper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
230a9108ebSHasso Tepper * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
240a9108ebSHasso Tepper * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
250a9108ebSHasso Tepper * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
260a9108ebSHasso Tepper * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
270a9108ebSHasso Tepper * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
280a9108ebSHasso Tepper * ON ANY THEORY OF LIABILITY, WHETHER IN
290a9108ebSHasso Tepper * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
300a9108ebSHasso Tepper * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
310a9108ebSHasso Tepper * POSSIBILITY OF SUCH DAMAGE.
320a9108ebSHasso Tepper */
330a9108ebSHasso Tepper
340a9108ebSHasso Tepper #include <sys/param.h>
350a9108ebSHasso Tepper #include <sys/domain.h>
360a9108ebSHasso Tepper #include <sys/kernel.h>
370a9108ebSHasso Tepper #include <sys/mbuf.h>
380a9108ebSHasso Tepper #include <sys/proc.h>
39*2b3f93eaSMatthew Dillon #include <sys/caps.h>
400a9108ebSHasso Tepper #include <sys/systm.h>
410a9108ebSHasso Tepper #include <sys/bus.h>
420a9108ebSHasso Tepper
430a9108ebSHasso Tepper #include <netbt/bluetooth.h>
440a9108ebSHasso Tepper #include <netbt/hci.h>
450a9108ebSHasso Tepper #include <netbt/l2cap.h>
460a9108ebSHasso Tepper #include <netbt/rfcomm.h>
470a9108ebSHasso Tepper
480a9108ebSHasso Tepper #ifdef BLUETOOTH_DEBUG
490a9108ebSHasso Tepper #define BDADDR(bd) (bd).b[5], (bd).b[4], (bd).b[3], \
500a9108ebSHasso Tepper (bd).b[2], (bd).b[1], (bd).b[0]
510a9108ebSHasso Tepper
520a9108ebSHasso Tepper static void
hci_dump(void)530a9108ebSHasso Tepper hci_dump(void)
540a9108ebSHasso Tepper {
550a9108ebSHasso Tepper struct hci_unit *unit;
560a9108ebSHasso Tepper struct hci_link *link;
570a9108ebSHasso Tepper struct l2cap_channel *chan;
580a9108ebSHasso Tepper struct rfcomm_session *rs;
590a9108ebSHasso Tepper struct rfcomm_dlc *dlc;
600a9108ebSHasso Tepper
610a9108ebSHasso Tepper kprintf("HCI:\n");
620a9108ebSHasso Tepper TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
630a9108ebSHasso Tepper kprintf("UNIT %s: flags 0x%4.4x, "
640a9108ebSHasso Tepper "num_cmd=%d, num_acl=%d, num_sco=%d\n",
6583aacedeSHasso Tepper device_get_nameunit(unit->hci_dev), unit->hci_flags,
660a9108ebSHasso Tepper unit->hci_num_cmd_pkts,
670a9108ebSHasso Tepper unit->hci_num_acl_pkts,
680a9108ebSHasso Tepper unit->hci_num_sco_pkts);
690a9108ebSHasso Tepper TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
700a9108ebSHasso Tepper kprintf("+HANDLE #%d: %s "
710a9108ebSHasso Tepper "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
720a9108ebSHasso Tepper "state %d, refcnt %d\n",
730a9108ebSHasso Tepper link->hl_handle,
740a9108ebSHasso Tepper (link->hl_type == HCI_LINK_ACL ? "ACL":"SCO"),
750a9108ebSHasso Tepper BDADDR(link->hl_bdaddr),
760a9108ebSHasso Tepper link->hl_state, link->hl_refcnt);
770a9108ebSHasso Tepper }
780a9108ebSHasso Tepper }
790a9108ebSHasso Tepper
800a9108ebSHasso Tepper kprintf("L2CAP:\n");
810a9108ebSHasso Tepper LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
820a9108ebSHasso Tepper kprintf("CID #%d state %d, psm=0x%4.4x, "
830a9108ebSHasso Tepper "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
840a9108ebSHasso Tepper "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
850a9108ebSHasso Tepper chan->lc_lcid, chan->lc_state, chan->lc_raddr.bt_psm,
860a9108ebSHasso Tepper BDADDR(chan->lc_laddr.bt_bdaddr),
870a9108ebSHasso Tepper BDADDR(chan->lc_raddr.bt_bdaddr));
880a9108ebSHasso Tepper }
890a9108ebSHasso Tepper
900a9108ebSHasso Tepper LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
910a9108ebSHasso Tepper kprintf("LISTEN psm=0x%4.4x, "
920a9108ebSHasso Tepper "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
930a9108ebSHasso Tepper chan->lc_laddr.bt_psm,
940a9108ebSHasso Tepper BDADDR(chan->lc_laddr.bt_bdaddr));
950a9108ebSHasso Tepper }
960a9108ebSHasso Tepper
970a9108ebSHasso Tepper kprintf("RFCOMM:\n");
980a9108ebSHasso Tepper LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
990a9108ebSHasso Tepper chan = rs->rs_l2cap;
1000a9108ebSHasso Tepper kprintf("SESSION: state=%d, flags=0x%4.4x, psm 0x%4.4x "
1010a9108ebSHasso Tepper "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
1020a9108ebSHasso Tepper "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
1030a9108ebSHasso Tepper rs->rs_state, rs->rs_flags, chan->lc_raddr.bt_psm,
1040a9108ebSHasso Tepper BDADDR(chan->lc_laddr.bt_bdaddr),
1050a9108ebSHasso Tepper BDADDR(chan->lc_raddr.bt_bdaddr));
1060a9108ebSHasso Tepper LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
1070a9108ebSHasso Tepper kprintf("+DLC channel=%d, dlci=%d, "
1080a9108ebSHasso Tepper "state=%d, flags=0x%4.4x, rxcred=%d, rxsize=%ld, "
1090a9108ebSHasso Tepper "txcred=%d, pending=%d, txqlen=%d\n",
1100a9108ebSHasso Tepper dlc->rd_raddr.bt_channel, dlc->rd_dlci,
1110a9108ebSHasso Tepper dlc->rd_state, dlc->rd_flags,
1120a9108ebSHasso Tepper dlc->rd_rxcred, (unsigned long)dlc->rd_rxsize,
1130a9108ebSHasso Tepper dlc->rd_txcred, dlc->rd_pending,
1140a9108ebSHasso Tepper (dlc->rd_txbuf ? dlc->rd_txbuf->m_pkthdr.len : 0));
1150a9108ebSHasso Tepper }
1160a9108ebSHasso Tepper }
1170a9108ebSHasso Tepper
1180a9108ebSHasso Tepper LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
1190a9108ebSHasso Tepper chan = rs->rs_l2cap;
1200a9108ebSHasso Tepper kprintf("LISTEN: psm 0x%4.4x, "
1210a9108ebSHasso Tepper "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
1220a9108ebSHasso Tepper chan->lc_laddr.bt_psm,
1230a9108ebSHasso Tepper BDADDR(chan->lc_laddr.bt_bdaddr));
1240a9108ebSHasso Tepper LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next)
1250a9108ebSHasso Tepper kprintf("+DLC channel=%d\n", dlc->rd_laddr.bt_channel);
1260a9108ebSHasso Tepper }
1270a9108ebSHasso Tepper }
1280a9108ebSHasso Tepper
1290a9108ebSHasso Tepper #undef BDADDR
1300a9108ebSHasso Tepper #endif
1310a9108ebSHasso Tepper
1320a9108ebSHasso Tepper int
hci_ioctl(unsigned long cmd,void * data,struct proc * p)1330a9108ebSHasso Tepper hci_ioctl(unsigned long cmd, void *data, struct proc *p)
1340a9108ebSHasso Tepper {
1350a9108ebSHasso Tepper struct btreq *btr = data;
1360a9108ebSHasso Tepper struct hci_unit *unit;
1370a9108ebSHasso Tepper int err = 0;
1380a9108ebSHasso Tepper
1390a9108ebSHasso Tepper DPRINTFN(1, "cmd %#lx\n", cmd);
1400a9108ebSHasso Tepper
1410a9108ebSHasso Tepper switch(cmd) {
1420a9108ebSHasso Tepper #ifdef BLUETOOTH_DEBUG
1430a9108ebSHasso Tepper case SIOCBTDUMP:
1440a9108ebSHasso Tepper hci_dump();
1450a9108ebSHasso Tepper return 0;
1460a9108ebSHasso Tepper #endif
1470a9108ebSHasso Tepper /*
1480a9108ebSHasso Tepper * Get unit info based on address rather than name
1490a9108ebSHasso Tepper */
1500a9108ebSHasso Tepper case SIOCGBTINFOA:
1510a9108ebSHasso Tepper unit = hci_unit_lookup(&btr->btr_bdaddr);
1520a9108ebSHasso Tepper if (unit == NULL)
1530a9108ebSHasso Tepper return ENXIO;
1540a9108ebSHasso Tepper
1550a9108ebSHasso Tepper break;
1560a9108ebSHasso Tepper
1570a9108ebSHasso Tepper /*
1580a9108ebSHasso Tepper * The remaining ioctl's all use the same btreq structure and
1590a9108ebSHasso Tepper * index on the name of the device, so we look that up first.
1600a9108ebSHasso Tepper */
1610a9108ebSHasso Tepper case SIOCNBTINFO:
1620a9108ebSHasso Tepper /* empty name means give the first unit */
1630a9108ebSHasso Tepper if (btr->btr_name[0] == '\0') {
1640a9108ebSHasso Tepper unit = NULL;
1650a9108ebSHasso Tepper break;
1660a9108ebSHasso Tepper }
1670a9108ebSHasso Tepper
1680a9108ebSHasso Tepper /* else fall through and look it up */
1690a9108ebSHasso Tepper case SIOCGBTINFO:
1700a9108ebSHasso Tepper case SIOCSBTFLAGS:
1710a9108ebSHasso Tepper case SIOCSBTPOLICY:
1720a9108ebSHasso Tepper case SIOCSBTPTYPE:
1730a9108ebSHasso Tepper case SIOCGBTSTATS:
1740a9108ebSHasso Tepper case SIOCZBTSTATS:
1750a9108ebSHasso Tepper case SIOCSBTSCOMTU:
1760a9108ebSHasso Tepper TAILQ_FOREACH(unit, &hci_unit_list, hci_next) {
17783aacedeSHasso Tepper if (strncmp(device_get_nameunit(unit->hci_dev),
17883aacedeSHasso Tepper btr->btr_name, HCI_DEVNAME_SIZE) == 0)
1790a9108ebSHasso Tepper break;
1800a9108ebSHasso Tepper }
1810a9108ebSHasso Tepper
1820a9108ebSHasso Tepper if (unit == NULL)
1830a9108ebSHasso Tepper return ENXIO;
1840a9108ebSHasso Tepper
1850a9108ebSHasso Tepper break;
1860a9108ebSHasso Tepper
1870a9108ebSHasso Tepper default: /* not one of mine */
1880a9108ebSHasso Tepper return EPASSTHROUGH;
1890a9108ebSHasso Tepper }
1900a9108ebSHasso Tepper
1910a9108ebSHasso Tepper switch(cmd) {
1920a9108ebSHasso Tepper case SIOCNBTINFO: /* get next info */
1930a9108ebSHasso Tepper if (unit)
1940a9108ebSHasso Tepper unit = TAILQ_NEXT(unit, hci_next);
1950a9108ebSHasso Tepper else
1960a9108ebSHasso Tepper unit = TAILQ_FIRST(&hci_unit_list);
1970a9108ebSHasso Tepper
1980a9108ebSHasso Tepper if (unit == NULL) {
1990a9108ebSHasso Tepper err = ENXIO;
2000a9108ebSHasso Tepper break;
2010a9108ebSHasso Tepper }
2020a9108ebSHasso Tepper
2030a9108ebSHasso Tepper /* and fall through to */
2040a9108ebSHasso Tepper case SIOCGBTINFO: /* get unit info */
2050a9108ebSHasso Tepper case SIOCGBTINFOA: /* get info by address */
2060a9108ebSHasso Tepper memset(btr, 0, sizeof(struct btreq));
20783aacedeSHasso Tepper strlcpy(btr->btr_name, device_get_nameunit(unit->hci_dev),
20883aacedeSHasso Tepper HCI_DEVNAME_SIZE);
2090a9108ebSHasso Tepper bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr);
2100a9108ebSHasso Tepper
2110a9108ebSHasso Tepper btr->btr_flags = unit->hci_flags;
2120a9108ebSHasso Tepper
2130a9108ebSHasso Tepper btr->btr_num_cmd = unit->hci_num_cmd_pkts;
2140a9108ebSHasso Tepper btr->btr_num_acl = unit->hci_num_acl_pkts;
2150a9108ebSHasso Tepper btr->btr_num_sco = unit->hci_num_sco_pkts;
2160a9108ebSHasso Tepper btr->btr_acl_mtu = unit->hci_max_acl_size;
2170a9108ebSHasso Tepper btr->btr_sco_mtu = unit->hci_max_sco_size;
2180a9108ebSHasso Tepper
2190a9108ebSHasso Tepper btr->btr_packet_type = unit->hci_packet_type;
2200a9108ebSHasso Tepper btr->btr_link_policy = unit->hci_link_policy;
2210a9108ebSHasso Tepper break;
2220a9108ebSHasso Tepper
2230a9108ebSHasso Tepper case SIOCSBTFLAGS: /* set unit flags (privileged) */
224*2b3f93eaSMatthew Dillon err = caps_priv_check_self(SYSCAP_RESTRICTEDROOT);
2250a9108ebSHasso Tepper if (err)
2260a9108ebSHasso Tepper break;
2270a9108ebSHasso Tepper
2280a9108ebSHasso Tepper if ((unit->hci_flags & BTF_UP)
2290a9108ebSHasso Tepper && (btr->btr_flags & BTF_UP) == 0) {
2300a9108ebSHasso Tepper hci_disable(unit);
2310a9108ebSHasso Tepper unit->hci_flags &= ~BTF_UP;
2320a9108ebSHasso Tepper }
2330a9108ebSHasso Tepper
2340a9108ebSHasso Tepper unit->hci_flags |= (btr->btr_flags & BTF_INIT);
2350a9108ebSHasso Tepper
2360a9108ebSHasso Tepper if ((unit->hci_flags & BTF_UP) == 0
2370a9108ebSHasso Tepper && (btr->btr_flags & BTF_UP)) {
2380a9108ebSHasso Tepper err = hci_enable(unit);
2390a9108ebSHasso Tepper if (err)
2400a9108ebSHasso Tepper break;
2410a9108ebSHasso Tepper
2420a9108ebSHasso Tepper unit->hci_flags |= BTF_UP;
2430a9108ebSHasso Tepper }
2440a9108ebSHasso Tepper
2450a9108ebSHasso Tepper btr->btr_flags = unit->hci_flags;
2460a9108ebSHasso Tepper break;
2470a9108ebSHasso Tepper
2480a9108ebSHasso Tepper case SIOCSBTPOLICY: /* set unit link policy (privileged) */
249*2b3f93eaSMatthew Dillon err = caps_priv_check_self(SYSCAP_RESTRICTEDROOT);
2500a9108ebSHasso Tepper if (err)
2510a9108ebSHasso Tepper break;
2520a9108ebSHasso Tepper
2530a9108ebSHasso Tepper unit->hci_link_policy = btr->btr_link_policy;
2540a9108ebSHasso Tepper unit->hci_link_policy &= unit->hci_lmp_mask;
2550a9108ebSHasso Tepper btr->btr_link_policy = unit->hci_link_policy;
2560a9108ebSHasso Tepper break;
2570a9108ebSHasso Tepper
2580a9108ebSHasso Tepper case SIOCSBTPTYPE: /* set unit packet types (privileged) */
259*2b3f93eaSMatthew Dillon err = caps_priv_check_self(SYSCAP_RESTRICTEDROOT);
2600a9108ebSHasso Tepper if (err)
2610a9108ebSHasso Tepper break;
2620a9108ebSHasso Tepper
2630a9108ebSHasso Tepper unit->hci_packet_type = btr->btr_packet_type;
2640a9108ebSHasso Tepper unit->hci_packet_type &= unit->hci_acl_mask;
2650a9108ebSHasso Tepper btr->btr_packet_type = unit->hci_packet_type;
2660a9108ebSHasso Tepper break;
2670a9108ebSHasso Tepper
2680a9108ebSHasso Tepper case SIOCGBTSTATS: /* get unit statistics */
26983aacedeSHasso Tepper (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 0);
2700a9108ebSHasso Tepper break;
2710a9108ebSHasso Tepper
2720a9108ebSHasso Tepper case SIOCZBTSTATS: /* get & reset unit statistics */
273*2b3f93eaSMatthew Dillon err = caps_priv_check_self(SYSCAP_RESTRICTEDROOT);
2740a9108ebSHasso Tepper if (err)
2750a9108ebSHasso Tepper break;
2760a9108ebSHasso Tepper
27783aacedeSHasso Tepper (*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 1);
2780a9108ebSHasso Tepper break;
2790a9108ebSHasso Tepper
2800a9108ebSHasso Tepper case SIOCSBTSCOMTU: /* set sco_mtu value for unit */
2810a9108ebSHasso Tepper /*
2820a9108ebSHasso Tepper * This is a temporary ioctl and may not be supported
2830a9108ebSHasso Tepper * in the future. The need is that if SCO packets are
2840a9108ebSHasso Tepper * sent to USB bluetooth controllers that are not an
2850a9108ebSHasso Tepper * integer number of frame sizes, the USB bus locks up.
2860a9108ebSHasso Tepper */
287*2b3f93eaSMatthew Dillon err = caps_priv_check_self(SYSCAP_RESTRICTEDROOT);
2880a9108ebSHasso Tepper if (err)
2890a9108ebSHasso Tepper break;
2900a9108ebSHasso Tepper
2910a9108ebSHasso Tepper unit->hci_max_sco_size = btr->btr_sco_mtu;
2920a9108ebSHasso Tepper break;
2930a9108ebSHasso Tepper
2940a9108ebSHasso Tepper default:
2950a9108ebSHasso Tepper err = EFAULT;
2960a9108ebSHasso Tepper break;
2970a9108ebSHasso Tepper }
2980a9108ebSHasso Tepper
2990a9108ebSHasso Tepper return err;
3000a9108ebSHasso Tepper }
301