From: Larry Finger <[email protected]>
Date: Wed, 13 Jul 2011 11:06:34 -0500
Subject: [PATCH] staging: rtl8192e: Fix kernel panics due to RX skb allocation 
failures

This driver uses RX skb's of O(2), thus it is possible for memory fragmentation
to prevent the allocation of a new one to replace a newly-received buffer.
When such a failure occurs, the kernel panics.

The fix is to drop an incoming packet whenever such an allocation fails. This
fix matches the one done in rtlwifi for other Realtek PCI devices.

Signed-off-by: Larry Finger <[email protected]>
---

Greg,

This patch fixes a nasty bug in the version of the RTL8192E driver recently
submitted by Mike McCormack.

Larry
---

Index: staging-2.6/drivers/staging/rtl8192e/rtl_core.c
===================================================================
--- staging-2.6.orig/drivers/staging/rtl8192e/rtl_core.c
+++ staging-2.6/drivers/staging/rtl8192e/rtl_core.c
@@ -2407,12 +2407,18 @@ void rtl8192_rx_normal(struct net_device
                rx_desc *pdesc = 
&priv->rx_ring[rx_queue_idx][priv->rx_idx[rx_queue_idx]];
                struct sk_buff *skb = 
priv->rx_buf[rx_queue_idx][priv->rx_idx[rx_queue_idx]];
 
-               if (pdesc->OWN){
+               if (pdesc->OWN) {
                        return;
                } else {
+                       struct sk_buff *new_skb;
 
-                       struct sk_buff *new_skb = NULL;
-                       if (!priv->ops->rx_query_status_descriptor(dev, &stats, 
pdesc, skb))
+                       if (!priv->ops->rx_query_status_descriptor(dev, &stats,
+                           pdesc, skb))
+                               goto done;
+                       new_skb = dev_alloc_skb(priv->rxbuffersize);
+                       /* if allocation of new skb failed - drop current packet
+                        * and reuse skb */
+                       if (unlikely(!new_skb))
                                goto done;
 
                        pci_unmap_single(priv->pdev,
@@ -2421,24 +2427,24 @@ void rtl8192_rx_normal(struct net_device
                                        PCI_DMA_FROMDEVICE);
 
                        skb_put(skb, pdesc->Length);
-                       skb_reserve(skb, stats.RxDrvInfoSize + 
stats.RxBufShift);
+                       skb_reserve(skb, stats.RxDrvInfoSize +
+                                   stats.RxBufShift);
                        skb_trim(skb, skb->len - 4/*sCrcLng*/);
                        rtllib_hdr = (struct rtllib_hdr_1addr *)skb->data;
-                       if (is_broadcast_ether_addr(rtllib_hdr->addr1)) {
-                       }else if (is_multicast_ether_addr(rtllib_hdr->addr1)){
-                       }else {
+                       if (!is_broadcast_ether_addr(rtllib_hdr->addr1) &&
+                           !is_multicast_ether_addr(rtllib_hdr->addr1)) {
                                /* unicast packet */
                                unicast_packet = true;
                        }
                        fc = le16_to_cpu(rtllib_hdr->frame_ctl);
                        type = WLAN_FC_GET_TYPE(fc);
                        if (type == RTLLIB_FTYPE_MGMT)
-                       {
                                bLedBlinking = false;
-                       }
+
                        if (bLedBlinking)
                                if (priv->rtllib->LedControlHandler)
-                               priv->rtllib->LedControlHandler(dev, 
LED_CTL_RX);
+                                       priv->rtllib->LedControlHandler(dev,
+                                                                LED_CTL_RX);
 
                        if (stats.bCRC) {
                                if (type != RTLLIB_FTYPE_MGMT)
@@ -2449,28 +2455,16 @@ void rtl8192_rx_normal(struct net_device
 
                        skb_len = skb->len;
 
-                       if (1)
-                       {
                        if (!rtllib_rx(priv->rtllib, skb, &stats)){
                                dev_kfree_skb_any(skb);
                        } else {
                                priv->stats.rxok++;
-                               if (unicast_packet) {
+                               if (unicast_packet)
                                        priv->stats.rxbytesunicast += skb_len;
-                               }
-                       }
-                       }else{
-                               dev_kfree_skb_any(skb);
                        }
 
-                       new_skb = dev_alloc_skb(priv->rxbuffersize);
-                       if (unlikely(!new_skb))
-                       {
-                               printk("==========>can't alloc skb for rx\n");
-                               goto done;
-                       }
-                       skb=new_skb;
-                        skb->dev = dev;
+                       skb = new_skb;
+                       skb->dev = dev;
 
                        priv->rx_buf[rx_queue_idx][priv->rx_idx[rx_queue_idx]] 
= skb;
                        *((dma_addr_t *) skb->cb) = pci_map_single(priv->pdev, 
skb_tail_pointer_rsl(skb), priv->rxbuffersize, PCI_DMA_FROMDEVICE);
_______________________________________________
devel mailing list
[email protected]
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel

Reply via email to