Commit 48b81cc1 authored by John W. Linville's avatar John W. Linville

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
parents 31c5770b 0227c7b5
...@@ -83,8 +83,8 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { ...@@ -83,8 +83,8 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
}; };
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
.helper = "sd8688_helper.bin", .helper = "mrvl/sd8688_helper.bin",
.firmware = "sd8688.bin", .firmware = "mrvl/sd8688.bin",
.reg = &btmrvl_reg_8688, .reg = &btmrvl_reg_8688,
.sd_blksz_fw_dl = 64, .sd_blksz_fw_dl = 64,
}; };
...@@ -1185,7 +1185,7 @@ MODULE_AUTHOR("Marvell International Ltd."); ...@@ -1185,7 +1185,7 @@ MODULE_AUTHOR("Marvell International Ltd.");
MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION); MODULE_DESCRIPTION("Marvell BT-over-SDIO driver ver " VERSION);
MODULE_VERSION(VERSION); MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE("sd8688_helper.bin"); MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
MODULE_FIRMWARE("sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8688.bin");
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
...@@ -232,7 +232,7 @@ struct bt_sock_list { ...@@ -232,7 +232,7 @@ struct bt_sock_list {
}; };
int bt_sock_register(int proto, const struct net_proto_family *ops); int bt_sock_register(int proto, const struct net_proto_family *ops);
int bt_sock_unregister(int proto); void bt_sock_unregister(int proto);
void bt_sock_link(struct bt_sock_list *l, struct sock *s); void bt_sock_link(struct bt_sock_list *l, struct sock *s);
void bt_sock_unlink(struct bt_sock_list *l, struct sock *s); void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
...@@ -260,12 +260,22 @@ struct l2cap_ctrl { ...@@ -260,12 +260,22 @@ struct l2cap_ctrl {
__u8 retries; __u8 retries;
}; };
struct hci_dev;
typedef void (*hci_req_complete_t)(struct hci_dev *hdev, u8 status);
struct hci_req_ctrl {
bool start;
hci_req_complete_t complete;
};
struct bt_skb_cb { struct bt_skb_cb {
__u8 pkt_type; __u8 pkt_type;
__u8 incoming; __u8 incoming;
__u16 expect; __u16 expect;
__u8 force_active; __u8 force_active;
struct l2cap_ctrl control; struct l2cap_ctrl control;
struct hci_req_ctrl req;
}; };
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
......
...@@ -119,10 +119,16 @@ enum { ...@@ -119,10 +119,16 @@ enum {
HCI_CONNECTABLE, HCI_CONNECTABLE,
HCI_DISCOVERABLE, HCI_DISCOVERABLE,
HCI_LINK_SECURITY, HCI_LINK_SECURITY,
HCI_PENDING_CLASS,
HCI_PERIODIC_INQ, HCI_PERIODIC_INQ,
HCI_FAST_CONNECTABLE,
}; };
/* A mask for the flags that are supposed to remain when a reset happens
* or the HCI device is closed.
*/
#define HCI_PERSISTENT_MASK (BIT(HCI_LE_SCAN) | BIT(HCI_PERIODIC_INQ) | \
BIT(HCI_FAST_CONNECTABLE))
/* HCI ioctl defines */ /* HCI ioctl defines */
#define HCIDEVUP _IOW('H', 201, int) #define HCIDEVUP _IOW('H', 201, int)
#define HCIDEVDOWN _IOW('H', 202, int) #define HCIDEVDOWN _IOW('H', 202, int)
...@@ -881,12 +887,25 @@ struct hci_rp_read_data_block_size { ...@@ -881,12 +887,25 @@ struct hci_rp_read_data_block_size {
__le16 num_blocks; __le16 num_blocks;
} __packed; } __packed;
#define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
struct hci_rp_read_page_scan_activity {
__u8 status;
__le16 interval;
__le16 window;
} __packed;
#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c #define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY 0x0c1c
struct hci_cp_write_page_scan_activity { struct hci_cp_write_page_scan_activity {
__le16 interval; __le16 interval;
__le16 window; __le16 window;
} __packed; } __packed;
#define HCI_OP_READ_PAGE_SCAN_TYPE 0x0c46
struct hci_rp_read_page_scan_type {
__u8 status;
__u8 type;
} __packed;
#define HCI_OP_WRITE_PAGE_SCAN_TYPE 0x0c47 #define HCI_OP_WRITE_PAGE_SCAN_TYPE 0x0c47
#define PAGE_SCAN_TYPE_STANDARD 0x00 #define PAGE_SCAN_TYPE_STANDARD 0x00
#define PAGE_SCAN_TYPE_INTERLACED 0x01 #define PAGE_SCAN_TYPE_INTERLACED 0x01
......
...@@ -165,6 +165,10 @@ struct hci_dev { ...@@ -165,6 +165,10 @@ struct hci_dev {
__u16 voice_setting; __u16 voice_setting;
__u8 io_capability; __u8 io_capability;
__s8 inq_tx_power; __s8 inq_tx_power;
__u16 page_scan_interval;
__u16 page_scan_window;
__u8 page_scan_type;
__u16 devid_source; __u16 devid_source;
__u16 devid_vendor; __u16 devid_vendor;
__u16 devid_product; __u16 devid_product;
...@@ -248,8 +252,6 @@ struct hci_dev { ...@@ -248,8 +252,6 @@ struct hci_dev {
__u32 req_status; __u32 req_status;
__u32 req_result; __u32 req_result;
__u16 init_last_cmd;
struct list_head mgmt_pending; struct list_head mgmt_pending;
struct discovery_state discovery; struct discovery_state discovery;
...@@ -574,7 +576,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev, ...@@ -574,7 +576,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
return NULL; return NULL;
} }
void hci_acl_disconn(struct hci_conn *conn, __u8 reason); void hci_disconnect(struct hci_conn *conn, __u8 reason);
void hci_setup_sync(struct hci_conn *conn, __u16 handle); void hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status); void hci_sco_setup(struct hci_conn *conn, __u8 status);
...@@ -742,8 +744,6 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, ...@@ -742,8 +744,6 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer); u8 *randomizer);
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
int hci_update_ad(struct hci_dev *hdev);
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct sk_buff *skb); int hci_recv_frame(struct sk_buff *skb);
...@@ -1041,6 +1041,22 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, ...@@ -1041,6 +1041,22 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
int hci_register_cb(struct hci_cb *hcb); int hci_register_cb(struct hci_cb *hcb);
int hci_unregister_cb(struct hci_cb *hcb); int hci_unregister_cb(struct hci_cb *hcb);
struct hci_request {
struct hci_dev *hdev;
struct sk_buff_head cmd_q;
/* If something goes wrong when building the HCI request, the error
* value is stored in this field.
*/
int err;
};
void hci_req_init(struct hci_request *req, struct hci_dev *hdev);
int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param);
void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status);
void hci_req_cmd_status(struct hci_dev *hdev, u16 opcode, u8 status);
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param); int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags); void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
...@@ -1153,7 +1169,7 @@ struct hci_sec_filter { ...@@ -1153,7 +1169,7 @@ struct hci_sec_filter {
#define hci_req_lock(d) mutex_lock(&d->req_lock) #define hci_req_lock(d) mutex_lock(&d->req_lock)
#define hci_req_unlock(d) mutex_unlock(&d->req_lock) #define hci_req_unlock(d) mutex_unlock(&d->req_lock)
void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result); void hci_update_ad(struct hci_request *req);
void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier); u16 latency, u16 to_multiplier);
......
...@@ -158,7 +158,6 @@ struct rfcomm_session { ...@@ -158,7 +158,6 @@ struct rfcomm_session {
struct timer_list timer; struct timer_list timer;
unsigned long state; unsigned long state;
unsigned long flags; unsigned long flags;
atomic_t refcnt;
int initiator; int initiator;
/* Default DLC parameters */ /* Default DLC parameters */
...@@ -276,11 +275,6 @@ static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) ...@@ -276,11 +275,6 @@ static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src,
bdaddr_t *dst); bdaddr_t *dst);
static inline void rfcomm_session_hold(struct rfcomm_session *s)
{
atomic_inc(&s->refcnt);
}
/* ---- RFCOMM sockets ---- */ /* ---- RFCOMM sockets ---- */
struct sockaddr_rc { struct sockaddr_rc {
sa_family_t rc_family; sa_family_t rc_family;
......
...@@ -397,13 +397,12 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb, ...@@ -397,13 +397,12 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
if (ctrl) { if (ctrl) {
u8 *assoc; u8 *assoc;
assoc = kzalloc(assoc_len, GFP_KERNEL); assoc = kmemdup(rsp->amp_assoc, assoc_len, GFP_KERNEL);
if (!assoc) { if (!assoc) {
amp_ctrl_put(ctrl); amp_ctrl_put(ctrl);
return -ENOMEM; return -ENOMEM;
} }
memcpy(assoc, rsp->amp_assoc, assoc_len);
ctrl->assoc = assoc; ctrl->assoc = assoc;
ctrl->assoc_len = assoc_len; ctrl->assoc_len = assoc_len;
ctrl->assoc_rem_len = assoc_len; ctrl->assoc_rem_len = assoc_len;
...@@ -472,13 +471,12 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, ...@@ -472,13 +471,12 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req); size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req);
u8 *assoc; u8 *assoc;
assoc = kzalloc(assoc_len, GFP_KERNEL); assoc = kmemdup(req->amp_assoc, assoc_len, GFP_KERNEL);
if (!assoc) { if (!assoc) {
amp_ctrl_put(ctrl); amp_ctrl_put(ctrl);
return -ENOMEM; return -ENOMEM;
} }
memcpy(assoc, req->amp_assoc, assoc_len);
ctrl->assoc = assoc; ctrl->assoc = assoc;
ctrl->assoc_len = assoc_len; ctrl->assoc_len = assoc_len;
ctrl->assoc_rem_len = assoc_len; ctrl->assoc_rem_len = assoc_len;
......
...@@ -92,23 +92,14 @@ int bt_sock_register(int proto, const struct net_proto_family *ops) ...@@ -92,23 +92,14 @@ int bt_sock_register(int proto, const struct net_proto_family *ops)
} }
EXPORT_SYMBOL(bt_sock_register); EXPORT_SYMBOL(bt_sock_register);
int bt_sock_unregister(int proto) void bt_sock_unregister(int proto)
{ {
int err = 0;
if (proto < 0 || proto >= BT_MAX_PROTO) if (proto < 0 || proto >= BT_MAX_PROTO)
return -EINVAL; return;
write_lock(&bt_proto_lock); write_lock(&bt_proto_lock);
if (!bt_proto[proto])
err = -ENOENT;
else
bt_proto[proto] = NULL; bt_proto[proto] = NULL;
write_unlock(&bt_proto_lock); write_unlock(&bt_proto_lock);
return err;
} }
EXPORT_SYMBOL(bt_sock_unregister); EXPORT_SYMBOL(bt_sock_unregister);
......
...@@ -253,8 +253,6 @@ int __init bnep_sock_init(void) ...@@ -253,8 +253,6 @@ int __init bnep_sock_init(void)
void __exit bnep_sock_cleanup(void) void __exit bnep_sock_cleanup(void)
{ {
bt_procfs_cleanup(&init_net, "bnep"); bt_procfs_cleanup(&init_net, "bnep");
if (bt_sock_unregister(BTPROTO_BNEP) < 0) bt_sock_unregister(BTPROTO_BNEP);
BT_ERR("Can't unregister BNEP socket");
proto_unregister(&bnep_proto); proto_unregister(&bnep_proto);
} }
...@@ -264,8 +264,6 @@ int cmtp_init_sockets(void) ...@@ -264,8 +264,6 @@ int cmtp_init_sockets(void)
void cmtp_cleanup_sockets(void) void cmtp_cleanup_sockets(void)
{ {
bt_procfs_cleanup(&init_net, "cmtp"); bt_procfs_cleanup(&init_net, "cmtp");
if (bt_sock_unregister(BTPROTO_CMTP) < 0) bt_sock_unregister(BTPROTO_CMTP);
BT_ERR("Can't unregister CMTP socket");
proto_unregister(&cmtp_proto); proto_unregister(&cmtp_proto);
} }
...@@ -117,7 +117,7 @@ static void hci_acl_create_connection_cancel(struct hci_conn *conn) ...@@ -117,7 +117,7 @@ static void hci_acl_create_connection_cancel(struct hci_conn *conn)
hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp); hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
} }
void hci_acl_disconn(struct hci_conn *conn, __u8 reason) void hci_disconnect(struct hci_conn *conn, __u8 reason)
{ {
struct hci_cp_disconnect cp; struct hci_cp_disconnect cp;
...@@ -253,7 +253,7 @@ static void hci_conn_disconnect(struct hci_conn *conn) ...@@ -253,7 +253,7 @@ static void hci_conn_disconnect(struct hci_conn *conn)
hci_amp_disconn(conn, reason); hci_amp_disconn(conn, reason);
break; break;
default: default:
hci_acl_disconn(conn, reason); hci_disconnect(conn, reason);
break; break;
} }
} }
......
...@@ -57,36 +57,9 @@ static void hci_notify(struct hci_dev *hdev, int event) ...@@ -57,36 +57,9 @@ static void hci_notify(struct hci_dev *hdev, int event)
/* ---- HCI requests ---- */ /* ---- HCI requests ---- */
void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
{ {
BT_DBG("%s command 0x%4.4x result 0x%2.2x", hdev->name, cmd, result); BT_DBG("%s result 0x%2.2x", hdev->name, result);
/* If this is the init phase check if the completed command matches
* the last init command, and if not just return.
*/
if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) {
struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
u16 opcode = __le16_to_cpu(sent->opcode);
struct sk_buff *skb;
/* Some CSR based controllers generate a spontaneous
* reset complete event during init and any pending
* command will never be completed. In such a case we
* need to resend whatever was the last sent
* command.
*/
if (cmd != HCI_OP_RESET || opcode == HCI_OP_RESET)
return;
skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC);
if (skb) {
skb_queue_head(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
}
return;
}
if (hdev->req_status == HCI_REQ_PEND) { if (hdev->req_status == HCI_REQ_PEND) {
hdev->req_result = result; hdev->req_result = result;
...@@ -107,21 +80,41 @@ static void hci_req_cancel(struct hci_dev *hdev, int err) ...@@ -107,21 +80,41 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
} }
/* Execute request and wait for completion. */ /* Execute request and wait for completion. */
static int __hci_request(struct hci_dev *hdev, static int __hci_req_sync(struct hci_dev *hdev,
void (*req)(struct hci_dev *hdev, unsigned long opt), void (*func)(struct hci_request *req,
unsigned long opt),
unsigned long opt, __u32 timeout) unsigned long opt, __u32 timeout)
{ {
struct hci_request req;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int err = 0; int err = 0;
BT_DBG("%s start", hdev->name); BT_DBG("%s start", hdev->name);
hci_req_init(&req, hdev);
hdev->req_status = HCI_REQ_PEND; hdev->req_status = HCI_REQ_PEND;
func(&req, opt);
err = hci_req_run(&req, hci_req_sync_complete);
if (err < 0) {
hdev->req_status = 0;
/* ENODATA means the HCI request command queue is empty.
* This can happen when a request with conditionals doesn't
* trigger any commands to be sent. This is normal behavior
* and should not trigger an error return.
*/
if (err == -ENODATA)
return 0;
return err;
}
add_wait_queue(&hdev->req_wait_q, &wait); add_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
req(hdev, opt);
schedule_timeout(timeout); schedule_timeout(timeout);
remove_wait_queue(&hdev->req_wait_q, &wait); remove_wait_queue(&hdev->req_wait_q, &wait);
...@@ -150,8 +143,9 @@ static int __hci_request(struct hci_dev *hdev, ...@@ -150,8 +143,9 @@ static int __hci_request(struct hci_dev *hdev,
return err; return err;
} }
static int hci_request(struct hci_dev *hdev, static int hci_req_sync(struct hci_dev *hdev,
void (*req)(struct hci_dev *hdev, unsigned long opt), void (*req)(struct hci_request *req,
unsigned long opt),
unsigned long opt, __u32 timeout) unsigned long opt, __u32 timeout)
{ {
int ret; int ret;
...@@ -161,75 +155,86 @@ static int hci_request(struct hci_dev *hdev, ...@@ -161,75 +155,86 @@ static int hci_request(struct hci_dev *hdev,
/* Serialize all requests */ /* Serialize all requests */
hci_req_lock(hdev); hci_req_lock(hdev);
ret = __hci_request(hdev, req, opt, timeout); ret = __hci_req_sync(hdev, req, opt, timeout);
hci_req_unlock(hdev); hci_req_unlock(hdev);
return ret; return ret;
} }
static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) static void hci_reset_req(struct hci_request *req, unsigned long opt)
{ {
BT_DBG("%s %ld", hdev->name, opt); BT_DBG("%s %ld", req->hdev->name, opt);
/* Reset device */ /* Reset device */
set_bit(HCI_RESET, &hdev->flags); set_bit(HCI_RESET, &req->hdev->flags);
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); hci_req_add(req, HCI_OP_RESET, 0, NULL);
} }
static void bredr_init(struct hci_dev *hdev) static void bredr_init(struct hci_request *req)
{ {
hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED; req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
/* Read Local Supported Features */ /* Read Local Supported Features */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); hci_req_add(req, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
/* Read Local Version */ /* Read Local Version */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL); hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
/* Read BD Address */
hci_req_add(req, HCI_OP_READ_BD_ADDR, 0, NULL);
} }
static void amp_init(struct hci_dev *hdev) static void amp_init(struct hci_request *req)
{ {
hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED; req->hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED;
/* Read Local Version */ /* Read Local Version */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL); hci_req_add(req, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
/* Read Local AMP Info */ /* Read Local AMP Info */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); hci_req_add(req, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
/* Read Data Blk size */ /* Read Data Blk size */
hci_send_cmd(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL); hci_req_add(req, HCI_OP_READ_DATA_BLOCK_SIZE, 0, NULL);
} }
static void hci_init_req(struct hci_dev *hdev, unsigned long opt) static void hci_init1_req(struct hci_request *req, unsigned long opt)
{ {
struct hci_dev *hdev = req->hdev;
struct hci_request init_req;
struct sk_buff *skb; struct sk_buff *skb;
BT_DBG("%s %ld", hdev->name, opt); BT_DBG("%s %ld", hdev->name, opt);
/* Driver initialization */ /* Driver initialization */
hci_req_init(&init_req, hdev);
/* Special commands */ /* Special commands */
while ((skb = skb_dequeue(&hdev->driver_init))) { while ((skb = skb_dequeue(&hdev->driver_init))) {
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev; skb->dev = (void *) hdev;
skb_queue_tail(&hdev->cmd_q, skb); if (skb_queue_empty(&init_req.cmd_q))
queue_work(hdev->workqueue, &hdev->cmd_work); bt_cb(skb)->req.start = true;
skb_queue_tail(&init_req.cmd_q, skb);
} }
skb_queue_purge(&hdev->driver_init); skb_queue_purge(&hdev->driver_init);
hci_req_run(&init_req, NULL);
/* Reset */ /* Reset */
if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks))
hci_reset_req(hdev, 0); hci_reset_req(req, 0);
switch (hdev->dev_type) { switch (hdev->dev_type) {
case HCI_BREDR: case HCI_BREDR:
bredr_init(hdev); bredr_init(req);
break; break;
case HCI_AMP: case HCI_AMP:
amp_init(hdev); amp_init(req);
break; break;
default: default:
...@@ -238,44 +243,327 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) ...@@ -238,44 +243,327 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
} }
} }
static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) static void bredr_setup(struct hci_request *req)
{
struct hci_cp_delete_stored_link_key cp;
__le16 param;
__u8 flt_type;
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
hci_req_add(req, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
/* Read Class of Device */
hci_req_add(req, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
/* Read Local Name */
hci_req_add(req, HCI_OP_READ_LOCAL_NAME, 0, NULL);
/* Read Voice Setting */
hci_req_add(req, HCI_OP_READ_VOICE_SETTING, 0, NULL);
/* Clear Event Filters */
flt_type = HCI_FLT_CLEAR_ALL;
hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
/* Connection accept timeout ~20 secs */
param = __constant_cpu_to_le16(0x7d00);
hci_req_add(req, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
bacpy(&cp.bdaddr, BDADDR_ANY);
cp.delete_all = 0x01;
hci_req_add(req, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
/* Read page scan parameters */
if (req->hdev->hci_ver > BLUETOOTH_VER_1_1) {
hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL);
hci_req_add(req, HCI_OP_READ_PAGE_SCAN_TYPE, 0, NULL);
}
}
static void le_setup(struct hci_request *req)
{
/* Read LE Buffer Size */
hci_req_add(req, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
/* Read LE Local Supported Features */
hci_req_add(req, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
/* Read LE Advertising Channel TX Power */
hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
/* Read LE White List Size */
hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
/* Read LE Supported States */
hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
}
static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
{
if (lmp_ext_inq_capable(hdev))
return 0x02;
if (lmp_inq_rssi_capable(hdev))
return 0x01;
if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
hdev->lmp_subver == 0x0757)
return 0x01;
if (hdev->manufacturer == 15) {
if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
return 0x01;
if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
return 0x01;
if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
return 0x01;
}
if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
hdev->lmp_subver == 0x1805)
return 0x01;
return 0x00;
}
static void hci_setup_inquiry_mode(struct hci_request *req)
{
u8 mode;
mode = hci_get_inquiry_mode(req->hdev);
hci_req_add(req, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
}
static void hci_setup_event_mask(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
/* The second byte is 0xff instead of 0x9f (two reserved bits
* disabled) since a Broadcom 1.2 dongle doesn't respond to the
* command otherwise.
*/
u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
/* CSR 1.1 dongles does not accept any bitfield so don't try to set
* any event mask for pre 1.2 devices.
*/
if (hdev->hci_ver < BLUETOOTH_VER_1_2)
return;
if (lmp_bredr_capable(hdev)) {
events[4] |= 0x01; /* Flow Specification Complete */
events[4] |= 0x02; /* Inquiry Result with RSSI */
events[4] |= 0x04; /* Read Remote Extended Features Complete */
events[5] |= 0x08; /* Synchronous Connection Complete */
events[5] |= 0x10; /* Synchronous Connection Changed */
}
if (lmp_inq_rssi_capable(hdev))
events[4] |= 0x02; /* Inquiry Result with RSSI */
if (lmp_sniffsubr_capable(hdev))
events[5] |= 0x20; /* Sniff Subrating */
if (lmp_pause_enc_capable(hdev))
events[5] |= 0x80; /* Encryption Key Refresh Complete */
if (lmp_ext_inq_capable(hdev))
events[5] |= 0x40; /* Extended Inquiry Result */
if (lmp_no_flush_capable(hdev))
events[7] |= 0x01; /* Enhanced Flush Complete */
if (lmp_lsto_capable(hdev))
events[6] |= 0x80; /* Link Supervision Timeout Changed */
if (lmp_ssp_capable(hdev)) {
events[6] |= 0x01; /* IO Capability Request */
events[6] |= 0x02; /* IO Capability Response */
events[6] |= 0x04; /* User Confirmation Request */
events[6] |= 0x08; /* User Passkey Request */
events[6] |= 0x10; /* Remote OOB Data Request */
events[6] |= 0x20; /* Simple Pairing Complete */
events[7] |= 0x04; /* User Passkey Notification */
events[7] |= 0x08; /* Keypress Notification */
events[7] |= 0x10; /* Remote Host Supported
* Features Notification
*/
}
if (lmp_le_capable(hdev))
events[7] |= 0x20; /* LE Meta-Event */
hci_req_add(req, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
if (lmp_le_capable(hdev)) {
memset(events, 0, sizeof(events));
events[0] = 0x1f;
hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK,
sizeof(events), events);
}
}
static void hci_init2_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
if (lmp_bredr_capable(hdev))
bredr_setup(req);
if (lmp_le_capable(hdev))
le_setup(req);
hci_setup_event_mask(req);
if (hdev->hci_ver > BLUETOOTH_VER_1_1)
hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
if (lmp_ssp_capable(hdev)) {
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
u8 mode = 0x01;
hci_req_add(req, HCI_OP_WRITE_SSP_MODE,
sizeof(mode), &mode);
} else {
struct hci_cp_write_eir cp;
memset(hdev->eir, 0, sizeof(hdev->eir));
memset(&cp, 0, sizeof(cp));
hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
}
}
if (lmp_inq_rssi_capable(hdev))
hci_setup_inquiry_mode(req);
if (lmp_inq_tx_pwr_capable(hdev))
hci_req_add(req, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
if (lmp_ext_feat_capable(hdev)) {
struct hci_cp_read_local_ext_features cp;
cp.page = 0x01;
hci_req_add(req, HCI_OP_READ_LOCAL_EXT_FEATURES,
sizeof(cp), &cp);
}
if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
u8 enable = 1;
hci_req_add(req, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
&enable);
}
}
static void hci_setup_link_policy(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_write_def_link_policy cp;
u16 link_policy = 0;
if (lmp_rswitch_capable(hdev))
link_policy |= HCI_LP_RSWITCH;
if (lmp_hold_capable(hdev))
link_policy |= HCI_LP_HOLD;
if (lmp_sniff_capable(hdev))
link_policy |= HCI_LP_SNIFF;
if (lmp_park_capable(hdev))
link_policy |= HCI_LP_PARK;
cp.policy = cpu_to_le16(link_policy);
hci_req_add(req, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
}
static void hci_set_le_support(struct hci_request *req)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_write_le_host_supported cp;
memset(&cp, 0, sizeof(cp));
if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
cp.le = 0x01;
cp.simul = lmp_le_br_capable(hdev);
}
if (cp.le != lmp_host_le_capable(hdev))
hci_req_add(req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
&cp);
}
static void hci_init3_req(struct hci_request *req, unsigned long opt)
{
struct hci_dev *hdev = req->hdev;
if (hdev->commands[5] & 0x10)
hci_setup_link_policy(req);
if (lmp_le_capable(hdev)) {
hci_set_le_support(req);
hci_update_ad(req);
}
}
static int __hci_init(struct hci_dev *hdev)
{
int err;
err = __hci_req_sync(hdev, hci_init1_req, 0, HCI_INIT_TIMEOUT);
if (err < 0)
return err;
/* HCI_BREDR covers both single-mode LE, BR/EDR and dual-mode
* BR/EDR/LE type controllers. AMP controllers only need the
* first stage init.
*/
if (hdev->dev_type != HCI_BREDR)
return 0;
err = __hci_req_sync(hdev, hci_init2_req, 0, HCI_INIT_TIMEOUT);
if (err < 0)
return err;
return __hci_req_sync(hdev, hci_init3_req, 0, HCI_INIT_TIMEOUT);
}
static void hci_scan_req(struct hci_request *req, unsigned long opt)
{ {
__u8 scan = opt; __u8 scan = opt;
BT_DBG("%s %x", hdev->name, scan); BT_DBG("%s %x", req->hdev->name, scan);
/* Inquiry and Page scans */ /* Inquiry and Page scans */
hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); hci_req_add(req, 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_request *req, unsigned long opt)
{ {
__u8 auth = opt; __u8 auth = opt;
BT_DBG("%s %x", hdev->name, auth); BT_DBG("%s %x", req->hdev->name, auth);
/* Authentication */ /* Authentication */
hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, 1, &auth); hci_req_add(req, 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_request *req, unsigned long opt)
{ {
__u8 encrypt = opt; __u8 encrypt = opt;
BT_DBG("%s %x", hdev->name, encrypt); BT_DBG("%s %x", req->hdev->name, encrypt);
/* Encryption */ /* Encryption */
hci_send_cmd(hdev, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt); hci_req_add(req, HCI_OP_WRITE_ENCRYPT_MODE, 1, &encrypt);
} }
static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt) static void hci_linkpol_req(struct hci_request *req, unsigned long opt)
{ {
__le16 policy = cpu_to_le16(opt); __le16 policy = cpu_to_le16(opt);
BT_DBG("%s %x", hdev->name, policy); BT_DBG("%s %x", req->hdev->name, policy);
/* Default link policy */ /* Default link policy */
hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy); hci_req_add(req, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
} }
/* Get HCI device by index. /* Get HCI device by index.
...@@ -512,9 +800,10 @@ static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) ...@@ -512,9 +800,10 @@ static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
return copied; return copied;
} }
static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) static void hci_inq_req(struct hci_request *req, unsigned long opt)
{ {
struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt; struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
struct hci_dev *hdev = req->hdev;
struct hci_cp_inquiry cp; struct hci_cp_inquiry cp;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
...@@ -526,7 +815,7 @@ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) ...@@ -526,7 +815,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, HCI_OP_INQUIRY, sizeof(cp), &cp); hci_req_add(req, HCI_OP_INQUIRY, sizeof(cp), &cp);
} }
int hci_inquiry(void __user *arg) int hci_inquiry(void __user *arg)
...@@ -556,7 +845,8 @@ int hci_inquiry(void __user *arg) ...@@ -556,7 +845,8 @@ int hci_inquiry(void __user *arg)
timeo = ir.length * msecs_to_jiffies(2000); timeo = ir.length * msecs_to_jiffies(2000);
if (do_inquiry) { if (do_inquiry) {
err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo); err = hci_req_sync(hdev, hci_inq_req, (unsigned long) &ir,
timeo);
if (err < 0) if (err < 0)
goto done; goto done;
} }
...@@ -654,39 +944,29 @@ static u8 create_ad(struct hci_dev *hdev, u8 *ptr) ...@@ -654,39 +944,29 @@ static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
return ad_len; return ad_len;
} }
int hci_update_ad(struct hci_dev *hdev) void hci_update_ad(struct hci_request *req)
{ {
struct hci_dev *hdev = req->hdev;
struct hci_cp_le_set_adv_data cp; struct hci_cp_le_set_adv_data cp;
u8 len; u8 len;
int err;
hci_dev_lock(hdev); if (!lmp_le_capable(hdev))
return;
if (!lmp_le_capable(hdev)) {
err = -EINVAL;
goto unlock;
}
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
len = create_ad(hdev, cp.data); len = create_ad(hdev, cp.data);
if (hdev->adv_data_len == len && if (hdev->adv_data_len == len &&
memcmp(cp.data, hdev->adv_data, len) == 0) { memcmp(cp.data, hdev->adv_data, len) == 0)
err = 0; return;
goto unlock;
}
memcpy(hdev->adv_data, cp.data, sizeof(cp.data)); memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
hdev->adv_data_len = len; hdev->adv_data_len = len;
cp.length = len; cp.length = len;
err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
unlock:
hci_dev_unlock(hdev);
return err; hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
} }
/* ---- HCI ioctl helpers ---- */ /* ---- HCI ioctl helpers ---- */
...@@ -735,10 +1015,7 @@ int hci_dev_open(__u16 dev) ...@@ -735,10 +1015,7 @@ int hci_dev_open(__u16 dev)
if (!test_bit(HCI_RAW, &hdev->flags)) { if (!test_bit(HCI_RAW, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
set_bit(HCI_INIT, &hdev->flags); set_bit(HCI_INIT, &hdev->flags);
hdev->init_last_cmd = 0; ret = __hci_init(hdev);
ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
clear_bit(HCI_INIT, &hdev->flags); clear_bit(HCI_INIT, &hdev->flags);
} }
...@@ -746,7 +1023,6 @@ int hci_dev_open(__u16 dev) ...@@ -746,7 +1023,6 @@ int hci_dev_open(__u16 dev)
hci_dev_hold(hdev); hci_dev_hold(hdev);
set_bit(HCI_UP, &hdev->flags); set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP); hci_notify(hdev, HCI_DEV_UP);
hci_update_ad(hdev);
if (!test_bit(HCI_SETUP, &hdev->dev_flags) && if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
mgmt_valid_hdev(hdev)) { mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev); hci_dev_lock(hdev);
...@@ -828,7 +1104,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -828,7 +1104,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
if (!test_bit(HCI_RAW, &hdev->flags) && if (!test_bit(HCI_RAW, &hdev->flags) &&
test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
set_bit(HCI_INIT, &hdev->flags); set_bit(HCI_INIT, &hdev->flags);
__hci_request(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT); __hci_req_sync(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT);
clear_bit(HCI_INIT, &hdev->flags); clear_bit(HCI_INIT, &hdev->flags);
} }
...@@ -851,6 +1127,10 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -851,6 +1127,10 @@ static int hci_dev_do_close(struct hci_dev *hdev)
* and no tasks are scheduled. */ * and no tasks are scheduled. */
hdev->close(hdev); hdev->close(hdev);
/* Clear flags */
hdev->flags = 0;
hdev->dev_flags &= ~HCI_PERSISTENT_MASK;
if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags) && if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags) &&
mgmt_valid_hdev(hdev)) { mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev); hci_dev_lock(hdev);
...@@ -858,9 +1138,6 @@ static int hci_dev_do_close(struct hci_dev *hdev) ...@@ -858,9 +1138,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
/* Clear flags */
hdev->flags = 0;
/* Controller radio is available but is currently powered down */ /* Controller radio is available but is currently powered down */
hdev->amp_status = 0; hdev->amp_status = 0;
...@@ -921,7 +1198,7 @@ int hci_dev_reset(__u16 dev) ...@@ -921,7 +1198,7 @@ int hci_dev_reset(__u16 dev)
hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0;
if (!test_bit(HCI_RAW, &hdev->flags)) if (!test_bit(HCI_RAW, &hdev->flags))
ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); ret = __hci_req_sync(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
done: done:
hci_req_unlock(hdev); hci_req_unlock(hdev);
...@@ -960,7 +1237,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) ...@@ -960,7 +1237,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
switch (cmd) { switch (cmd) {
case HCISETAUTH: case HCISETAUTH:
err = hci_request(hdev, hci_auth_req, dr.dev_opt, err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt,
HCI_INIT_TIMEOUT); HCI_INIT_TIMEOUT);
break; break;
...@@ -972,23 +1249,23 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) ...@@ -972,23 +1249,23 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
if (!test_bit(HCI_AUTH, &hdev->flags)) { if (!test_bit(HCI_AUTH, &hdev->flags)) {
/* Auth must be enabled first */ /* Auth must be enabled first */
err = hci_request(hdev, hci_auth_req, dr.dev_opt, err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt,
HCI_INIT_TIMEOUT); HCI_INIT_TIMEOUT);
if (err) if (err)
break; break;
} }
err = hci_request(hdev, hci_encrypt_req, dr.dev_opt, err = hci_req_sync(hdev, hci_encrypt_req, dr.dev_opt,
HCI_INIT_TIMEOUT); HCI_INIT_TIMEOUT);
break; break;
case HCISETSCAN: case HCISETSCAN:
err = hci_request(hdev, hci_scan_req, dr.dev_opt, err = hci_req_sync(hdev, hci_scan_req, dr.dev_opt,
HCI_INIT_TIMEOUT); HCI_INIT_TIMEOUT);
break; break;
case HCISETLINKPOL: case HCISETLINKPOL:
err = hci_request(hdev, hci_linkpol_req, dr.dev_opt, err = hci_req_sync(hdev, hci_linkpol_req, dr.dev_opt,
HCI_INIT_TIMEOUT); HCI_INIT_TIMEOUT);
break; break;
...@@ -1566,7 +1843,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) ...@@ -1566,7 +1843,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
return mgmt_device_unblocked(hdev, bdaddr, type); return mgmt_device_unblocked(hdev, bdaddr, type);
} }
static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt) static void le_scan_param_req(struct hci_request *req, unsigned long opt)
{ {
struct le_scan_params *param = (struct le_scan_params *) opt; struct le_scan_params *param = (struct le_scan_params *) opt;
struct hci_cp_le_set_scan_param cp; struct hci_cp_le_set_scan_param cp;
...@@ -1576,10 +1853,10 @@ static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt) ...@@ -1576,10 +1853,10 @@ static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
cp.interval = cpu_to_le16(param->interval); cp.interval = cpu_to_le16(param->interval);
cp.window = cpu_to_le16(param->window); cp.window = cpu_to_le16(param->window);
hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp); hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
} }
static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt) static void le_scan_enable_req(struct hci_request *req, unsigned long opt)
{ {
struct hci_cp_le_set_scan_enable cp; struct hci_cp_le_set_scan_enable cp;
...@@ -1587,7 +1864,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt) ...@@ -1587,7 +1864,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
cp.enable = 1; cp.enable = 1;
cp.filter_dup = 1; cp.filter_dup = 1;
hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
} }
static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
...@@ -1608,10 +1885,10 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, ...@@ -1608,10 +1885,10 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
hci_req_lock(hdev); hci_req_lock(hdev);
err = __hci_request(hdev, le_scan_param_req, (unsigned long) &param, err = __hci_req_sync(hdev, le_scan_param_req, (unsigned long) &param,
timeo); timeo);
if (!err) if (!err)
err = __hci_request(hdev, le_scan_enable_req, 0, timeo); err = __hci_req_sync(hdev, le_scan_enable_req, 0, timeo);
hci_req_unlock(hdev); hci_req_unlock(hdev);
...@@ -2160,20 +2437,55 @@ static int hci_send_frame(struct sk_buff *skb) ...@@ -2160,20 +2437,55 @@ static int hci_send_frame(struct sk_buff *skb)
return hdev->send(skb); return hdev->send(skb);
} }
/* Send HCI command */ void hci_req_init(struct hci_request *req, struct hci_dev *hdev)
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) {
skb_queue_head_init(&req->cmd_q);
req->hdev = hdev;
req->err = 0;
}
int hci_req_run(struct hci_request *req, hci_req_complete_t complete)
{
struct hci_dev *hdev = req->hdev;
struct sk_buff *skb;
unsigned long flags;
BT_DBG("length %u", skb_queue_len(&req->cmd_q));
/* If an error occured during request building, remove all HCI
* commands queued on the HCI request queue.
*/
if (req->err) {
skb_queue_purge(&req->cmd_q);
return req->err;
}
/* Do not allow empty requests */
if (skb_queue_empty(&req->cmd_q))
return -ENODATA;
skb = skb_peek_tail(&req->cmd_q);
bt_cb(skb)->req.complete = complete;
spin_lock_irqsave(&hdev->cmd_q.lock, flags);
skb_queue_splice_tail(&req->cmd_q, &hdev->cmd_q);
spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
queue_work(hdev->workqueue, &hdev->cmd_work);
return 0;
}
static struct sk_buff *hci_prepare_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 opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
skb = bt_skb_alloc(len, GFP_ATOMIC); skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb) { if (!skb)
BT_ERR("%s no memory for command", hdev->name); return NULL;
return -ENOMEM;
}
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(opcode); hdr->opcode = cpu_to_le16(opcode);
...@@ -2187,8 +2499,26 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) ...@@ -2187,8 +2499,26 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev; skb->dev = (void *) hdev;
if (test_bit(HCI_INIT, &hdev->flags)) return skb;
hdev->init_last_cmd = opcode; }
/* Send HCI command */
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
{
struct sk_buff *skb;
BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
skb = hci_prepare_cmd(hdev, opcode, plen, param);
if (!skb) {
BT_ERR("%s no memory for command", hdev->name);
return -ENOMEM;
}
/* Stand-alone HCI commands must be flaged as
* single-command requests.
*/
bt_cb(skb)->req.start = true;
skb_queue_tail(&hdev->cmd_q, skb); skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work); queue_work(hdev->workqueue, &hdev->cmd_work);
...@@ -2196,6 +2526,34 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) ...@@ -2196,6 +2526,34 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
return 0; return 0;
} }
/* Queue a command to an asynchronous HCI request */
void hci_req_add(struct hci_request *req, u16 opcode, u32 plen, void *param)
{
struct hci_dev *hdev = req->hdev;
struct sk_buff *skb;
BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
/* If an error occured during request building, there is no point in
* queueing the HCI command. We can simply return.
*/
if (req->err)
return;
skb = hci_prepare_cmd(hdev, opcode, plen, param);
if (!skb) {
BT_ERR("%s no memory for command (opcode 0x%4.4x)",
hdev->name, opcode);
req->err = -ENOMEM;
return;
}
if (skb_queue_empty(&req->cmd_q))
bt_cb(skb)->req.start = true;
skb_queue_tail(&req->cmd_q, skb);
}
/* Get data from the previously sent command */ /* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
{ {
...@@ -2398,7 +2756,7 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type) ...@@ -2398,7 +2756,7 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
if (c->type == type && c->sent) { if (c->type == type && c->sent) {
BT_ERR("%s killing stalled connection %pMR", BT_ERR("%s killing stalled connection %pMR",
hdev->name, &c->dst); hdev->name, &c->dst);
hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM); hci_disconnect(c, HCI_ERROR_REMOTE_USER_TERM);
} }
} }
...@@ -2860,6 +3218,123 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2860,6 +3218,123 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
} }
static bool hci_req_is_complete(struct hci_dev *hdev)
{
struct sk_buff *skb;
skb = skb_peek(&hdev->cmd_q);
if (!skb)
return true;
return bt_cb(skb)->req.start;
}
static void hci_resend_last(struct hci_dev *hdev)
{
struct hci_command_hdr *sent;
struct sk_buff *skb;
u16 opcode;
if (!hdev->sent_cmd)
return;
sent = (void *) hdev->sent_cmd->data;
opcode = __le16_to_cpu(sent->opcode);
if (opcode == HCI_OP_RESET)
return;
skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);
if (!skb)
return;
skb_queue_head(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work);
}
void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
{
hci_req_complete_t req_complete = NULL;
struct sk_buff *skb;
unsigned long flags;
BT_DBG("opcode 0x%04x status 0x%02x", opcode, status);
/* If the completed command doesn't match the last one that was
* sent we need to do special handling of it.
*/
if (!hci_sent_cmd_data(hdev, opcode)) {
/* Some CSR based controllers generate a spontaneous
* reset complete event during init and any pending
* command will never be completed. In such a case we
* need to resend whatever was the last sent
* command.
*/
if (test_bit(HCI_INIT, &hdev->flags) && opcode == HCI_OP_RESET)
hci_resend_last(hdev);
return;
}
/* If the command succeeded and there's still more commands in
* this request the request is not yet complete.
*/
if (!status && !hci_req_is_complete(hdev))
return;
/* If this was the last command in a request the complete
* callback would be found in hdev->sent_cmd instead of the
* command queue (hdev->cmd_q).
*/
if (hdev->sent_cmd) {
req_complete = bt_cb(hdev->sent_cmd)->req.complete;
if (req_complete)
goto call_complete;
}
/* Remove all pending commands belonging to this request */
spin_lock_irqsave(&hdev->cmd_q.lock, flags);
while ((skb = __skb_dequeue(&hdev->cmd_q))) {
if (bt_cb(skb)->req.start) {
__skb_queue_head(&hdev->cmd_q, skb);
break;
}
req_complete = bt_cb(skb)->req.complete;
kfree_skb(skb);
}
spin_unlock_irqrestore(&hdev->cmd_q.lock, flags);
call_complete:
if (req_complete)
req_complete(hdev, status);
}
void hci_req_cmd_status(struct hci_dev *hdev, u16 opcode, u8 status)
{
hci_req_complete_t req_complete = NULL;
BT_DBG("opcode 0x%04x status 0x%02x", opcode, status);
if (status) {
hci_req_cmd_complete(hdev, opcode, status);
return;
}
/* No need to handle success status if there are more commands */
if (!hci_req_is_complete(hdev))
return;
if (hdev->sent_cmd)
req_complete = bt_cb(hdev->sent_cmd)->req.complete;
/* If the request doesn't have a complete callback or there
* are other commands/requests in the hdev queue we consider
* this request as completed.
*/
if (!req_complete || !skb_queue_empty(&hdev->cmd_q))
hci_req_cmd_complete(hdev, opcode, status);
}
static void hci_rx_work(struct work_struct *work) static void hci_rx_work(struct work_struct *work)
{ {
struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work); struct hci_dev *hdev = container_of(work, struct hci_dev, rx_work);
......
...@@ -53,7 +53,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -53,7 +53,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); hci_req_cmd_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev); hci_conn_check_pending(hdev);
} }
...@@ -183,8 +183,6 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev, ...@@ -183,8 +183,6 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
if (!status) if (!status)
hdev->link_policy = get_unaligned_le16(sent); hdev->link_policy = get_unaligned_le16(sent);
hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status);
} }
static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -195,11 +193,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -195,11 +193,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_RESET, &hdev->flags); clear_bit(HCI_RESET, &hdev->flags);
hci_req_complete(hdev, HCI_OP_RESET, status);
/* Reset all non-persistent flags */ /* Reset all non-persistent flags */
hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS) | hdev->dev_flags &= ~HCI_PERSISTENT_MASK;
BIT(HCI_PERIODIC_INQ));
hdev->discovery.state = DISCOVERY_STOPPED; hdev->discovery.state = DISCOVERY_STOPPED;
hdev->inq_tx_power = HCI_TX_POWER_INVALID; hdev->inq_tx_power = HCI_TX_POWER_INVALID;
...@@ -228,11 +223,6 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -228,11 +223,6 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
if (!status && !test_bit(HCI_INIT, &hdev->flags))
hci_update_ad(hdev);
hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
} }
static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -270,8 +260,6 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -270,8 +260,6 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb)
if (test_bit(HCI_MGMT, &hdev->dev_flags)) if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_auth_enable_complete(hdev, status); mgmt_auth_enable_complete(hdev, status);
hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status);
} }
static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -293,8 +281,6 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -293,8 +281,6 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
else else
clear_bit(HCI_ENCRYPT, &hdev->flags); clear_bit(HCI_ENCRYPT, &hdev->flags);
} }
hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status);
} }
static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -343,7 +329,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -343,7 +329,6 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
done: done:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
} }
static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -435,15 +420,6 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev, ...@@ -435,15 +420,6 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev,
hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
} }
static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%2.2x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status);
}
static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
{ {
__u8 status = *((__u8 *) skb->data); __u8 status = *((__u8 *) skb->data);
...@@ -472,211 +448,6 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -472,211 +448,6 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
} }
} }
static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
{
if (lmp_ext_inq_capable(hdev))
return 2;
if (lmp_inq_rssi_capable(hdev))
return 1;
if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
hdev->lmp_subver == 0x0757)
return 1;
if (hdev->manufacturer == 15) {
if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963)
return 1;
if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963)
return 1;
if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965)
return 1;
}
if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 &&
hdev->lmp_subver == 0x1805)
return 1;
return 0;
}
static void hci_setup_inquiry_mode(struct hci_dev *hdev)
{
u8 mode;
mode = hci_get_inquiry_mode(hdev);
hci_send_cmd(hdev, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode);
}
static void hci_setup_event_mask(struct hci_dev *hdev)
{
/* The second byte is 0xff instead of 0x9f (two reserved bits
* disabled) since a Broadcom 1.2 dongle doesn't respond to the
* command otherwise */
u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
/* CSR 1.1 dongles does not accept any bitfield so don't try to set
* any event mask for pre 1.2 devices */
if (hdev->hci_ver < BLUETOOTH_VER_1_2)
return;
if (lmp_bredr_capable(hdev)) {
events[4] |= 0x01; /* Flow Specification Complete */
events[4] |= 0x02; /* Inquiry Result with RSSI */
events[4] |= 0x04; /* Read Remote Extended Features Complete */
events[5] |= 0x08; /* Synchronous Connection Complete */
events[5] |= 0x10; /* Synchronous Connection Changed */
}
if (lmp_inq_rssi_capable(hdev))
events[4] |= 0x02; /* Inquiry Result with RSSI */
if (lmp_sniffsubr_capable(hdev))
events[5] |= 0x20; /* Sniff Subrating */
if (lmp_pause_enc_capable(hdev))
events[5] |= 0x80; /* Encryption Key Refresh Complete */
if (lmp_ext_inq_capable(hdev))
events[5] |= 0x40; /* Extended Inquiry Result */
if (lmp_no_flush_capable(hdev))
events[7] |= 0x01; /* Enhanced Flush Complete */
if (lmp_lsto_capable(hdev))
events[6] |= 0x80; /* Link Supervision Timeout Changed */
if (lmp_ssp_capable(hdev)) {
events[6] |= 0x01; /* IO Capability Request */
events[6] |= 0x02; /* IO Capability Response */
events[6] |= 0x04; /* User Confirmation Request */
events[6] |= 0x08; /* User Passkey Request */
events[6] |= 0x10; /* Remote OOB Data Request */
events[6] |= 0x20; /* Simple Pairing Complete */
events[7] |= 0x04; /* User Passkey Notification */
events[7] |= 0x08; /* Keypress Notification */
events[7] |= 0x10; /* Remote Host Supported
* Features Notification */
}
if (lmp_le_capable(hdev))
events[7] |= 0x20; /* LE Meta-Event */
hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
if (lmp_le_capable(hdev)) {
memset(events, 0, sizeof(events));
events[0] = 0x1f;
hci_send_cmd(hdev, HCI_OP_LE_SET_EVENT_MASK,
sizeof(events), events);
}
}
static void bredr_setup(struct hci_dev *hdev)
{
struct hci_cp_delete_stored_link_key cp;
__le16 param;
__u8 flt_type;
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 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 */
hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
/* Clear Event Filters */
flt_type = HCI_FLT_CLEAR_ALL;
hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
/* Connection accept timeout ~20 secs */
param = __constant_cpu_to_le16(0x7d00);
hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
bacpy(&cp.bdaddr, BDADDR_ANY);
cp.delete_all = 1;
hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
}
static void le_setup(struct hci_dev *hdev)
{
/* Read LE Buffer Size */
hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
/* Read LE Local Supported Features */
hci_send_cmd(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, 0, NULL);
/* Read LE Advertising Channel TX Power */
hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
/* Read LE White List Size */
hci_send_cmd(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
/* Read LE Supported States */
hci_send_cmd(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
}
static void hci_setup(struct hci_dev *hdev)
{
if (hdev->dev_type != HCI_BREDR)
return;
/* Read BD Address */
hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
if (lmp_bredr_capable(hdev))
bredr_setup(hdev);
if (lmp_le_capable(hdev))
le_setup(hdev);
hci_setup_event_mask(hdev);
if (hdev->hci_ver > BLUETOOTH_VER_1_1)
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
if (lmp_ssp_capable(hdev)) {
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
u8 mode = 0x01;
hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
sizeof(mode), &mode);
} else {
struct hci_cp_write_eir cp;
memset(hdev->eir, 0, sizeof(hdev->eir));
memset(&cp, 0, sizeof(cp));
hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
}
}
if (lmp_inq_rssi_capable(hdev))
hci_setup_inquiry_mode(hdev);
if (lmp_inq_tx_pwr_capable(hdev))
hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
if (lmp_ext_feat_capable(hdev)) {
struct hci_cp_read_local_ext_features cp;
cp.page = 0x01;
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, sizeof(cp),
&cp);
}
if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags)) {
u8 enable = 1;
hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(enable),
&enable);
}
}
static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_rp_read_local_version *rp = (void *) skb->data; struct hci_rp_read_local_version *rp = (void *) skb->data;
...@@ -684,7 +455,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -684,7 +455,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status) if (rp->status)
goto done; return;
hdev->hci_ver = rp->hci_ver; hdev->hci_ver = rp->hci_ver;
hdev->hci_rev = __le16_to_cpu(rp->hci_rev); hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
...@@ -694,30 +465,6 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -694,30 +465,6 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s manufacturer 0x%4.4x hci ver %d:%d", hdev->name, BT_DBG("%s manufacturer 0x%4.4x hci ver %d:%d", hdev->name,
hdev->manufacturer, hdev->hci_ver, hdev->hci_rev); hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
if (test_bit(HCI_INIT, &hdev->flags))
hci_setup(hdev);
done:
hci_req_complete(hdev, HCI_OP_READ_LOCAL_VERSION, rp->status);
}
static void hci_setup_link_policy(struct hci_dev *hdev)
{
struct hci_cp_write_def_link_policy cp;
u16 link_policy = 0;
if (lmp_rswitch_capable(hdev))
link_policy |= HCI_LP_RSWITCH;
if (lmp_hold_capable(hdev))
link_policy |= HCI_LP_HOLD;
if (lmp_sniff_capable(hdev))
link_policy |= HCI_LP_SNIFF;
if (lmp_park_capable(hdev))
link_policy |= HCI_LP_PARK;
cp.policy = cpu_to_le16(link_policy);
hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
} }
static void hci_cc_read_local_commands(struct hci_dev *hdev, static void hci_cc_read_local_commands(struct hci_dev *hdev,
...@@ -727,16 +474,8 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev, ...@@ -727,16 +474,8 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status) if (!rp->status)
goto done;
memcpy(hdev->commands, rp->commands, sizeof(hdev->commands)); memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
if (test_bit(HCI_INIT, &hdev->flags) && (hdev->commands[5] & 0x10))
hci_setup_link_policy(hdev);
done:
hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
} }
static void hci_cc_read_local_features(struct hci_dev *hdev, static void hci_cc_read_local_features(struct hci_dev *hdev,
...@@ -795,22 +534,6 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, ...@@ -795,22 +534,6 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
hdev->features[6], hdev->features[7]); hdev->features[6], hdev->features[7]);
} }
static void hci_set_le_support(struct hci_dev *hdev)
{
struct hci_cp_write_le_host_supported cp;
memset(&cp, 0, sizeof(cp));
if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
cp.le = 1;
cp.simul = lmp_le_br_capable(hdev);
}
if (cp.le != lmp_host_le_capable(hdev))
hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
&cp);
}
static void hci_cc_read_local_ext_features(struct hci_dev *hdev, static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -819,7 +542,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev, ...@@ -819,7 +542,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status) if (rp->status)
goto done; return;
switch (rp->page) { switch (rp->page) {
case 0: case 0:
...@@ -829,12 +552,6 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev, ...@@ -829,12 +552,6 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
memcpy(hdev->host_features, rp->features, 8); memcpy(hdev->host_features, rp->features, 8);
break; break;
} }
if (test_bit(HCI_INIT, &hdev->flags) && lmp_le_capable(hdev))
hci_set_le_support(hdev);
done:
hci_req_complete(hdev, HCI_OP_READ_LOCAL_EXT_FEATURES, rp->status);
} }
static void hci_cc_read_flow_control_mode(struct hci_dev *hdev, static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
...@@ -844,12 +561,8 @@ static void hci_cc_read_flow_control_mode(struct hci_dev *hdev, ...@@ -844,12 +561,8 @@ static void hci_cc_read_flow_control_mode(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status) if (!rp->status)
return;
hdev->flow_ctl_mode = rp->mode; hdev->flow_ctl_mode = rp->mode;
hci_req_complete(hdev, HCI_OP_READ_FLOW_CONTROL_MODE, rp->status);
} }
static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -886,8 +599,65 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -886,8 +599,65 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
if (!rp->status) if (!rp->status)
bacpy(&hdev->bdaddr, &rp->bdaddr); bacpy(&hdev->bdaddr, &rp->bdaddr);
}
static void hci_cc_read_page_scan_activity(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_read_page_scan_activity *rp = (void *) skb->data;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (test_bit(HCI_INIT, &hdev->flags) && !rp->status) {
hdev->page_scan_interval = __le16_to_cpu(rp->interval);
hdev->page_scan_window = __le16_to_cpu(rp->window);
}
}
static void hci_cc_write_page_scan_activity(struct hci_dev *hdev,
struct sk_buff *skb)
{
u8 status = *((u8 *) skb->data);
struct hci_cp_write_page_scan_activity *sent;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status)
return;
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY);
if (!sent)
return;
hdev->page_scan_interval = __le16_to_cpu(sent->interval);
hdev->page_scan_window = __le16_to_cpu(sent->window);
}
static void hci_cc_read_page_scan_type(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_read_page_scan_type *rp = (void *) skb->data;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status); if (test_bit(HCI_INIT, &hdev->flags) && !rp->status)
hdev->page_scan_type = rp->type;
}
static void hci_cc_write_page_scan_type(struct hci_dev *hdev,
struct sk_buff *skb)
{
u8 status = *((u8 *) skb->data);
u8 *type;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status)
return;
type = hci_sent_cmd_data(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE);
if (type)
hdev->page_scan_type = *type;
} }
static void hci_cc_read_data_block_size(struct hci_dev *hdev, static void hci_cc_read_data_block_size(struct hci_dev *hdev,
...@@ -908,17 +678,6 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev, ...@@ -908,17 +678,6 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev,
BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu, BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
hdev->block_cnt, hdev->block_len); hdev->block_cnt, hdev->block_len);
hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status);
}
static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%2.2x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
} }
static void hci_cc_read_local_amp_info(struct hci_dev *hdev, static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
...@@ -942,8 +701,6 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev, ...@@ -942,8 +701,6 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to); hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to); hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
a2mp_rsp: a2mp_rsp:
a2mp_send_getinfo_rsp(hdev); a2mp_send_getinfo_rsp(hdev);
} }
...@@ -985,35 +742,6 @@ static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev, ...@@ -985,35 +742,6 @@ static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
a2mp_send_create_phy_link_req(hdev, rp->status); a2mp_send_create_phy_link_req(hdev, rp->status);
} }
static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%2.2x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status);
}
static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%2.2x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_SET_EVENT_MASK, status);
}
static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%2.2x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_WRITE_INQUIRY_MODE, status);
}
static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -1023,17 +751,6 @@ static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, ...@@ -1023,17 +751,6 @@ static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
if (!rp->status) if (!rp->status)
hdev->inq_tx_power = rp->tx_power; hdev->inq_tx_power = rp->tx_power;
hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, rp->status);
}
static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%2.2x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status);
} }
static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -1095,8 +812,6 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, ...@@ -1095,8 +812,6 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
hdev->le_cnt = hdev->le_pkts; hdev->le_cnt = hdev->le_pkts;
BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts); BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
} }
static void hci_cc_le_read_local_features(struct hci_dev *hdev, static void hci_cc_le_read_local_features(struct hci_dev *hdev,
...@@ -1108,8 +823,6 @@ static void hci_cc_le_read_local_features(struct hci_dev *hdev, ...@@ -1108,8 +823,6 @@ static void hci_cc_le_read_local_features(struct hci_dev *hdev,
if (!rp->status) if (!rp->status)
memcpy(hdev->le_features, rp->features, 8); memcpy(hdev->le_features, rp->features, 8);
hci_req_complete(hdev, HCI_OP_LE_READ_LOCAL_FEATURES, rp->status);
} }
static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
...@@ -1119,22 +832,8 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev, ...@@ -1119,22 +832,8 @@ static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (!rp->status) { if (!rp->status)
hdev->adv_tx_power = rp->tx_power; hdev->adv_tx_power = rp->tx_power;
if (!test_bit(HCI_INIT, &hdev->flags))
hci_update_ad(hdev);
}
hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status);
}
static void hci_cc_le_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
BT_DBG("%s status 0x%2.2x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_LE_SET_EVENT_MASK, status);
} }
static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -1231,12 +930,15 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1231,12 +930,15 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags); clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
} }
hci_dev_unlock(hdev); if (!test_bit(HCI_INIT, &hdev->flags)) {
struct hci_request req;
if (!test_bit(HCI_INIT, &hdev->flags)) hci_req_init(&req, hdev);
hci_update_ad(hdev); hci_update_ad(&req);
hci_req_run(&req, NULL);
}
hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status); hci_dev_unlock(hdev);
} }
static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
...@@ -1245,8 +947,6 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1245,8 +947,6 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, status); BT_DBG("%s status 0x%2.2x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status);
if (status) { if (status) {
hci_dev_lock(hdev); hci_dev_lock(hdev);
mgmt_start_discovery_failed(hdev, status); mgmt_start_discovery_failed(hdev, status);
...@@ -1269,8 +969,6 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, ...@@ -1269,8 +969,6 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
switch (cp->enable) { switch (cp->enable) {
case LE_SCANNING_ENABLED: case LE_SCANNING_ENABLED:
hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_ENABLE, status);
if (status) { if (status) {
hci_dev_lock(hdev); hci_dev_lock(hdev);
mgmt_start_discovery_failed(hdev, status); mgmt_start_discovery_failed(hdev, status);
...@@ -1321,32 +1019,6 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev, ...@@ -1321,32 +1019,6 @@ static void hci_cc_le_read_white_list_size(struct hci_dev *hdev,
if (!rp->status) if (!rp->status)
hdev->le_white_list_size = rp->size; hdev->le_white_list_size = rp->size;
hci_req_complete(hdev, HCI_OP_LE_READ_WHITE_LIST_SIZE, rp->status);
}
static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_le_ltk_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
return;
hci_req_complete(hdev, HCI_OP_LE_LTK_REPLY, rp->status);
}
static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
return;
hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
} }
static void hci_cc_le_read_supported_states(struct hci_dev *hdev, static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
...@@ -1358,8 +1030,6 @@ static void hci_cc_le_read_supported_states(struct hci_dev *hdev, ...@@ -1358,8 +1030,6 @@ static void hci_cc_le_read_supported_states(struct hci_dev *hdev,
if (!rp->status) if (!rp->status)
memcpy(hdev->le_states, rp->le_states, 8); memcpy(hdev->le_states, rp->le_states, 8);
hci_req_complete(hdev, HCI_OP_LE_READ_SUPPORTED_STATES, rp->status);
} }
static void hci_cc_write_le_host_supported(struct hci_dev *hdev, static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
...@@ -1389,8 +1059,6 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, ...@@ -1389,8 +1059,6 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
if (test_bit(HCI_MGMT, &hdev->dev_flags) && if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
!test_bit(HCI_INIT, &hdev->flags)) !test_bit(HCI_INIT, &hdev->flags))
mgmt_le_enable_complete(hdev, sent->le, status); mgmt_le_enable_complete(hdev, sent->le, status);
hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
} }
static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev, static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
...@@ -1412,7 +1080,6 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) ...@@ -1412,7 +1080,6 @@ static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
BT_DBG("%s status 0x%2.2x", hdev->name, status); BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status) { if (status) {
hci_req_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev); hci_conn_check_pending(hdev);
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->dev_flags)) if (test_bit(HCI_MGMT, &hdev->dev_flags))
...@@ -1884,11 +1551,6 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) ...@@ -1884,11 +1551,6 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
} }
} }
static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
{
BT_DBG("%s status 0x%2.2x", hdev->name, status);
}
static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status) static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
{ {
struct hci_cp_create_phy_link *cp; struct hci_cp_create_phy_link *cp;
...@@ -1930,11 +1592,6 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status) ...@@ -1930,11 +1592,6 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
amp_write_remote_assoc(hdev, cp->phy_handle); amp_write_remote_assoc(hdev, cp->phy_handle);
} }
static void hci_cs_create_logical_link(struct hci_dev *hdev, u8 status)
{
BT_DBG("%s status 0x%2.2x", hdev->name, status);
}
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
__u8 status = *((__u8 *) skb->data); __u8 status = *((__u8 *) skb->data);
...@@ -1943,7 +1600,7 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1943,7 +1600,7 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%2.2x", hdev->name, status); BT_DBG("%s status 0x%2.2x", hdev->name, status);
hci_req_complete(hdev, HCI_OP_INQUIRY, status); hci_req_cmd_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev); hci_conn_check_pending(hdev);
...@@ -2399,7 +2056,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2399,7 +2056,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
if (ev->status && conn->state == BT_CONNECTED) { if (ev->status && conn->state == BT_CONNECTED) {
hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE); hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
hci_conn_put(conn); hci_conn_put(conn);
goto unlock; goto unlock;
} }
...@@ -2491,20 +2148,10 @@ static void hci_remote_features_evt(struct hci_dev *hdev, ...@@ -2491,20 +2148,10 @@ static void hci_remote_features_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
static void hci_qos_setup_complete_evt(struct hci_dev *hdev,
struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_cmd_complete *ev = (void *) skb->data; struct hci_ev_cmd_complete *ev = (void *) skb->data;
u8 status = skb->data[sizeof(*ev)];
__u16 opcode; __u16 opcode;
skb_pull(skb, sizeof(*ev)); skb_pull(skb, sizeof(*ev));
...@@ -2588,10 +2235,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2588,10 +2235,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_write_voice_setting(hdev, skb); hci_cc_write_voice_setting(hdev, skb);
break; break;
case HCI_OP_HOST_BUFFER_SIZE:
hci_cc_host_buffer_size(hdev, skb);
break;
case HCI_OP_WRITE_SSP_MODE: case HCI_OP_WRITE_SSP_MODE:
hci_cc_write_ssp_mode(hdev, skb); hci_cc_write_ssp_mode(hdev, skb);
break; break;
...@@ -2620,46 +2263,42 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2620,46 +2263,42 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_read_bd_addr(hdev, skb); hci_cc_read_bd_addr(hdev, skb);
break; break;
case HCI_OP_READ_DATA_BLOCK_SIZE: case HCI_OP_READ_PAGE_SCAN_ACTIVITY:
hci_cc_read_data_block_size(hdev, skb); hci_cc_read_page_scan_activity(hdev, skb);
break; break;
case HCI_OP_WRITE_CA_TIMEOUT: case HCI_OP_WRITE_PAGE_SCAN_ACTIVITY:
hci_cc_write_ca_timeout(hdev, skb); hci_cc_write_page_scan_activity(hdev, skb);
break; break;
case HCI_OP_READ_FLOW_CONTROL_MODE: case HCI_OP_READ_PAGE_SCAN_TYPE:
hci_cc_read_flow_control_mode(hdev, skb); hci_cc_read_page_scan_type(hdev, skb);
break; break;
case HCI_OP_READ_LOCAL_AMP_INFO: case HCI_OP_WRITE_PAGE_SCAN_TYPE:
hci_cc_read_local_amp_info(hdev, skb); hci_cc_write_page_scan_type(hdev, skb);
break; break;
case HCI_OP_READ_LOCAL_AMP_ASSOC: case HCI_OP_READ_DATA_BLOCK_SIZE:
hci_cc_read_local_amp_assoc(hdev, skb); hci_cc_read_data_block_size(hdev, skb);
break; break;
case HCI_OP_DELETE_STORED_LINK_KEY: case HCI_OP_READ_FLOW_CONTROL_MODE:
hci_cc_delete_stored_link_key(hdev, skb); hci_cc_read_flow_control_mode(hdev, skb);
break; break;
case HCI_OP_SET_EVENT_MASK: case HCI_OP_READ_LOCAL_AMP_INFO:
hci_cc_set_event_mask(hdev, skb); hci_cc_read_local_amp_info(hdev, skb);
break; break;
case HCI_OP_WRITE_INQUIRY_MODE: case HCI_OP_READ_LOCAL_AMP_ASSOC:
hci_cc_write_inquiry_mode(hdev, skb); hci_cc_read_local_amp_assoc(hdev, skb);
break; break;
case HCI_OP_READ_INQ_RSP_TX_POWER: case HCI_OP_READ_INQ_RSP_TX_POWER:
hci_cc_read_inq_rsp_tx_power(hdev, skb); hci_cc_read_inq_rsp_tx_power(hdev, skb);
break; break;
case HCI_OP_SET_EVENT_FLT:
hci_cc_set_event_flt(hdev, skb);
break;
case HCI_OP_PIN_CODE_REPLY: case HCI_OP_PIN_CODE_REPLY:
hci_cc_pin_code_reply(hdev, skb); hci_cc_pin_code_reply(hdev, skb);
break; break;
...@@ -2684,10 +2323,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2684,10 +2323,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_le_read_adv_tx_power(hdev, skb); hci_cc_le_read_adv_tx_power(hdev, skb);
break; break;
case HCI_OP_LE_SET_EVENT_MASK:
hci_cc_le_set_event_mask(hdev, skb);
break;
case HCI_OP_USER_CONFIRM_REPLY: case HCI_OP_USER_CONFIRM_REPLY:
hci_cc_user_confirm_reply(hdev, skb); hci_cc_user_confirm_reply(hdev, skb);
break; break;
...@@ -2720,14 +2355,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2720,14 +2355,6 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_le_read_white_list_size(hdev, skb); hci_cc_le_read_white_list_size(hdev, skb);
break; break;
case HCI_OP_LE_LTK_REPLY:
hci_cc_le_ltk_reply(hdev, skb);
break;
case HCI_OP_LE_LTK_NEG_REPLY:
hci_cc_le_ltk_neg_reply(hdev, skb);
break;
case HCI_OP_LE_READ_SUPPORTED_STATES: case HCI_OP_LE_READ_SUPPORTED_STATES:
hci_cc_le_read_supported_states(hdev, skb); hci_cc_le_read_supported_states(hdev, skb);
break; break;
...@@ -2745,9 +2372,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2745,9 +2372,11 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
break; break;
} }
if (ev->opcode != HCI_OP_NOP) if (opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer); del_timer(&hdev->cmd_timer);
hci_req_cmd_complete(hdev, opcode, status);
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q)) if (!skb_queue_empty(&hdev->cmd_q))
...@@ -2817,10 +2446,6 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2817,10 +2446,6 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_le_create_conn(hdev, ev->status); hci_cs_le_create_conn(hdev, ev->status);
break; break;
case HCI_OP_LE_START_ENC:
hci_cs_le_start_enc(hdev, ev->status);
break;
case HCI_OP_CREATE_PHY_LINK: case HCI_OP_CREATE_PHY_LINK:
hci_cs_create_phylink(hdev, ev->status); hci_cs_create_phylink(hdev, ev->status);
break; break;
...@@ -2829,18 +2454,16 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2829,18 +2454,16 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_accept_phylink(hdev, ev->status); hci_cs_accept_phylink(hdev, ev->status);
break; break;
case HCI_OP_CREATE_LOGICAL_LINK:
hci_cs_create_logical_link(hdev, ev->status);
break;
default: default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
break; break;
} }
if (ev->opcode != HCI_OP_NOP) if (opcode != HCI_OP_NOP)
del_timer(&hdev->cmd_timer); del_timer(&hdev->cmd_timer);
hci_req_cmd_status(hdev, opcode, ev->status);
if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
atomic_set(&hdev->cmd_cnt, 1); atomic_set(&hdev->cmd_cnt, 1);
if (!skb_queue_empty(&hdev->cmd_q)) if (!skb_queue_empty(&hdev->cmd_q))
...@@ -3391,18 +3014,6 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, ...@@ -3391,18 +3014,6 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
BT_DBG("%s", hdev->name);
}
static void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_sniff_subrate *ev = (void *) skb->data;
BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
}
static void hci_extended_inquiry_result_evt(struct hci_dev *hdev, static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -3472,7 +3083,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev, ...@@ -3472,7 +3083,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev,
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
if (ev->status && conn->state == BT_CONNECTED) { if (ev->status && conn->state == BT_CONNECTED) {
hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE); hci_disconnect(conn, HCI_ERROR_AUTH_FAILURE);
hci_conn_put(conn); hci_conn_put(conn);
goto unlock; goto unlock;
} }
...@@ -4130,14 +3741,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -4130,14 +3741,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_remote_features_evt(hdev, skb); hci_remote_features_evt(hdev, skb);
break; break;
case HCI_EV_REMOTE_VERSION:
hci_remote_version_evt(hdev, skb);
break;
case HCI_EV_QOS_SETUP_COMPLETE:
hci_qos_setup_complete_evt(hdev, skb);
break;
case HCI_EV_CMD_COMPLETE: case HCI_EV_CMD_COMPLETE:
hci_cmd_complete_evt(hdev, skb); hci_cmd_complete_evt(hdev, skb);
break; break;
...@@ -4194,14 +3797,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -4194,14 +3797,6 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_sync_conn_complete_evt(hdev, skb); hci_sync_conn_complete_evt(hdev, skb);
break; break;
case HCI_EV_SYNC_CONN_CHANGED:
hci_sync_conn_changed_evt(hdev, skb);
break;
case HCI_EV_SNIFF_SUBRATE:
hci_sniff_subrate_evt(hdev, skb);
break;
case HCI_EV_EXTENDED_INQUIRY_RESULT: case HCI_EV_EXTENDED_INQUIRY_RESULT:
hci_extended_inquiry_result_evt(hdev, skb); hci_extended_inquiry_result_evt(hdev, skb);
break; break;
......
...@@ -854,6 +854,11 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, ...@@ -854,6 +854,11 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
skb_queue_tail(&hdev->raw_q, skb); skb_queue_tail(&hdev->raw_q, skb);
queue_work(hdev->workqueue, &hdev->tx_work); queue_work(hdev->workqueue, &hdev->tx_work);
} else { } else {
/* Stand-alone HCI commands must be flaged as
* single-command requests.
*/
bt_cb(skb)->req.start = true;
skb_queue_tail(&hdev->cmd_q, skb); skb_queue_tail(&hdev->cmd_q, skb);
queue_work(hdev->workqueue, &hdev->cmd_work); queue_work(hdev->workqueue, &hdev->cmd_work);
} }
...@@ -1121,8 +1126,6 @@ int __init hci_sock_init(void) ...@@ -1121,8 +1126,6 @@ int __init hci_sock_init(void)
void hci_sock_cleanup(void) void hci_sock_cleanup(void)
{ {
bt_procfs_cleanup(&init_net, "hci"); bt_procfs_cleanup(&init_net, "hci");
if (bt_sock_unregister(BTPROTO_HCI) < 0) bt_sock_unregister(BTPROTO_HCI);
BT_ERR("HCI socket unregistration failed");
proto_unregister(&hci_sk_proto); proto_unregister(&hci_sk_proto);
} }
...@@ -590,10 +590,8 @@ int __init bt_sysfs_init(void) ...@@ -590,10 +590,8 @@ int __init bt_sysfs_init(void)
bt_debugfs = debugfs_create_dir("bluetooth", NULL); bt_debugfs = debugfs_create_dir("bluetooth", NULL);
bt_class = class_create(THIS_MODULE, "bluetooth"); bt_class = class_create(THIS_MODULE, "bluetooth");
if (IS_ERR(bt_class))
return PTR_ERR(bt_class);
return 0; return PTR_RET(bt_class);
} }
void bt_sysfs_cleanup(void) void bt_sysfs_cleanup(void)
......
...@@ -311,6 +311,9 @@ static int hidp_get_raw_report(struct hid_device *hid, ...@@ -311,6 +311,9 @@ static int hidp_get_raw_report(struct hid_device *hid,
int numbered_reports = hid->report_enum[report_type].numbered; int numbered_reports = hid->report_enum[report_type].numbered;
int ret; int ret;
if (atomic_read(&session->terminate))
return -EIO;
switch (report_type) { switch (report_type) {
case HID_FEATURE_REPORT: case HID_FEATURE_REPORT:
report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE; report_type = HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE;
...@@ -722,6 +725,7 @@ static int hidp_session(void *arg) ...@@ -722,6 +725,7 @@ static int hidp_session(void *arg)
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
} }
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
atomic_inc(&session->terminate);
remove_wait_queue(sk_sleep(intr_sk), &intr_wait); remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait); remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
......
...@@ -304,8 +304,6 @@ int __init hidp_init_sockets(void) ...@@ -304,8 +304,6 @@ int __init hidp_init_sockets(void)
void __exit hidp_cleanup_sockets(void) void __exit hidp_cleanup_sockets(void)
{ {
bt_procfs_cleanup(&init_net, "hidp"); bt_procfs_cleanup(&init_net, "hidp");
if (bt_sock_unregister(BTPROTO_HIDP) < 0) bt_sock_unregister(BTPROTO_HIDP);
BT_ERR("Can't unregister HIDP socket");
proto_unregister(&hidp_proto); proto_unregister(&hidp_proto);
} }
...@@ -1312,8 +1312,6 @@ int __init l2cap_init_sockets(void) ...@@ -1312,8 +1312,6 @@ int __init l2cap_init_sockets(void)
void l2cap_cleanup_sockets(void) void l2cap_cleanup_sockets(void)
{ {
bt_procfs_cleanup(&init_net, "l2cap"); bt_procfs_cleanup(&init_net, "l2cap");
if (bt_sock_unregister(BTPROTO_L2CAP) < 0) bt_sock_unregister(BTPROTO_L2CAP);
BT_ERR("L2CAP socket unregistration failed");
proto_unregister(&l2cap_proto); proto_unregister(&l2cap_proto);
} }
...@@ -384,6 +384,7 @@ static u32 get_supported_settings(struct hci_dev *hdev) ...@@ -384,6 +384,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (lmp_bredr_capable(hdev)) { if (lmp_bredr_capable(hdev)) {
settings |= MGMT_SETTING_CONNECTABLE; settings |= MGMT_SETTING_CONNECTABLE;
if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
settings |= MGMT_SETTING_FAST_CONNECTABLE; settings |= MGMT_SETTING_FAST_CONNECTABLE;
settings |= MGMT_SETTING_DISCOVERABLE; settings |= MGMT_SETTING_DISCOVERABLE;
settings |= MGMT_SETTING_BREDR; settings |= MGMT_SETTING_BREDR;
...@@ -409,6 +410,9 @@ static u32 get_current_settings(struct hci_dev *hdev) ...@@ -409,6 +410,9 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
settings |= MGMT_SETTING_CONNECTABLE; settings |= MGMT_SETTING_CONNECTABLE;
if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
settings |= MGMT_SETTING_FAST_CONNECTABLE;
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
settings |= MGMT_SETTING_DISCOVERABLE; settings |= MGMT_SETTING_DISCOVERABLE;
...@@ -591,32 +595,33 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ...@@ -591,32 +595,33 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data)); ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
} }
static int update_eir(struct hci_dev *hdev) static void update_eir(struct hci_request *req)
{ {
struct hci_dev *hdev = req->hdev;
struct hci_cp_write_eir cp; struct hci_cp_write_eir cp;
if (!hdev_is_powered(hdev)) if (!hdev_is_powered(hdev))
return 0; return;
if (!lmp_ext_inq_capable(hdev)) if (!lmp_ext_inq_capable(hdev))
return 0; return;
if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
return 0; return;
if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
return 0; return;
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
create_eir(hdev, cp.data); create_eir(hdev, cp.data);
if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
return 0; return;
memcpy(hdev->eir, cp.data, sizeof(cp.data)); memcpy(hdev->eir, cp.data, sizeof(cp.data));
return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
} }
static u8 get_service_classes(struct hci_dev *hdev) static u8 get_service_classes(struct hci_dev *hdev)
...@@ -630,47 +635,48 @@ static u8 get_service_classes(struct hci_dev *hdev) ...@@ -630,47 +635,48 @@ static u8 get_service_classes(struct hci_dev *hdev)
return val; return val;
} }
static int update_class(struct hci_dev *hdev) static void update_class(struct hci_request *req)
{ {
struct hci_dev *hdev = req->hdev;
u8 cod[3]; u8 cod[3];
int err;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (!hdev_is_powered(hdev)) if (!hdev_is_powered(hdev))
return 0; return;
if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
return 0; return;
cod[0] = hdev->minor_class; cod[0] = hdev->minor_class;
cod[1] = hdev->major_class; cod[1] = hdev->major_class;
cod[2] = get_service_classes(hdev); cod[2] = get_service_classes(hdev);
if (memcmp(cod, hdev->dev_class, 3) == 0) if (memcmp(cod, hdev->dev_class, 3) == 0)
return 0; return;
err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
if (err == 0)
set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
return err; hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
} }
static void service_cache_off(struct work_struct *work) static void service_cache_off(struct work_struct *work)
{ {
struct hci_dev *hdev = container_of(work, struct hci_dev, struct hci_dev *hdev = container_of(work, struct hci_dev,
service_cache.work); service_cache.work);
struct hci_request req;
if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
return; return;
hci_req_init(&req, hdev);
hci_dev_lock(hdev); hci_dev_lock(hdev);
update_eir(hdev); update_eir(&req);
update_class(hdev); update_class(&req);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
hci_req_run(&req, NULL);
} }
static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev) static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
...@@ -994,11 +1000,64 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -994,11 +1000,64 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
return err; return err;
} }
static void write_fast_connectable(struct hci_request *req, bool enable)
{
struct hci_dev *hdev = req->hdev;
struct hci_cp_write_page_scan_activity acp;
u8 type;
if (hdev->hci_ver < BLUETOOTH_VER_1_2)
return;
if (enable) {
type = PAGE_SCAN_TYPE_INTERLACED;
/* 160 msec page scan interval */
acp.interval = __constant_cpu_to_le16(0x0100);
} else {
type = PAGE_SCAN_TYPE_STANDARD; /* default */
/* default 1.28 sec page scan */
acp.interval = __constant_cpu_to_le16(0x0800);
}
acp.window = __constant_cpu_to_le16(0x0012);
if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
__cpu_to_le16(hdev->page_scan_window) != acp.window)
hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
sizeof(acp), &acp);
if (hdev->page_scan_type != type)
hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
}
static void set_connectable_complete(struct hci_dev *hdev, u8 status)
{
struct pending_cmd *cmd;
BT_DBG("status 0x%02x", status);
hci_dev_lock(hdev);
cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
if (!cmd)
goto unlock;
send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
mgmt_pending_remove(cmd);
unlock:
hci_dev_unlock(hdev);
}
static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len) u16 len)
{ {
struct mgmt_mode *cp = data; struct mgmt_mode *cp = data;
struct pending_cmd *cmd; struct pending_cmd *cmd;
struct hci_request req;
u8 scan; u8 scan;
int err; int err;
...@@ -1065,7 +1124,20 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -1065,7 +1124,20 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
cancel_delayed_work(&hdev->discov_off); cancel_delayed_work(&hdev->discov_off);
} }
err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); hci_req_init(&req, hdev);
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
/* If we're going from non-connectable to connectable or
* vice-versa when fast connectable is enabled ensure that fast
* connectable gets disabled. write_fast_connectable won't do
* anything if the page scan parameters are already what they
* should be.
*/
if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
write_fast_connectable(&req, false);
err = hci_req_run(&req, set_connectable_complete);
if (err < 0) if (err < 0)
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
...@@ -1332,6 +1404,29 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) ...@@ -1332,6 +1404,29 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
return err; return err;
} }
/* This is a helper function to test for pending mgmt commands that can
* cause CoD or EIR HCI commands. We can only allow one such pending
* mgmt command at a time since otherwise we cannot easily track what
* the current values are, will be, and based on that calculate if a new
* HCI command needs to be sent and if yes with what value.
*/
static bool pending_eir_or_class(struct hci_dev *hdev)
{
struct pending_cmd *cmd;
list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
switch (cmd->opcode) {
case MGMT_OP_ADD_UUID:
case MGMT_OP_REMOVE_UUID:
case MGMT_OP_SET_DEV_CLASS:
case MGMT_OP_SET_POWERED:
return true;
}
}
return false;
}
static const u8 bluetooth_base_uuid[] = { static const u8 bluetooth_base_uuid[] = {
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
...@@ -1351,10 +1446,37 @@ static u8 get_uuid_size(const u8 *uuid) ...@@ -1351,10 +1446,37 @@ static u8 get_uuid_size(const u8 *uuid)
return 16; return 16;
} }
static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
{
struct pending_cmd *cmd;
hci_dev_lock(hdev);
cmd = mgmt_pending_find(mgmt_op, hdev);
if (!cmd)
goto unlock;
cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
hdev->dev_class, 3);
mgmt_pending_remove(cmd);
unlock:
hci_dev_unlock(hdev);
}
static void add_uuid_complete(struct hci_dev *hdev, u8 status)
{
BT_DBG("status 0x%02x", status);
mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
}
static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
{ {
struct mgmt_cp_add_uuid *cp = data; struct mgmt_cp_add_uuid *cp = data;
struct pending_cmd *cmd; struct pending_cmd *cmd;
struct hci_request req;
struct bt_uuid *uuid; struct bt_uuid *uuid;
int err; int err;
...@@ -1362,7 +1484,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) ...@@ -1362,7 +1484,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { if (pending_eir_or_class(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID, err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
MGMT_STATUS_BUSY); MGMT_STATUS_BUSY);
goto failed; goto failed;
...@@ -1380,23 +1502,28 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) ...@@ -1380,23 +1502,28 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
list_add_tail(&uuid->list, &hdev->uuids); list_add_tail(&uuid->list, &hdev->uuids);
err = update_class(hdev); hci_req_init(&req, hdev);
if (err < 0)
goto failed;
err = update_eir(hdev); update_class(&req);
if (err < 0) update_eir(&req);
err = hci_req_run(&req, add_uuid_complete);
if (err < 0) {
if (err != -ENODATA)
goto failed; goto failed;
if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0, err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
hdev->dev_class, 3); hdev->dev_class, 3);
goto failed; goto failed;
} }
cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len); cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
if (!cmd) if (!cmd) {
err = -ENOMEM; err = -ENOMEM;
goto failed;
}
err = 0;
failed: failed:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -1417,6 +1544,13 @@ static bool enable_service_cache(struct hci_dev *hdev) ...@@ -1417,6 +1544,13 @@ static bool enable_service_cache(struct hci_dev *hdev)
return false; return false;
} }
static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
{
BT_DBG("status 0x%02x", status);
mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
}
static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len) u16 len)
{ {
...@@ -1424,13 +1558,14 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -1424,13 +1558,14 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
struct pending_cmd *cmd; struct pending_cmd *cmd;
struct bt_uuid *match, *tmp; struct bt_uuid *match, *tmp;
u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
struct hci_request req;
int err, found; int err, found;
BT_DBG("request for %s", hdev->name); BT_DBG("request for %s", hdev->name);
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) { if (pending_eir_or_class(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID, err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
MGMT_STATUS_BUSY); MGMT_STATUS_BUSY);
goto unlock; goto unlock;
...@@ -1466,34 +1601,47 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -1466,34 +1601,47 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
} }
update_class: update_class:
err = update_class(hdev); hci_req_init(&req, hdev);
if (err < 0)
goto unlock;
err = update_eir(hdev); update_class(&req);
if (err < 0) update_eir(&req);
err = hci_req_run(&req, remove_uuid_complete);
if (err < 0) {
if (err != -ENODATA)
goto unlock; goto unlock;
if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0, err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
hdev->dev_class, 3); hdev->dev_class, 3);
goto unlock; goto unlock;
} }
cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len); cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
if (!cmd) if (!cmd) {
err = -ENOMEM; err = -ENOMEM;
goto unlock;
}
err = 0;
unlock: unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
return err; return err;
} }
static void set_class_complete(struct hci_dev *hdev, u8 status)
{
BT_DBG("status 0x%02x", status);
mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
}
static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len) u16 len)
{ {
struct mgmt_cp_set_dev_class *cp = data; struct mgmt_cp_set_dev_class *cp = data;
struct pending_cmd *cmd; struct pending_cmd *cmd;
struct hci_request req;
int err; int err;
BT_DBG("request for %s", hdev->name); BT_DBG("request for %s", hdev->name);
...@@ -1502,15 +1650,19 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -1502,15 +1650,19 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
MGMT_STATUS_NOT_SUPPORTED); MGMT_STATUS_NOT_SUPPORTED);
if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) hci_dev_lock(hdev);
return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
if (pending_eir_or_class(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
MGMT_STATUS_BUSY); MGMT_STATUS_BUSY);
goto unlock;
}
if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
MGMT_STATUS_INVALID_PARAMS); MGMT_STATUS_INVALID_PARAMS);
goto unlock;
hci_dev_lock(hdev); }
hdev->major_class = cp->major; hdev->major_class = cp->major;
hdev->minor_class = cp->minor; hdev->minor_class = cp->minor;
...@@ -1521,26 +1673,34 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -1521,26 +1673,34 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
goto unlock; goto unlock;
} }
hci_req_init(&req, hdev);
if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) { if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
cancel_delayed_work_sync(&hdev->service_cache); cancel_delayed_work_sync(&hdev->service_cache);
hci_dev_lock(hdev); hci_dev_lock(hdev);
update_eir(hdev); update_eir(&req);
} }
err = update_class(hdev); update_class(&req);
if (err < 0)
err = hci_req_run(&req, set_class_complete);
if (err < 0) {
if (err != -ENODATA)
goto unlock; goto unlock;
if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
hdev->dev_class, 3); hdev->dev_class, 3);
goto unlock; goto unlock;
} }
cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len); cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
if (!cmd) if (!cmd) {
err = -ENOMEM; err = -ENOMEM;
goto unlock;
}
err = 0;
unlock: unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
...@@ -2140,7 +2300,7 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2140,7 +2300,7 @@ static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
} }
static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 type, u16 mgmt_op, struct mgmt_addr_info *addr, u16 mgmt_op,
u16 hci_op, __le32 passkey) u16 hci_op, __le32 passkey)
{ {
struct pending_cmd *cmd; struct pending_cmd *cmd;
...@@ -2150,37 +2310,41 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, ...@@ -2150,37 +2310,41 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) { if (!hdev_is_powered(hdev)) {
err = cmd_status(sk, hdev->id, mgmt_op, err = cmd_complete(sk, hdev->id, mgmt_op,
MGMT_STATUS_NOT_POWERED); MGMT_STATUS_NOT_POWERED, addr,
sizeof(*addr));
goto done; goto done;
} }
if (type == BDADDR_BREDR) if (addr->type == BDADDR_BREDR)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
else else
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
if (!conn) { if (!conn) {
err = cmd_status(sk, hdev->id, mgmt_op, err = cmd_complete(sk, hdev->id, mgmt_op,
MGMT_STATUS_NOT_CONNECTED); MGMT_STATUS_NOT_CONNECTED, addr,
sizeof(*addr));
goto done; goto done;
} }
if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) { if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
/* Continue with pairing via SMP */ /* Continue with pairing via SMP */
err = smp_user_confirm_reply(conn, mgmt_op, passkey); err = smp_user_confirm_reply(conn, mgmt_op, passkey);
if (!err) if (!err)
err = cmd_status(sk, hdev->id, mgmt_op, err = cmd_complete(sk, hdev->id, mgmt_op,
MGMT_STATUS_SUCCESS); MGMT_STATUS_SUCCESS, addr,
sizeof(*addr));
else else
err = cmd_status(sk, hdev->id, mgmt_op, err = cmd_complete(sk, hdev->id, mgmt_op,
MGMT_STATUS_FAILED); MGMT_STATUS_FAILED, addr,
sizeof(*addr));
goto done; goto done;
} }
cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr)); cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
if (!cmd) { if (!cmd) {
err = -ENOMEM; err = -ENOMEM;
goto done; goto done;
...@@ -2190,11 +2354,12 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, ...@@ -2190,11 +2354,12 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
if (hci_op == HCI_OP_USER_PASSKEY_REPLY) { if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
struct hci_cp_user_passkey_reply cp; struct hci_cp_user_passkey_reply cp;
bacpy(&cp.bdaddr, bdaddr); bacpy(&cp.bdaddr, &addr->bdaddr);
cp.passkey = passkey; cp.passkey = passkey;
err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp); err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
} else } else
err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr); err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
&addr->bdaddr);
if (err < 0) if (err < 0)
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
...@@ -2211,7 +2376,7 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, ...@@ -2211,7 +2376,7 @@ static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
BT_DBG(""); BT_DBG("");
return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_PIN_CODE_NEG_REPLY, MGMT_OP_PIN_CODE_NEG_REPLY,
HCI_OP_PIN_CODE_NEG_REPLY, 0); HCI_OP_PIN_CODE_NEG_REPLY, 0);
} }
...@@ -2227,7 +2392,7 @@ static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2227,7 +2392,7 @@ static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY, return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
MGMT_STATUS_INVALID_PARAMS); MGMT_STATUS_INVALID_PARAMS);
return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_CONFIRM_REPLY, MGMT_OP_USER_CONFIRM_REPLY,
HCI_OP_USER_CONFIRM_REPLY, 0); HCI_OP_USER_CONFIRM_REPLY, 0);
} }
...@@ -2239,7 +2404,7 @@ static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev, ...@@ -2239,7 +2404,7 @@ static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
BT_DBG(""); BT_DBG("");
return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_CONFIRM_NEG_REPLY, MGMT_OP_USER_CONFIRM_NEG_REPLY,
HCI_OP_USER_CONFIRM_NEG_REPLY, 0); HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
} }
...@@ -2251,7 +2416,7 @@ static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2251,7 +2416,7 @@ static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG(""); BT_DBG("");
return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_PASSKEY_REPLY, MGMT_OP_USER_PASSKEY_REPLY,
HCI_OP_USER_PASSKEY_REPLY, cp->passkey); HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
} }
...@@ -2263,18 +2428,47 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev, ...@@ -2263,18 +2428,47 @@ static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
BT_DBG(""); BT_DBG("");
return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, return user_pairing_resp(sk, hdev, &cp->addr,
MGMT_OP_USER_PASSKEY_NEG_REPLY, MGMT_OP_USER_PASSKEY_NEG_REPLY,
HCI_OP_USER_PASSKEY_NEG_REPLY, 0); HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
} }
static int update_name(struct hci_dev *hdev, const char *name) static void update_name(struct hci_request *req)
{ {
struct hci_dev *hdev = req->hdev;
struct hci_cp_write_local_name cp; struct hci_cp_write_local_name cp;
memcpy(cp.name, name, sizeof(cp.name)); memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp); hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
}
static void set_name_complete(struct hci_dev *hdev, u8 status)
{
struct mgmt_cp_set_local_name *cp;
struct pending_cmd *cmd;
BT_DBG("status 0x%02x", status);
hci_dev_lock(hdev);
cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
if (!cmd)
goto unlock;
cp = cmd->param;
if (status)
cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
mgmt_status(status));
else
cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
cp, sizeof(*cp));
mgmt_pending_remove(cmd);
unlock:
hci_dev_unlock(hdev);
} }
static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
...@@ -2282,12 +2476,24 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2282,12 +2476,24 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
{ {
struct mgmt_cp_set_local_name *cp = data; struct mgmt_cp_set_local_name *cp = data;
struct pending_cmd *cmd; struct pending_cmd *cmd;
struct hci_request req;
int err; int err;
BT_DBG(""); BT_DBG("");
hci_dev_lock(hdev); hci_dev_lock(hdev);
/* If the old values are the same as the new ones just return a
* direct command complete event.
*/
if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
!memcmp(hdev->short_name, cp->short_name,
sizeof(hdev->short_name))) {
err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
data, len);
goto failed;
}
memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name)); memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
if (!hdev_is_powered(hdev)) { if (!hdev_is_powered(hdev)) {
...@@ -2310,7 +2516,19 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2310,7 +2516,19 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
goto failed; goto failed;
} }
err = update_name(hdev, cp->name); memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
hci_req_init(&req, hdev);
if (lmp_bredr_capable(hdev)) {
update_name(&req);
update_eir(&req);
}
if (lmp_le_capable(hdev))
hci_update_ad(&req);
err = hci_req_run(&req, set_name_complete);
if (err < 0) if (err < 0)
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
...@@ -2698,6 +2916,7 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2698,6 +2916,7 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
u16 len) u16 len)
{ {
struct mgmt_cp_set_device_id *cp = data; struct mgmt_cp_set_device_id *cp = data;
struct hci_request req;
int err; int err;
__u16 source; __u16 source;
...@@ -2718,24 +2937,59 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -2718,24 +2937,59 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0); err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
update_eir(hdev); hci_req_init(&req, hdev);
update_eir(&req);
hci_req_run(&req, NULL);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
return err; return err;
} }
static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
{
struct pending_cmd *cmd;
BT_DBG("status 0x%02x", status);
hci_dev_lock(hdev);
cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
if (!cmd)
goto unlock;
if (status) {
cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
mgmt_status(status));
} else {
struct mgmt_mode *cp = cmd->param;
if (cp->val)
set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
else
clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
new_settings(hdev, cmd->sk);
}
mgmt_pending_remove(cmd);
unlock:
hci_dev_unlock(hdev);
}
static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len) void *data, u16 len)
{ {
struct mgmt_mode *cp = data; struct mgmt_mode *cp = data;
struct hci_cp_write_page_scan_activity acp; struct pending_cmd *cmd;
u8 type; struct hci_request req;
int err; int err;
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (!lmp_bredr_capable(hdev)) if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_STATUS_NOT_SUPPORTED); MGMT_STATUS_NOT_SUPPORTED);
...@@ -2753,40 +3007,39 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, ...@@ -2753,40 +3007,39 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev); hci_dev_lock(hdev);
if (cp->val) { if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
type = PAGE_SCAN_TYPE_INTERLACED; err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_STATUS_BUSY);
goto unlock;
}
/* 160 msec page scan interval */ if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
acp.interval = __constant_cpu_to_le16(0x0100); err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
} else { hdev);
type = PAGE_SCAN_TYPE_STANDARD; /* default */ goto unlock;
}
/* default 1.28 sec page scan */ cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
acp.interval = __constant_cpu_to_le16(0x0800); data, len);
if (!cmd) {
err = -ENOMEM;
goto unlock;
} }
/* default 11.25 msec page scan window */ hci_req_init(&req, hdev);
acp.window = __constant_cpu_to_le16(0x0012);
err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp), write_fast_connectable(&req, cp->val);
&acp);
if (err < 0) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_STATUS_FAILED);
goto done;
}
err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type); err = hci_req_run(&req, fast_connectable_complete);
if (err < 0) { if (err < 0) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
MGMT_STATUS_FAILED); MGMT_STATUS_FAILED);
goto done; mgmt_pending_remove(cmd);
} }
err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0, unlock:
NULL, 0);
done:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
return err; return err;
} }
...@@ -3043,39 +3296,56 @@ static void settings_rsp(struct pending_cmd *cmd, void *data) ...@@ -3043,39 +3296,56 @@ static void settings_rsp(struct pending_cmd *cmd, void *data)
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
} }
static int set_bredr_scan(struct hci_dev *hdev) static void set_bredr_scan(struct hci_request *req)
{ {
struct hci_dev *hdev = req->hdev;
u8 scan = 0; u8 scan = 0;
/* Ensure that fast connectable is disabled. This function will
* not do anything if the page scan parameters are already what
* they should be.
*/
write_fast_connectable(req, false);
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
scan |= SCAN_PAGE; scan |= SCAN_PAGE;
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
scan |= SCAN_INQUIRY; scan |= SCAN_INQUIRY;
if (!scan) if (scan)
return 0; hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
} }
int mgmt_powered(struct hci_dev *hdev, u8 powered) static void powered_complete(struct hci_dev *hdev, u8 status)
{ {
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
int err;
if (!test_bit(HCI_MGMT, &hdev->dev_flags)) BT_DBG("status 0x%02x", status);
return 0;
hci_dev_lock(hdev);
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
if (powered) { new_settings(hdev, match.sk);
hci_dev_unlock(hdev);
if (match.sk)
sock_put(match.sk);
}
static int powered_update_hci(struct hci_dev *hdev)
{
struct hci_request req;
u8 link_sec; u8 link_sec;
hci_req_init(&req, hdev);
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
!lmp_host_ssp_capable(hdev)) { !lmp_host_ssp_capable(hdev)) {
u8 ssp = 1; u8 ssp = 1;
hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp); hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
} }
if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
...@@ -3089,33 +3359,52 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered) ...@@ -3089,33 +3359,52 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
*/ */
if (cp.le != lmp_host_le_capable(hdev) || if (cp.le != lmp_host_le_capable(hdev) ||
cp.simul != lmp_host_le_br_capable(hdev)) cp.simul != lmp_host_le_br_capable(hdev))
hci_send_cmd(hdev, hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
HCI_OP_WRITE_LE_HOST_SUPPORTED,
sizeof(cp), &cp); sizeof(cp), &cp);
} }
link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags); link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
if (link_sec != test_bit(HCI_AUTH, &hdev->flags)) if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
sizeof(link_sec), &link_sec); sizeof(link_sec), &link_sec);
if (lmp_bredr_capable(hdev)) { if (lmp_bredr_capable(hdev)) {
set_bredr_scan(hdev); set_bredr_scan(&req);
update_class(hdev); update_class(&req);
update_name(hdev, hdev->dev_name); update_name(&req);
update_eir(hdev); update_eir(&req);
} }
} else {
u8 status = MGMT_STATUS_NOT_POWERED; return hci_req_run(&req, powered_complete);
}
int mgmt_powered(struct hci_dev *hdev, u8 powered)
{
struct cmd_lookup match = { NULL, hdev };
u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
u8 zero_cod[] = { 0, 0, 0 }; u8 zero_cod[] = { 0, 0, 0 };
int err;
mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status); if (!test_bit(HCI_MGMT, &hdev->dev_flags))
return 0;
if (powered) {
if (powered_update_hci(hdev) == 0)
return 0;
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
&match);
goto new_settings;
}
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
zero_cod, sizeof(zero_cod), NULL); zero_cod, sizeof(zero_cod), NULL);
}
new_settings:
err = new_settings(hdev, match.sk); err = new_settings(hdev, match.sk);
if (match.sk) if (match.sk)
...@@ -3152,7 +3441,7 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable) ...@@ -3152,7 +3441,7 @@ int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
int mgmt_connectable(struct hci_dev *hdev, u8 connectable) int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
{ {
struct cmd_lookup match = { NULL, hdev }; struct pending_cmd *cmd;
bool changed = false; bool changed = false;
int err = 0; int err = 0;
...@@ -3164,14 +3453,10 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable) ...@@ -3164,14 +3453,10 @@ int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
changed = true; changed = true;
} }
mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp, cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
&match);
if (changed) if (changed)
err = new_settings(hdev, match.sk); err = new_settings(hdev, cmd ? cmd->sk : NULL);
if (match.sk)
sock_put(match.sk);
return err; return err;
} }
...@@ -3555,23 +3840,25 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status) ...@@ -3555,23 +3840,25 @@ int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
return err; return err;
} }
static int clear_eir(struct hci_dev *hdev) static void clear_eir(struct hci_request *req)
{ {
struct hci_dev *hdev = req->hdev;
struct hci_cp_write_eir cp; struct hci_cp_write_eir cp;
if (!lmp_ext_inq_capable(hdev)) if (!lmp_ext_inq_capable(hdev))
return 0; return;
memset(hdev->eir, 0, sizeof(hdev->eir)); memset(hdev->eir, 0, sizeof(hdev->eir));
memset(&cp, 0, sizeof(cp)); memset(&cp, 0, sizeof(cp));
return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
} }
int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
{ {
struct cmd_lookup match = { NULL, hdev }; struct cmd_lookup match = { NULL, hdev };
struct hci_request req;
bool changed = false; bool changed = false;
int err = 0; int err = 0;
...@@ -3604,29 +3891,26 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) ...@@ -3604,29 +3891,26 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
if (match.sk) if (match.sk)
sock_put(match.sk); sock_put(match.sk);
hci_req_init(&req, hdev);
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
update_eir(hdev); update_eir(&req);
else else
clear_eir(hdev); clear_eir(&req);
hci_req_run(&req, NULL);
return err; return err;
} }
static void class_rsp(struct pending_cmd *cmd, void *data) static void sk_lookup(struct pending_cmd *cmd, void *data)
{ {
struct cmd_lookup *match = data; struct cmd_lookup *match = data;
cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
match->hdev->dev_class, 3);
list_del(&cmd->list);
if (match->sk == NULL) { if (match->sk == NULL) {
match->sk = cmd->sk; match->sk = cmd->sk;
sock_hold(match->sk); sock_hold(match->sk);
} }
mgmt_pending_free(cmd);
} }
int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
...@@ -3635,11 +3919,9 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, ...@@ -3635,11 +3919,9 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
int err = 0; int err = 0;
clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags); mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match); mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
if (!status) if (!status)
err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
...@@ -3653,55 +3935,29 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, ...@@ -3653,55 +3935,29 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status) int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
{ {
struct pending_cmd *cmd;
struct mgmt_cp_set_local_name ev; struct mgmt_cp_set_local_name ev;
bool changed = false; struct pending_cmd *cmd;
int err = 0;
if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) { if (status)
memcpy(hdev->dev_name, name, sizeof(hdev->dev_name)); return 0;
changed = true;
}
memset(&ev, 0, sizeof(ev)); memset(&ev, 0, sizeof(ev));
memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH); memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev); cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
if (!cmd) if (!cmd) {
goto send_event; memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
/* Always assume that either the short or the complete name has
* changed if there was a pending mgmt command */
changed = true;
if (status) {
err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
mgmt_status(status));
goto failed;
}
err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
sizeof(ev));
if (err < 0)
goto failed;
send_event:
if (changed)
err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
sizeof(ev), cmd ? cmd->sk : NULL);
/* EIR is taken care of separately when powering on the /* If this is a HCI command related to powering on the
* adapter so only update them here if this is a name change * HCI dev don't send any mgmt signals.
* unrelated to power on.
*/ */
if (!test_bit(HCI_INIT, &hdev->flags)) if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
update_eir(hdev); return 0;
}
failed: return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
if (cmd) cmd ? cmd->sk : NULL);
mgmt_pending_remove(cmd);
return err;
} }
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
......
...@@ -69,7 +69,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, ...@@ -69,7 +69,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
u8 sec_level, u8 sec_level,
int *err); int *err);
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst); static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
static void rfcomm_session_del(struct rfcomm_session *s); static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
/* ---- RFCOMM frame parsing macros ---- */ /* ---- RFCOMM frame parsing macros ---- */
#define __get_dlci(b) ((b & 0xfc) >> 2) #define __get_dlci(b) ((b & 0xfc) >> 2)
...@@ -108,12 +108,6 @@ static void rfcomm_schedule(void) ...@@ -108,12 +108,6 @@ static void rfcomm_schedule(void)
wake_up_process(rfcomm_thread); wake_up_process(rfcomm_thread);
} }
static void rfcomm_session_put(struct rfcomm_session *s)
{
if (atomic_dec_and_test(&s->refcnt))
rfcomm_session_del(s);
}
/* ---- RFCOMM FCS computation ---- */ /* ---- RFCOMM FCS computation ---- */
/* reversed, 8-bit, poly=0x07 */ /* reversed, 8-bit, poly=0x07 */
...@@ -249,16 +243,14 @@ static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout) ...@@ -249,16 +243,14 @@ static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
{ {
BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout); BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout);
if (!mod_timer(&s->timer, jiffies + timeout)) mod_timer(&s->timer, jiffies + timeout);
rfcomm_session_hold(s);
} }
static void rfcomm_session_clear_timer(struct rfcomm_session *s) static void rfcomm_session_clear_timer(struct rfcomm_session *s)
{ {
BT_DBG("session %p state %ld", s, s->state); BT_DBG("session %p state %ld", s, s->state);
if (del_timer(&s->timer)) del_timer_sync(&s->timer);
rfcomm_session_put(s);
} }
/* ---- RFCOMM DLCs ---- */ /* ---- RFCOMM DLCs ---- */
...@@ -336,8 +328,6 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d) ...@@ -336,8 +328,6 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
{ {
BT_DBG("dlc %p session %p", d, s); BT_DBG("dlc %p session %p", d, s);
rfcomm_session_hold(s);
rfcomm_session_clear_timer(s); rfcomm_session_clear_timer(s);
rfcomm_dlc_hold(d); rfcomm_dlc_hold(d);
list_add(&d->list, &s->dlcs); list_add(&d->list, &s->dlcs);
...@@ -356,8 +346,6 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d) ...@@ -356,8 +346,6 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
if (list_empty(&s->dlcs)) if (list_empty(&s->dlcs))
rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT); rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT);
rfcomm_session_put(s);
} }
static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci) static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
...@@ -493,12 +481,34 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) ...@@ -493,12 +481,34 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
int rfcomm_dlc_close(struct rfcomm_dlc *d, int err) int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
{ {
int r; int r = 0;
struct rfcomm_dlc *d_list;
struct rfcomm_session *s, *s_list;
BT_DBG("dlc %p state %ld dlci %d err %d", d, d->state, d->dlci, err);
rfcomm_lock(); rfcomm_lock();
s = d->session;
if (!s)
goto no_session;
/* after waiting on the mutex check the session still exists
* then check the dlc still exists
*/
list_for_each_entry(s_list, &session_list, list) {
if (s_list == s) {
list_for_each_entry(d_list, &s->dlcs, list) {
if (d_list == d) {
r = __rfcomm_dlc_close(d, err); r = __rfcomm_dlc_close(d, err);
break;
}
}
break;
}
}
no_session:
rfcomm_unlock(); rfcomm_unlock();
return r; return r;
} }
...@@ -609,7 +619,7 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) ...@@ -609,7 +619,7 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
return s; return s;
} }
static void rfcomm_session_del(struct rfcomm_session *s) static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s)
{ {
int state = s->state; int state = s->state;
...@@ -617,15 +627,14 @@ static void rfcomm_session_del(struct rfcomm_session *s) ...@@ -617,15 +627,14 @@ static void rfcomm_session_del(struct rfcomm_session *s)
list_del(&s->list); list_del(&s->list);
if (state == BT_CONNECTED)
rfcomm_send_disc(s, 0);
rfcomm_session_clear_timer(s); rfcomm_session_clear_timer(s);
sock_release(s->sock); sock_release(s->sock);
kfree(s); kfree(s);
if (state != BT_LISTEN) if (state != BT_LISTEN)
module_put(THIS_MODULE); module_put(THIS_MODULE);
return NULL;
} }
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
...@@ -644,17 +653,16 @@ static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) ...@@ -644,17 +653,16 @@ static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
return NULL; return NULL;
} }
static void rfcomm_session_close(struct rfcomm_session *s, int err) static struct rfcomm_session *rfcomm_session_close(struct rfcomm_session *s,
int err)
{ {
struct rfcomm_dlc *d; struct rfcomm_dlc *d;
struct list_head *p, *n; struct list_head *p, *n;
BT_DBG("session %p state %ld err %d", s, s->state, err);
rfcomm_session_hold(s);
s->state = BT_CLOSED; s->state = BT_CLOSED;
BT_DBG("session %p state %ld err %d", s, s->state, err);
/* Close all dlcs */ /* Close all dlcs */
list_for_each_safe(p, n, &s->dlcs) { list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list); d = list_entry(p, struct rfcomm_dlc, list);
...@@ -663,7 +671,7 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err) ...@@ -663,7 +671,7 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
} }
rfcomm_session_clear_timer(s); rfcomm_session_clear_timer(s);
rfcomm_session_put(s); return rfcomm_session_del(s);
} }
static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
...@@ -715,8 +723,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, ...@@ -715,8 +723,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
if (*err == 0 || *err == -EINPROGRESS) if (*err == 0 || *err == -EINPROGRESS)
return s; return s;
rfcomm_session_del(s); return rfcomm_session_del(s);
return NULL;
failed: failed:
sock_release(sock); sock_release(sock);
...@@ -1105,7 +1112,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) ...@@ -1105,7 +1112,7 @@ static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
} }
/* ---- RFCOMM frame reception ---- */ /* ---- RFCOMM frame reception ---- */
static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) static struct rfcomm_session *rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
{ {
BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
...@@ -1114,7 +1121,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) ...@@ -1114,7 +1121,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
if (!d) { if (!d) {
rfcomm_send_dm(s, dlci); rfcomm_send_dm(s, dlci);
return 0; return s;
} }
switch (d->state) { switch (d->state) {
...@@ -1150,25 +1157,14 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) ...@@ -1150,25 +1157,14 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
break; break;
case BT_DISCONN: case BT_DISCONN:
/* rfcomm_session_put is called later so don't do s = rfcomm_session_close(s, ECONNRESET);
* anything here otherwise we will mess up the session
* reference counter:
*
* (a) when we are the initiator dlc_unlink will drive
* the reference counter to 0 (there is no initial put
* after session_add)
*
* (b) when we are not the initiator rfcomm_rx_process
* will explicitly call put to balance the initial hold
* done after session add.
*/
break; break;
} }
} }
return 0; return s;
} }
static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci) static struct rfcomm_session *rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
{ {
int err = 0; int err = 0;
...@@ -1192,13 +1188,13 @@ static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci) ...@@ -1192,13 +1188,13 @@ static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
else else
err = ECONNRESET; err = ECONNRESET;
s->state = BT_CLOSED; s = rfcomm_session_close(s, err);
rfcomm_session_close(s, err);
} }
return 0; return s;
} }
static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) static struct rfcomm_session *rfcomm_recv_disc(struct rfcomm_session *s,
u8 dlci)
{ {
int err = 0; int err = 0;
...@@ -1227,11 +1223,9 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) ...@@ -1227,11 +1223,9 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
else else
err = ECONNRESET; err = ECONNRESET;
s->state = BT_CLOSED; s = rfcomm_session_close(s, err);
rfcomm_session_close(s, err);
} }
return s;
return 0;
} }
void rfcomm_dlc_accept(struct rfcomm_dlc *d) void rfcomm_dlc_accept(struct rfcomm_dlc *d)
...@@ -1652,11 +1646,18 @@ static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk ...@@ -1652,11 +1646,18 @@ static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk
return 0; return 0;
} }
static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) static struct rfcomm_session *rfcomm_recv_frame(struct rfcomm_session *s,
struct sk_buff *skb)
{ {
struct rfcomm_hdr *hdr = (void *) skb->data; struct rfcomm_hdr *hdr = (void *) skb->data;
u8 type, dlci, fcs; u8 type, dlci, fcs;
if (!s) {
/* no session, so free socket data */
kfree_skb(skb);
return s;
}
dlci = __get_dlci(hdr->addr); dlci = __get_dlci(hdr->addr);
type = __get_type(hdr->ctrl); type = __get_type(hdr->ctrl);
...@@ -1667,7 +1668,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) ...@@ -1667,7 +1668,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
if (__check_fcs(skb->data, type, fcs)) { if (__check_fcs(skb->data, type, fcs)) {
BT_ERR("bad checksum in packet"); BT_ERR("bad checksum in packet");
kfree_skb(skb); kfree_skb(skb);
return -EILSEQ; return s;
} }
if (__test_ea(hdr->len)) if (__test_ea(hdr->len))
...@@ -1683,22 +1684,23 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) ...@@ -1683,22 +1684,23 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
case RFCOMM_DISC: case RFCOMM_DISC:
if (__test_pf(hdr->ctrl)) if (__test_pf(hdr->ctrl))
rfcomm_recv_disc(s, dlci); s = rfcomm_recv_disc(s, dlci);
break; break;
case RFCOMM_UA: case RFCOMM_UA:
if (__test_pf(hdr->ctrl)) if (__test_pf(hdr->ctrl))
rfcomm_recv_ua(s, dlci); s = rfcomm_recv_ua(s, dlci);
break; break;
case RFCOMM_DM: case RFCOMM_DM:
rfcomm_recv_dm(s, dlci); s = rfcomm_recv_dm(s, dlci);
break; break;
case RFCOMM_UIH: case RFCOMM_UIH:
if (dlci) if (dlci) {
return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb); rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
return s;
}
rfcomm_recv_mcc(s, skb); rfcomm_recv_mcc(s, skb);
break; break;
...@@ -1707,7 +1709,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) ...@@ -1707,7 +1709,7 @@ static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
break; break;
} }
kfree_skb(skb); kfree_skb(skb);
return 0; return s;
} }
/* ---- Connection and data processing ---- */ /* ---- Connection and data processing ---- */
...@@ -1844,7 +1846,7 @@ static void rfcomm_process_dlcs(struct rfcomm_session *s) ...@@ -1844,7 +1846,7 @@ static void rfcomm_process_dlcs(struct rfcomm_session *s)
} }
} }
static void rfcomm_process_rx(struct rfcomm_session *s) static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s)
{ {
struct socket *sock = s->sock; struct socket *sock = s->sock;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -1856,17 +1858,15 @@ static void rfcomm_process_rx(struct rfcomm_session *s) ...@@ -1856,17 +1858,15 @@ static void rfcomm_process_rx(struct rfcomm_session *s)
while ((skb = skb_dequeue(&sk->sk_receive_queue))) { while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb); skb_orphan(skb);
if (!skb_linearize(skb)) if (!skb_linearize(skb))
rfcomm_recv_frame(s, skb); s = rfcomm_recv_frame(s, skb);
else else
kfree_skb(skb); kfree_skb(skb);
} }
if (sk->sk_state == BT_CLOSED) { if (s && (sk->sk_state == BT_CLOSED))
if (!s->initiator) s = rfcomm_session_close(s, sk->sk_err);
rfcomm_session_put(s);
rfcomm_session_close(s, sk->sk_err); return s;
}
} }
static void rfcomm_accept_connection(struct rfcomm_session *s) static void rfcomm_accept_connection(struct rfcomm_session *s)
...@@ -1891,8 +1891,6 @@ static void rfcomm_accept_connection(struct rfcomm_session *s) ...@@ -1891,8 +1891,6 @@ static void rfcomm_accept_connection(struct rfcomm_session *s)
s = rfcomm_session_add(nsock, BT_OPEN); s = rfcomm_session_add(nsock, BT_OPEN);
if (s) { if (s) {
rfcomm_session_hold(s);
/* We should adjust MTU on incoming sessions. /* We should adjust MTU on incoming sessions.
* L2CAP MTU minus UIH header and FCS. */ * L2CAP MTU minus UIH header and FCS. */
s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu, s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
...@@ -1903,7 +1901,7 @@ static void rfcomm_accept_connection(struct rfcomm_session *s) ...@@ -1903,7 +1901,7 @@ static void rfcomm_accept_connection(struct rfcomm_session *s)
sock_release(nsock); sock_release(nsock);
} }
static void rfcomm_check_connection(struct rfcomm_session *s) static struct rfcomm_session *rfcomm_check_connection(struct rfcomm_session *s)
{ {
struct sock *sk = s->sock->sk; struct sock *sk = s->sock->sk;
...@@ -1921,10 +1919,10 @@ static void rfcomm_check_connection(struct rfcomm_session *s) ...@@ -1921,10 +1919,10 @@ static void rfcomm_check_connection(struct rfcomm_session *s)
break; break;
case BT_CLOSED: case BT_CLOSED:
s->state = BT_CLOSED; s = rfcomm_session_close(s, sk->sk_err);
rfcomm_session_close(s, sk->sk_err);
break; break;
} }
return s;
} }
static void rfcomm_process_sessions(void) static void rfcomm_process_sessions(void)
...@@ -1940,7 +1938,6 @@ static void rfcomm_process_sessions(void) ...@@ -1940,7 +1938,6 @@ static void rfcomm_process_sessions(void)
if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) { if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
s->state = BT_DISCONN; s->state = BT_DISCONN;
rfcomm_send_disc(s, 0); rfcomm_send_disc(s, 0);
rfcomm_session_put(s);
continue; continue;
} }
...@@ -1949,21 +1946,18 @@ static void rfcomm_process_sessions(void) ...@@ -1949,21 +1946,18 @@ static void rfcomm_process_sessions(void)
continue; continue;
} }
rfcomm_session_hold(s);
switch (s->state) { switch (s->state) {
case BT_BOUND: case BT_BOUND:
rfcomm_check_connection(s); s = rfcomm_check_connection(s);
break; break;
default: default:
rfcomm_process_rx(s); s = rfcomm_process_rx(s);
break; break;
} }
if (s)
rfcomm_process_dlcs(s); rfcomm_process_dlcs(s);
rfcomm_session_put(s);
} }
rfcomm_unlock(); rfcomm_unlock();
...@@ -2010,10 +2004,11 @@ static int rfcomm_add_listener(bdaddr_t *ba) ...@@ -2010,10 +2004,11 @@ static int rfcomm_add_listener(bdaddr_t *ba)
/* Add listening session */ /* Add listening session */
s = rfcomm_session_add(sock, BT_LISTEN); s = rfcomm_session_add(sock, BT_LISTEN);
if (!s) if (!s) {
err = -ENOMEM;
goto failed; goto failed;
}
rfcomm_session_hold(s);
return 0; return 0;
failed: failed:
sock_release(sock); sock_release(sock);
...@@ -2071,8 +2066,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) ...@@ -2071,8 +2066,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
if (!s) if (!s)
return; return;
rfcomm_session_hold(s);
list_for_each_safe(p, n, &s->dlcs) { list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list); d = list_entry(p, struct rfcomm_dlc, list);
...@@ -2104,8 +2097,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) ...@@ -2104,8 +2097,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
set_bit(RFCOMM_AUTH_REJECT, &d->flags); set_bit(RFCOMM_AUTH_REJECT, &d->flags);
} }
rfcomm_session_put(s);
rfcomm_schedule(); rfcomm_schedule();
} }
......
...@@ -1065,8 +1065,7 @@ void __exit rfcomm_cleanup_sockets(void) ...@@ -1065,8 +1065,7 @@ void __exit rfcomm_cleanup_sockets(void)
debugfs_remove(rfcomm_sock_debugfs); debugfs_remove(rfcomm_sock_debugfs);
if (bt_sock_unregister(BTPROTO_RFCOMM) < 0) bt_sock_unregister(BTPROTO_RFCOMM);
BT_ERR("RFCOMM socket layer unregistration failed");
proto_unregister(&rfcomm_proto); proto_unregister(&rfcomm_proto);
} }
...@@ -1111,8 +1111,7 @@ void __exit sco_exit(void) ...@@ -1111,8 +1111,7 @@ void __exit sco_exit(void)
debugfs_remove(sco_debugfs); debugfs_remove(sco_debugfs);
if (bt_sock_unregister(BTPROTO_SCO) < 0) bt_sock_unregister(BTPROTO_SCO);
BT_ERR("SCO socket unregistration failed");
proto_unregister(&sco_proto); proto_unregister(&sco_proto);
} }
......
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