📄 skcsum.c
字号:
/******************************************************************************
*
* Name: skcsum.c
* Project: GEnesis, PCI Gigabit Ethernet Adapter
* Version: $Revision: 2.4 $
* Date: $Date: 2007/03/14 16:20:40 $
* Purpose: Store/verify Internet checksum in send/receive packets.
*
******************************************************************************/
/******************************************************************************
*
* LICENSE:
* (C)Copyright Marvell.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The information in this file is provided "AS IS" without warranty.
* /LICENSE
*
******************************************************************************/
#ifdef SK_USE_CSUM /* Check if CSUM is to be used. */
#ifndef lint
static const char SysKonnectFileId[] =
"@(#) $Id: skcsum.c,v 2.4 2007/03/14 16:20:40 rassmann Exp $ (C) SysKonnect.";
#endif /* !lint */
/******************************************************************************
*
* Description:
*
* This is the "GEnesis" common module "CSUM".
*
* This module contains the code necessary to calculate, store, and verify the
* Internet Checksum of IP, TCP, and UDP frames.
*
* "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon"
* and is the code name of this SysKonnect project.
*
* Compilation Options:
*
* SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an
* empty module.
*
* SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id
* definitions. In this case, all SKCS_PROTO_xxx definitions must be made
* external.
*
* SKCS_OVERWRITE_STATUS - Define to overwrite the default return status
* definitions. In this case, all SKCS_STATUS_xxx definitions must be made
* external.
*
* Include File Hierarchy:
*
* "h/skdrv1st.h"
* "h/skcsum.h"
* "h/sktypes.h"
* "h/skqueue.h"
* "h/skdrv2nd.h"
*
******************************************************************************/
#include "h/skdrv1st.h"
#include "h/skcsum.h"
#include "h/skdrv2nd.h"
/* defines ********************************************************************/
/* The size of an Ethernet MAC header. */
#define SKCS_ETHERNET_MAC_HEADER_SIZE (6+6+2)
/* The size of the used topology's MAC header. */
#define SKCS_MAC_HEADER_SIZE SKCS_ETHERNET_MAC_HEADER_SIZE
/*
* Field offsets within the IPv4 header.
*/
/* "Internet Header Version" and "Length". */
#define SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH 0
/* "Total Length". */
#define SKCS_OFS_IP_TOTAL_LENGTH 2
/* "Flags" "Fragment Offset". */
#define SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET 6
/* "Next Level Protocol" identifier. */
#define SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL 9
/* Source IP address. */
#define SKCS_OFS_IP_SOURCE_ADDRESS 12
/* Destination IP address. */
#define SKCS_OFS_IP_DESTINATION_ADDRESS 16
#ifdef SK_IPV6_SUPPORT
/*
* Field offsets in the IPv6 header
*/
/* Payload length field (size without IP header) */
#define SKCS_OFS_IP6_PAYLOAD_LENGTH 4
/* Next header identifier */
#define SKCS_OFS_IP6_NEXT_HEADER 6
/* Source IP adress (16 byte) */
#define SKCS_OFS_IP6_SOURCE_ADDRESS 8
/* Destination IP address (16 byte) */
#define SKCS_OFS_IP6_DESTINATION_ADDRESS 32
#endif /* SK_IPV6_SUPPORT */
/*
* Field offsets within the UDP header.
*/
/* UDP checksum. */
#define SKCS_OFS_UDP_CHECKSUM 6
/* IP "Next Level Protocol" identifiers (see RFC 790). */
#define SKCS_PROTO_ID_TCP 6 /* Transport Control Protocol */
#define SKCS_PROTO_ID_UDP 17 /* User Datagram Protocol */
#ifdef SK_IPV6_SUPPORT
#define SKCS_PROTO_ID_ICMPV6 58 /* ICMPv6 */
#define SKCS_PROTO_ID_NONE 59 /* No next header (used with IPv6) */
#endif /* SK_IPV6_SUPPORT */
/* IP "Don't Fragment" bit. */
#define SKCS_IP_DONT_FRAGMENT SKCS_HTON16(0x4000)
/* Add a byte offset to a pointer. */
#define SKCS_IDX(pPtr, Ofs) ((void *) ((char *) (pPtr) + (Ofs)))
/* Check whether offset is within buffer. */
#define SKCS_IDX_CHECK(Le, Ofs) ((Le) <= (Ofs))
/*
* Macros that convert host to network representation and vice versa, i.e.
* little/big endian conversion on little endian machines only.
*/
#ifdef SK_LITTLE_ENDIAN
#define SKCS_HTON16(Val16) (((unsigned) (Val16) >> 8) | (((Val16) & 0xff) << 8))
#endif /* SK_LITTLE_ENDIAN */
#ifdef SK_BIG_ENDIAN
#define SKCS_HTON16(Val16) (Val16)
#endif /* SK_BIG_ENDIAN */
#define SKCS_NTOH16(Val16) SKCS_HTON16(Val16)
/* typedefs *******************************************************************/
/* function prototypes ********************************************************/
/******************************************************************************
*
* SkCsGetSendInfo - get checksum information for a send packet
*
* Description:
* Get all checksum information necessary to send a TCP or UDP packet. The
* function checks the IP header passed to it. If the high-level protocol
* is either TCP or UDP the pseudo header checksum is calculated and
* returned.
*
* The function returns the total length of the IP header (including any
* IP option fields), which is the same as the start offset of the IP data
* which in turn is the start offset of the TCP or UDP header.
*
* The function also returns the TCP or UDP pseudo header checksum, which
* should be used as the start value for the hardware checksum calculation.
* (Note that any actual pseudo header checksum can never calculate to
* zero.)
*
* Note:
* There is a bug in the GENESIS ASIC which may lead to wrong checksums.
*
* Arguments:
* pAc - A pointer to the adapter context struct.
*
* pIpHeader - Pointer to IP header. Must be at least the IP header *not*
* including any option fields, i.e. at least 20 bytes.
*
* Note: This pointer will be used to address 8-, 16-, and 32-bit
* variables with the respective alignment offsets relative to the pointer.
* Thus, the pointer should point to a 32-bit aligned address. If the
* target system cannot address 32-bit variables on non 32-bit aligned
* addresses, then the pointer *must* point to a 32-bit aligned address.
*
* pPacketInfo - A pointer to the packet information structure for this
* packet. Before calling this SkCsGetSendInfo(), the following field must
* be initialized:
*
* ProtocolFlags - Initialize with any combination of
* SKCS_PROTO_XXX bit flags. SkCsGetSendInfo() will only work on
* the protocols specified here. Any protocol(s) not specified
* here will be ignored.
*
* Note: Only one checksum can be calculated in hardware. Thus, if
* SKCS_PROTO_IP is specified in the 'ProtocolFlags',
* SkCsGetSendInfo() must calculate the IP header checksum in
* software. It might be a better idea to have the calling
* protocol stack calculate the IP header checksum.
*
* Returns: N/A
* On return, the following fields in 'pPacketInfo' may or may not have
* been filled with information, depending on the protocol(s) found in the
* packet:
*
* ProtocolFlags - Returns the SKCS_PROTO_XXX bit flags of the protocol(s)
* that were both requested by the caller and actually found in the packet.
* Protocol(s) not specified by the caller and/or not found in the packet
* will have their respective SKCS_PROTO_XXX bit flags reset.
*
* Note: For IP fragments, TCP and UDP packet information is ignored.
*
* IpHeaderLength - The total length in bytes of the complete IP header
* including any option fields is returned here. This is the start offset
* of the IP data, i.e. the TCP or UDP header if present.
*
* IpHeaderChecksum - If IP has been specified in the 'ProtocolFlags', the
* 16-bit Internet Checksum of the IP header is returned here. This value
* is to be stored into the packet's 'IP Header Checksum' field.
*
* PseudoHeaderChecksum - If this is a TCP or UDP packet and if TCP or UDP
* has been specified in the 'ProtocolFlags', the 16-bit Internet Checksum
* of the TCP or UDP pseudo header is returned here.
*/
void SkCsGetSendInfo(
SK_AC *pAc, /* Adapter context struct. */
void *pIpHeader, /* IP header. */
SKCS_PACKET_INFO *pPacketInfo, /* Packet information struct. */
int NetNumber) /* Net number */
{
/* Internet Header Version found in IP header. */
unsigned InternetHeaderVersion;
/* Length of the IP header as found in IP header. */
unsigned IpHeaderLength;
/* Bit field specifiying the desired/found protocols. */
unsigned ProtocolFlags;
/* Next level protocol identifier found in IP header. */
unsigned NextLevelProtocol;
/* Length of IP data portion. */
unsigned IpDataLength;
/* TCP/UDP pseudo header checksum. */
unsigned long PseudoHeaderChecksum;
/* Pointer to next level protocol statistics structure. */
SKCS_PROTO_STATS *NextLevelProtoStats;
/* Temporary variable. */
unsigned Tmp;
Tmp = *(SK_U8 *)
SKCS_IDX(pIpHeader, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH);
/* Get the Internet Header Version (IHV). */
/* Note: The IHV is stored in the upper four bits. */
InternetHeaderVersion = Tmp >> 4;
/* Check the Internet Header Version. */
/* Note: We currently only support IP version 4. */
if (InternetHeaderVersion != 4) { /* IPv4? */
SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX,
("Tx: Unknown Internet Header Version %u.\n",
InternetHeaderVersion));
pPacketInfo->ProtocolFlags = 0;
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++;
return;
}
/* Get the IP header length (IHL). */
/*
* Note: The IHL is stored in the lower four bits as the number of
* 4-byte words.
*/
IpHeaderLength = (Tmp & 0xf) * 4;
pPacketInfo->IpHeaderLength = IpHeaderLength;
/* Check the IP header length. */
/* 04-Aug-1998 sw - Really check the IHL? Necessary? */
if (IpHeaderLength < 5*4) {
SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_TX,
("Tx: Invalid IP Header Length %u.\n", IpHeaderLength));
pPacketInfo->ProtocolFlags = 0;
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxUnableCts++;
return;
}
/* This is an IPv4 frame with a header of valid length. */
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].TxOkCts++;
/* Check if we should calculate the IP header checksum. */
ProtocolFlags = pPacketInfo->ProtocolFlags;
if (ProtocolFlags & SKCS_PROTO_IP) {
pPacketInfo->IpHeaderChecksum =
SkCsCalculateChecksum(pIpHeader, IpHeaderLength);
}
/* Get the next level protocol identifier. */
NextLevelProtocol =
*(SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
/*
* Check if this is a TCP or UDP frame and if we should calculate the
* TCP/UDP pseudo header checksum.
*
* Also clear all protocol bit flags of protocols not present in the
* frame.
*/
if ((ProtocolFlags & SKCS_PROTO_TCP) != 0 &&
NextLevelProtocol == SKCS_PROTO_ID_TCP) {
/* TCP/IP frame. */
ProtocolFlags &= SKCS_PROTO_TCP | SKCS_PROTO_IP;
NextLevelProtoStats =
&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP];
}
else if ((ProtocolFlags & SKCS_PROTO_UDP) != 0 &&
NextLevelProtocol == SKCS_PROTO_ID_UDP) {
/* UDP/IP frame. */
ProtocolFlags &= SKCS_PROTO_UDP | SKCS_PROTO_IP;
NextLevelProtoStats =
&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP];
}
else {
/*
* Either not a TCP or UDP frame and/or TCP/UDP processing not
* specified.
*/
pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP;
return;
}
/* Check if this is an IP fragment. */
/*
* Note: An IP fragment has a non-zero "Fragment Offset" field and/or
* the "More Fragments" bit set. Thus, if both the "Fragment Offset"
* and the "More Fragments" are zero, it is *not* a fragment. We can
* easily check both at the same time since they are in the same 16-bit
* word.
*/
if ((*(SK_U16 *)
SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) &
~SKCS_IP_DONT_FRAGMENT) != 0) {
/* IP fragment; ignore all other protocols. */
pPacketInfo->ProtocolFlags = ProtocolFlags & SKCS_PROTO_IP;
NextLevelProtoStats->TxUnableCts++;
return;
}
/*
* Calculate the TCP/UDP pseudo header checksum.
*/
/* Get total length of IP header and data. */
IpDataLength =
*(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -