summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/tcpip/tcp/tlcommon.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/tcpip/tcp/tlcommon.c553
1 files changed, 553 insertions, 0 deletions
diff --git a/private/ntos/tdi/tcpip/tcp/tlcommon.c b/private/ntos/tdi/tcpip/tcp/tlcommon.c
new file mode 100644
index 000000000..902378004
--- /dev/null
+++ b/private/ntos/tdi/tcpip/tcp/tlcommon.c
@@ -0,0 +1,553 @@
+/********************************************************************/
+/** Microsoft LAN Manager **/
+/** Copyright(c) Microsoft Corp., 1990-1993 **/
+/********************************************************************/
+/* :ts=4 */
+
+//** TLCOMMON.C - Common transport layer code.
+//
+// This file contains the code for routines that are common to
+// both TCP and UDP.
+//
+#include "oscfg.h"
+#include "ndis.h"
+#include "cxport.h"
+#include "ip.h"
+#include "tdi.h"
+#include "tdistat.h"
+#ifdef NT
+#include "tdikrnl.h"
+#endif
+#include "tlcommon.h"
+
+extern uint tcpxsum(uint Seed, void *Ptr, uint Length);
+extern IPInfo LocalNetInfo;
+
+//* XsumSendChain - Checksum a chain of NDIS send buffers.
+//
+// Called to xsum a chain of NDIS send buffers. We're given the
+// pseudo-header xsum to start with, and we call xsum on each
+// buffer. We assume that this is a send chain, and that the
+// first buffer of the chain has room for an IP header that we
+// need to skip.
+//
+// Input: PHXsum - Pseudo-header xsum.
+// BufChain - Pointer to NDIS_BUFFER chain.
+//
+// Returns: The computed xsum.
+//
+
+ushort
+XsumSendChain(uint PHXsum, PNDIS_BUFFER BufChain)
+{
+ uint HeaderSize;
+ uint OldLength;
+ uint SwapCount;
+ uchar *Ptr;
+
+ HeaderSize = LocalNetInfo.ipi_hsize;
+ OldLength = 0;
+ SwapCount = 0;
+
+ //
+ // ***** The following line of code can be removed if the pseudo
+ // checksum never has any bits sets in the upper word.
+ //
+
+ PHXsum = (((PHXsum << 16) | (PHXsum >> 16)) + PHXsum) >> 16;
+ do {
+
+ //
+ // If the length of the last buffer was odd, then swap the checksum.
+ //
+
+ if ((OldLength & 1) != 0) {
+ PHXsum = ((PHXsum & 0xff) << 8) | (PHXsum >> 8);
+ SwapCount ^= 1;
+ }
+
+ Ptr = (uchar *)NdisBufferVirtualAddress(BufChain) + HeaderSize;
+ PHXsum = tcpxsum(PHXsum, Ptr, NdisBufferLength(BufChain));
+ HeaderSize = 0;
+ OldLength = NdisBufferLength(BufChain);
+ BufChain = NDIS_BUFFER_LINKAGE(BufChain);
+ } while(BufChain != NULL);
+
+ //
+ // If an odd number of swaps were done, then swap the xsum again.
+ //
+ // N.B. At this point the checksum is only a word.
+ //
+
+ if (SwapCount != 0) {
+ PHXsum = ((PHXsum & 0xff) << 8) | (PHXsum >> 8);
+ }
+
+ return (ushort)PHXsum;
+}
+
+//* XsumRcvBuf - Checksum a chain of IP receive buffers.
+//
+// Called to xsum a chain of IP receive buffers. We're given the
+// pseudo-header xsum to start with, and we call xsum on each buffer.
+//
+// We assume that this rcv buf chain has no odd sized buffers, except
+// possibly the last one.
+//
+// Input: PHXsum - Pseudo-header xsum.
+// BufChain - Pointer to IPRcvBuf chain.
+//
+// Returns: The computed xsum.
+//
+
+ushort
+XsumRcvBuf(uint PHXsum, IPRcvBuf *BufChain)
+{
+
+ //
+ // ***** The following line of code can be removed if the pseudo
+ // checksum never has any bits sets in the upper word.
+ //
+
+ PHXsum = (((PHXsum << 16) | (PHXsum >> 16)) + PHXsum) >> 16;
+ do {
+ CTEAssert(!(BufChain->ipr_size & 1) || (BufChain->ipr_next == NULL));
+
+ PHXsum = tcpxsum(PHXsum, BufChain->ipr_buffer, BufChain->ipr_size);
+ BufChain = BufChain->ipr_next;
+ } while (BufChain != NULL);
+
+ return (ushort)(PHXsum);
+}
+
+
+//* CopyRcvToNdis - Copy from an IPRcvBuf chain to an NDIS buffer chain.
+//
+// This is the function we use to copy from a chain of IP receive buffers
+// to a chain of NDIS buffers. The caller specifies the source and destination,
+// a maximum size to copy, and an offset into the first buffer to start
+// copying from. We copy as much as possible up to the size, and return
+// the size copied.
+//
+// Input: RcvBuf - Pointer to receive buffer chain.
+// DestBuf - Pointer to NDIS buffer chain.
+// Size - Size in bytes to copy.
+// RcvOffset - Offset into first buffer to copy from.
+// DestOffset - Offset into dest buffer to start copying at.
+//
+// Returns: Bytes copied.
+//
+
+#ifdef NT
+
+uint
+CopyRcvToNdis(IPRcvBuf *RcvBuf, PNDIS_BUFFER DestBuf, uint Size,
+ uint RcvOffset, uint DestOffset)
+{
+ uint TotalBytesCopied = 0; // Bytes we've copied so far.
+ uint BytesCopied = 0; // Bytes copied out of each buffer.
+ uint DestSize, RcvSize; // Size left in current destination and
+ // recv. buffers, respectively.
+ uint BytesToCopy; // How many bytes to copy this time.
+ NTSTATUS Status;
+
+
+ CTEAssert(RcvBuf != NULL);
+
+ CTEAssert(RcvOffset <= RcvBuf->ipr_size);
+
+ // The destination buffer can be NULL - this is valid, if odd.
+ if (DestBuf != NULL) {
+
+ RcvSize = RcvBuf->ipr_size - RcvOffset;
+ DestSize = NdisBufferLength(DestBuf);
+
+ if (Size < DestSize) {
+ DestSize = Size;
+ }
+
+ do {
+ // Compute the amount to copy, and then copy from the
+ // appropriate offsets.
+ BytesToCopy = MIN(DestSize, RcvSize);
+
+ Status = TdiCopyBufferToMdl(RcvBuf->ipr_buffer, RcvOffset,
+ BytesToCopy, DestBuf, DestOffset, &BytesCopied);
+
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ CTEAssert(BytesCopied == BytesToCopy);
+
+ TotalBytesCopied += BytesCopied;
+ DestSize -= BytesCopied;
+ DestOffset += BytesCopied;
+ RcvSize -= BytesToCopy;
+
+ if (!RcvSize) {
+ // Exhausted this buffer.
+
+ RcvBuf = RcvBuf->ipr_next;
+
+ // If we have another one, use it.
+ if (RcvBuf != NULL) {
+ RcvOffset = 0;
+ RcvSize = RcvBuf->ipr_size;
+ }
+ else {
+ break;
+ }
+ }
+ else { // Buffer not exhausted, update offset.
+ RcvOffset += BytesToCopy;
+ }
+
+ } while (DestSize);
+
+ }
+
+ return TotalBytesCopied;
+
+
+}
+
+#else // NT
+
+uint
+CopyRcvToNdis(IPRcvBuf *RcvBuf, PNDIS_BUFFER DestBuf, uint Size,
+ uint RcvOffset, uint DestOffset)
+{
+ uint BytesCopied = 0; // Bytes we've copied so far.
+ uint DestSize, RcvSize; // Size left in current destination and
+ // recv. buffers, respectively.
+ uint BytesToCopy; // How many bytes to copy this time.
+
+ CTEAssert(RcvBuf != NULL);
+
+ CTEAssert(RcvOffset <= RcvBuf->ipr_size);
+
+ // The destination buffer can be NULL - this is valid, if odd.
+ if (DestBuf != NULL) {
+
+ DestSize = NdisBufferLength(DestBuf);
+ RcvSize = RcvBuf->ipr_size - RcvOffset;
+
+ //
+ // Skip over DestOffset bytes
+ //
+ while (DestOffset >= DestSize) {
+ DestOffset -= DestSize;
+ DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
+
+ if (DestBuf == NULL) {
+ return(0);
+ }
+
+ DestSize = NdisBufferLength(DestBuf);
+ }
+
+ DestSize -= DestOffset;
+
+ do {
+
+ // Compute the amount to copy, and then copy from the
+ // appropriate offsets.
+ BytesToCopy = MIN(MIN(DestSize, RcvSize), Size);
+
+ // Do the copy using the intrinsic - we might want to
+ // do this with a function that does a smarter job of
+ // copying.
+
+ CTEMemCopy((uchar *)NdisBufferVirtualAddress(DestBuf) + DestOffset,
+ RcvBuf->ipr_buffer + RcvOffset, BytesToCopy);
+
+ BytesCopied += BytesToCopy;
+
+ if (!(RcvSize -= BytesToCopy)) {
+ // Exhausted this buffer.
+
+ RcvBuf = RcvBuf->ipr_next;
+
+ // If we have another one, use it.
+ if (RcvBuf != NULL) {
+ RcvOffset = 0;
+ RcvSize = RcvBuf->ipr_size;
+ } else
+ break;
+ } else // Buffer not exhausted, update offset.
+ RcvOffset += BytesToCopy;
+
+ // Now do the same thing for the destination buffer.
+ if (!(DestSize -= BytesToCopy)) {
+ // Exhausted this buffer.
+
+ DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
+
+ // If we have another one, use it.
+ if (DestBuf != NULL) {
+ DestOffset = 0;
+ DestSize = NdisBufferLength(DestBuf);
+ } else
+ break;
+ } else // Buffer not exhausted, update offset.
+ DestOffset += BytesToCopy;
+
+ Size -= BytesToCopy; // Decrement amount left to copy.
+ } while (Size);
+
+ }
+
+ return BytesCopied;
+
+
+}
+#endif // NT
+
+
+//* CopyRcvToBuffer - Copy from an IPRcvBuf chain to a flat buffer.
+//
+// Called during receive processing to copy from an IPRcvBuffer chain to a
+// flag buffer. We skip Offset bytes in the src chain, and then
+// copy Size bytes.
+//
+// Input: DestBuf - Pointer to destination buffer.
+// SrcRB - Pointer to SrcRB chain.
+// Size - Size in bytes to copy.
+// SrcOffset - Offset in SrcRB to start copying from.
+//
+// Returns: Nothing.
+//
+void
+CopyRcvToBuffer(uchar *DestBuf, IPRcvBuf *SrcRB, uint Size, uint SrcOffset)
+{
+#ifdef DEBUG
+ IPRcvBuf *TempRB;
+ uint TempSize;
+#endif
+
+ CTEAssert(DestBuf != NULL);
+ CTEAssert(SrcRB != NULL);
+
+ // In debug versions check to make sure we're copying a reasonable size
+ // and from a reasonable offset.
+
+#ifdef DEBUG
+ TempRB = SrcRB;
+ TempSize = 0;
+ while (TempRB != NULL) {
+ TempSize += TempRB->ipr_size;
+ TempRB = TempRB->ipr_next;
+ }
+
+ CTEAssert(SrcOffset < TempSize);
+ CTEAssert((SrcOffset + Size) <= TempSize);
+#endif
+
+ // First, skip Offset bytes.
+ while (SrcOffset >= SrcRB->ipr_size) {
+ SrcOffset -= SrcRB->ipr_size;
+ SrcRB = SrcRB->ipr_next;
+ }
+
+ while (Size != 0) {
+ uint BytesToCopy, SrcSize;
+
+ CTEAssert(SrcRB != NULL);
+
+ SrcSize = SrcRB->ipr_size - SrcOffset;
+ BytesToCopy = MIN(Size, SrcSize);
+ CTEMemCopy(DestBuf, SrcRB->ipr_buffer + SrcOffset, BytesToCopy);
+
+ if (BytesToCopy == SrcSize) {
+ // Copied everything from this buffer.
+ SrcRB = SrcRB->ipr_next;
+ SrcOffset = 0;
+ }
+
+ DestBuf += BytesToCopy;
+ Size -= BytesToCopy;
+ }
+
+}
+
+//* CopyFlatToNdis - Copy a flat buffer to an NDIS_BUFFER chain.
+//
+// A utility function to copy a flat buffer to an NDIS buffer chain. We
+// assume that the NDIS_BUFFER chain is big enough to hold the copy amount;
+// in a debug build we'll debugcheck if this isn't true. We return a pointer
+// to the buffer where we stopped copying, and an offset into that buffer.
+// This is useful for copying in pieces into the chain.
+//
+// Input: DestBuf - Destination NDIS_BUFFER chain.
+// SrcBuf - Src flat buffer.
+// Size - Size in bytes to copy.
+// StartOffset - Pointer to start of offset into first buffer in
+// chain. Filled in on return with the offset to
+// copy into next.
+// BytesCopied - Pointer to a variable into which to store the
+// number of bytes copied by this operation
+//
+// Returns: Pointer to next buffer in chain to copy into.
+//
+
+#ifdef NT
+
+PNDIS_BUFFER
+CopyFlatToNdis(PNDIS_BUFFER DestBuf, uchar *SrcBuf, uint Size,
+ uint *StartOffset, uint *BytesCopied)
+{
+ NTSTATUS Status = 0;
+
+ *BytesCopied = 0;
+
+ Status = TdiCopyBufferToMdl(SrcBuf, 0, Size, DestBuf, *StartOffset,
+ BytesCopied);
+
+ *StartOffset += *BytesCopied;
+
+ //
+ // Always return the first buffer, since the TdiCopy function handles
+ // finding the appropriate buffer based on offset.
+ //
+ return(DestBuf);
+
+}
+
+#else // NT
+
+PNDIS_BUFFER
+CopyFlatToNdis(PNDIS_BUFFER DestBuf, uchar *SrcBuf, uint Size,
+ uint *StartOffset, uint *BytesCopied)
+{
+ uint CopySize;
+ uchar *DestPtr;
+ uint DestSize;
+ uint Offset = *StartOffset;
+ uint bytesCopied = 0;
+
+ CTEAssert(DestBuf != NULL);
+ CTEAssert(SrcBuf != NULL);
+
+ CTEAssert(NdisBufferLength(DestBuf) >= Offset);
+ DestPtr = ((uchar *) NdisBufferVirtualAddress(DestBuf)) + Offset;
+ DestSize = NdisBufferLength(DestBuf) - Offset;
+
+ for (;;) {
+ CopySize = MIN(Size, DestSize);
+ CTEMemCopy(DestPtr, SrcBuf, CopySize);
+
+ DestPtr += CopySize;
+ SrcBuf += CopySize;
+ bytesCopied += CopySize;
+
+ if ((Size -= CopySize) == 0)
+ break;
+
+ if ((DestSize -= CopySize) == 0) {
+ DestBuf = NDIS_BUFFER_LINKAGE(DestBuf);
+ CTEAssert(DestBuf != NULL);
+ DestPtr = NdisBufferVirtualAddress(DestBuf);
+ DestSize = NdisBufferLength(DestBuf);
+ }
+ }
+
+ *StartOffset = DestPtr - NdisBufferVirtualAddress(DestBuf);
+ *BytesCopied = bytesCopied;
+
+ return DestBuf;
+
+}
+
+#endif // NT
+
+
+//* BuildTDIAddress - Build a TDI address structure.
+//
+// Called when we need to build a TDI address structure. We fill in
+// the specifed buffer with the correct information in the correct
+// format.
+//
+// Input: Buffer - Buffer to be filled in as TDI address structure.
+// Addr - IP Address to fill in.
+// Port - Port to be filled in.
+//
+// Returns: Nothing.
+//
+void
+BuildTDIAddress(uchar *Buffer, IPAddr Addr, ushort Port)
+{
+ PTRANSPORT_ADDRESS XportAddr;
+ PTA_ADDRESS TAAddr;
+
+ XportAddr = (PTRANSPORT_ADDRESS)Buffer;
+ XportAddr->TAAddressCount = 1;
+ TAAddr = XportAddr->Address;
+ TAAddr->AddressType = TDI_ADDRESS_TYPE_IP;
+ TAAddr->AddressLength = sizeof(TDI_ADDRESS_IP);
+ ((PTDI_ADDRESS_IP)TAAddr->Address)->sin_port = Port;
+ ((PTDI_ADDRESS_IP)TAAddr->Address)->in_addr = Addr;
+}
+
+//* UpdateConnInfo - Update a connection information structure.
+//
+// Called when we need to update a connection information structure. We
+// copy any options, and create a transport address. If any buffer is
+// too small we return an error.
+//
+// Input: ConnInfo - Pointer to TDI_CONNECTION_INFORMATION struc
+// to be filled in.
+// OptInfo - Pointer to IP options information.
+// SrcAddress - Source IP address.
+// SrcPort - Source port.
+//
+// Returns: TDI_SUCCESS if it worked, TDI_BUFFER_OVERFLOW for an error.
+//
+TDI_STATUS
+UpdateConnInfo(PTDI_CONNECTION_INFORMATION ConnInfo, IPOptInfo *OptInfo,
+ IPAddr SrcAddress, ushort SrcPort)
+{
+ TDI_STATUS Status = TDI_SUCCESS; // Default status to return.
+ uint AddrLength, OptLength;
+
+
+ if (ConnInfo != NULL) {
+ ConnInfo->UserDataLength = 0; // No user data.
+
+ // Fill in the options. If the provided buffer is too small,
+ // we'll truncate the options and return an error. Otherwise
+ // we'll copy the whole IP option buffer.
+ if (ConnInfo->OptionsLength) {
+ if (ConnInfo->OptionsLength < OptInfo->ioi_optlength) {
+ Status = TDI_BUFFER_OVERFLOW;
+ OptLength = ConnInfo->OptionsLength;
+ } else
+ OptLength = OptInfo->ioi_optlength;
+
+ CTEMemCopy(ConnInfo->Options, OptInfo->ioi_options, OptLength);
+
+ ConnInfo->OptionsLength = OptLength;
+ }
+
+ // Options are copied. Build a TRANSPORT_ADDRESS structure in
+ // the buffer.
+ if (AddrLength = ConnInfo->RemoteAddressLength) {
+
+ // Make sure we have at least enough to fill in the count and type.
+ if (AddrLength >= TCP_TA_SIZE) {
+
+ // The address fits. Fill it in.
+ ConnInfo->RemoteAddressLength = TCP_TA_SIZE;
+ BuildTDIAddress(ConnInfo->RemoteAddress, SrcAddress, SrcPort);
+
+ } else {
+ ConnInfo->RemoteAddressLength = 0;
+ Status = TDI_INVALID_PARAMETER;
+ }
+ }
+
+ }
+
+ return Status;
+
+}