/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS TCP/IP protocol driver * FILE: network/ip.c * PURPOSE: Internet Protocol module * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) * REVISIONS: * CSH 01/08-2000 Created */ #include "precomp.h" #define __LWIP_INET_H__ #include "lwip/netifapi.h" LIST_ENTRY InterfaceListHead; KSPIN_LOCK InterfaceListLock; LIST_ENTRY NetTableListHead; KSPIN_LOCK NetTableListLock; BOOLEAN IPInitialized = FALSE; BOOLEAN IpWorkItemQueued = FALSE; /* Work around calling timer at Dpc level */ IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE]; ULONG IpTimerExpirations; VOID TCPRegisterInterface(PIP_INTERFACE IF); VOID TCPUnregisterInterface(PIP_INTERFACE IF); VOID DeinitializePacket( PVOID Object) /* * FUNCTION: Frees buffers attached to the packet * ARGUMENTS: * Object = Pointer to an IP packet structure */ { PIP_PACKET IPPacket = Object; TI_DbgPrint(MAX_TRACE, ("Freeing object: 0x%p\n", Object)); /* Detect double free */ ASSERT(IPPacket->Type != 0xFF); IPPacket->Type = 0xFF; /* Check if there's a packet to free */ if (IPPacket->NdisPacket != NULL) { if (IPPacket->ReturnPacket) { /* Return the packet to the miniport driver */ TI_DbgPrint(MAX_TRACE, ("Returning packet 0x%p\n", IPPacket->NdisPacket)); NdisReturnPackets(&IPPacket->NdisPacket, 1); } else { /* Free it the conventional way */ TI_DbgPrint(MAX_TRACE, ("Freeing packet 0x%p\n", IPPacket->NdisPacket)); FreeNdisPacket(IPPacket->NdisPacket); } } /* Check if we have a pool-allocated header */ if (!IPPacket->MappedHeader && IPPacket->Header) { /* Free it */ TI_DbgPrint(MAX_TRACE, ("Freeing header: 0x%p\n", IPPacket->Header)); ExFreePoolWithTag(IPPacket->Header, PACKET_BUFFER_TAG); } } VOID FreeIF( PVOID Object) /* * FUNCTION: Frees an interface object * ARGUMENTS: * Object = Pointer to an interface structure */ { ExFreePoolWithTag(Object, IP_INTERFACE_TAG); } PIP_PACKET IPInitializePacket( PIP_PACKET IPPacket, ULONG Type) /* * FUNCTION: Creates an IP packet object * ARGUMENTS: * Type = Type of IP packet * RETURNS: * Pointer to the created IP packet. NULL if there was not enough free resources. */ { RtlZeroMemory(IPPacket, sizeof(IP_PACKET)); IPPacket->Free = DeinitializePacket; IPPacket->Type = Type; return IPPacket; } VOID NTAPI IPTimeoutDpcFn(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2) /* * FUNCTION: Timeout DPC * ARGUMENTS: * Dpc = Pointer to our DPC object * DeferredContext = Pointer to context information (unused) * SystemArgument1 = Unused * SystemArgument2 = Unused * NOTES: * This routine is dispatched once in a while to do maintenance jobs */ { IpTimerExpirations++; if ((IpTimerExpirations % 10) == 0) { LogActiveObjects(); } /* Check if datagram fragments have taken too long to assemble */ IPDatagramReassemblyTimeout(); /* Clean possible outdated cached neighbor addresses */ NBTimeout(); } VOID IPDispatchProtocol( PIP_INTERFACE Interface, PIP_PACKET IPPacket) /* * FUNCTION: IP protocol dispatcher * ARGUMENTS: * NTE = Pointer to net table entry which the packet was received on * IPPacket = Pointer to an IP packet that was received * NOTES: * This routine examines the IP header and passes the packet on to the * right upper level protocol receive handler */ { UINT Protocol; IP_ADDRESS SrcAddress; switch (IPPacket->Type) { case IP_ADDRESS_V4: Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol; AddrInitIPv4(&SrcAddress, ((PIPv4_HEADER)(IPPacket->Header))->SrcAddr); break; case IP_ADDRESS_V6: /* FIXME: IPv6 adresses not supported */ TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n")); return; default: TI_DbgPrint(MIN_TRACE, ("Unrecognized datagram discarded.\n")); return; } NBResetNeighborTimeout(&SrcAddress); if (Protocol < IP_PROTOCOL_TABLE_SIZE) { /* Call the appropriate protocol handler */ (*ProtocolTable[Protocol])(Interface, IPPacket); } } PIP_INTERFACE IPCreateInterface( PLLIP_BIND_INFO BindInfo) /* * FUNCTION: Creates an IP interface * ARGUMENTS: * BindInfo = Pointer to link layer to IP binding information * RETURNS: * Pointer to IP_INTERFACE structure, NULL if there was * not enough free resources */ { PIP_INTERFACE IF; TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo)); #if DBG if (BindInfo->Address) { PUCHAR A = BindInfo->Address; TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n", A[0], A[1], A[2], A[3], A[4], A[5])); } #endif IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(IP_INTERFACE), IP_INTERFACE_TAG); if (!IF) { TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); return NULL; } RtlZeroMemory(IF, sizeof(IP_INTERFACE)); IF->Free = FreeIF; IF->Context = BindInfo->Context; IF->HeaderSize = BindInfo->HeaderSize; IF->MinFrameSize = BindInfo->MinFrameSize; IF->Address = BindInfo->Address; IF->AddressLength = BindInfo->AddressLength; IF->Transmit = BindInfo->Transmit; IF->Unicast.Type = IP_ADDRESS_V4; IF->PointToPoint.Type = IP_ADDRESS_V4; IF->Netmask.Type = IP_ADDRESS_V4; IF->Broadcast.Type = IP_ADDRESS_V4; TcpipInitializeSpinLock(&IF->Lock); IF->TCPContext = ExAllocatePool ( NonPagedPool, sizeof(struct netif)); if (!IF->TCPContext) { ExFreePoolWithTag(IF, IP_INTERFACE_TAG); return NULL; } TCPRegisterInterface(IF); #ifdef __NTDRIVER__ InsertTDIInterfaceEntity( IF ); #endif return IF; } VOID IPDestroyInterface( PIP_INTERFACE IF) /* * FUNCTION: Destroys an IP interface * ARGUMENTS: * IF = Pointer to interface to destroy */ { TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); #ifdef __NTDRIVER__ RemoveTDIInterfaceEntity( IF ); #endif TCPUnregisterInterface(IF); ExFreePool(IF->TCPContext); ExFreePoolWithTag(IF, IP_INTERFACE_TAG); } VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) { PNEIGHBOR_CACHE_ENTRY NCE; IP_ADDRESS NetworkAddress; /* Add a permanent neighbor for this NTE */ NCE = NBAddNeighbor(IF, &IF->Unicast, IF->Address, IF->AddressLength, NUD_PERMANENT, 0); if (!NCE) { TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n")); return; } AddrWidenAddress( &NetworkAddress, &IF->Unicast, &IF->Netmask ); if (!RouterAddRoute(&NetworkAddress, &IF->Netmask, NCE, 1)) { TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n")); } /* Send a gratuitous ARP packet to update the route caches of * other computers */ if (IF != Loopback) ARPTransmit(NULL, NULL, IF); TCPUpdateInterfaceIPInformation(IF); } BOOLEAN IPRegisterInterface( PIP_INTERFACE IF) /* * FUNCTION: Registers an IP interface with IP layer * ARGUMENTS: * IF = Pointer to interface to register * RETURNS; * TRUE if interface was successfully registered, FALSE if not */ { KIRQL OldIrql; UINT ChosenIndex = 0; BOOLEAN IndexHasBeenChosen; IF_LIST_ITER(Interface); TI_DbgPrint(MID_TRACE, ("Called. IF (0x%X).\n", IF)); TcpipAcquireSpinLock(&IF->Lock, &OldIrql); /* Choose an index */ do { IndexHasBeenChosen = TRUE; ForEachInterface(Interface) { if( Interface->Index == ChosenIndex ) { ChosenIndex++; IndexHasBeenChosen = FALSE; } } EndFor(Interface); } while( !IndexHasBeenChosen ); IF->Index = ChosenIndex; /* Add interface to the global interface list */ TcpipInterlockedInsertTailList(&InterfaceListHead, &IF->ListEntry, &InterfaceListLock); TcpipReleaseSpinLock(&IF->Lock, OldIrql); return TRUE; } VOID IPRemoveInterfaceRoute( PIP_INTERFACE IF ) { PNEIGHBOR_CACHE_ENTRY NCE; IP_ADDRESS GeneralRoute; NCE = NBLocateNeighbor(&IF->Unicast, IF); if (NCE) { TI_DbgPrint(DEBUG_IP,("Removing interface Addr %s\n", A2S(&IF->Unicast))); TI_DbgPrint(DEBUG_IP,(" Mask %s\n", A2S(&IF->Netmask))); AddrWidenAddress(&GeneralRoute,&IF->Unicast,&IF->Netmask); RouterRemoveRoute(&GeneralRoute, &IF->Unicast); NBRemoveNeighbor(NCE); } } VOID IPUnregisterInterface( PIP_INTERFACE IF) /* * FUNCTION: Unregisters an IP interface with IP layer * ARGUMENTS: * IF = Pointer to interface to unregister */ { KIRQL OldIrql3; TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); IPRemoveInterfaceRoute( IF ); TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql3); RemoveEntryList(&IF->ListEntry); TcpipReleaseSpinLock(&InterfaceListLock, OldIrql3); } VOID DefaultProtocolHandler( PIP_INTERFACE Interface, PIP_PACKET IPPacket) /* * FUNCTION: Default handler for Internet protocols * ARGUMENTS: * NTE = Pointer to net table entry which the packet was received on * IPPacket = Pointer to an IP packet that was received */ { TI_DbgPrint(MID_TRACE, ("[IF %x] Packet of unknown Internet protocol " "discarded.\n", Interface)); Interface->Stats.InDiscardedUnknownProto++; } VOID IPRegisterProtocol( UINT ProtocolNumber, IP_PROTOCOL_HANDLER Handler) /* * FUNCTION: Registers a handler for an IP protocol number * ARGUMENTS: * ProtocolNumber = Internet Protocol number for which to register handler * Handler = Pointer to handler to be called when a packet is received * NOTES: * To unregister a protocol handler, call this function with Handler = NULL */ { if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE) { TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber)); return; } ProtocolTable[ProtocolNumber] = Handler ? Handler : DefaultProtocolHandler; } NTSTATUS IPStartup(PUNICODE_STRING RegistryPath) /* * FUNCTION: Initializes the IP subsystem * ARGUMENTS: * RegistryPath = Our registry node for configuration parameters * RETURNS: * Status of operation */ { UINT i; TI_DbgPrint(MAX_TRACE, ("Called.\n")); /* Initialize lookaside lists */ ExInitializeNPagedLookasideList( &IPDRList, /* Lookaside list */ NULL, /* Allocate routine */ NULL, /* Free routine */ 0, /* Flags */ sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */ DATAGRAM_REASSEMBLY_TAG, /* Tag */ 0); /* Depth */ ExInitializeNPagedLookasideList( &IPFragmentList, /* Lookaside list */ NULL, /* Allocate routine */ NULL, /* Free routine */ 0, /* Flags */ sizeof(IP_FRAGMENT), /* Size of each entry */ DATAGRAM_FRAGMENT_TAG, /* Tag */ 0); /* Depth */ ExInitializeNPagedLookasideList( &IPHoleList, /* Lookaside list */ NULL, /* Allocate routine */ NULL, /* Free routine */ 0, /* Flags */ sizeof(IPDATAGRAM_HOLE), /* Size of each entry */ DATAGRAM_HOLE_TAG, /* Tag */ 0); /* Depth */ /* Start routing subsystem */ RouterStartup(); /* Start neighbor cache subsystem */ NBStartup(); /* Fill the protocol dispatch table with pointers to the default protocol handler */ for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++) IPRegisterProtocol(i, DefaultProtocolHandler); /* Initialize NTE list and protecting lock */ InitializeListHead(&NetTableListHead); TcpipInitializeSpinLock(&NetTableListLock); /* Initialize reassembly list and protecting lock */ InitializeListHead(&ReassemblyListHead); TcpipInitializeSpinLock(&ReassemblyListLock); IPInitialized = TRUE; return STATUS_SUCCESS; } NTSTATUS IPShutdown( VOID) /* * FUNCTION: Shuts down the IP subsystem * RETURNS: * Status of operation */ { TI_DbgPrint(MAX_TRACE, ("Called.\n")); if (!IPInitialized) return STATUS_SUCCESS; /* Shutdown neighbor cache subsystem */ NBShutdown(); /* Shutdown routing subsystem */ RouterShutdown(); IPFreeReassemblyList(); /* Destroy lookaside lists */ ExDeleteNPagedLookasideList(&IPHoleList); ExDeleteNPagedLookasideList(&IPDRList); ExDeleteNPagedLookasideList(&IPFragmentList); IPInitialized = FALSE; return STATUS_SUCCESS; } /* EOF */