diff options
| author | Pengpeng Hou <pengpeng@iscas.ac.cn> | 2026-04-02 12:21:48 +0800 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-04-03 15:57:46 -0700 |
| commit | 5c14a19d5b1645cce1cb1252833d70b23635b632 (patch) | |
| tree | 16f06b64966b82ac404ad40be9320f7ccc3df08b /drivers | |
| parent | 77facb35227c421467cdb49268de433168c2dcef (diff) | |
| download | lwn-5c14a19d5b1645cce1cb1252833d70b23635b632.tar.gz lwn-5c14a19d5b1645cce1cb1252833d70b23635b632.zip | |
nfc: s3fwrn5: allocate rx skb before consuming bytes
s3fwrn82_uart_read() reports the number of accepted bytes to the serdev
core. The current code consumes bytes into recv_skb and may already
deliver a complete frame before allocating a fresh receive buffer.
If that alloc_skb() fails, the callback returns 0 even though it has
already consumed bytes, and it leaves recv_skb as NULL for the next
receive callback. That breaks the receive_buf() accounting contract and
can also lead to a NULL dereference on the next skb_put_u8().
Allocate the receive skb lazily before consuming the next byte instead.
If allocation fails, return the number of bytes already accepted.
Fixes: 3f52c2cb7e3a ("nfc: s3fwrn5: Support a UART interface")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Link: https://patch.msgid.link/20260402042148.65236-1-pengpeng@iscas.ac.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/nfc/s3fwrn5/uart.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/drivers/nfc/s3fwrn5/uart.c b/drivers/nfc/s3fwrn5/uart.c index 9c09c10c2a46..4ee481bd7e96 100644 --- a/drivers/nfc/s3fwrn5/uart.c +++ b/drivers/nfc/s3fwrn5/uart.c @@ -58,6 +58,12 @@ static size_t s3fwrn82_uart_read(struct serdev_device *serdev, size_t i; for (i = 0; i < count; i++) { + if (!phy->recv_skb) { + phy->recv_skb = alloc_skb(NCI_SKB_BUFF_LEN, GFP_KERNEL); + if (!phy->recv_skb) + return i; + } + skb_put_u8(phy->recv_skb, *data++); if (phy->recv_skb->len < S3FWRN82_NCI_HEADER) @@ -69,9 +75,7 @@ static size_t s3fwrn82_uart_read(struct serdev_device *serdev, s3fwrn5_recv_frame(phy->common.ndev, phy->recv_skb, phy->common.mode); - phy->recv_skb = alloc_skb(NCI_SKB_BUFF_LEN, GFP_KERNEL); - if (!phy->recv_skb) - return 0; + phy->recv_skb = NULL; } return i; |
