Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

brcmfmac: fix txglomming scatter-gather packet transfers

The driver concatenates multiple packets in one MMC transfer. For
scatter-gather to work the total length need to be multiple of 512
bytes. A pre-allocated buffer was used to add padding to accomplish
that. However, the length was not properly set and it was freed after
the first transfer causing a crash.

Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Arend van Spriel and committed by
John W. Linville
1eb43018 21f8aaee

+4 -10
+4 -10
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
··· 457 457 458 458 u8 tx_hdrlen; /* sdio bus header length for tx packet */ 459 459 bool txglom; /* host tx glomming enable flag */ 460 - struct sk_buff *txglom_sgpad; /* scatter-gather padding buffer */ 461 460 u16 head_align; /* buffer pointer alignment */ 462 461 u16 sgentry_align; /* scatter-gather buffer alignment */ 463 462 }; ··· 1943 1944 if (lastfrm && chain_pad) 1944 1945 tail_pad += blksize - chain_pad; 1945 1946 if (skb_tailroom(pkt) < tail_pad && pkt->len > blksize) { 1946 - pkt_pad = bus->txglom_sgpad; 1947 - if (pkt_pad == NULL) 1948 - brcmu_pkt_buf_get_skb(tail_pad + tail_chop); 1947 + pkt_pad = brcmu_pkt_buf_get_skb(tail_pad + tail_chop + 1948 + bus->head_align); 1949 1949 if (pkt_pad == NULL) 1950 1950 return -ENOMEM; 1951 1951 ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad); ··· 1955 1957 tail_chop); 1956 1958 *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop; 1957 1959 skb_trim(pkt, pkt->len - tail_chop); 1960 + skb_trim(pkt_pad, tail_pad + tail_chop); 1958 1961 __skb_queue_after(pktq, pkt, pkt_pad); 1959 1962 } else { 1960 1963 ntail = pkt->data_len + tail_pad - ··· 2010 2011 return ret; 2011 2012 head_pad = (u16)ret; 2012 2013 if (head_pad) 2013 - memset(pkt_next->data, 0, head_pad + bus->tx_hdrlen); 2014 + memset(pkt_next->data + bus->tx_hdrlen, 0, head_pad); 2014 2015 2015 2016 total_len += pkt_next->len; 2016 2017 ··· 3485 3486 bus->txglom = false; 3486 3487 value = 1; 3487 3488 pad_size = bus->sdiodev->func[2]->cur_blksize << 1; 3488 - bus->txglom_sgpad = brcmu_pkt_buf_get_skb(pad_size); 3489 - if (!bus->txglom_sgpad) 3490 - brcmf_err("allocating txglom padding skb failed, reduced performance\n"); 3491 - 3492 3489 err = brcmf_iovar_data_set(bus->sdiodev->dev, "bus:rxglom", 3493 3490 &value, sizeof(u32)); 3494 3491 if (err < 0) { ··· 4048 4053 brcmf_sdio_chip_detach(&bus->ci); 4049 4054 } 4050 4055 4051 - brcmu_pkt_buf_free_skb(bus->txglom_sgpad); 4052 4056 kfree(bus->rxbuf); 4053 4057 kfree(bus->hdrbuf); 4054 4058 kfree(bus);