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

mwifiex: fix tx_info/rx_info overlap with PCIe dma_mapping

On PCIe Tx data path, network interface specific tx_info
parameters such as bss_num and bss_type are saved at
"skb->cb + sizeof(dma_addr_t)" (returned by MWIFIEX_SKB_TXCB).
Later mwifiex_map_pci_memory() called from
mwifiex_pcie_send_data() will memcpy
sizeof(struct mwifiex_dma_mapping) bytes to save PCIe DMA
address and length information at beginning of skb->cb.
This accidently overwrites bss_num and bss_type saved in skb->cb
previously because bss_num/bss_type and mwifiex_dma_mapping data
overlap.
Similarly, on PCIe Rx data path, rx_info parameters overlaps
with PCIe DMA address and length information too.

Fix it by defining mwifiex_cb structure and having
MWIFIEX_SKB_TXCB and MWIFIEX_SKB_RXCB return the correct address
of tx_info/rx_info using the structure members.

Also add a BUILD_BUG_ON to maks sure that mwifiex_cb structure
doesn't exceed the size of skb->cb.

Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Signed-off-by: Chin-Ran Lo <crlo@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Chin-Ran Lo and committed by
John W. Linville
bca463e8 f15ec345

+39 -16
+2 -2
drivers/net/wireless/mwifiex/pcie.c
··· 50 50 return -1; 51 51 } 52 52 mapping.len = size; 53 - memcpy(skb->cb, &mapping, sizeof(mapping)); 53 + mwifiex_store_mapping(skb, &mapping); 54 54 return 0; 55 55 } 56 56 ··· 60 60 struct pcie_service_card *card = adapter->card; 61 61 struct mwifiex_dma_mapping mapping; 62 62 63 - MWIFIEX_SKB_PACB(skb, &mapping); 63 + mwifiex_get_mapping(skb, &mapping); 64 64 pci_unmap_single(card->dev, mapping.addr, mapping.len, flags); 65 65 } 66 66
+37 -14
drivers/net/wireless/mwifiex/util.h
··· 20 20 #ifndef _MWIFIEX_UTIL_H_ 21 21 #define _MWIFIEX_UTIL_H_ 22 22 23 - static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) 24 - { 25 - return (struct mwifiex_rxinfo *)(skb->cb + sizeof(dma_addr_t)); 26 - } 27 - 28 - static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) 29 - { 30 - return (struct mwifiex_txinfo *)(skb->cb + sizeof(dma_addr_t)); 31 - } 32 - 33 23 struct mwifiex_dma_mapping { 34 24 dma_addr_t addr; 35 25 size_t len; 36 26 }; 37 27 38 - static inline void MWIFIEX_SKB_PACB(struct sk_buff *skb, 39 - struct mwifiex_dma_mapping *mapping) 28 + struct mwifiex_cb { 29 + struct mwifiex_dma_mapping dma_mapping; 30 + union { 31 + struct mwifiex_rxinfo rx_info; 32 + struct mwifiex_txinfo tx_info; 33 + }; 34 + }; 35 + 36 + static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) 40 37 { 41 - memcpy(mapping, skb->cb, sizeof(*mapping)); 38 + struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb; 39 + 40 + BUILD_BUG_ON(sizeof(struct mwifiex_cb) > sizeof(skb->cb)); 41 + return &cb->rx_info; 42 + } 43 + 44 + static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) 45 + { 46 + struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb; 47 + 48 + return &cb->tx_info; 49 + } 50 + 51 + static inline void mwifiex_store_mapping(struct sk_buff *skb, 52 + struct mwifiex_dma_mapping *mapping) 53 + { 54 + struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb; 55 + 56 + memcpy(&cb->dma_mapping, mapping, sizeof(*mapping)); 57 + } 58 + 59 + static inline void mwifiex_get_mapping(struct sk_buff *skb, 60 + struct mwifiex_dma_mapping *mapping) 61 + { 62 + struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb; 63 + 64 + memcpy(mapping, &cb->dma_mapping, sizeof(*mapping)); 42 65 } 43 66 44 67 static inline dma_addr_t MWIFIEX_SKB_DMA_ADDR(struct sk_buff *skb) 45 68 { 46 69 struct mwifiex_dma_mapping mapping; 47 70 48 - MWIFIEX_SKB_PACB(skb, &mapping); 71 + mwifiex_get_mapping(skb, &mapping); 49 72 50 73 return mapping.addr; 51 74 }