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); }
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; }
BOOLEAN AddrIsBroadcastMatch( PIP_ADDRESS UnicastAddress, PIP_ADDRESS BroadcastAddress ) { IF_LIST_ITER(IF); ForEachInterface(IF) { if ((AddrIsUnspecified(UnicastAddress) || AddrIsEqual(&IF->Unicast, UnicastAddress)) && (AddrIsEqual(&IF->Broadcast, BroadcastAddress))) return TRUE; } EndFor(IF); return FALSE; }
BOOLEAN AddrReceiveMatch( PIP_ADDRESS LocalAddress, PIP_ADDRESS RemoteAddress) { if (AddrIsEqual(LocalAddress, RemoteAddress)) { /* Unicast address match */ return TRUE; } if (AddrIsBroadcastMatch(LocalAddress, RemoteAddress)) { /* Broadcast address match */ return TRUE; } if (AddrIsUnspecified(LocalAddress)) { /* Local address unspecified */ return TRUE; } if (AddrIsUnspecified(RemoteAddress)) { /* Remote address unspecified */ return TRUE; } return FALSE; }
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); }
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; }
PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor( PIP_INTERFACE Interface, PIP_ADDRESS Address, BOOLEAN NoTimeout) /* * FUNCTION: Tries to find a neighbor and if unsuccesful, creates a new NCE * ARGUMENTS: * Interface = Pointer to interface to use (in case NCE is not found) * Address = Pointer to IP address * RETURNS: * Pointer to NCE, NULL if there is not enough free resources * NOTES: * The NCE is referenced if found or created. The caller is * responsible for dereferencing it again after use */ { PNEIGHBOR_CACHE_ENTRY NCE; TI_DbgPrint(DEBUG_NCACHE, ("Called. Interface (0x%X) Address (0x%X).\n", Interface, Address)); NCE = NBLocateNeighbor(Address, Interface); if (NCE == NULL) { TI_DbgPrint(MID_TRACE,("BCAST: %s\n", A2S(&Interface->Broadcast))); if( AddrIsEqual(Address, &Interface->Broadcast) || AddrIsUnspecified(Address) ) { TI_DbgPrint(MID_TRACE,("Packet targeted at broadcast addr\n")); NCE = NBAddNeighbor(Interface, Address, NULL, Interface->AddressLength, NUD_PERMANENT, 0); } else { NCE = NBAddNeighbor(Interface, Address, NULL, Interface->AddressLength, NUD_INCOMPLETE, NoTimeout ? 0 : ARP_INCOMPLETE_TIMEOUT); if (!NCE) return NULL; NBSendSolicit(NCE); } } return 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; }
VOID ARPReceive( PVOID Context, PIP_PACKET Packet) /* * FUNCTION: Receives an ARP packet * ARGUMENTS: * Context = Pointer to context information (IP_INTERFACE) * Packet = Pointer to packet */ { PARP_HEADER Header; IP_ADDRESS SrcAddress; IP_ADDRESS DstAddress; PCHAR SenderHWAddress, SenderProtoAddress, TargetProtoAddress; PNEIGHBOR_CACHE_ENTRY NCE; PNDIS_PACKET NdisPacket; PIP_INTERFACE Interface = (PIP_INTERFACE)Context; ULONG BytesCopied, DataSize; PCHAR DataBuffer; PAGED_CODE(); TI_DbgPrint(DEBUG_ARP, ("Called.\n")); Packet->Header = ExAllocatePoolWithTag(PagedPool, sizeof(ARP_HEADER), PACKET_BUFFER_TAG); if (!Packet->Header) { TI_DbgPrint(DEBUG_ARP, ("Unable to allocate header buffer\n")); Packet->Free(Packet); return; } Packet->MappedHeader = FALSE; BytesCopied = CopyPacketToBuffer((PCHAR)Packet->Header, Packet->NdisPacket, Packet->Position, sizeof(ARP_HEADER)); if (BytesCopied != sizeof(ARP_HEADER)) { TI_DbgPrint(DEBUG_ARP, ("Unable to copy in header buffer\n")); Packet->Free(Packet); return; } Header = (PARP_HEADER)Packet->Header; /* FIXME: Ethernet only */ if (WN2H(Header->HWType) != 1) { TI_DbgPrint(DEBUG_ARP, ("Unknown ARP hardware type (0x%X).\n", WN2H(Header->HWType))); Packet->Free(Packet); return; } /* Check protocol type */ if (Header->ProtoType != ETYPE_IPv4) { TI_DbgPrint(DEBUG_ARP, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header->ProtoType))); Packet->Free(Packet); return; } DataSize = (2 * Header->HWAddrLen) + (2 * Header->ProtoAddrLen); DataBuffer = ExAllocatePool(PagedPool, DataSize); if (!DataBuffer) { TI_DbgPrint(DEBUG_ARP, ("Unable to allocate data buffer\n")); Packet->Free(Packet); return; } BytesCopied = CopyPacketToBuffer(DataBuffer, Packet->NdisPacket, Packet->Position + sizeof(ARP_HEADER), DataSize); if (BytesCopied != DataSize) { TI_DbgPrint(DEBUG_ARP, ("Unable to copy in data buffer\n")); ExFreePool(DataBuffer); Packet->Free(Packet); return; } SenderHWAddress = (PVOID)(DataBuffer); SenderProtoAddress = (PVOID)(SenderHWAddress + Header->HWAddrLen); TargetProtoAddress = (PVOID)(SenderProtoAddress + Header->ProtoAddrLen + Header->HWAddrLen); AddrInitIPv4(&DstAddress, *((PULONG)TargetProtoAddress)); if (!AddrIsEqual(&DstAddress, &Interface->Unicast)) { ExFreePool(DataBuffer); Packet->Free(Packet); return; } AddrInitIPv4(&SrcAddress, *((PULONG)SenderProtoAddress)); /* Check if we know the sender */ NCE = NBLocateNeighbor(&SrcAddress, Interface); if (NCE) { /* We know the sender. Update the hardware address and state in our neighbor address cache */ NBUpdateNeighbor(NCE, SenderHWAddress, 0); } else { /* The packet had our protocol address as target. The sender may want to communicate with us soon, so add his address to our address cache */ NBAddNeighbor(Interface, &SrcAddress, SenderHWAddress, Header->HWAddrLen, 0, ARP_COMPLETE_TIMEOUT); } if (Header->Opcode != ARP_OPCODE_REQUEST) { ExFreePool(DataBuffer); Packet->Free(Packet); return; } /* This is a request for our address. Swap the addresses and send an ARP reply back to the sender */ NdisPacket = PrepareARPPacket( Interface, Header->HWType, /* Hardware type */ Header->ProtoType, /* Protocol type */ (UCHAR)Interface->AddressLength, /* Hardware address length */ (UCHAR)Header->ProtoAddrLen, /* Protocol address length */ Interface->Address, /* Sender's (local) hardware address */ &Interface->Unicast.Address.IPv4Address,/* Sender's (local) protocol address */ SenderHWAddress, /* Target's (remote) hardware address */ SenderProtoAddress, /* Target's (remote) protocol address */ ARP_OPCODE_REPLY); /* ARP reply */ if (NdisPacket) { PC(NdisPacket)->DLComplete = ARPTransmitComplete; (*Interface->Transmit)(Interface->Context, NdisPacket, 0, SenderHWAddress, LAN_PROTO_ARP); } ExFreePool(DataBuffer); Packet->Free(Packet); }
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; }