mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
bluetooth pull request for net:
- Fix MGMT add advmon with RSSI command - L2CAP: Fix responding with wrong PDU type - Fix race condition in hci_cmd_sync_clear - ISO: Fix timestamped HCI ISO data packet parsing - HCI: Fix global-out-of-bounds - hci_sync: Resume adv with no RPA when active scan -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmQcskUZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKUVID/9wBdLUiz+5ZMeyzsrX2Izi Bph2b6z/DSEAk+DTaG4PPOGNc5DPdRt1wdPo4v24HexICi5GB7fgKeJN3Uhge9iO 2bp1LgB/SwBdRPCDamEhx9WNOyMO11qIsrQxfqzl+3YyLTgleE0kErh8Dcq9Z9r7 IMdajwV64I4NzxAva7IAFV/LC9WA7BxX3hnFxx3YYjumJgK3QMZ91x5xc7veNt3v ZD0YQLU2uYE/yQ8r+WaUatfeAAiBOmpb6BcTYbowhrqkER5KFJTeKGU6gkphnHbS 12EJ6hW84tBdUELGp9JpuElPQoOHC9MYBWd0FvyRe7HGIZARtxUnm3B0FcmlMdgG OsI9VQ8SM3eLg9G+Kz/wMOW1enJf5bMgY7LKzE5EcpsaVr+pkng+ROThHv7YFqXQ uU99uksQrDVpnjhWBmHgUOmoIJYZPsRQyAz0GTA2Zvlr8nAohqzmWKvXRdb+Gmtt 7Ss61MCNAFqDYOxAq8qo/QgR2toa8W4ULTqHlJuLkHeszZlyKL+5qDipG9WvirWd C8pwHpsR3KTJnQOyVCLYLq46rY14sxNp4RbtlydgQ3Xa4kvFbi/ZycWI5DMIRPsc sg8vyzQN7UKL2Sd59JS7Vi6YK4aPu+Br1BdHIKwp+0pdqRxVfsz2UM8D8E9OZ4QT jN2Iqxztt0cFG9pyq2z+cw== =mBpY -----END PGP SIGNATURE----- Merge tag 'for-net-2023-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth Luiz Augusto von Dentz says: ==================== bluetooth pull request for net: - Fix MGMT add advmon with RSSI command - L2CAP: Fix responding with wrong PDU type - Fix race condition in hci_cmd_sync_clear - ISO: Fix timestamped HCI ISO data packet parsing - HCI: Fix global-out-of-bounds - hci_sync: Resume adv with no RPA when active scan * tag 'for-net-2023-03-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth: Bluetooth: HCI: Fix global-out-of-bounds Bluetooth: mgmt: Fix MGMT add advmon with RSSI command Bluetooth: btsdio: fix use after free bug in btsdio_remove due to unfinished work Bluetooth: L2CAP: Fix responding with wrong PDU type Bluetooth: btqcomsmd: Fix command timeout after setting BD address Bluetooth: btinel: Check ACPI handle for NULL before accessing Bluetooth: Remove "Power-on" check from Mesh feature Bluetooth: Fix race condition in hci_cmd_sync_clear Bluetooth: btintel: Iterate only bluetooth device ACPI entries Bluetooth: ISO: fix timestamped HCI ISO data packet parsing Bluetooth: btusb: Remove detection of ISO packets over bulk Bluetooth: hci_core: Detect if an ACL packet is in fact an ISO packet Bluetooth: hci_sync: Resume adv with no RPA when active scan ==================== Link: https://lore.kernel.org/r/20230323202335.3380841-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
2e63a2dfe7
@ -26,7 +26,14 @@
|
||||
#define ECDSA_HEADER_LEN 320
|
||||
|
||||
#define BTINTEL_PPAG_NAME "PPAG"
|
||||
#define BTINTEL_PPAG_PREFIX "\\_SB_.PCI0.XHCI.RHUB"
|
||||
|
||||
/* structure to store the PPAG data read from ACPI table */
|
||||
struct btintel_ppag {
|
||||
u32 domain;
|
||||
u32 mode;
|
||||
acpi_status status;
|
||||
struct hci_dev *hdev;
|
||||
};
|
||||
|
||||
#define CMD_WRITE_BOOT_PARAMS 0xfc0e
|
||||
struct cmd_write_boot_params {
|
||||
@ -1295,17 +1302,16 @@ static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data
|
||||
|
||||
status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
bt_dev_warn(hdev, "ACPI Failure: %s", acpi_format_exception(status));
|
||||
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
if (strncmp(BTINTEL_PPAG_PREFIX, string.pointer,
|
||||
strlen(BTINTEL_PPAG_PREFIX))) {
|
||||
len = strlen(string.pointer);
|
||||
if (len < strlen(BTINTEL_PPAG_NAME)) {
|
||||
kfree(string.pointer);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
len = strlen(string.pointer);
|
||||
if (strncmp((char *)string.pointer + len - 4, BTINTEL_PPAG_NAME, 4)) {
|
||||
kfree(string.pointer);
|
||||
return AE_OK;
|
||||
@ -1314,7 +1320,8 @@ static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data
|
||||
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
bt_dev_warn(hdev, "ACPI Failure: %s", acpi_format_exception(status));
|
||||
ppag->status = status;
|
||||
bt_dev_warn(hdev, "PPAG-BT: ACPI Failure: %s", acpi_format_exception(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -1323,8 +1330,9 @@ static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data
|
||||
|
||||
if (p->type != ACPI_TYPE_PACKAGE || p->package.count != 2) {
|
||||
kfree(buffer.pointer);
|
||||
bt_dev_warn(hdev, "Invalid object type: %d or package count: %d",
|
||||
bt_dev_warn(hdev, "PPAG-BT: Invalid object type: %d or package count: %d",
|
||||
p->type, p->package.count);
|
||||
ppag->status = AE_ERROR;
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
||||
@ -1335,6 +1343,7 @@ static acpi_status btintel_ppag_callback(acpi_handle handle, u32 lvl, void *data
|
||||
|
||||
ppag->domain = (u32)p->package.elements[0].integer.value;
|
||||
ppag->mode = (u32)p->package.elements[1].integer.value;
|
||||
ppag->status = AE_OK;
|
||||
kfree(buffer.pointer);
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
@ -2314,12 +2323,12 @@ error:
|
||||
|
||||
static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver)
|
||||
{
|
||||
acpi_status status;
|
||||
struct btintel_ppag ppag;
|
||||
struct sk_buff *skb;
|
||||
struct btintel_loc_aware_reg ppag_cmd;
|
||||
acpi_handle handle;
|
||||
|
||||
/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
|
||||
/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
|
||||
switch (ver->cnvr_top & 0xFFF) {
|
||||
case 0x504: /* Hrp2 */
|
||||
case 0x202: /* Jfp2 */
|
||||
@ -2327,29 +2336,35 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
|
||||
return;
|
||||
}
|
||||
|
||||
handle = ACPI_HANDLE(GET_HCIDEV_DEV(hdev));
|
||||
if (!handle) {
|
||||
bt_dev_info(hdev, "No support for BT device in ACPI firmware");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&ppag, 0, sizeof(ppag));
|
||||
|
||||
ppag.hdev = hdev;
|
||||
status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
|
||||
ACPI_UINT32_MAX, NULL,
|
||||
btintel_ppag_callback, &ppag, NULL);
|
||||
ppag.status = AE_NOT_FOUND;
|
||||
acpi_walk_namespace(ACPI_TYPE_PACKAGE, handle, 1, NULL,
|
||||
btintel_ppag_callback, &ppag, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
/* Do not log warning message if ACPI entry is not found */
|
||||
if (status == AE_NOT_FOUND)
|
||||
if (ACPI_FAILURE(ppag.status)) {
|
||||
if (ppag.status == AE_NOT_FOUND) {
|
||||
bt_dev_dbg(hdev, "PPAG-BT: ACPI entry not found");
|
||||
return;
|
||||
bt_dev_warn(hdev, "PPAG: ACPI Failure: %s", acpi_format_exception(status));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ppag.domain != 0x12) {
|
||||
bt_dev_warn(hdev, "PPAG-BT Domain disabled");
|
||||
bt_dev_warn(hdev, "PPAG-BT: domain is not bluetooth");
|
||||
return;
|
||||
}
|
||||
|
||||
/* PPAG mode, BIT0 = 0 Disabled, BIT0 = 1 Enabled */
|
||||
if (!(ppag.mode & BIT(0))) {
|
||||
bt_dev_dbg(hdev, "PPAG disabled");
|
||||
bt_dev_dbg(hdev, "PPAG-BT: disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -137,13 +137,6 @@ struct intel_offload_use_cases {
|
||||
__u8 preset[8];
|
||||
} __packed;
|
||||
|
||||
/* structure to store the PPAG data read from ACPI table */
|
||||
struct btintel_ppag {
|
||||
u32 domain;
|
||||
u32 mode;
|
||||
struct hci_dev *hdev;
|
||||
};
|
||||
|
||||
struct btintel_loc_aware_reg {
|
||||
__le32 mcc;
|
||||
__le32 sel;
|
||||
|
@ -122,6 +122,21 @@ static int btqcomsmd_setup(struct hci_dev *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btqcomsmd_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = qca_set_bdaddr_rome(hdev, bdaddr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* The firmware stops responding for a while after setting the bdaddr,
|
||||
* causing timeouts for subsequent commands. Sleep a bit to avoid this.
|
||||
*/
|
||||
usleep_range(1000, 10000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btqcomsmd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct btqcomsmd *btq;
|
||||
@ -162,7 +177,7 @@ static int btqcomsmd_probe(struct platform_device *pdev)
|
||||
hdev->close = btqcomsmd_close;
|
||||
hdev->send = btqcomsmd_send;
|
||||
hdev->setup = btqcomsmd_setup;
|
||||
hdev->set_bdaddr = qca_set_bdaddr_rome;
|
||||
hdev->set_bdaddr = btqcomsmd_set_bdaddr;
|
||||
|
||||
ret = hci_register_dev(hdev);
|
||||
if (ret < 0)
|
||||
|
@ -354,6 +354,7 @@ static void btsdio_remove(struct sdio_func *func)
|
||||
|
||||
BT_DBG("func %p", func);
|
||||
|
||||
cancel_work_sync(&data->work);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
|
@ -1050,21 +1050,11 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
||||
hci_skb_expect(skb) -= len;
|
||||
|
||||
if (skb->len == HCI_ACL_HDR_SIZE) {
|
||||
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
|
||||
__le16 dlen = hci_acl_hdr(skb)->dlen;
|
||||
__u8 type;
|
||||
|
||||
/* Complete ACL header */
|
||||
hci_skb_expect(skb) = __le16_to_cpu(dlen);
|
||||
|
||||
/* Detect if ISO packet has been sent over bulk */
|
||||
if (hci_conn_num(data->hdev, ISO_LINK)) {
|
||||
type = hci_conn_lookup_type(data->hdev,
|
||||
hci_handle(handle));
|
||||
if (type == ISO_LINK)
|
||||
hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;
|
||||
}
|
||||
|
||||
if (skb_tailroom(skb) < hci_skb_expect(skb)) {
|
||||
kfree_skb(skb);
|
||||
skb = NULL;
|
||||
|
@ -1613,6 +1613,7 @@ void hci_conn_add_sysfs(struct hci_conn *conn);
|
||||
void hci_conn_del_sysfs(struct hci_conn *conn);
|
||||
|
||||
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
|
||||
#define GET_HCIDEV_DEV(hdev) ((hdev)->dev.parent)
|
||||
|
||||
/* ----- LMP capabilities ----- */
|
||||
#define lmp_encrypt_capable(dev) ((dev)->features[0][0] & LMP_ENCRYPT)
|
||||
|
@ -2871,10 +2871,25 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT &&
|
||||
hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
|
||||
hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
|
||||
hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) {
|
||||
switch (hci_skb_pkt_type(skb)) {
|
||||
case HCI_EVENT_PKT:
|
||||
break;
|
||||
case HCI_ACLDATA_PKT:
|
||||
/* Detect if ISO packet has been sent as ACL */
|
||||
if (hci_conn_num(hdev, ISO_LINK)) {
|
||||
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
|
||||
__u8 type;
|
||||
|
||||
type = hci_conn_lookup_type(hdev, hci_handle(handle));
|
||||
if (type == ISO_LINK)
|
||||
hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;
|
||||
}
|
||||
break;
|
||||
case HCI_SCODATA_PKT:
|
||||
break;
|
||||
case HCI_ISODATA_PKT:
|
||||
break;
|
||||
default:
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -643,6 +643,7 @@ void hci_cmd_sync_clear(struct hci_dev *hdev)
|
||||
cancel_work_sync(&hdev->cmd_sync_work);
|
||||
cancel_work_sync(&hdev->reenable_adv_work);
|
||||
|
||||
mutex_lock(&hdev->cmd_sync_work_lock);
|
||||
list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list) {
|
||||
if (entry->destroy)
|
||||
entry->destroy(hdev, entry->data, -ECANCELED);
|
||||
@ -650,6 +651,7 @@ void hci_cmd_sync_clear(struct hci_dev *hdev)
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
mutex_unlock(&hdev->cmd_sync_work_lock);
|
||||
}
|
||||
|
||||
void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
|
||||
@ -2367,6 +2369,45 @@ static int hci_resume_advertising_sync(struct hci_dev *hdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hci_pause_addr_resolution(struct hci_dev *hdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!use_ll_privacy(hdev))
|
||||
return 0;
|
||||
|
||||
if (!hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION))
|
||||
return 0;
|
||||
|
||||
/* Cannot disable addr resolution if scanning is enabled or
|
||||
* when initiating an LE connection.
|
||||
*/
|
||||
if (hci_dev_test_flag(hdev, HCI_LE_SCAN) ||
|
||||
hci_lookup_le_connect(hdev)) {
|
||||
bt_dev_err(hdev, "Command not allowed when scan/LE connect");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* Cannot disable addr resolution if advertising is enabled. */
|
||||
err = hci_pause_advertising_sync(hdev);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Pause advertising failed: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = hci_le_set_addr_resolution_enable_sync(hdev, 0x00);
|
||||
if (err)
|
||||
bt_dev_err(hdev, "Unable to disable Address Resolution: %d",
|
||||
err);
|
||||
|
||||
/* Return if address resolution is disabled and RPA is not used. */
|
||||
if (!err && scan_use_rpa(hdev))
|
||||
return err;
|
||||
|
||||
hci_resume_advertising_sync(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev,
|
||||
bool extended, struct sock *sk)
|
||||
{
|
||||
@ -2402,7 +2443,7 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
|
||||
u8 filter_policy;
|
||||
int err;
|
||||
|
||||
/* Pause advertising if resolving list can be used as controllers are
|
||||
/* Pause advertising if resolving list can be used as controllers
|
||||
* cannot accept resolving list modifications while advertising.
|
||||
*/
|
||||
if (use_ll_privacy(hdev)) {
|
||||
@ -3319,6 +3360,7 @@ static const struct hci_init_stage amp_init1[] = {
|
||||
HCI_INIT(hci_read_flow_control_mode_sync),
|
||||
/* HCI_OP_READ_LOCATION_DATA */
|
||||
HCI_INIT(hci_read_location_data_sync),
|
||||
{}
|
||||
};
|
||||
|
||||
static int hci_init1_sync(struct hci_dev *hdev)
|
||||
@ -3353,6 +3395,7 @@ static int hci_init1_sync(struct hci_dev *hdev)
|
||||
static const struct hci_init_stage amp_init2[] = {
|
||||
/* HCI_OP_READ_LOCAL_FEATURES */
|
||||
HCI_INIT(hci_read_local_features_sync),
|
||||
{}
|
||||
};
|
||||
|
||||
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
|
||||
@ -5394,27 +5437,12 @@ static int hci_active_scan_sync(struct hci_dev *hdev, uint16_t interval)
|
||||
|
||||
cancel_interleave_scan(hdev);
|
||||
|
||||
/* Pause advertising since active scanning disables address resolution
|
||||
* which advertising depend on in order to generate its RPAs.
|
||||
/* Pause address resolution for active scan and stop advertising if
|
||||
* privacy is enabled.
|
||||
*/
|
||||
if (use_ll_privacy(hdev) && hci_dev_test_flag(hdev, HCI_PRIVACY)) {
|
||||
err = hci_pause_advertising_sync(hdev);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "pause advertising failed: %d", err);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable address resolution while doing active scanning since the
|
||||
* accept list shall not be used and all reports shall reach the host
|
||||
* anyway.
|
||||
*/
|
||||
err = hci_le_set_addr_resolution_enable_sync(hdev, 0x00);
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Unable to disable Address Resolution: %d",
|
||||
err);
|
||||
err = hci_pause_addr_resolution(hdev);
|
||||
if (err)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* All active scans will be done with either a resolvable private
|
||||
* address (when privacy feature has been enabled) or non-resolvable
|
||||
|
@ -1620,7 +1620,6 @@ static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason)
|
||||
void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
{
|
||||
struct iso_conn *conn = hcon->iso_data;
|
||||
struct hci_iso_data_hdr *hdr;
|
||||
__u16 pb, ts, len;
|
||||
|
||||
if (!conn)
|
||||
@ -1642,6 +1641,8 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
}
|
||||
|
||||
if (ts) {
|
||||
struct hci_iso_ts_data_hdr *hdr;
|
||||
|
||||
/* TODO: add timestamp to the packet? */
|
||||
hdr = skb_pull_data(skb, HCI_ISO_TS_DATA_HDR_SIZE);
|
||||
if (!hdr) {
|
||||
@ -1649,15 +1650,19 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
goto drop;
|
||||
}
|
||||
|
||||
len = __le16_to_cpu(hdr->slen);
|
||||
} else {
|
||||
struct hci_iso_data_hdr *hdr;
|
||||
|
||||
hdr = skb_pull_data(skb, HCI_ISO_DATA_HDR_SIZE);
|
||||
if (!hdr) {
|
||||
BT_ERR("Frame is too short (len %d)", skb->len);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
len = __le16_to_cpu(hdr->slen);
|
||||
}
|
||||
|
||||
len = __le16_to_cpu(hdr->slen);
|
||||
flags = hci_iso_data_flags(len);
|
||||
len = hci_iso_data_len(len);
|
||||
|
||||
|
@ -708,6 +708,17 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(l2cap_chan_del);
|
||||
|
||||
static void __l2cap_chan_list_id(struct l2cap_conn *conn, u16 id,
|
||||
l2cap_chan_func_t func, void *data)
|
||||
{
|
||||
struct l2cap_chan *chan, *l;
|
||||
|
||||
list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
|
||||
if (chan->ident == id)
|
||||
func(chan, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void __l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
|
||||
void *data)
|
||||
{
|
||||
@ -775,23 +786,9 @@ static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
|
||||
|
||||
static void l2cap_chan_ecred_connect_reject(struct l2cap_chan *chan)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
struct l2cap_ecred_conn_rsp rsp;
|
||||
u16 result;
|
||||
|
||||
if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
|
||||
result = L2CAP_CR_LE_AUTHORIZATION;
|
||||
else
|
||||
result = L2CAP_CR_LE_BAD_PSM;
|
||||
|
||||
l2cap_state_change(chan, BT_DISCONN);
|
||||
|
||||
memset(&rsp, 0, sizeof(rsp));
|
||||
|
||||
rsp.result = cpu_to_le16(result);
|
||||
|
||||
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
|
||||
&rsp);
|
||||
__l2cap_ecred_conn_rsp_defer(chan);
|
||||
}
|
||||
|
||||
static void l2cap_chan_connect_reject(struct l2cap_chan *chan)
|
||||
@ -846,7 +843,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
|
||||
break;
|
||||
case L2CAP_MODE_EXT_FLOWCTL:
|
||||
l2cap_chan_ecred_connect_reject(chan);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3938,43 +3935,86 @@ void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan)
|
||||
&rsp);
|
||||
}
|
||||
|
||||
void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan)
|
||||
static void l2cap_ecred_list_defer(struct l2cap_chan *chan, void *data)
|
||||
{
|
||||
struct {
|
||||
struct l2cap_ecred_conn_rsp rsp;
|
||||
__le16 dcid[5];
|
||||
} __packed pdu;
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
u16 ident = chan->ident;
|
||||
int i = 0;
|
||||
int *result = data;
|
||||
|
||||
if (!ident)
|
||||
if (*result || test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
|
||||
return;
|
||||
|
||||
BT_DBG("chan %p ident %d", chan, ident);
|
||||
|
||||
pdu.rsp.mtu = cpu_to_le16(chan->imtu);
|
||||
pdu.rsp.mps = cpu_to_le16(chan->mps);
|
||||
pdu.rsp.credits = cpu_to_le16(chan->rx_credits);
|
||||
pdu.rsp.result = cpu_to_le16(L2CAP_CR_LE_SUCCESS);
|
||||
|
||||
mutex_lock(&conn->chan_lock);
|
||||
|
||||
list_for_each_entry(chan, &conn->chan_l, list) {
|
||||
if (chan->ident != ident)
|
||||
continue;
|
||||
|
||||
/* Reset ident so only one response is sent */
|
||||
chan->ident = 0;
|
||||
|
||||
/* Include all channels pending with the same ident */
|
||||
pdu.dcid[i++] = cpu_to_le16(chan->scid);
|
||||
switch (chan->state) {
|
||||
case BT_CONNECT2:
|
||||
/* If channel still pending accept add to result */
|
||||
(*result)++;
|
||||
return;
|
||||
case BT_CONNECTED:
|
||||
return;
|
||||
default:
|
||||
/* If not connected or pending accept it has been refused */
|
||||
*result = -ECONNREFUSED;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&conn->chan_lock);
|
||||
struct l2cap_ecred_rsp_data {
|
||||
struct {
|
||||
struct l2cap_ecred_conn_rsp rsp;
|
||||
__le16 scid[L2CAP_ECRED_MAX_CID];
|
||||
} __packed pdu;
|
||||
int count;
|
||||
};
|
||||
|
||||
l2cap_send_cmd(conn, ident, L2CAP_ECRED_CONN_RSP,
|
||||
sizeof(pdu.rsp) + i * sizeof(__le16), &pdu);
|
||||
static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
|
||||
{
|
||||
struct l2cap_ecred_rsp_data *rsp = data;
|
||||
|
||||
if (test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
|
||||
return;
|
||||
|
||||
/* Reset ident so only one response is sent */
|
||||
chan->ident = 0;
|
||||
|
||||
/* Include all channels pending with the same ident */
|
||||
if (!rsp->pdu.rsp.result)
|
||||
rsp->pdu.rsp.dcid[rsp->count++] = cpu_to_le16(chan->scid);
|
||||
else
|
||||
l2cap_chan_del(chan, ECONNRESET);
|
||||
}
|
||||
|
||||
void __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
struct l2cap_ecred_rsp_data data;
|
||||
u16 id = chan->ident;
|
||||
int result = 0;
|
||||
|
||||
if (!id)
|
||||
return;
|
||||
|
||||
BT_DBG("chan %p id %d", chan, id);
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
data.pdu.rsp.mtu = cpu_to_le16(chan->imtu);
|
||||
data.pdu.rsp.mps = cpu_to_le16(chan->mps);
|
||||
data.pdu.rsp.credits = cpu_to_le16(chan->rx_credits);
|
||||
data.pdu.rsp.result = cpu_to_le16(L2CAP_CR_LE_SUCCESS);
|
||||
|
||||
/* Verify that all channels are ready */
|
||||
__l2cap_chan_list_id(conn, id, l2cap_ecred_list_defer, &result);
|
||||
|
||||
if (result > 0)
|
||||
return;
|
||||
|
||||
if (result < 0)
|
||||
data.pdu.rsp.result = cpu_to_le16(L2CAP_CR_LE_AUTHORIZATION);
|
||||
|
||||
/* Build response */
|
||||
__l2cap_chan_list_id(conn, id, l2cap_ecred_rsp_defer, &data);
|
||||
|
||||
l2cap_send_cmd(conn, id, L2CAP_ECRED_CONN_RSP,
|
||||
sizeof(data.pdu.rsp) + (data.count * sizeof(__le16)),
|
||||
&data.pdu);
|
||||
}
|
||||
|
||||
void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
|
||||
@ -6078,6 +6118,7 @@ static inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
|
||||
__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
|
||||
|
||||
chan->ident = cmd->ident;
|
||||
chan->mode = L2CAP_MODE_EXT_FLOWCTL;
|
||||
|
||||
if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
|
||||
l2cap_state_change(chan, BT_CONNECT2);
|
||||
|
@ -4639,12 +4639,6 @@ static int set_mgmt_mesh_func(struct sock *sk, struct hci_dev *hdev,
|
||||
MGMT_OP_SET_EXP_FEATURE,
|
||||
MGMT_STATUS_INVALID_INDEX);
|
||||
|
||||
/* Changes can only be made when controller is powered down */
|
||||
if (hdev_is_powered(hdev))
|
||||
return mgmt_cmd_status(sk, hdev->id,
|
||||
MGMT_OP_SET_EXP_FEATURE,
|
||||
MGMT_STATUS_REJECTED);
|
||||
|
||||
/* Parameters are limited to a single octet */
|
||||
if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
|
||||
return mgmt_cmd_status(sk, hdev->id,
|
||||
@ -9363,7 +9357,8 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
|
||||
{ add_ext_adv_data, MGMT_ADD_EXT_ADV_DATA_SIZE,
|
||||
HCI_MGMT_VAR_LEN },
|
||||
{ add_adv_patterns_monitor_rssi,
|
||||
MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE },
|
||||
MGMT_ADD_ADV_PATTERNS_MONITOR_RSSI_SIZE,
|
||||
HCI_MGMT_VAR_LEN },
|
||||
{ set_mesh, MGMT_SET_MESH_RECEIVER_SIZE,
|
||||
HCI_MGMT_VAR_LEN },
|
||||
{ mesh_features, MGMT_MESH_READ_FEATURES_SIZE },
|
||||
|
Loading…
Reference in New Issue
Block a user