TDI_STATUS InfoTdiQueryEntityType(TDIEntityID ID, PNDIS_BUFFER Buffer, PUINT BufferSize) { KIRQL OldIrql; UINT i, Flags = 0; TcpipAcquireSpinLock(&EntityListLock, &OldIrql); for (i = 0; i < EntityCount; i++) { if (EntityList[i].tei_entity == ID.tei_entity && EntityList[i].tei_instance == ID.tei_instance) break; } if (i == EntityCount) { TcpipReleaseSpinLock(&EntityListLock, OldIrql); return TDI_INVALID_PARAMETER; } Flags = EntityList[i].flags; InfoCopyOut((PCHAR)&Flags, sizeof(ULONG), Buffer, BufferSize); TcpipReleaseSpinLock(&EntityListLock, OldIrql); return TDI_SUCCESS; }
PVOID GetContext(TDIEntityID ID) { UINT i; KIRQL OldIrql; PVOID Context; TcpipAcquireSpinLock(&EntityListLock, &OldIrql); for (i = 0; i < EntityCount; i++) { if (EntityList[i].tei_entity == ID.tei_entity && EntityList[i].tei_instance == ID.tei_instance) break; } if (i == EntityCount) { TcpipReleaseSpinLock(&EntityListLock, OldIrql); DbgPrint("WARNING: Unable to get context for %d %d\n", ID.tei_entity, ID.tei_instance); return NULL; } Context = EntityList[i].context; TcpipReleaseSpinLock(&EntityListLock, OldIrql); return Context; }
PFIB_ENTRY RouterCreateRoute( PIP_ADDRESS NetworkAddress, PIP_ADDRESS Netmask, PIP_ADDRESS RouterAddress, PIP_INTERFACE Interface, UINT Metric) /* * FUNCTION: Creates a route with IPv4 addresses as parameters * ARGUMENTS: * NetworkAddress = Address of network * Netmask = Netmask of network * RouterAddress = Address of router to use * NTE = Pointer to NTE to use * Metric = Cost of this route * RETURNS: * Pointer to FIB entry if the route was created, NULL if not. * The FIB entry references the NTE. The caller is responsible * for providing this reference */ { KIRQL OldIrql; PLIST_ENTRY CurrentEntry; PLIST_ENTRY NextEntry; PFIB_ENTRY Current; PNEIGHBOR_CACHE_ENTRY NCE; TcpipAcquireSpinLock(&FIBLock, &OldIrql); CurrentEntry = FIBListHead.Flink; while (CurrentEntry != &FIBListHead) { NextEntry = CurrentEntry->Flink; Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); NCE = Current->Router; if( AddrIsEqual(NetworkAddress, &Current->NetworkAddress) && AddrIsEqual(Netmask, &Current->Netmask) ) { TI_DbgPrint(DEBUG_ROUTER,("Attempting to add duplicate route to %s\n", A2S(NetworkAddress))); TcpipReleaseSpinLock(&FIBLock, OldIrql); return NULL; } CurrentEntry = NextEntry; } TcpipReleaseSpinLock(&FIBLock, OldIrql); /* The NCE references RouterAddress. The NCE is referenced for us */ NCE = NBFindOrCreateNeighbor(Interface, RouterAddress); if (!NCE) { /* Not enough free resources */ return NULL; } return RouterAddRoute(NetworkAddress, Netmask, NCE, Metric); }
TDI_STATUS InfoTdiQueryGetAddrTable(TDIEntityID ID, PNDIS_BUFFER Buffer, PUINT BufferSize) { KIRQL OldIrql; PIPADDR_ENTRY IPEntry; PIP_INTERFACE CurrentIF; UINT i; TI_DbgPrint(DEBUG_INFO, ("Called.\n")); TcpipAcquireSpinLock(&EntityListLock, &OldIrql); for (i = 0; i < EntityCount; i++) { if (EntityList[i].tei_entity == ID.tei_entity && EntityList[i].tei_instance == ID.tei_instance) break; } if (i == EntityCount) { TcpipReleaseSpinLock(&EntityListLock, OldIrql); return TDI_INVALID_PARAMETER; } IPEntry = ExAllocatePool(NonPagedPool, sizeof(IPADDR_ENTRY)); if (!IPEntry) { TcpipReleaseSpinLock(&EntityListLock, OldIrql); return TDI_NO_RESOURCES; } CurrentIF = EntityList[i].context; IPEntry->Index = CurrentIF->Index; GetInterfaceIPv4Address(CurrentIF, ADE_UNICAST, &IPEntry->Addr); GetInterfaceIPv4Address(CurrentIF, ADE_ADDRMASK, &IPEntry->Mask); GetInterfaceIPv4Address(CurrentIF, ADE_BROADCAST, &IPEntry->BcastAddr); TcpipReleaseSpinLock(&EntityListLock, OldIrql); InfoCopyOut((PCHAR)IPEntry, sizeof(IPADDR_ENTRY), Buffer, BufferSize); ExFreePool(IPEntry); return TDI_SUCCESS; }
PADDRESS_FILE AddrFindShared( PIP_ADDRESS BindAddress, USHORT Port, USHORT Protocol) { PLIST_ENTRY CurrentEntry; KIRQL OldIrql; PADDRESS_FILE Current = NULL; TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); CurrentEntry = AddressFileListHead.Flink; while (CurrentEntry != &AddressFileListHead) { Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry); /* See if this address matches the search criteria */ if ((Current->Port == Port) && (Current->Protocol == Protocol)) { /* Increase the sharer count */ ASSERT(Current->Sharers != 0); InterlockedIncrement(&Current->Sharers); break; } CurrentEntry = CurrentEntry->Flink; Current = NULL; } TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); return Current; }
VOID NBResetNeighborTimeout(PIP_ADDRESS Address) { KIRQL OldIrql; UINT HashValue; PNEIGHBOR_CACHE_ENTRY NCE; TI_DbgPrint(DEBUG_NCACHE, ("Resetting NCE timout for 0x%s\n", A2S(Address))); HashValue = *(PULONG)(&Address->Address); HashValue ^= HashValue >> 16; HashValue ^= HashValue >> 8; HashValue ^= HashValue >> 4; HashValue &= NB_HASHMASK; TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); for (NCE = NeighborCache[HashValue].Cache; NCE != NULL; NCE = NCE->Next) { if (AddrIsEqual(Address, &NCE->Address)) { NCE->EventCount = 0; break; } } TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); }
VOID AddEntity(ULONG EntityType, PVOID Context, ULONG Flags) { KIRQL OldIrql; ULONG i, Instance = 0; BOOLEAN ChoseIndex = FALSE; TcpipAcquireSpinLock(&EntityListLock, &OldIrql); while (!ChoseIndex) { ChoseIndex = TRUE; for (i = 0; i < EntityCount; i++) { if (EntityList[i].tei_entity == EntityType && EntityList[i].tei_instance == Instance) { Instance++; ChoseIndex = FALSE; } } } EntityList[EntityCount].tei_entity = EntityType; EntityList[EntityCount].tei_instance = Instance; EntityList[EntityCount].context = Context; EntityList[EntityCount].flags = Flags; EntityCount++; TcpipReleaseSpinLock(&EntityListLock, OldIrql); }
NTSTATUS RouterRemoveRoute(PIP_ADDRESS Target, PIP_ADDRESS Router) /* * FUNCTION: Removes a route from the Forward Information Base (FIB) * ARGUMENTS: * Target: The machine or network targeted by the route * Router: The router used to pass the packet to the destination * * Searches the FIB and removes a route matching the indicated parameters. */ { KIRQL OldIrql; PLIST_ENTRY CurrentEntry; PLIST_ENTRY NextEntry; PFIB_ENTRY Current; BOOLEAN Found = FALSE; PNEIGHBOR_CACHE_ENTRY NCE; TI_DbgPrint(DEBUG_ROUTER, ("Called\n")); TI_DbgPrint(DEBUG_ROUTER, ("Deleting Route From: %s\n", A2S(Router))); TI_DbgPrint(DEBUG_ROUTER, (" To: %s\n", A2S(Target))); TcpipAcquireSpinLock(&FIBLock, &OldIrql); RouterDumpRoutes(); CurrentEntry = FIBListHead.Flink; while (CurrentEntry != &FIBListHead) { NextEntry = CurrentEntry->Flink; Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); NCE = Current->Router; if( AddrIsEqual( &Current->NetworkAddress, Target ) && AddrIsEqual( &NCE->Address, Router ) ) { Found = TRUE; break; } Current = NULL; CurrentEntry = NextEntry; } if( Found ) { TI_DbgPrint(DEBUG_ROUTER, ("Deleting route\n")); DestroyFIBE( Current ); } RouterDumpRoutes(); TcpipReleaseSpinLock(&FIBLock, OldIrql); TI_DbgPrint(DEBUG_ROUTER, ("Leaving\n")); return Found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; }
VOID ConnectionFree(PVOID Object) { PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Object; KIRQL OldIrql; TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n")); TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql); RemoveEntryList(&Connection->ListEntry); TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql); ExFreePoolWithTag( Connection, CONN_ENDPT_TAG ); }
TDI_STATUS InfoTdiQueryListEntities(PNDIS_BUFFER Buffer, PUINT BufferSize) { UINT Count, Size, BufSize = *BufferSize; KIRQL OldIrql; TI_DbgPrint(DEBUG_INFO,("About to copy %d TDIEntityIDs to user\n", EntityCount)); TcpipAcquireSpinLock(&EntityListLock, &OldIrql); Size = EntityCount * sizeof(TDIEntityID); *BufferSize = Size; TI_DbgPrint(DEBUG_INFO,("BufSize: %d, NeededSize: %d\n", BufSize, Size)); if (BufSize < Size || !Buffer) { TcpipReleaseSpinLock( &EntityListLock, OldIrql ); /* The buffer is too small to contain requested data, but we return * success anyway, as we did everything we wanted. */ return TDI_SUCCESS; } /* Return entity list -- Copy only the TDIEntityID parts. */ for( Count = 0; Count < EntityCount; Count++ ) { CopyBufferToBufferChain(Buffer, Count * sizeof(TDIEntityID), (PCHAR)&EntityList[Count], sizeof(TDIEntityID)); } TcpipReleaseSpinLock(&EntityListLock, OldIrql); return TDI_SUCCESS; }
BOOLEAN NBQueuePacket( PNEIGHBOR_CACHE_ENTRY NCE, PNDIS_PACKET NdisPacket, PNEIGHBOR_PACKET_COMPLETE PacketComplete, PVOID PacketContext) /* * FUNCTION: Queues a packet on an NCE for later transmission * ARGUMENTS: * NCE = Pointer to NCE to queue packet on * NdisPacket = Pointer to NDIS packet to queue * RETURNS: * TRUE if the packet was successfully queued, FALSE if not */ { KIRQL OldIrql; PNEIGHBOR_PACKET Packet; UINT HashValue; TI_DbgPrint (DEBUG_NCACHE, ("Called. NCE (0x%X) NdisPacket (0x%X).\n", NCE, NdisPacket)); Packet = ExAllocatePoolWithTag( NonPagedPool, sizeof(NEIGHBOR_PACKET), NEIGHBOR_PACKET_TAG ); if( !Packet ) return FALSE; /* FIXME: Should we limit the number of queued packets? */ HashValue = *(PULONG)(&NCE->Address.Address); HashValue ^= HashValue >> 16; HashValue ^= HashValue >> 8; HashValue ^= HashValue >> 4; HashValue &= NB_HASHMASK; TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); Packet->Complete = PacketComplete; Packet->Context = PacketContext; Packet->Packet = NdisPacket; InsertTailList( &NCE->PacketQueue, &Packet->Next ); TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); if( !(NCE->State & NUD_INCOMPLETE) ) NBSendPackets( NCE ); return TRUE; }
VOID NBRemoveNeighbor( PNEIGHBOR_CACHE_ENTRY NCE) /* * FUNCTION: Removes a neighbor from the neighbor cache * ARGUMENTS: * NCE = Pointer to NCE to remove from cache * NOTES: * The NCE must be in a safe state */ { PNEIGHBOR_CACHE_ENTRY *PrevNCE; PNEIGHBOR_CACHE_ENTRY CurNCE; ULONG HashValue; KIRQL OldIrql; TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE)); HashValue = *(PULONG)(&NCE->Address.Address); HashValue ^= HashValue >> 16; HashValue ^= HashValue >> 8; HashValue ^= HashValue >> 4; HashValue &= NB_HASHMASK; TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); /* Search the list and remove the NCE from the list if found */ for (PrevNCE = &NeighborCache[HashValue].Cache; (CurNCE = *PrevNCE) != NULL; PrevNCE = &CurNCE->Next) { if (CurNCE == NCE) { /* Found it, now unlink it from the list */ *PrevNCE = CurNCE->Next; NBFlushPacketQueue( CurNCE, NDIS_STATUS_REQUEST_ABORTED ); ExFreePoolWithTag(CurNCE, NCE_TAG); break; } } TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); }
NTSTATUS RouterShutdown( VOID) /* * FUNCTION: Shuts down the routing subsystem * RETURNS: * Status of operation */ { KIRQL OldIrql; TI_DbgPrint(DEBUG_ROUTER, ("Called.\n")); /* Clear Forward Information Base */ TcpipAcquireSpinLock(&FIBLock, &OldIrql); DestroyFIBEs(); TcpipReleaseSpinLock(&FIBLock, OldIrql); return STATUS_SUCCESS; }
VOID RemoveEntityByContext(PVOID Context) { ULONG i; KIRQL OldIrql; TcpipAcquireSpinLock(&EntityListLock, &OldIrql); for (i = 0; i < EntityCount; i++) { if( EntityList[i].context == Context ) { if( i != EntityCount - 1 ) { memcpy( &EntityList[i], &EntityList[--EntityCount], sizeof(EntityList[i]) ); } else { EntityCount--; } } } TcpipReleaseSpinLock(&EntityListLock, OldIrql); }
PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor( PIP_ADDRESS Address) /* * FUNCTION: Locates a neighbor in the neighbor cache * ARGUMENTS: * Address = Pointer to IP address * RETURNS: * Pointer to NCE, NULL if not found * NOTES: * If the NCE is found, it is referenced. The caller is * responsible for dereferencing it again after use */ { PNEIGHBOR_CACHE_ENTRY NCE; UINT HashValue; KIRQL OldIrql; TI_DbgPrint(DEBUG_NCACHE, ("Called. Address (0x%X).\n", Address)); HashValue = *(PULONG)&Address->Address; HashValue ^= HashValue >> 16; HashValue ^= HashValue >> 8; HashValue ^= HashValue >> 4; HashValue &= NB_HASHMASK; TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); NCE = NeighborCache[HashValue].Cache; while ((NCE) && (!AddrIsEqual(Address, &NCE->Address))) { NCE = NCE->Next; } TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); return NCE; }
VOID NBUpdateNeighbor( PNEIGHBOR_CACHE_ENTRY NCE, PVOID LinkAddress, UCHAR State) /* * FUNCTION: Update link address information in NCE * ARGUMENTS: * NCE = Pointer to NCE to update * LinkAddress = Pointer to link address * State = State of NCE * NOTES: * The link address and state is updated. Any waiting packets are sent */ { KIRQL OldIrql; UINT HashValue; TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X) LinkAddress (0x%X) State (0x%X).\n", NCE, LinkAddress, State)); HashValue = *(PULONG)(&NCE->Address.Address); HashValue ^= HashValue >> 16; HashValue ^= HashValue >> 8; HashValue ^= HashValue >> 4; HashValue &= NB_HASHMASK; TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); RtlCopyMemory(NCE->LinkAddress, LinkAddress, NCE->LinkAddressLength); NCE->State = State; NCE->EventCount = 0; TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); if( !(NCE->State & NUD_INCOMPLETE) ) { if (NCE->EventTimer) NCE->EventTimer = ARP_COMPLETE_TIMEOUT; NBSendPackets( NCE ); } }
ULONG NBCopyNeighbors (PIP_INTERFACE Interface, PIPARP_ENTRY ArpTable) { PNEIGHBOR_CACHE_ENTRY CurNCE; KIRQL OldIrql; UINT Size = 0, i; for (i = 0; i <= NB_HASHMASK; i++) { TcpipAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql); for( CurNCE = NeighborCache[i].Cache; CurNCE; CurNCE = CurNCE->Next ) { if( CurNCE->Interface == Interface && !AddrIsEqual( &CurNCE->Address, &CurNCE->Interface->Unicast ) ) { if( ArpTable ) { ArpTable[Size].Index = Interface->Index; ArpTable[Size].AddrSize = CurNCE->LinkAddressLength; RtlCopyMemory (ArpTable[Size].PhysAddr, CurNCE->LinkAddress, CurNCE->LinkAddressLength); ArpTable[Size].LogAddr = CurNCE->Address.Address.IPv4Address; if( CurNCE->State & NUD_PERMANENT ) ArpTable[Size].Type = ARP_ENTRY_STATIC; else if( CurNCE->State & NUD_INCOMPLETE ) ArpTable[Size].Type = ARP_ENTRY_INVALID; else ArpTable[Size].Type = ARP_ENTRY_DYNAMIC; } Size++; } } TcpipReleaseSpinLock(&NeighborCache[i].Lock, OldIrql); } return Size; }
/* * FUNCTION: Searches through address file entries to find the first match * ARGUMENTS: * Address = IP address * Port = Port number * Protocol = Protocol number * SearchContext = Pointer to search context * RETURNS: * Pointer to address file, NULL if none was found */ PADDRESS_FILE AddrSearchFirst( PIP_ADDRESS Address, USHORT Port, USHORT Protocol, PAF_SEARCH SearchContext) { KIRQL OldIrql; SearchContext->Address = Address; SearchContext->Port = Port; SearchContext->Protocol = Protocol; TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); SearchContext->Next = AddressFileListHead.Flink; if (!IsListEmpty(&AddressFileListHead)) ReferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry)); TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); return AddrSearchNext(SearchContext); }
VOID NBShutdown(VOID) /* * FUNCTION: Shuts down the neighbor cache */ { PNEIGHBOR_CACHE_ENTRY NextNCE; PNEIGHBOR_CACHE_ENTRY CurNCE; KIRQL OldIrql; UINT i; TI_DbgPrint(DEBUG_NCACHE, ("Called.\n")); /* Remove possible entries from the cache */ for (i = 0; i <= NB_HASHMASK; i++) { TcpipAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql); CurNCE = NeighborCache[i].Cache; while (CurNCE) { NextNCE = CurNCE->Next; /* Flush wait queue */ NBFlushPacketQueue( CurNCE, NDIS_STATUS_NOT_ACCEPTED ); ExFreePoolWithTag(CurNCE, NCE_TAG); CurNCE = NextNCE; } NeighborCache[i].Cache = NULL; TcpipReleaseSpinLock(&NeighborCache[i].Lock, OldIrql); } TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); }
PNEIGHBOR_CACHE_ENTRY NBAddNeighbor( PIP_INTERFACE Interface, PIP_ADDRESS Address, PVOID LinkAddress, UINT LinkAddressLength, UCHAR State, UINT EventTimer) /* * FUNCTION: Adds a neighbor to the neighbor cache * ARGUMENTS: * Interface = Pointer to interface * Address = Pointer to IP address * LinkAddress = Pointer to link address (may be NULL) * LinkAddressLength = Length of link address * State = State of NCE * RETURNS: * Pointer to NCE, NULL there is not enough free resources * NOTES: * The NCE if referenced for the caller if created. The NCE retains * a reference to the IP address if it is created, the caller is * responsible for providing this reference */ { PNEIGHBOR_CACHE_ENTRY NCE; ULONG HashValue; KIRQL OldIrql; TI_DbgPrint (DEBUG_NCACHE, ("Called. Interface (0x%X) Address (0x%X) " "LinkAddress (0x%X) LinkAddressLength (%d) State (0x%X)\n", Interface, Address, LinkAddress, LinkAddressLength, State)); NCE = ExAllocatePoolWithTag (NonPagedPool, sizeof(NEIGHBOR_CACHE_ENTRY) + LinkAddressLength, NCE_TAG); if (NCE == NULL) { TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); return NULL; } NCE->Interface = Interface; NCE->Address = *Address; NCE->LinkAddressLength = LinkAddressLength; NCE->LinkAddress = (PVOID)&NCE[1]; if( LinkAddress ) RtlCopyMemory(NCE->LinkAddress, LinkAddress, LinkAddressLength); else memset(NCE->LinkAddress, 0xff, LinkAddressLength); NCE->State = State; NCE->EventTimer = EventTimer; NCE->EventCount = 0; InitializeListHead( &NCE->PacketQueue ); TI_DbgPrint(MID_TRACE,("NCE: %x\n", NCE)); HashValue = *(PULONG)&Address->Address; HashValue ^= HashValue >> 16; HashValue ^= HashValue >> 8; HashValue ^= HashValue >> 4; HashValue &= NB_HASHMASK; TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); NCE->Next = NeighborCache[HashValue].Cache; NeighborCache[HashValue].Cache = NCE; TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); return NCE; }
PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor( PIP_ADDRESS Address, PIP_INTERFACE Interface) /* * FUNCTION: Locates a neighbor in the neighbor cache * ARGUMENTS: * Address = Pointer to IP address * Interface = Pointer to IP interface * RETURNS: * Pointer to NCE, NULL if not found * NOTES: * If the NCE is found, it is referenced. The caller is * responsible for dereferencing it again after use */ { PNEIGHBOR_CACHE_ENTRY NCE; UINT HashValue; KIRQL OldIrql; PIP_INTERFACE FirstInterface; TI_DbgPrint(DEBUG_NCACHE, ("Called. Address (0x%X).\n", Address)); HashValue = *(PULONG)&Address->Address; HashValue ^= HashValue >> 16; HashValue ^= HashValue >> 8; HashValue ^= HashValue >> 4; HashValue &= NB_HASHMASK; TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); /* If there's no adapter specified, we'll look for a match on * each one. */ if (Interface == NULL) { FirstInterface = GetDefaultInterface(); Interface = FirstInterface; } else { FirstInterface = NULL; } do { NCE = NeighborCache[HashValue].Cache; while (NCE != NULL) { if (NCE->Interface == Interface && AddrIsEqual(Address, &NCE->Address)) { break; } NCE = NCE->Next; } if (NCE != NULL) break; } while ((FirstInterface != NULL) && ((Interface = GetDefaultInterface()) != FirstInterface)); if ((NCE == NULL) && (FirstInterface != NULL)) { /* This time we'll even match loopback NCEs */ NCE = NeighborCache[HashValue].Cache; while (NCE != NULL) { if (AddrIsEqual(Address, &NCE->Address)) { break; } NCE = NCE->Next; } } TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); return NCE; }
/* Get IPRouteEntry s for each of the routes in the system */ TDI_STATUS InfoTdiQueryGetRouteTable( PIP_INTERFACE IF, PNDIS_BUFFER Buffer, PUINT BufferSize ) { TDI_STATUS Status; KIRQL OldIrql; UINT RtCount = CountFIBs(IF); UINT Size = sizeof( IPROUTE_ENTRY ) * RtCount; PFIB_ENTRY RCache, RCacheCur; PIPROUTE_ENTRY RouteEntries, RtCurrent; UINT i; TI_DbgPrint(DEBUG_INFO, ("Called, routes = %d\n", RtCount)); if (RtCount == 0) return InfoCopyOut(NULL, 0, NULL, BufferSize); RouteEntries = ExAllocatePool( NonPagedPool, Size ); RtCurrent = RouteEntries; RCache = ExAllocatePool( NonPagedPool, sizeof( FIB_ENTRY ) * RtCount ); RCacheCur = RCache; if( !RCache || !RouteEntries ) { if( RCache ) ExFreePool( RCache ); if( RouteEntries ) ExFreePool( RouteEntries ); return TDI_NO_RESOURCES; } RtlZeroMemory( RouteEntries, Size ); RtCount = CopyFIBs( IF, RCache ); while( RtCurrent < RouteEntries + RtCount ) { ASSERT(RCacheCur->Router); RtlCopyMemory( &RtCurrent->Dest, &RCacheCur->NetworkAddress.Address, sizeof(RtCurrent->Dest) ); RtlCopyMemory( &RtCurrent->Mask, &RCacheCur->Netmask.Address, sizeof(RtCurrent->Mask) ); RtlCopyMemory( &RtCurrent->Gw, &RCacheCur->Router->Address.Address, sizeof(RtCurrent->Gw) ); RtCurrent->Metric1 = RCacheCur->Metric; RtCurrent->Type = TDI_ADDRESS_TYPE_IP; TI_DbgPrint (DEBUG_INFO, ("%d: NA %08x NM %08x GW %08x MT %x\n", RtCurrent - RouteEntries, RtCurrent->Dest, RtCurrent->Mask, RtCurrent->Gw, RtCurrent->Metric1 )); TcpipAcquireSpinLock(&EntityListLock, &OldIrql); for (i = 0; i < EntityCount; i++) if (EntityList[i].context == IF) break; if (i < EntityCount) RtCurrent->Index = EntityList[i].tei_instance; else RtCurrent->Index = 0; TcpipReleaseSpinLock(&EntityListLock, OldIrql); RtCurrent++; RCacheCur++; } Status = InfoCopyOut( (PCHAR)RouteEntries, Size, Buffer, BufferSize ); ExFreePool( RouteEntries ); ExFreePool( RCache ); TI_DbgPrint(DEBUG_INFO, ("Returning %08x\n", Status)); return Status; }
VOID AddrFileFree( PVOID Object) /* * FUNCTION: Frees an address file object * ARGUMENTS: * Object = Pointer to address file object to free */ { PADDRESS_FILE AddrFile = Object; KIRQL OldIrql; PDATAGRAM_RECEIVE_REQUEST ReceiveRequest; PDATAGRAM_SEND_REQUEST SendRequest; PLIST_ENTRY CurrentEntry; TI_DbgPrint(MID_TRACE, ("Called.\n")); /* We should not be associated with a connection here */ ASSERT(!AddrFile->Connection); /* Remove address file from the global list */ TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); RemoveEntryList(&AddrFile->ListEntry); TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); /* FIXME: Kill TCP connections on this address file object */ /* Return pending requests with error */ TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile)); /* Go through pending receive request list and cancel them all */ while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) { ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry); (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_CANCELLED, 0); /* ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG); FIXME: WTF? */ } TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile)); /* Go through pending send request list and cancel them all */ while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) { SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); (*SendRequest->Complete)(SendRequest->Context, STATUS_CANCELLED, 0); ExFreePoolWithTag(SendRequest, DATAGRAM_SEND_TAG); } /* Protocol specific handling */ switch (AddrFile->Protocol) { case IPPROTO_TCP: if (AddrFile->Port) { TCPFreePort(AddrFile->Port); } break; case IPPROTO_UDP: UDPFreePort( AddrFile->Port ); break; } RemoveEntityByContext(AddrFile); ExFreePoolWithTag(Object, ADDR_FILE_TAG); }
VOID LogActiveObjects(VOID) { #ifdef LOG_OBJECTS PLIST_ENTRY CurrentEntry; KIRQL OldIrql; PADDRESS_FILE AddrFile; PCONNECTION_ENDPOINT Conn; DbgPrint("----------- TCP/IP Active Object Dump -------------\n"); TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); CurrentEntry = AddressFileListHead.Flink; while (CurrentEntry != &AddressFileListHead) { AddrFile = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry); DbgPrint("Address File (%s, %d, %d) @ 0x%p | Ref count: %d | Sharers: %d\n", A2S(&AddrFile->Address), WN2H(AddrFile->Port), AddrFile->Protocol, AddrFile, AddrFile->RefCount, AddrFile->Sharers); DbgPrint("\tListener: "); if (AddrFile->Listener == NULL) DbgPrint("<None>\n"); else DbgPrint("0x%p\n", AddrFile->Listener); DbgPrint("\tAssociated endpoints: "); if (AddrFile->Connection == NULL) DbgPrint("<None>\n"); else { Conn = AddrFile->Connection; while (Conn) { DbgPrint("0x%p ", Conn); Conn = Conn->Next; } DbgPrint("\n"); } CurrentEntry = CurrentEntry->Flink; } TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql); CurrentEntry = ConnectionEndpointListHead.Flink; while (CurrentEntry != &ConnectionEndpointListHead) { Conn = CONTAINING_RECORD(CurrentEntry, CONNECTION_ENDPOINT, ListEntry); DbgPrint("Connection @ 0x%p | Ref count: %d\n", Conn, Conn->RefCount); DbgPrint("\tPCB: "); if (Conn->SocketContext == NULL) DbgPrint("<None>\n"); else { DbgPrint("0x%p\n", Conn->SocketContext); LibTCPDumpPcb(Conn->SocketContext); } DbgPrint("\tPacket queue status: %s\n", IsListEmpty(&Conn->PacketQueue) ? "Empty" : "Not Empty"); DbgPrint("\tRequest lists: Connect: %s | Recv: %s | Send: %s | Shutdown: %s | Listen: %s\n", IsListEmpty(&Conn->ConnectRequest) ? "Empty" : "Not Empty", IsListEmpty(&Conn->ReceiveRequest) ? "Empty" : "Not Empty", IsListEmpty(&Conn->SendRequest) ? "Empty" : "Not Empty", IsListEmpty(&Conn->ShutdownRequest) ? "Empty" : "Not Empty", IsListEmpty(&Conn->ListenRequest) ? "Empty" : "Not Empty"); DbgPrint("\tSend shutdown: %s\n", Conn->SendShutdown ? "Yes" : "No"); DbgPrint("\tReceive shutdown: %s\n", Conn->ReceiveShutdown ? "Yes" : "No"); if (Conn->ReceiveShutdown) DbgPrint("\tReceive shutdown status: 0x%x\n", Conn->ReceiveShutdownStatus); DbgPrint("\tClosing: %s\n", Conn->Closing ? "Yes" : "No"); CurrentEntry = CurrentEntry->Flink; } TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql); DbgPrint("---------------------------------------------------\n"); #endif }
VOID NTAPI TiUnload( PDRIVER_OBJECT DriverObject) /* * FUNCTION: Unloads the driver * ARGUMENTS: * DriverObject = Pointer to driver object created by the system */ { #if DBG KIRQL OldIrql; TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); if (!IsListEmpty(&AddressFileListHead)) { TI_DbgPrint(MIN_TRACE, ("[TCPIP, TiUnload] Called. Open address file objects exists.\n")); } TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); #endif /* Cancel timer */ KeCancelTimer(&IPTimer); /* Unregister loopback adapter */ LoopUnregisterAdapter(NULL); /* Unregister protocol with NDIS */ LANUnregisterProtocol(); /* Shutdown transport level protocol subsystems */ TCPShutdown(); UDPShutdown(); RawIPShutdown(); ICMPShutdown(); /* Shutdown network level protocol subsystem */ IPShutdown(); /* Free NDIS buffer descriptors */ if (GlobalBufferPool) NdisFreeBufferPool(GlobalBufferPool); /* Free NDIS packet descriptors */ if (GlobalPacketPool) NdisFreePacketPool(GlobalPacketPool); /* Release all device objects */ if (TCPDeviceObject) IoDeleteDevice(TCPDeviceObject); if (UDPDeviceObject) IoDeleteDevice(UDPDeviceObject); if (RawIPDeviceObject) IoDeleteDevice(RawIPDeviceObject); if (IPDeviceObject) { ChewShutdown(); IoDeleteDevice(IPDeviceObject); } if (EntityList) ExFreePoolWithTag(EntityList, TDI_ENTITY_TAG); TI_DbgPrint(MAX_TRACE, ("[TCPIP, TiUnload] Leaving.\n")); }
NTSTATUS NTAPI TiDispatch( PDEVICE_OBJECT DeviceObject, PIRP Irp) /* * FUNCTION: Dispatch routine for IRP_MJ_DEVICE_CONTROL requests * ARGUMENTS: * DeviceObject = Pointer to a device object for this driver * Irp = Pointer to a I/O request packet * RETURNS: * Status of the operation */ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; IrpSp = IoGetCurrentIrpStackLocation(Irp); TI_DbgPrint(DEBUG_IRP, ("[TCPIP, TiDispatch] Called. IRP is at (0x%X).\n", Irp)); Irp->IoStatus.Information = 0; #if 0 Status = TdiMapUserRequest(DeviceObject, Irp, IrpSp); if (NT_SUCCESS(Status)) { TiDispatchInternal(DeviceObject, Irp); Status = STATUS_PENDING; } else { #else if (TRUE) { #endif /* See if this request is TCP/IP specific */ switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_TCP_QUERY_INFORMATION_EX: TI_DbgPrint(MIN_TRACE, ("TCP_QUERY_INFORMATION_EX\n")); Status = DispTdiQueryInformationEx(Irp, IrpSp); break; case IOCTL_TCP_SET_INFORMATION_EX: TI_DbgPrint(MIN_TRACE, ("TCP_SET_INFORMATION_EX\n")); Status = DispTdiSetInformationEx(Irp, IrpSp); break; case IOCTL_SET_IP_ADDRESS: TI_DbgPrint(MIN_TRACE, ("SET_IP_ADDRESS\n")); Status = DispTdiSetIPAddress(Irp, IrpSp); break; case IOCTL_DELETE_IP_ADDRESS: TI_DbgPrint(MIN_TRACE, ("DELETE_IP_ADDRESS\n")); Status = DispTdiDeleteIPAddress(Irp, IrpSp); break; case IOCTL_QUERY_IP_HW_ADDRESS: TI_DbgPrint(MIN_TRACE, ("QUERY_IP_HW_ADDRESS\n")); Status = DispTdiQueryIpHwAddress(DeviceObject, Irp, IrpSp); break; default: TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n", IrpSp->Parameters.DeviceIoControl.IoControlCode)); Status = STATUS_NOT_IMPLEMENTED; break; } } TI_DbgPrint(DEBUG_IRP, ("[TCPIP, TiDispatch] Leaving. Status = (0x%X).\n", Status)); return IRPFinish( Irp, Status ); } VOID NTAPI TiUnload( PDRIVER_OBJECT DriverObject) /* * FUNCTION: Unloads the driver * ARGUMENTS: * DriverObject = Pointer to driver object created by the system */ { #if DBG KIRQL OldIrql; TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); if (!IsListEmpty(&AddressFileListHead)) { TI_DbgPrint(MIN_TRACE, ("[TCPIP, TiUnload] Called. Open address file objects exists.\n")); } TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); #endif /* Cancel timer */ KeCancelTimer(&IPTimer); /* Unregister loopback adapter */ LoopUnregisterAdapter(NULL); /* Unregister protocol with NDIS */ LANUnregisterProtocol(); /* Shutdown transport level protocol subsystems */ TCPShutdown(); UDPShutdown(); RawIPShutdown(); ICMPShutdown(); /* Shutdown network level protocol subsystem */ IPShutdown(); /* Free NDIS buffer descriptors */ if (GlobalBufferPool) NdisFreeBufferPool(GlobalBufferPool); /* Free NDIS packet descriptors */ if (GlobalPacketPool) NdisFreePacketPool(GlobalPacketPool); /* Release all device objects */ if (TCPDeviceObject) IoDeleteDevice(TCPDeviceObject); if (UDPDeviceObject) IoDeleteDevice(UDPDeviceObject); if (RawIPDeviceObject) IoDeleteDevice(RawIPDeviceObject); if (IPDeviceObject) { ChewShutdown(); IoDeleteDevice(IPDeviceObject); } if (EntityList) ExFreePoolWithTag(EntityList, TDI_ENTITY_TAG); TI_DbgPrint(MAX_TRACE, ("[TCPIP, TiUnload] Leaving.\n")); }
/* * FUNCTION: Searches through address file entries to find next match * ARGUMENTS: * SearchContext = Pointer to search context * RETURNS: * Pointer to referenced address file, NULL if none was found */ PADDRESS_FILE AddrSearchNext( PAF_SEARCH SearchContext) { PLIST_ENTRY CurrentEntry; PIP_ADDRESS IPAddress; KIRQL OldIrql; PADDRESS_FILE Current = NULL; BOOLEAN Found = FALSE; PADDRESS_FILE StartingAddrFile; TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql); if (SearchContext->Next == &AddressFileListHead) { TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); return NULL; } /* Save this pointer so we can dereference it later */ StartingAddrFile = CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry); CurrentEntry = SearchContext->Next; while (CurrentEntry != &AddressFileListHead) { Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry); IPAddress = &Current->Address; TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n", WN2H(Current->Port), Current->Protocol, A2S(IPAddress), WN2H(SearchContext->Port), SearchContext->Protocol, A2S(SearchContext->Address))); /* See if this address matches the search criteria */ if ((Current->Port == SearchContext->Port) && (Current->Protocol == SearchContext->Protocol) && (AddrReceiveMatch(IPAddress, SearchContext->Address))) { /* We've found a match */ Found = TRUE; break; } CurrentEntry = CurrentEntry->Flink; } if (Found) { SearchContext->Next = CurrentEntry->Flink; if (SearchContext->Next != &AddressFileListHead) { /* Reference the next address file to prevent the link from disappearing behind our back */ ReferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry)); } /* Reference the returned address file before dereferencing the starting * address file because it may be that Current == StartingAddrFile */ ReferenceObject(Current); } else Current = NULL; DereferenceObject(StartingAddrFile); TcpipReleaseSpinLock(&AddressFileListLock, OldIrql); return Current; }
PNEIGHBOR_CACHE_ENTRY RouterGetRoute(PIP_ADDRESS Destination) /* * FUNCTION: Finds a router to use to get to Destination * ARGUMENTS: * Destination = Pointer to destination address (NULL means don't care) * RETURNS: * Pointer to NCE for router, NULL if none was found * NOTES: * If found the NCE is referenced */ { KIRQL OldIrql; PLIST_ENTRY CurrentEntry; PLIST_ENTRY NextEntry; PFIB_ENTRY Current; UCHAR State, BestState = 0; UINT Length, BestLength = 0, MaskLength; PNEIGHBOR_CACHE_ENTRY NCE, BestNCE = NULL; TI_DbgPrint(DEBUG_ROUTER, ("Called. Destination (0x%X)\n", Destination)); TI_DbgPrint(DEBUG_ROUTER, ("Destination (%s)\n", A2S(Destination))); TcpipAcquireSpinLock(&FIBLock, &OldIrql); CurrentEntry = FIBListHead.Flink; while (CurrentEntry != &FIBListHead) { NextEntry = CurrentEntry->Flink; Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); NCE = Current->Router; State = NCE->State; Length = CommonPrefixLength(Destination, &Current->NetworkAddress); MaskLength = AddrCountPrefixBits(&Current->Netmask); TI_DbgPrint(DEBUG_ROUTER,("This-Route: %s (Sharing %d bits)\n", A2S(&NCE->Address), Length)); if(Length >= MaskLength && (Length > BestLength || !BestNCE) && (!(State & NUD_STALE) || !BestNCE)) { /* This seems to be a better router */ BestNCE = NCE; BestLength = Length; BestState = State; TI_DbgPrint(DEBUG_ROUTER,("Route selected\n")); } CurrentEntry = NextEntry; } TcpipReleaseSpinLock(&FIBLock, OldIrql); if( BestNCE ) { TI_DbgPrint(DEBUG_ROUTER,("Routing to %s\n", A2S(&BestNCE->Address))); } else { TI_DbgPrint(DEBUG_ROUTER,("Packet won't be routed\n")); } return BestNCE; }