forked from Minki/linux
rtlwifi: Fix error when accessing unmapped memory in skb
These drivers use 9100-byte receive buffers, thus allocating an skb requires an O(3) memory allocation. Under heavy memory loads and fragmentation, such a request can fail. Previous versions of the driver have dropped the packet and reused the old buffer; however, the new version introduced a bug in that it released the old buffer before trying to allocate a new one. The previous method is implemented here. The skb is unmapped before any attempt is made to allocate another. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Cc: Stable <stable@vger.kernel.org> [v3.18] Reported-by: Eric Biggers <ebiggers3@gmail.com> Cc: Eric Biggers <ebiggers3@gmail.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
7ce67a38f7
commit
e9538cf4f9
@ -666,7 +666,8 @@ tx_status_ok:
|
||||
}
|
||||
|
||||
static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
|
||||
u8 *entry, int rxring_idx, int desc_idx)
|
||||
struct sk_buff *new_skb, u8 *entry,
|
||||
int rxring_idx, int desc_idx)
|
||||
{
|
||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
|
||||
@ -674,11 +675,15 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
|
||||
u8 tmp_one = 1;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (likely(new_skb)) {
|
||||
skb = new_skb;
|
||||
goto remap;
|
||||
}
|
||||
skb = dev_alloc_skb(rtlpci->rxbuffersize);
|
||||
if (!skb)
|
||||
return 0;
|
||||
rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
|
||||
|
||||
remap:
|
||||
/* just set skb->cb to mapping addr for pci_unmap_single use */
|
||||
*((dma_addr_t *)skb->cb) =
|
||||
pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
|
||||
@ -686,6 +691,7 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
|
||||
bufferaddress = *((dma_addr_t *)skb->cb);
|
||||
if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
|
||||
return 0;
|
||||
rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
|
||||
if (rtlpriv->use_new_trx_flow) {
|
||||
rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
|
||||
HW_DESC_RX_PREPARE,
|
||||
@ -781,6 +787,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
|
||||
/*rx pkt */
|
||||
struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[
|
||||
rtlpci->rx_ring[rxring_idx].idx];
|
||||
struct sk_buff *new_skb;
|
||||
|
||||
if (rtlpriv->use_new_trx_flow) {
|
||||
rx_remained_cnt =
|
||||
@ -807,6 +814,13 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
|
||||
pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb),
|
||||
rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
|
||||
|
||||
/* get a new skb - if fail, old one will be reused */
|
||||
new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
|
||||
if (unlikely(!new_skb)) {
|
||||
pr_err("Allocation of new skb failed in %s\n",
|
||||
__func__);
|
||||
goto no_new;
|
||||
}
|
||||
if (rtlpriv->use_new_trx_flow) {
|
||||
buffer_desc =
|
||||
&rtlpci->rx_ring[rxring_idx].buffer_desc
|
||||
@ -911,14 +925,16 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
|
||||
schedule_work(&rtlpriv->works.lps_change_work);
|
||||
}
|
||||
end:
|
||||
skb = new_skb;
|
||||
no_new:
|
||||
if (rtlpriv->use_new_trx_flow) {
|
||||
_rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
|
||||
_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)buffer_desc,
|
||||
rxring_idx,
|
||||
rtlpci->rx_ring[rxring_idx].idx);
|
||||
} else {
|
||||
_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc,
|
||||
rxring_idx,
|
||||
rtlpci->rx_ring[rxring_idx].idx);
|
||||
} else {
|
||||
_rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc, rxring_idx,
|
||||
rtlpci->rx_ring[rxring_idx].idx);
|
||||
|
||||
if (rtlpci->rx_ring[rxring_idx].idx ==
|
||||
rtlpci->rxringcount - 1)
|
||||
rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc,
|
||||
@ -1307,7 +1323,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
|
||||
rtlpci->rx_ring[rxring_idx].idx = 0;
|
||||
for (i = 0; i < rtlpci->rxringcount; i++) {
|
||||
entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i];
|
||||
if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
|
||||
if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
|
||||
rxring_idx, i))
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -1332,7 +1348,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
|
||||
|
||||
for (i = 0; i < rtlpci->rxringcount; i++) {
|
||||
entry = &rtlpci->rx_ring[rxring_idx].desc[i];
|
||||
if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
|
||||
if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
|
||||
rxring_idx, i))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user