SKCSUM.TXT Driver File Contents (CardAssistant1_3.zip)

	SysKonnect
	Software Implementation
	Advisory Paper

				"CSUM"

		Using the Internet Checksum Calculation Feature of

				SK-NET GE PCI-64

		for IP, TCP, and UDP




	03-Aug-1998, v1.10
	> WORKING; last update: 31-Aug-1998 sw <


	(C)Copyright 1995-1998 SysKonnect,
	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
	All Rights Reserved


Overview
========

Note: The terms "packet", "frame", and "datagram" are used as synonyms
throughout this document.

The Internet checksum algorithm has been defined for and is used by network
protocols like IP, TCP, and UDP. Some protocols like IP use this algorithm
to calculate a checksum for only part of the information contained in a
network packet while others like TCP and UDP form a checksum for all of the
packet data that they maintain plus some extra data not contained in the
actual packet.

The CSUM module has been defined to implement all functionality necessary
for any SK-NET GE PCI-64 device driver written in C. Below is a description
of the function interface followed by some background theory on Internet
Checksumming.

Limitations
===========

Due to a bug in the ASIC the calculated checksum may be wrong if the result
is 0 or 1 (see also asicqueen errata). Because of this bug checksumming in
the transmit path may lead to wrong checksums in transmitted frames.

If a frame is shorter than minimum Ethernet frame length it will be padded
to this length. On the receive path the calculated hardware checksums will
include the padding bytes. The current implementation of the function
SkCsGetReceiveInfo cannot correctly verify the checksums for padded frames.

CSUM Interface Functions
========================

The CSUM module assumes that the caller is able to recognize any IP frames
as well as the start offset of the IP header within such frames.


SkCsGetSendInfo
---------------

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.)

void SkCsGetSendInfo(
	IN SK_AC		*pAc,
	IN void			*pIpHeader,
	OUT SKCS_PACKET_INFO	*pPacketInfo);

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.

On return, the following fields 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.

Return Value - None.


SkCsSetReceiveFlags
-------------------

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.

void SkCsSetReceiveFlags(
	IN SK_AC	*pAc,
	IN unsigned	ReceiveFlags,
	OUT unsigned	*pChecksum1Offset,
	OUT unsigned	*pChecksum2Offset);

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.

Return Value - None.


SkCsGetReceiveInfo
------------------

Verify a received frame's checksum. The function returns a status code
reflecting the result of the verification.
This function cannot be used if Checksum1 or Checksum2 have the value 0 or 1
or if the frame was padded.

int SkCsGetReceiveInfo(
	IN SK_AC	*pAc,
	IN void		*pIpHeader,
	IN unsigned	Checksum1,
	IN unsigned	Checksum2);

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.

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().

Return Value - One of the following:

	SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
	SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
	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.

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.


SkCsCalculateChecksum
---------------------

Calculate and return the 16-bit Internet Checksum for the specified data.

unsigned SkCsCalculateChecksum(
	void		*pData,
	unsigned	Length);

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.


SKCS_OC_ADD
-----------

Add two values in one's complement.

SKCS_OC_ADD(Result, Value1, Value2)

Result - The one's complement sum of 'Value1' plus 'Value2' is returned
here.

Value1 - The first value from which the second value will be subtracted.

Value2 - The second value which will be subtracted from the first value.

Return Value - None.


SKCS_OC_SUB
-----------

Subtract two values in one's complement.

SKCS_OC_SUB(Result, Value1, Value2)

Result - The one's complement difference of 'Value1' minus 'Value2' is
returned here.

Value1 - The first value from which the second value will be subtracted.

Value2 - The second value which will be subtracted from the first value.

Return Value - None.


How To Use The CSUM Module
==========================

For each frame received or to be sent, first check the Ethernet 16-bit
'Type/Length' field for IP type, which is the value 0x0800.

CAVEAT: The Type/Length field is in network format, i.e. big-endian
(high-low). Code should be written such that the data representation format
of the target machine does not matter (big-endian vs. little-endian).

A save way to check the Ethernet 'Type/Length' field for IP Type is to
check both bytes of the 16-bit field individually, e.g.

	UCHAR TypeLength[2];

	if (TypeLength[0] == 0x80 && TypeLength[1] == 0x00) {
		/* This is an IP frame. */
		...
	}


Sending Frames
--------------

For IP frames to be sent, call SkCsGetSendInfo() and pass to it a pointer
to the IP header. The IP header starts immediately behind the frame's
Ethernet 'Type/Length' field. At least 20 bytes of the frame's IP header
must be present here.

Note: If the IP header is only available to your driver as (virtual)
fragments you must copy at least 20 bytes of the IP header to some buffer
(e.g. on the stack) and pass a pointer to this buffer to SkCsGetSendInfo().

SkCsGetSendInfo() also needs the information for which protocols
checksumming should be performed. You can pass any combination of
SKCS_PROTO_XXX bit flags as the 'ProtocolFlags' in the 'pPacketInfo'.
SkCsGetSendInfo() will always only work on the protocols actually found in
the frame as of the IP header information.

After SkCsGetSendInfo() has returned, check the 'ProtocolFlags' in
'pPacketInfo'. Then do the following:

- If the SKCS_PROTO_IP bit flag is set in the 'ProtocolFlags', store the
  returned 16-bit 'IpHeaderChecksum' into the 'Checksum' field, which is
  located at offset 10 (0xa) of the packet's IP header.

NOTE: Most environments do not allow the driver to modify any fields of the
packet passed from a protocol driver to the network card driver. In this
case, copy part or all of the IP header to some buffer maintained by your
driver and store the checksum there. Then store the physical address of
this buffer into a separate transmit descriptor.

- If the SKCS_PROTO_TCP or SKCS_PROTO_UDP bit flag is set in the
  'ProtocolFlags', store the returned 16-bit 'PseudoHeaderChecksum' into
  the 'TCP Sum Start' field of the first transmit descriptor for this
  packet.

NOTE: If the 'Checksum' field of the packet's TCP or UDP header is not set
to zero by the calling protocol layer, you must subtract the 'Checksum'
from the 'PseudoHeaderChecksum' in one's complement arithmetic before
storing it into the transmit descriptor's 'TCP Sum Start' field. Use the
SKCS_OC_SUB() macro for this purpose.

The 16-bit 'Checksum' field is located at offset 16 (0x10) in the TCP
header and at offset 6 (0x6) in the UDP header.


Receiving Frames
----------------

Before passing any received packets to CSUM for checksum validation, CSUM
needs to know for which protocols it shall validate the checksum. Thus,
the driver at least once calls SkCsSetReceiveFlags() and passes to it any
combination of SK_PROTO_XXX flags of the protocols for which it wants
checksum information on received frames. SkCsSetReceiveFlags() then
returns the start offsets for the two hardware checksums, which must be
written into the 'TCP Sum Start 1' and 'TCP Sum Start 2' fields of each
receive descriptor that also gets the STP (start of packet) bit set.

When a packet is received you first have to check if it is an IP frame.
Then you have to make sure that the two calculated hardware checksums do
not have the values 0 or 1. In the next step you must check if the frame has
been padded. Therefore compare the length field inside the IP Header with
the received frame length from the descriptor. If the difference is 14 the
frame was not padded. Now you can pass a pointer to the IP header along with
the two hardware checksums from the receive descriptor's 'TCP Sum 1' and
'TCP Sum 2' fields to SkCsGetReceiveInfo(). The function will examine the
received IP header and, according to the SK_PROTO_XXX protocol bit flags once
specified in the call to SkCsSetReceiveFlags(), will validate the appropriate
IP and/or TCP or UDP checksums.

The value returned by SkCsGetReceiveInfo() reflects the status of the
validation. Note that the SKCS_STATUS_XXX codes used as the return values
by SkCsGetReceiveInfo() must be defined by the calling module in some
header file. This gives the programmer of the calling module the
opportunity to define meaningful return values that can easily be
translated into packet checksum information as required by the network
interface of the operating system environment.


Packet Format
-------------

The following gives an overview of the various fields and their respective
offsets within an IP packet:

- IP Header: Starts immediately behind the MAC header, i.e. at offset 14
  (0xe) on Ethernet.

- IP Header Length: Varies between 20 and 60 bytes. The actual IP header
  length is stored as the number of 4-byte words in the lower four bits of
  the first byte (offset 0) in the IP header.

- IP Header Checksum: 16-bit word stored at offset 10 (0xa) in the IP
  header.

- TCP/UDP Header: Starts immediately behind the IP header. Thus, the offset
  of the TCP or UDP header can be calculated as: IP header offset + IP
  header length.

- TCP Checksum: 16-bit word stored at offset 16 (0x10) in the TCP header.

- UDP Checksum: 16-bit word stored at offset 6 (0x6) in the UDP header.


Checksum Generation
===================

The Internet checksum is calculated as the 16 bit one's complement of the
one's complement sum of all 16 bit words in the data. A more detailed
description follows further below in this document.

The SK-NET GE PCI-64 adapter has been designed to be able to calculate two
independent Internet checksums per send and receive packet in hardware:

- When a packet is received the two checksums are calculated starting at
  the two start offsets that the software has configured. The two checksums
  are then stored into the last receive descriptor of the packet.

- When a packet is sent, the software stores the checksum start value
  along with the start offset and the length of the data area to be
  checksummed into the first transmit descriptor of the packet. It also
  stores the offset within the packet where the calculated checksum will
  finally be written to by the hardware before the packet is actually sent
  out to the wire.

The checksum calculated by the hardware needs some modification before or
after sending or receiving a packet to or from the network, respectively.
Thus, it is important to understand the Internet checksum algorithm in
detail and how to implement the code to modify the checksum.


The One's Complement
====================

The Internet checksum is calculated using one's complement arithmetic. The
one's complement is the binary negation of all bits, i.e. 0 -> 1 and 1 -> 0
(the binary NOT operator does this, i.e. in "C", the '~' operator).

Negative values are represented by the one's complement of their positive
counterpart, e.g.:

	 5 = 0101
	-5 = 1010

[Note: Today's computers represent negative values as the two's complement,
which is the one's complement plus one.]

In one's complement, there are two representations of zero: the all zero
and the all one bit values, often referred to as +0 and -0. One's
complement addition of non-zero inputs can produce -0 as a result, but
never +0.

Calculating the one's complement sum of two values is done as follows:

	1. Add the two values.
	2. If there is a carry, add it to the result.


The Internet Checksum Algorithm
===============================

The Internet checksum is calculated as follows (this is a quote from RFC
793 "Transmission Control Protocol", chapter 3 "Functional Specification",
3.1 "Header Format"):

 Checksum: 16 bits

	The checksum field is the 16 bit one's complement of the one's
	complement sum of all 16 bit words in the header and text. If a
	segment contains an odd number of header and text octets to be
	checksummed, the last octet is padded on the right with zeros to
	form a 16 bit word for checksum purposes. The pad is not
	transmitted as part of the segment. While computing the checksum,
	the checksum field itself is replaced with zeros.

IP uses this algorithm to form the checksum for only the IP header, which
is stored in the IP header itself. IP does not form a checksum for the IP
data portion of IP packets.


The Pseudo Header
=================

TCP and UDP do not only form a checksum from the data found in the TCP/UDP
header and the TCP/UDP data portions of the packet, but do also add a
so-called pseudo header to the checksum. The pseudo header is the same for
TCP and UDP except for the value found in the 'protocol' field. Here is
another quote from RFC 793:

	The checksum also covers a 96 bit pseudo header conceptually
	prefixed to the TCP header. This pseudo header contains the Source
	Address, the Destination Address, the Protocol, and TCP length.
	This gives the TCP protection against misrouted segments. This
	information is carried in the Internet Protocol and is transferred
	across the TCP/Network interface in the arguments or results of
	calls by the TCP on the IP.

		     +--------+--------+--------+--------+
		     |		 Source Address		 |
		     +--------+--------+--------+--------+
		     |	       Destination Address	 |
		     +--------+--------+--------+--------+
		     |	zero  |	 PTCL  |    TCP Length	 |
		     +--------+--------+--------+--------+

	The TCP Length is the TCP header length plus the data length in
	octets (this is not an explicitly transmitted quantity, but is
	computed), and it does not count the 12 octets of the pseudo
	header.


Ethernet Packet Format
======================

On Ethernet, each packet consists of the portions described below. All
octets within a field are in high-low order.

	Offset	Length	Description
	------	------	-----------
	0	14	MAC (Medium Access Control) header
	14	0..1500	packet data
	14+n	4	frame check sequence (FCS)
	------	------	-----------
	-	(*)	total size

	(*) The total packet length is 64 to 1518 octets (including the
	FCS).

Note: The minimum packet length is 64 because the CSMA (Carrier
Sense/Multiple Access) algorithm used by traditional Ethernet (10 Mbit/s)
has this requirement.

	+-----+--..--+-----+
	| MAC | data | FCS |	Ethernet packet format
	+-----+--..--+-----+

Note: The FCS is automatically generated and appended by the MAC chip when
a packet is sent. Upon reception of a packet, the MAC chip can be
programmed such that the FCS is automatically stripped from the packet
before it is transferred to memory.

The MAC header contains the following fields:

	Offset	Length	Description
	------	------	-----------
	0	6	Destination Address (DA)
	6	6	Source Address (SA)
	12	2	Type/Length (T/L)
	------	------	-----------
	-	14	total size

	+----+----+-----+
	| DA | SA | T/L |	Ethernet MAC header format
	+----+----+-----+

The Type/Length field holds either a "Type Code" or the length of the
packet's data portion, which must be between 0 and 1500 octets. Thus,
values found in this field can be interpreted as follows:

	Type/Length	Meaning
	-----------	-------
	0..1500		length of data portion
	0x5DD..0xFFFF	Type Code

Note: Ethernet has been standardized by more than one gremium, which led
to the two different interpretations of the Type/Length field:

	Standard		Meaning of Type/Length field
	--------		----------------------------
	DIX (DEC, Intel Xerox)	}
	blue book		} Type Code
	Ethernet II		}
	IEEE 802.3		length of data portion


IP Frame Format
===============

According to RFC 894 "A Standard for the Transmission of IP Datagrams over
Ethernet Networks", the IP frame format is as follows:

	The type field of the Ethernet frame must contain the value
	hexadecimal 0800. The data field contains the IP header followed
	immediately by the IP data.

	+----+----+--------+-----------+---...---+
	| DA | SA | 0x0800 | IP Header | IP Data |
	+----+----+--------+-----------+---...---+


TCP/UDP Frame Format
====================

TCP and UDP use the IP data portion of the packet to store their TCP/UDP
headers followed by the TCP/UDP data, respectively.

	+----+----+--------+-----------+----------------+------...-----+
	| DA | SA | 0x0800 | IP Header | TCP/UDP Header | TCP/UDP Data |
	+----+----+--------+-----------+----------------+------...-----+


Receiving Checksummed Frames
============================

During reception of a packet from the network, the SK-NET GE PCI-64
hardware calculates two Internet checksums for the packet and stores them
into the last receive descriptor used by this packet (EOF bit set).

Calculation starts at the offsets as configured in the first receive
descriptor used by this packet (STF bit set). This allows us to calculate
one checksum for the IP header and one for the IP data.

	+----+----+--------+-----------+---...---+
	| DA | SA | 0x0800 | IP Header | IP Data |
	+----+----+--------+-----------+---...---+
			   ^Offset1    ^Offset2

Offset1 is set to the start of the IP header and Offset2 is set to the
start of the IP data.

However, since the checksum is always calculated from the individual start
offsets to the end of the packet, we must first subtract the IP data
checksum from the IP header checksum to get the correct IP header
checksum:

	CS(IP Header) := CS(IP Data) - CS(IP Header)

If there are any option fields in the IP header we must also calculate the
checksum for this part of the frame. The resulting checksum must be added
to Checksum1 and subtracted from Checksum2.


References
==========

RFC 791	 "Internet Protocol"
RFC 793	 "Transmission Control Protocol"
RFC 1071 "Computing the Internet Checksum"
RFC 1624 "Computation of the Internet Checksum via Incremental Update"


History
=======
04-May-1999 mk	v1.20
		added ASIC workaround
		added remarks for padded frames
03-Aug-1998 sw	v1.10.
		Software interface reworked.
21-Jul-1998 sw	v1.00.
11-May-1998 sw	Created.


===========================================================================
22-Jul-1998 sw - The following is pseudo code for SkCsGetReceiveInfo. This
should be removed when CSUM is actually implemented.

---

CONST MAC_HEADER_SIZE	= (6+6+2);
CONST IP_HEADER_OFFSET	= MAC_HEADER_SIZE;
CONST IP_HEADER_SIZE	= (5 * 4);	# min. IP header size (no options used)

CONST IP_PROTO_TCP	6
CONST IP_PROTO_UDP	17

PROC Initialization;
BEGIN
	Receive.Checksum1Offset := IP_HEADER_OFFSET;
	Receive.Checksum2Offset := IP_HEADER_OFFSET + IP_HEADER_SIZE;
END

PROC VerifyChecksum;
pPacket		: POINTER;	# pointer to Ethernet packet to verify
PacketLength	: UINT;		# length of packet
Checksum1	: UINT16;	# hardware checksum 1
Checksum2	: UINT16;	# hardware checksum 1
BEGIN
	IpHeaderLength		: UINT;
	IpHeaderChecksum	: UINT32;
	IpOptionsChecksum	: UINT32;
	IpDataChecksum		: UINT32;
	PseudoHeader		: array[12] of UINT8;

	# Check if this is an IP frame.
	IF pPacket.Mac.TypeCode <> 0x0800 THEN
		RETURN "not an IP frame";

	# Check for ASIC bug.
	if Checksum1 < 2 OR Checksum2 < 2 THEN
		RETURN "checksum not reliable";

	# Check for padded frames.
	If IpDataLength + 14 <> PacketLength
		RETURN "checksum not reliable";
		
	# Check the IP version.
	IF pPacket.Ip.Version <> 4 THEN
		RETURN "unknown IP version";

	# Check the IP header length.

	IpHeaderLength := pPacket.Ip.HeaderLength * 4;

	IF IpHeaderLength < IP_HEADER_SIZE THEN
		RETURN "invalid length";

	# Get IP header & data checksum.

	IpDataChecksum := Checksum2;
	IpHeaderChecksum := Checksum1 + ((NOT IpDataChecksum) AND 0xffff);
	IpHeaderChecksum := (IpHeaderChecksum +
		(IpHeaderChecksum SHR 16)) AND 0xffff;

	# Check if any IP header options.
	IF IpHeaderLength > IP_HEADER_SIZE THEN
	BEGIN
		IpOptionsChecksum := CalculateChecksum(
			&pPacket.Ip[IP_HEADER_SIZE],
			IpHeaderLength - IP_HEADER_SIZE);

		# Adjust the hardware checksums.

		# Add IP options checksum.
		IpHeaderChecksum := IpHeaderChecksum + IpOptionsChecksum;
		# Add-in any carry.
		IpHeaderChecksum := (IpHeaderChecksum +
			(IpHeaderChecksum SHR 16)) AND 0xffff;

		# Subtract IP options checksum.
		IpDataChecksum := IpDataChecksum +
			((NOT IpOptionsChecksum) AND 0xffff);
		# Add-in any carry.
		IpDataChecksum := (IpDataChecksum +
			(IpDataChecksum SHR 16)) AND 0xffff;

		# NOTE: If the IP data checksum is now 0xffff, the checksum is
		# *wrong* if and only if the whole IP data area is zero. In
		# this case, the correct checksum is zero (0x0000).
		#
		# Note that this is not an actual problem for TCP and UDP since
		# at least their headers are different from zero.
	END

	IF IpHeaderChecksum <> 0xffff THEN
		RETURN "IP checksum error";

	# Note: At this point, the IP header checksum has been verified ok.

	# Check if this is an IP fragment.
	IF pPacket.Ip.MoreFragments OR pPacket.Ip.FragmentOffset <> 0 THEN
		RETURN "IP datagram fragment";

	IF pPacket.Ip.Protocol <> IP_PROTO_TCP AND
		pPacket.Ip.Protocol <> IP_PROTO_UDP THEN
		RETURN "Not a TCP or UDP frame";

	# This is a TCP or UDP datagram.

	IpDataLength := PacketLength - IpHeaderLength;

	# Build the 96-bit (3 * 32-bit) pseudo header.
	# Note: It is important that this be in network octet order (high-low).

	PseudoHeader[0..3] = pPacket.Ip.SourceAddress;
	PseudoHeader[4..7] = pPacket.Ip.DestinationAddress;
	PseudoHeader[8] = 0;
	PseudoHeader[9] = pPacket.Ip.Protocol;
	PseudoHeader[10] = IpDataLength SHR 8;
	PseudoHeader[11] = IpDataLength AND 0xff;

	# Add the pseudo header to the checksum.

	IpDataChecksum := IpDataChecksum + CalculateChecksum(
		PseudoHeader,
		12);
	IpDataChecksum := (IpDataChecksum + (IpDataChecksum SHR 16)) AND 0xffff;

	IF IpDataChecksum <> 0xffff THEN
		RETURN "TCP/UDP checksum error";

	RETURN "TCP/UDP checksum verified ok";
END


PROC CalculateChecksum;
pData		: POINTER;	# pointer to data to checksum
DataLength	: UINT;		# length of data
BEGIN
END

---
Download Driver Pack

How To Update Drivers Manually

After your driver has been downloaded, follow these simple steps to install it.

  • Expand the archive file (if the download file is in zip or rar format).

  • If the expanded file has an .exe extension, double click it and follow the installation instructions.

  • Otherwise, open Device Manager by right-clicking the Start menu and selecting Device Manager.

  • Find the device and model you want to update in the device list.

  • Double-click on it to open the Properties dialog box.

  • From the Properties dialog box, select the Driver tab.

  • Click the Update Driver button, then follow the instructions.

Very important: You must reboot your system to ensure that any driver updates have taken effect.

For more help, visit our Driver Support section for step-by-step videos on how to install drivers for every file type.

server: web2, load: 1.03