diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/tcpip/ip/iploop.c | 665 |
1 files changed, 665 insertions, 0 deletions
diff --git a/private/ntos/tdi/tcpip/ip/iploop.c b/private/ntos/tdi/tcpip/ip/iploop.c new file mode 100644 index 000000000..b47676876 --- /dev/null +++ b/private/ntos/tdi/tcpip/ip/iploop.c @@ -0,0 +1,665 @@ +/********************************************************************/ +/** Microsoft LAN Manager **/ +/** Copyright(c) Microsoft Corp., 1990-1992 **/ +/********************************************************************/ +/* :ts=4 */ + +//*** iploop.c - IP loopback routines. +// +// This file contains all the routines related to loopback + +#include "oscfg.h" +#include "cxport.h" +#include "ndis.h" +#include "ip.h" +#include "tdistat.h" +#include "ipdef.h" +#include "ipinit.h" +#include "llipif.h" +#include "iprtdef.h" +#include "iproute.h" +#include "tdiinfo.h" +#include "llinfo.h" + +#define LOOP_LOOKAHEAD MAX_HDR_SIZE + 8 + +extern int NumNTE; + +extern Interface *IFList; +extern uint NumIF; + +extern void IPRcv(void *, void *, uint, uint, NDIS_HANDLE, uint, uint); +extern void IPSendComplete(void *, PNDIS_PACKET, NDIS_STATUS); +extern void IPRcvComplete(void); +extern PNDIS_BUFFER CopyToNdis(PNDIS_BUFFER DestBuf, uchar *SrcBuf, uint Size, + uint *StartOffset); + +DEFINE_LOCK_STRUCTURE(LoopLock) +PNDIS_PACKET LoopXmitHead = (PNDIS_PACKET)NULL; +PNDIS_PACKET LoopXmitTail = (PNDIS_PACKET)NULL; +CTEEvent LoopXmitEvent; +RouteInterface LoopInterface; // Loopback interface. +uint LoopXmitRtnRunning = 0; + + +#ifdef NT +#ifdef ALLOC_PRAGMA +// +// Make init code disposable. +// +NetTableEntry *InitLoopback(IPConfigInfo *ConfigInfo); + +#pragma alloc_text(INIT, InitLoopback) + +#endif // ALLOC_PRAGMA +#endif // NT + + +uint LoopIndex; // Index of loop I/F. +uint LoopInstance; // I/F instance of loopback I/F. +NetTableEntry *LoopNTE; // Pointer to loopback NTE. + +IFEntry LoopIFE; // Loopback IF Entry. + +uchar LoopName[] = "MS TCP Loopback interface"; + +uint LoopEntityType = IF_MIB; + +//* LoopXmitRtn - Loopback xmit event routine. +// +// This is the delayed event routine called for a loopback transmit. +// +// Entry: Event - Pointer to event structure. +// Context - Pointer to loopback NTE +// +// Returns: Nothing. +// +void +LoopXmitRtn(CTEEvent *Event, void *Context) +{ + PNDIS_PACKET Packet; // Pointer to packet being transmitted + CTELockHandle Handle; + PNDIS_BUFFER Buffer; // Current NDIS buffer being processed. + uint TotalLength; // Total length of send. + uint LookaheadLength; // Bytes in lookahead. + uint Copied; // Bytes copied so far. + uchar *CopyPtr; // Pointer to buffer being copied into. + uchar *SrcPtr; // Pointer to buffer being copied from. + uint SrcLength; // Length of src buffer. + uchar LookaheadBuffer[LOOP_LOOKAHEAD]; + uchar Rcvd = FALSE; +#ifdef NT + KIRQL OldIrql; + + + ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); + + // + // Raise IRQL so we can acquire locks at DPC level in the receive code. + // + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); +#endif // NT + + CTEGetLock(&LoopLock, &Handle); + + if (LoopXmitRtnRunning) { + CTEFreeLock(&LoopLock, Handle); +#ifdef NT + KeLowerIrql(OldIrql); +#endif // NT + return; + } + + LoopXmitRtnRunning = 1; + + for (;;) { + + Packet = LoopXmitHead; // Get the next packet from the list. + if (Packet != (PNDIS_PACKET)NULL) { + LoopXmitHead = *(PNDIS_PACKET *)Packet->MacReserved; + LoopIFE.if_outqlen--; + CTEFreeLock(&LoopLock, Handle); + } else { // Nothing left to do. + LoopXmitRtnRunning = 0; + CTEFreeLock(&LoopLock, Handle); + break; + } + + NdisQueryPacket(Packet, NULL, NULL, &Buffer, &TotalLength); + LoopIFE.if_outoctets += TotalLength; + LoopIFE.if_inoctets += TotalLength; + + // See if the interface is up. If it's not, we can't deliver it. + if (LoopIFE.if_adminstatus == IF_STATUS_UP) { + LookaheadLength = MIN(LOOP_LOOKAHEAD, TotalLength); + Copied = 0; + CopyPtr = LookaheadBuffer; + while (Copied < LookaheadLength) { + uint ThisCopy; // Bytes to copy this time. + +#ifdef DEBUG + if (!Buffer) { + DEBUGCHK; + CTEGetLock(&LoopLock, &Handle); + LoopXmitRtnRunning = 0; + CTEFreeLock(&LoopLock, Handle); +#ifdef NT + KeLowerIrql(OldIrql); +#endif // NT + return; + } +#endif + + NdisQueryBuffer(Buffer, &SrcPtr, &SrcLength); + ThisCopy = MIN(SrcLength, LookaheadLength - Copied); + CTEMemCopy(CopyPtr, SrcPtr, ThisCopy); + Copied += ThisCopy; + CopyPtr += ThisCopy; + NdisGetNextBuffer(Buffer, &Buffer); + } + + Rcvd = TRUE; + LoopIFE.if_inucastpkts++; + + IPRcv(Context, LookaheadBuffer, LookaheadLength, TotalLength, + (NDIS_HANDLE) Packet, 0, FALSE); + + } else { + LoopIFE.if_indiscards++; + } + + IPSendComplete(Context, Packet, NDIS_STATUS_SUCCESS); + +#ifdef NT + // + // Give other threads a chance to run. + // + KeLowerIrql(OldIrql); + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); +#endif // NT + + CTEGetLock(&LoopLock, &Handle); + } + + if (Rcvd) { + IPRcvComplete(); + } + +#ifdef NT + KeLowerIrql(OldIrql); +#endif // NT + +} + +//** LoopXmit - Transmit a loopback packet. +// +// This is the routine called when we need to transmit a packet to ourselves. We put +// the packet on our loopback list, and schedule an event to deal with it. +// +// Entry: Context - Pointer to the loopback NTE. +// Packet - Pointer to packet to be transmitted. +// Dest - Destination addres of packet. +// RCE - Pointer to RCE (should be NULL). +// +// Returns: NDIS_STATUS_PENDING +// +NDIS_STATUS +LoopXmit(void *Context, PNDIS_PACKET Packet, IPAddr Dest, RouteCacheEntry *RCE) +{ + PNDIS_PACKET *PacketPtr; + CTELockHandle Handle; + + LoopIFE.if_outucastpkts++; + + if (LoopIFE.if_adminstatus == IF_STATUS_UP) { + PacketPtr = (PNDIS_PACKET *)Packet->MacReserved; + *PacketPtr = (PNDIS_PACKET)NULL; + + + CTEGetLock(&LoopLock, &Handle); + if (LoopXmitHead == (PNDIS_PACKET)NULL) { // Xmit. Q is empty + LoopXmitHead = Packet; + } else { // Xmit. Q is not empty + PacketPtr = (PNDIS_PACKET *)LoopXmitTail->MacReserved; + *PacketPtr = Packet; + } + LoopXmitTail = Packet; + LoopIFE.if_outqlen++; + if (!LoopXmitRtnRunning) { + CTEScheduleEvent(&LoopXmitEvent, Context); + } + CTEFreeLock(&LoopLock, Handle); + return NDIS_STATUS_PENDING; + } else { + LoopIFE.if_outdiscards++; + return NDIS_STATUS_SUCCESS; + } +} + +//* LoopXfer - Loopback transfer data routine. +// +// Called when we need to transfer data for the loopback net. The input TDContext is +// the original packet. +// +// Entry: Context - Pointer to loopback NTE. +// TDContext - Original packet that was sent. +// Dummy - Unused +// Offset - Offset in frame from which to start copying. +// BytesToCopy - Number of bytes to copy. +// DestPacket - Packet describing buffer to copy into. +// BytesCopied - Place to return bytes copied. +// +// Returns: NDIS_STATUS_SUCCESS +// +NDIS_STATUS +LoopXfer(void *Context, NDIS_HANDLE TDContext, uint Dummy, uint Offset, uint BytesToCopy, + PNDIS_PACKET DestPacket, uint *BytesCopied) +{ + PNDIS_BUFFER SrcBuffer; // Current buffer we're copying from. + PNDIS_PACKET SrcPacket = (PNDIS_PACKET)TDContext; + uchar *SrcPtr; // Where we're copying from. + uint SrcLength; // Length of current src buffer. + PNDIS_BUFFER DestBuffer; // Buffer we're copying to. + uchar *DestPtr; // Where we're copying to. + uint DestLength; // Length of current dest. buffer. + uint Copied; // Length we've copied so far. + + // First, skip over Offset bytes in the packet. + NdisQueryPacket(SrcPacket, NULL, NULL, &SrcBuffer, NULL); +#ifdef DEBUG + if (!SrcBuffer) + DEBUGCHK; +#endif + NdisQueryBuffer(SrcBuffer, &SrcPtr, &SrcLength); + while (Offset >= SrcLength) { + Offset -= SrcLength; + NdisGetNextBuffer(SrcBuffer, &SrcBuffer); +#ifdef DEBUG + if (!SrcBuffer) + DEBUGCHK; +#endif + NdisQueryBuffer(SrcBuffer, &SrcPtr, &SrcLength); + } + // Update Src pointer and length. + SrcPtr += Offset; + SrcLength -= Offset; + + // Set up the destination pointers and lengths. + NdisQueryPacket(DestPacket, NULL, NULL, &DestBuffer, NULL); + NdisQueryBuffer(DestBuffer, &DestPtr, &DestLength); + Copied = 0; + + while (BytesToCopy) { + uint ThisCopy; // What we're copying this time. + + ThisCopy = MIN(SrcLength, DestLength); + CTEMemCopy(DestPtr, SrcPtr, ThisCopy); + Copied += ThisCopy; + DestPtr += ThisCopy; + SrcPtr += ThisCopy; + BytesToCopy -= ThisCopy; + SrcLength -= ThisCopy; + DestLength -= ThisCopy; + if (!SrcLength) { // We've exhausted the source buffer. + NdisGetNextBuffer(SrcBuffer, &SrcBuffer); + if (!SrcBuffer) { +#ifdef DEBUG + if (BytesToCopy) + DEBUGCHK; +#endif + break; // Copy is done. + } + NdisQueryBuffer(SrcBuffer, &SrcPtr, &SrcLength); + } + if (!DestLength) { // We've exhausted the destination buffer. + NdisGetNextBuffer(DestBuffer, &DestBuffer); + if (!DestBuffer) { +#ifdef DEBUG + if (BytesToCopy) + DEBUGCHK; +#endif + break; // Copy is done. + } + NdisQueryBuffer(DestBuffer, &DestPtr, &DestLength); + } + } + + *BytesCopied = Copied; + return NDIS_STATUS_SUCCESS; + + +} + +//* LoopClose - Loopback close routine. +// +// This is the loopback close routine. It does nothing but return. +// +// Entry: Context - Unused. +// +// Returns: Nothing. +// +void +LoopClose(void *Context) +{ + +} + +//* LoopInvalidate - Invalidate an RCE. +// +// The loopback invalidate RCE routine. It also does nothing. +// +// Entry: Context - Unused. +// RCE - Pointer to RCE to be invalidated. +// +// Returns: Nothing. +// +void +LoopInvalidate(void *Context, RouteCacheEntry *RCE) +{ + +} + +//* LoopQInfo - Loopback query information handler. +// +// Called when the upper layer wants to query information about the loopback +// interface. +// +// Input: IFContext - Interface context (unused). +// ID - TDIObjectID for object. +// Buffer - Buffer to put data into. +// Size - Pointer to size of buffer. On return, filled with +// bytes copied. +// Context - Pointer to context block. +// +// Returns: Status of attempt to query information. +// +int +LoopQInfo(void *IFContext, TDIObjectID *ID, PNDIS_BUFFER Buffer, uint *Size, + void *Context) +{ + uint Offset = 0; + uint BufferSize = *Size; + uint Entity; + uint Instance; + + + Entity = ID->toi_entity.tei_entity; + Instance = ID->toi_entity.tei_instance; + + // First, make sure it's possibly an ID we can handle. + if (Entity != IF_ENTITY || Instance != LoopInstance) { + return TDI_INVALID_REQUEST; + } + + *Size = 0; // In case of an error. + + if (ID->toi_type != INFO_TYPE_PROVIDER) + return TDI_INVALID_PARAMETER; + + if (ID->toi_class == INFO_CLASS_GENERIC) { + if (ID->toi_id == ENTITY_TYPE_ID) { + // He's trying to see what type we are. + if (BufferSize >= sizeof(uint)) { + (void)CopyToNdis(Buffer, (uchar *)&LoopEntityType, sizeof(uint), + &Offset); + return TDI_SUCCESS; + } else + return TDI_BUFFER_TOO_SMALL; + } + return TDI_INVALID_PARAMETER; + } else + if (ID->toi_class != INFO_CLASS_PROTOCOL) + return TDI_INVALID_PARAMETER; + + // If he's asking for MIB statistics, then return them, otherwise fail + // the request. + + if (ID->toi_id == IF_MIB_STATS_ID) { + + + // He's asking for statistics. Make sure his buffer is at least big + // enough to hold the fixed part. + + if (BufferSize < IFE_FIXED_SIZE) { + return TDI_BUFFER_TOO_SMALL; + } + + // He's got enough to hold the fixed part. Copy our IFE structure + // into his buffer. + Buffer = CopyToNdis(Buffer, (uchar *)&LoopIFE, IFE_FIXED_SIZE, &Offset); + + // See if he has room for the descriptor string. + if (BufferSize >= (IFE_FIXED_SIZE + sizeof(LoopName))) { + // He has room. Copy it. + (void)CopyToNdis(Buffer, LoopName, sizeof(LoopName), &Offset); + *Size = IFE_FIXED_SIZE + sizeof(LoopName); + return TDI_SUCCESS; + } else { + // Not enough room to copy the desc. string. + *Size = IFE_FIXED_SIZE; + return TDI_BUFFER_OVERFLOW; + } + + } + + return TDI_INVALID_PARAMETER; + +} + +//* LoopSetInfo - Loopback set information handler. +// +// The loopback set information handler. We support setting of an I/F admin +// status. +// +// Input: Context - Pointer to I/F to set on. +// ID - The object ID +// Buffer - Pointer to buffer containing value to set. +// Size - Size in bytes of Buffer. +// +// Returns: Status of attempt to set information. +// +int +LoopSetInfo(void *Context, TDIObjectID *ID, void *Buffer, uint Size) +{ + IFEntry *IFE = (IFEntry *)Buffer; + uint Entity, Instance, Status; + + Entity = ID->toi_entity.tei_entity; + Instance = ID->toi_entity.tei_instance; + + // First, make sure it's possibly an ID we can handle. + if (Entity != IF_ENTITY || Instance != LoopInstance) { + return TDI_INVALID_REQUEST; + } + + if (ID->toi_class != INFO_CLASS_PROTOCOL || + ID->toi_type != INFO_TYPE_PROVIDER) { + return TDI_INVALID_PARAMETER; + } + + // It's for the I/F level, see if it's for the statistics. + if (ID->toi_id == IF_MIB_STATS_ID) { + // It's for the stats. Make sure it's a valid size. + if (Size >= IFE_FIXED_SIZE) { + // It's a valid size. See what he wants to do. + Status = IFE->if_adminstatus; + if (Status == IF_STATUS_UP || Status == IF_STATUS_DOWN) + LoopIFE.if_adminstatus = Status; + else + if (Status != IF_STATUS_TESTING) + return TDI_INVALID_PARAMETER; + + return TDI_SUCCESS; + + } else + return TDI_INVALID_PARAMETER; + } + + return TDI_INVALID_PARAMETER; +} + +//* LoopAddAddr - Dummy loopback add address routine. +// +// Called at init time when we need to initialize ourselves. +// +uint +LoopAddAddr(void *Context, uint Type, IPAddr Address, IPMask Mask, void *Context2) +{ + + return TRUE; +} + +//* LoopDelAddr - Dummy loopback del address routine. +// +// Called at init time when we need to initialize ourselves. +// +uint +LoopDelAddr(void *Context, uint Type, IPAddr Address, IPMask Mask) +{ + + return TRUE; +} + +#pragma BEGIN_INIT + +extern int InitNTE(NetTableEntry *); +extern int InitInterface(NetTableEntry *); + +#ifdef CHICAGO +#pragma END_INIT +#pragma code_seg("_LTEXT", "LCODE") +#endif + +//* LoopGetEList - Get the entity list. +// +// Called at init time to get an entity list. We fill our stuff in and return. +// +// Input: Context - Unused. +// EntityList - Pointer to entity list to be filled in. +// Count - Pointer to number of entries in the list. +// +// Returns Status of attempt to get the info. +// +int +LoopGetEList(void *Context, TDIEntityID *EntityList, uint *Count) +{ + uint ECount; + uint MyIFBase; + uint i; + + ECount = *Count; + + // Walk down the list, looking for existing IF entities, and + // adjust our base instance accordingly. + + MyIFBase = 0; + for (i = 0; i < ECount; i++, EntityList++) { + if (EntityList->tei_entity == IF_ENTITY) + MyIFBase = MAX(MyIFBase, EntityList->tei_instance + 1); + } + + // EntityList points to the start of where we want to begin filling in. + // Make sure we have enough room. + + if ((ECount + 1) > MAX_TDI_ENTITIES) + return FALSE; + + // At this point we've figure out our base instance. Save for later use. + LoopInstance = MyIFBase; + + // Now fill it in. + EntityList->tei_entity = IF_ENTITY; + EntityList->tei_instance = MyIFBase; + (*Count)++; + + return TRUE; +} + +#ifdef CHICAGO +#pragma BEGIN_INIT +#endif + + +//** InitLoopback - Initialize the loopback NTE. +// +// This function initialized the loopback NTE. We set up the the MSS and pointer to +// the various pseudo-link routines, then call InitNTE and return. +// +// Entry: ConfigInfo - Pointer to config. info structure. +// +// Returns: TRUE if we initialized, FALSE if we didn't. +// +NetTableEntry * +InitLoopback(IPConfigInfo *ConfigInfo) +{ + LLIPBindInfo ARPInfo; + + CTERefillMem(); + LoopNTE = CTEAllocMem(sizeof(NetTableEntry)); + if (LoopNTE == NULL) + return LoopNTE; + + CTEMemSet(LoopNTE, 0, sizeof(NetTableEntry)); + + LoopNTE->nte_addr = LOOPBACK_ADDR; + LoopNTE->nte_mask = CLASSA_MASK; + LoopNTE->nte_icmpseq = 1; + LoopNTE->nte_flags = NTE_VALID | NTE_ACTIVE | NTE_PRIMARY; + + CTEInitLock(&LoopNTE->nte_lock); + CTEInitLock(&LoopInterface.ri_if.if_lock); + LoopNTE->nte_mss = LOOPBACK_MSS; + LoopNTE->nte_if = (Interface *)&LoopInterface; + LoopInterface.ri_if.if_lcontext = LoopNTE; + LoopInterface.ri_if.if_xmit = LoopXmit; + LoopInterface.ri_if.if_transfer = LoopXfer; + LoopInterface.ri_if.if_close = LoopClose; + LoopInterface.ri_if.if_invalidate = LoopInvalidate; + LoopInterface.ri_if.if_qinfo = LoopQInfo; + LoopInterface.ri_if.if_setinfo = LoopSetInfo; + LoopInterface.ri_if.if_getelist = LoopGetEList; + LoopInterface.ri_if.if_addaddr = LoopAddAddr; + LoopInterface.ri_if.if_deladdr = LoopDelAddr; + LoopInterface.ri_if.if_bcast = IP_LOCAL_BCST; + LoopInterface.ri_if.if_speed = 10000000; + LoopInterface.ri_if.if_mtu = LOOPBACK_MSS; + LoopInterface.ri_if.if_llipflags = LIP_COPY_FLAG; +#ifdef _PNP_POWER + LoopInterface.ri_if.if_refcount = 1; + LoopInterface.ri_if.if_pnpcontext = 0; +#endif + + ARPInfo.lip_mss = LOOPBACK_MSS + sizeof(IPHeader); + ARPInfo.lip_index = LoopIndex; + ARPInfo.lip_close = LoopClose; + ARPInfo.lip_addaddr = LoopAddAddr; + ARPInfo.lip_deladdr = LoopDelAddr; + ARPInfo.lip_flags = LIP_COPY_FLAG; + LoopIndex = NumIF + 1; + LoopInterface.ri_if.if_index = LoopIndex; + CTEInitEvent(&LoopXmitEvent, LoopXmitRtn); + CTEInitLock(&LoopLock); + LoopIFE.if_index = LoopIndex; + LoopIFE.if_type = IF_TYPE_LOOPBACK; + LoopIFE.if_mtu = ARPInfo.lip_mss; + LoopIFE.if_speed = 10000000; + LoopIFE.if_adminstatus = IF_STATUS_UP; + LoopIFE.if_operstatus = IF_STATUS_UP; + LoopIFE.if_descrlen = sizeof(LoopName); + + IFList = (Interface *)&LoopInterface; + NumIF++; + + NumNTE++; + + if (!InitInterface(LoopNTE)) + return NULL; + + if (!InitNTE(LoopNTE)) + return NULL; + + return LoopNTE; +} + +#pragma END_INIT + |