mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-03 11:13:56 +08:00
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,
|
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_priv *rtlpriv = rtl_priv(hw);
|
||||||
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(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;
|
u8 tmp_one = 1;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
if (likely(new_skb)) {
|
||||||
|
skb = new_skb;
|
||||||
|
goto remap;
|
||||||
|
}
|
||||||
skb = dev_alloc_skb(rtlpci->rxbuffersize);
|
skb = dev_alloc_skb(rtlpci->rxbuffersize);
|
||||||
if (!skb)
|
if (!skb)
|
||||||
return 0;
|
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 */
|
/* just set skb->cb to mapping addr for pci_unmap_single use */
|
||||||
*((dma_addr_t *)skb->cb) =
|
*((dma_addr_t *)skb->cb) =
|
||||||
pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
|
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);
|
bufferaddress = *((dma_addr_t *)skb->cb);
|
||||||
if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
|
if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
|
||||||
return 0;
|
return 0;
|
||||||
|
rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
|
||||||
if (rtlpriv->use_new_trx_flow) {
|
if (rtlpriv->use_new_trx_flow) {
|
||||||
rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
|
rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
|
||||||
HW_DESC_RX_PREPARE,
|
HW_DESC_RX_PREPARE,
|
||||||
@ -781,6 +787,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
|
|||||||
/*rx pkt */
|
/*rx pkt */
|
||||||
struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[
|
struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[
|
||||||
rtlpci->rx_ring[rxring_idx].idx];
|
rtlpci->rx_ring[rxring_idx].idx];
|
||||||
|
struct sk_buff *new_skb;
|
||||||
|
|
||||||
if (rtlpriv->use_new_trx_flow) {
|
if (rtlpriv->use_new_trx_flow) {
|
||||||
rx_remained_cnt =
|
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),
|
pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb),
|
||||||
rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
|
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) {
|
if (rtlpriv->use_new_trx_flow) {
|
||||||
buffer_desc =
|
buffer_desc =
|
||||||
&rtlpci->rx_ring[rxring_idx].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);
|
schedule_work(&rtlpriv->works.lps_change_work);
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
|
skb = new_skb;
|
||||||
|
no_new:
|
||||||
if (rtlpriv->use_new_trx_flow) {
|
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,
|
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);
|
rtlpci->rx_ring[rxring_idx].idx);
|
||||||
|
|
||||||
if (rtlpci->rx_ring[rxring_idx].idx ==
|
if (rtlpci->rx_ring[rxring_idx].idx ==
|
||||||
rtlpci->rxringcount - 1)
|
rtlpci->rxringcount - 1)
|
||||||
rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc,
|
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;
|
rtlpci->rx_ring[rxring_idx].idx = 0;
|
||||||
for (i = 0; i < rtlpci->rxringcount; i++) {
|
for (i = 0; i < rtlpci->rxringcount; i++) {
|
||||||
entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[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))
|
rxring_idx, i))
|
||||||
return -ENOMEM;
|
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++) {
|
for (i = 0; i < rtlpci->rxringcount; i++) {
|
||||||
entry = &rtlpci->rx_ring[rxring_idx].desc[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))
|
rxring_idx, i))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user