diff options
author | Mithlesh Thukral <mithlesh@linsyssoft.com> | 2009-03-25 06:21:49 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-04-17 14:06:31 -0400 |
commit | b824adc9686fb9a6edca164c13107bfed3e41d4e (patch) | |
tree | 44d7f0a710882e68e8679dcb06d2e4190fcf851b /drivers/staging | |
parent | cc4b8dfc3ff32f890cd5de0ce22de44f124d0d05 (diff) |
Staging: sxg: Fix leaks and checksum errors in transmit code path
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>
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/sxg/sxg.c | 93 |
1 files changed, 58 insertions, 35 deletions
diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c index 583fbb470e9..076b3f7d39e 100644 --- a/drivers/staging/sxg/sxg.c +++ b/drivers/staging/sxg/sxg.c | |||
@@ -2582,6 +2582,7 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, | |||
2582 | u64 phys_addr; | 2582 | u64 phys_addr; |
2583 | unsigned long flags; | 2583 | unsigned long flags; |
2584 | unsigned long queue_id=0; | 2584 | unsigned long queue_id=0; |
2585 | int offload_cksum = 0; | ||
2585 | 2586 | ||
2586 | SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSgl", | 2587 | SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSgl", |
2587 | pSgl, SxgSgl, 0, 0); | 2588 | pSgl, SxgSgl, 0, 0); |
@@ -2620,9 +2621,11 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, | |||
2620 | struct iphdr *ip; | 2621 | struct iphdr *ip; |
2621 | 2622 | ||
2622 | ip = ip_hdr(skb); | 2623 | ip = ip_hdr(skb); |
2623 | if (ip->protocol != IPPROTO_TCP || !tcp_hdr(skb)) | 2624 | if (ip->protocol == IPPROTO_TCP) |
2625 | offload_cksum = 1; | ||
2626 | if (!offload_cksum || !tcp_hdr(skb)) | ||
2624 | queue_id = 0; | 2627 | queue_id = 0; |
2625 | else if ((ip->protocol == IPPROTO_TCP)&&(DataLength >= sizeof( | 2628 | else if (offload_cksum && (DataLength >= sizeof( |
2626 | struct tcphdr))){ | 2629 | struct tcphdr))){ |
2627 | queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ? | 2630 | queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ? |
2628 | (ntohs (tcp_hdr(skb)->source) & | 2631 | (ntohs (tcp_hdr(skb)->source) & |
@@ -2631,10 +2634,11 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, | |||
2631 | SXG_LARGE_SEND_QUEUE_MASK)); | 2634 | SXG_LARGE_SEND_QUEUE_MASK)); |
2632 | } | 2635 | } |
2633 | } else if (skb->protocol == htons(ETH_P_IPV6)) { | 2636 | } else if (skb->protocol == htons(ETH_P_IPV6)) { |
2634 | if (ipv6_hdr(skb)->nexthdr != IPPROTO_TCP || !tcp_hdr(skb)) | 2637 | if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) |
2638 | offload_cksum = 1; | ||
2639 | if (!offload_cksum || !tcp_hdr(skb)) | ||
2635 | queue_id = 0; | 2640 | queue_id = 0; |
2636 | else if ((ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) && (DataLength | 2641 | else if (offload_cksum && (DataLength>=sizeof(struct tcphdr))){ |
2637 | >= sizeof(struct tcphdr)) ) { | ||
2638 | queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ? | 2642 | queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ? |
2639 | (ntohs (tcp_hdr(skb)->source) & | 2643 | (ntohs (tcp_hdr(skb)->source) & |
2640 | SXG_LARGE_SEND_QUEUE_MASK): | 2644 | SXG_LARGE_SEND_QUEUE_MASK): |
@@ -2663,23 +2667,38 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, | |||
2663 | } | 2667 | } |
2664 | SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbCmd", | 2668 | SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbCmd", |
2665 | XmtCmd, XmtRingInfo->Head, XmtRingInfo->Tail, 0); | 2669 | XmtCmd, XmtRingInfo->Head, XmtRingInfo->Tail, 0); |
2666 | /* Update stats */ | 2670 | memset(XmtCmd, '\0', sizeof(*XmtCmd)); |
2667 | adapter->stats.tx_packets++; | 2671 | XmtCmd->SgEntries = 1; |
2668 | adapter->stats.tx_bytes += DataLength; | 2672 | XmtCmd->Flags = 0; |
2669 | #if XXXTODO /* Stats stuff */ | 2673 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
2670 | if (SXG_MULTICAST_PACKET(EtherHdr)) { | 2674 | /* |
2671 | if (SXG_BROADCAST_PACKET(EtherHdr)) { | 2675 | * We need to set the Checkum in IP header to 0. This is |
2672 | adapter->Stats.DumbXmtBcastPkts++; | 2676 | * required by hardware. |
2673 | adapter->Stats.DumbXmtBcastBytes += DataLength; | 2677 | */ |
2678 | if (offload_cksum) { | ||
2679 | ip_hdr(skb)->check = 0x0; | ||
2680 | XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_IP; | ||
2681 | XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_TCP; | ||
2682 | /* | ||
2683 | * Dont know if length will require a change in | ||
2684 | * case of VLAN | ||
2685 | */ | ||
2686 | XmtCmd->CsumFlags.MacLen = ETH_HLEN; | ||
2687 | XmtCmd->CsumFlags.IpHl = skb_network_header_len(skb) >> | ||
2688 | SXG_NW_HDR_LEN_SHIFT; | ||
2674 | } else { | 2689 | } else { |
2675 | adapter->Stats.DumbXmtMcastPkts++; | 2690 | if (skb_checksum_help(skb)){ |
2676 | adapter->Stats.DumbXmtMcastBytes += DataLength; | 2691 | printk(KERN_EMERG "Dropped UDP packet for" |
2692 | " incorrect checksum calculation\n"); | ||
2693 | if (XmtCmd) | ||
2694 | SXG_ABORT_CMD(XmtRingInfo); | ||
2695 | spin_unlock_irqrestore(&adapter->XmtZeroLock, | ||
2696 | flags); | ||
2697 | return STATUS_SUCCESS; | ||
2698 | } | ||
2677 | } | 2699 | } |
2678 | } else { | ||
2679 | adapter->Stats.DumbXmtUcastPkts++; | ||
2680 | adapter->Stats.DumbXmtUcastBytes += DataLength; | ||
2681 | } | 2700 | } |
2682 | #endif | 2701 | |
2683 | /* | 2702 | /* |
2684 | * Fill in the command | 2703 | * Fill in the command |
2685 | * Copy out the first SGE to the command and adjust for offset | 2704 | * 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, | |||
2697 | (SXG_INVALID_SGL(phys_addr,skb->data_len))) | 2716 | (SXG_INVALID_SGL(phys_addr,skb->data_len))) |
2698 | { | 2717 | { |
2699 | spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); | 2718 | spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); |
2719 | if (XmtCmd) | ||
2720 | SXG_ABORT_CMD(XmtRingInfo); | ||
2700 | /* Silently drop this packet */ | 2721 | /* Silently drop this packet */ |
2701 | printk(KERN_EMERG"Dropped a packet for 64k boundary problem\n"); | 2722 | printk(KERN_EMERG"Dropped a packet for 64k boundary problem\n"); |
2702 | return STATUS_SUCCESS; | 2723 | return STATUS_SUCCESS; |
2703 | } | 2724 | } |
2704 | memset(XmtCmd, '\0', sizeof(*XmtCmd)); | ||
2705 | XmtCmd->Buffer.FirstSgeAddress = phys_addr; | 2725 | XmtCmd->Buffer.FirstSgeAddress = phys_addr; |
2706 | XmtCmd->Buffer.FirstSgeLength = DataLength; | 2726 | XmtCmd->Buffer.FirstSgeLength = DataLength; |
2707 | XmtCmd->Buffer.SgeOffset = 0; | 2727 | XmtCmd->Buffer.SgeOffset = 0; |
2708 | XmtCmd->Buffer.TotalLength = DataLength; | 2728 | XmtCmd->Buffer.TotalLength = DataLength; |
2709 | XmtCmd->SgEntries = 1; | ||
2710 | XmtCmd->Flags = 0; | ||
2711 | 2729 | ||
2712 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
2713 | /* | ||
2714 | * We need to set the Checkum in IP header to 0. This is | ||
2715 | * required by hardware. | ||
2716 | */ | ||
2717 | ip_hdr(skb)->check = 0x0; | ||
2718 | XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_IP; | ||
2719 | XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_TCP; | ||
2720 | /* Dont know if length will require a change in case of VLAN */ | ||
2721 | XmtCmd->CsumFlags.MacLen = ETH_HLEN; | ||
2722 | XmtCmd->CsumFlags.IpHl = skb_network_header_len(skb) >> | ||
2723 | SXG_NW_HDR_LEN_SHIFT; | ||
2724 | } | ||
2725 | /* | 2730 | /* |
2726 | * Advance transmit cmd descripter by 1. | 2731 | * Advance transmit cmd descripter by 1. |
2727 | * NOTE - See comments in SxgTcpOutput where we write | 2732 | * NOTE - See comments in SxgTcpOutput where we write |
@@ -2733,6 +2738,24 @@ static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, | |||
2733 | ASSERT((queue_id & ~SXG_LARGE_SEND_QUEUE_MASK) == 0); | 2738 | ASSERT((queue_id & ~SXG_LARGE_SEND_QUEUE_MASK) == 0); |
2734 | WRITE_REG(adapter->UcodeRegs[0].XmtCmd, ((queue_id << 16) | 1), TRUE); | 2739 | WRITE_REG(adapter->UcodeRegs[0].XmtCmd, ((queue_id << 16) | 1), TRUE); |
2735 | adapter->Stats.XmtQLen++; /* Stats within lock */ | 2740 | adapter->Stats.XmtQLen++; /* Stats within lock */ |
2741 | /* Update stats */ | ||
2742 | adapter->stats.tx_packets++; | ||
2743 | adapter->stats.tx_bytes += DataLength; | ||
2744 | #if XXXTODO /* Stats stuff */ | ||
2745 | if (SXG_MULTICAST_PACKET(EtherHdr)) { | ||
2746 | if (SXG_BROADCAST_PACKET(EtherHdr)) { | ||
2747 | adapter->Stats.DumbXmtBcastPkts++; | ||
2748 | adapter->Stats.DumbXmtBcastBytes += DataLength; | ||
2749 | } else { | ||
2750 | adapter->Stats.DumbXmtMcastPkts++; | ||
2751 | adapter->Stats.DumbXmtMcastBytes += DataLength; | ||
2752 | } | ||
2753 | } else { | ||
2754 | adapter->Stats.DumbXmtUcastPkts++; | ||
2755 | adapter->Stats.DumbXmtUcastBytes += DataLength; | ||
2756 | } | ||
2757 | #endif | ||
2758 | |||
2736 | spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); | 2759 | spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); |
2737 | SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDumSgl2", | 2760 | SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDumSgl2", |
2738 | XmtCmd, pSgl, SxgSgl, 0); | 2761 | XmtCmd, pSgl, SxgSgl, 0); |