/*++ Copyright (c) 1989-1993 Microsoft Corporation Module Name: spxutils.c Abstract: This contains all utility routines for the ISN SPX module. Revision History: --*/ #include "precomp.h" #pragma hdrstop // Define module number for event logging entries #define FILENUM SPXUTILS UINT SpxUtilWstrLength( IN PWSTR Wstr ) /*++ Routine Description: Arguments: Return Value: --*/ { UINT length = 0; while (*Wstr++) { length += sizeof(WCHAR); } return length; } LONG SpxRandomNumber( VOID ) /*++ Routine Description: Arguments: Return Value: --*/ { LARGE_INTEGER Li; static LONG seed = 0; // Return a positive pseudo-random number; simple linear congruential // algorithm. ANSI C "rand()" function. if (seed == 0) { KeQuerySystemTime(&Li); seed = Li.LowPart; } seed *= (0x41C64E6D + 0x3039); return (seed & 0x7FFFFFFF); } NTSTATUS SpxUtilGetSocketType( PUNICODE_STRING RemainingFileName, PBYTE SocketType ) /*++ Routine Description: For PROTO_SPX, i'd return a device name from the dll of the form \Device\IsnSpx\SpxStream (for SOCK_STREAM) or \Device\IsnSpx\Spx (for SOCK_SEQPKT) and for PROTO_SPXII (the more common case we hope, even if internally we degrade to SPX1 cause of the remote client's limitations) \Device\IsnSpx\Stream (for SOCK_STREAM) or \Device\IsnSpx (for SOCK_SEQPKT) Arguments: Return Value: --*/ { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING typeString; *SocketType = SOCKET2_TYPE_SEQPKT; // Check for the socket type do { if (RemainingFileName->Length == 0) { break; } if ((UINT)RemainingFileName->Length == SpxUtilWstrLength(SOCKET1STREAM_SUFFIX)) { RtlInitUnicodeString(&typeString, SOCKET1STREAM_SUFFIX); // Case insensitive compare if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE)) { *SocketType = SOCKET1_TYPE_STREAM; break; } } if ((UINT)RemainingFileName->Length == SpxUtilWstrLength(SOCKET1_SUFFIX)) { RtlInitUnicodeString(&typeString, SOCKET1_SUFFIX); // Case insensitive compare if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE)) { *SocketType = SOCKET1_TYPE_SEQPKT; break; } } if ((UINT)RemainingFileName->Length == SpxUtilWstrLength(SOCKET2STREAM_SUFFIX)) { RtlInitUnicodeString(&typeString, SOCKET2STREAM_SUFFIX); // Case insensitive compare if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE)) { *SocketType = SOCKET2_TYPE_STREAM; break; } } status = STATUS_NO_SUCH_DEVICE; } while (FALSE); return(status); } #define ONE_MS_IN_100ns -10000L // 1ms in 100ns units VOID SpxSleep( IN ULONG TimeInMs ) /*++ Routine Description: Arguments: Return Value: --*/ { KTIMER SleepTimer; ASSERT (KeGetCurrentIrql() == LOW_LEVEL); KeInitializeTimer(&SleepTimer); KeSetTimer(&SleepTimer, RtlConvertLongToLargeInteger(TimeInMs * ONE_MS_IN_100ns), NULL); KeWaitForSingleObject(&SleepTimer, UserRequest, KernelMode, FALSE, NULL); return; } TDI_ADDRESS_IPX UNALIGNED * SpxParseTdiAddress( IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress ) /*++ Routine Description: This routine scans a TRANSPORT_ADDRESS, looking for an address of type TDI_ADDRESS_TYPE_IPX. Arguments: Transport - The generic TDI address. Return Value: A pointer to the IPX address, or NULL if none is found. --*/ { TA_ADDRESS * addressName; INT i; addressName = &TransportAddress->Address[0]; // The name can be passed with multiple entries; we'll take and use only // the IPX one. for (i=0;iTAAddressCount;i++) { if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX) { if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX)) { return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address)); } } addressName = (TA_ADDRESS *)(addressName->Address + addressName->AddressLength); } return NULL; } // SpxParseTdiAddress BOOLEAN SpxValidateTdiAddress( IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress, IN ULONG TransportAddressLength ) /*++ Routine Description: This routine scans a TRANSPORT_ADDRESS, verifying that the components of the address do not extend past the specified length. Arguments: TransportAddress - The generic TDI address. TransportAddressLength - The specific length of TransportAddress. Return Value: TRUE if the address is valid, FALSE otherwise. --*/ { PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength; TA_ADDRESS * addressName; INT i; if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount)) { DBGPRINT(TDI, ERR, ("SpxValidateTdiAddress: runt address\n")); return FALSE; } addressName = &TransportAddress->Address[0]; for (i=0;iTAAddressCount;i++) { if (addressName->Address > AddressEnd) { DBGPRINT(TDI, ERR, ("SpxValidateTdiAddress: address too short\n")); return FALSE; } addressName = (TA_ADDRESS *)(addressName->Address + addressName->AddressLength); } if ((PUCHAR)addressName > AddressEnd) { DBGPRINT(TDI, ERR, ("SpxValidateTdiAddress: address too short\n")); return FALSE; } return TRUE; } // SpxValidateTdiAddress ULONG SpxBuildTdiAddress( IN PVOID AddressBuffer, IN ULONG AddressBufferLength, IN UCHAR Network[4], IN UCHAR Node[6], IN USHORT Socket ) /*++ Routine Description: This routine fills in a TRANSPORT_ADDRESS in the specified buffer, given the socket, network and node. It will write less than the full address if the buffer is too short. Arguments: AddressBuffer - The buffer that will hold the address. AddressBufferLength - The length of the buffer. Network - The network number. Node - The node address. Socket - The socket. Return Value: The number of bytes written into AddressBuffer. --*/ { TA_IPX_ADDRESS UNALIGNED * SpxAddress; TA_IPX_ADDRESS TempAddress; if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS)) { SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer; } else { SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)&TempAddress; } SpxAddress->TAAddressCount = 1; SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX); SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX; SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)Network; SpxAddress->Address[0].Address[0].Socket = Socket; RtlCopyMemory(SpxAddress->Address[0].Address[0].NodeAddress, Node, 6); if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS)) { return sizeof(TA_IPX_ADDRESS); } else { RtlCopyMemory(AddressBuffer, &TempAddress, AddressBufferLength); return AddressBufferLength; } } // SpxBuildTdiAddress VOID SpxBuildTdiAddressFromIpxAddr( IN PVOID AddressBuffer, IN PBYTE pIpxAddr ) { TA_IPX_ADDRESS UNALIGNED * SpxAddress; SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer; SpxAddress->TAAddressCount = 1; SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX); SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX; SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)pIpxAddr; RtlCopyMemory( SpxAddress->Address[0].Address[0].NodeAddress, pIpxAddr+4, 6); GETSHORT2SHORT( &SpxAddress->Address[0].Address[0].Socket, pIpxAddr + 10); return; } VOID SpxCalculateNewT1( IN struct _SPX_CONN_FILE * pSpxConnFile, IN int NewT1 ) /*++ Routine Description: Arguments: NewT1 - New value for the RTT in ms. Return Value: --*/ { int baseT1, error; // // VAN JACOBSEN Algorithm. From Internetworking with Tcp/ip // (Comer) book. // error = NewT1 - (pSpxConnFile->scf_AveT1 >> 3); pSpxConnFile->scf_AveT1 += error; if (pSpxConnFile->scf_AveT1 <= 0) // Make sure not too small { pSpxConnFile->scf_AveT1 = SPX_T1_MIN; } if (error < 0) error = -error; error -= (pSpxConnFile->scf_DevT1 >> 2); pSpxConnFile->scf_DevT1 += error; if (pSpxConnFile->scf_DevT1 <= 0) pSpxConnFile->scf_DevT1 = 1; baseT1 = (((pSpxConnFile->scf_AveT1 >> 2) + pSpxConnFile->scf_DevT1) >> 1); // If less then min - set it if (baseT1 < SPX_T1_MIN) baseT1 = SPX_T1_MIN; // Set the new value DBGPRINT(TDI, DBG, ("SpxCalculateNewT1: Old value %lx New %lx\n", pSpxConnFile->scf_BaseT1, baseT1)); pSpxConnFile->scf_BaseT1 = baseT1; // At the time of restarting the timer,we convert this to a tick value. return; }