xref: /dflybsd-src/sys/netbt/hci_ioctl.c (revision 2b3f93ea6d1f70880f3e87f3c2cbe0dc0bfc9332)
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