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>
This commit is contained in:
Mithlesh Thukral 2009-03-25 15:51:49 +05:30 коммит произвёл Greg Kroah-Hartman
Родитель cc4b8dfc3f
Коммит b824adc968
1 изменённых файлов: 58 добавлений и 35 удалений

Просмотреть файл

@ -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);