Staging: sxg: Fix leaks and checksum errors in transmit code path
authorMithlesh Thukral <mithlesh@linsyssoft.com>
Wed, 25 Mar 2009 10:21:49 +0000 (15:51 +0530)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 17 Apr 2009 18:06:31 +0000 (11:06 -0700)
Fix the transmit function for the following:
* Free XmtCmd in the error code path. This use to leak memory in
  error conditions.
* Do pci mapping after the checksum operations are over. They can
  reallocate the skb at a different location.
* Fix UDP checksum errors which were seen in wireshark

Signed-off-by: LinSysSoft Sahara Team <saharaproj@linsyssoft.com>
Signed-off-by: Mithlesh Thukral <mithlesh@linsyssoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/sxg/sxg.c

index 583fbb470e9dbeb9963b286584c3d5339b0b024e..076b3f7d39eb2904129120708b566236bf1f1634 100644 (file)
@@ -2582,6 +2582,7 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl,
        u64 phys_addr;
        unsigned long flags;
        unsigned long queue_id=0;
+       int offload_cksum = 0;
 
        SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSgl",
                  pSgl, SxgSgl, 0, 0);
@@ -2620,9 +2621,11 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl,
                 struct iphdr *ip;
 
                 ip = ip_hdr(skb);
-               if (ip->protocol != IPPROTO_TCP || !tcp_hdr(skb))
+               if (ip->protocol == IPPROTO_TCP)
+                       offload_cksum = 1;
+               if (!offload_cksum || !tcp_hdr(skb))
                        queue_id = 0;
-               else if ((ip->protocol == IPPROTO_TCP)&&(DataLength >= sizeof(
+               else if (offload_cksum && (DataLength >= sizeof(
                                                        struct tcphdr))){
                        queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ?
                                        (ntohs (tcp_hdr(skb)->source) &
@@ -2631,10 +2634,11 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl,
                                                SXG_LARGE_SEND_QUEUE_MASK));
                }
        } else if (skb->protocol == htons(ETH_P_IPV6)) {
-               if (ipv6_hdr(skb)->nexthdr != IPPROTO_TCP || !tcp_hdr(skb))
+               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+                       offload_cksum = 1;
+               if (!offload_cksum || !tcp_hdr(skb))
                        queue_id = 0;
-               else if ((ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) && (DataLength
-                                               >= sizeof(struct tcphdr)) ) {
+               else if (offload_cksum && (DataLength>=sizeof(struct tcphdr))){
                        queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ?
                                        (ntohs (tcp_hdr(skb)->source) &
                                        SXG_LARGE_SEND_QUEUE_MASK):
@@ -2663,23 +2667,38 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl,
        }
        SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbCmd",
                  XmtCmd, XmtRingInfo->Head, XmtRingInfo->Tail, 0);
-       /* Update stats */
-       adapter->stats.tx_packets++;
-       adapter->stats.tx_bytes += DataLength;
-#if XXXTODO                    /* Stats stuff */
-       if (SXG_MULTICAST_PACKET(EtherHdr)) {
-               if (SXG_BROADCAST_PACKET(EtherHdr)) {
-                       adapter->Stats.DumbXmtBcastPkts++;
-                       adapter->Stats.DumbXmtBcastBytes += DataLength;
+       memset(XmtCmd, '\0', sizeof(*XmtCmd));
+       XmtCmd->SgEntries = 1;
+       XmtCmd->Flags = 0;
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               /*
+                * We need to set the Checkum in IP  header to 0. This is
+                * required by hardware.
+                */
+               if (offload_cksum) {
+                       ip_hdr(skb)->check = 0x0;
+                       XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_IP;
+                       XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_TCP;
+                       /*
+                        * Dont know if length will require a change in
+                        * case of VLAN
+                        */
+                       XmtCmd->CsumFlags.MacLen = ETH_HLEN;
+                       XmtCmd->CsumFlags.IpHl = skb_network_header_len(skb) >>
+                                                       SXG_NW_HDR_LEN_SHIFT;
                } else {
-                       adapter->Stats.DumbXmtMcastPkts++;
-                       adapter->Stats.DumbXmtMcastBytes += DataLength;
+                       if (skb_checksum_help(skb)){
+                               printk(KERN_EMERG "Dropped UDP packet for"
+                                       " incorrect checksum calculation\n");
+                               if (XmtCmd)
+                                       SXG_ABORT_CMD(XmtRingInfo);
+                               spin_unlock_irqrestore(&adapter->XmtZeroLock,
+                                                        flags);
+                               return STATUS_SUCCESS;
+                       }
                }
-       } else {
-               adapter->Stats.DumbXmtUcastPkts++;
-               adapter->Stats.DumbXmtUcastBytes += DataLength;
        }
-#endif
+
        /*
         * Fill in the command
         * Copy out the first SGE to the command and adjust for offset
@@ -2697,31 +2716,17 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl,
                (SXG_INVALID_SGL(phys_addr,skb->data_len)))
        {
                spin_unlock_irqrestore(&adapter->XmtZeroLock, flags);
+               if (XmtCmd)
+                       SXG_ABORT_CMD(XmtRingInfo);
                /* Silently drop this packet */
                printk(KERN_EMERG"Dropped a packet for 64k boundary problem\n");
                return STATUS_SUCCESS;
        }
-       memset(XmtCmd, '\0', sizeof(*XmtCmd));
        XmtCmd->Buffer.FirstSgeAddress = phys_addr;
        XmtCmd->Buffer.FirstSgeLength = DataLength;
        XmtCmd->Buffer.SgeOffset = 0;
        XmtCmd->Buffer.TotalLength = DataLength;
-       XmtCmd->SgEntries = 1;
-       XmtCmd->Flags = 0;
 
-       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               /*
-                * We need to set the Checkum in IP  header to 0. This is
-                * required by hardware.
-                */
-               ip_hdr(skb)->check = 0x0;
-               XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_IP;
-               XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_TCP;
-               /* Dont know if length will require a change in case of VLAN */
-               XmtCmd->CsumFlags.MacLen = ETH_HLEN;
-               XmtCmd->CsumFlags.IpHl = skb_network_header_len(skb) >>
-                                                       SXG_NW_HDR_LEN_SHIFT;
-       }
        /*
         * Advance transmit cmd descripter by 1.
         * NOTE - See comments in SxgTcpOutput where we write
@@ -2733,6 +2738,24 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl,
        ASSERT((queue_id & ~SXG_LARGE_SEND_QUEUE_MASK) == 0);
        WRITE_REG(adapter->UcodeRegs[0].XmtCmd, ((queue_id << 16) | 1), TRUE);
        adapter->Stats.XmtQLen++;       /* Stats within lock */
+       /* Update stats */
+       adapter->stats.tx_packets++;
+       adapter->stats.tx_bytes += DataLength;
+#if XXXTODO                    /* Stats stuff */
+       if (SXG_MULTICAST_PACKET(EtherHdr)) {
+               if (SXG_BROADCAST_PACKET(EtherHdr)) {
+                       adapter->Stats.DumbXmtBcastPkts++;
+                       adapter->Stats.DumbXmtBcastBytes += DataLength;
+               } else {
+                       adapter->Stats.DumbXmtMcastPkts++;
+                       adapter->Stats.DumbXmtMcastBytes += DataLength;
+               }
+       } else {
+               adapter->Stats.DumbXmtUcastPkts++;
+               adapter->Stats.DumbXmtUcastBytes += DataLength;
+       }
+#endif
+
        spin_unlock_irqrestore(&adapter->XmtZeroLock, flags);
        SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDumSgl2",
                  XmtCmd, pSgl, SxgSgl, 0);