2020-09-30 17:12:29 +02:00

598 lines
14 KiB
C

/********************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1990-1993 **/
/********************************************************************/
/* :ts=4 */
//** INIT.C - TCP/UDP init code.
//
// This file contain init code for the TCP/UDP driver. Some things
// here are ifdef'ed for building a UDP only version.
//
#include "oscfg.h"
#include "ndis.h"
#include "cxport.h"
#include "ip.h"
#include "tdi.h"
#ifdef NT
#include <tdikrnl.h>
#endif
#ifdef VXD
#include "tdivxd.h"
#include "tdistat.h"
#endif
#ifdef NT
#include "tdint.h"
#include "tdistat.h"
#endif
#include "queue.h"
#include "addr.h"
#include "udp.h"
#include "raw.h"
#include "info.h"
#ifndef UDP_ONLY
#include "tcp.h"
#include "tcpsend.h"
#include "tcb.h"
#include "tcpconn.h"
#include "tcpdeliv.h"
#include "tlcommon.h"
extern int InitTCPRcv(void);
extern void UnInitTCPRcv(void);
#endif // UDP_ONLY
#include "tdiinfo.h"
#include "tcpcfg.h"
//* Definitions of global variables.
IPInfo LocalNetInfo;
uint DeadGWDetect;
uint PMTUDiscovery;
uint PMTUBHDetect;
uint KeepAliveTime;
uint KAInterval;
uint DefaultRcvWin;
uint MaxConnections;
uint MaxConnectRexmitCount;
uint MaxConnectResponseRexmitCount;
#ifdef SYN_ATTACK
uint MaxConnectResponseRexmitCountTmp;
#endif
uint MaxDataRexmitCount;
uint BSDUrgent;
uint FinWait2TO;
uint NTWMaxConnectCount;
uint NTWMaxConnectTime;
uint MaxUserPort;
#ifdef SECFLTR
uint SecurityFilteringEnabled;
#endif // SECFLTR
#ifdef VXD
uint PreloadCount;
#endif
#ifdef _PNP_POWER
HANDLE AddressChangeHandle;
#endif
#ifdef VXD
TDIDispatchTable TLDispatch;
#ifndef CHICAGO
char TransportName[] = "MSTCP";
#else
char TransportName[] = TCP_NAME;
#endif
#ifdef CHICAGO
extern int RegisterAddrChangeHndlr(void *Handler, uint Add);
#endif
#endif
uint StartTime;
extern void *UDPProtInfo;
extern void *RawProtInfo;
extern int InitTCPConn(void);
extern void UnInitTCPConn(void);
extern IP_STATUS TLGetIPInfo(IPInfo *Buffer, int Size);
//
// All of the init code can be discarded.
//
#ifdef NT
#ifdef ALLOC_PRAGMA
int tlinit();
#pragma alloc_text(INIT, tlinit)
#endif // ALLOC_PRAGMA
#endif
//* Dummy routines for UDP only version. All of these routines return
// 'Invalid Request'.
#ifdef UDP_ONLY
TDI_STATUS
TdiOpenConnection(PTDI_REQUEST Request, PVOID Context)
{
return TDI_INVALID_REQUEST;
}
TDI_STATUS
TdiCloseConnection(PTDI_REQUEST Request)
{
return TDI_INVALID_REQUEST;
}
TDI_STATUS
TdiAssociateAddress(PTDI_REQUEST Request, HANDLE AddrHandle)
{
return TDI_INVALID_REQUEST;
}
TDI_STATUS TdiDisAssociateAddress(PTDI_REQUEST Request)
{
return TDI_INVALID_REQUEST;
}
TDI_STATUS TdiConnect(PTDI_REQUEST Request, void *Timeout,
PTDI_CONNECTION_INFORMATION RequestAddr,
PTDI_CONNECTION_INFORMATION ReturnAddr)
{
return TDI_INVALID_REQUEST;
}
TDI_STATUS TdiListen(PTDI_REQUEST Request, ushort Flags,
PTDI_CONNECTION_INFORMATION AcceptableAddr,
PTDI_CONNECTION_INFORMATION ConnectedAddr)
{
return TDI_INVALID_REQUEST;
}
TDI_STATUS TdiAccept(PTDI_REQUEST Request,
PTDI_CONNECTION_INFORMATION AcceptInfo,
PTDI_CONNECTION_INFORMATION ConnectedInfo)
{
return TDI_INVALID_REQUEST;
}
TDI_STATUS TdiReceive(PTDI_REQUEST Request, ushort *Flags,
uint *RcvLength, PNDIS_BUFFER Buffer)
{
return TDI_INVALID_REQUEST;
}
TDI_STATUS TdiSend(PTDI_REQUEST Request, ushort Flags, uint SendLength,
PNDIS_BUFFER Buffer)
{
return TDI_INVALID_REQUEST;
}
TDI_STATUS TdiDisconnect(PTDI_REQUEST Request, PVOID Timeout, ushort Flags,
PTDI_CONNECTION_INFORMATION DisconnectInfo,
PTDI_CONNECTION_INFORMATION ReturnInfo)
{
return TDI_INVALID_REQUEST;
}
#endif
#ifdef VXD
extern void *ConvertPtr(void *Ptr);
//** Routines to handle incoming QueryInformation requests, and dispatch
//** them.
struct ClientReq {
ushort cr_opcode;
void *cr_ID;
void *cr_buffer;
void *cr_length;
void *cr_context;
};
//* VxDQueryInfo - VxD thunk to query information.
//
// The VxD thunk to TdiQueryInformationEx. All we do it convert the pointers
// and call in.
//
// Input: Req - A pointer to a ClientReq structure.
//
// Returns: Status of command.
//
TDI_STATUS
VxDQueryInfo(struct ClientReq *Req)
{
NDIS_BUFFER Buffer;
TDI_REQUEST Request;
uint *Size;
TDIObjectID *ID;
void *Context;
CTEAssert(Req->cr_opcode == 0);
CTEMemSet(&Request, 0, sizeof(TDI_REQUEST));
ID = (TDIObjectID *)ConvertPtr(Req->cr_ID);
Size = (uint *)ConvertPtr(Req->cr_length);
#ifdef DEBUG
Buffer.Signature = BUFFER_SIGN;
#endif
Buffer.VirtualAddress = ConvertPtr(Req->cr_buffer);
Buffer.Length = *Size;
Buffer.Next = NULL;
return TdiQueryInformationEx(&Request, ID, &Buffer, Size,
ConvertPtr(Req->cr_context));
}
//* VxDSetInfo - VxD thunk to set information.
//
// The VxD thunk to TdiSetInformationEx. All we do it convert the pointers
// and call in.
//
// Input: Req - A pointer to a ClientReq structure.
//
// Returns: Status of command.
//
TDI_STATUS
VxDSetInfo(struct ClientReq *Req)
{
TDIObjectID *ID;
uint *Size;
void *Buffer;
TDI_REQUEST Request;
CTEAssert(Req->cr_opcode == 1);
CTEMemSet(&Request, 0, sizeof(TDI_REQUEST));
ID = (TDIObjectID *)ConvertPtr(Req->cr_ID);
Size = (uint *)ConvertPtr(Req->cr_length);
Buffer = ConvertPtr(Req->cr_buffer);
return TdiSetInformationEx(&Request, ID, Buffer, *Size);
}
#endif
#ifdef CHICAGO
//* AddrChange - Receive notification of an IP address change.
//
// Called by IP when an address comes or goes. We get the address
// and mask, and depending on what's actually happened we may close address
// and connections.
//
// Input: Addr - IP address that's coming or going.
// Mask - Mask for Addr.
// Context - PNP context (unused)
// IPContext - IP context (unused)
// Added - True if the address is coming, False if it's going.
//
// Returns: Nothing.
//
void
AddrChange(IPAddr Addr, IPMask Mask, void *Context, ushort IPContext,
uint Added)
{
if (Added) {
// He's adding an address. Re-query the entity list now.
EntityList[0].tei_entity = CO_TL_ENTITY;
EntityList[0].tei_instance = 0;
EntityList[1].tei_entity = CL_TL_ENTITY;
EntityList[1].tei_instance = 0;
EntityCount = 2;
// When we have multiple networks under us, we'll want to loop through
// here calling them all. For now just call the one we have.
(*LocalNetInfo.ipi_getelist)(EntityList, &EntityCount);
} else {
// He's deleting an address.
if (!IP_ADDR_EQUAL(Addr, NULL_IP_ADDR)) {
#ifndef UDP_ONLY
TCBWalk(DeleteTCBWithSrc, &Addr, NULL, NULL);
#endif
InvalidateAddrs(Addr);
}
}
}
#endif
#ifdef NT
#ifdef _PNP_POWER
//* AddressArrival - Handle an IP address arriving
//
// Called by TDI when an address arrives. All we do is query the
// EntityList.
//
// Input: Addr - IP address that's coming.
//
// Returns: Nothing.
//
void
AddressArrival(PTA_ADDRESS Addr)
{
if (Addr->AddressType == TDI_ADDRESS_TYPE_IP) {
// He's adding an address. Re-query the entity list now.
EntityList[0].tei_entity = CO_TL_ENTITY;
EntityList[0].tei_instance = 0;
EntityList[1].tei_entity = CL_TL_ENTITY;
EntityList[1].tei_instance = 0;
EntityCount = 2;
// When we have multiple networks under us, we'll want to loop through
// here calling them all. For now just call the one we have.
(*LocalNetInfo.ipi_getelist)(EntityList, &EntityCount);
}
}
//* AddressDeletion - Handle an IP address going away.
//
// Called by TDI when an address is deleted. If it's an address we
// care about we'll clean up appropriately.
//
// Input: Addr - IP address that's going.
//
// Returns: Nothing.
//
void
AddressDeletion(PTA_ADDRESS Addr)
{
PTDI_ADDRESS_IP MyAddress;
IPAddr LocalAddress;
if (Addr->AddressType == TDI_ADDRESS_TYPE_IP) {
// He's deleting an address.
MyAddress = (PTDI_ADDRESS_IP)Addr->Address;
LocalAddress = MyAddress->in_addr;
if (!IP_ADDR_EQUAL(LocalAddress, NULL_IP_ADDR)) {
#ifndef UDP_ONLY
TCBWalk(DeleteTCBWithSrc, &LocalAddress, NULL, NULL);
#endif
InvalidateAddrs(LocalAddress);
}
}
}
#endif // _PNP_POWER
#endif // NT
#pragma BEGIN_INIT
extern uchar TCPGetConfigInfo(void);
extern uchar IPPresent(void);
//** tlinit - Initialize the transport layer.
//
// The main transport layer initialize routine. We get whatever config
// info we need, initialize some data structures, get information
// from IP, do some more initialization, and finally register our
// protocol values with IP.
//
// Input: Nothing
//
// Returns: True is we succeeded, False if we fail to initialize.
//
int
tlinit()
{
#ifdef VXD
void *PreloadPtrs[MAX_PRELOAD_COUNT];
uint i;
#endif
uint TCBInitialized = 0;
if (!CTEInitialize())
return FALSE;
#ifdef VXD
if (!IPPresent())
return FALSE;
#endif
if (!TCPGetConfigInfo())
return FALSE;
StartTime = CTESystemUpTime();
#ifndef UDP_ONLY
KeepAliveTime = MS_TO_TICKS(KeepAliveTime);
KAInterval = MS_TO_TICKS(KAInterval);
#endif
CTERefillMem();
// Get net information from IP.
if (TLGetIPInfo(&LocalNetInfo, sizeof(IPInfo)) != IP_SUCCESS)
goto failure;
if (LocalNetInfo.ipi_version != IP_DRIVER_VERSION)
goto failure; // Wrong version of IP.
#ifdef CHICAGO
if (!RegisterAddrChangeHndlr(AddrChange, TRUE))
goto failure;
#endif
#ifdef NT
#ifdef _PNP_POWER
(void)TdiRegisterAddressChangeHandler(
AddressArrival,
AddressDeletion,
&AddressChangeHandle
);
#endif // _PNP_POWER
#endif // NT
//* Initialize addr obj management code.
if (!InitAddr())
goto failure;
CTERefillMem();
if (!InitDG(sizeof(UDPHeader)))
goto failure;
#ifndef UDP_ONLY
MaxConnections = MIN(MaxConnections, INVALID_CONN_INDEX - 1);
CTERefillMem();
if (!InitTCPConn())
goto failure;
CTERefillMem();
if (!InitTCB())
goto failure;
TCBInitialized = 1;
CTERefillMem();
if (!InitTCPRcv())
goto failure;
CTERefillMem();
if (!InitTCPSend())
goto failure;
CTEMemSet(&TStats, 0, sizeof(TCPStats));
TStats.ts_rtoalgorithm = TCP_RTO_VANJ;
TStats.ts_rtomin = MIN_RETRAN_TICKS * MS_PER_TICK;
TStats.ts_rtomax = MAX_REXMIT_TO * MS_PER_TICK;
TStats.ts_maxconn = (ulong) TCP_MAXCONN_DYNAMIC;
#endif
CTEMemSet(&UStats,0, sizeof(UDPStats));
// Register our UDP protocol handler.
UDPProtInfo = TLRegisterProtocol(PROTOCOL_UDP, UDPRcv, DGSendComplete,
UDPStatus, NULL);
if (UDPProtInfo == NULL)
goto failure; // Failed to register!
// Register the Raw IP (wildcard) protocol handler.
RawProtInfo = TLRegisterProtocol(PROTOCOL_ANY, RawRcv, DGSendComplete,
RawStatus, NULL);
if (RawProtInfo == NULL) {
CTEPrint(("failed to register raw prot with IP\n"));
goto failure; // Failed to register!
}
#ifdef VXD
TLDispatch.TdiOpenAddressEntry = TdiOpenAddress;
TLDispatch.TdiCloseAddressEntry = TdiCloseAddress;
TLDispatch.TdiSendDatagramEntry = TdiSendDatagram;
TLDispatch.TdiReceiveDatagramEntry = TdiReceiveDatagram;
TLDispatch.TdiSetEventEntry = TdiSetEvent;
TLDispatch.TdiOpenConnectionEntry = TdiOpenConnection;
TLDispatch.TdiCloseConnectionEntry = TdiCloseConnection;
TLDispatch.TdiAssociateAddressEntry = TdiAssociateAddress;
TLDispatch.TdiDisAssociateAddressEntry = TdiDisAssociateAddress;
TLDispatch.TdiConnectEntry = TdiConnect;
TLDispatch.TdiDisconnectEntry = TdiDisconnect;
TLDispatch.TdiListenEntry = TdiListen;
TLDispatch.TdiAcceptEntry = TdiAccept;
TLDispatch.TdiReceiveEntry = TdiReceive;
TLDispatch.TdiSendEntry = TdiSend;
TLDispatch.TdiQueryInformationEntry = TdiQueryInformation;
TLDispatch.TdiSetInformationEntry = TdiSetInformation;
TLDispatch.TdiActionEntry = TdiAction;
TLDispatch.TdiQueryInformationExEntry = TdiQueryInformationEx;
TLDispatch.TdiSetInformationExEntry = TdiSetInformationEx;
if (!TLRegisterDispatch(TransportName, &TLDispatch))
goto failure;
#endif
CTERefillMem();
// Now query the lower layer entities, and save the information.
EntityList = CTEAllocMem(sizeof(TDIEntityID) * MAX_TDI_ENTITIES);
if (EntityList == NULL)
goto failure;
EntityList[0].tei_entity = CO_TL_ENTITY;
EntityList[0].tei_instance = 0;
EntityList[1].tei_entity = CL_TL_ENTITY;
EntityList[1].tei_instance = 0;
EntityCount = 2;
// When we have multiple networks under us, we'll want to loop through
// here calling them all. For now just call the one we have.
(*LocalNetInfo.ipi_getelist)(EntityList, &EntityCount);
CTERefillMem();
#ifdef VXD
// Allocate memory as needed to satisfy the heap preload requirements. We'll
// allocate a bunch of memory from the IFSMgr and then free it, so
// hopefully it'll be there later when we need it.
PreloadCount = MIN(PreloadCount, MAX_PRELOAD_COUNT);
for (i = 0; i < PreloadCount; i++) {
void *Temp;
Temp = CTEAllocMem(PRELOAD_BLOCK_SIZE);
if (Temp != NULL)
PreloadPtrs[i] = Temp;
else
break;
CTERefillMem();
}
PreloadCount = i;
for (i = 0; i < PreloadCount; i++) {
CTEFreeMem(PreloadPtrs[i]);
}
#endif
return TRUE;
// Come here to handle all failure cases.
failure:
// If we've registered Raw IP, unregister it now.
if (RawProtInfo != NULL)
TLRegisterProtocol(PROTOCOL_ANY, NULL, NULL, NULL, NULL);
// If we've registered UDP, unregister it now.
if (UDPProtInfo != NULL)
TLRegisterProtocol(PROTOCOL_UDP, NULL, NULL, NULL, NULL);
#ifndef UDP_ONLY
UnInitTCPSend();
UnInitTCPRcv();
if (TCBInitialized) {
UnInitTCB();
}
UnInitTCPConn();
#endif
CTERefillMem();
return FALSE;
}
#pragma END_INIT