📄 skcsum.c
字号:
/* First test if the frame has at least the length of the IP header. */
if (Len < IpHeaderLength) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
/* Get the IP header and data checksum. */
IpDataChecksum = Checksum2;
/* Get the next level protocol identifier. */
/* this access has been secured by checking frame len against IpHeaderLength */
NextLevelProtocol = *(SK_U8 *)
SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_IP) != 0) {
/* IPv4 checksum verification is specified */
/*
* The IP header checksum is calculated as follows:
*
* IpHeaderChecksum = Checksum1 - Checksum2
*/
SKCS_OC_SUB(IpHeaderChecksum, Checksum1, Checksum2);
/* Check if any IP header options. */
if (IpHeaderLength > SKCS_IP_HEADER_SIZE) {
/*
* Get the IP options checksum.
*
* This access has been secured by checking the frame length
* against IpHeaderLength.
*/
IpOptionsChecksum = SkCsCalculateChecksum(
SKCS_IDX(pIpHeader, SKCS_IP_HEADER_SIZE),
IpHeaderLength - SKCS_IP_HEADER_SIZE);
/* Adjust the IP header and IP data checksums. */
SKCS_OC_ADD(IpHeaderChecksum, IpHeaderChecksum, IpOptionsChecksum);
SKCS_OC_SUB(IpDataChecksum, IpDataChecksum, IpOptionsChecksum);
}
/*
* Check if the IP header checksum is ok.
*
* NOTE: We must check the IP header checksum even if the caller
* just wants us to check upper-layer checksums, because we cannot do
* any further processing of the packet without a valid IP checksum.
*/
if (IpHeaderChecksum != 0xffff) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxErrCts++;
/* The NDIS tester wants to know the upper level protocol, too. */
if (NextLevelProtocol == SKCS_PROTO_ID_TCP) {
return(SKCS_STATUS_IP_CSUM_ERROR_TCP);
}
else if (NextLevelProtocol == SKCS_PROTO_ID_UDP) {
return(SKCS_STATUS_IP_CSUM_ERROR_UDP);
}
return (SKCS_STATUS_IP_CSUM_ERROR);
}
}
/*
* 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 ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_TCP) != 0 &&
NextLevelProtocol == SKCS_PROTO_ID_TCP) {
/* TCP/IP frame. */
NextLevelProtoStats =
&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_TCP];
}
else if ((pAc->Csum.ReceiveFlags[NetNumber] & SKCS_PROTO_UDP) != 0 &&
NextLevelProtocol == SKCS_PROTO_ID_UDP) {
/* UDP/IP frame. */
NextLevelProtoStats =
&pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_UDP];
}
else {
/*
* Either not a TCP or UDP frame and/or TCP/UDP processing not
* specified.
*/
return (SKCS_STATUS_IP_CSUM_OK);
}
/* 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.
*
* This access has been secured by checking the frame length
* against IpHeaderLength.
*/
if ((*(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET) &
~SKCS_IP_DONT_FRAGMENT) != 0) {
/* IP fragment; ignore all other protocols. */
NextLevelProtoStats->RxUnableCts++;
return (SKCS_STATUS_IP_FRAGMENT);
}
if (SKCS_IDX_CHECK(Len, (IpHeaderLength + 6 + 1))) {
pAc->Csum.ProtoStats[NetNumber][SKCS_PROTO_STATS_IP].RxUnableCts++;
return (SKCS_STATUS_NO_CSUM_POSSIBLE);
}
/*
* A checksum value of 0 in UDP over IPv4 frames means that no checksum
* was inserted by the sender (RFC 768).
*/
if (NextLevelProtocol == SKCS_PROTO_ID_UDP &&
*(SK_U16 *) SKCS_IDX(pIpHeader, IpHeaderLength + 6) == 0x0000) {
NextLevelProtoStats->RxOkCts++;
return (SKCS_STATUS_IP_CSUM_OK_NO_UDP);
}
/*
* Calculate the TCP/UDP checksum.
*/
/*
* Get total length of IP header and data.
*
* This access has been secured by checking the frame length
* against IpHeaderLength.
*/
IpDataLength =
*(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_TOTAL_LENGTH);
/* Get length of IP data portion. */
IpDataLength = SKCS_NTOH16(IpDataLength) - IpHeaderLength;
/*
* This access has been secured by checking the frame length
* against IpHeaderLength.
*/
NextLevelProtocolChecksum =
/* Calculate the pseudo header checksum. */
(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 the TCP/UDP header checksum. */
(unsigned long) IpDataChecksum;
/* Add-in any carries. */
SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0);
/* Add-in any new carry. */
SKCS_OC_ADD(NextLevelProtocolChecksum, NextLevelProtocolChecksum, 0);
/* Check if the TCP/UDP checksum is ok. */
if ((unsigned) NextLevelProtocolChecksum == 0xffff) {
/* TCP/UDP checksum ok. */
NextLevelProtoStats->RxOkCts++;
return (NextLevelProtocol == SKCS_PROTO_ID_TCP ?
SKCS_STATUS_TCP_CSUM_OK : SKCS_STATUS_UDP_CSUM_OK);
}
/* TCP/UDP checksum error. */
NextLevelProtoStats->RxErrCts++;
return (NextLevelProtocol == SKCS_PROTO_ID_TCP ?
SKCS_STATUS_TCP_CSUM_ERROR : SKCS_STATUS_UDP_CSUM_ERROR);
} /* SkCsGetReceiveInfo */
/******************************************************************************
*
* SkCsSetReceiveFlags - set checksum receive flags
*
* Description:
* Use this function to set the various receive flags. According to the
* protocol flags set by the caller, the start offsets within received
* packets of the two hardware checksums are returned. These offsets must
* be stored in all receive descriptors.
*
* Arguments:
* pAc - Pointer to adapter context struct.
*
* ReceiveFlags - Any combination of SK_PROTO_XXX flags of the protocols
* for which the caller wants checksum information on received frames.
*
* pChecksum1Offset - The start offset of the first receive descriptor
* hardware checksum to be calculated for received frames is returned
* here.
*
* pChecksum2Offset - The start offset of the second receive descriptor
* hardware checksum to be calculated for received frames is returned
* here.
*
* Returns: N/A
* Returns the two hardware checksum start offsets.
*/
void SkCsSetReceiveFlags(
SK_AC *pAc, /* Adapter context struct. */
unsigned ReceiveFlags, /* New receive flags. */
unsigned *pChecksum1Offset, /* Offset for hardware checksum 1. */
unsigned *pChecksum2Offset, /* Offset for hardware checksum 2. */
int NetNumber)
{
/* Save the receive flags. */
pAc->Csum.ReceiveFlags[NetNumber] = ReceiveFlags;
/* First checksum start offset is the IP header. */
*pChecksum1Offset = SKCS_MAC_HEADER_SIZE;
/*
* Second checksum start offset is the IP data. Note that this may vary
* if there are any IP header options in the actual packet.
*/
*pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE;
} /* SkCsSetReceiveFlags */
#ifndef SK_CS_CALCULATE_CHECKSUM
/******************************************************************************
*
* SkCsCalculateChecksum - calculate checksum for specified data
*
* Description:
* Calculate and return the 16-bit Internet Checksum for the specified
* data.
*
* Arguments:
* pData - Pointer to data for which the checksum shall be calculated.
* Note: The pointer should be aligned on a 16-bit boundary.
*
* Length - Length in bytes of data to checksum.
*
* Returns:
* The 16-bit Internet Checksum for the specified data.
*
* Note: The checksum is calculated in the machine's natural byte order,
* i.e. little vs. big endian. Thus, the resulting checksum is different
* for the same input data on little and big endian machines.
*
* However, when written back to the network packet, the byte order is
* always in correct network order.
*/
unsigned SkCsCalculateChecksum(
void *pData, /* Data to checksum. */
unsigned Length) /* Length of data. */
{
SK_U16 *pU16; /* Pointer to the data as 16-bit words. */
unsigned long Checksum; /* Checksum; must be at least 32 bits. */
/* Sum up all 16-bit words. */
pU16 = (SK_U16 *) pData;
for (Checksum = 0; Length > 1; Length -= 2) {
Checksum += *pU16++;
}
/* If this is an odd number of bytes, add-in the last byte. */
if (Length > 0) {
#ifdef SK_BIG_ENDIAN
/* Add the last byte as the high byte. */
Checksum += ((unsigned) *(SK_U8 *) pU16) << 8;
#else /* !SK_BIG_ENDIAN */
/* Add the last byte as the low byte. */
Checksum += *(SK_U8 *) pU16;
#endif /* !SK_BIG_ENDIAN */
}
/* Add-in any carries. */
SKCS_OC_ADD(Checksum, Checksum, 0);
/* Add-in any new carry. */
SKCS_OC_ADD(Checksum, Checksum, 0);
/* Note: All bits beyond the 16-bit limit are now zero. */
return ((unsigned) Checksum);
} /* SkCsCalculateChecksum */
#endif /* SK_CS_CALCULATE_CHECKSUM */
/******************************************************************************
*
* SkCsEvent - the CSUM event dispatcher
*
* Description:
* This is the event handler for the CSUM module.
*
* Arguments:
* pAc - Pointer to adapter context.
*
* Ioc - I/O context.
*
* Event - Event id.
*
* Param - Event dependent parameter.
*
* Returns:
* 0 (Success)
*/
int SkCsEvent(
SK_AC *pAc, /* Pointer to adapter context. */
SK_IOC Ioc, /* I/O context. */
SK_U32 Event, /* Event id. */
SK_EVPARA Param) /* Event dependent parameter. */
{
int ProtoIndex;
int NetNumber;
switch (Event) {
/*
* Clear protocol statistics.
*
* Param - Protocol index, or -1 for all protocols.
* - Net number.
*/
case SK_CSUM_EVENT_CLEAR_PROTO_STATS:
ProtoIndex = (int)Param.Para32[1];
NetNumber = (int)Param.Para32[0];
if (ProtoIndex < 0) { /* Clear for all protocols. */
if (NetNumber >= 0) {
SK_MEMSET(&pAc->Csum.ProtoStats[NetNumber][0], 0,
sizeof(pAc->Csum.ProtoStats[NetNumber]));
}
}
else { /* Clear for individual protocol. */
SK_MEMSET(&pAc->Csum.ProtoStats[NetNumber][ProtoIndex], 0,
sizeof(pAc->Csum.ProtoStats[NetNumber][ProtoIndex]));
}
break;
default:
break;
}
return (0); /* Success. */
} /* SkCsEvent */
#endif /* SK_USE_CSUM */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -