📄 skcsum.c
字号:
/* Get length of IP data portion. */
IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength;
/* Calculate the sum of all pseudo header fields (16-bit). */
PseudoHeaderChecksum =
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_SOURCE_ADDRESS + 0) +
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_SOURCE_ADDRESS + 2) +
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_DESTINATION_ADDRESS + 0) +
(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
SKCS_OFS_IP_DESTINATION_ADDRESS + 2) +
(unsigned long) SKCS_HTON16(NextLevelProtocol) +
(unsigned long) SKCS_HTON16(IpDataLength);
/* Add-in any carries. */
SKCS_OC_ADD(PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
/* Add-in any new carry. */
SKCS_OC_ADD(pPacketInfo->PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
pPacketInfo->ProtocolFlags = ProtocolFlags;
NextLevelProtoStats->TxOkCts++; /* Success. */
} /* SkCsGetSendInfo */
/******************************************************************************
*
* SkCsGetReceiveInfo - verify checksum information for a received packet
*
* Description:
* Verify a received frame's checksum. The function returns a status code
* reflecting the result of the verification.
*
* Note:
* Before calling this function you have to verify that the frame is
* not padded and Checksum1 and Checksum2 are bigger than 1.
*
* Arguments:
* pAc - Pointer to adapter context struct.
*
* pIpHeader - Pointer to IP header. Must be at least the length in bytes
* of the received IP header including any option fields. For UDP packets,
* 8 additional bytes are needed to access the UDP checksum.
*
* Note: The actual length of the IP header is stored in the lower four
* bits of the first octet of the IP header as the number of 4-byte words,
* so it must be multiplied by four to get the length in bytes. Thus, the
* maximum IP header length is 15 * 4 = 60 bytes.
*
* Checksum1 - The first 16-bit Internet Checksum calculated by the
* hardware starting at the offset returned by SkCsSetReceiveFlags().
*
* Checksum2 - The second 16-bit Internet Checksum calculated by the
* hardware starting at the offset returned by SkCsSetReceiveFlags().
*
* NetNumber - The net number.
*
* Len - The packet length (without MAC header) - never access memory
* behind pIpHeader[Len].
*
* Returns:
* SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
* SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
* SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame.
* SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame
* SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok).
* SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame).
* SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok).
* SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok).
* SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok.
* SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok.
* SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum.
* SKCS_STATUS_NO_CSUM_POSSIBLE - Checksum could not be built (various reasons).
*
* Note: If SKCS_OVERWRITE_STATUS is defined, the SKCS_STATUS_XXX values
* returned here can be defined in some header file by the module using CSUM.
* In this way, the calling module can assign return values for its own needs,
* e.g. by assigning bit flags to the individual protocols.
*/
SKCS_STATUS SkCsGetReceiveInfo(
SK_AC *pAc, /* Adapter context struct. */
void *pIpHeader, /* IP header. */
unsigned Checksum1, /* Hardware checksum 1. */
unsigned Checksum2, /* Hardware checksum 2. */
int NetNumber, /* Net number. */
unsigned Len) /* Packet length (without MAC header). */
{
/* Internet Header Version found in IP header. */
unsigned InternetHeaderVersion;
/* Length of the IP header as found in IP header. */
unsigned IpHeaderLength;
/* Length of IP data portion. */
unsigned IpDataLength;
/* IP header checksum. */
unsigned IpHeaderChecksum;
/* IP header options checksum, if any. */
unsigned IpOptionsChecksum;
/* IP data checksum, i.e. TCP/UDP checksum. */
unsigned IpDataChecksum;
/* Next level protocol identifier found in IP header. */
unsigned NextLevelProtocol;
/* The checksum of the "next level protocol", i.e. TCP or UDP. */
unsigned long NextLevelProtocolChecksum;
/* Pointer to next level protocol statistics structure. */
SKCS_PROTO_STATS *NextLevelProtoStats;
/* Temporary variable. */
unsigned Tmp;
#ifdef SK_IPV6_SUPPORT
/* For parsing IPv6 packets */
SK_U8 *pDst;
SK_U32 ProtCsum;
SK_U32 Pseudo;
SK_U32 Pseudo2;
SK_U16 Offset;
SK_U16 NextHeaderOffset;
SK_U16 OptSize;
SK_U8 NextHeader;
#endif
if (SKCS_IDX_CHECK(Len, SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH)) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
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. */
#ifdef SK_IPV6_SUPPORT
if (InternetHeaderVersion == 6) { /* IPv6? */
if ((pAc->Csum.ReceiveFlags[NetNumber] &
(SKCS_PROTO_TCPV6 | SKCS_PROTO_UDPV6)) == 0) {
/* The OS/stack told us not to verify IPv6 checksum. */
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
/* Get the payload length. the payload starts immediately after the
* IPv6 header. This value includes all additional headers!
*/
/* first test if the frame has at least the length of the IPv6 header */
if (Len < SKCS_IP6_HEADER_SIZE) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
IpDataLength = *(SK_U16 *)
SKCS_IDX(pIpHeader, SKCS_OFS_IP6_PAYLOAD_LENGTH);
IpDataLength = SKCS_NTOH16(IpDataLength);
/* Before we can proceed we need to find the protocol frame that
* contains the checksum. We support TCP and UDP.
*/
Offset = SKCS_IP6_HEADER_SIZE;
NextHeaderOffset = SKCS_OFS_IP6_NEXT_HEADER;
/* this access has been secured by checking frame len against SKCS_IP6_HEADER_SIZE */
NextHeader = *(SK_U8 *) SKCS_IDX(pIpHeader, NextHeaderOffset);
pDst = (SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP6_DESTINATION_ADDRESS);
do {
if ((NextHeader == SKCS_PROTO_ID_TCP) ||
(NextHeader == SKCS_PROTO_ID_UDP)) {
/* We found the TCP/UDP header */
break;
}
/* Check type of next header to find "Next Header" field */
switch (NextHeader) {
case 0: /* hop-by-hop options header */
case 60: /* Destination options header */
NextHeaderOffset = Offset;
/*
* Calculate the size of the option header. The size is in
* units of 8-octets and does not contain the first 8 octets.
*/
if (SKCS_IDX_CHECK(Len, (unsigned) (NextHeaderOffset + 1))) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
OptSize = *(SK_U8 *) SKCS_IDX(pIpHeader, NextHeaderOffset + 1);
OptSize *= 8;
Offset += OptSize + 8;
break;
case 43: /* routing header */
NextHeaderOffset = Offset;
/*
* Calculate the size of the option header. The size is in
* units of 8-octets and does not contain the first 8 octets.
*/
if (SKCS_IDX_CHECK(Len, (unsigned) (NextHeaderOffset + 1))) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
OptSize = *(SK_U8 *) SKCS_IDX(pIpHeader, NextHeaderOffset + 1);
OptSize *= 8;
Offset += OptSize + 8;
/*
* If SegLeft != 0, use the last address in the routing header
* as IP dst in the pseudo header (for both, type 0 and type 2).
*/
if (*(SK_U8 *) SKCS_IDX(pIpHeader, NextHeaderOffset + 3) != 0) {
SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
("Rx: IPv6 Routing Header with SegLeft != 0.\n"));
pDst = (SK_U8 *) SKCS_IDX(pIpHeader, Offset - 16);
}
break;
case 44: /* fragment header */
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_IP_FRAGMENT);
case 46: /* resource ReSerVation protocol */
case 41: /* encapsulated IPv6 header */
case 59: /* No next header */
SK_DBG_MSG(
pAc,
SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
("Rx: Header in IPv6 packet can not be processed: %u.\n",
NextHeader));
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
case 51: /* authentication header, would have to use OptSize *= 4! */
case 50: /* encapsulating security payload */
case 58: /* ICMP v6 */
default:
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
/* Continue with the next header */
if (SKCS_IDX_CHECK(Len, NextHeaderOffset)) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
NextHeader = *(SK_U8 *) SKCS_IDX(pIpHeader, NextHeaderOffset);
} while (Offset < (IpDataLength + SKCS_IP6_HEADER_SIZE));
if (Offset >= (IpDataLength + SKCS_IP6_HEADER_SIZE)) {
/* We passed the end of the packet without finding the payload. */
SK_DBG_MSG(
pAc,
SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
("Rx: malformed IPv6 packet.\n"));
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
/* Before starting checksum calculating, check if we really need to. */
if ((NextHeader == SKCS_PROTO_ID_TCP) &&
(((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_TCPV6) == 0))) {
/* Header is TCP but we shall not verify TCP checksum. */
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
if ((NextHeader == SKCS_PROTO_ID_UDP) &&
(((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_UDPV6) == 0))) {
/* Header is UDP but we shall not verify UDP checksum. */
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
if (IpDataLength + SKCS_IP6_HEADER_SIZE > Len) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
ProtCsum = SkCsCalculateChecksum(
SKCS_IDX(pIpHeader, Offset),
IpDataLength + SKCS_IP6_HEADER_SIZE -Offset);
/*
* Calculate the pseudo header checksum.
*/
/* Start with src and dest address */
/* this access has been secured by checking frame len against SKCS_IP6_HEADER_SIZE */
Pseudo = SkCsCalculateChecksum(
SKCS_IDX(pIpHeader, SKCS_OFS_IP6_SOURCE_ADDRESS), 16);
Pseudo2 = SkCsCalculateChecksum(pDst, 16);
SKCS_OC_ADD(Pseudo, Pseudo, Pseudo2);
SKCS_OC_ADD(Pseudo, Pseudo, 0); /* Add-in any carries. */
SKCS_OC_ADD(Pseudo, Pseudo,
SKCS_HTON16(IpDataLength + SKCS_IP6_HEADER_SIZE -Offset));
SKCS_OC_ADD(Pseudo, Pseudo, SKCS_HTON16(NextHeader));
SKCS_OC_ADD(Pseudo, Pseudo, 0); /* Add-in any carries. */
/* Add to protocol part's checksum */
SKCS_OC_ADD(ProtCsum, ProtCsum, Pseudo);
SKCS_OC_ADD(ProtCsum, ProtCsum, 0); /* Add-in any carries. */
/*
* Check result. We can only process TCP or UDP.
*/
switch (NextHeader) {
case SKCS_PROTO_ID_TCP:
if (ProtCsum != 0xFFFF) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP].RxErrCts++;
return (SKCS_STATUS_TCP_CSUM_ERROR);
}
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP].RxOkCts++;
return (SKCS_STATUS_TCP_CSUM_OK);
case SKCS_PROTO_ID_UDP:
if (ProtCsum != 0xFFFF) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP].RxErrCts++;
return (SKCS_STATUS_UDP_CSUM_ERROR);
}
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP].RxOkCts++;
return (SKCS_STATUS_UDP_CSUM_OK);
default:
/* This case should already be eliminated because we only compute
* the checksum for TCP, UDP or ICMPv6
*/
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
}
#endif /* SK_IPV6_SUPPORT */
if (InternetHeaderVersion != 4) { /* IPv4? */
SK_DBG_MSG(pAc, SK_DBGMOD_CSUM, SK_DBGCAT_ERR | SK_DBGCAT_RX,
("Rx: Unknown Internet Header Version %u.\n",
InternetHeaderVersion));
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_UNKNOWN_IP_VERSION);
}
/* 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;
/* 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_RX,
("Rx: Invalid IP Header Length %u.\n", IpHeaderLength));
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++;
return (SKCS_STATUS_IP_CSUM_ERROR);
}
/* This is an IPv4 frame with a header of valid length. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -