Commit a9de9248 authored by Marcel Holtmann's avatar Marcel Holtmann Committed by David S. Miller

[Bluetooth] Switch from OGF+OCF to using only opcodes

The Bluetooth HCI commands are divided into logical OGF groups for
easier identification of their purposes. While this still makes sense
for the written specification, its makes the code only more complex
and harder to read. So instead of using separate OGF and OCF values
to identify the commands, use a common 16-bit opcode that combines
both values. As a side effect this also reduces the complexity of
OGF and OCF calculations during command header parsing.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 55b70a03
...@@ -237,7 +237,8 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, ...@@ -237,7 +237,8 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
if (hciextn && chan == 5) { if (hciextn && chan == 5) {
struct hci_command_hdr *hdr = (struct hci_command_hdr *) data; struct hci_command_hdr *hdr = (struct hci_command_hdr *) data;
if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == OGF_VENDOR_CMD) { /* Vendor specific commands */
if (hci_opcode_ogf(__le16_to_cpu(hdr->opcode)) == 0x3f) {
u8 desc = *(data + HCI_COMMAND_HDR_SIZE); u8 desc = *(data + HCI_COMMAND_HDR_SIZE);
if ((desc & 0xf0) == 0xc0) { if ((desc & 0xf0) == 0xc0) {
data += HCI_COMMAND_HDR_SIZE + 1; data += HCI_COMMAND_HDR_SIZE + 1;
......
...@@ -200,119 +200,18 @@ enum { ...@@ -200,119 +200,18 @@ enum {
#define HCI_LM_SECURE 0x0020 #define HCI_LM_SECURE 0x0020
/* ----- HCI Commands ---- */ /* ----- HCI Commands ---- */
/* OGF & OCF values */ #define HCI_OP_INQUIRY 0x0401
struct hci_cp_inquiry {
/* Informational Parameters */ __u8 lap[3];
#define OGF_INFO_PARAM 0x04 __u8 length;
__u8 num_rsp;
#define OCF_READ_LOCAL_VERSION 0x0001
struct hci_rp_read_loc_version {
__u8 status;
__u8 hci_ver;
__le16 hci_rev;
__u8 lmp_ver;
__le16 manufacturer;
__le16 lmp_subver;
} __attribute__ ((packed));
#define OCF_READ_LOCAL_FEATURES 0x0003
struct hci_rp_read_local_features {
__u8 status;
__u8 features[8];
} __attribute__ ((packed));
#define OCF_READ_BUFFER_SIZE 0x0005
struct hci_rp_read_buffer_size {
__u8 status;
__le16 acl_mtu;
__u8 sco_mtu;
__le16 acl_max_pkt;
__le16 sco_max_pkt;
} __attribute__ ((packed));
#define OCF_READ_BD_ADDR 0x0009
struct hci_rp_read_bd_addr {
__u8 status;
bdaddr_t bdaddr;
} __attribute__ ((packed));
/* Host Controller and Baseband */
#define OGF_HOST_CTL 0x03
#define OCF_RESET 0x0003
#define OCF_READ_AUTH_ENABLE 0x001F
#define OCF_WRITE_AUTH_ENABLE 0x0020
#define AUTH_DISABLED 0x00
#define AUTH_ENABLED 0x01
#define OCF_READ_ENCRYPT_MODE 0x0021
#define OCF_WRITE_ENCRYPT_MODE 0x0022
#define ENCRYPT_DISABLED 0x00
#define ENCRYPT_P2P 0x01
#define ENCRYPT_BOTH 0x02
#define OCF_WRITE_CA_TIMEOUT 0x0016
#define OCF_WRITE_PG_TIMEOUT 0x0018
#define OCF_WRITE_SCAN_ENABLE 0x001A
#define SCAN_DISABLED 0x00
#define SCAN_INQUIRY 0x01
#define SCAN_PAGE 0x02
#define OCF_SET_EVENT_FLT 0x0005
struct hci_cp_set_event_flt {
__u8 flt_type;
__u8 cond_type;
__u8 condition[0];
} __attribute__ ((packed));
/* Filter types */
#define HCI_FLT_CLEAR_ALL 0x00
#define HCI_FLT_INQ_RESULT 0x01
#define HCI_FLT_CONN_SETUP 0x02
/* CONN_SETUP Condition types */
#define HCI_CONN_SETUP_ALLOW_ALL 0x00
#define HCI_CONN_SETUP_ALLOW_CLASS 0x01
#define HCI_CONN_SETUP_ALLOW_BDADDR 0x02
/* CONN_SETUP Conditions */
#define HCI_CONN_SETUP_AUTO_OFF 0x01
#define HCI_CONN_SETUP_AUTO_ON 0x02
#define OCF_READ_CLASS_OF_DEV 0x0023
struct hci_rp_read_dev_class {
__u8 status;
__u8 dev_class[3];
} __attribute__ ((packed));
#define OCF_WRITE_CLASS_OF_DEV 0x0024
struct hci_cp_write_dev_class {
__u8 dev_class[3];
} __attribute__ ((packed));
#define OCF_READ_VOICE_SETTING 0x0025
struct hci_rp_read_voice_setting {
__u8 status;
__le16 voice_setting;
} __attribute__ ((packed));
#define OCF_WRITE_VOICE_SETTING 0x0026
struct hci_cp_write_voice_setting {
__le16 voice_setting;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_HOST_BUFFER_SIZE 0x0033 #define HCI_OP_INQUIRY_CANCEL 0x0402
struct hci_cp_host_buffer_size {
__le16 acl_mtu;
__u8 sco_mtu;
__le16 acl_max_pkt;
__le16 sco_max_pkt;
} __attribute__ ((packed));
/* Link Control */ #define HCI_OP_EXIT_PERIODIC_INQ 0x0404
#define OGF_LINK_CTL 0x01
#define OCF_CREATE_CONN 0x0005 #define HCI_OP_CREATE_CONN 0x0405
struct hci_cp_create_conn { struct hci_cp_create_conn {
bdaddr_t bdaddr; bdaddr_t bdaddr;
__le16 pkt_type; __le16 pkt_type;
...@@ -322,105 +221,138 @@ struct hci_cp_create_conn { ...@@ -322,105 +221,138 @@ struct hci_cp_create_conn {
__u8 role_switch; __u8 role_switch;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_CREATE_CONN_CANCEL 0x0008 #define HCI_OP_DISCONNECT 0x0406
struct hci_cp_create_conn_cancel {
bdaddr_t bdaddr;
} __attribute__ ((packed));
#define OCF_ACCEPT_CONN_REQ 0x0009
struct hci_cp_accept_conn_req {
bdaddr_t bdaddr;
__u8 role;
} __attribute__ ((packed));
#define OCF_REJECT_CONN_REQ 0x000a
struct hci_cp_reject_conn_req {
bdaddr_t bdaddr;
__u8 reason;
} __attribute__ ((packed));
#define OCF_DISCONNECT 0x0006
struct hci_cp_disconnect { struct hci_cp_disconnect {
__le16 handle; __le16 handle;
__u8 reason; __u8 reason;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_ADD_SCO 0x0007 #define HCI_OP_ADD_SCO 0x0407
struct hci_cp_add_sco { struct hci_cp_add_sco {
__le16 handle; __le16 handle;
__le16 pkt_type; __le16 pkt_type;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_INQUIRY 0x0001 #define HCI_OP_CREATE_CONN_CANCEL 0x0408
struct hci_cp_inquiry { struct hci_cp_create_conn_cancel {
__u8 lap[3]; bdaddr_t bdaddr;
__u8 length;
__u8 num_rsp;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_INQUIRY_CANCEL 0x0002 #define HCI_OP_ACCEPT_CONN_REQ 0x0409
struct hci_cp_accept_conn_req {
bdaddr_t bdaddr;
__u8 role;
} __attribute__ ((packed));
#define OCF_EXIT_PERIODIC_INQ 0x0004 #define HCI_OP_REJECT_CONN_REQ 0x040a
struct hci_cp_reject_conn_req {
bdaddr_t bdaddr;
__u8 reason;
} __attribute__ ((packed));
#define OCF_LINK_KEY_REPLY 0x000B #define HCI_OP_LINK_KEY_REPLY 0x040b
struct hci_cp_link_key_reply { struct hci_cp_link_key_reply {
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 link_key[16]; __u8 link_key[16];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_LINK_KEY_NEG_REPLY 0x000C #define HCI_OP_LINK_KEY_NEG_REPLY 0x040c
struct hci_cp_link_key_neg_reply { struct hci_cp_link_key_neg_reply {
bdaddr_t bdaddr; bdaddr_t bdaddr;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_PIN_CODE_REPLY 0x000D #define HCI_OP_PIN_CODE_REPLY 0x040d
struct hci_cp_pin_code_reply { struct hci_cp_pin_code_reply {
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 pin_len; __u8 pin_len;
__u8 pin_code[16]; __u8 pin_code[16];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_PIN_CODE_NEG_REPLY 0x000E #define HCI_OP_PIN_CODE_NEG_REPLY 0x040e
struct hci_cp_pin_code_neg_reply { struct hci_cp_pin_code_neg_reply {
bdaddr_t bdaddr; bdaddr_t bdaddr;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_CHANGE_CONN_PTYPE 0x000F #define HCI_OP_CHANGE_CONN_PTYPE 0x040f
struct hci_cp_change_conn_ptype { struct hci_cp_change_conn_ptype {
__le16 handle; __le16 handle;
__le16 pkt_type; __le16 pkt_type;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_AUTH_REQUESTED 0x0011 #define HCI_OP_AUTH_REQUESTED 0x0411
struct hci_cp_auth_requested { struct hci_cp_auth_requested {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_SET_CONN_ENCRYPT 0x0013 #define HCI_OP_SET_CONN_ENCRYPT 0x0413
struct hci_cp_set_conn_encrypt { struct hci_cp_set_conn_encrypt {
__le16 handle; __le16 handle;
__u8 encrypt; __u8 encrypt;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_CHANGE_CONN_LINK_KEY 0x0015 #define HCI_OP_CHANGE_CONN_LINK_KEY 0x0415
struct hci_cp_change_conn_link_key { struct hci_cp_change_conn_link_key {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_READ_REMOTE_FEATURES 0x001B #define HCI_OP_REMOTE_NAME_REQ 0x0419
struct hci_cp_remote_name_req {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_mode;
__le16 clock_offset;
} __attribute__ ((packed));
#define HCI_OP_REMOTE_NAME_REQ_CANCEL 0x041a
struct hci_cp_remote_name_req_cancel {
bdaddr_t bdaddr;
} __attribute__ ((packed));
#define HCI_OP_READ_REMOTE_FEATURES 0x041b
struct hci_cp_read_remote_features { struct hci_cp_read_remote_features {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_READ_REMOTE_VERSION 0x001D #define HCI_OP_READ_REMOTE_EXT_FEATURES 0x041c
struct hci_cp_read_remote_ext_features {
__le16 handle;
__u8 page;
} __attribute__ ((packed));
#define HCI_OP_READ_REMOTE_VERSION 0x041d
struct hci_cp_read_remote_version { struct hci_cp_read_remote_version {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Link Policy */ #define HCI_OP_SETUP_SYNC_CONN 0x0428
#define OGF_LINK_POLICY 0x02 struct hci_cp_setup_sync_conn {
__le16 handle;
__le32 tx_bandwidth;
__le32 rx_bandwidth;
__le16 max_latency;
__le16 voice_setting;
__u8 retrans_effort;
__le16 pkt_type;
} __attribute__ ((packed));
#define HCI_OP_ACCEPT_SYNC_CONN_REQ 0x0429
struct hci_cp_accept_sync_conn_req {
bdaddr_t bdaddr;
__le32 tx_bandwidth;
__le32 rx_bandwidth;
__le16 max_latency;
__le16 content_format;
__u8 retrans_effort;
__le16 pkt_type;
} __attribute__ ((packed));
#define HCI_OP_REJECT_SYNC_CONN_REQ 0x042a
struct hci_cp_reject_sync_conn_req {
bdaddr_t bdaddr;
__u8 reason;
} __attribute__ ((packed));
#define OCF_SNIFF_MODE 0x0003 #define HCI_OP_SNIFF_MODE 0x0803
struct hci_cp_sniff_mode { struct hci_cp_sniff_mode {
__le16 handle; __le16 handle;
__le16 max_interval; __le16 max_interval;
...@@ -429,12 +361,12 @@ struct hci_cp_sniff_mode { ...@@ -429,12 +361,12 @@ struct hci_cp_sniff_mode {
__le16 timeout; __le16 timeout;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_EXIT_SNIFF_MODE 0x0004 #define HCI_OP_EXIT_SNIFF_MODE 0x0804
struct hci_cp_exit_sniff_mode { struct hci_cp_exit_sniff_mode {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_ROLE_DISCOVERY 0x0009 #define HCI_OP_ROLE_DISCOVERY 0x0809
struct hci_cp_role_discovery { struct hci_cp_role_discovery {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
...@@ -444,7 +376,13 @@ struct hci_rp_role_discovery { ...@@ -444,7 +376,13 @@ struct hci_rp_role_discovery {
__u8 role; __u8 role;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_READ_LINK_POLICY 0x000C #define HCI_OP_SWITCH_ROLE 0x080b
struct hci_cp_switch_role {
bdaddr_t bdaddr;
__u8 role;
} __attribute__ ((packed));
#define HCI_OP_READ_LINK_POLICY 0x080c
struct hci_cp_read_link_policy { struct hci_cp_read_link_policy {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
...@@ -454,13 +392,7 @@ struct hci_rp_read_link_policy { ...@@ -454,13 +392,7 @@ struct hci_rp_read_link_policy {
__le16 policy; __le16 policy;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_SWITCH_ROLE 0x000B #define HCI_OP_WRITE_LINK_POLICY 0x080d
struct hci_cp_switch_role {
bdaddr_t bdaddr;
__u8 role;
} __attribute__ ((packed));
#define OCF_WRITE_LINK_POLICY 0x000D
struct hci_cp_write_link_policy { struct hci_cp_write_link_policy {
__le16 handle; __le16 handle;
__le16 policy; __le16 policy;
...@@ -470,7 +402,7 @@ struct hci_rp_write_link_policy { ...@@ -470,7 +402,7 @@ struct hci_rp_write_link_policy {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define OCF_SNIFF_SUBRATE 0x0011 #define HCI_OP_SNIFF_SUBRATE 0x0811
struct hci_cp_sniff_subrate { struct hci_cp_sniff_subrate {
__le16 handle; __le16 handle;
__le16 max_latency; __le16 max_latency;
...@@ -478,56 +410,153 @@ struct hci_cp_sniff_subrate { ...@@ -478,56 +410,153 @@ struct hci_cp_sniff_subrate {
__le16 min_local_timeout; __le16 min_local_timeout;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* Status params */ #define HCI_OP_SET_EVENT_MASK 0x0c01
#define OGF_STATUS_PARAM 0x05 struct hci_cp_set_event_mask {
__u8 mask[8];
} __attribute__ ((packed));
#define HCI_OP_RESET 0x0c03
#define HCI_OP_SET_EVENT_FLT 0x0c05
struct hci_cp_set_event_flt {
__u8 flt_type;
__u8 cond_type;
__u8 condition[0];
} __attribute__ ((packed));
/* Testing commands */ /* Filter types */
#define OGF_TESTING_CMD 0x3E #define HCI_FLT_CLEAR_ALL 0x00
#define HCI_FLT_INQ_RESULT 0x01
#define HCI_FLT_CONN_SETUP 0x02
/* Vendor specific commands */ /* CONN_SETUP Condition types */
#define OGF_VENDOR_CMD 0x3F #define HCI_CONN_SETUP_ALLOW_ALL 0x00
#define HCI_CONN_SETUP_ALLOW_CLASS 0x01
#define HCI_CONN_SETUP_ALLOW_BDADDR 0x02
/* ---- HCI Events ---- */ /* CONN_SETUP Conditions */
#define HCI_EV_INQUIRY_COMPLETE 0x01 #define HCI_CONN_SETUP_AUTO_OFF 0x01
#define HCI_CONN_SETUP_AUTO_ON 0x02
#define HCI_EV_INQUIRY_RESULT 0x02 #define HCI_OP_WRITE_LOCAL_NAME 0x0c13
struct inquiry_info { struct hci_cp_write_local_name {
bdaddr_t bdaddr; __u8 name[248];
__u8 pscan_rep_mode; } __attribute__ ((packed));
__u8 pscan_period_mode;
__u8 pscan_mode; #define HCI_OP_READ_LOCAL_NAME 0x0c14
struct hci_rp_read_local_name {
__u8 status;
__u8 name[248];
} __attribute__ ((packed));
#define HCI_OP_WRITE_CA_TIMEOUT 0x0c16
#define HCI_OP_WRITE_PG_TIMEOUT 0x0c18
#define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a
#define SCAN_DISABLED 0x00
#define SCAN_INQUIRY 0x01
#define SCAN_PAGE 0x02
#define HCI_OP_READ_AUTH_ENABLE 0x0c1f
#define HCI_OP_WRITE_AUTH_ENABLE 0x0c20
#define AUTH_DISABLED 0x00
#define AUTH_ENABLED 0x01
#define HCI_OP_READ_ENCRYPT_MODE 0x0c21
#define HCI_OP_WRITE_ENCRYPT_MODE 0x0c22
#define ENCRYPT_DISABLED 0x00
#define ENCRYPT_P2P 0x01
#define ENCRYPT_BOTH 0x02
#define HCI_OP_READ_CLASS_OF_DEV 0x0c23
struct hci_rp_read_class_of_dev {
__u8 status;
__u8 dev_class[3]; __u8 dev_class[3];
__le16 clock_offset;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22 #define HCI_OP_WRITE_CLASS_OF_DEV 0x0c24
struct inquiry_info_with_rssi { struct hci_cp_write_class_of_dev {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_period_mode;
__u8 dev_class[3]; __u8 dev_class[3];
__le16 clock_offset;
__s8 rssi;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct inquiry_info_with_rssi_and_pscan_mode {
#define HCI_OP_READ_VOICE_SETTING 0x0c25
struct hci_rp_read_voice_setting {
__u8 status;
__le16 voice_setting;
} __attribute__ ((packed));
#define HCI_OP_WRITE_VOICE_SETTING 0x0c26
struct hci_cp_write_voice_setting {
__le16 voice_setting;
} __attribute__ ((packed));
#define HCI_OP_HOST_BUFFER_SIZE 0x0c33
struct hci_cp_host_buffer_size {
__le16 acl_mtu;
__u8 sco_mtu;
__le16 acl_max_pkt;
__le16 sco_max_pkt;
} __attribute__ ((packed));
#define HCI_OP_READ_LOCAL_VERSION 0x1001
struct hci_rp_read_local_version {
__u8 status;
__u8 hci_ver;
__le16 hci_rev;
__u8 lmp_ver;
__le16 manufacturer;
__le16 lmp_subver;
} __attribute__ ((packed));
#define HCI_OP_READ_LOCAL_COMMANDS 0x1002
struct hci_rp_read_local_commands {
__u8 status;
__u8 commands[64];
} __attribute__ ((packed));
#define HCI_OP_READ_LOCAL_FEATURES 0x1003
struct hci_rp_read_local_features {
__u8 status;
__u8 features[8];
} __attribute__ ((packed));
#define HCI_OP_READ_LOCAL_EXT_FEATURES 0x1004
struct hci_rp_read_local_ext_features {
__u8 status;
__u8 page;
__u8 max_page;
__u8 features[8];
} __attribute__ ((packed));
#define HCI_OP_READ_BUFFER_SIZE 0x1005
struct hci_rp_read_buffer_size {
__u8 status;
__le16 acl_mtu;
__u8 sco_mtu;
__le16 acl_max_pkt;
__le16 sco_max_pkt;
} __attribute__ ((packed));
#define HCI_OP_READ_BD_ADDR 0x1009
struct hci_rp_read_bd_addr {
__u8 status;
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_period_mode;
__u8 pscan_mode;
__u8 dev_class[3];
__le16 clock_offset;
__s8 rssi;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2F /* ---- HCI Events ---- */
struct extended_inquiry_info { #define HCI_EV_INQUIRY_COMPLETE 0x01
#define HCI_EV_INQUIRY_RESULT 0x02
struct inquiry_info {
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 pscan_rep_mode; __u8 pscan_rep_mode;
__u8 pscan_period_mode; __u8 pscan_period_mode;
__u8 pscan_mode;
__u8 dev_class[3]; __u8 dev_class[3];
__le16 clock_offset; __le16 clock_offset;
__s8 rssi;
__u8 data[240];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_CONN_COMPLETE 0x03 #define HCI_EV_CONN_COMPLETE 0x03
...@@ -559,6 +588,13 @@ struct hci_ev_auth_complete { ...@@ -559,6 +588,13 @@ struct hci_ev_auth_complete {
__le16 handle; __le16 handle;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_REMOTE_NAME 0x07
struct hci_ev_remote_name {
__u8 status;
bdaddr_t bdaddr;
__u8 name[248];
} __attribute__ ((packed));
#define HCI_EV_ENCRYPT_CHANGE 0x08 #define HCI_EV_ENCRYPT_CHANGE 0x08
struct hci_ev_encrypt_change { struct hci_ev_encrypt_change {
__u8 status; __u8 status;
...@@ -566,13 +602,29 @@ struct hci_ev_encrypt_change { ...@@ -566,13 +602,29 @@ struct hci_ev_encrypt_change {
__u8 encrypt; __u8 encrypt;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE 0x09 #define HCI_EV_CHANGE_LINK_KEY_COMPLETE 0x09
struct hci_ev_change_conn_link_key_complete { struct hci_ev_change_link_key_complete {
__u8 status;
__le16 handle;
} __attribute__ ((packed));
#define HCI_EV_REMOTE_FEATURES 0x0b
struct hci_ev_remote_features {
__u8 status; __u8 status;
__le16 handle; __le16 handle;
__u8 features[8];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_QOS_SETUP_COMPLETE 0x0D #define HCI_EV_REMOTE_VERSION 0x0c
struct hci_ev_remote_version {
__u8 status;
__le16 handle;
__u8 lmp_ver;
__le16 manufacturer;
__le16 lmp_subver;
} __attribute__ ((packed));
#define HCI_EV_QOS_SETUP_COMPLETE 0x0d
struct hci_qos { struct hci_qos {
__u8 service_type; __u8 service_type;
__u32 token_rate; __u32 token_rate;
...@@ -586,25 +638,19 @@ struct hci_ev_qos_setup_complete { ...@@ -586,25 +638,19 @@ struct hci_ev_qos_setup_complete {
struct hci_qos qos; struct hci_qos qos;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_CMD_COMPLETE 0x0E #define HCI_EV_CMD_COMPLETE 0x0e
struct hci_ev_cmd_complete { struct hci_ev_cmd_complete {
__u8 ncmd; __u8 ncmd;
__le16 opcode; __le16 opcode;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_CMD_STATUS 0x0F #define HCI_EV_CMD_STATUS 0x0f
struct hci_ev_cmd_status { struct hci_ev_cmd_status {
__u8 status; __u8 status;
__u8 ncmd; __u8 ncmd;
__le16 opcode; __le16 opcode;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_NUM_COMP_PKTS 0x13
struct hci_ev_num_comp_pkts {
__u8 num_hndl;
/* variable length part */
} __attribute__ ((packed));
#define HCI_EV_ROLE_CHANGE 0x12 #define HCI_EV_ROLE_CHANGE 0x12
struct hci_ev_role_change { struct hci_ev_role_change {
__u8 status; __u8 status;
...@@ -612,6 +658,12 @@ struct hci_ev_role_change { ...@@ -612,6 +658,12 @@ struct hci_ev_role_change {
__u8 role; __u8 role;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_NUM_COMP_PKTS 0x13
struct hci_ev_num_comp_pkts {
__u8 num_hndl;
/* variable length part */
} __attribute__ ((packed));
#define HCI_EV_MODE_CHANGE 0x14 #define HCI_EV_MODE_CHANGE 0x14
struct hci_ev_mode_change { struct hci_ev_mode_change {
__u8 status; __u8 status;
...@@ -637,36 +689,71 @@ struct hci_ev_link_key_notify { ...@@ -637,36 +689,71 @@ struct hci_ev_link_key_notify {
__u8 key_type; __u8 key_type;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_REMOTE_FEATURES 0x0B #define HCI_EV_CLOCK_OFFSET 0x1c
struct hci_ev_remote_features { struct hci_ev_clock_offset {
__u8 status; __u8 status;
__le16 handle; __le16 handle;
__u8 features[8]; __le16 clock_offset;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_REMOTE_VERSION 0x0C #define HCI_EV_PSCAN_REP_MODE 0x20
struct hci_ev_remote_version { struct hci_ev_pscan_rep_mode {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
} __attribute__ ((packed));
#define HCI_EV_INQUIRY_RESULT_WITH_RSSI 0x22
struct inquiry_info_with_rssi {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_period_mode;
__u8 dev_class[3];
__le16 clock_offset;
__s8 rssi;
} __attribute__ ((packed));
struct inquiry_info_with_rssi_and_pscan_mode {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_period_mode;
__u8 pscan_mode;
__u8 dev_class[3];
__le16 clock_offset;
__s8 rssi;
} __attribute__ ((packed));
#define HCI_EV_REMOTE_EXT_FEATURES 0x23
struct hci_ev_remote_ext_features {
__u8 status; __u8 status;
__le16 handle; __le16 handle;
__u8 lmp_ver; __u8 page;
__le16 manufacturer; __u8 max_page;
__le16 lmp_subver; __u8 features[8];
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_CLOCK_OFFSET 0x01C #define HCI_EV_SYNC_CONN_COMPLETE 0x2c
struct hci_ev_clock_offset { struct hci_ev_sync_conn_complete {
__u8 status; __u8 status;
__le16 handle; __le16 handle;
__le16 clock_offset; bdaddr_t bdaddr;
__u8 link_type;
__u8 tx_interval;
__u8 retrans_window;
__le16 rx_pkt_len;
__le16 tx_pkt_len;
__u8 air_mode;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_PSCAN_REP_MODE 0x20 #define HCI_EV_SYNC_CONN_CHANGED 0x2d
struct hci_ev_pscan_rep_mode { struct hci_ev_sync_conn_changed {
bdaddr_t bdaddr; __u8 status;
__u8 pscan_rep_mode; __le16 handle;
__u8 tx_interval;
__u8 retrans_window;
__le16 rx_pkt_len;
__le16 tx_pkt_len;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_SNIFF_SUBRATE 0x2E #define HCI_EV_SNIFF_SUBRATE 0x2e
struct hci_ev_sniff_subrate { struct hci_ev_sniff_subrate {
__u8 status; __u8 status;
__le16 handle; __le16 handle;
...@@ -676,8 +763,19 @@ struct hci_ev_sniff_subrate { ...@@ -676,8 +763,19 @@ struct hci_ev_sniff_subrate {
__le16 max_local_timeout; __le16 max_local_timeout;
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2f
struct extended_inquiry_info {
bdaddr_t bdaddr;
__u8 pscan_rep_mode;
__u8 pscan_period_mode;
__u8 dev_class[3];
__le16 clock_offset;
__s8 rssi;
__u8 data[240];
} __attribute__ ((packed));
/* Internal events generated by Bluetooth stack */ /* Internal events generated by Bluetooth stack */
#define HCI_EV_STACK_INTERNAL 0xFD #define HCI_EV_STACK_INTERNAL 0xfd
struct hci_ev_stack_internal { struct hci_ev_stack_internal {
__u16 type; __u16 type;
__u8 data[0]; __u8 data[0];
...@@ -727,17 +825,17 @@ struct hci_sco_hdr { ...@@ -727,17 +825,17 @@ struct hci_sco_hdr {
#include <linux/skbuff.h> #include <linux/skbuff.h>
static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb) static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
{ {
return (struct hci_event_hdr *)skb->data; return (struct hci_event_hdr *) skb->data;
} }
static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb) static inline struct hci_acl_hdr *hci_acl_hdr(const struct sk_buff *skb)
{ {
return (struct hci_acl_hdr *)skb->data; return (struct hci_acl_hdr *) skb->data;
} }
static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb) static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
{ {
return (struct hci_sco_hdr *)skb->data; return (struct hci_sco_hdr *) skb->data;
} }
#endif #endif
......
...@@ -71,7 +71,10 @@ struct hci_dev { ...@@ -71,7 +71,10 @@ struct hci_dev {
__u16 id; __u16 id;
__u8 type; __u8 type;
bdaddr_t bdaddr; bdaddr_t bdaddr;
__u8 dev_name[248];
__u8 dev_class[3];
__u8 features[8]; __u8 features[8];
__u8 commands[64];
__u8 hci_ver; __u8 hci_ver;
__u16 hci_rev; __u16 hci_rev;
__u16 manufacturer; __u16 manufacturer;
...@@ -314,6 +317,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle); ...@@ -314,6 +317,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle);
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst); struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
int hci_conn_del(struct hci_conn *conn); int hci_conn_del(struct hci_conn *conn);
void hci_conn_hash_flush(struct hci_dev *hdev); void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src); struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
int hci_conn_auth(struct hci_conn *conn); int hci_conn_auth(struct hci_conn *conn);
...@@ -617,11 +621,11 @@ int hci_unregister_cb(struct hci_cb *hcb); ...@@ -617,11 +621,11 @@ int hci_unregister_cb(struct hci_cb *hcb);
int hci_register_notifier(struct notifier_block *nb); int hci_register_notifier(struct notifier_block *nb);
int hci_unregister_notifier(struct notifier_block *nb); int hci_unregister_notifier(struct notifier_block *nb);
int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param); int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data); void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
......
...@@ -82,7 +82,7 @@ void hci_acl_connect(struct hci_conn *conn) ...@@ -82,7 +82,7 @@ void hci_acl_connect(struct hci_conn *conn)
else else
cp.role_switch = 0x00; cp.role_switch = 0x00;
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
} }
static void hci_acl_connect_cancel(struct hci_conn *conn) static void hci_acl_connect_cancel(struct hci_conn *conn)
...@@ -95,8 +95,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn) ...@@ -95,8 +95,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn)
return; return;
bacpy(&cp.bdaddr, &conn->dst); bacpy(&cp.bdaddr, &conn->dst);
hci_send_cmd(conn->hdev, OGF_LINK_CTL, hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
OCF_CREATE_CONN_CANCEL, sizeof(cp), &cp);
} }
void hci_acl_disconn(struct hci_conn *conn, __u8 reason) void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
...@@ -109,8 +108,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason) ...@@ -109,8 +108,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
cp.reason = reason; cp.reason = reason;
hci_send_cmd(conn->hdev, OGF_LINK_CTL, hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
OCF_DISCONNECT, sizeof(cp), &cp);
} }
void hci_add_sco(struct hci_conn *conn, __u16 handle) void hci_add_sco(struct hci_conn *conn, __u16 handle)
...@@ -126,7 +124,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) ...@@ -126,7 +124,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
cp.handle = cpu_to_le16(handle); cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
} }
static void hci_conn_timeout(unsigned long arg) static void hci_conn_timeout(unsigned long arg)
...@@ -348,7 +346,7 @@ int hci_conn_auth(struct hci_conn *conn) ...@@ -348,7 +346,7 @@ int hci_conn_auth(struct hci_conn *conn)
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
struct hci_cp_auth_requested cp; struct hci_cp_auth_requested cp;
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, sizeof(cp), &cp); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
} }
return 0; return 0;
} }
...@@ -369,7 +367,7 @@ int hci_conn_encrypt(struct hci_conn *conn) ...@@ -369,7 +367,7 @@ int hci_conn_encrypt(struct hci_conn *conn)
struct hci_cp_set_conn_encrypt cp; struct hci_cp_set_conn_encrypt cp;
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 1; cp.encrypt = 1;
hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp); hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
} }
return 0; return 0;
} }
...@@ -383,7 +381,7 @@ int hci_conn_change_link_key(struct hci_conn *conn) ...@@ -383,7 +381,7 @@ int hci_conn_change_link_key(struct hci_conn *conn)
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
struct hci_cp_change_conn_link_key cp; struct hci_cp_change_conn_link_key cp;
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp); hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
} }
return 0; return 0;
} }
...@@ -401,7 +399,7 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role) ...@@ -401,7 +399,7 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
struct hci_cp_switch_role cp; struct hci_cp_switch_role cp;
bacpy(&cp.bdaddr, &conn->dst); bacpy(&cp.bdaddr, &conn->dst);
cp.role = role; cp.role = role;
hci_send_cmd(conn->hdev, OGF_LINK_POLICY, OCF_SWITCH_ROLE, sizeof(cp), &cp); hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
} }
return 0; return 0;
} }
...@@ -423,8 +421,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn) ...@@ -423,8 +421,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn)
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
struct hci_cp_exit_sniff_mode cp; struct hci_cp_exit_sniff_mode cp;
cp.handle = cpu_to_le16(conn->handle); cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(hdev, OGF_LINK_POLICY, hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp);
} }
timer: timer:
...@@ -455,8 +452,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn) ...@@ -455,8 +452,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
cp.max_latency = cpu_to_le16(0); cp.max_latency = cpu_to_le16(0);
cp.min_remote_timeout = cpu_to_le16(0); cp.min_remote_timeout = cpu_to_le16(0);
cp.min_local_timeout = cpu_to_le16(0); cp.min_local_timeout = cpu_to_le16(0);
hci_send_cmd(hdev, OGF_LINK_POLICY, hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
OCF_SNIFF_SUBRATE, sizeof(cp), &cp);
} }
if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
...@@ -466,8 +462,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn) ...@@ -466,8 +462,7 @@ void hci_conn_enter_sniff_mode(struct hci_conn *conn)
cp.min_interval = cpu_to_le16(hdev->sniff_min_interval); cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
cp.attempt = cpu_to_le16(4); cp.attempt = cpu_to_le16(4);
cp.timeout = cpu_to_le16(1); cp.timeout = cpu_to_le16(1);
hci_send_cmd(hdev, OGF_LINK_POLICY, hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
OCF_SNIFF_MODE, sizeof(cp), &cp);
} }
} }
...@@ -493,6 +488,22 @@ void hci_conn_hash_flush(struct hci_dev *hdev) ...@@ -493,6 +488,22 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
} }
} }
/* Check pending connect attempts */
void hci_conn_check_pending(struct hci_dev *hdev)
{
struct hci_conn *conn;
BT_DBG("hdev %s", hdev->name);
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
if (conn)
hci_acl_connect(conn);
hci_dev_unlock(hdev);
}
int hci_get_conn_list(void __user *arg) int hci_get_conn_list(void __user *arg)
{ {
struct hci_conn_list_req req, *cl; struct hci_conn_list_req req, *cl;
......
...@@ -176,7 +176,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) ...@@ -176,7 +176,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
BT_DBG("%s %ld", hdev->name, opt); BT_DBG("%s %ld", hdev->name, opt);
/* Reset device */ /* Reset device */
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
} }
static void hci_init_req(struct hci_dev *hdev, unsigned long opt) static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
...@@ -202,16 +202,16 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) ...@@ -202,16 +202,16 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
/* Reset */ /* Reset */
if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks)) if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
/* Read Local Supported Features */ /* Read Local Supported Features */
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL); hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
/* Read Local Version */ /* Read Local Version */
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL); hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
/* Read Buffer Size (ACL mtu, max pkt, etc.) */ /* Read Buffer Size (ACL mtu, max pkt, etc.) */
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL); hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
#if 0 #if 0
/* Host buffer size */ /* Host buffer size */
...@@ -221,29 +221,35 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) ...@@ -221,29 +221,35 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
cp.sco_mtu = HCI_MAX_SCO_SIZE; cp.sco_mtu = HCI_MAX_SCO_SIZE;
cp.acl_max_pkt = cpu_to_le16(0xffff); cp.acl_max_pkt = cpu_to_le16(0xffff);
cp.sco_max_pkt = cpu_to_le16(0xffff); cp.sco_max_pkt = cpu_to_le16(0xffff);
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_HOST_BUFFER_SIZE, sizeof(cp), &cp);
} }
#endif #endif
/* Read BD Address */ /* Read BD Address */
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL); hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
/* Read Class of Device */
hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
/* Read Local Name */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
/* Read Voice Setting */ /* Read Voice Setting */
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL); hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
/* Optional initialization */ /* Optional initialization */
/* Clear Event Filters */ /* Clear Event Filters */
flt_type = HCI_FLT_CLEAR_ALL; flt_type = HCI_FLT_CLEAR_ALL;
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &flt_type); hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
/* Page timeout ~20 secs */ /* Page timeout ~20 secs */
param = cpu_to_le16(0x8000); param = cpu_to_le16(0x8000);
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_PG_TIMEOUT, 2, &param); hci_send_cmd(hdev, HCI_OP_WRITE_PG_TIMEOUT, 2, &param);
/* Connection accept timeout ~20 secs */ /* Connection accept timeout ~20 secs */
param = cpu_to_le16(0x7d00); param = cpu_to_le16(0x7d00);
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_CA_TIMEOUT, 2, &param); hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
} }
static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
...@@ -253,7 +259,7 @@ static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) ...@@ -253,7 +259,7 @@ static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
BT_DBG("%s %x", hdev->name, scan); BT_DBG("%s %x", hdev->name, scan);
/* Inquiry and Page scans */ /* Inquiry and Page scans */
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan); hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
} }
static void hci_auth_req(struct hci_dev *hdev, unsigned long opt) static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
...@@ -263,7 +269,7 @@ static void hci_auth_req(struct hci_dev *hdev, unsigned long opt) ...@@ -263,7 +269,7 @@ static void hci_auth_req(struct hci_dev *hdev, unsigned long opt)
BT_DBG("%s %x", hdev->name, auth); BT_DBG("%s %x", hdev->name, auth);
/* Authentication */ /* Authentication */
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth); hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth);
} }
static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt) static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
...@@ -273,7 +279,7 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt) ...@@ -273,7 +279,7 @@ static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
BT_DBG("%s %x", hdev->name, encrypt); BT_DBG("%s %x", hdev->name, encrypt);
/* Authentication */ /* Authentication */
hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt); hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
} }
/* Get HCI device by index. /* Get HCI device by index.
...@@ -384,7 +390,7 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) ...@@ -384,7 +390,7 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
memcpy(&cp.lap, &ir->lap, 3); memcpy(&cp.lap, &ir->lap, 3);
cp.length = ir->length; cp.length = ir->length;
cp.num_rsp = ir->num_rsp; cp.num_rsp = ir->num_rsp;
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, sizeof(cp), &cp); hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
} }
int hci_inquiry(void __user *arg) int hci_inquiry(void __user *arg)
...@@ -1111,13 +1117,13 @@ static int hci_send_frame(struct sk_buff *skb) ...@@ -1111,13 +1117,13 @@ static int hci_send_frame(struct sk_buff *skb)
} }
/* Send HCI command */ /* Send HCI command */
int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param) int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
{ {
int len = HCI_COMMAND_HDR_SIZE + plen; int len = HCI_COMMAND_HDR_SIZE + plen;
struct hci_command_hdr *hdr; struct hci_command_hdr *hdr;
struct sk_buff *skb; struct sk_buff *skb;
BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen); BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);
skb = bt_skb_alloc(len, GFP_ATOMIC); skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb) { if (!skb) {
...@@ -1126,7 +1132,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p ...@@ -1126,7 +1132,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
} }
hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE); hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
hdr->opcode = cpu_to_le16(hci_opcode_pack(ogf, ocf)); hdr->opcode = cpu_to_le16(opcode);
hdr->plen = plen; hdr->plen = plen;
if (plen) if (plen)
...@@ -1143,7 +1149,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p ...@@ -1143,7 +1149,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
} }
/* Get data from the previously sent command */ /* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf) void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
{ {
struct hci_command_hdr *hdr; struct hci_command_hdr *hdr;
...@@ -1152,10 +1158,10 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf) ...@@ -1152,10 +1158,10 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
hdr = (void *) hdev->sent_cmd->data; hdr = (void *) hdev->sent_cmd->data;
if (hdr->opcode != cpu_to_le16(hci_opcode_pack(ogf, ocf))) if (hdr->opcode != cpu_to_le16(opcode))
return NULL; return NULL;
BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf); BT_DBG("%s opcode 0x%x", hdev->name, opcode);
return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
} }
......
...@@ -52,234 +52,273 @@ ...@@ -52,234 +52,273 @@
/* Handle HCI Event packets */ /* Handle HCI Event packets */
/* Command Complete OGF LINK_CTL */ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{ {
__u8 status; __u8 status = *((__u8 *) skb->data);
struct hci_conn *pend;
BT_DBG("%s ocf 0x%x", hdev->name, ocf); BT_DBG("%s status 0x%x", hdev->name, status);
switch (ocf) { if (status)
case OCF_INQUIRY_CANCEL: return;
case OCF_EXIT_PERIODIC_INQ:
status = *((__u8 *) skb->data);
if (status) {
BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
} else {
clear_bit(HCI_INQUIRY, &hdev->flags); clear_bit(HCI_INQUIRY, &hdev->flags);
hci_req_complete(hdev, status); hci_req_complete(hdev, status);
}
hci_dev_lock(hdev); hci_conn_check_pending(hdev);
}
pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
if (pend) {
hci_acl_connect(pend); __u8 status = *((__u8 *) skb->data);
hci_dev_unlock(hdev); BT_DBG("%s status 0x%x", hdev->name, status);
break; if (status)
return;
default: clear_bit(HCI_INQUIRY, &hdev->flags);
BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
break; hci_conn_check_pending(hdev);
}
} }
/* Command Complete OGF LINK_POLICY */ static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{ {
struct hci_conn *conn; BT_DBG("%s", hdev->name);
struct hci_rp_role_discovery *rd; }
struct hci_rp_write_link_policy *lp;
void *sent;
BT_DBG("%s ocf 0x%x", hdev->name, ocf); static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_role_discovery *rp = (void *) skb->data;
struct hci_conn *conn;
switch (ocf) { BT_DBG("%s status 0x%x", hdev->name, rp->status);
case OCF_ROLE_DISCOVERY:
rd = (void *) skb->data;
if (rd->status) if (rp->status)
break; return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle)); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
if (conn) { if (conn) {
if (rd->role) if (rp->role)
conn->link_mode &= ~HCI_LM_MASTER; conn->link_mode &= ~HCI_LM_MASTER;
else else
conn->link_mode |= HCI_LM_MASTER; conn->link_mode |= HCI_LM_MASTER;
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
break; }
case OCF_WRITE_LINK_POLICY: static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY); {
if (!sent) struct hci_rp_write_link_policy *rp = (void *) skb->data;
break; struct hci_conn *conn;
void *sent;
lp = (struct hci_rp_write_link_policy *) skb->data; BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (lp->status) if (rp->status)
break; return;
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LINK_POLICY);
if (!sent)
return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle)); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
if (conn) { if (conn) {
__le16 policy = get_unaligned((__le16 *) (sent + 2)); __le16 policy = get_unaligned((__le16 *) (sent + 2));
conn->link_policy = __le16_to_cpu(policy); conn->link_policy = __le16_to_cpu(policy);
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
break;
default:
BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x",
hdev->name, ocf);
break;
}
} }
/* Command Complete OGF HOST_CTL */ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{ {
__u8 status, param; __u8 status = *((__u8 *) skb->data);
__u16 setting;
struct hci_rp_read_voice_setting *vs;
void *sent;
BT_DBG("%s ocf 0x%x", hdev->name, ocf); BT_DBG("%s status 0x%x", hdev->name, status);
switch (ocf) {
case OCF_RESET:
status = *((__u8 *) skb->data);
hci_req_complete(hdev, status); hci_req_complete(hdev, status);
break; }
case OCF_SET_EVENT_FLT: static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
status = *((__u8 *) skb->data); {
if (status) { __u8 status = *((__u8 *) skb->data);
BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status); void *sent;
} else {
BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name); BT_DBG("%s status 0x%x", hdev->name, status);
}
break;
case OCF_WRITE_AUTH_ENABLE: sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME);
sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
if (!sent) if (!sent)
break; return;
if (!status)
memcpy(hdev->dev_name, sent, 248);
}
static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_local_name *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
memcpy(hdev->dev_name, rp->name, 248);
}
static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
void *sent;
BT_DBG("%s status 0x%x", hdev->name, status);
status = *((__u8 *) skb->data); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE);
param = *((__u8 *) sent); if (!sent)
return;
if (!status) { if (!status) {
__u8 param = *((__u8 *) sent);
if (param == AUTH_ENABLED) if (param == AUTH_ENABLED)
set_bit(HCI_AUTH, &hdev->flags); set_bit(HCI_AUTH, &hdev->flags);
else else
clear_bit(HCI_AUTH, &hdev->flags); clear_bit(HCI_AUTH, &hdev->flags);
} }
hci_req_complete(hdev, status); hci_req_complete(hdev, status);
break; }
case OCF_WRITE_ENCRYPT_MODE: static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE); {
if (!sent) __u8 status = *((__u8 *) skb->data);
break; void *sent;
BT_DBG("%s status 0x%x", hdev->name, status);
status = *((__u8 *) skb->data); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE);
param = *((__u8 *) sent); if (!sent)
return;
if (!status) { if (!status) {
__u8 param = *((__u8 *) sent);
if (param) if (param)
set_bit(HCI_ENCRYPT, &hdev->flags); set_bit(HCI_ENCRYPT, &hdev->flags);
else else
clear_bit(HCI_ENCRYPT, &hdev->flags); clear_bit(HCI_ENCRYPT, &hdev->flags);
} }
hci_req_complete(hdev, status); hci_req_complete(hdev, status);
break; }
case OCF_WRITE_CA_TIMEOUT: static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
status = *((__u8 *) skb->data); {
if (status) { __u8 status = *((__u8 *) skb->data);
BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status); void *sent;
} else {
BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
}
break;
case OCF_WRITE_PG_TIMEOUT: BT_DBG("%s status 0x%x", hdev->name, status);
status = *((__u8 *) skb->data);
if (status) {
BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
} else {
BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
}
break;
case OCF_WRITE_SCAN_ENABLE: sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE);
sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
if (!sent) if (!sent)
break; return;
status = *((__u8 *) skb->data);
param = *((__u8 *) sent);
BT_DBG("param 0x%x", param);
if (!status) { if (!status) {
__u8 param = *((__u8 *) sent);
clear_bit(HCI_PSCAN, &hdev->flags); clear_bit(HCI_PSCAN, &hdev->flags);
clear_bit(HCI_ISCAN, &hdev->flags); clear_bit(HCI_ISCAN, &hdev->flags);
if (param & SCAN_INQUIRY) if (param & SCAN_INQUIRY)
set_bit(HCI_ISCAN, &hdev->flags); set_bit(HCI_ISCAN, &hdev->flags);
if (param & SCAN_PAGE) if (param & SCAN_PAGE)
set_bit(HCI_PSCAN, &hdev->flags); set_bit(HCI_PSCAN, &hdev->flags);
} }
hci_req_complete(hdev, status); hci_req_complete(hdev, status);
break; }
case OCF_READ_VOICE_SETTING: static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
vs = (struct hci_rp_read_voice_setting *) skb->data; {
struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
if (vs->status) { BT_DBG("%s status 0x%x", hdev->name, rp->status);
BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vs->status);
break; if (rp->status)
} return;
memcpy(hdev->dev_class, rp->dev_class, 3);
BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name,
hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
}
static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
void *sent;
BT_DBG("%s status 0x%x", hdev->name, status);
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV);
if (!sent)
return;
if (!status)
memcpy(hdev->dev_class, sent, 3);
}
setting = __le16_to_cpu(vs->voice_setting); static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_voice_setting *rp = (void *) skb->data;
__u16 setting;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
setting = __le16_to_cpu(rp->voice_setting);
if (hdev->voice_setting == setting )
return;
if (hdev->voice_setting != setting ) {
hdev->voice_setting = setting; hdev->voice_setting = setting;
BT_DBG("%s: voice setting 0x%04x", hdev->name, setting); BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
if (hdev->notify) { if (hdev->notify) {
tasklet_disable(&hdev->tx_task); tasklet_disable(&hdev->tx_task);
hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
tasklet_enable(&hdev->tx_task); tasklet_enable(&hdev->tx_task);
} }
} }
break;
static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
void *sent;
BT_DBG("%s status 0x%x", hdev->name, status);
case OCF_WRITE_VOICE_SETTING: sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_VOICE_SETTING);
sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING);
if (!sent) if (!sent)
break; return;
status = *((__u8 *) skb->data); if (!status) {
setting = __le16_to_cpu(get_unaligned((__le16 *) sent)); __u16 setting = __le16_to_cpu(get_unaligned((__le16 *) sent));
if (!status && hdev->voice_setting != setting) { if (hdev->voice_setting != setting) {
hdev->voice_setting = setting; hdev->voice_setting = setting;
BT_DBG("%s: voice setting 0x%04x", hdev->name, setting); BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
if (hdev->notify) { if (hdev->notify) {
tasklet_disable(&hdev->tx_task); tasklet_disable(&hdev->tx_task);
...@@ -287,63 +326,62 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb ...@@ -287,63 +326,62 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
tasklet_enable(&hdev->tx_task); tasklet_enable(&hdev->tx_task);
} }
} }
hci_req_complete(hdev, status);
break;
case OCF_HOST_BUFFER_SIZE:
status = *((__u8 *) skb->data);
if (status) {
BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
hci_req_complete(hdev, status);
} }
break; }
default: static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf); {
break; __u8 status = *((__u8 *) skb->data);
}
BT_DBG("%s status 0x%x", hdev->name, status);
hci_req_complete(hdev, status);
} }
/* Command Complete OGF INFO_PARAM */ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{ {
struct hci_rp_read_loc_version *lv; struct hci_rp_read_local_version *rp = (void *) skb->data;
struct hci_rp_read_local_features *lf;
struct hci_rp_read_buffer_size *bs;
struct hci_rp_read_bd_addr *ba;
BT_DBG("%s ocf 0x%x", hdev->name, ocf); BT_DBG("%s status 0x%x", hdev->name, rp->status);
switch (ocf) { if (rp->status)
case OCF_READ_LOCAL_VERSION: return;
lv = (struct hci_rp_read_loc_version *) skb->data;
if (lv->status) { hdev->hci_ver = rp->hci_ver;
BT_DBG("%s READ_LOCAL_VERSION failed %d", hdev->name, lf->status); hdev->hci_rev = btohs(rp->hci_rev);
break; hdev->manufacturer = btohs(rp->manufacturer);
}
hdev->hci_ver = lv->hci_ver; BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
hdev->hci_rev = btohs(lv->hci_rev); hdev->manufacturer,
hdev->manufacturer = btohs(lv->manufacturer); hdev->hci_ver, hdev->hci_rev);
}
BT_DBG("%s: manufacturer %d hci_ver %d hci_rev %d", hdev->name, static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
hdev->manufacturer, hdev->hci_ver, hdev->hci_rev); {
struct hci_rp_read_local_commands *rp = (void *) skb->data;
break; BT_DBG("%s status 0x%x", hdev->name, rp->status);
case OCF_READ_LOCAL_FEATURES: if (rp->status)
lf = (struct hci_rp_read_local_features *) skb->data; return;
if (lf->status) { memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); }
break;
} static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_local_features *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
memcpy(hdev->features, lf->features, sizeof(hdev->features)); memcpy(hdev->features, rp->features, 8);
/* Adjust default settings according to features /* Adjust default settings according to features
* supported by device. */ * supported by device. */
if (hdev->features[0] & LMP_3SLOT) if (hdev->features[0] & LMP_3SLOT)
hdev->pkt_type |= (HCI_DM3 | HCI_DH3); hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
...@@ -369,24 +407,26 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s ...@@ -369,24 +407,26 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
if (hdev->features[4] & LMP_EV5) if (hdev->features[4] & LMP_EV5)
hdev->esco_type |= (ESCO_EV5); hdev->esco_type |= (ESCO_EV5);
BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
lf->features[0], lf->features[1], lf->features[2]); hdev->features[0], hdev->features[1],
hdev->features[2], hdev->features[3],
hdev->features[4], hdev->features[5],
hdev->features[6], hdev->features[7]);
}
break; static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_buffer_size *rp = (void *) skb->data;
case OCF_READ_BUFFER_SIZE: BT_DBG("%s status 0x%x", hdev->name, rp->status);
bs = (struct hci_rp_read_buffer_size *) skb->data;
if (bs->status) { if (rp->status)
BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status); return;
hci_req_complete(hdev, bs->status);
break;
}
hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); hdev->acl_mtu = __le16_to_cpu(rp->acl_mtu);
hdev->sco_mtu = bs->sco_mtu; hdev->sco_mtu = rp->sco_mtu;
hdev->acl_pkts = __le16_to_cpu(bs->acl_max_pkt); hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
hdev->sco_pkts = __le16_to_cpu(bs->sco_max_pkt); hdev->sco_pkts = __le16_to_cpu(rp->sco_max_pkt);
if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) { if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) {
hdev->sco_mtu = 64; hdev->sco_mtu = 64;
...@@ -396,34 +436,43 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s ...@@ -396,34 +436,43 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
hdev->acl_cnt = hdev->acl_pkts; hdev->acl_cnt = hdev->acl_pkts;
hdev->sco_cnt = hdev->sco_pkts; hdev->sco_cnt = hdev->sco_pkts;
BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts); hdev->acl_mtu, hdev->acl_pkts,
break; hdev->sco_mtu, hdev->sco_pkts);
}
case OCF_READ_BD_ADDR: static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
ba = (struct hci_rp_read_bd_addr *) skb->data; {
struct hci_rp_read_bd_addr *rp = (void *) skb->data;
if (!ba->status) { BT_DBG("%s status 0x%x", hdev->name, rp->status);
bacpy(&hdev->bdaddr, &ba->bdaddr);
} else {
BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
}
hci_req_complete(hdev, ba->status); if (!rp->status)
break; bacpy(&hdev->bdaddr, &rp->bdaddr);
default: hci_req_complete(hdev, rp->status);
BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf); }
break;
} static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{
BT_DBG("%s status 0x%x", hdev->name, status);
if (status) {
hci_req_complete(hdev, status);
hci_conn_check_pending(hdev);
} else
set_bit(HCI_INQUIRY, &hdev->flags);
} }
/* Command Status OGF LINK_CTL */
static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
{ {
struct hci_cp_create_conn *cp;
struct hci_conn *conn; struct hci_conn *conn;
struct hci_cp_create_conn *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
BT_DBG("%s status 0x%x", hdev->name, status);
cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_CONN);
if (!cp) if (!cp)
return; return;
...@@ -431,8 +480,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) ...@@ -431,8 +480,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->bdaddr), conn);
status, batostr(&cp->bdaddr), conn);
if (status) { if (status) {
if (conn && conn->state == BT_CONNECT) { if (conn && conn->state == BT_CONNECT) {
...@@ -457,27 +505,24 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) ...@@ -457,27 +505,24 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status)
{ {
BT_DBG("%s ocf 0x%x", hdev->name, ocf); struct hci_cp_add_sco *cp;
switch (ocf) {
case OCF_CREATE_CONN:
hci_cs_create_conn(hdev, status);
break;
case OCF_ADD_SCO:
if (status) {
struct hci_conn *acl, *sco; struct hci_conn *acl, *sco;
struct hci_cp_add_sco *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_ADD_SCO);
__u16 handle; __u16 handle;
if (!status)
return;
BT_DBG("%s status 0x%x", hdev->name, status);
cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO);
if (!cp) if (!cp)
break; return;
handle = __le16_to_cpu(cp->handle); handle = __le16_to_cpu(cp->handle);
BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status); BT_DBG("%s handle %d", hdev->name, handle);
hci_dev_lock(hdev); hci_dev_lock(hdev);
...@@ -490,124 +535,81 @@ static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) ...@@ -490,124 +535,81 @@ static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
break;
case OCF_INQUIRY:
if (status) {
BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status);
hci_req_complete(hdev, status);
} else {
set_bit(HCI_INQUIRY, &hdev->flags);
}
break;
default: static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", {
hdev->name, ocf, status); BT_DBG("%s status 0x%x", hdev->name, status);
break;
}
} }
/* Command Status OGF LINK_POLICY */ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
{ {
BT_DBG("%s ocf 0x%x", hdev->name, ocf); BT_DBG("%s status 0x%x", hdev->name, status);
}
switch (ocf) { static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
case OCF_SNIFF_MODE: {
if (status) { struct hci_cp_sniff_mode *cp;
struct hci_conn *conn; struct hci_conn *conn;
struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE);
BT_DBG("%s status 0x%x", hdev->name, status);
if (!status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_SNIFF_MODE);
if (!cp) if (!cp)
break; return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
if (conn) { if (conn)
clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
}
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
break;
case OCF_EXIT_SNIFF_MODE: static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
if (status) { {
struct hci_cp_exit_sniff_mode *cp;
struct hci_conn *conn; struct hci_conn *conn;
struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE);
BT_DBG("%s status 0x%x", hdev->name, status);
if (!status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_EXIT_SNIFF_MODE);
if (!cp) if (!cp)
break; return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
if (conn) { if (conn)
clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend);
}
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
}
break;
default:
BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf);
break;
}
} }
/* Command Status OGF HOST_CTL */ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
{ {
BT_DBG("%s ocf 0x%x", hdev->name, ocf); __u8 status = *((__u8 *) skb->data);
switch (ocf) {
default:
BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
break;
}
}
/* Command Status OGF INFO_PARAM */
static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
{
BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
switch (ocf) {
default:
BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
break;
}
}
/* Inquiry Complete */
static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
struct hci_conn *pend;
BT_DBG("%s status %d", hdev->name, status); BT_DBG("%s status %d", hdev->name, status);
clear_bit(HCI_INQUIRY, &hdev->flags); clear_bit(HCI_INQUIRY, &hdev->flags);
hci_req_complete(hdev, status);
hci_dev_lock(hdev); hci_req_complete(hdev, status);
pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
if (pend)
hci_acl_connect(pend);
hci_dev_unlock(hdev); hci_conn_check_pending(hdev);
} }
/* Inquiry Result */
static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct inquiry_data data; struct inquiry_data data;
struct inquiry_info *info = (struct inquiry_info *) (skb->data + 1); struct inquiry_info *info = (void *) (skb->data + 1);
int num_rsp = *((__u8 *) skb->data); int num_rsp = *((__u8 *) skb->data);
BT_DBG("%s num_rsp %d", hdev->name, num_rsp); BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
...@@ -632,147 +634,18 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * ...@@ -632,147 +634,18 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
/* Inquiry Result With RSSI */
static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct inquiry_data data;
int num_rsp = *((__u8 *) skb->data);
BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
if (!num_rsp)
return;
hci_dev_lock(hdev);
if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
struct inquiry_info_with_rssi_and_pscan_mode *info =
(struct inquiry_info_with_rssi_and_pscan_mode *) (skb->data + 1);
for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode;
data.pscan_mode = info->pscan_mode;
memcpy(data.dev_class, info->dev_class, 3);
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
info++;
hci_inquiry_cache_update(hdev, &data);
}
} else {
struct inquiry_info_with_rssi *info =
(struct inquiry_info_with_rssi *) (skb->data + 1);
for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode;
data.pscan_mode = 0x00;
memcpy(data.dev_class, info->dev_class, 3);
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
info++;
hci_inquiry_cache_update(hdev, &data);
}
}
hci_dev_unlock(hdev);
}
/* Extended Inquiry Result */
static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct inquiry_data data;
struct extended_inquiry_info *info = (struct extended_inquiry_info *) (skb->data + 1);
int num_rsp = *((__u8 *) skb->data);
BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
if (!num_rsp)
return;
hci_dev_lock(hdev);
for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode;
data.pscan_mode = 0x00;
memcpy(data.dev_class, info->dev_class, 3);
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
info++;
hci_inquiry_cache_update(hdev, &data);
}
hci_dev_unlock(hdev);
}
/* Connect Request */
static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_conn_request *ev = (struct hci_ev_conn_request *) skb->data;
int mask = hdev->link_mode;
BT_DBG("%s Connection request: %s type 0x%x", hdev->name,
batostr(&ev->bdaddr), ev->link_type);
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
if (mask & HCI_LM_ACCEPT) {
/* Connection accepted */
struct hci_conn *conn;
struct hci_cp_accept_conn_req cp;
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) {
if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
BT_ERR("No memmory for new connection");
hci_dev_unlock(hdev);
return;
}
}
memcpy(conn->dev_class, ev->dev_class, 3);
conn->state = BT_CONNECT;
hci_dev_unlock(hdev);
bacpy(&cp.bdaddr, &ev->bdaddr);
if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
cp.role = 0x00; /* Become master */
else
cp.role = 0x01; /* Remain slave */
hci_send_cmd(hdev, OGF_LINK_CTL,
OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp);
} else {
/* Connection rejected */
struct hci_cp_reject_conn_req cp;
bacpy(&cp.bdaddr, &ev->bdaddr);
cp.reason = 0x0f;
hci_send_cmd(hdev, OGF_LINK_CTL,
OCF_REJECT_CONN_REQ, sizeof(cp), &cp);
}
}
/* Connect Complete */
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data; struct hci_ev_conn_complete *ev = (void *) skb->data;
struct hci_conn *conn, *pend; struct hci_conn *conn;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) { if (!conn)
hci_dev_unlock(hdev); goto unlock;
return;
}
if (!ev->status) { if (!ev->status) {
conn->handle = __le16_to_cpu(ev->handle); conn->handle = __le16_to_cpu(ev->handle);
...@@ -788,8 +661,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -788,8 +661,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if (conn->type == ACL_LINK) { if (conn->type == ACL_LINK) {
struct hci_cp_read_remote_features cp; struct hci_cp_read_remote_features cp;
cp.handle = ev->handle; cp.handle = ev->handle;
hci_send_cmd(hdev, OGF_LINK_CTL, hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES, sizeof(cp), &cp);
OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp);
} }
/* Set link policy */ /* Set link policy */
...@@ -797,8 +669,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -797,8 +669,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
struct hci_cp_write_link_policy cp; struct hci_cp_write_link_policy cp;
cp.handle = ev->handle; cp.handle = ev->handle;
cp.policy = cpu_to_le16(hdev->link_policy); cp.policy = cpu_to_le16(hdev->link_policy);
hci_send_cmd(hdev, OGF_LINK_POLICY, hci_send_cmd(hdev, HCI_OP_WRITE_LINK_POLICY, sizeof(cp), &cp);
OCF_WRITE_LINK_POLICY, sizeof(cp), &cp);
} }
/* Set packet type for incoming connection */ /* Set packet type for incoming connection */
...@@ -809,8 +680,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -809,8 +680,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
hci_send_cmd(hdev, OGF_LINK_CTL, hci_send_cmd(hdev, HCI_OP_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
} else { } else {
/* Update disconnect timer */ /* Update disconnect timer */
hci_conn_hold(conn); hci_conn_hold(conn);
...@@ -835,17 +705,61 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -835,17 +705,61 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if (ev->status) if (ev->status)
hci_conn_del(conn); hci_conn_del(conn);
pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2); unlock:
if (pend) hci_dev_unlock(hdev);
hci_acl_connect(pend);
hci_conn_check_pending(hdev);
}
static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_conn_request *ev = (void *) skb->data;
int mask = hdev->link_mode;
BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
batostr(&ev->bdaddr), ev->link_type);
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
if (mask & HCI_LM_ACCEPT) {
/* Connection accepted */
struct hci_conn *conn;
struct hci_cp_accept_conn_req cp;
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) {
if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
BT_ERR("No memmory for new connection");
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
return;
}
}
memcpy(conn->dev_class, ev->dev_class, 3);
conn->state = BT_CONNECT;
hci_dev_unlock(hdev);
bacpy(&cp.bdaddr, &ev->bdaddr);
if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
cp.role = 0x00; /* Become master */
else
cp.role = 0x01; /* Remain slave */
hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
} else {
/* Connection rejected */
struct hci_cp_reject_conn_req cp;
bacpy(&cp.bdaddr, &ev->bdaddr);
cp.reason = 0x0f;
hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
}
} }
/* Disconnect Complete */
static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data; struct hci_ev_disconn_complete *ev = (void *) skb->data;
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status); BT_DBG("%s status %d", hdev->name, ev->status);
...@@ -865,80 +779,77 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff ...@@ -865,80 +779,77 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
/* Number of completed packets */ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_num_comp_pkts *ev = (struct hci_ev_num_comp_pkts *) skb->data; struct hci_ev_auth_complete *ev = (void *) skb->data;
__le16 *ptr; struct hci_conn *conn;
int i;
skb_pull(skb, sizeof(*ev));
BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
if (skb->len < ev->num_hndl * 4) { BT_DBG("%s status %d", hdev->name, ev->status);
BT_DBG("%s bad parameters", hdev->name);
return;
}
tasklet_disable(&hdev->tx_task); hci_dev_lock(hdev);
for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) { conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
struct hci_conn *conn; if (conn) {
__u16 handle, count; if (!ev->status)
conn->link_mode |= HCI_LM_AUTH;
handle = __le16_to_cpu(get_unaligned(ptr++)); clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
count = __le16_to_cpu(get_unaligned(ptr++));
conn = hci_conn_hash_lookup_handle(hdev, handle); hci_auth_cfm(conn, ev->status);
if (conn) {
conn->sent -= count;
if (conn->type == ACL_LINK) { if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
if ((hdev->acl_cnt += count) > hdev->acl_pkts) if (!ev->status) {
hdev->acl_cnt = hdev->acl_pkts; struct hci_cp_set_conn_encrypt cp;
cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 1;
hci_send_cmd(conn->hdev,
HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), &cp);
} else { } else {
if ((hdev->sco_cnt += count) > hdev->sco_pkts) clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
hdev->sco_cnt = hdev->sco_pkts; hci_encrypt_cfm(conn, ev->status, 0x00);
} }
} }
} }
hci_sched_tx(hdev);
tasklet_enable(&hdev->tx_task); hci_dev_unlock(hdev);
} }
/* Role Change */ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) {
BT_DBG("%s", hdev->name);
hci_conn_check_pending(hdev);
}
static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data; struct hci_ev_encrypt_change *ev = (void *) skb->data;
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status); BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) { if (conn) {
if (!ev->status) { if (!ev->status) {
if (ev->role) if (ev->encrypt)
conn->link_mode &= ~HCI_LM_MASTER; conn->link_mode |= HCI_LM_ENCRYPT;
else else
conn->link_mode |= HCI_LM_MASTER; conn->link_mode &= ~HCI_LM_ENCRYPT;
} }
clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
hci_role_switch_cfm(conn, ev->status, ev->role); hci_encrypt_cfm(conn, ev->status, ev->encrypt);
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
/* Mode Change */ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) skb->data; struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status); BT_DBG("%s status %d", hdev->name, ev->status);
...@@ -947,87 +858,274 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb ...@@ -947,87 +858,274 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) { if (conn) {
conn->mode = ev->mode; if (!ev->status)
conn->interval = __le16_to_cpu(ev->interval); conn->link_mode |= HCI_LM_SECURE;
if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
if (conn->mode == HCI_CM_ACTIVE)
conn->power_save = 1; hci_key_change_cfm(conn, ev->status);
else
conn->power_save = 0;
}
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
/* Authentication Complete */ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data; struct hci_ev_remote_features *ev = (void *) skb->data;
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status); BT_DBG("%s status %d", hdev->name, ev->status);
if (ev->status)
return;
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) { if (conn)
if (!ev->status) memcpy(conn->features, ev->features, 8);
conn->link_mode |= HCI_LM_AUTH;
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); hci_dev_unlock(hdev);
}
hci_auth_cfm(conn, ev->status); static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
if (!ev->status) { {
struct hci_cp_set_conn_encrypt cp; BT_DBG("%s", hdev->name);
cp.handle = cpu_to_le16(conn->handle); }
cp.encrypt = 1;
hci_send_cmd(conn->hdev, OGF_LINK_CTL, static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp); {
} else { struct hci_ev_cmd_complete *ev = (void *) skb->data;
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); __u16 opcode;
hci_encrypt_cfm(conn, ev->status, 0x00);
skb_pull(skb, sizeof(*ev));
opcode = __le16_to_cpu(ev->opcode);
switch (opcode) {
case HCI_OP_INQUIRY_CANCEL:
hci_cc_inquiry_cancel(hdev, skb);
break;
case HCI_OP_EXIT_PERIODIC_INQ:
hci_cc_exit_periodic_inq(hdev, skb);
break;
case HCI_OP_REMOTE_NAME_REQ_CANCEL:
hci_cc_remote_name_req_cancel(hdev, skb);
break;
case HCI_OP_ROLE_DISCOVERY:
hci_cc_role_discovery(hdev, skb);
break;
case HCI_OP_WRITE_LINK_POLICY:
hci_cc_write_link_policy(hdev, skb);
break;
case HCI_OP_RESET:
hci_cc_reset(hdev, skb);
break;
case HCI_OP_WRITE_LOCAL_NAME:
hci_cc_write_local_name(hdev, skb);
break;
case HCI_OP_READ_LOCAL_NAME:
hci_cc_read_local_name(hdev, skb);
break;
case HCI_OP_WRITE_AUTH_ENABLE:
hci_cc_write_auth_enable(hdev, skb);
break;
case HCI_OP_WRITE_ENCRYPT_MODE:
hci_cc_write_encrypt_mode(hdev, skb);
break;
case HCI_OP_WRITE_SCAN_ENABLE:
hci_cc_write_scan_enable(hdev, skb);
break;
case HCI_OP_READ_CLASS_OF_DEV:
hci_cc_read_class_of_dev(hdev, skb);
break;
case HCI_OP_WRITE_CLASS_OF_DEV:
hci_cc_write_class_of_dev(hdev, skb);
break;
case HCI_OP_READ_VOICE_SETTING:
hci_cc_read_voice_setting(hdev, skb);
break;
case HCI_OP_WRITE_VOICE_SETTING:
hci_cc_write_voice_setting(hdev, skb);
break;
case HCI_OP_HOST_BUFFER_SIZE:
hci_cc_host_buffer_size(hdev, skb);
break;
case HCI_OP_READ_LOCAL_VERSION:
hci_cc_read_local_version(hdev, skb);
break;
case HCI_OP_READ_LOCAL_COMMANDS:
hci_cc_read_local_commands(hdev, skb);
break;
case HCI_OP_READ_LOCAL_FEATURES:
hci_cc_read_local_features(hdev, skb);
break;
case HCI_OP_READ_BUFFER_SIZE:
hci_cc_read_buffer_size(hdev, skb);
break;
case HCI_OP_READ_BD_ADDR:
hci_cc_read_bd_addr(hdev, skb);
break;
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
} }
if (ev->ncmd) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
hci_sched_cmd(hdev);
} }
}
static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_cmd_status *ev = (void *) skb->data;
__u16 opcode;
skb_pull(skb, sizeof(*ev));
opcode = __le16_to_cpu(ev->opcode);
switch (opcode) {
case HCI_OP_INQUIRY:
hci_cs_inquiry(hdev, ev->status);
break;
case HCI_OP_CREATE_CONN:
hci_cs_create_conn(hdev, ev->status);
break;
case HCI_OP_ADD_SCO:
hci_cs_add_sco(hdev, ev->status);
break;
case HCI_OP_REMOTE_NAME_REQ:
hci_cs_remote_name_req(hdev, ev->status);
break;
case HCI_OP_SETUP_SYNC_CONN:
hci_cs_setup_sync_conn(hdev, ev->status);
break;
case HCI_OP_SNIFF_MODE:
hci_cs_sniff_mode(hdev, ev->status);
break;
case HCI_OP_EXIT_SNIFF_MODE:
hci_cs_exit_sniff_mode(hdev, ev->status);
break;
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
} }
hci_dev_unlock(hdev); if (ev->ncmd) {
atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q))
hci_sched_cmd(hdev);
}
} }
/* Encryption Change */ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data; struct hci_ev_role_change *ev = (void *) skb->data;
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status); BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (conn) { if (conn) {
if (!ev->status) { if (!ev->status) {
if (ev->encrypt) if (ev->role)
conn->link_mode |= HCI_LM_ENCRYPT; conn->link_mode &= ~HCI_LM_MASTER;
else else
conn->link_mode &= ~HCI_LM_ENCRYPT; conn->link_mode |= HCI_LM_MASTER;
} }
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); clear_bit(HCI_CONN_RSWITCH_PEND, &conn->pend);
hci_encrypt_cfm(conn, ev->status, ev->encrypt); hci_role_switch_cfm(conn, ev->status, ev->role);
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
/* Change Connection Link Key Complete */ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) {
struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
__le16 *ptr;
int i;
skb_pull(skb, sizeof(*ev));
BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
if (skb->len < ev->num_hndl * 4) {
BT_DBG("%s bad parameters", hdev->name);
return;
}
tasklet_disable(&hdev->tx_task);
for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
struct hci_conn *conn;
__u16 handle, count;
handle = __le16_to_cpu(get_unaligned(ptr++));
count = __le16_to_cpu(get_unaligned(ptr++));
conn = hci_conn_hash_lookup_handle(hdev, handle);
if (conn) {
conn->sent -= count;
if (conn->type == ACL_LINK) {
if ((hdev->acl_cnt += count) > hdev->acl_pkts)
hdev->acl_cnt = hdev->acl_pkts;
} else {
if ((hdev->sco_cnt += count) > hdev->sco_pkts)
hdev->sco_cnt = hdev->sco_pkts;
}
}
}
hci_sched_tx(hdev);
tasklet_enable(&hdev->tx_task);
}
static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data; struct hci_ev_mode_change *ev = (void *) skb->data;
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status); BT_DBG("%s status %d", hdev->name, ev->status);
...@@ -1036,54 +1134,38 @@ static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, s ...@@ -1036,54 +1134,38 @@ static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, s
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn) { if (conn) {
if (!ev->status) conn->mode = ev->mode;
conn->link_mode |= HCI_LM_SECURE; conn->interval = __le16_to_cpu(ev->interval);
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
hci_key_change_cfm(conn, ev->status); if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
if (conn->mode == HCI_CM_ACTIVE)
conn->power_save = 1;
else
conn->power_save = 0;
}
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
/* Pin Code Request*/
static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
BT_DBG("%s", hdev->name);
} }
/* Link Key Request */
static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
BT_DBG("%s", hdev->name);
} }
/* Link Key Notification */
static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
BT_DBG("%s", hdev->name);
} }
/* Remote Features */
static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_remote_features *ev = (struct hci_ev_remote_features *) skb->data;
struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status);
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
if (conn && !ev->status) {
memcpy(conn->features, ev->features, sizeof(conn->features));
}
hci_dev_unlock(hdev);
}
/* Clock Offset */
static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data; struct hci_ev_clock_offset *ev = (void *) skb->data;
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status); BT_DBG("%s status %d", hdev->name, ev->status);
...@@ -1103,10 +1185,9 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk ...@@ -1103,10 +1185,9 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
/* Page Scan Repetition Mode */
static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_pscan_rep_mode *ev = (struct hci_ev_pscan_rep_mode *) skb->data; struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
struct inquiry_entry *ie; struct inquiry_entry *ie;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
...@@ -1121,10 +1202,69 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff * ...@@ -1121,10 +1202,69 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
/* Sniff Subrate */ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct inquiry_data data;
int num_rsp = *((__u8 *) skb->data);
BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
if (!num_rsp)
return;
hci_dev_lock(hdev);
if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
struct inquiry_info_with_rssi_and_pscan_mode *info = (void *) (skb->data + 1);
for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode;
data.pscan_mode = info->pscan_mode;
memcpy(data.dev_class, info->dev_class, 3);
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
info++;
hci_inquiry_cache_update(hdev, &data);
}
} else {
struct inquiry_info_with_rssi *info = (void *) (skb->data + 1);
for (; num_rsp; num_rsp--) {
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode;
data.pscan_mode = 0x00;
memcpy(data.dev_class, info->dev_class, 3);
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
info++;
hci_inquiry_cache_update(hdev, &data);
}
}
hci_dev_unlock(hdev);
}
static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_sniff_subrate *ev = (struct hci_ev_sniff_subrate *) skb->data; struct hci_ev_sniff_subrate *ev = (void *) skb->data;
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s status %d", hdev->name, ev->status); BT_DBG("%s status %d", hdev->name, ev->status);
...@@ -1138,22 +1278,42 @@ static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -1138,22 +1278,42 @@ static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *s
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data; struct inquiry_data data;
struct hci_ev_cmd_complete *ec; struct extended_inquiry_info *info = (void *) (skb->data + 1);
struct hci_ev_cmd_status *cs; int num_rsp = *((__u8 *) skb->data);
u16 opcode, ocf, ogf;
skb_pull(skb, HCI_EVENT_HDR_SIZE); BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
BT_DBG("%s evt 0x%x", hdev->name, hdr->evt); if (!num_rsp)
return;
switch (hdr->evt) { hci_dev_lock(hdev);
case HCI_EV_NUM_COMP_PKTS:
hci_num_comp_pkts_evt(hdev, skb); for (; num_rsp; num_rsp--) {
break; bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
data.pscan_period_mode = info->pscan_period_mode;
data.pscan_mode = 0x00;
memcpy(data.dev_class, info->dev_class, 3);
data.clock_offset = info->clock_offset;
data.rssi = info->rssi;
info++;
hci_inquiry_cache_update(hdev, &data);
}
hci_dev_unlock(hdev);
}
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_event_hdr *hdr = (void *) skb->data;
__u8 event = hdr->evt;
skb_pull(skb, HCI_EVENT_HDR_SIZE);
switch (event) {
case HCI_EV_INQUIRY_COMPLETE: case HCI_EV_INQUIRY_COMPLETE:
hci_inquiry_complete_evt(hdev, skb); hci_inquiry_complete_evt(hdev, skb);
break; break;
...@@ -1162,146 +1322,112 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1162,146 +1322,112 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_inquiry_result_evt(hdev, skb); hci_inquiry_result_evt(hdev, skb);
break; break;
case HCI_EV_INQUIRY_RESULT_WITH_RSSI: case HCI_EV_CONN_COMPLETE:
hci_inquiry_result_with_rssi_evt(hdev, skb); hci_conn_complete_evt(hdev, skb);
break;
case HCI_EV_EXTENDED_INQUIRY_RESULT:
hci_extended_inquiry_result_evt(hdev, skb);
break; break;
case HCI_EV_CONN_REQUEST: case HCI_EV_CONN_REQUEST:
hci_conn_request_evt(hdev, skb); hci_conn_request_evt(hdev, skb);
break; break;
case HCI_EV_CONN_COMPLETE:
hci_conn_complete_evt(hdev, skb);
break;
case HCI_EV_DISCONN_COMPLETE: case HCI_EV_DISCONN_COMPLETE:
hci_disconn_complete_evt(hdev, skb); hci_disconn_complete_evt(hdev, skb);
break; break;
case HCI_EV_ROLE_CHANGE:
hci_role_change_evt(hdev, skb);
break;
case HCI_EV_MODE_CHANGE:
hci_mode_change_evt(hdev, skb);
break;
case HCI_EV_AUTH_COMPLETE: case HCI_EV_AUTH_COMPLETE:
hci_auth_complete_evt(hdev, skb); hci_auth_complete_evt(hdev, skb);
break; break;
case HCI_EV_ENCRYPT_CHANGE: case HCI_EV_REMOTE_NAME:
hci_encrypt_change_evt(hdev, skb); hci_remote_name_evt(hdev, skb);
break;
case HCI_EV_CHANGE_CONN_LINK_KEY_COMPLETE:
hci_change_conn_link_key_complete_evt(hdev, skb);
break;
case HCI_EV_PIN_CODE_REQ:
hci_pin_code_request_evt(hdev, skb);
break; break;
case HCI_EV_LINK_KEY_REQ: case HCI_EV_ENCRYPT_CHANGE:
hci_link_key_request_evt(hdev, skb); hci_encrypt_change_evt(hdev, skb);
break; break;
case HCI_EV_LINK_KEY_NOTIFY: case HCI_EV_CHANGE_LINK_KEY_COMPLETE:
hci_link_key_notify_evt(hdev, skb); hci_change_link_key_complete_evt(hdev, skb);
break; break;
case HCI_EV_REMOTE_FEATURES: case HCI_EV_REMOTE_FEATURES:
hci_remote_features_evt(hdev, skb); hci_remote_features_evt(hdev, skb);
break; break;
case HCI_EV_CLOCK_OFFSET: case HCI_EV_REMOTE_VERSION:
hci_clock_offset_evt(hdev, skb); hci_remote_version_evt(hdev, skb);
break; break;
case HCI_EV_PSCAN_REP_MODE: case HCI_EV_QOS_SETUP_COMPLETE:
hci_pscan_rep_mode_evt(hdev, skb); hci_qos_setup_complete_evt(hdev, skb);
break; break;
case HCI_EV_SNIFF_SUBRATE: case HCI_EV_CMD_COMPLETE:
hci_sniff_subrate_evt(hdev, skb); hci_cmd_complete_evt(hdev, skb);
break; break;
case HCI_EV_CMD_STATUS: case HCI_EV_CMD_STATUS:
cs = (struct hci_ev_cmd_status *) skb->data; hci_cmd_status_evt(hdev, skb);
skb_pull(skb, sizeof(cs)); break;
opcode = __le16_to_cpu(cs->opcode); case HCI_EV_ROLE_CHANGE:
ogf = hci_opcode_ogf(opcode); hci_role_change_evt(hdev, skb);
ocf = hci_opcode_ocf(opcode); break;
switch (ogf) { case HCI_EV_NUM_COMP_PKTS:
case OGF_INFO_PARAM: hci_num_comp_pkts_evt(hdev, skb);
hci_cs_info_param(hdev, ocf, cs->status);
break; break;
case OGF_HOST_CTL: case HCI_EV_MODE_CHANGE:
hci_cs_host_ctl(hdev, ocf, cs->status); hci_mode_change_evt(hdev, skb);
break; break;
case OGF_LINK_CTL: case HCI_EV_PIN_CODE_REQ:
hci_cs_link_ctl(hdev, ocf, cs->status); hci_pin_code_request_evt(hdev, skb);
break; break;
case OGF_LINK_POLICY: case HCI_EV_LINK_KEY_REQ:
hci_cs_link_policy(hdev, ocf, cs->status); hci_link_key_request_evt(hdev, skb);
break; break;
default: case HCI_EV_LINK_KEY_NOTIFY:
BT_DBG("%s Command Status OGF %x", hdev->name, ogf); hci_link_key_notify_evt(hdev, skb);
break; break;
}
if (cs->ncmd) { case HCI_EV_CLOCK_OFFSET:
atomic_set(&hdev->cmd_cnt, 1); hci_clock_offset_evt(hdev, skb);
if (!skb_queue_empty(&hdev->cmd_q))
hci_sched_cmd(hdev);
}
break; break;
case HCI_EV_CMD_COMPLETE: case HCI_EV_PSCAN_REP_MODE:
ec = (struct hci_ev_cmd_complete *) skb->data; hci_pscan_rep_mode_evt(hdev, skb);
skb_pull(skb, sizeof(*ec)); break;
opcode = __le16_to_cpu(ec->opcode); case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
ogf = hci_opcode_ogf(opcode); hci_inquiry_result_with_rssi_evt(hdev, skb);
ocf = hci_opcode_ocf(opcode); break;
switch (ogf) { case HCI_EV_REMOTE_EXT_FEATURES:
case OGF_INFO_PARAM: hci_remote_ext_features_evt(hdev, skb);
hci_cc_info_param(hdev, ocf, skb);
break; break;
case OGF_HOST_CTL: case HCI_EV_SYNC_CONN_COMPLETE:
hci_cc_host_ctl(hdev, ocf, skb); hci_sync_conn_complete_evt(hdev, skb);
break; break;
case OGF_LINK_CTL: case HCI_EV_SYNC_CONN_CHANGED:
hci_cc_link_ctl(hdev, ocf, skb); hci_sync_conn_changed_evt(hdev, skb);
break; break;
case OGF_LINK_POLICY: case HCI_EV_SNIFF_SUBRATE:
hci_cc_link_policy(hdev, ocf, skb); hci_sniff_subrate_evt(hdev, skb);
break; break;
default: case HCI_EV_EXTENDED_INQUIRY_RESULT:
BT_DBG("%s Command Completed OGF %x", hdev->name, ogf); hci_extended_inquiry_result_evt(hdev, skb);
break; break;
}
if (ec->ncmd) { default:
atomic_set(&hdev->cmd_cnt, 1); BT_DBG("%s event 0x%x", hdev->name, event);
if (!skb_queue_empty(&hdev->cmd_q))
hci_sched_cmd(hdev);
}
break; break;
} }
......
...@@ -451,7 +451,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -451,7 +451,7 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
goto drop; goto drop;
} }
if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) { if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
skb_queue_tail(&hdev->raw_q, skb); skb_queue_tail(&hdev->raw_q, skb);
hci_sched_tx(hdev); hci_sched_tx(hdev);
} else { } else {
......
...@@ -41,6 +41,26 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char ...@@ -41,6 +41,26 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char
return sprintf(buf, "%s\n", typetostr(hdev->type)); return sprintf(buf, "%s\n", typetostr(hdev->type));
} }
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
char name[249];
int i;
for (i = 0; i < 248; i++)
name[i] = hdev->dev_name[i];
name[248] = '\0';
return sprintf(buf, "%s\n", name);
}
static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
return sprintf(buf, "0x%.2x%.2x%.2x\n",
hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
}
static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct hci_dev *hdev = dev_get_drvdata(dev); struct hci_dev *hdev = dev_get_drvdata(dev);
...@@ -49,6 +69,17 @@ static ssize_t show_address(struct device *dev, struct device_attribute *attr, c ...@@ -49,6 +69,17 @@ static ssize_t show_address(struct device *dev, struct device_attribute *attr, c
return sprintf(buf, "%s\n", batostr(&bdaddr)); return sprintf(buf, "%s\n", batostr(&bdaddr));
} }
static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
hdev->features[0], hdev->features[1],
hdev->features[2], hdev->features[3],
hdev->features[4], hdev->features[5],
hdev->features[6], hdev->features[7]);
}
static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct hci_dev *hdev = dev_get_drvdata(dev); struct hci_dev *hdev = dev_get_drvdata(dev);
...@@ -170,7 +201,10 @@ static ssize_t store_sniff_min_interval(struct device *dev, struct device_attrib ...@@ -170,7 +201,10 @@ static ssize_t store_sniff_min_interval(struct device *dev, struct device_attrib
} }
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static DEVICE_ATTR(class, S_IRUGO, show_class, NULL);
static DEVICE_ATTR(address, S_IRUGO, show_address, NULL); static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
static DEVICE_ATTR(features, S_IRUGO, show_features, NULL);
static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL); static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL); static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL); static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
...@@ -185,7 +219,10 @@ static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR, ...@@ -185,7 +219,10 @@ static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
static struct device_attribute *bt_attrs[] = { static struct device_attribute *bt_attrs[] = {
&dev_attr_type, &dev_attr_type,
&dev_attr_name,
&dev_attr_class,
&dev_attr_address, &dev_attr_address,
&dev_attr_features,
&dev_attr_manufacturer, &dev_attr_manufacturer,
&dev_attr_hci_version, &dev_attr_hci_version,
&dev_attr_hci_revision, &dev_attr_hci_revision,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment