Commit 10888140 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Marcel Holtmann

Bluetooth: btusb: fix excessive stack usage

Enlarging the size of 'struct btmtk_hci_wmt_cmd' makes it no longer
fit on the kernel stack, as seen from this compiler warning:

drivers/bluetooth/btusb.c:3365:12: error: stack frame size of 1036 bytes in function 'btusb_mtk_hci_wmt_sync' [-Werror,-Wframe-larger-than=]

Change the function to dynamically allocate the buffer instead.
As there are other sleeping functions called from the same location,
using GFP_KERNEL should be fine here, and the runtime overhead should
not matter as this is rarely called.

Unfortunately, I could not figure out why the message size is
increased in the previous patch. Using dynamic allocation means
any size is possible now, but there is still a range check that
limits the total size (including the five-byte header) to 255
bytes, so whatever was intended there is now undone.

Fixes: 48c13301 ("Bluetooth: btusb: Fine-tune mt7663 mechanism.")
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 8564baa3
...@@ -3161,7 +3161,7 @@ struct btmtk_wmt_hdr { ...@@ -3161,7 +3161,7 @@ struct btmtk_wmt_hdr {
struct btmtk_hci_wmt_cmd { struct btmtk_hci_wmt_cmd {
struct btmtk_wmt_hdr hdr; struct btmtk_wmt_hdr hdr;
u8 data[1000]; u8 data[];
} __packed; } __packed;
struct btmtk_hci_wmt_evt { struct btmtk_hci_wmt_evt {
...@@ -3369,7 +3369,7 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev, ...@@ -3369,7 +3369,7 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc; struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
u32 hlen, status = BTMTK_WMT_INVALID; u32 hlen, status = BTMTK_WMT_INVALID;
struct btmtk_hci_wmt_evt *wmt_evt; struct btmtk_hci_wmt_evt *wmt_evt;
struct btmtk_hci_wmt_cmd wc; struct btmtk_hci_wmt_cmd *wc;
struct btmtk_wmt_hdr *hdr; struct btmtk_wmt_hdr *hdr;
int err; int err;
...@@ -3383,20 +3383,24 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev, ...@@ -3383,20 +3383,24 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
if (hlen > 255) if (hlen > 255)
return -EINVAL; return -EINVAL;
hdr = (struct btmtk_wmt_hdr *)&wc; wc = kzalloc(hlen, GFP_KERNEL);
if (!wc)
return -ENOMEM;
hdr = &wc->hdr;
hdr->dir = 1; hdr->dir = 1;
hdr->op = wmt_params->op; hdr->op = wmt_params->op;
hdr->dlen = cpu_to_le16(wmt_params->dlen + 1); hdr->dlen = cpu_to_le16(wmt_params->dlen + 1);
hdr->flag = wmt_params->flag; hdr->flag = wmt_params->flag;
memcpy(wc.data, wmt_params->data, wmt_params->dlen); memcpy(wc->data, wmt_params->data, wmt_params->dlen);
set_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); set_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
err = __hci_cmd_send(hdev, 0xfc6f, hlen, &wc); err = __hci_cmd_send(hdev, 0xfc6f, hlen, wc);
if (err < 0) { if (err < 0) {
clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
return err; goto err_free_wc;
} }
/* The vendor specific WMT commands are all answered by a vendor /* The vendor specific WMT commands are all answered by a vendor
...@@ -3413,13 +3417,14 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev, ...@@ -3413,13 +3417,14 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
if (err == -EINTR) { if (err == -EINTR) {
bt_dev_err(hdev, "Execution of wmt command interrupted"); bt_dev_err(hdev, "Execution of wmt command interrupted");
clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
return err; goto err_free_wc;
} }
if (err) { if (err) {
bt_dev_err(hdev, "Execution of wmt command timed out"); bt_dev_err(hdev, "Execution of wmt command timed out");
clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags); clear_bit(BTUSB_TX_WAIT_VND_EVT, &data->flags);
return -ETIMEDOUT; err = -ETIMEDOUT;
goto err_free_wc;
} }
/* Parse and handle the return WMT event */ /* Parse and handle the return WMT event */
...@@ -3463,7 +3468,8 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev, ...@@ -3463,7 +3468,8 @@ static int btusb_mtk_hci_wmt_sync(struct hci_dev *hdev,
err_free_skb: err_free_skb:
kfree_skb(data->evt_skb); kfree_skb(data->evt_skb);
data->evt_skb = NULL; data->evt_skb = NULL;
err_free_wc:
kfree(wc);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment