patch-2.4.0-test9 linux/drivers/net/sk98lin/skcsum.c

Next file: linux/drivers/net/sk98lin/skge.c
Previous file: linux/drivers/net/sk98lin/skaddr.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skcsum.c linux/drivers/net/sk98lin/skcsum.c
@@ -2,19 +2,17 @@
  *
  * Name:	skcsum.c
  * Project:	GEnesis, PCI Gigabit Ethernet Adapter
- * Version:	$Revision: 1.3 $
- * Date:	$Date: 1999/05/10 08:39:33 $
+ * Version:	$Revision: 1.7 $
+ * Date:	$Date: 2000/06/29 13:17:05 $
  * Purpose:	Store/verify Internet checksum in send/receive packets.
  *
  ******************************************************************************/
 
 /******************************************************************************
  *
- *	(C)Copyright 1998,1999 SysKonnect,
+ *	(C)Copyright 1998-2000 SysKonnect,
  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
  *
- *	See the file "skge.c" for further information.
- *
  *	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
@@ -29,6 +27,23 @@
  * History:
  *
  *	$Log: skcsum.c,v $
+ *	Revision 1.7  2000/06/29 13:17:05  rassmann
+ *	Corrected reception of a packet with UDP checksum == 0 (which means there
+ *	is no UDP checksum).
+ *	
+ *	Revision 1.6  2000/02/21 12:35:10  cgoos
+ *	Fixed license header comment.
+ *	
+ *	Revision 1.5  2000/02/21 11:05:19  cgoos
+ *	Merged changes back to common source.
+ *	Fixed rx path for BIG ENDIAN architecture.
+ *	
+ *	Revision 1.1  1999/07/26 15:28:12  mkarl
+ *	added return SKCS_STATUS_IP_CSUM_ERROR_UDP and
+ *	SKCS_STATUS_IP_CSUM_ERROR_TCP to pass the NidsTester
+ *	changed from common source to windows specific source
+ *	therefore restarting with v1.0
+ *	
  *	Revision 1.3  1999/05/10 08:39:33  mkarl
  *	prevent overflows in SKCS_HTON16
  *	fixed a bug in pseudo header checksum calculation
@@ -48,7 +63,7 @@
 
 #ifndef lint
 static const char SysKonnectFileId[] = "@(#)"
-	"$Id: skcsum.c,v 1.3 1999/05/10 08:39:33 mkarl Exp $"
+	"$Id: skcsum.c,v 1.7 2000/06/29 13:17:05 rassmann Exp $"
 	" (C) SysKonnect.";
 #endif	/* !lint */
 
@@ -94,13 +109,13 @@
 /* defines ********************************************************************/
 
 /* The size of an Ethernet MAC header. */
-#define SKCS_ETHERNET_MAC_HEADER_SIZE	(6+6+2)
+#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
 
 /* The size of the IP header without any option fields. */
-#define SKCS_IP_HEADER_SIZE	20
+#define SKCS_IP_HEADER_SIZE						20
 
 /*
  * Field offsets within the IP header.
@@ -110,23 +125,31 @@
 #define SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH	0
 
 /* "Total Length". */
-#define SKCS_OFS_IP_TOTAL_LENGTH		2
+#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
+#define SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL			9
 
 /* Source IP address. */
-#define SKCS_OFS_IP_SOURCE_ADDRESS		12
+#define SKCS_OFS_IP_SOURCE_ADDRESS				12
 
 /* Destination IP address. */
-#define SKCS_OFS_IP_DESTINATION_ADDRESS		16
+#define SKCS_OFS_IP_DESTINATION_ADDRESS			16
+
+
+/*
+ * 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 */
+#define SKCS_PROTO_ID_TCP		6	/* Transport Control Protocol */
+#define SKCS_PROTO_ID_UDP		17	/* User Datagram Protocol */
 
 /* IP "Don't Fragment" bit. */
 #define SKCS_IP_DONT_FRAGMENT	SKCS_HTON16(0x4000)
@@ -224,8 +247,8 @@
  *	of the TCP or UDP pseudo header is returned here.
  */
 void SkCsGetSendInfo(
-SK_AC			*pAc,		/* Adapter context struct. */
-void			*pIpHeader,	/* IP header. */
+SK_AC				*pAc,			/* Adapter context struct. */
+void				*pIpHeader,		/* IP header. */
 SKCS_PACKET_INFO	*pPacketInfo)	/* Packet information struct. */
 {
 	/* Internet Header Version found in IP header. */
@@ -397,7 +420,8 @@
 	SKCS_OC_ADD(pPacketInfo->PseudoHeaderChecksum, PseudoHeaderChecksum, 0);
 
 	NextLevelProtoStats->TxOkCts++;	/* Success. */
-}
+}	/* SkCsGetSendInfo */
+
 
 /******************************************************************************
  *
@@ -415,7 +439,8 @@
  *	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.
+ *	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,
@@ -431,18 +456,20 @@
  * 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.
  *
- *	Note: The SKCS_STATUS_XXX values returned here are *not* defined by
- *	the CSUM module but must 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.
+ *	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. */
@@ -544,30 +571,36 @@
 
 		/* Adjust the IP header and IP data checksums. */
 
-		SKCS_OC_ADD(IpHeaderChecksum,
-			IpHeaderChecksum, IpOptionsChecksum);
+		SKCS_OC_ADD(IpHeaderChecksum, IpHeaderChecksum, IpOptionsChecksum);
 
-		SKCS_OC_SUB(IpDataChecksum,
-			IpDataChecksum, 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 does
-	 * not want us to do so because we cannot do any further processing of
-	 * the packet without a valid IP checksum.
+	 * 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.
 	 */
+	
+	/* Get the next level protocol identifier. */
+	
+	NextLevelProtocol = *(SK_U8 *)
+		SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL);
 
 	if (IpHeaderChecksum != 0xFFFF) {
 		pAc->Csum.ProtoStats[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);
 	}
 
-	/* 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.
@@ -579,14 +612,12 @@
 	if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_TCP) != 0 &&
 		NextLevelProtocol == SKCS_PROTO_ID_TCP) {
 		/* TCP/IP frame. */
-		NextLevelProtoStats =
-			&pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP];
+		NextLevelProtoStats = &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP];
 	}
 	else if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_UDP) != 0 &&
 		NextLevelProtocol == SKCS_PROTO_ID_UDP) {
 		/* UDP/IP frame. */
-		NextLevelProtoStats =
-			&pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP];
+		NextLevelProtoStats = &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP];
 	}
 	else {
 		/*
@@ -615,6 +646,24 @@
 	}
 
 	/*
+	 * 08-May-2000 ra
+	 *
+	 * From RFC 768 (UDP)
+	 * If the computed checksum is zero, it is transmitted as all ones (the
+	 * equivalent in one's complement arithmetic).  An all zero transmitted
+	 * checksum value means that the transmitter generated no checksum (for
+	 * debugging or for higher level protocols that don't care).
+	 */
+
+	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.
 	 */
 
@@ -639,7 +688,7 @@
 			SKCS_OFS_IP_DESTINATION_ADDRESS + 0) +
 		(unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader,
 			SKCS_OFS_IP_DESTINATION_ADDRESS + 2) +
-		(unsigned long) (NextLevelProtocol << 8) +
+		(unsigned long) SKCS_HTON16(NextLevelProtocol) +
 		(unsigned long) SKCS_HTON16(IpDataLength) +
 
 		/* Add the TCP/UDP header checksum. */
@@ -672,7 +721,8 @@
 
 	return (NextLevelProtocol == SKCS_PROTO_ID_TCP ?
 		SKCS_STATUS_TCP_CSUM_ERROR : SKCS_STATUS_UDP_CSUM_ERROR);
-}
+}	/* SkCsGetReceiveInfo */
+
 
 /******************************************************************************
  *
@@ -702,7 +752,7 @@
  *	Returns the two hardware checksum start offsets.
  */
 void SkCsSetReceiveFlags(
-SK_AC		*pAc,			/* Adapter context struct. */
+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. */
@@ -719,9 +769,10 @@
 	 * if there are any IP header options in the actual packet.
 	 */
 	*pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE;
-}
+}	/* SkCsSetReceiveFlags */
 
 #ifndef SkCsCalculateChecksum
+
 /******************************************************************************
  *
  *	SkCsCalculateChecksum - calculate checksum for specified data
@@ -783,7 +834,8 @@
 	/* Note: All bits beyond the 16-bit limit are now zero. */
 
 	return ((unsigned) Checksum);
-}
+}	/* SkCsCalculateChecksum */
+
 #endif /* SkCsCalculateChecksum */
 
 /******************************************************************************
@@ -833,7 +885,7 @@
 			memset(&pAc->Csum.ProtoStats[0], 0,
 				sizeof(pAc->Csum.ProtoStats));
 		}
-		else {			/* Clear for individual protocol. */
+		else {					/* Clear for individual protocol. */
 			memset(&pAc->Csum.ProtoStats[ProtoIndex], 0,
 				sizeof(pAc->Csum.ProtoStats[ProtoIndex]));
 		}
@@ -842,6 +894,6 @@
 		break;
 	}
 	return (0);	/* Success. */
-}
+}	/* SkCsEvent */
 
 #endif	/* SK_USE_CSUM */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)