⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 skcsum.c

📁 这是Marvell Technology Group Ltd. 4355 (rev 12)网卡在linux下的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:

	/* 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 + -