1*162ec756Splunky /* $NetBSD: hci_socket.c,v 1.7 2007/03/05 19:11:54 plunky Exp $ */ 2a5c89047Sgdamore 3a5c89047Sgdamore /*- 4a5c89047Sgdamore * Copyright (c) 2005 Iain Hibbert. 5a5c89047Sgdamore * Copyright (c) 2006 Itronix Inc. 6a5c89047Sgdamore * All rights reserved. 7a5c89047Sgdamore * 8a5c89047Sgdamore * Redistribution and use in source and binary forms, with or without 9a5c89047Sgdamore * modification, are permitted provided that the following conditions 10a5c89047Sgdamore * are met: 11a5c89047Sgdamore * 1. Redistributions of source code must retain the above copyright 12a5c89047Sgdamore * notice, this list of conditions and the following disclaimer. 13a5c89047Sgdamore * 2. Redistributions in binary form must reproduce the above copyright 14a5c89047Sgdamore * notice, this list of conditions and the following disclaimer in the 15a5c89047Sgdamore * documentation and/or other materials provided with the distribution. 16a5c89047Sgdamore * 3. The name of Itronix Inc. may not be used to endorse 17a5c89047Sgdamore * or promote products derived from this software without specific 18a5c89047Sgdamore * prior written permission. 19a5c89047Sgdamore * 20a5c89047Sgdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 21a5c89047Sgdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22a5c89047Sgdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23a5c89047Sgdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 24a5c89047Sgdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25a5c89047Sgdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26a5c89047Sgdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27a5c89047Sgdamore * ON ANY THEORY OF LIABILITY, WHETHER IN 28a5c89047Sgdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29a5c89047Sgdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30a5c89047Sgdamore * POSSIBILITY OF SUCH DAMAGE. 31a5c89047Sgdamore */ 32a5c89047Sgdamore 33a5c89047Sgdamore #include <sys/cdefs.h> 34*162ec756Splunky __KERNEL_RCSID(0, "$NetBSD: hci_socket.c,v 1.7 2007/03/05 19:11:54 plunky Exp $"); 35a5c89047Sgdamore 36a5c89047Sgdamore #include "opt_bluetooth.h" 37a5c89047Sgdamore #ifdef BLUETOOTH_DEBUG 38a5c89047Sgdamore #define PRCOREQUESTS 39a5c89047Sgdamore #endif 40a5c89047Sgdamore 41a5c89047Sgdamore #include <sys/param.h> 42a5c89047Sgdamore #include <sys/domain.h> 43a5c89047Sgdamore #include <sys/kauth.h> 44a5c89047Sgdamore #include <sys/kernel.h> 45a5c89047Sgdamore #include <sys/mbuf.h> 46a5c89047Sgdamore #include <sys/proc.h> 47a5c89047Sgdamore #include <sys/protosw.h> 48a5c89047Sgdamore #include <sys/socket.h> 49a5c89047Sgdamore #include <sys/socketvar.h> 50a5c89047Sgdamore #include <sys/systm.h> 51a5c89047Sgdamore 52a5c89047Sgdamore #include <netbt/bluetooth.h> 53a5c89047Sgdamore #include <netbt/hci.h> 54a5c89047Sgdamore 55a5c89047Sgdamore /******************************************************************************* 56a5c89047Sgdamore * 57a5c89047Sgdamore * HCI SOCK_RAW Sockets - for control of Bluetooth Devices 58a5c89047Sgdamore * 59a5c89047Sgdamore */ 60a5c89047Sgdamore 61a5c89047Sgdamore /* 62a5c89047Sgdamore * the raw HCI protocol control block 63a5c89047Sgdamore */ 64a5c89047Sgdamore struct hci_pcb { 65a5c89047Sgdamore struct socket *hp_socket; /* socket */ 66a5c89047Sgdamore unsigned int hp_flags; /* flags */ 67a5c89047Sgdamore bdaddr_t hp_laddr; /* local address */ 68a5c89047Sgdamore bdaddr_t hp_raddr; /* remote address */ 69a5c89047Sgdamore struct hci_filter hp_efilter; /* user event filter */ 70a5c89047Sgdamore struct hci_filter hp_pfilter; /* user packet filter */ 71a5c89047Sgdamore LIST_ENTRY(hci_pcb) hp_next; /* next HCI pcb */ 72a5c89047Sgdamore }; 73a5c89047Sgdamore 74a5c89047Sgdamore /* hp_flags */ 75a5c89047Sgdamore #define HCI_PRIVILEGED (1<<0) /* no security filter for root */ 76a5c89047Sgdamore #define HCI_DIRECTION (1<<1) /* direction control messages */ 77a5c89047Sgdamore #define HCI_PROMISCUOUS (1<<2) /* listen to all units */ 78a5c89047Sgdamore 79a5c89047Sgdamore LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb); 80a5c89047Sgdamore 81a5c89047Sgdamore /* sysctl defaults */ 82a5c89047Sgdamore int hci_sendspace = HCI_CMD_PKT_SIZE; 83a5c89047Sgdamore int hci_recvspace = 4096; 84a5c89047Sgdamore 85a5c89047Sgdamore /* 86b1b95bf6Splunky * Security filter routines for unprivileged users. 87b1b95bf6Splunky * Allow all but a few critical events, and only permit read commands. 88a5c89047Sgdamore */ 89a5c89047Sgdamore 90b1b95bf6Splunky static int 91a5c89047Sgdamore hci_security_check_opcode(uint16_t opcode) 92a5c89047Sgdamore { 93a5c89047Sgdamore 94b1b95bf6Splunky switch (opcode) { 95b1b95bf6Splunky /* Link control */ 96b1b95bf6Splunky case HCI_CMD_INQUIRY: 97b1b95bf6Splunky case HCI_CMD_REMOTE_NAME_REQ: 98b1b95bf6Splunky case HCI_CMD_READ_REMOTE_FEATURES: 99b1b95bf6Splunky case HCI_CMD_READ_REMOTE_EXTENDED_FEATURES: 100b1b95bf6Splunky case HCI_CMD_READ_REMOTE_VER_INFO: 101b1b95bf6Splunky case HCI_CMD_READ_CLOCK_OFFSET: 102b1b95bf6Splunky case HCI_CMD_READ_LMP_HANDLE: 103b1b95bf6Splunky 104b1b95bf6Splunky /* Link policy */ 105b1b95bf6Splunky case HCI_CMD_ROLE_DISCOVERY: 106b1b95bf6Splunky case HCI_CMD_READ_LINK_POLICY_SETTINGS: 107b1b95bf6Splunky case HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS: 108b1b95bf6Splunky 109b1b95bf6Splunky /* Host controller and baseband */ 110b1b95bf6Splunky case HCI_CMD_READ_PIN_TYPE: 111b1b95bf6Splunky case HCI_CMD_READ_LOCAL_NAME: 112b1b95bf6Splunky case HCI_CMD_READ_CON_ACCEPT_TIMEOUT: 113b1b95bf6Splunky case HCI_CMD_READ_PAGE_TIMEOUT: 114b1b95bf6Splunky case HCI_CMD_READ_SCAN_ENABLE: 115b1b95bf6Splunky case HCI_CMD_READ_PAGE_SCAN_ACTIVITY: 116b1b95bf6Splunky case HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY: 117b1b95bf6Splunky case HCI_CMD_READ_AUTH_ENABLE: 118b1b95bf6Splunky case HCI_CMD_READ_ENCRYPTION_MODE: 119b1b95bf6Splunky case HCI_CMD_READ_UNIT_CLASS: 120b1b95bf6Splunky case HCI_CMD_READ_VOICE_SETTING: 121b1b95bf6Splunky case HCI_CMD_READ_AUTO_FLUSH_TIMEOUT: 122b1b95bf6Splunky case HCI_CMD_READ_NUM_BROADCAST_RETRANS: 123b1b95bf6Splunky case HCI_CMD_READ_HOLD_MODE_ACTIVITY: 124b1b95bf6Splunky case HCI_CMD_READ_XMIT_LEVEL: 125b1b95bf6Splunky case HCI_CMD_READ_SCO_FLOW_CONTROL: 126b1b95bf6Splunky case HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT: 127b1b95bf6Splunky case HCI_CMD_READ_NUM_SUPPORTED_IAC: 128b1b95bf6Splunky case HCI_CMD_READ_IAC_LAP: 129b1b95bf6Splunky case HCI_CMD_READ_PAGE_SCAN_PERIOD: 130b1b95bf6Splunky case HCI_CMD_READ_PAGE_SCAN: 131b1b95bf6Splunky case HCI_CMD_READ_INQUIRY_SCAN_TYPE: 132b1b95bf6Splunky case HCI_CMD_READ_INQUIRY_MODE: 133b1b95bf6Splunky case HCI_CMD_READ_PAGE_SCAN_TYPE: 134b1b95bf6Splunky case HCI_CMD_READ_AFH_ASSESSMENT: 135b1b95bf6Splunky 136b1b95bf6Splunky /* Informational */ 137b1b95bf6Splunky case HCI_CMD_READ_LOCAL_VER: 138b1b95bf6Splunky case HCI_CMD_READ_LOCAL_COMMANDS: 139b1b95bf6Splunky case HCI_CMD_READ_LOCAL_FEATURES: 140b1b95bf6Splunky case HCI_CMD_READ_LOCAL_EXTENDED_FEATURES: 141b1b95bf6Splunky case HCI_CMD_READ_BUFFER_SIZE: 142b1b95bf6Splunky case HCI_CMD_READ_COUNTRY_CODE: 143b1b95bf6Splunky case HCI_CMD_READ_BDADDR: 144b1b95bf6Splunky 145b1b95bf6Splunky /* Status */ 146b1b95bf6Splunky case HCI_CMD_READ_FAILED_CONTACT_CNTR: 147b1b95bf6Splunky case HCI_CMD_READ_LINK_QUALITY: 148b1b95bf6Splunky case HCI_CMD_READ_RSSI: 149b1b95bf6Splunky case HCI_CMD_READ_AFH_CHANNEL_MAP: 150b1b95bf6Splunky case HCI_CMD_READ_CLOCK: 151b1b95bf6Splunky 152b1b95bf6Splunky /* Testing */ 153b1b95bf6Splunky case HCI_CMD_READ_LOOPBACK_MODE: 154b1b95bf6Splunky return 1; 155a5c89047Sgdamore } 156a5c89047Sgdamore 157b1b95bf6Splunky return 0; 158a5c89047Sgdamore } 159a5c89047Sgdamore 160a5c89047Sgdamore static int 161b1b95bf6Splunky hci_security_check_event(uint8_t event) 162a5c89047Sgdamore { 163a5c89047Sgdamore 164b1b95bf6Splunky switch (event) { 165b1b95bf6Splunky case HCI_EVENT_RETURN_LINK_KEYS: 166b1b95bf6Splunky case HCI_EVENT_LINK_KEY_NOTIFICATION: 167b1b95bf6Splunky case HCI_EVENT_VENDOR: 168a5c89047Sgdamore return 0; 169a5c89047Sgdamore } 170a5c89047Sgdamore 171b1b95bf6Splunky return 1; 172a5c89047Sgdamore } 173a5c89047Sgdamore 174a5c89047Sgdamore /* 175a5c89047Sgdamore * When command packet reaches the device, we can drop 176a5c89047Sgdamore * it from the socket buffer (called from hci_output_acl) 177a5c89047Sgdamore */ 178a5c89047Sgdamore void 179a5c89047Sgdamore hci_drop(void *arg) 180a5c89047Sgdamore { 181a5c89047Sgdamore struct socket *so = arg; 182a5c89047Sgdamore 183a5c89047Sgdamore sbdroprecord(&so->so_snd); 184a5c89047Sgdamore sowwakeup(so); 185a5c89047Sgdamore } 186a5c89047Sgdamore 187a5c89047Sgdamore /* 188a5c89047Sgdamore * HCI socket is going away and has some pending packets. We let them 189a5c89047Sgdamore * go by design, but remove the context pointer as it will be invalid 190a5c89047Sgdamore * and we no longer need to be notified. 191a5c89047Sgdamore */ 192a5c89047Sgdamore static void 193a5c89047Sgdamore hci_cmdwait_flush(struct socket *so) 194a5c89047Sgdamore { 195a5c89047Sgdamore struct hci_unit *unit; 196a5c89047Sgdamore struct socket *ctx; 197a5c89047Sgdamore struct mbuf *m; 198a5c89047Sgdamore 199a5c89047Sgdamore DPRINTF("flushing %p\n", so); 200a5c89047Sgdamore 201a5c89047Sgdamore SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) { 202a5c89047Sgdamore m = MBUFQ_FIRST(&unit->hci_cmdwait); 203a5c89047Sgdamore while (m != NULL) { 204a5c89047Sgdamore ctx = M_GETCTX(m, struct socket *); 205a5c89047Sgdamore if (ctx == so) 206a5c89047Sgdamore M_SETCTX(m, NULL); 207a5c89047Sgdamore 208a5c89047Sgdamore m = MBUFQ_NEXT(m); 209a5c89047Sgdamore } 210a5c89047Sgdamore } 211a5c89047Sgdamore } 212a5c89047Sgdamore 213a5c89047Sgdamore /* 214a5c89047Sgdamore * HCI send packet 215a5c89047Sgdamore * This came from userland, so check it out. 216a5c89047Sgdamore */ 217a5c89047Sgdamore static int 218a5c89047Sgdamore hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) 219a5c89047Sgdamore { 220a5c89047Sgdamore struct hci_unit *unit; 221a5c89047Sgdamore struct mbuf *m0; 222a5c89047Sgdamore hci_cmd_hdr_t hdr; 223a5c89047Sgdamore int err; 224a5c89047Sgdamore 225a5c89047Sgdamore KASSERT(m); 226a5c89047Sgdamore KASSERT(addr); 227a5c89047Sgdamore 228a5c89047Sgdamore /* wants at least a header to start with */ 229a5c89047Sgdamore if (m->m_pkthdr.len < sizeof(hdr)) { 230a5c89047Sgdamore err = EMSGSIZE; 231a5c89047Sgdamore goto bad; 232a5c89047Sgdamore } 233a5c89047Sgdamore m_copydata(m, 0, sizeof(hdr), &hdr); 234a5c89047Sgdamore 235a5c89047Sgdamore /* only allows CMD packets to be sent */ 236a5c89047Sgdamore if (hdr.type != HCI_CMD_PKT) { 237a5c89047Sgdamore err = EINVAL; 238a5c89047Sgdamore goto bad; 239a5c89047Sgdamore } 240a5c89047Sgdamore 241a5c89047Sgdamore /* validates packet length */ 242a5c89047Sgdamore if (m->m_pkthdr.len != sizeof(hdr) + hdr.length) { 243a5c89047Sgdamore err = EMSGSIZE; 244a5c89047Sgdamore goto bad; 245a5c89047Sgdamore } 246a5c89047Sgdamore 247a5c89047Sgdamore /* security checks for unprivileged users */ 248a5c89047Sgdamore if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 249a5c89047Sgdamore && (hci_security_check_opcode(le16toh(hdr.opcode)) == 0)) { 250a5c89047Sgdamore err = EPERM; 251a5c89047Sgdamore goto bad; 252a5c89047Sgdamore } 253a5c89047Sgdamore 254a5c89047Sgdamore /* finds destination */ 255a5c89047Sgdamore unit = hci_unit_lookup(addr); 256a5c89047Sgdamore if (unit == NULL) { 257a5c89047Sgdamore err = ENETDOWN; 258a5c89047Sgdamore goto bad; 259a5c89047Sgdamore } 260a5c89047Sgdamore 261a5c89047Sgdamore /* makess a copy for precious to keep */ 262a5c89047Sgdamore m0 = m_copypacket(m, M_DONTWAIT); 263a5c89047Sgdamore if (m0 == NULL) { 264a5c89047Sgdamore err = ENOMEM; 265a5c89047Sgdamore goto bad; 266a5c89047Sgdamore } 267a5c89047Sgdamore sbappendrecord(&pcb->hp_socket->so_snd, m0); 268a5c89047Sgdamore M_SETCTX(m, pcb->hp_socket); /* enable drop callback */ 269a5c89047Sgdamore 270a5c89047Sgdamore DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", unit->hci_devname, 271a5c89047Sgdamore HCI_OGF(le16toh(hdr.opcode)), HCI_OCF(le16toh(hdr.opcode))); 272a5c89047Sgdamore 273a5c89047Sgdamore /* Sendss it */ 274a5c89047Sgdamore if (unit->hci_num_cmd_pkts == 0) 275a5c89047Sgdamore MBUFQ_ENQUEUE(&unit->hci_cmdwait, m); 276a5c89047Sgdamore else 277a5c89047Sgdamore hci_output_cmd(unit, m); 278a5c89047Sgdamore 279a5c89047Sgdamore return 0; 280a5c89047Sgdamore 281a5c89047Sgdamore bad: 282a5c89047Sgdamore DPRINTF("packet (%d bytes) not sent (error %d)\n", 283a5c89047Sgdamore m->m_pkthdr.len, err); 284a5c89047Sgdamore if (m) m_freem(m); 285a5c89047Sgdamore return err; 286a5c89047Sgdamore } 287a5c89047Sgdamore 288a5c89047Sgdamore /* 289a5c89047Sgdamore * User Request. 290a5c89047Sgdamore * up is socket 291a5c89047Sgdamore * m is either 292a5c89047Sgdamore * optional mbuf chain containing message 293a5c89047Sgdamore * ioctl command (PRU_CONTROL) 294a5c89047Sgdamore * nam is either 295a5c89047Sgdamore * optional mbuf chain containing an address 296a5c89047Sgdamore * ioctl data (PRU_CONTROL) 297a5c89047Sgdamore * optionally, protocol number (PRU_ATTACH) 298a5c89047Sgdamore * ctl is optional mbuf chain containing socket options 299a5c89047Sgdamore * l is pointer to process requesting action (if any) 300a5c89047Sgdamore * 301a5c89047Sgdamore * we are responsible for disposing of m and ctl if 302a5c89047Sgdamore * they are mbuf chains 303a5c89047Sgdamore */ 304a5c89047Sgdamore int 305a5c89047Sgdamore hci_usrreq(struct socket *up, int req, struct mbuf *m, 306a5c89047Sgdamore struct mbuf *nam, struct mbuf *ctl, struct lwp *l) 307a5c89047Sgdamore { 308a5c89047Sgdamore struct hci_pcb *pcb = (struct hci_pcb *)up->so_pcb; 309a5c89047Sgdamore struct sockaddr_bt *sa; 310b1b95bf6Splunky int err = 0; 311a5c89047Sgdamore 312a5c89047Sgdamore DPRINTFN(2, "%s\n", prurequests[req]); 313a5c89047Sgdamore 314a5c89047Sgdamore switch(req) { 315a5c89047Sgdamore case PRU_CONTROL: 316f474dcebSad return hci_ioctl((unsigned long)m, (void *)nam, l); 317a5c89047Sgdamore 318a5c89047Sgdamore case PRU_PURGEIF: 319a5c89047Sgdamore return EOPNOTSUPP; 320a5c89047Sgdamore 321a5c89047Sgdamore case PRU_ATTACH: 322a5c89047Sgdamore if (pcb) 323a5c89047Sgdamore return EINVAL; 324a5c89047Sgdamore 325a5c89047Sgdamore err = soreserve(up, hci_sendspace, hci_recvspace); 326a5c89047Sgdamore if (err) 327a5c89047Sgdamore return err; 328a5c89047Sgdamore 329a5c89047Sgdamore pcb = malloc(sizeof(struct hci_pcb), M_PCB, M_NOWAIT | M_ZERO); 330a5c89047Sgdamore if (pcb == NULL) 331a5c89047Sgdamore return ENOMEM; 332a5c89047Sgdamore 333a5c89047Sgdamore up->so_pcb = pcb; 334a5c89047Sgdamore pcb->hp_socket = up; 335b1b95bf6Splunky 336b2eb9a53Selad if (l == NULL || kauth_authorize_generic(l->l_cred, 337b2eb9a53Selad KAUTH_GENERIC_ISSUSER, NULL) == 0) 338b1b95bf6Splunky pcb->hp_flags |= HCI_PRIVILEGED; 339a5c89047Sgdamore 340a5c89047Sgdamore /* 341a5c89047Sgdamore * Set default user filter. By default, socket only passes 342a5c89047Sgdamore * Command_Complete and Command_Status Events. 343a5c89047Sgdamore */ 344a5c89047Sgdamore hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter); 345a5c89047Sgdamore hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter); 346a5c89047Sgdamore hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter); 347a5c89047Sgdamore 348a5c89047Sgdamore LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next); 349a5c89047Sgdamore 350a5c89047Sgdamore return 0; 351a5c89047Sgdamore } 352a5c89047Sgdamore 353a5c89047Sgdamore /* anything after here *requires* a pcb */ 354a5c89047Sgdamore if (pcb == NULL) { 355a5c89047Sgdamore err = EINVAL; 356a5c89047Sgdamore goto release; 357a5c89047Sgdamore } 358a5c89047Sgdamore 359a5c89047Sgdamore switch(req) { 360a5c89047Sgdamore case PRU_DISCONNECT: 361a5c89047Sgdamore bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY); 362a5c89047Sgdamore 363a5c89047Sgdamore /* XXX we cannot call soisdisconnected() here, as it sets 364a5c89047Sgdamore * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being, 365a5c89047Sgdamore * that soisconnected() does not clear these and if you 366a5c89047Sgdamore * try to reconnect this socket (which is permitted) you 367a5c89047Sgdamore * get a broken pipe when you try to write any data. 368a5c89047Sgdamore */ 369a5c89047Sgdamore up->so_state &= ~SS_ISCONNECTED; 370a5c89047Sgdamore break; 371a5c89047Sgdamore 372a5c89047Sgdamore case PRU_ABORT: 373a5c89047Sgdamore soisdisconnected(up); 374a5c89047Sgdamore /* fall through to */ 375a5c89047Sgdamore case PRU_DETACH: 376a5c89047Sgdamore if (up->so_snd.sb_mb != NULL) 377a5c89047Sgdamore hci_cmdwait_flush(up); 378a5c89047Sgdamore 379a5c89047Sgdamore up->so_pcb = NULL; 380a5c89047Sgdamore LIST_REMOVE(pcb, hp_next); 381a5c89047Sgdamore free(pcb, M_PCB); 382a5c89047Sgdamore return 0; 383a5c89047Sgdamore 384a5c89047Sgdamore case PRU_BIND: 385a5c89047Sgdamore KASSERT(nam); 386a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 387a5c89047Sgdamore 388a5c89047Sgdamore if (sa->bt_len != sizeof(struct sockaddr_bt)) 389a5c89047Sgdamore return EINVAL; 390a5c89047Sgdamore 391a5c89047Sgdamore if (sa->bt_family != AF_BLUETOOTH) 392a5c89047Sgdamore return EAFNOSUPPORT; 393a5c89047Sgdamore 394a5c89047Sgdamore bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr); 395a5c89047Sgdamore 396a5c89047Sgdamore if (bdaddr_any(&sa->bt_bdaddr)) 397a5c89047Sgdamore pcb->hp_flags |= HCI_PROMISCUOUS; 398a5c89047Sgdamore else 399a5c89047Sgdamore pcb->hp_flags &= ~HCI_PROMISCUOUS; 400a5c89047Sgdamore 401a5c89047Sgdamore return 0; 402a5c89047Sgdamore 403a5c89047Sgdamore case PRU_CONNECT: 404a5c89047Sgdamore KASSERT(nam); 405a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 406a5c89047Sgdamore 407a5c89047Sgdamore if (sa->bt_len != sizeof(struct sockaddr_bt)) 408a5c89047Sgdamore return EINVAL; 409a5c89047Sgdamore 410a5c89047Sgdamore if (sa->bt_family != AF_BLUETOOTH) 411a5c89047Sgdamore return EAFNOSUPPORT; 412a5c89047Sgdamore 413a5c89047Sgdamore if (hci_unit_lookup(&sa->bt_bdaddr) == NULL) 414a5c89047Sgdamore return EADDRNOTAVAIL; 415a5c89047Sgdamore 416a5c89047Sgdamore bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr); 417a5c89047Sgdamore soisconnected(up); 418a5c89047Sgdamore return 0; 419a5c89047Sgdamore 420a5c89047Sgdamore case PRU_PEERADDR: 421a5c89047Sgdamore KASSERT(nam); 422a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 423a5c89047Sgdamore 424a5c89047Sgdamore memset(sa, 0, sizeof(struct sockaddr_bt)); 425a5c89047Sgdamore nam->m_len = 426a5c89047Sgdamore sa->bt_len = sizeof(struct sockaddr_bt); 427a5c89047Sgdamore sa->bt_family = AF_BLUETOOTH; 428a5c89047Sgdamore bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr); 429a5c89047Sgdamore return 0; 430a5c89047Sgdamore 431a5c89047Sgdamore case PRU_SOCKADDR: 432a5c89047Sgdamore KASSERT(nam); 433a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 434a5c89047Sgdamore 435a5c89047Sgdamore memset(sa, 0, sizeof(struct sockaddr_bt)); 436a5c89047Sgdamore nam->m_len = 437a5c89047Sgdamore sa->bt_len = sizeof(struct sockaddr_bt); 438a5c89047Sgdamore sa->bt_family = AF_BLUETOOTH; 439a5c89047Sgdamore bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr); 440a5c89047Sgdamore return 0; 441a5c89047Sgdamore 442a5c89047Sgdamore case PRU_SHUTDOWN: 443a5c89047Sgdamore socantsendmore(up); 444a5c89047Sgdamore break; 445a5c89047Sgdamore 446a5c89047Sgdamore case PRU_SEND: 447a5c89047Sgdamore sa = NULL; 448a5c89047Sgdamore if (nam) { 449a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 450a5c89047Sgdamore 451a5c89047Sgdamore if (sa->bt_len != sizeof(struct sockaddr_bt)) { 452a5c89047Sgdamore err = EINVAL; 453a5c89047Sgdamore goto release; 454a5c89047Sgdamore } 455a5c89047Sgdamore 456a5c89047Sgdamore if (sa->bt_family != AF_BLUETOOTH) { 457a5c89047Sgdamore err = EAFNOSUPPORT; 458a5c89047Sgdamore goto release; 459a5c89047Sgdamore } 460a5c89047Sgdamore } 461a5c89047Sgdamore 462a5c89047Sgdamore if (ctl) /* have no use for this */ 463a5c89047Sgdamore m_freem(ctl); 464a5c89047Sgdamore 465a5c89047Sgdamore return hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr)); 466a5c89047Sgdamore 467a5c89047Sgdamore case PRU_SENSE: 468a5c89047Sgdamore return 0; /* (no sense - Doh!) */ 469a5c89047Sgdamore 470a5c89047Sgdamore case PRU_RCVD: 471a5c89047Sgdamore case PRU_RCVOOB: 472a5c89047Sgdamore return EOPNOTSUPP; /* (no release) */ 473a5c89047Sgdamore 474a5c89047Sgdamore case PRU_ACCEPT: 475a5c89047Sgdamore case PRU_CONNECT2: 476a5c89047Sgdamore case PRU_LISTEN: 477a5c89047Sgdamore case PRU_SENDOOB: 478a5c89047Sgdamore case PRU_FASTTIMO: 479a5c89047Sgdamore case PRU_SLOWTIMO: 480a5c89047Sgdamore case PRU_PROTORCV: 481a5c89047Sgdamore case PRU_PROTOSEND: 482a5c89047Sgdamore err = EOPNOTSUPP; 483a5c89047Sgdamore break; 484a5c89047Sgdamore 485a5c89047Sgdamore default: 486a5c89047Sgdamore UNKNOWN(req); 487a5c89047Sgdamore err = EOPNOTSUPP; 488a5c89047Sgdamore break; 489a5c89047Sgdamore } 490a5c89047Sgdamore 491a5c89047Sgdamore release: 492f474dcebSad if (m) 493f474dcebSad m_freem(m); 494f474dcebSad if (ctl) 495f474dcebSad m_freem(ctl); 496a5c89047Sgdamore return err; 497a5c89047Sgdamore } 498a5c89047Sgdamore 499a5c89047Sgdamore /* 500a5c89047Sgdamore * get/set socket options 501a5c89047Sgdamore */ 502a5c89047Sgdamore int 503a5c89047Sgdamore hci_ctloutput(int req, struct socket *so, int level, 504a5c89047Sgdamore int optname, struct mbuf **opt) 505a5c89047Sgdamore { 506a5c89047Sgdamore struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb; 507a5c89047Sgdamore struct mbuf *m; 508a5c89047Sgdamore int err = 0; 509a5c89047Sgdamore 510a5c89047Sgdamore DPRINTFN(2, "req %s\n", prcorequests[req]); 511a5c89047Sgdamore 512a5c89047Sgdamore if (pcb == NULL) 513a5c89047Sgdamore return EINVAL; 514a5c89047Sgdamore 515a5c89047Sgdamore if (level != BTPROTO_HCI) 516*162ec756Splunky return ENOPROTOOPT; 517a5c89047Sgdamore 518a5c89047Sgdamore switch(req) { 519a5c89047Sgdamore case PRCO_GETOPT: 520a5c89047Sgdamore m = m_get(M_WAIT, MT_SOOPTS); 521a5c89047Sgdamore switch (optname) { 522a5c89047Sgdamore case SO_HCI_EVT_FILTER: 523a5c89047Sgdamore m->m_len = sizeof(struct hci_filter); 524a5c89047Sgdamore memcpy(mtod(m, void *), &pcb->hp_efilter, m->m_len); 525a5c89047Sgdamore break; 526a5c89047Sgdamore 527a5c89047Sgdamore case SO_HCI_PKT_FILTER: 528a5c89047Sgdamore m->m_len = sizeof(struct hci_filter); 529a5c89047Sgdamore memcpy(mtod(m, void *), &pcb->hp_pfilter, m->m_len); 530a5c89047Sgdamore break; 531a5c89047Sgdamore 532a5c89047Sgdamore case SO_HCI_DIRECTION: 533a5c89047Sgdamore m->m_len = sizeof(int); 534a5c89047Sgdamore if (pcb->hp_flags & HCI_DIRECTION) 535a5c89047Sgdamore *mtod(m, int *) = 1; 536a5c89047Sgdamore else 537a5c89047Sgdamore *mtod(m, int *) = 0; 538a5c89047Sgdamore break; 539a5c89047Sgdamore 540a5c89047Sgdamore default: 541*162ec756Splunky err = ENOPROTOOPT; 542a5c89047Sgdamore m_freem(m); 543a5c89047Sgdamore m = NULL; 544a5c89047Sgdamore break; 545a5c89047Sgdamore } 546a5c89047Sgdamore *opt = m; 547a5c89047Sgdamore break; 548a5c89047Sgdamore 549a5c89047Sgdamore case PRCO_SETOPT: 550a5c89047Sgdamore m = *opt; 551a5c89047Sgdamore if (m) switch (optname) { 552a5c89047Sgdamore case SO_HCI_EVT_FILTER: /* set event filter */ 553a5c89047Sgdamore m->m_len = min(m->m_len, sizeof(struct hci_filter)); 554a5c89047Sgdamore memcpy(&pcb->hp_efilter, mtod(m, void *), m->m_len); 555a5c89047Sgdamore break; 556a5c89047Sgdamore 557a5c89047Sgdamore case SO_HCI_PKT_FILTER: /* set packet filter */ 558a5c89047Sgdamore m->m_len = min(m->m_len, sizeof(struct hci_filter)); 559a5c89047Sgdamore memcpy(&pcb->hp_pfilter, mtod(m, void *), m->m_len); 560a5c89047Sgdamore break; 561a5c89047Sgdamore 562a5c89047Sgdamore case SO_HCI_DIRECTION: /* request direction ctl messages */ 563a5c89047Sgdamore if (*mtod(m, int *)) 564a5c89047Sgdamore pcb->hp_flags |= HCI_DIRECTION; 565a5c89047Sgdamore else 566a5c89047Sgdamore pcb->hp_flags &= ~HCI_DIRECTION; 567a5c89047Sgdamore break; 568a5c89047Sgdamore 569a5c89047Sgdamore default: 570*162ec756Splunky err = ENOPROTOOPT; 571a5c89047Sgdamore break; 572a5c89047Sgdamore } 573a5c89047Sgdamore m_freem(m); 574a5c89047Sgdamore break; 575a5c89047Sgdamore 576a5c89047Sgdamore default: 577*162ec756Splunky err = ENOPROTOOPT; 578a5c89047Sgdamore break; 579a5c89047Sgdamore } 580a5c89047Sgdamore 581a5c89047Sgdamore return err; 582a5c89047Sgdamore } 583a5c89047Sgdamore 584a5c89047Sgdamore /* 585a5c89047Sgdamore * HCI mbuf tap routine 586a5c89047Sgdamore * 587a5c89047Sgdamore * copy packets to any raw HCI sockets that wish (and are 588a5c89047Sgdamore * permitted) to see them 589a5c89047Sgdamore */ 590a5c89047Sgdamore void 591a5c89047Sgdamore hci_mtap(struct mbuf *m, struct hci_unit *unit) 592a5c89047Sgdamore { 593a5c89047Sgdamore struct hci_pcb *pcb; 594a5c89047Sgdamore struct mbuf *m0, *ctlmsg, **ctl; 595a5c89047Sgdamore struct sockaddr_bt sa; 596a5c89047Sgdamore uint8_t type; 597a5c89047Sgdamore uint8_t event; 598a5c89047Sgdamore uint16_t opcode; 599a5c89047Sgdamore 600a5c89047Sgdamore KASSERT(m->m_len >= sizeof(type)); 601a5c89047Sgdamore 602a5c89047Sgdamore type = *mtod(m, uint8_t *); 603a5c89047Sgdamore 604a5c89047Sgdamore memset(&sa, 0, sizeof(sa)); 605a5c89047Sgdamore sa.bt_len = sizeof(struct sockaddr_bt); 606a5c89047Sgdamore sa.bt_family = AF_BLUETOOTH; 607a5c89047Sgdamore bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr); 608a5c89047Sgdamore 609a5c89047Sgdamore LIST_FOREACH(pcb, &hci_pcb, hp_next) { 610a5c89047Sgdamore /* 611a5c89047Sgdamore * filter according to source address 612a5c89047Sgdamore */ 613a5c89047Sgdamore if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0 614a5c89047Sgdamore && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0) 615a5c89047Sgdamore continue; 616a5c89047Sgdamore 617a5c89047Sgdamore /* 618a5c89047Sgdamore * filter according to packet type filter 619a5c89047Sgdamore */ 620a5c89047Sgdamore if (hci_filter_test(type, &pcb->hp_pfilter) == 0) 621a5c89047Sgdamore continue; 622a5c89047Sgdamore 623a5c89047Sgdamore /* 624a5c89047Sgdamore * filter according to event/security filters 625a5c89047Sgdamore */ 626a5c89047Sgdamore switch(type) { 627a5c89047Sgdamore case HCI_EVENT_PKT: 628a5c89047Sgdamore KASSERT(m->m_len >= sizeof(hci_event_hdr_t)); 629a5c89047Sgdamore 630a5c89047Sgdamore event = mtod(m, hci_event_hdr_t *)->event; 631a5c89047Sgdamore 632a5c89047Sgdamore if (hci_filter_test(event, &pcb->hp_efilter) == 0) 633a5c89047Sgdamore continue; 634a5c89047Sgdamore 635a5c89047Sgdamore if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 636a5c89047Sgdamore && hci_security_check_event(event) == 0) 637a5c89047Sgdamore continue; 638a5c89047Sgdamore break; 639a5c89047Sgdamore 640a5c89047Sgdamore case HCI_CMD_PKT: 641a5c89047Sgdamore KASSERT(m->m_len >= sizeof(hci_cmd_hdr_t)); 642a5c89047Sgdamore 643a5c89047Sgdamore opcode = le16toh(mtod(m, hci_cmd_hdr_t *)->opcode); 644a5c89047Sgdamore 645a5c89047Sgdamore if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 646a5c89047Sgdamore && hci_security_check_opcode(opcode) == 0) 647a5c89047Sgdamore continue; 648a5c89047Sgdamore break; 649a5c89047Sgdamore 650a5c89047Sgdamore case HCI_ACL_DATA_PKT: 651a5c89047Sgdamore case HCI_SCO_DATA_PKT: 652a5c89047Sgdamore default: 653a5c89047Sgdamore if ((pcb->hp_flags & HCI_PRIVILEGED) == 0) 654a5c89047Sgdamore continue; 655a5c89047Sgdamore 656a5c89047Sgdamore break; 657a5c89047Sgdamore } 658a5c89047Sgdamore 659a5c89047Sgdamore /* 660a5c89047Sgdamore * create control messages 661a5c89047Sgdamore */ 662a5c89047Sgdamore ctlmsg = NULL; 663a5c89047Sgdamore ctl = &ctlmsg; 664a5c89047Sgdamore if (pcb->hp_flags & HCI_DIRECTION) { 665a5c89047Sgdamore int dir = m->m_flags & M_LINK0 ? 1 : 0; 666a5c89047Sgdamore 66753524e44Schristos *ctl = sbcreatecontrol((void *)&dir, sizeof(dir), 668a5c89047Sgdamore SCM_HCI_DIRECTION, BTPROTO_HCI); 669a5c89047Sgdamore 670a5c89047Sgdamore if (*ctl != NULL) 671a5c89047Sgdamore ctl = &((*ctl)->m_next); 672a5c89047Sgdamore } 673a5c89047Sgdamore 674a5c89047Sgdamore /* 675a5c89047Sgdamore * copy to socket 676a5c89047Sgdamore */ 677a5c89047Sgdamore m0 = m_copypacket(m, M_DONTWAIT); 678a5c89047Sgdamore if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv, 679a5c89047Sgdamore (struct sockaddr *)&sa, m0, ctlmsg)) { 680a5c89047Sgdamore sorwakeup(pcb->hp_socket); 681a5c89047Sgdamore } else { 682a5c89047Sgdamore m_freem(ctlmsg); 683a5c89047Sgdamore m_freem(m0); 684a5c89047Sgdamore } 685a5c89047Sgdamore } 686a5c89047Sgdamore } 687