Home | History | Annotate | Line # | Download | only in netbt
hci_ioctl.c revision 1.9
      1 /*	$NetBSD: hci_ioctl.c,v 1.9 2009/08/20 21:40:59 plunky Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2005 Iain Hibbert.
      5  * Copyright (c) 2006 Itronix Inc.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. The name of Itronix Inc. may not be used to endorse
     17  *    or promote products derived from this software without specific
     18  *    prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
     21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
     24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     27  * ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: hci_ioctl.c,v 1.9 2009/08/20 21:40:59 plunky Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/domain.h>
     38 #include <sys/ioctl.h>
     39 #include <sys/kauth.h>
     40 #include <sys/kernel.h>
     41 #include <sys/mbuf.h>
     42 #include <sys/proc.h>
     43 #include <sys/systm.h>
     44 
     45 #include <netbt/bluetooth.h>
     46 #include <netbt/hci.h>
     47 #include <netbt/l2cap.h>
     48 #include <netbt/rfcomm.h>
     49 
     50 #ifdef BLUETOOTH_DEBUG
     51 #define BDADDR(bd)	(bd).b[5], (bd).b[4], (bd).b[3],	\
     52 			(bd).b[2], (bd).b[1], (bd).b[0]
     53 
     54 static void
     55 hci_dump(void)
     56 {
     57 	struct hci_unit *unit;
     58 	struct hci_link *link;
     59 	struct l2cap_channel *chan;
     60 	struct rfcomm_session *rs;
     61 	struct rfcomm_dlc *dlc;
     62 
     63 	uprintf("HCI:\n");
     64 	SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
     65 		uprintf("UNIT %s: flags 0x%4.4x, "
     66 			"num_cmd=%d, num_acl=%d, num_sco=%d\n",
     67 			device_xname(unit->hci_dev), unit->hci_flags,
     68 			unit->hci_num_cmd_pkts,
     69 			unit->hci_num_acl_pkts,
     70 			unit->hci_num_sco_pkts);
     71 		TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
     72 			uprintf("+HANDLE #%d: %s "
     73 			    "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
     74 			    "state %d, refcnt %d\n",
     75 			    link->hl_handle,
     76 			    (link->hl_type == HCI_LINK_ACL ? "ACL":"SCO"),
     77 			    BDADDR(link->hl_bdaddr),
     78 			    link->hl_state, link->hl_refcnt);
     79 		}
     80 	}
     81 
     82 	uprintf("L2CAP:\n");
     83 	LIST_FOREACH(chan, &l2cap_active_list, lc_ncid) {
     84 		uprintf("CID #%d state %d, psm=0x%4.4x, "
     85 		    "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
     86 		    "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
     87 		    chan->lc_lcid, chan->lc_state, chan->lc_raddr.bt_psm,
     88 		    BDADDR(chan->lc_laddr.bt_bdaddr),
     89 		    BDADDR(chan->lc_raddr.bt_bdaddr));
     90 	}
     91 
     92 	LIST_FOREACH(chan, &l2cap_listen_list, lc_ncid) {
     93 		uprintf("LISTEN psm=0x%4.4x, "
     94 		    "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
     95 		    chan->lc_laddr.bt_psm,
     96 		    BDADDR(chan->lc_laddr.bt_bdaddr));
     97 	}
     98 
     99 	uprintf("RFCOMM:\n");
    100 	LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
    101 		chan = rs->rs_l2cap;
    102 		uprintf("SESSION: state=%d, flags=0x%4.4x, psm 0x%4.4x "
    103 		    "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
    104 		    "raddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
    105 		    rs->rs_state, rs->rs_flags, chan->lc_raddr.bt_psm,
    106 		    BDADDR(chan->lc_laddr.bt_bdaddr),
    107 		    BDADDR(chan->lc_raddr.bt_bdaddr));
    108 		LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
    109 			uprintf("+DLC channel=%d, dlci=%d, "
    110 			    "state=%d, flags=0x%4.4x, rxcred=%d, rxsize=%ld, "
    111 			    "txcred=%d, pending=%d, txqlen=%d\n",
    112 			    dlc->rd_raddr.bt_channel, dlc->rd_dlci,
    113 			    dlc->rd_state, dlc->rd_flags,
    114 			    dlc->rd_rxcred, (unsigned long)dlc->rd_rxsize,
    115 			    dlc->rd_txcred, dlc->rd_pending,
    116 			    (dlc->rd_txbuf ? dlc->rd_txbuf->m_pkthdr.len : 0));
    117 		}
    118 	}
    119 
    120 	LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
    121 		chan = rs->rs_l2cap;
    122 		uprintf("LISTEN: psm 0x%4.4x, "
    123 		    "laddr=%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
    124 		    chan->lc_laddr.bt_psm,
    125 		    BDADDR(chan->lc_laddr.bt_bdaddr));
    126 		LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next)
    127 			uprintf("+DLC channel=%d\n", dlc->rd_laddr.bt_channel);
    128 	}
    129 }
    130 
    131 #undef BDADDR
    132 #endif
    133 
    134 int
    135 hci_ioctl(unsigned long cmd, void *data, struct lwp *l)
    136 {
    137 	struct btreq *btr = data;
    138 	struct hci_unit *unit;
    139 	int err = 0;
    140 
    141 	DPRINTFN(1, "cmd %#lx\n", cmd);
    142 
    143 	switch(cmd) {
    144 #ifdef BLUETOOTH_DEBUG
    145 	case SIOCBTDUMP:
    146 		hci_dump();
    147 		return 0;
    148 #endif
    149 	/*
    150 	 * Get unit info based on address rather than name
    151 	 */
    152 	case SIOCGBTINFOA:
    153 		unit = hci_unit_lookup(&btr->btr_bdaddr);
    154 		if (unit == NULL)
    155 			return ENXIO;
    156 
    157 		break;
    158 
    159 	/*
    160 	 * The remaining ioctl's all use the same btreq structure and
    161 	 * index on the name of the device, so we look that up first.
    162 	 */
    163 	case SIOCNBTINFO:
    164 		/* empty name means give the first unit */
    165 		if (btr->btr_name[0] == '\0') {
    166 			unit = NULL;
    167 			break;
    168 		}
    169 
    170 		/* else fall through and look it up */
    171 	case SIOCGBTINFO:
    172 	case SIOCSBTFLAGS:
    173 	case SIOCSBTPOLICY:
    174 	case SIOCSBTPTYPE:
    175 	case SIOCGBTSTATS:
    176 	case SIOCZBTSTATS:
    177 	case SIOCSBTSCOMTU:
    178 		SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
    179 			if (strncmp(device_xname(unit->hci_dev),
    180 			    btr->btr_name, HCI_DEVNAME_SIZE) == 0)
    181 				break;
    182 		}
    183 
    184 		if (unit == NULL)
    185 			return ENXIO;
    186 
    187 		break;
    188 
    189 	default:	/* not one of mine */
    190 		return EPASSTHROUGH;
    191 	}
    192 
    193 	switch(cmd) {
    194 	case SIOCNBTINFO:	/* get next info */
    195 		if (unit)
    196 			unit = SIMPLEQ_NEXT(unit, hci_next);
    197 		else
    198 			unit = SIMPLEQ_FIRST(&hci_unit_list);
    199 
    200 		if (unit == NULL) {
    201 			err = ENXIO;
    202 			break;
    203 		}
    204 
    205 		/* and fall through to */
    206 	case SIOCGBTINFO:	/* get unit info */
    207 	case SIOCGBTINFOA:	/* get info by address */
    208 		memset(btr, 0, sizeof(struct btreq));
    209 		strlcpy(btr->btr_name, device_xname(unit->hci_dev), HCI_DEVNAME_SIZE);
    210 		bdaddr_copy(&btr->btr_bdaddr, &unit->hci_bdaddr);
    211 
    212 		btr->btr_flags = unit->hci_flags;
    213 
    214 		btr->btr_num_cmd = unit->hci_num_cmd_pkts;
    215 		btr->btr_num_acl = unit->hci_num_acl_pkts;
    216 		btr->btr_num_sco = unit->hci_num_sco_pkts;
    217 		btr->btr_acl_mtu = unit->hci_max_acl_size;
    218 		btr->btr_sco_mtu = unit->hci_max_sco_size;
    219 
    220 		btr->btr_packet_type = unit->hci_packet_type;
    221 		btr->btr_link_policy = unit->hci_link_policy;
    222 		break;
    223 
    224 	case SIOCSBTFLAGS:	/* set unit flags (privileged) */
    225 		err = kauth_authorize_device(l->l_cred,
    226 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
    227 		    btr, NULL);
    228 		if (err)
    229 			break;
    230 
    231 		if ((unit->hci_flags & BTF_UP)
    232 		    && (btr->btr_flags & BTF_UP) == 0) {
    233 			hci_disable(unit);
    234 			unit->hci_flags &= ~BTF_UP;
    235 		}
    236 
    237 		unit->hci_flags &= ~BTF_MASTER;
    238 		unit->hci_flags |= (btr->btr_flags & (BTF_INIT | BTF_MASTER));
    239 
    240 		if ((unit->hci_flags & BTF_UP) == 0
    241 		    && (btr->btr_flags & BTF_UP)) {
    242 			err = hci_enable(unit);
    243 			if (err)
    244 				break;
    245 
    246 			unit->hci_flags |= BTF_UP;
    247 		}
    248 
    249 		btr->btr_flags = unit->hci_flags;
    250 		break;
    251 
    252 	case SIOCSBTPOLICY:	/* set unit link policy (privileged) */
    253 		err = kauth_authorize_device(l->l_cred,
    254 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
    255 		    btr, NULL);
    256 		if (err)
    257 			break;
    258 
    259 		unit->hci_link_policy = btr->btr_link_policy;
    260 		unit->hci_link_policy &= unit->hci_lmp_mask;
    261 		btr->btr_link_policy = unit->hci_link_policy;
    262 		break;
    263 
    264 	case SIOCSBTPTYPE:	/* set unit packet types (privileged) */
    265 		err = kauth_authorize_device(l->l_cred,
    266 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
    267 		    btr, NULL);
    268 		if (err)
    269 			break;
    270 
    271 		unit->hci_packet_type = btr->btr_packet_type;
    272 		unit->hci_packet_type &= unit->hci_acl_mask;
    273 		btr->btr_packet_type = unit->hci_packet_type;
    274 		break;
    275 
    276 	case SIOCGBTSTATS:	/* get unit statistics */
    277 		(*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 0);
    278 		break;
    279 
    280 	case SIOCZBTSTATS:	/* get & reset unit statistics */
    281 		err = kauth_authorize_device(l->l_cred,
    282 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
    283 		    btr, NULL);
    284 		if (err)
    285 			break;
    286 
    287 		(*unit->hci_if->get_stats)(unit->hci_dev, &btr->btr_stats, 1);
    288 		break;
    289 
    290 	case SIOCSBTSCOMTU:	/* set sco_mtu value for unit */
    291 		/*
    292 		 * This is a temporary ioctl and may not be supported
    293 		 * in the future. The need is that if SCO packets are
    294 		 * sent to USB bluetooth controllers that are not an
    295 		 * integer number of frame sizes, the USB bus locks up.
    296 		 */
    297 		err = kauth_authorize_device(l->l_cred,
    298 		    KAUTH_DEVICE_BLUETOOTH_SETPRIV, unit, KAUTH_ARG(cmd),
    299 		    btr, NULL);
    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 }
    313