1*b1b95bf6Splunky /* $NetBSD: hci_socket.c,v 1.4 2006/10/01 10:13: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*b1b95bf6Splunky __KERNEL_RCSID(0, "$NetBSD: hci_socket.c,v 1.4 2006/10/01 10:13: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 /* 86*b1b95bf6Splunky * Security filter routines for unprivileged users. 87*b1b95bf6Splunky * Allow all but a few critical events, and only permit read commands. 88a5c89047Sgdamore */ 89a5c89047Sgdamore 90*b1b95bf6Splunky static int 91a5c89047Sgdamore hci_security_check_opcode(uint16_t opcode) 92a5c89047Sgdamore { 93a5c89047Sgdamore 94*b1b95bf6Splunky switch (opcode) { 95*b1b95bf6Splunky /* Link control */ 96*b1b95bf6Splunky case HCI_CMD_INQUIRY: 97*b1b95bf6Splunky case HCI_CMD_REMOTE_NAME_REQ: 98*b1b95bf6Splunky case HCI_CMD_READ_REMOTE_FEATURES: 99*b1b95bf6Splunky case HCI_CMD_READ_REMOTE_EXTENDED_FEATURES: 100*b1b95bf6Splunky case HCI_CMD_READ_REMOTE_VER_INFO: 101*b1b95bf6Splunky case HCI_CMD_READ_CLOCK_OFFSET: 102*b1b95bf6Splunky case HCI_CMD_READ_LMP_HANDLE: 103*b1b95bf6Splunky 104*b1b95bf6Splunky /* Link policy */ 105*b1b95bf6Splunky case HCI_CMD_ROLE_DISCOVERY: 106*b1b95bf6Splunky case HCI_CMD_READ_LINK_POLICY_SETTINGS: 107*b1b95bf6Splunky case HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS: 108*b1b95bf6Splunky 109*b1b95bf6Splunky /* Host controller and baseband */ 110*b1b95bf6Splunky case HCI_CMD_READ_PIN_TYPE: 111*b1b95bf6Splunky case HCI_CMD_READ_LOCAL_NAME: 112*b1b95bf6Splunky case HCI_CMD_READ_CON_ACCEPT_TIMEOUT: 113*b1b95bf6Splunky case HCI_CMD_READ_PAGE_TIMEOUT: 114*b1b95bf6Splunky case HCI_CMD_READ_SCAN_ENABLE: 115*b1b95bf6Splunky case HCI_CMD_READ_PAGE_SCAN_ACTIVITY: 116*b1b95bf6Splunky case HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY: 117*b1b95bf6Splunky case HCI_CMD_READ_AUTH_ENABLE: 118*b1b95bf6Splunky case HCI_CMD_READ_ENCRYPTION_MODE: 119*b1b95bf6Splunky case HCI_CMD_READ_UNIT_CLASS: 120*b1b95bf6Splunky case HCI_CMD_READ_VOICE_SETTING: 121*b1b95bf6Splunky case HCI_CMD_READ_AUTO_FLUSH_TIMEOUT: 122*b1b95bf6Splunky case HCI_CMD_READ_NUM_BROADCAST_RETRANS: 123*b1b95bf6Splunky case HCI_CMD_READ_HOLD_MODE_ACTIVITY: 124*b1b95bf6Splunky case HCI_CMD_READ_XMIT_LEVEL: 125*b1b95bf6Splunky case HCI_CMD_READ_SCO_FLOW_CONTROL: 126*b1b95bf6Splunky case HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT: 127*b1b95bf6Splunky case HCI_CMD_READ_NUM_SUPPORTED_IAC: 128*b1b95bf6Splunky case HCI_CMD_READ_IAC_LAP: 129*b1b95bf6Splunky case HCI_CMD_READ_PAGE_SCAN_PERIOD: 130*b1b95bf6Splunky case HCI_CMD_READ_PAGE_SCAN: 131*b1b95bf6Splunky case HCI_CMD_READ_INQUIRY_SCAN_TYPE: 132*b1b95bf6Splunky case HCI_CMD_READ_INQUIRY_MODE: 133*b1b95bf6Splunky case HCI_CMD_READ_PAGE_SCAN_TYPE: 134*b1b95bf6Splunky case HCI_CMD_READ_AFH_ASSESSMENT: 135*b1b95bf6Splunky 136*b1b95bf6Splunky /* Informational */ 137*b1b95bf6Splunky case HCI_CMD_READ_LOCAL_VER: 138*b1b95bf6Splunky case HCI_CMD_READ_LOCAL_COMMANDS: 139*b1b95bf6Splunky case HCI_CMD_READ_LOCAL_FEATURES: 140*b1b95bf6Splunky case HCI_CMD_READ_LOCAL_EXTENDED_FEATURES: 141*b1b95bf6Splunky case HCI_CMD_READ_BUFFER_SIZE: 142*b1b95bf6Splunky case HCI_CMD_READ_COUNTRY_CODE: 143*b1b95bf6Splunky case HCI_CMD_READ_BDADDR: 144*b1b95bf6Splunky 145*b1b95bf6Splunky /* Status */ 146*b1b95bf6Splunky case HCI_CMD_READ_FAILED_CONTACT_CNTR: 147*b1b95bf6Splunky case HCI_CMD_READ_LINK_QUALITY: 148*b1b95bf6Splunky case HCI_CMD_READ_RSSI: 149*b1b95bf6Splunky case HCI_CMD_READ_AFH_CHANNEL_MAP: 150*b1b95bf6Splunky case HCI_CMD_READ_CLOCK: 151*b1b95bf6Splunky 152*b1b95bf6Splunky /* Testing */ 153*b1b95bf6Splunky case HCI_CMD_READ_LOOPBACK_MODE: 154*b1b95bf6Splunky return 1; 155a5c89047Sgdamore } 156a5c89047Sgdamore 157*b1b95bf6Splunky return 0; 158a5c89047Sgdamore } 159a5c89047Sgdamore 160a5c89047Sgdamore static int 161*b1b95bf6Splunky hci_security_check_event(uint8_t event) 162a5c89047Sgdamore { 163a5c89047Sgdamore 164*b1b95bf6Splunky switch (event) { 165*b1b95bf6Splunky case HCI_EVENT_RETURN_LINK_KEYS: 166*b1b95bf6Splunky case HCI_EVENT_LINK_KEY_NOTIFICATION: 167*b1b95bf6Splunky case HCI_EVENT_VENDOR: 168a5c89047Sgdamore return 0; 169a5c89047Sgdamore } 170a5c89047Sgdamore 171*b1b95bf6Splunky 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; 310*b1b95bf6Splunky 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; 335*b1b95bf6Splunky 336*b1b95bf6Splunky if (l == NULL 337*b1b95bf6Splunky || kauth_authorize_generic(l->l_cred, 338*b1b95bf6Splunky KAUTH_GENERIC_ISSUSER, 339*b1b95bf6Splunky &l->l_acflag) == 0) 340*b1b95bf6Splunky pcb->hp_flags |= HCI_PRIVILEGED; 341a5c89047Sgdamore 342a5c89047Sgdamore /* 343a5c89047Sgdamore * Set default user filter. By default, socket only passes 344a5c89047Sgdamore * Command_Complete and Command_Status Events. 345a5c89047Sgdamore */ 346a5c89047Sgdamore hci_filter_set(HCI_EVENT_COMMAND_COMPL, &pcb->hp_efilter); 347a5c89047Sgdamore hci_filter_set(HCI_EVENT_COMMAND_STATUS, &pcb->hp_efilter); 348a5c89047Sgdamore hci_filter_set(HCI_EVENT_PKT, &pcb->hp_pfilter); 349a5c89047Sgdamore 350a5c89047Sgdamore LIST_INSERT_HEAD(&hci_pcb, pcb, hp_next); 351a5c89047Sgdamore 352a5c89047Sgdamore return 0; 353a5c89047Sgdamore } 354a5c89047Sgdamore 355a5c89047Sgdamore /* anything after here *requires* a pcb */ 356a5c89047Sgdamore if (pcb == NULL) { 357a5c89047Sgdamore err = EINVAL; 358a5c89047Sgdamore goto release; 359a5c89047Sgdamore } 360a5c89047Sgdamore 361a5c89047Sgdamore switch(req) { 362a5c89047Sgdamore case PRU_DISCONNECT: 363a5c89047Sgdamore bdaddr_copy(&pcb->hp_raddr, BDADDR_ANY); 364a5c89047Sgdamore 365a5c89047Sgdamore /* XXX we cannot call soisdisconnected() here, as it sets 366a5c89047Sgdamore * SS_CANTRCVMORE and SS_CANTSENDMORE. The problem being, 367a5c89047Sgdamore * that soisconnected() does not clear these and if you 368a5c89047Sgdamore * try to reconnect this socket (which is permitted) you 369a5c89047Sgdamore * get a broken pipe when you try to write any data. 370a5c89047Sgdamore */ 371a5c89047Sgdamore up->so_state &= ~SS_ISCONNECTED; 372a5c89047Sgdamore break; 373a5c89047Sgdamore 374a5c89047Sgdamore case PRU_ABORT: 375a5c89047Sgdamore soisdisconnected(up); 376a5c89047Sgdamore /* fall through to */ 377a5c89047Sgdamore case PRU_DETACH: 378a5c89047Sgdamore if (up->so_snd.sb_mb != NULL) 379a5c89047Sgdamore hci_cmdwait_flush(up); 380a5c89047Sgdamore 381a5c89047Sgdamore up->so_pcb = NULL; 382a5c89047Sgdamore LIST_REMOVE(pcb, hp_next); 383a5c89047Sgdamore free(pcb, M_PCB); 384a5c89047Sgdamore return 0; 385a5c89047Sgdamore 386a5c89047Sgdamore case PRU_BIND: 387a5c89047Sgdamore KASSERT(nam); 388a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 389a5c89047Sgdamore 390a5c89047Sgdamore if (sa->bt_len != sizeof(struct sockaddr_bt)) 391a5c89047Sgdamore return EINVAL; 392a5c89047Sgdamore 393a5c89047Sgdamore if (sa->bt_family != AF_BLUETOOTH) 394a5c89047Sgdamore return EAFNOSUPPORT; 395a5c89047Sgdamore 396a5c89047Sgdamore bdaddr_copy(&pcb->hp_laddr, &sa->bt_bdaddr); 397a5c89047Sgdamore 398a5c89047Sgdamore if (bdaddr_any(&sa->bt_bdaddr)) 399a5c89047Sgdamore pcb->hp_flags |= HCI_PROMISCUOUS; 400a5c89047Sgdamore else 401a5c89047Sgdamore pcb->hp_flags &= ~HCI_PROMISCUOUS; 402a5c89047Sgdamore 403a5c89047Sgdamore return 0; 404a5c89047Sgdamore 405a5c89047Sgdamore case PRU_CONNECT: 406a5c89047Sgdamore KASSERT(nam); 407a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 408a5c89047Sgdamore 409a5c89047Sgdamore if (sa->bt_len != sizeof(struct sockaddr_bt)) 410a5c89047Sgdamore return EINVAL; 411a5c89047Sgdamore 412a5c89047Sgdamore if (sa->bt_family != AF_BLUETOOTH) 413a5c89047Sgdamore return EAFNOSUPPORT; 414a5c89047Sgdamore 415a5c89047Sgdamore if (hci_unit_lookup(&sa->bt_bdaddr) == NULL) 416a5c89047Sgdamore return EADDRNOTAVAIL; 417a5c89047Sgdamore 418a5c89047Sgdamore bdaddr_copy(&pcb->hp_raddr, &sa->bt_bdaddr); 419a5c89047Sgdamore soisconnected(up); 420a5c89047Sgdamore return 0; 421a5c89047Sgdamore 422a5c89047Sgdamore case PRU_PEERADDR: 423a5c89047Sgdamore KASSERT(nam); 424a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 425a5c89047Sgdamore 426a5c89047Sgdamore memset(sa, 0, sizeof(struct sockaddr_bt)); 427a5c89047Sgdamore nam->m_len = 428a5c89047Sgdamore sa->bt_len = sizeof(struct sockaddr_bt); 429a5c89047Sgdamore sa->bt_family = AF_BLUETOOTH; 430a5c89047Sgdamore bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_raddr); 431a5c89047Sgdamore return 0; 432a5c89047Sgdamore 433a5c89047Sgdamore case PRU_SOCKADDR: 434a5c89047Sgdamore KASSERT(nam); 435a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 436a5c89047Sgdamore 437a5c89047Sgdamore memset(sa, 0, sizeof(struct sockaddr_bt)); 438a5c89047Sgdamore nam->m_len = 439a5c89047Sgdamore sa->bt_len = sizeof(struct sockaddr_bt); 440a5c89047Sgdamore sa->bt_family = AF_BLUETOOTH; 441a5c89047Sgdamore bdaddr_copy(&sa->bt_bdaddr, &pcb->hp_laddr); 442a5c89047Sgdamore return 0; 443a5c89047Sgdamore 444a5c89047Sgdamore case PRU_SHUTDOWN: 445a5c89047Sgdamore socantsendmore(up); 446a5c89047Sgdamore break; 447a5c89047Sgdamore 448a5c89047Sgdamore case PRU_SEND: 449a5c89047Sgdamore sa = NULL; 450a5c89047Sgdamore if (nam) { 451a5c89047Sgdamore sa = mtod(nam, struct sockaddr_bt *); 452a5c89047Sgdamore 453a5c89047Sgdamore if (sa->bt_len != sizeof(struct sockaddr_bt)) { 454a5c89047Sgdamore err = EINVAL; 455a5c89047Sgdamore goto release; 456a5c89047Sgdamore } 457a5c89047Sgdamore 458a5c89047Sgdamore if (sa->bt_family != AF_BLUETOOTH) { 459a5c89047Sgdamore err = EAFNOSUPPORT; 460a5c89047Sgdamore goto release; 461a5c89047Sgdamore } 462a5c89047Sgdamore } 463a5c89047Sgdamore 464a5c89047Sgdamore if (ctl) /* have no use for this */ 465a5c89047Sgdamore m_freem(ctl); 466a5c89047Sgdamore 467a5c89047Sgdamore return hci_send(pcb, m, (sa ? &sa->bt_bdaddr : &pcb->hp_raddr)); 468a5c89047Sgdamore 469a5c89047Sgdamore case PRU_SENSE: 470a5c89047Sgdamore return 0; /* (no sense - Doh!) */ 471a5c89047Sgdamore 472a5c89047Sgdamore case PRU_RCVD: 473a5c89047Sgdamore case PRU_RCVOOB: 474a5c89047Sgdamore return EOPNOTSUPP; /* (no release) */ 475a5c89047Sgdamore 476a5c89047Sgdamore case PRU_ACCEPT: 477a5c89047Sgdamore case PRU_CONNECT2: 478a5c89047Sgdamore case PRU_LISTEN: 479a5c89047Sgdamore case PRU_SENDOOB: 480a5c89047Sgdamore case PRU_FASTTIMO: 481a5c89047Sgdamore case PRU_SLOWTIMO: 482a5c89047Sgdamore case PRU_PROTORCV: 483a5c89047Sgdamore case PRU_PROTOSEND: 484a5c89047Sgdamore err = EOPNOTSUPP; 485a5c89047Sgdamore break; 486a5c89047Sgdamore 487a5c89047Sgdamore default: 488a5c89047Sgdamore UNKNOWN(req); 489a5c89047Sgdamore err = EOPNOTSUPP; 490a5c89047Sgdamore break; 491a5c89047Sgdamore } 492a5c89047Sgdamore 493a5c89047Sgdamore release: 494f474dcebSad if (m) 495f474dcebSad m_freem(m); 496f474dcebSad if (ctl) 497f474dcebSad m_freem(ctl); 498a5c89047Sgdamore return err; 499a5c89047Sgdamore } 500a5c89047Sgdamore 501a5c89047Sgdamore /* 502a5c89047Sgdamore * get/set socket options 503a5c89047Sgdamore */ 504a5c89047Sgdamore int 505a5c89047Sgdamore hci_ctloutput(int req, struct socket *so, int level, 506a5c89047Sgdamore int optname, struct mbuf **opt) 507a5c89047Sgdamore { 508a5c89047Sgdamore struct hci_pcb *pcb = (struct hci_pcb *)so->so_pcb; 509a5c89047Sgdamore struct mbuf *m; 510a5c89047Sgdamore int err = 0; 511a5c89047Sgdamore 512a5c89047Sgdamore DPRINTFN(2, "req %s\n", prcorequests[req]); 513a5c89047Sgdamore 514a5c89047Sgdamore if (pcb == NULL) 515a5c89047Sgdamore return EINVAL; 516a5c89047Sgdamore 517a5c89047Sgdamore if (level != BTPROTO_HCI) 518a5c89047Sgdamore return 0; 519a5c89047Sgdamore 520a5c89047Sgdamore switch(req) { 521a5c89047Sgdamore case PRCO_GETOPT: 522a5c89047Sgdamore m = m_get(M_WAIT, MT_SOOPTS); 523a5c89047Sgdamore switch (optname) { 524a5c89047Sgdamore case SO_HCI_EVT_FILTER: 525a5c89047Sgdamore m->m_len = sizeof(struct hci_filter); 526a5c89047Sgdamore memcpy(mtod(m, void *), &pcb->hp_efilter, m->m_len); 527a5c89047Sgdamore break; 528a5c89047Sgdamore 529a5c89047Sgdamore case SO_HCI_PKT_FILTER: 530a5c89047Sgdamore m->m_len = sizeof(struct hci_filter); 531a5c89047Sgdamore memcpy(mtod(m, void *), &pcb->hp_pfilter, m->m_len); 532a5c89047Sgdamore break; 533a5c89047Sgdamore 534a5c89047Sgdamore case SO_HCI_DIRECTION: 535a5c89047Sgdamore m->m_len = sizeof(int); 536a5c89047Sgdamore if (pcb->hp_flags & HCI_DIRECTION) 537a5c89047Sgdamore *mtod(m, int *) = 1; 538a5c89047Sgdamore else 539a5c89047Sgdamore *mtod(m, int *) = 0; 540a5c89047Sgdamore break; 541a5c89047Sgdamore 542a5c89047Sgdamore default: 543a5c89047Sgdamore err = EINVAL; 544a5c89047Sgdamore m_freem(m); 545a5c89047Sgdamore m = NULL; 546a5c89047Sgdamore break; 547a5c89047Sgdamore } 548a5c89047Sgdamore *opt = m; 549a5c89047Sgdamore break; 550a5c89047Sgdamore 551a5c89047Sgdamore case PRCO_SETOPT: 552a5c89047Sgdamore m = *opt; 553a5c89047Sgdamore if (m) switch (optname) { 554a5c89047Sgdamore case SO_HCI_EVT_FILTER: /* set event filter */ 555a5c89047Sgdamore m->m_len = min(m->m_len, sizeof(struct hci_filter)); 556a5c89047Sgdamore memcpy(&pcb->hp_efilter, mtod(m, void *), m->m_len); 557a5c89047Sgdamore break; 558a5c89047Sgdamore 559a5c89047Sgdamore case SO_HCI_PKT_FILTER: /* set packet filter */ 560a5c89047Sgdamore m->m_len = min(m->m_len, sizeof(struct hci_filter)); 561a5c89047Sgdamore memcpy(&pcb->hp_pfilter, mtod(m, void *), m->m_len); 562a5c89047Sgdamore break; 563a5c89047Sgdamore 564a5c89047Sgdamore case SO_HCI_DIRECTION: /* request direction ctl messages */ 565a5c89047Sgdamore if (*mtod(m, int *)) 566a5c89047Sgdamore pcb->hp_flags |= HCI_DIRECTION; 567a5c89047Sgdamore else 568a5c89047Sgdamore pcb->hp_flags &= ~HCI_DIRECTION; 569a5c89047Sgdamore break; 570a5c89047Sgdamore 571a5c89047Sgdamore default: 572a5c89047Sgdamore err = EINVAL; 573a5c89047Sgdamore break; 574a5c89047Sgdamore } 575a5c89047Sgdamore m_freem(m); 576a5c89047Sgdamore break; 577a5c89047Sgdamore 578a5c89047Sgdamore default: 579a5c89047Sgdamore err = EINVAL; 580a5c89047Sgdamore break; 581a5c89047Sgdamore } 582a5c89047Sgdamore 583a5c89047Sgdamore return err; 584a5c89047Sgdamore } 585a5c89047Sgdamore 586a5c89047Sgdamore /* 587a5c89047Sgdamore * HCI mbuf tap routine 588a5c89047Sgdamore * 589a5c89047Sgdamore * copy packets to any raw HCI sockets that wish (and are 590a5c89047Sgdamore * permitted) to see them 591a5c89047Sgdamore */ 592a5c89047Sgdamore void 593a5c89047Sgdamore hci_mtap(struct mbuf *m, struct hci_unit *unit) 594a5c89047Sgdamore { 595a5c89047Sgdamore struct hci_pcb *pcb; 596a5c89047Sgdamore struct mbuf *m0, *ctlmsg, **ctl; 597a5c89047Sgdamore struct sockaddr_bt sa; 598a5c89047Sgdamore uint8_t type; 599a5c89047Sgdamore uint8_t event; 600a5c89047Sgdamore uint16_t opcode; 601a5c89047Sgdamore 602a5c89047Sgdamore KASSERT(m->m_len >= sizeof(type)); 603a5c89047Sgdamore 604a5c89047Sgdamore type = *mtod(m, uint8_t *); 605a5c89047Sgdamore 606a5c89047Sgdamore memset(&sa, 0, sizeof(sa)); 607a5c89047Sgdamore sa.bt_len = sizeof(struct sockaddr_bt); 608a5c89047Sgdamore sa.bt_family = AF_BLUETOOTH; 609a5c89047Sgdamore bdaddr_copy(&sa.bt_bdaddr, &unit->hci_bdaddr); 610a5c89047Sgdamore 611a5c89047Sgdamore LIST_FOREACH(pcb, &hci_pcb, hp_next) { 612a5c89047Sgdamore /* 613a5c89047Sgdamore * filter according to source address 614a5c89047Sgdamore */ 615a5c89047Sgdamore if ((pcb->hp_flags & HCI_PROMISCUOUS) == 0 616a5c89047Sgdamore && bdaddr_same(&pcb->hp_laddr, &sa.bt_bdaddr) == 0) 617a5c89047Sgdamore continue; 618a5c89047Sgdamore 619a5c89047Sgdamore /* 620a5c89047Sgdamore * filter according to packet type filter 621a5c89047Sgdamore */ 622a5c89047Sgdamore if (hci_filter_test(type, &pcb->hp_pfilter) == 0) 623a5c89047Sgdamore continue; 624a5c89047Sgdamore 625a5c89047Sgdamore /* 626a5c89047Sgdamore * filter according to event/security filters 627a5c89047Sgdamore */ 628a5c89047Sgdamore switch(type) { 629a5c89047Sgdamore case HCI_EVENT_PKT: 630a5c89047Sgdamore KASSERT(m->m_len >= sizeof(hci_event_hdr_t)); 631a5c89047Sgdamore 632a5c89047Sgdamore event = mtod(m, hci_event_hdr_t *)->event; 633a5c89047Sgdamore 634a5c89047Sgdamore if (hci_filter_test(event, &pcb->hp_efilter) == 0) 635a5c89047Sgdamore continue; 636a5c89047Sgdamore 637a5c89047Sgdamore if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 638a5c89047Sgdamore && hci_security_check_event(event) == 0) 639a5c89047Sgdamore continue; 640a5c89047Sgdamore break; 641a5c89047Sgdamore 642a5c89047Sgdamore case HCI_CMD_PKT: 643a5c89047Sgdamore KASSERT(m->m_len >= sizeof(hci_cmd_hdr_t)); 644a5c89047Sgdamore 645a5c89047Sgdamore opcode = le16toh(mtod(m, hci_cmd_hdr_t *)->opcode); 646a5c89047Sgdamore 647a5c89047Sgdamore if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 648a5c89047Sgdamore && hci_security_check_opcode(opcode) == 0) 649a5c89047Sgdamore continue; 650a5c89047Sgdamore break; 651a5c89047Sgdamore 652a5c89047Sgdamore case HCI_ACL_DATA_PKT: 653a5c89047Sgdamore case HCI_SCO_DATA_PKT: 654a5c89047Sgdamore default: 655a5c89047Sgdamore if ((pcb->hp_flags & HCI_PRIVILEGED) == 0) 656a5c89047Sgdamore continue; 657a5c89047Sgdamore 658a5c89047Sgdamore break; 659a5c89047Sgdamore } 660a5c89047Sgdamore 661a5c89047Sgdamore /* 662a5c89047Sgdamore * create control messages 663a5c89047Sgdamore */ 664a5c89047Sgdamore ctlmsg = NULL; 665a5c89047Sgdamore ctl = &ctlmsg; 666a5c89047Sgdamore if (pcb->hp_flags & HCI_DIRECTION) { 667a5c89047Sgdamore int dir = m->m_flags & M_LINK0 ? 1 : 0; 668a5c89047Sgdamore 669a5c89047Sgdamore *ctl = sbcreatecontrol((caddr_t)&dir, sizeof(dir), 670a5c89047Sgdamore SCM_HCI_DIRECTION, BTPROTO_HCI); 671a5c89047Sgdamore 672a5c89047Sgdamore if (*ctl != NULL) 673a5c89047Sgdamore ctl = &((*ctl)->m_next); 674a5c89047Sgdamore } 675a5c89047Sgdamore 676a5c89047Sgdamore /* 677a5c89047Sgdamore * copy to socket 678a5c89047Sgdamore */ 679a5c89047Sgdamore m0 = m_copypacket(m, M_DONTWAIT); 680a5c89047Sgdamore if (m0 && sbappendaddr(&pcb->hp_socket->so_rcv, 681a5c89047Sgdamore (struct sockaddr *)&sa, m0, ctlmsg)) { 682a5c89047Sgdamore sorwakeup(pcb->hp_socket); 683a5c89047Sgdamore } else { 684a5c89047Sgdamore m_freem(ctlmsg); 685a5c89047Sgdamore m_freem(m0); 686a5c89047Sgdamore } 687a5c89047Sgdamore } 688a5c89047Sgdamore } 689