diff options
Diffstat (limited to 'sys/netbt/hci_socket.c')
-rw-r--r-- | sys/netbt/hci_socket.c | 421 |
1 files changed, 318 insertions, 103 deletions
diff --git a/sys/netbt/hci_socket.c b/sys/netbt/hci_socket.c index 4933e461aa0..7e9c74ba3af 100644 --- a/sys/netbt/hci_socket.c +++ b/sys/netbt/hci_socket.c @@ -1,5 +1,5 @@ -/* $OpenBSD: hci_socket.c,v 1.4 2007/09/17 01:33:33 krw Exp $ */ -/* $NetBSD: hci_socket.c,v 1.10 2007/03/31 18:17:13 plunky Exp $ */ +/* $OpenBSD: hci_socket.c,v 1.5 2008/02/24 21:34:48 uwe Exp $ */ +/* $NetBSD: hci_socket.c,v 1.14 2008/02/10 17:40:54 plunky Exp $ */ /*- * Copyright (c) 2005 Iain Hibbert. @@ -31,8 +31,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include <sys/cdefs.h> - /* load symbolic names */ #ifdef BLUETOOTH_DEBUG #define PRUREQUESTS @@ -82,104 +80,318 @@ LIST_HEAD(hci_pcb_list, hci_pcb) hci_pcb = LIST_HEAD_INITIALIZER(hci_pcb); int hci_sendspace = HCI_CMD_PKT_SIZE; int hci_recvspace = 4096; +/* supported commands opcode table */ +static const struct { + uint16_t opcode; + uint8_t offs; /* 0 - 63 */ + uint8_t mask; /* bit 0 - 7 */ + int16_t length; /* -1 if privileged */ +} hci_cmds[] = { + { HCI_CMD_INQUIRY, + 0, 0x01, sizeof(hci_inquiry_cp) }, + { HCI_CMD_INQUIRY_CANCEL, + 0, 0x02, -1 }, + { HCI_CMD_PERIODIC_INQUIRY, + 0, 0x04, -1 }, + { HCI_CMD_EXIT_PERIODIC_INQUIRY, + 0, 0x08, -1 }, + { HCI_CMD_CREATE_CON, + 0, 0x10, -1 }, + { HCI_CMD_DISCONNECT, + 0, 0x20, -1 }, + { HCI_CMD_ADD_SCO_CON, + 0, 0x40, -1 }, + { HCI_CMD_CREATE_CON_CANCEL, + 0, 0x80, -1 }, + { HCI_CMD_ACCEPT_CON, + 1, 0x01, -1 }, + { HCI_CMD_REJECT_CON, + 1, 0x02, -1 }, + { HCI_CMD_LINK_KEY_REP, + 1, 0x04, -1 }, + { HCI_CMD_LINK_KEY_NEG_REP, + 1, 0x08, -1 }, + { HCI_CMD_PIN_CODE_REP, + 1, 0x10, -1 }, + { HCI_CMD_PIN_CODE_NEG_REP, + 1, 0x20, -1 }, + { HCI_CMD_CHANGE_CON_PACKET_TYPE, + 1, 0x40, -1 }, + { HCI_CMD_AUTH_REQ, + 1, 0x80, -1 }, + { HCI_CMD_SET_CON_ENCRYPTION, + 2, 0x01, -1 }, + { HCI_CMD_CHANGE_CON_LINK_KEY, + 2, 0x02, -1 }, + { HCI_CMD_MASTER_LINK_KEY, + 2, 0x04, -1 }, + { HCI_CMD_REMOTE_NAME_REQ, + 2, 0x08, sizeof(hci_remote_name_req_cp) }, + { HCI_CMD_REMOTE_NAME_REQ_CANCEL, + 2, 0x10, -1 }, + { HCI_CMD_READ_REMOTE_FEATURES, + 2, 0x20, sizeof(hci_read_remote_features_cp) }, + { HCI_CMD_READ_REMOTE_EXTENDED_FEATURES, + 2, 0x40, sizeof(hci_read_remote_extended_features_cp) }, + { HCI_CMD_READ_REMOTE_VER_INFO, + 2, 0x80, sizeof(hci_read_remote_ver_info_cp) }, + { HCI_CMD_READ_CLOCK_OFFSET, + 3, 0x01, sizeof(hci_read_clock_offset_cp) }, + { HCI_CMD_READ_LMP_HANDLE, + 3, 0x02, sizeof(hci_read_lmp_handle_cp) }, + { HCI_CMD_HOLD_MODE, + 4, 0x02, -1 }, + { HCI_CMD_SNIFF_MODE, + 4, 0x04, -1 }, + { HCI_CMD_EXIT_SNIFF_MODE, + 4, 0x08, -1 }, + { HCI_CMD_PARK_MODE, + 4, 0x10, -1 }, + { HCI_CMD_EXIT_PARK_MODE, + 4, 0x20, -1 }, + { HCI_CMD_QOS_SETUP, + 4, 0x40, -1 }, + { HCI_CMD_ROLE_DISCOVERY, + 4, 0x80, sizeof(hci_role_discovery_cp) }, + { HCI_CMD_SWITCH_ROLE, + 5, 0x01, -1 }, + { HCI_CMD_READ_LINK_POLICY_SETTINGS, + 5, 0x02, sizeof(hci_read_link_policy_settings_cp) }, + { HCI_CMD_WRITE_LINK_POLICY_SETTINGS, + 5, 0x04, -1 }, + { HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS, + 5, 0x08, 0 }, + { HCI_CMD_WRITE_DEFAULT_LINK_POLICY_SETTINGS, + 5, 0x10, -1 }, + { HCI_CMD_FLOW_SPECIFICATION, + 5, 0x20, -1 }, + { HCI_CMD_SET_EVENT_MASK, + 5, 0x40, -1 }, + { HCI_CMD_RESET, + 5, 0x80, -1 }, + { HCI_CMD_SET_EVENT_FILTER, + 6, 0x01, -1 }, + { HCI_CMD_FLUSH, + 6, 0x02, -1 }, + { HCI_CMD_READ_PIN_TYPE, + 6, 0x04, 0 }, + { HCI_CMD_WRITE_PIN_TYPE, + 6, 0x08, -1 }, + { HCI_CMD_CREATE_NEW_UNIT_KEY, + 6, 0x10, -1 }, + { HCI_CMD_READ_STORED_LINK_KEY, + 6, 0x20, -1 }, + { HCI_CMD_WRITE_STORED_LINK_KEY, + 6, 0x40, -1 }, + { HCI_CMD_DELETE_STORED_LINK_KEY, + 6, 0x80, -1 }, + { HCI_CMD_WRITE_LOCAL_NAME, + 7, 0x01, -1 }, + { HCI_CMD_READ_LOCAL_NAME, + 7, 0x02, 0 }, + { HCI_CMD_READ_CON_ACCEPT_TIMEOUT, + 7, 0x04, 0 }, + { HCI_CMD_WRITE_CON_ACCEPT_TIMEOUT, + 7, 0x08, -1 }, + { HCI_CMD_READ_PAGE_TIMEOUT, + 7, 0x10, 0 }, + { HCI_CMD_WRITE_PAGE_TIMEOUT, + 7, 0x20, -1 }, + { HCI_CMD_READ_SCAN_ENABLE, + 7, 0x40, 0 }, + { HCI_CMD_WRITE_SCAN_ENABLE, + 7, 0x80, -1 }, + { HCI_CMD_READ_PAGE_SCAN_ACTIVITY, + 8, 0x01, 0 }, + { HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY, + 8, 0x02, -1 }, + { HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY, + 8, 0x04, 0 }, + { HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY, + 8, 0x08, -1 }, + { HCI_CMD_READ_AUTH_ENABLE, + 8, 0x10, 0 }, + { HCI_CMD_WRITE_AUTH_ENABLE, + 8, 0x20, -1 }, + { HCI_CMD_READ_ENCRYPTION_MODE, + 8, 0x40, 0 }, + { HCI_CMD_WRITE_ENCRYPTION_MODE, + 8, 0x80, -1 }, + { HCI_CMD_READ_UNIT_CLASS, + 9, 0x01, 0 }, + { HCI_CMD_WRITE_UNIT_CLASS, + 9, 0x02, -1 }, + { HCI_CMD_READ_VOICE_SETTING, + 9, 0x04, 0 }, + { HCI_CMD_WRITE_VOICE_SETTING, + 9, 0x08, -1 }, + { HCI_CMD_READ_AUTO_FLUSH_TIMEOUT, + 9, 0x10, sizeof(hci_read_auto_flush_timeout_cp) }, + { HCI_CMD_WRITE_AUTO_FLUSH_TIMEOUT, + 9, 0x20, -1 }, + { HCI_CMD_READ_NUM_BROADCAST_RETRANS, + 9, 0x40, 0 }, + { HCI_CMD_WRITE_NUM_BROADCAST_RETRANS, + 9, 0x80, -1 }, + { HCI_CMD_READ_HOLD_MODE_ACTIVITY, + 10, 0x01, 0 }, + { HCI_CMD_WRITE_HOLD_MODE_ACTIVITY, + 10, 0x02, -1 }, + { HCI_CMD_READ_XMIT_LEVEL, + 10, 0x04, sizeof(hci_read_xmit_level_cp) }, + { HCI_CMD_READ_SCO_FLOW_CONTROL, + 10, 0x08, 0 }, + { HCI_CMD_WRITE_SCO_FLOW_CONTROL, + 10, 0x10, -1 }, + { HCI_CMD_HC2H_FLOW_CONTROL, + 10, 0x20, -1 }, + { HCI_CMD_HOST_BUFFER_SIZE, + 10, 0x40, -1 }, + { HCI_CMD_HOST_NUM_COMPL_PKTS, + 10, 0x80, -1 }, + { HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT, + 11, 0x01, sizeof(hci_read_link_supervision_timeout_cp) }, + { HCI_CMD_WRITE_LINK_SUPERVISION_TIMEOUT, + 11, 0x02, -1 }, + { HCI_CMD_READ_NUM_SUPPORTED_IAC, + 11, 0x04, 0 }, + { HCI_CMD_READ_IAC_LAP, + 11, 0x08, 0 }, + { HCI_CMD_WRITE_IAC_LAP, + 11, 0x10, -1 }, + { HCI_CMD_READ_PAGE_SCAN_PERIOD, + 11, 0x20, 0 }, + { HCI_CMD_WRITE_PAGE_SCAN_PERIOD, + 11, 0x40, -1 }, + { HCI_CMD_READ_PAGE_SCAN, + 11, 0x80, 0 }, + { HCI_CMD_WRITE_PAGE_SCAN, + 12, 0x01, -1 }, + { HCI_CMD_SET_AFH_CLASSIFICATION, + 12, 0x02, -1 }, + { HCI_CMD_READ_INQUIRY_SCAN_TYPE, + 12, 0x10, 0 }, + { HCI_CMD_WRITE_INQUIRY_SCAN_TYPE, + 12, 0x20, -1 }, + { HCI_CMD_READ_INQUIRY_MODE, + 12, 0x40, 0 }, + { HCI_CMD_WRITE_INQUIRY_MODE, + 12, 0x80, -1 }, + { HCI_CMD_READ_PAGE_SCAN_TYPE, + 13, 0x01, 0 }, + { HCI_CMD_WRITE_PAGE_SCAN_TYPE, + 13, 0x02, -1 }, + { HCI_CMD_READ_AFH_ASSESSMENT, + 13, 0x04, 0 }, + { HCI_CMD_WRITE_AFH_ASSESSMENT, + 13, 0x08, -1 }, + { HCI_CMD_READ_LOCAL_VER, + 14, 0x08, 0 }, + { HCI_CMD_READ_LOCAL_COMMANDS, + 14, 0x10, 0 }, + { HCI_CMD_READ_LOCAL_FEATURES, + 14, 0x20, 0 }, + { HCI_CMD_READ_LOCAL_EXTENDED_FEATURES, + 14, 0x40, sizeof(hci_read_local_extended_features_cp) }, + { HCI_CMD_READ_BUFFER_SIZE, + 14, 0x80, 0 }, + { HCI_CMD_READ_COUNTRY_CODE, + 15, 0x01, 0 }, + { HCI_CMD_READ_BDADDR, + 15, 0x02, 0 }, + { HCI_CMD_READ_FAILED_CONTACT_CNTR, + 15, 0x04, sizeof(hci_read_failed_contact_cntr_cp) }, + { HCI_CMD_RESET_FAILED_CONTACT_CNTR, + 15, 0x08, -1 }, + { HCI_CMD_READ_LINK_QUALITY, + 15, 0x10, sizeof(hci_read_link_quality_cp) }, + { HCI_CMD_READ_RSSI, + 15, 0x20, sizeof(hci_read_rssi_cp) }, + { HCI_CMD_READ_AFH_CHANNEL_MAP, + 15, 0x40, sizeof(hci_read_afh_channel_map_cp) }, + { HCI_CMD_READ_CLOCK, + 15, 0x80, sizeof(hci_read_clock_cp) }, + { HCI_CMD_READ_LOOPBACK_MODE, + 16, 0x01, 0 }, + { HCI_CMD_WRITE_LOOPBACK_MODE, + 16, 0x02, -1 }, + { HCI_CMD_ENABLE_UNIT_UNDER_TEST, + 16, 0x04, -1 }, + { HCI_CMD_SETUP_SCO_CON, + 16, 0x08, -1 }, + { HCI_CMD_ACCEPT_SCO_CON_REQ, + 16, 0x10, -1 }, + { HCI_CMD_REJECT_SCO_CON_REQ, + 16, 0x20, -1 }, + { HCI_CMD_READ_EXTENDED_INQUIRY_RSP, + 17, 0x01, 0 }, + { HCI_CMD_WRITE_EXTENDED_INQUIRY_RSP, + 17, 0x02, -1 }, + { HCI_CMD_REFRESH_ENCRYPTION_KEY, + 17, 0x04, -1 }, + { HCI_CMD_SNIFF_SUBRATING, + 17, 0x10, -1 }, + { HCI_CMD_READ_SIMPLE_PAIRING_MODE, + 17, 0x20, 0 }, + { HCI_CMD_WRITE_SIMPLE_PAIRING_MODE, + 17, 0x40, -1 }, + { HCI_CMD_READ_LOCAL_OOB_DATA, + 17, 0x80, -1 }, + { HCI_CMD_READ_INQUIRY_RSP_XMIT_POWER, + 18, 0x01, 0 }, + { HCI_CMD_WRITE_INQUIRY_RSP_XMIT_POWER, + 18, 0x02, -1 }, + { HCI_CMD_READ_DEFAULT_ERRDATA_REPORTING, + 18, 0x04, 0 }, + { HCI_CMD_WRITE_DEFAULT_ERRDATA_REPORTING, + 18, 0x08, -1 }, + { HCI_CMD_IO_CAPABILITY_REP, + 18, 0x80, -1 }, + { HCI_CMD_USER_CONFIRM_REP, + 19, 0x01, -1 }, + { HCI_CMD_USER_CONFIRM_NEG_REP, + 19, 0x02, -1 }, + { HCI_CMD_USER_PASSKEY_REP, + 19, 0x04, -1 }, + { HCI_CMD_USER_PASSKEY_NEG_REP, + 19, 0x08, -1 }, + { HCI_CMD_OOB_DATA_REP, + 19, 0x10, -1 }, + { HCI_CMD_WRITE_SIMPLE_PAIRING_DEBUG_MODE, + 19, 0x20, -1 }, + { HCI_CMD_ENHANCED_FLUSH, + 19, 0x40, -1 }, + { HCI_CMD_OOB_DATA_NEG_REP, + 19, 0x80, -1 }, + { HCI_CMD_SEND_KEYPRESS_NOTIFICATION, + 20, 0x40, -1 }, + { HCI_CMD_IO_CAPABILITY_NEG_REP, + 20, 0x80, -1 }, +}; + /* * Security filter routines for unprivileged users. * Allow all but a few critical events, and only permit read commands. + * If a unit is given, verify the command is supported. */ static int -hci_security_check_opcode(uint16_t opcode) +hci_security_check_opcode(struct hci_unit *unit, uint16_t opcode) { + int i; + + for (i = 0 ; i < sizeof(hci_cmds) / sizeof(hci_cmds[0]); i++) { + if (opcode != hci_cmds[i].opcode) + continue; - switch (opcode) { - /* Link control */ - case HCI_CMD_INQUIRY: - return sizeof(hci_inquiry_cp); - case HCI_CMD_REMOTE_NAME_REQ: - return sizeof(hci_remote_name_req_cp); - case HCI_CMD_READ_REMOTE_FEATURES: - return sizeof(hci_read_remote_features_cp); - case HCI_CMD_READ_REMOTE_EXTENDED_FEATURES: - return sizeof(hci_read_remote_extended_features_cp); - case HCI_CMD_READ_REMOTE_VER_INFO: - return sizeof(hci_read_remote_ver_info_cp); - case HCI_CMD_READ_CLOCK_OFFSET: - return sizeof(hci_read_clock_offset_cp); - case HCI_CMD_READ_LMP_HANDLE: - return sizeof(hci_read_lmp_handle_cp); - - /* Link policy */ - case HCI_CMD_ROLE_DISCOVERY: - return sizeof(hci_role_discovery_cp); - case HCI_CMD_READ_LINK_POLICY_SETTINGS: - return sizeof(hci_read_link_policy_settings_cp); - case HCI_CMD_READ_DEFAULT_LINK_POLICY_SETTINGS: - return 0; /* No command parameters */ - - /* Host controller and baseband */ - case HCI_CMD_READ_PIN_TYPE: - case HCI_CMD_READ_LOCAL_NAME: - case HCI_CMD_READ_CON_ACCEPT_TIMEOUT: - case HCI_CMD_READ_PAGE_TIMEOUT: - case HCI_CMD_READ_SCAN_ENABLE: - case HCI_CMD_READ_PAGE_SCAN_ACTIVITY: - case HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY: - case HCI_CMD_READ_AUTH_ENABLE: - case HCI_CMD_READ_ENCRYPTION_MODE: - case HCI_CMD_READ_UNIT_CLASS: - case HCI_CMD_READ_VOICE_SETTING: - return 0; /* No command parameters */ - case HCI_CMD_READ_AUTO_FLUSH_TIMEOUT: - return sizeof(hci_read_auto_flush_timeout_cp); - case HCI_CMD_READ_NUM_BROADCAST_RETRANS: - case HCI_CMD_READ_HOLD_MODE_ACTIVITY: - return 0; /* No command parameters */ - case HCI_CMD_READ_XMIT_LEVEL: - return sizeof(hci_read_xmit_level_cp); - case HCI_CMD_READ_SCO_FLOW_CONTROL: - return 0; /* No command parameters */ - case HCI_CMD_READ_LINK_SUPERVISION_TIMEOUT: - return sizeof(hci_read_link_supervision_timeout_cp); - case HCI_CMD_READ_NUM_SUPPORTED_IAC: - case HCI_CMD_READ_IAC_LAP: - case HCI_CMD_READ_PAGE_SCAN_PERIOD: - case HCI_CMD_READ_PAGE_SCAN: - case HCI_CMD_READ_INQUIRY_SCAN_TYPE: - case HCI_CMD_READ_INQUIRY_MODE: - case HCI_CMD_READ_PAGE_SCAN_TYPE: - case HCI_CMD_READ_AFH_ASSESSMENT: - return 0; /* No command parameters */ - - /* Informational */ - case HCI_CMD_READ_LOCAL_VER: - case HCI_CMD_READ_LOCAL_COMMANDS: - case HCI_CMD_READ_LOCAL_FEATURES: - return 0; /* No command parameters */ - case HCI_CMD_READ_LOCAL_EXTENDED_FEATURES: - return sizeof(hci_read_local_extended_features_cp); - case HCI_CMD_READ_BUFFER_SIZE: - case HCI_CMD_READ_COUNTRY_CODE: - case HCI_CMD_READ_BDADDR: - return 0; /* No command parameters */ - - /* Status */ - case HCI_CMD_READ_FAILED_CONTACT_CNTR: - return sizeof(hci_read_failed_contact_cntr_cp); - case HCI_CMD_READ_LINK_QUALITY: - return sizeof(hci_read_link_quality_cp); - case HCI_CMD_READ_RSSI: - return sizeof(hci_read_rssi_cp); - case HCI_CMD_READ_AFH_CHANNEL_MAP: - return sizeof(hci_read_afh_channel_map_cp); - case HCI_CMD_READ_CLOCK: - return sizeof(hci_read_clock_cp); - - /* Testing */ - case HCI_CMD_READ_LOOPBACK_MODE: - return 0; /* No command parameters */ + if (unit == NULL + || (unit->hci_cmds[hci_cmds[i].offs] & hci_cmds[i].mask)) + return hci_cmds[i].length; + + break; } - return -1; /* disallowed */ + return -1; } static int @@ -189,6 +401,8 @@ hci_security_check_event(uint8_t event) switch (event) { case HCI_EVENT_RETURN_LINK_KEYS: case HCI_EVENT_LINK_KEY_NOTIFICATION: + case HCI_EVENT_USER_CONFIRM_REQ: + case HCI_EVENT_USER_PASSKEY_NOTIFICATION: case HCI_EVENT_VENDOR: return -1; /* disallowed */ } @@ -256,6 +470,7 @@ hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) goto bad; } m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr); + hdr.opcode = letoh16(hdr.opcode); /* only allows CMD packets to be sent */ if (hdr.type != HCI_CMD_PKT) { @@ -269,13 +484,6 @@ hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) goto bad; } - /* security checks for unprivileged users */ - if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 - && hci_security_check_opcode(letoh16(hdr.opcode)) != hdr.length) { - err = EPERM; - goto bad; - } - /* finds destination */ unit = hci_unit_lookup(addr); if (unit == NULL) { @@ -283,6 +491,13 @@ hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) goto bad; } + /* security checks for unprivileged users */ + if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 + && hci_security_check_opcode(unit, hdr.opcode) != hdr.length) { + err = EPERM; + goto bad; + } + /* makes a copy for precious to keep */ m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); if (m0 == NULL) { @@ -292,8 +507,8 @@ hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) sbappendrecord(&pcb->hp_socket->so_snd, m0); M_SETCTX(m, pcb->hp_socket); /* enable drop callback */ - DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", unit->hci_devname, - HCI_OGF(letoh16(hdr.opcode)), HCI_OCF(letoh16(hdr.opcode))); + DPRINTFN(2, "(%s) opcode (%03x|%04x)\n", device_xname(unit->hci_dev), + HCI_OGF(hdr.opcode), HCI_OCF(hdr.opcode)); /* Sendss it */ if (unit->hci_num_cmd_pkts == 0) @@ -305,7 +520,7 @@ hci_send(struct hci_pcb *pcb, struct mbuf *m, bdaddr_t *addr) bad: DPRINTF("packet (%d bytes) not sent (error %d)\n", - m->m_pkthdr.len, err); + m->m_pkthdr.len, err); if (m) m_freem(m); return err; } @@ -668,7 +883,7 @@ hci_mtap(struct mbuf *m, struct hci_unit *unit) opcode = letoh16(mtod(m, hci_cmd_hdr_t *)->opcode); if ((pcb->hp_flags & HCI_PRIVILEGED) == 0 - && hci_security_check_opcode(opcode) == -1) + && hci_security_check_opcode(NULL, opcode) == -1) continue; break; |