Loading include/net/bluetooth/hci_sync.h +2 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ int hci_disable_advertising_sync(struct hci_dev *hdev); int hci_update_passive_scan_sync(struct hci_dev *hdev); int hci_update_passive_scan(struct hci_dev *hdev); int hci_read_rssi_sync(struct hci_dev *hdev, __le16 handle); int hci_read_tx_power_sync(struct hci_dev *hdev, __le16 handle, u8 type); int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable); int hci_update_scan_sync(struct hci_dev *hdev); Loading net/bluetooth/hci_sync.c +19 −0 Original line number Diff line number Diff line Loading @@ -1309,6 +1309,25 @@ int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk, return 0; } int hci_read_rssi_sync(struct hci_dev *hdev, __le16 handle) { struct hci_cp_read_rssi cp; cp.handle = handle; return __hci_cmd_sync_status(hdev, HCI_OP_READ_RSSI, sizeof(cp), &cp, HCI_CMD_TIMEOUT); } int hci_read_tx_power_sync(struct hci_dev *hdev, __le16 handle, u8 type) { struct hci_cp_read_tx_power cp; cp.handle = handle; cp.type = type; return __hci_cmd_sync_status(hdev, HCI_OP_READ_TX_POWER, sizeof(cp), &cp, HCI_CMD_TIMEOUT); } int hci_disable_advertising_sync(struct hci_dev *hdev) { u8 enable = 0x00; Loading net/bluetooth/mgmt.c +58 −90 Original line number Diff line number Diff line Loading @@ -5942,7 +5942,6 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_FAILED); if (cmd) mgmt_pending_free(cmd); } Loading Loading @@ -6534,14 +6533,19 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, return err; } static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err) { struct mgmt_pending_cmd *cmd = data; struct hci_conn *conn = cmd->user_data; struct mgmt_cp_get_conn_info *cp = cmd->param; struct mgmt_rp_get_conn_info rp; int err; u8 status; memcpy(&rp.addr, cmd->param, sizeof(rp.addr)); bt_dev_dbg(hdev, "err %d", err); memcpy(&rp.addr, &cp->addr.bdaddr, sizeof(rp.addr)); status = mgmt_status(err); if (status == MGMT_STATUS_SUCCESS) { rp.rssi = conn->rssi; rp.tx_power = conn->tx_power; Loading @@ -6552,67 +6556,58 @@ static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) rp.max_tx_power = HCI_TX_POWER_INVALID; } err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, &rp, sizeof(rp)); mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, &rp, sizeof(rp)); if (conn) { hci_conn_drop(conn); hci_conn_put(conn); } return err; mgmt_pending_free(cmd); } static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status, u16 opcode) static int get_conn_info_sync(struct hci_dev *hdev, void *data) { struct hci_cp_read_rssi *cp; struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd = data; struct mgmt_cp_get_conn_info *cp = cmd->param; struct hci_conn *conn; u16 handle; u8 status; bt_dev_dbg(hdev, "status 0x%02x", hci_status); int err; __le16 handle; hci_dev_lock(hdev); /* Make sure we are still connected */ if (cp->addr.type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); /* Commands sent in request are either Read RSSI or Read Transmit Power * Level so we check which one was last sent to retrieve connection * handle. Both commands have handle as first parameter so it's safe to * cast data on the same command struct. * * First command sent is always Read RSSI and we fail only if it fails. * In other case we simply override error to indicate success as we * already remembered if TX power value is actually valid. */ cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI); if (!cp) { cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER); status = MGMT_STATUS_SUCCESS; } else { status = mgmt_status(hci_status); if (!conn || conn != cmd->user_data || conn->state != BT_CONNECTED) { if (cmd->user_data) { hci_conn_drop(cmd->user_data); hci_conn_put(cmd->user_data); cmd->user_data = NULL; } if (!cp) { bt_dev_err(hdev, "invalid sent_cmd in conn_info response"); goto unlock; return MGMT_STATUS_NOT_CONNECTED; } handle = __le16_to_cpu(cp->handle); conn = hci_conn_hash_lookup_handle(hdev, handle); if (!conn) { bt_dev_err(hdev, "unknown handle (%u) in conn_info response", handle); goto unlock; } handle = cpu_to_le16(conn->handle); cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn); if (!cmd) goto unlock; /* Refresh RSSI each time */ err = hci_read_rssi_sync(hdev, handle); cmd->cmd_complete(cmd, status); mgmt_pending_remove(cmd); /* For LE links TX power does not change thus we don't need to * query for it once value is known. */ if (!err && (!bdaddr_type_is_le(cp->addr.type) || conn->tx_power == HCI_TX_POWER_INVALID)) err = hci_read_tx_power_sync(hdev, handle, 0x00); unlock: hci_dev_unlock(hdev); /* Max TX power needs to be read only once per connection */ if (!err && conn->max_tx_power == HCI_TX_POWER_INVALID) err = hci_read_tx_power_sync(hdev, handle, 0x01); return err; } static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data, Loading Loading @@ -6657,12 +6652,6 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) { err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO, MGMT_STATUS_BUSY, &rp, sizeof(rp)); goto unlock; } /* To avoid client trying to guess when to poll again for information we * calculate conn info age as random value between min/max set in hdev. */ Loading @@ -6676,49 +6665,28 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data, if (time_after(jiffies, conn->conn_info_timestamp + msecs_to_jiffies(conn_info_age)) || !conn->conn_info_timestamp) { struct hci_request req; struct hci_cp_read_tx_power req_txp_cp; struct hci_cp_read_rssi req_rssi_cp; struct mgmt_pending_cmd *cmd; hci_req_init(&req, hdev); req_rssi_cp.handle = cpu_to_le16(conn->handle); hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp), &req_rssi_cp); /* For LE links TX power does not change thus we don't need to * query for it once value is known. */ if (!bdaddr_type_is_le(cp->addr.type) || conn->tx_power == HCI_TX_POWER_INVALID) { req_txp_cp.handle = cpu_to_le16(conn->handle); req_txp_cp.type = 0x00; hci_req_add(&req, HCI_OP_READ_TX_POWER, sizeof(req_txp_cp), &req_txp_cp); } cmd = mgmt_pending_new(sk, MGMT_OP_GET_CONN_INFO, hdev, data, len); if (!cmd) err = -ENOMEM; else err = hci_cmd_sync_queue(hdev, get_conn_info_sync, cmd, get_conn_info_complete); /* Max TX power needs to be read only once per connection */ if (conn->max_tx_power == HCI_TX_POWER_INVALID) { req_txp_cp.handle = cpu_to_le16(conn->handle); req_txp_cp.type = 0x01; hci_req_add(&req, HCI_OP_READ_TX_POWER, sizeof(req_txp_cp), &req_txp_cp); } if (err < 0) { mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO, MGMT_STATUS_FAILED, &rp, sizeof(rp)); err = hci_req_run(&req, conn_info_refresh_complete); if (err < 0) goto unlock; if (cmd) mgmt_pending_free(cmd); cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev, data, len); if (!cmd) { err = -ENOMEM; goto unlock; } hci_conn_hold(conn); cmd->user_data = hci_conn_get(conn); cmd->cmd_complete = conn_info_cmd_complete; conn->conn_info_timestamp = jiffies; } else { Loading Loading
include/net/bluetooth/hci_sync.h +2 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ int hci_disable_advertising_sync(struct hci_dev *hdev); int hci_update_passive_scan_sync(struct hci_dev *hdev); int hci_update_passive_scan(struct hci_dev *hdev); int hci_read_rssi_sync(struct hci_dev *hdev, __le16 handle); int hci_read_tx_power_sync(struct hci_dev *hdev, __le16 handle, u8 type); int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable); int hci_update_scan_sync(struct hci_dev *hdev); Loading
net/bluetooth/hci_sync.c +19 −0 Original line number Diff line number Diff line Loading @@ -1309,6 +1309,25 @@ int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk, return 0; } int hci_read_rssi_sync(struct hci_dev *hdev, __le16 handle) { struct hci_cp_read_rssi cp; cp.handle = handle; return __hci_cmd_sync_status(hdev, HCI_OP_READ_RSSI, sizeof(cp), &cp, HCI_CMD_TIMEOUT); } int hci_read_tx_power_sync(struct hci_dev *hdev, __le16 handle, u8 type) { struct hci_cp_read_tx_power cp; cp.handle = handle; cp.type = type; return __hci_cmd_sync_status(hdev, HCI_OP_READ_TX_POWER, sizeof(cp), &cp, HCI_CMD_TIMEOUT); } int hci_disable_advertising_sync(struct hci_dev *hdev) { u8 enable = 0x00; Loading
net/bluetooth/mgmt.c +58 −90 Original line number Diff line number Diff line Loading @@ -5942,7 +5942,6 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, MGMT_STATUS_FAILED); if (cmd) mgmt_pending_free(cmd); } Loading Loading @@ -6534,14 +6533,19 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, return err; } static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err) { struct mgmt_pending_cmd *cmd = data; struct hci_conn *conn = cmd->user_data; struct mgmt_cp_get_conn_info *cp = cmd->param; struct mgmt_rp_get_conn_info rp; int err; u8 status; memcpy(&rp.addr, cmd->param, sizeof(rp.addr)); bt_dev_dbg(hdev, "err %d", err); memcpy(&rp.addr, &cp->addr.bdaddr, sizeof(rp.addr)); status = mgmt_status(err); if (status == MGMT_STATUS_SUCCESS) { rp.rssi = conn->rssi; rp.tx_power = conn->tx_power; Loading @@ -6552,67 +6556,58 @@ static int conn_info_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) rp.max_tx_power = HCI_TX_POWER_INVALID; } err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, &rp, sizeof(rp)); mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, &rp, sizeof(rp)); if (conn) { hci_conn_drop(conn); hci_conn_put(conn); } return err; mgmt_pending_free(cmd); } static void conn_info_refresh_complete(struct hci_dev *hdev, u8 hci_status, u16 opcode) static int get_conn_info_sync(struct hci_dev *hdev, void *data) { struct hci_cp_read_rssi *cp; struct mgmt_pending_cmd *cmd; struct mgmt_pending_cmd *cmd = data; struct mgmt_cp_get_conn_info *cp = cmd->param; struct hci_conn *conn; u16 handle; u8 status; bt_dev_dbg(hdev, "status 0x%02x", hci_status); int err; __le16 handle; hci_dev_lock(hdev); /* Make sure we are still connected */ if (cp->addr.type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); /* Commands sent in request are either Read RSSI or Read Transmit Power * Level so we check which one was last sent to retrieve connection * handle. Both commands have handle as first parameter so it's safe to * cast data on the same command struct. * * First command sent is always Read RSSI and we fail only if it fails. * In other case we simply override error to indicate success as we * already remembered if TX power value is actually valid. */ cp = hci_sent_cmd_data(hdev, HCI_OP_READ_RSSI); if (!cp) { cp = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER); status = MGMT_STATUS_SUCCESS; } else { status = mgmt_status(hci_status); if (!conn || conn != cmd->user_data || conn->state != BT_CONNECTED) { if (cmd->user_data) { hci_conn_drop(cmd->user_data); hci_conn_put(cmd->user_data); cmd->user_data = NULL; } if (!cp) { bt_dev_err(hdev, "invalid sent_cmd in conn_info response"); goto unlock; return MGMT_STATUS_NOT_CONNECTED; } handle = __le16_to_cpu(cp->handle); conn = hci_conn_hash_lookup_handle(hdev, handle); if (!conn) { bt_dev_err(hdev, "unknown handle (%u) in conn_info response", handle); goto unlock; } handle = cpu_to_le16(conn->handle); cmd = pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn); if (!cmd) goto unlock; /* Refresh RSSI each time */ err = hci_read_rssi_sync(hdev, handle); cmd->cmd_complete(cmd, status); mgmt_pending_remove(cmd); /* For LE links TX power does not change thus we don't need to * query for it once value is known. */ if (!err && (!bdaddr_type_is_le(cp->addr.type) || conn->tx_power == HCI_TX_POWER_INVALID)) err = hci_read_tx_power_sync(hdev, handle, 0x00); unlock: hci_dev_unlock(hdev); /* Max TX power needs to be read only once per connection */ if (!err && conn->max_tx_power == HCI_TX_POWER_INVALID) err = hci_read_tx_power_sync(hdev, handle, 0x01); return err; } static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data, Loading Loading @@ -6657,12 +6652,6 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } if (pending_find_data(MGMT_OP_GET_CONN_INFO, hdev, conn)) { err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO, MGMT_STATUS_BUSY, &rp, sizeof(rp)); goto unlock; } /* To avoid client trying to guess when to poll again for information we * calculate conn info age as random value between min/max set in hdev. */ Loading @@ -6676,49 +6665,28 @@ static int get_conn_info(struct sock *sk, struct hci_dev *hdev, void *data, if (time_after(jiffies, conn->conn_info_timestamp + msecs_to_jiffies(conn_info_age)) || !conn->conn_info_timestamp) { struct hci_request req; struct hci_cp_read_tx_power req_txp_cp; struct hci_cp_read_rssi req_rssi_cp; struct mgmt_pending_cmd *cmd; hci_req_init(&req, hdev); req_rssi_cp.handle = cpu_to_le16(conn->handle); hci_req_add(&req, HCI_OP_READ_RSSI, sizeof(req_rssi_cp), &req_rssi_cp); /* For LE links TX power does not change thus we don't need to * query for it once value is known. */ if (!bdaddr_type_is_le(cp->addr.type) || conn->tx_power == HCI_TX_POWER_INVALID) { req_txp_cp.handle = cpu_to_le16(conn->handle); req_txp_cp.type = 0x00; hci_req_add(&req, HCI_OP_READ_TX_POWER, sizeof(req_txp_cp), &req_txp_cp); } cmd = mgmt_pending_new(sk, MGMT_OP_GET_CONN_INFO, hdev, data, len); if (!cmd) err = -ENOMEM; else err = hci_cmd_sync_queue(hdev, get_conn_info_sync, cmd, get_conn_info_complete); /* Max TX power needs to be read only once per connection */ if (conn->max_tx_power == HCI_TX_POWER_INVALID) { req_txp_cp.handle = cpu_to_le16(conn->handle); req_txp_cp.type = 0x01; hci_req_add(&req, HCI_OP_READ_TX_POWER, sizeof(req_txp_cp), &req_txp_cp); } if (err < 0) { mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_CONN_INFO, MGMT_STATUS_FAILED, &rp, sizeof(rp)); err = hci_req_run(&req, conn_info_refresh_complete); if (err < 0) goto unlock; if (cmd) mgmt_pending_free(cmd); cmd = mgmt_pending_add(sk, MGMT_OP_GET_CONN_INFO, hdev, data, len); if (!cmd) { err = -ENOMEM; goto unlock; } hci_conn_hold(conn); cmd->user_data = hci_conn_get(conn); cmd->cmd_complete = conn_info_cmd_complete; conn->conn_info_timestamp = jiffies; } else { Loading