Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
48b81cc1d9
21 changed files with 1338 additions and 998 deletions
|
@ -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.");
|
||||||
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 {
|
||||||
};
|
};
|
||||||
|
|
||||||
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 {
|
||||||
__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 {
|
||||||
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 {
|
||||||
__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 {
|
||||||
__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 {
|
||||||
__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,
|
||||||
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,
|
||||||
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,
|
||||||
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 {
|
||||||
#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 {
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
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 @@ error:
|
||||||
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 @@ error:
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
/* ---- 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
||||||
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,
|
||||||
|
|
||||||
/* 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, ¶m);
|
||||||
|
|
||||||
|
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
|
||||||
hci_dev_unlock(hdev);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- HCI ioctl helpers ---- */
|
/* ---- HCI ioctl helpers ---- */
|
||||||
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
hci_req_lock(hdev);
|
hci_req_lock(hdev);
|
||||||
|
|
||||||
err = __hci_request(hdev, le_scan_param_req, (unsigned long) ¶m,
|
err = __hci_req_sync(hdev, le_scan_param_req, (unsigned long) ¶m,
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, ¶m);
|
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
if (!rp->status)
|
if (!rp->status)
|
||||||
bacpy(&hdev->bdaddr, &rp->bdaddr);
|
bacpy(&hdev->bdaddr, &rp->bdaddr);
|
||||||
|
}
|
||||||
|
|
||||||
hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status);
|
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);
|
||||||
|
|
||||||
|
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,
|
||||||
|
|
||||||
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,
|
||||||
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 @@ a2mp_rsp:
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
|
clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!test_bit(HCI_INIT, &hdev->flags)) {
|
||||||
|
struct hci_request req;
|
||||||
|
|
||||||
|
hci_req_init(&req, hdev);
|
||||||
|
hci_update_ad(&req);
|
||||||
|
hci_req_run(&req, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
hci_dev_unlock(hdev);
|
hci_dev_unlock(hdev);
|
||||||
|
|
||||||
if (!test_bit(HCI_INIT, &hdev->flags))
|
|
||||||
hci_update_ad(hdev);
|
|
||||||
|
|
||||||
hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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 @@ unlock:
|
||||||
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)
|
||||||
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,12 +2263,24 @@ 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;
|
||||||
|
|
||||||
|
case HCI_OP_READ_PAGE_SCAN_TYPE:
|
||||||
|
hci_cc_read_page_scan_type(hdev, skb);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HCI_OP_WRITE_PAGE_SCAN_TYPE:
|
||||||
|
hci_cc_write_page_scan_type(hdev, skb);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HCI_OP_READ_DATA_BLOCK_SIZE:
|
||||||
|
hci_cc_read_data_block_size(hdev, skb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_OP_READ_FLOW_CONTROL_MODE:
|
case HCI_OP_READ_FLOW_CONTROL_MODE:
|
||||||
|
@ -2640,26 +2295,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
hci_cc_read_local_amp_assoc(hdev, skb);
|
hci_cc_read_local_amp_assoc(hdev, skb);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HCI_OP_DELETE_STORED_LINK_KEY:
|
|
||||||
hci_cc_delete_stored_link_key(hdev, skb);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HCI_OP_SET_EVENT_MASK:
|
|
||||||
hci_cc_set_event_mask(hdev, skb);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HCI_OP_WRITE_INQUIRY_MODE:
|
|
||||||
hci_cc_write_inquiry_mode(hdev, skb);
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ unlock:
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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 @@ error:
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
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 @@ error:
|
||||||
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 @@ error:
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
r = __rfcomm_dlc_close(d, err);
|
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);
|
||||||
|
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ drop:
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue