adm80211: add checks for dma mapping errors
authorAlexey Khoroshilov <khoroshilov@ispras.ru>
Fri, 2 Dec 2016 21:52:46 +0000 (00:52 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Mon, 5 Dec 2016 11:10:53 +0000 (13:10 +0200)
The driver does not check if mapping dma memory succeed.
The patch adds the checks and failure handling.

Found by Linux Driver Verification project (linuxtesting.org).

Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/admtek/adm8211.c

index 70ecd82d674dcee50aef2cbf64b321959f09544a..2b4a3eb38dfa0d5b403d11c6e2830e1d888e832f 100644 (file)
@@ -413,6 +413,13 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
                                                       skb_tail_pointer(newskb),
                                                       RX_PKT_SIZE,
                                                       PCI_DMA_FROMDEVICE);
+                               if (pci_dma_mapping_error(priv->pdev,
+                                          priv->rx_buffers[entry].mapping)) {
+                                       priv->rx_buffers[entry].skb = NULL;
+                                       dev_kfree_skb(newskb);
+                                       skb = NULL;
+                                       /* TODO: update rx dropped stats */
+                               }
                        } else {
                                skb = NULL;
                                /* TODO: update rx dropped stats */
@@ -1450,6 +1457,12 @@ static int adm8211_init_rings(struct ieee80211_hw *dev)
                                                  skb_tail_pointer(rx_info->skb),
                                                  RX_PKT_SIZE,
                                                  PCI_DMA_FROMDEVICE);
+               if (pci_dma_mapping_error(priv->pdev, rx_info->mapping)) {
+                       dev_kfree_skb(rx_info->skb);
+                       rx_info->skb = NULL;
+                       break;
+               }
+
                desc->buffer1 = cpu_to_le32(rx_info->mapping);
                desc->status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL);
        }
@@ -1613,7 +1626,7 @@ static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int
 }
 
 /* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
-static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
+static int adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
                           u16 plcp_signal,
                           size_t hdrlen)
 {
@@ -1625,6 +1638,8 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
 
        mapping = pci_map_single(priv->pdev, skb->data, skb->len,
                                 PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(priv->pdev, mapping))
+               return -ENOMEM;
 
        spin_lock_irqsave(&priv->lock, flags);
 
@@ -1657,6 +1672,8 @@ static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
 
        /* Trigger transmit poll */
        ADM8211_CSR_WRITE(TDR, 0);
+
+       return 0;
 }
 
 /* Put adm8211_tx_hdr on skb and transmit */
@@ -1710,7 +1727,10 @@ static void adm8211_tx(struct ieee80211_hw *dev,
 
        txhdr->retry_limit = info->control.rates[0].count;
 
-       adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
+       if (adm8211_tx_raw(dev, skb, plcp_signal, hdrlen)) {
+               /* Drop packet */
+               ieee80211_free_txskb(dev, skb);
+       }
 }
 
 static int adm8211_alloc_rings(struct ieee80211_hw *dev)