diff --git a/reactos/Makefile b/reactos/Makefile index 394f718ae47..efaaa56cd78 100644 --- a/reactos/Makefile +++ b/reactos/Makefile @@ -34,11 +34,16 @@ LOADERS = dos # # Select the device drivers and filesystems you want # -DEVICE_DRIVERS = blue ide keyboard null parallel serial vidport floppy -# DEVICE_DRIVERS = beep event floppy ide_test mouse sound test test1 -FS_DRIVERS = vfat minix +DEVICE_DRIVERS = vga blue ide keyboard null parallel serial vidport +# DEVICE_DRIVERS = beep event floppy ide_test mouse sound test test1 + +FS_DRIVERS = vfat # FS_DRIVERS = minix ext2 template -KERNEL_SERVICES = $(DEVICE_DRIVERS) $(FS_DRIVERS) + +# ndis tdi tcpip tditest +NET_DRIVERS = ndis tcpip tditest + +KERNEL_SERVICES = $(DEVICE_DRIVERS) $(FS_DRIVERS) $(NET_DRIVERS) APPS = args hello shell test cat bench apc shm lpc thread event file gditest \ pteb consume @@ -54,7 +59,7 @@ clean: buildno_clean $(COMPONENTS:%=%_clean) $(DLLS:%=%_clean) $(LOADERS:%=%_cle .PHONY: clean -install_floppy: make_floppy_dirs autoexec_floppy $(COMPONENTS:%=%_floppy) \ +floppy: make_floppy_dirs autoexec_floppy $(COMPONENTS:%=%_floppy) \ $(DLLS:%=%_floppy) $(LOADERS:%=%_floppy) \ $(KERNEL_SERVICES:%=%_floppy) $(SUBSYS:%=%_floppy) \ $(APPS:%=%_floppy) @@ -155,6 +160,15 @@ $(FS_DRIVERS:%=%_dist): %_dist: .PHONY: $(FS_DRIVERS) $(FS_DRIVERS:%=%_clean) $(FS_DRIVERS:%=%_floppy) \ $(FS_DRIVERS:%=%_dist) + +$(NET_DRIVERS): %: + make -C services/net/$* + +$(NET_DRIVERS:%=%_clean): %_clean: + make -C services/net/$* clean + +.PHONY: $(NET_DRIVERS) $(NET_DRIVERS:%=%_clean) + # # Kernel loaders diff --git a/reactos/drivers/net/tcpip/DIRS b/reactos/drivers/net/tcpip/DIRS index a49d00ed81c..de50bbd357f 100644 --- a/reactos/drivers/net/tcpip/DIRS +++ b/reactos/drivers/net/tcpip/DIRS @@ -1,5 +1,5 @@ -DIRS= datalink \ - network \ - transport \ - tcpip - +DIRS= datalink \ + network \ + transport \ + tcpip + diff --git a/reactos/drivers/net/tcpip/datalink/Makefile b/reactos/drivers/net/tcpip/datalink/Makefile index 9c985f57bc6..58189757d61 100644 --- a/reactos/drivers/net/tcpip/datalink/Makefile +++ b/reactos/drivers/net/tcpip/datalink/Makefile @@ -1,7 +1,7 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/reactos/drivers/net/tcpip/datalink/SOURCES b/reactos/drivers/net/tcpip/datalink/SOURCES index b941923ac79..25571acb83a 100644 --- a/reactos/drivers/net/tcpip/datalink/SOURCES +++ b/reactos/drivers/net/tcpip/datalink/SOURCES @@ -1,13 +1,13 @@ -TARGETNAME=datalink -TARGETPATH=..\objects -TARGETTYPE=LIBRARY - -TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ - $(DDK_LIB_PATH)\ndis.lib - -INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net -SOURCES= arp.c \ - lan.c \ - loopback.c - -MSC_WARNING_LEVEL=/W3 /WX +TARGETNAME=datalink +TARGETPATH=..\objects +TARGETTYPE=LIBRARY + +TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ + $(DDK_LIB_PATH)\ndis.lib + +INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net +SOURCES= arp.c \ + lan.c \ + loopback.c + +MSC_WARNING_LEVEL=/W3 /WX diff --git a/reactos/drivers/net/tcpip/datalink/arp.c b/reactos/drivers/net/tcpip/datalink/arp.c index 83d249096e9..6121918860d 100644 --- a/reactos/drivers/net/tcpip/datalink/arp.c +++ b/reactos/drivers/net/tcpip/datalink/arp.c @@ -1,277 +1,277 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: datalink/arp.c - * PURPOSE: Address Resolution Protocol routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include - - -PNDIS_PACKET PrepareARPPacket( - USHORT HardwareType, - USHORT ProtocolType, - UCHAR LinkAddressLength, - UCHAR ProtoAddressLength, - PVOID SenderLinkAddress, - PVOID SenderProtoAddress, - PVOID TargetLinkAddress, - PVOID TargetProtoAddress, - USHORT Opcode) -/* - * FUNCTION: Prepares an ARP packet - * ARGUMENTS: - * HardwareType = Hardware type (in network byte order) - * ProtocolType = Protocol type (in network byte order) - * LinkAddressLength = Length of link address fields - * ProtoAddressLength = Length of protocol address fields - * SenderLinkAddress = Sender's link address - * SenderProtoAddress = Sender's protocol address - * TargetLinkAddress = Target's link address (NULL if don't care) - * TargetProtoAddress = Target's protocol address - * Opcode = ARP opcode (in network byte order) - * RETURNS: - * Pointer to NDIS packet, NULL if there is not enough free resources - */ -{ - PNDIS_PACKET NdisPacket; - PNDIS_BUFFER NdisBuffer; - NDIS_STATUS NdisStatus; - PARP_HEADER Header; - PVOID DataBuffer; - ULONG Size; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - /* Prepare ARP packet */ - Size = MaxLLHeaderSize + sizeof(ARP_HEADER) + - 2 * LinkAddressLength + /* Hardware address length */ - 2 * ProtoAddressLength; /* Protocol address length */ - Size = MAX(Size, MinLLFrameSize); - - DataBuffer = ExAllocatePool(NonPagedPool, Size); - if (!DataBuffer) - return NULL; - - /* Allocate NDIS packet */ - NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - ExFreePool(DataBuffer); - return NULL; - } - - /* Allocate NDIS buffer for maximum link level header and ARP packet */ - NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool, - DataBuffer, Size); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - NdisFreePacket(NdisPacket); - ExFreePool(DataBuffer); - return NULL; - } - - /* Link NDIS buffer into packet */ - NdisChainBufferAtFront(NdisPacket, NdisBuffer); - RtlZeroMemory(DataBuffer, Size); - Header = (PARP_HEADER)((ULONG_PTR)DataBuffer + MaxLLHeaderSize); - Header->HWType = HardwareType; - Header->ProtoType = ProtocolType; - Header->HWAddrLen = LinkAddressLength; - Header->ProtoAddrLen = ProtoAddressLength; - Header->Opcode = Opcode; /* Already swapped */ - DataBuffer = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER)); - - /* Our hardware address */ - RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength); - (ULONG_PTR)DataBuffer += LinkAddressLength; - - /* Our protocol address */ - RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength); - - if (TargetLinkAddress) { - (ULONG_PTR)DataBuffer += ProtoAddressLength; - /* Target hardware address */ - RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength); - (ULONG_PTR)DataBuffer += LinkAddressLength; - } else - /* Don't care about target hardware address */ - (ULONG_PTR)DataBuffer += (ProtoAddressLength + LinkAddressLength); - - /* Target protocol address */ - RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength); - - return NdisPacket; -} - - -VOID ARPTransmitComplete( - PVOID Context, - PNDIS_PACKET NdisPacket, - NDIS_STATUS NdisStatus) -/* - * FUNCTION: ARP request transmit completion handler - * ARGUMENTS: - * Context = Pointer to context information (IP_INTERFACE) - * Packet = Pointer to NDIS packet that was sent - * NdisStatus = NDIS status of operation - * NOTES: - * This routine is called when an ARP request has been sent - */ -{ - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - FreeNdisPacket(NdisPacket); -} - - -BOOLEAN ARPTransmit( - PIP_ADDRESS Address, - PNET_TABLE_ENTRY NTE) -/* - * FUNCTION: Creates an ARP request and transmits it on a network - * ARGUMENTS: - * Address = Pointer to IP address to resolve - * NTE = Pointer to net table entru to use for transmitting request - * RETURNS: - * TRUE if the request was successfully sent, FALSE if not - */ -{ - PIP_INTERFACE Interface; - PNDIS_PACKET NdisPacket; - UCHAR ProtoAddrLen; - USHORT ProtoType; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - Interface = NTE->Interface; - - switch (Address->Type) { - case IP_ADDRESS_V4: - ProtoType = (USHORT)ETYPE_IPv4; /* IPv4 */ - ProtoAddrLen = 4; /* Length of IPv4 address */ - break; - case IP_ADDRESS_V6: - ProtoType = (USHORT)ETYPE_IPv6; /* IPv6 */ - ProtoAddrLen = 16; /* Length of IPv6 address */ - break; - default: - /* Should not happen */ - return FALSE; - } - - NdisPacket = PrepareARPPacket( - WN2H(0x0001), /* FIXME: Ethernet only */ - ProtoType, /* Protocol type */ - (UCHAR)Interface->AddressLength, /* Hardware address length */ - (UCHAR)ProtoAddrLen, /* Protocol address length */ - Interface->Address, /* Sender's (local) hardware address */ - &NTE->Address->Address, /* Sender's (local) protocol address */ - NULL, /* Don't care */ - &Address->Address, /* Target's (remote) protocol address */ - ARP_OPCODE_REQUEST); /* ARP request */ - - PC(NdisPacket)->DLComplete = ARPTransmitComplete; - - (*Interface->Transmit)(Interface->Context, NdisPacket, - MaxLLHeaderSize, NULL, LAN_PROTO_ARP); - - return TRUE; -} - - -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; - PIP_ADDRESS Address; - PVOID SenderHWAddress; - PVOID SenderProtoAddress; - PVOID TargetProtoAddress; - PADDRESS_ENTRY ADE; - PNEIGHBOR_CACHE_ENTRY NCE; - PNDIS_PACKET NdisPacket; - PIP_INTERFACE Interface = (PIP_INTERFACE)Context; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - Header = (PARP_HEADER)Packet->Header; - - /* FIXME: Ethernet only */ - if (WN2H(Header->HWType) != 1) - return; - - /* Check protocol type */ - if (Header->ProtoType != ETYPE_IPv4) - return; - - SenderHWAddress = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER)); - SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen); - - /* Check if we have the target protocol address */ - - TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress + - Header->ProtoAddrLen + Header->HWAddrLen); - - Address = AddrBuildIPv4(*(PULONG)(TargetProtoAddress)); - ADE = IPLocateADE(Address, ADE_UNICAST); - if (!ADE) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return; - } - - /* Check if we know the sender */ - - AddrInitIPv4(Address, *(PULONG)(SenderProtoAddress)); - NCE = NBLocateNeighbor(Address); - if (NCE) { - DereferenceObject(Address); - /* We know the sender. Update the hardware address - and state in our neighbor address cache */ - NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE); - } 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 */ - NCE = NBAddNeighbor(Interface, Address, SenderHWAddress, - Header->HWAddrLen, NUD_REACHABLE); - } - if (NCE) - DereferenceObject(NCE) - - if (Header->Opcode != ARP_OPCODE_REQUEST) - return; - - /* This is a request for our address. Swap the addresses and - send an ARP reply back to the sender */ - NdisPacket = PrepareARPPacket( - 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 */ - &ADE->Address->Address, /* 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, - MaxLLHeaderSize, SenderHWAddress, LAN_PROTO_ARP); - } -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: datalink/arp.c + * PURPOSE: Address Resolution Protocol routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include + + +PNDIS_PACKET PrepareARPPacket( + USHORT HardwareType, + USHORT ProtocolType, + UCHAR LinkAddressLength, + UCHAR ProtoAddressLength, + PVOID SenderLinkAddress, + PVOID SenderProtoAddress, + PVOID TargetLinkAddress, + PVOID TargetProtoAddress, + USHORT Opcode) +/* + * FUNCTION: Prepares an ARP packet + * ARGUMENTS: + * HardwareType = Hardware type (in network byte order) + * ProtocolType = Protocol type (in network byte order) + * LinkAddressLength = Length of link address fields + * ProtoAddressLength = Length of protocol address fields + * SenderLinkAddress = Sender's link address + * SenderProtoAddress = Sender's protocol address + * TargetLinkAddress = Target's link address (NULL if don't care) + * TargetProtoAddress = Target's protocol address + * Opcode = ARP opcode (in network byte order) + * RETURNS: + * Pointer to NDIS packet, NULL if there is not enough free resources + */ +{ + PNDIS_PACKET NdisPacket; + PNDIS_BUFFER NdisBuffer; + NDIS_STATUS NdisStatus; + PARP_HEADER Header; + PVOID DataBuffer; + ULONG Size; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + /* Prepare ARP packet */ + Size = MaxLLHeaderSize + sizeof(ARP_HEADER) + + 2 * LinkAddressLength + /* Hardware address length */ + 2 * ProtoAddressLength; /* Protocol address length */ + Size = MAX(Size, MinLLFrameSize); + + DataBuffer = ExAllocatePool(NonPagedPool, Size); + if (!DataBuffer) + return NULL; + + /* Allocate NDIS packet */ + NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + ExFreePool(DataBuffer); + return NULL; + } + + /* Allocate NDIS buffer for maximum link level header and ARP packet */ + NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool, + DataBuffer, Size); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + NdisFreePacket(NdisPacket); + ExFreePool(DataBuffer); + return NULL; + } + + /* Link NDIS buffer into packet */ + NdisChainBufferAtFront(NdisPacket, NdisBuffer); + RtlZeroMemory(DataBuffer, Size); + Header = (PARP_HEADER)((ULONG_PTR)DataBuffer + MaxLLHeaderSize); + Header->HWType = HardwareType; + Header->ProtoType = ProtocolType; + Header->HWAddrLen = LinkAddressLength; + Header->ProtoAddrLen = ProtoAddressLength; + Header->Opcode = Opcode; /* Already swapped */ + DataBuffer = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER)); + + /* Our hardware address */ + RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength); + (ULONG_PTR)DataBuffer += LinkAddressLength; + + /* Our protocol address */ + RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength); + + if (TargetLinkAddress) { + (ULONG_PTR)DataBuffer += ProtoAddressLength; + /* Target hardware address */ + RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength); + (ULONG_PTR)DataBuffer += LinkAddressLength; + } else + /* Don't care about target hardware address */ + (ULONG_PTR)DataBuffer += (ProtoAddressLength + LinkAddressLength); + + /* Target protocol address */ + RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength); + + return NdisPacket; +} + + +VOID ARPTransmitComplete( + PVOID Context, + PNDIS_PACKET NdisPacket, + NDIS_STATUS NdisStatus) +/* + * FUNCTION: ARP request transmit completion handler + * ARGUMENTS: + * Context = Pointer to context information (IP_INTERFACE) + * Packet = Pointer to NDIS packet that was sent + * NdisStatus = NDIS status of operation + * NOTES: + * This routine is called when an ARP request has been sent + */ +{ + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + FreeNdisPacket(NdisPacket); +} + + +BOOLEAN ARPTransmit( + PIP_ADDRESS Address, + PNET_TABLE_ENTRY NTE) +/* + * FUNCTION: Creates an ARP request and transmits it on a network + * ARGUMENTS: + * Address = Pointer to IP address to resolve + * NTE = Pointer to net table entru to use for transmitting request + * RETURNS: + * TRUE if the request was successfully sent, FALSE if not + */ +{ + PIP_INTERFACE Interface; + PNDIS_PACKET NdisPacket; + UCHAR ProtoAddrLen; + USHORT ProtoType; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + Interface = NTE->Interface; + + switch (Address->Type) { + case IP_ADDRESS_V4: + ProtoType = (USHORT)ETYPE_IPv4; /* IPv4 */ + ProtoAddrLen = 4; /* Length of IPv4 address */ + break; + case IP_ADDRESS_V6: + ProtoType = (USHORT)ETYPE_IPv6; /* IPv6 */ + ProtoAddrLen = 16; /* Length of IPv6 address */ + break; + default: + /* Should not happen */ + return FALSE; + } + + NdisPacket = PrepareARPPacket( + WN2H(0x0001), /* FIXME: Ethernet only */ + ProtoType, /* Protocol type */ + (UCHAR)Interface->AddressLength, /* Hardware address length */ + (UCHAR)ProtoAddrLen, /* Protocol address length */ + Interface->Address, /* Sender's (local) hardware address */ + &NTE->Address->Address, /* Sender's (local) protocol address */ + NULL, /* Don't care */ + &Address->Address, /* Target's (remote) protocol address */ + ARP_OPCODE_REQUEST); /* ARP request */ + + PC(NdisPacket)->DLComplete = ARPTransmitComplete; + + (*Interface->Transmit)(Interface->Context, NdisPacket, + MaxLLHeaderSize, NULL, LAN_PROTO_ARP); + + return TRUE; +} + + +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; + PIP_ADDRESS Address; + PVOID SenderHWAddress; + PVOID SenderProtoAddress; + PVOID TargetProtoAddress; + PADDRESS_ENTRY ADE; + PNEIGHBOR_CACHE_ENTRY NCE; + PNDIS_PACKET NdisPacket; + PIP_INTERFACE Interface = (PIP_INTERFACE)Context; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + Header = (PARP_HEADER)Packet->Header; + + /* FIXME: Ethernet only */ + if (WN2H(Header->HWType) != 1) + return; + + /* Check protocol type */ + if (Header->ProtoType != ETYPE_IPv4) + return; + + SenderHWAddress = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER)); + SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen); + + /* Check if we have the target protocol address */ + + TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress + + Header->ProtoAddrLen + Header->HWAddrLen); + + Address = AddrBuildIPv4(*(PULONG)(TargetProtoAddress)); + ADE = IPLocateADE(Address, ADE_UNICAST); + if (!ADE) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return; + } + + /* Check if we know the sender */ + + AddrInitIPv4(Address, *(PULONG)(SenderProtoAddress)); + NCE = NBLocateNeighbor(Address); + if (NCE) { + DereferenceObject(Address); + /* We know the sender. Update the hardware address + and state in our neighbor address cache */ + NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE); + } 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 */ + NCE = NBAddNeighbor(Interface, Address, SenderHWAddress, + Header->HWAddrLen, NUD_REACHABLE); + } + if (NCE) + DereferenceObject(NCE) + + if (Header->Opcode != ARP_OPCODE_REQUEST) + return; + + /* This is a request for our address. Swap the addresses and + send an ARP reply back to the sender */ + NdisPacket = PrepareARPPacket( + 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 */ + &ADE->Address->Address, /* 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, + MaxLLHeaderSize, SenderHWAddress, LAN_PROTO_ARP); + } +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/datalink/lan.c b/reactos/drivers/net/tcpip/datalink/lan.c index 4476922b982..df15ca94b8b 100644 --- a/reactos/drivers/net/tcpip/datalink/lan.c +++ b/reactos/drivers/net/tcpip/datalink/lan.c @@ -1,903 +1,903 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: datalink/lan.c - * PURPOSE: Local Area Network media routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include - - -NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL; -BOOLEAN ProtocolRegistered = FALSE; -PLAN_ADAPTER Adapters = NULL; - - -NDIS_STATUS NDISCall( - PLAN_ADAPTER Adapter, - NDIS_REQUEST_TYPE Type, - NDIS_OID OID, - PVOID Buffer, - UINT Length) -/* - * FUNCTION: Send a request to NDIS - * ARGUMENTS: - * Adapter = Pointer to a LAN_ADAPTER structure - * Type = Type of request (Set or Query) - * OID = Value to be set/queried for - * Buffer = Pointer to a buffer to use - * Length = Number of bytes in Buffer - * RETURNS: - * Status of operation - */ -{ - NDIS_REQUEST Request; - NDIS_STATUS NdisStatus; - - Request.RequestType = Type; - if (Type == NdisRequestSetInformation) { - Request.DATA.SET_INFORMATION.Oid = OID; - Request.DATA.SET_INFORMATION.InformationBuffer = Buffer; - Request.DATA.SET_INFORMATION.InformationBufferLength = Length; - } else { - Request.DATA.QUERY_INFORMATION.Oid = OID; - Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer; - Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length; - } - - if (Adapter->State != LAN_STATE_RESETTING) { - NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request); - } else - NdisStatus = NDIS_STATUS_NOT_ACCEPTED; - - /* Wait for NDIS to complete the request */ - if (NdisStatus == NDIS_STATUS_PENDING) { - KeWaitForSingleObject(&Adapter->Event, UserRequest, KernelMode, FALSE, NULL); - NdisStatus = Adapter->NdisStatus; - } - - return NdisStatus; -} - - -PNDIS_PACKET AllocateTDPacket( - PLAN_ADAPTER Adapter) -/* - * FUNCTION: Allocates an NDIS packet for NdisTransferData - * ARGUMENTS: - * Adapter = Pointer to LAN_ADAPTER structure - * RETURNS: - * Pointer to NDIS packet or NULL if there was not enough free - * non-paged memory - */ -{ - NDIS_STATUS NdisStatus; - PNDIS_PACKET NdisPacket; - PNDIS_BUFFER Buffer; - PVOID Data; - - NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool); - if (NdisStatus != NDIS_STATUS_SUCCESS) - return NULL; - - Data = ExAllocatePool(NonPagedPool, Adapter->MTU); - if (!Data) { - NdisFreePacket(NdisPacket); - return NULL; - } - - NdisAllocateBuffer(&NdisStatus, &Buffer, GlobalBufferPool, Data, Adapter->MTU); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - NdisFreePacket(NdisPacket); - ExFreePool(Data); - return NULL; - } - - NdisChainBufferAtFront(NdisPacket, Buffer); - - PC(NdisPacket)->Context = NULL; /* End of list */ - - return NdisPacket; -} - - -VOID FreeTDPackets( - PLAN_ADAPTER Adapter) -/* - * FUNCTION: Frees transfer data packets - * ARGUMENTS: - * Adapter = Pointer to LAN_ADAPTER structure - */ -{ - PNDIS_PACKET NdisPacket, Next; - - /* Release transfer data packets */ - NdisPacket = Adapter->TDPackets; - while (NdisPacket) { - Next = PC(NdisPacket)->Context; - FreeNdisPacket(NdisPacket); - NdisPacket = Next; - } - Adapter->TDPackets = NULL; -} - - -VOID FreeAdapter( - PLAN_ADAPTER Adapter) -/* - * FUNCTION: Frees memory for a LAN_ADAPTER structure - * ARGUMENTS: - * Adapter = Pointer to LAN_ADAPTER structure to free - */ -{ - FreeTDPackets(Adapter); - ExFreePool(Adapter); -} - - -VOID ProtocolOpenAdapterComplete( - NDIS_HANDLE BindingContext, - NDIS_STATUS Status, - NDIS_STATUS OpenErrorStatus) -/* - * FUNCTION: Called by NDIS to complete opening of an adapter - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - * Status = Status of the operation - * OpenErrorStatus = Additional status information - */ -{ - PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - KeSetEvent(&Adapter->Event, 0, FALSE); -} - - -VOID ProtocolCloseAdapterComplete( - NDIS_HANDLE BindingContext, - NDIS_STATUS Status) -/* - * FUNCTION: Called by NDIS to complete closing an adapter - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - * Status = Status of the operation - */ -{ - PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - Adapter->NdisStatus = Status; - - KeSetEvent(&Adapter->Event, 0, FALSE); -} - - -VOID ProtocolResetComplete( - NDIS_HANDLE BindingContext, - NDIS_STATUS Status) -/* - * FUNCTION: Called by NDIS to complete resetting an adapter - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - * Status = Status of the operation - */ -{ - TI_DbgPrint(MID_TRACE, ("Called.\n")); -} - - -VOID ProtocolRequestComplete( - NDIS_HANDLE BindingContext, - PNDIS_REQUEST NdisRequest, - NDIS_STATUS Status) -/* - * FUNCTION: Called by NDIS to complete a request - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - * NdisRequest = Pointer to an object describing the request - * Status = Status of the operation - */ -{ - PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; - - /* Save status of request and signal an event */ - Adapter->NdisStatus = Status; - - KeSetEvent(&Adapter->Event, 0, FALSE); -} - - -VOID ProtocolSendComplete( - NDIS_HANDLE BindingContext, - PNDIS_PACKET Packet, - NDIS_STATUS Status) -/* - * FUNCTION: Called by NDIS to complete sending process - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - * Packet = Pointer to a packet descriptor - * Status = Status of the operation - */ -{ - PLAN_ADAPTER Adapter = BindingContext; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset); - - (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status); -} - - -VOID ProtocolTransferDataComplete( - NDIS_HANDLE BindingContext, - PNDIS_PACKET Packet, - NDIS_STATUS Status, - UINT BytesTransferred) -/* - * FUNCTION: Called by NDIS to complete reception of data - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - * Packet = Pointer to a packet descriptor - * Status = Status of the operation - * BytesTransferred = Number of bytes transferred - * NOTES: - * If the packet was successfully received, determine the protocol - * type and pass it to the correct receive handler - */ -{ - UINT PacketType; - PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; - - if (Status == NDIS_STATUS_SUCCESS) { - PNDIS_BUFFER NdisBuffer; - IP_PACKET IPPacket; - - NdisGetFirstBufferFromPacket( - Packet, &NdisBuffer, &IPPacket.Header, - &IPPacket.ContigSize, &IPPacket.TotalSize); - - /* Determine which upper layer protocol that should receive - this packet and pass it to the correct receive handler */ - PacketType = ((PETH_HEADER)IPPacket.Header)->EType; - switch (PacketType) { - case ETYPE_IPv4: - case ETYPE_IPv6: - IPReceive(Adapter->Context, &IPPacket); - break; - case ETYPE_ARP: - ARPReceive(Adapter->Context, &IPPacket); - default: - break; - } - } - - /* Release the packet descriptor */ - KeAcquireSpinLockAtDpcLevel(&Adapter->Lock); - - PC(Packet)->Context = Adapter->TDPackets; - Adapter->TDPackets = Packet; - - KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); -} - - -NDIS_STATUS ProtocolReceive( - NDIS_HANDLE BindingContext, - NDIS_HANDLE MacReceiveContext, - PVOID HeaderBuffer, - UINT HeaderBufferSize, - PVOID LookaheadBuffer, - UINT LookaheadBufferSize, - UINT PacketSize) -/* - * FUNCTION: Called by NDIS when a packet has been received on the physical link - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - * MacReceiveContext = Handle used by underlying NIC driver - * HeaderBuffer = Pointer to a buffer containing the packet header - * HeaderBufferSize = Number of bytes in HeaderBuffer - * LookaheadBuffer = Pointer to a buffer containing buffered packet data - * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for - * PacketSize = Overall size of the packet (not including header) - * RETURNS: - * Status of operation - */ -{ - USHORT EType; - UINT PacketType; - IP_PACKET IPPacket; - PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; - PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - if ((Adapter->State != LAN_STATE_STARTED) || - HeaderBufferSize < Adapter->HeaderSize) - /* Adapter is not started or the header was too small */ - return NDIS_STATUS_NOT_ACCEPTED; - - if (Adapter->Media == NdisMedium802_3) { - /* Ethernet and IEEE 802.3 frames can be destinguished by - looking at the IEEE 802.3 length field. This field is - less than or equal to 1500 for a valid IEEE 802.3 frame - and larger than 1500 is it's a valid Ether-Type value. - See RFC 1122, section 2.3.3 for more information */ - if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) - return NDIS_STATUS_NOT_ACCEPTED; - /* We use Ether-Type constants to destinguish packets */ - PacketType = EType; - } else - /* FIXME: Support other medias */ - return NDIS_STATUS_NOT_ACCEPTED; - - if (LookaheadBufferSize < PacketSize) { - NDIS_STATUS NdisStatus; - PNDIS_PACKET NdisPacket; - UINT BytesTransferred; - - /* Get transfer data packet */ - - KeAcquireSpinLockAtDpcLevel(&Adapter->Lock); - - NdisPacket = Adapter->TDPackets; - if (NdisPacket == (PNDIS_PACKET)NULL) { - /* We don't have a free packet descriptor. Drop the packet */ - KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); - return NDIS_STATUS_SUCCESS; - } - Adapter->TDPackets = PC(NdisPacket)->Context; - - KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); - - /* Get the data */ - NdisTransferData(&NdisStatus, Adapter->NdisHandle, - MacReceiveContext, 0, PacketSize, - NdisPacket, &BytesTransferred); - if (NdisStatus != NDIS_STATUS_PENDING) - ProtocolTransferDataComplete(BindingContext, - NdisPacket, NdisStatus, BytesTransferred); - - return NDIS_STATUS_SUCCESS; - } - - /* We got all the data in the lookahead buffer */ - RtlZeroMemory(&IPPacket, sizeof(IPPacket)); - IPPacket.Header = LookaheadBuffer; - IPPacket.TotalSize = PacketSize; - - switch (PacketType) { - case ETYPE_IPv4: - case ETYPE_IPv6: - IPReceive(Adapter->Context, &IPPacket); - break; - case ETYPE_ARP: - ARPReceive(Adapter->Context, &IPPacket); - break; - default: - break; - } - - return NDIS_STATUS_SUCCESS; -} - - -VOID ProtocolReceiveComplete( - NDIS_HANDLE BindingContext) -/* - * FUNCTION: Called by NDIS when we're done receiving data - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - */ -{ - TI_DbgPrint(MID_TRACE, ("Called.\n")); -} - - -VOID ProtocolStatus( - NDIS_HANDLE BindingContext, - NDIS_STATUS GenerelStatus, - PVOID StatusBuffer, - UINT StatusBufferSize) -/* - * FUNCTION: Called by NDIS when the underlying driver has changed state - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - * GenerelStatus = A generel status code - * StatusBuffer = Pointer to a buffer with medium-specific data - * StatusBufferSize = Number of bytes in StatusBuffer - */ -{ - TI_DbgPrint(MID_TRACE, ("Called.\n")); -} - - -VOID ProtocolStatusComplete( - NDIS_HANDLE NdisBindingContext) -/* - * FUNCTION: Called by NDIS when a status-change has occurred - * ARGUMENTS: - * BindingContext = Pointer to a device context (LAN_ADAPTER) - */ -{ - TI_DbgPrint(MID_TRACE, ("Called.\n")); -} - - -VOID LANTransmit( - PVOID Context, - PNDIS_PACKET NdisPacket, - UINT Offset, - PVOID LinkAddress, - USHORT Type) -/* - * FUNCTION: Transmits a packet - * ARGUMENTS: - * Context = Pointer to context information (LAN_ADAPTER) - * NdisPacket = Pointer to NDIS packet to send - * Offset = Offset in packet where data starts - * LinkAddress = Pointer to link address of destination (NULL = broadcast) - * Type = LAN protocol type (LAN_PROTO_*) - */ -{ - NDIS_STATUS NdisStatus; - PETH_HEADER EHeader; - PVOID Data; - PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - /* NDIS send routines don't have an offset argument so we - must offset the data in upper layers and adjust the - packet here. We save the offset in the packet context - area so it can be undone before we release the packet */ - Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize); - PC(NdisPacket)->DLOffset = Offset; - - if (Adapter->State == LAN_STATE_STARTED) { - switch (Adapter->Media) { - case NdisMedium802_3: - EHeader = (PETH_HEADER)Data; - - if (LinkAddress) - /* Unicast address */ - RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH); - else - /* Broadcast address */ - RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF); - - RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH); - - switch (Type) { - case LAN_PROTO_IPv4: - EHeader->EType = ETYPE_IPv4; - break; - case LAN_PROTO_ARP: - EHeader->EType = ETYPE_ARP; - break; - case LAN_PROTO_IPv6: - EHeader->EType = ETYPE_IPv6; - break; - default: -#if DBG - /* Should not happen */ - TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n")); - - ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_FAILURE); -#endif - return; - } - break; - - default: - /* FIXME: Support other medias */ - break; - } - - NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket); - if (NdisStatus != NDIS_STATUS_PENDING) - ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus); - } else - ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED); -} - - -VOID BindAdapter( - PLAN_ADAPTER Adapter) -/* - * FUNCTION: Binds a LAN adapter to IP layer - * ARGUMENTS: - * Adapter = Pointer to LAN_ADAPTER structure - * NOTES: - * We set the lookahead buffer size, set the packet filter and - * bind the adapter to IP layer - */ -{ - INT i; - PIP_INTERFACE IF; - PIP_ADDRESS Address; - PNDIS_PACKET Packet; - NDIS_STATUS NdisStatus; - LLIP_BIND_INFO BindInfo; - ULONG Lookahead = LOOKAHEAD_SIZE; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - Adapter->State = LAN_STATE_OPENING; - - NdisStatus = NDISCall(Adapter, NdisRequestSetInformation, - OID_GEN_CURRENT_LOOKAHEAD, &Lookahead, sizeof(ULONG)); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus)); - return; - } - - /* Allocate packets for NdisTransferData */ - /* FIXME: How many should we allocate? */ - Adapter->TDPackets = NULL; - for (i = 0; i < 2; i++) { - Packet = AllocateTDPacket(Adapter); - PC(Packet)->Context = Adapter->TDPackets; - Adapter->TDPackets = Packet; - if (!Packet) { - TI_DbgPrint(MID_TRACE, ("Could not allocate transfer data packet (out of resources).\n")); - FreeTDPackets(Adapter); - return; - } - } - - /* Bind the adapter to IP layer */ - BindInfo.Context = Adapter; - BindInfo.HeaderSize = Adapter->HeaderSize; - BindInfo.MinFrameSize = Adapter->MinFrameSize; - BindInfo.MTU = Adapter->MTU; - BindInfo.Address = (PUCHAR)&Adapter->HWAddress; - BindInfo.AddressLength = Adapter->HWAddressLength; - BindInfo.Transmit = LANTransmit; - - IF = IPCreateInterface(&BindInfo); - if (!IF) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - FreeTDPackets(Adapter); - return; - } - - /* FIXME: Get address from registry. - For now just use a private address, eg. 10.0.0.10 */ - Address = AddrBuildIPv4(0x0A00000A); - if (!Address) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - FreeTDPackets(Adapter); - IPDestroyInterface(Adapter->Context); - return; - } - /* Create a net table entry for this interface */ - if (!IPCreateNTE(IF, Address, 8)) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - FreeTDPackets(Adapter); - IPDestroyInterface(IF); - return; - } - - /* Reference the interface for the NTE. The reference for - the address is just passed on to the NTE */ - ReferenceObject(IF); - - /* Register interface with IP layer */ - IPRegisterInterface(IF); - - /* Set packet filter so we can send and receive packets */ - NdisStatus = NDISCall(Adapter, NdisRequestSetInformation, - OID_GEN_CURRENT_PACKET_FILTER, &Adapter->PacketFilter, sizeof(UINT)); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus)); - FreeTDPackets(Adapter); - IPDestroyInterface(IF); - return; - } - - Adapter->Context = IF; - - Adapter->State = LAN_STATE_STARTED; -} - - -VOID UnbindAdapter( - PLAN_ADAPTER Adapter) -/* - * FUNCTION: Unbinds a LAN adapter from IP layer - * ARGUMENTS: - * Adapter = Pointer to LAN_ADAPTER structure - */ -{ - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - if (Adapter->State == LAN_STATE_STARTED) { - PIP_INTERFACE IF = Adapter->Context; - - IPUnregisterInterface(IF); - - IPDestroyInterface(IF); - - /* Free transfer data packets */ - FreeTDPackets(Adapter); - } -} - - -NDIS_STATUS LANRegisterAdapter( - PNDIS_STRING AdapterName, - PLAN_ADAPTER *Adapter) -/* - * FUNCTION: Registers protocol with an NDIS adapter - * ARGUMENTS: - * AdapterName = Pointer to string with name of adapter to register - * Adapter = Address of pointer to a LAN_ADAPTER structure - * RETURNS: - * Status of operation - */ -{ - PLAN_ADAPTER IF; - NDIS_STATUS NdisStatus; - NDIS_STATUS OpenStatus; - UINT MediaIndex; - NDIS_MEDIUM MediaArray[MAX_MEDIA]; - UINT AddressOID; - UINT Speed; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER)); - if (!IF) - return NDIS_STATUS_RESOURCES; - - RtlZeroMemory(IF, sizeof(LAN_ADAPTER)); - - /* Put adapter in stopped state */ - IF->State = LAN_STATE_STOPPED; - - /* Initialize protecting spin lock */ - KeInitializeSpinLock(&IF->Lock); - - KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE); - - /* Initialize array with media IDs we support */ - MediaArray[MEDIA_ETH] = NdisMedium802_3; - - /* Open the adapter. */ - NdisOpenAdapter(&NdisStatus, &OpenStatus, &IF->NdisHandle, &MediaIndex, - MediaArray, MAX_MEDIA, NdisProtocolHandle, IF, AdapterName, 0, NULL); - - /* Wait until the adapter is opened */ - if (NdisStatus == NDIS_STATUS_PENDING) - KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL); - else if (NdisStatus != NDIS_STATUS_SUCCESS) { - ExFreePool(IF); - return NdisStatus; - } - - IF->Media = MediaArray[MediaIndex]; - - /* Fill LAN_ADAPTER structure with some adapter specific information */ - switch (IF->Media) { - case NdisMedium802_3: - IF->HWAddressLength = IEEE_802_ADDR_LENGTH; - IF->BCastMask = BCAST_ETH_MASK; - IF->BCastCheck = BCAST_ETH_CHECK; - IF->BCastOffset = BCAST_ETH_OFFSET; - IF->HeaderSize = sizeof(ETH_HEADER); - IF->MinFrameSize = 60; - AddressOID = OID_802_3_CURRENT_ADDRESS; - IF->PacketFilter = - NDIS_PACKET_TYPE_BROADCAST | - NDIS_PACKET_TYPE_DIRECTED | - NDIS_PACKET_TYPE_MULTICAST; - break; - - default: - /* Unsupported media */ - TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n")); - ExFreePool(IF); - return NDIS_STATUS_NOT_SUPPORTED; - } - - /* Get maximum frame size */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, - OID_GEN_MAXIMUM_FRAME_SIZE, &IF->MTU, sizeof(UINT)); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - ExFreePool(IF); - return NdisStatus; - } - - /* Get maximum packet size */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, - OID_GEN_MAXIMUM_TOTAL_SIZE, &IF->MaxPacketSize, sizeof(UINT)); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n")); - ExFreePool(IF); - return NdisStatus; - } - - /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, - OID_GEN_MAXIMUM_SEND_PACKETS, &IF->MaxSendPackets, sizeof(UINT)); - if (NdisStatus != NDIS_STATUS_SUCCESS) - /* Legacy NIC drivers may not support this query, if it fails we - assume it can send at least one packet per call to NdisSend(Packets) */ - IF->MaxSendPackets = 1; - - /* Get current hardware address */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, AddressOID, - IF->HWAddress, IF->HWAddressLength); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n")); - ExFreePool(IF); - return NdisStatus; - } - - /* Get maximum link speed */ - NdisStatus = NDISCall(IF, NdisRequestQueryInformation, - OID_GEN_LINK_SPEED, &Speed, sizeof(UINT)); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n")); - ExFreePool(IF); - return NdisStatus; - } - - /* Convert returned link speed to bps (it is in 100bps increments) */ - IF->Speed = Speed * 100L; - - *Adapter = IF; - - /* Add adapter to the adapter list */ - IF->Next = Adapters; - Adapters = IF; - - /* Bind adapter to IP layer */ - BindAdapter(IF); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); - - return NDIS_STATUS_SUCCESS; -} - - -NDIS_STATUS LANUnregisterAdapter( - PLAN_ADAPTER Adapter) -/* - * FUNCTION: Unregisters protocol with NDIS adapter - * ARGUMENTS: - * Adapter = Pointer to a LAN_ADAPTER structure - * RETURNS: - * Status of operation - */ -{ - KIRQL OldIrql; - NDIS_HANDLE NdisHandle; - PLAN_ADAPTER IF, PrevIF; - BOOLEAN Found = FALSE; - NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - /* Search the adapter list for the specified adapter and remove it */ - IF = Adapters; - if (IF) { - if (Adapter != Adapters) { - PrevIF = IF; - while ((IF) && (!Found)) { - if (IF == Adapter) { - /* We've found the adapter, now remove it from the list */ - PrevIF->Next = IF->Next; - Found = TRUE; - } - PrevIF = IF; - IF = IF->Next; - } - } else { - Adapters = NULL; - Found = TRUE; - } - } - if (!Found) { - TI_DbgPrint(MIN_TRACE, ("Leaving (adapter was not in list).\n")); - return NDIS_STATUS_ADAPTER_NOT_FOUND; - } - - /* Unbind adapter from IP layer */ - UnbindAdapter(Adapter); - - KeAcquireSpinLock(&Adapter->Lock, &OldIrql); - NdisHandle = Adapter->NdisHandle; - if (NdisHandle) { - Adapter->NdisHandle = NULL; - KeReleaseSpinLock(&Adapter->Lock, OldIrql); - - NdisCloseAdapter(&NdisStatus, NdisHandle); - if (NdisStatus == NDIS_STATUS_PENDING) { - KeWaitForSingleObject(&Adapter->Event, - UserRequest, KernelMode, FALSE, NULL); - NdisStatus = Adapter->NdisStatus; - } - } else - KeReleaseSpinLock(&Adapter->Lock, OldIrql); - - FreeAdapter(Adapter); - - return NDIS_STATUS_SUCCESS; -} - - -NTSTATUS LANRegisterProtocol( - PSTRING Name) -/* - * FUNCTION: Registers this protocol driver with NDIS - * ARGUMENTS: - * Name = Name of this protocol driver - * RETURNS: - * Status of operation - */ -{ - NDIS_STATUS NdisStatus; - NDIS_PROTOCOL_CHARACTERISTICS ProtChars; - - /* Set up protocol characteristics */ - RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); - ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR; - ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR; - ProtChars.Name.Length = Name->Length; - ProtChars.Name.Buffer = (PVOID)Name->Buffer; - ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete; - ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete; - ProtChars.ResetCompleteHandler = ProtocolResetComplete; - ProtChars.RequestCompleteHandler = ProtocolRequestComplete; - ProtChars.SendCompleteHandler = ProtocolSendComplete; - ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete; - ProtChars.ReceiveHandler = ProtocolReceive; - ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete; - ProtChars.StatusHandler = ProtocolStatus; - ProtChars.StatusCompleteHandler = ProtocolStatusComplete; - - /* Try to register protocol */ - NdisRegisterProtocol( - &NdisStatus, &NdisProtocolHandle, &ProtChars, - sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length); - if (NdisStatus != NDIS_STATUS_SUCCESS) - return (NTSTATUS)NdisStatus; - - ProtocolRegistered = TRUE; - - return STATUS_SUCCESS; -} - - -VOID LANUnregisterProtocol( - VOID) -/* - * FUNCTION: Unregisters this protocol driver with NDIS - * NOTES: Does not care wether we are already registered - */ -{ - if (ProtocolRegistered) { - NDIS_STATUS NdisStatus; - - while (Adapters) - NdisStatus = LANUnregisterAdapter(Adapters); - - NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle); - ProtocolRegistered = FALSE; - } -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: datalink/lan.c + * PURPOSE: Local Area Network media routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include + + +NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL; +BOOLEAN ProtocolRegistered = FALSE; +PLAN_ADAPTER Adapters = NULL; + + +NDIS_STATUS NDISCall( + PLAN_ADAPTER Adapter, + NDIS_REQUEST_TYPE Type, + NDIS_OID OID, + PVOID Buffer, + UINT Length) +/* + * FUNCTION: Send a request to NDIS + * ARGUMENTS: + * Adapter = Pointer to a LAN_ADAPTER structure + * Type = Type of request (Set or Query) + * OID = Value to be set/queried for + * Buffer = Pointer to a buffer to use + * Length = Number of bytes in Buffer + * RETURNS: + * Status of operation + */ +{ + NDIS_REQUEST Request; + NDIS_STATUS NdisStatus; + + Request.RequestType = Type; + if (Type == NdisRequestSetInformation) { + Request.DATA.SET_INFORMATION.Oid = OID; + Request.DATA.SET_INFORMATION.InformationBuffer = Buffer; + Request.DATA.SET_INFORMATION.InformationBufferLength = Length; + } else { + Request.DATA.QUERY_INFORMATION.Oid = OID; + Request.DATA.QUERY_INFORMATION.InformationBuffer = Buffer; + Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length; + } + + if (Adapter->State != LAN_STATE_RESETTING) { + NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request); + } else + NdisStatus = NDIS_STATUS_NOT_ACCEPTED; + + /* Wait for NDIS to complete the request */ + if (NdisStatus == NDIS_STATUS_PENDING) { + KeWaitForSingleObject(&Adapter->Event, UserRequest, KernelMode, FALSE, NULL); + NdisStatus = Adapter->NdisStatus; + } + + return NdisStatus; +} + + +PNDIS_PACKET AllocateTDPacket( + PLAN_ADAPTER Adapter) +/* + * FUNCTION: Allocates an NDIS packet for NdisTransferData + * ARGUMENTS: + * Adapter = Pointer to LAN_ADAPTER structure + * RETURNS: + * Pointer to NDIS packet or NULL if there was not enough free + * non-paged memory + */ +{ + NDIS_STATUS NdisStatus; + PNDIS_PACKET NdisPacket; + PNDIS_BUFFER Buffer; + PVOID Data; + + NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool); + if (NdisStatus != NDIS_STATUS_SUCCESS) + return NULL; + + Data = ExAllocatePool(NonPagedPool, Adapter->MTU); + if (!Data) { + NdisFreePacket(NdisPacket); + return NULL; + } + + NdisAllocateBuffer(&NdisStatus, &Buffer, GlobalBufferPool, Data, Adapter->MTU); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + NdisFreePacket(NdisPacket); + ExFreePool(Data); + return NULL; + } + + NdisChainBufferAtFront(NdisPacket, Buffer); + + PC(NdisPacket)->Context = NULL; /* End of list */ + + return NdisPacket; +} + + +VOID FreeTDPackets( + PLAN_ADAPTER Adapter) +/* + * FUNCTION: Frees transfer data packets + * ARGUMENTS: + * Adapter = Pointer to LAN_ADAPTER structure + */ +{ + PNDIS_PACKET NdisPacket, Next; + + /* Release transfer data packets */ + NdisPacket = Adapter->TDPackets; + while (NdisPacket) { + Next = PC(NdisPacket)->Context; + FreeNdisPacket(NdisPacket); + NdisPacket = Next; + } + Adapter->TDPackets = NULL; +} + + +VOID FreeAdapter( + PLAN_ADAPTER Adapter) +/* + * FUNCTION: Frees memory for a LAN_ADAPTER structure + * ARGUMENTS: + * Adapter = Pointer to LAN_ADAPTER structure to free + */ +{ + FreeTDPackets(Adapter); + ExFreePool(Adapter); +} + + +VOID ProtocolOpenAdapterComplete( + NDIS_HANDLE BindingContext, + NDIS_STATUS Status, + NDIS_STATUS OpenErrorStatus) +/* + * FUNCTION: Called by NDIS to complete opening of an adapter + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + * Status = Status of the operation + * OpenErrorStatus = Additional status information + */ +{ + PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + KeSetEvent(&Adapter->Event, 0, FALSE); +} + + +VOID ProtocolCloseAdapterComplete( + NDIS_HANDLE BindingContext, + NDIS_STATUS Status) +/* + * FUNCTION: Called by NDIS to complete closing an adapter + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + * Status = Status of the operation + */ +{ + PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + Adapter->NdisStatus = Status; + + KeSetEvent(&Adapter->Event, 0, FALSE); +} + + +VOID ProtocolResetComplete( + NDIS_HANDLE BindingContext, + NDIS_STATUS Status) +/* + * FUNCTION: Called by NDIS to complete resetting an adapter + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + * Status = Status of the operation + */ +{ + TI_DbgPrint(MID_TRACE, ("Called.\n")); +} + + +VOID ProtocolRequestComplete( + NDIS_HANDLE BindingContext, + PNDIS_REQUEST NdisRequest, + NDIS_STATUS Status) +/* + * FUNCTION: Called by NDIS to complete a request + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + * NdisRequest = Pointer to an object describing the request + * Status = Status of the operation + */ +{ + PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; + + /* Save status of request and signal an event */ + Adapter->NdisStatus = Status; + + KeSetEvent(&Adapter->Event, 0, FALSE); +} + + +VOID ProtocolSendComplete( + NDIS_HANDLE BindingContext, + PNDIS_PACKET Packet, + NDIS_STATUS Status) +/* + * FUNCTION: Called by NDIS to complete sending process + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + * Packet = Pointer to a packet descriptor + * Status = Status of the operation + */ +{ + PLAN_ADAPTER Adapter = BindingContext; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset); + + (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status); +} + + +VOID ProtocolTransferDataComplete( + NDIS_HANDLE BindingContext, + PNDIS_PACKET Packet, + NDIS_STATUS Status, + UINT BytesTransferred) +/* + * FUNCTION: Called by NDIS to complete reception of data + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + * Packet = Pointer to a packet descriptor + * Status = Status of the operation + * BytesTransferred = Number of bytes transferred + * NOTES: + * If the packet was successfully received, determine the protocol + * type and pass it to the correct receive handler + */ +{ + UINT PacketType; + PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; + + if (Status == NDIS_STATUS_SUCCESS) { + PNDIS_BUFFER NdisBuffer; + IP_PACKET IPPacket; + + NdisGetFirstBufferFromPacket( + Packet, &NdisBuffer, &IPPacket.Header, + &IPPacket.ContigSize, &IPPacket.TotalSize); + + /* Determine which upper layer protocol that should receive + this packet and pass it to the correct receive handler */ + PacketType = ((PETH_HEADER)IPPacket.Header)->EType; + switch (PacketType) { + case ETYPE_IPv4: + case ETYPE_IPv6: + IPReceive(Adapter->Context, &IPPacket); + break; + case ETYPE_ARP: + ARPReceive(Adapter->Context, &IPPacket); + default: + break; + } + } + + /* Release the packet descriptor */ + KeAcquireSpinLockAtDpcLevel(&Adapter->Lock); + + PC(Packet)->Context = Adapter->TDPackets; + Adapter->TDPackets = Packet; + + KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); +} + + +NDIS_STATUS ProtocolReceive( + NDIS_HANDLE BindingContext, + NDIS_HANDLE MacReceiveContext, + PVOID HeaderBuffer, + UINT HeaderBufferSize, + PVOID LookaheadBuffer, + UINT LookaheadBufferSize, + UINT PacketSize) +/* + * FUNCTION: Called by NDIS when a packet has been received on the physical link + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + * MacReceiveContext = Handle used by underlying NIC driver + * HeaderBuffer = Pointer to a buffer containing the packet header + * HeaderBufferSize = Number of bytes in HeaderBuffer + * LookaheadBuffer = Pointer to a buffer containing buffered packet data + * LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for + * PacketSize = Overall size of the packet (not including header) + * RETURNS: + * Status of operation + */ +{ + USHORT EType; + UINT PacketType; + IP_PACKET IPPacket; + PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext; + PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + if ((Adapter->State != LAN_STATE_STARTED) || + HeaderBufferSize < Adapter->HeaderSize) + /* Adapter is not started or the header was too small */ + return NDIS_STATUS_NOT_ACCEPTED; + + if (Adapter->Media == NdisMedium802_3) { + /* Ethernet and IEEE 802.3 frames can be destinguished by + looking at the IEEE 802.3 length field. This field is + less than or equal to 1500 for a valid IEEE 802.3 frame + and larger than 1500 is it's a valid Ether-Type value. + See RFC 1122, section 2.3.3 for more information */ + if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP)) + return NDIS_STATUS_NOT_ACCEPTED; + /* We use Ether-Type constants to destinguish packets */ + PacketType = EType; + } else + /* FIXME: Support other medias */ + return NDIS_STATUS_NOT_ACCEPTED; + + if (LookaheadBufferSize < PacketSize) { + NDIS_STATUS NdisStatus; + PNDIS_PACKET NdisPacket; + UINT BytesTransferred; + + /* Get transfer data packet */ + + KeAcquireSpinLockAtDpcLevel(&Adapter->Lock); + + NdisPacket = Adapter->TDPackets; + if (NdisPacket == (PNDIS_PACKET)NULL) { + /* We don't have a free packet descriptor. Drop the packet */ + KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); + return NDIS_STATUS_SUCCESS; + } + Adapter->TDPackets = PC(NdisPacket)->Context; + + KeReleaseSpinLockFromDpcLevel(&Adapter->Lock); + + /* Get the data */ + NdisTransferData(&NdisStatus, Adapter->NdisHandle, + MacReceiveContext, 0, PacketSize, + NdisPacket, &BytesTransferred); + if (NdisStatus != NDIS_STATUS_PENDING) + ProtocolTransferDataComplete(BindingContext, + NdisPacket, NdisStatus, BytesTransferred); + + return NDIS_STATUS_SUCCESS; + } + + /* We got all the data in the lookahead buffer */ + RtlZeroMemory(&IPPacket, sizeof(IPPacket)); + IPPacket.Header = LookaheadBuffer; + IPPacket.TotalSize = PacketSize; + + switch (PacketType) { + case ETYPE_IPv4: + case ETYPE_IPv6: + IPReceive(Adapter->Context, &IPPacket); + break; + case ETYPE_ARP: + ARPReceive(Adapter->Context, &IPPacket); + break; + default: + break; + } + + return NDIS_STATUS_SUCCESS; +} + + +VOID ProtocolReceiveComplete( + NDIS_HANDLE BindingContext) +/* + * FUNCTION: Called by NDIS when we're done receiving data + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + */ +{ + TI_DbgPrint(MID_TRACE, ("Called.\n")); +} + + +VOID ProtocolStatus( + NDIS_HANDLE BindingContext, + NDIS_STATUS GenerelStatus, + PVOID StatusBuffer, + UINT StatusBufferSize) +/* + * FUNCTION: Called by NDIS when the underlying driver has changed state + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + * GenerelStatus = A generel status code + * StatusBuffer = Pointer to a buffer with medium-specific data + * StatusBufferSize = Number of bytes in StatusBuffer + */ +{ + TI_DbgPrint(MID_TRACE, ("Called.\n")); +} + + +VOID ProtocolStatusComplete( + NDIS_HANDLE NdisBindingContext) +/* + * FUNCTION: Called by NDIS when a status-change has occurred + * ARGUMENTS: + * BindingContext = Pointer to a device context (LAN_ADAPTER) + */ +{ + TI_DbgPrint(MID_TRACE, ("Called.\n")); +} + + +VOID LANTransmit( + PVOID Context, + PNDIS_PACKET NdisPacket, + UINT Offset, + PVOID LinkAddress, + USHORT Type) +/* + * FUNCTION: Transmits a packet + * ARGUMENTS: + * Context = Pointer to context information (LAN_ADAPTER) + * NdisPacket = Pointer to NDIS packet to send + * Offset = Offset in packet where data starts + * LinkAddress = Pointer to link address of destination (NULL = broadcast) + * Type = LAN protocol type (LAN_PROTO_*) + */ +{ + NDIS_STATUS NdisStatus; + PETH_HEADER EHeader; + PVOID Data; + PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + /* NDIS send routines don't have an offset argument so we + must offset the data in upper layers and adjust the + packet here. We save the offset in the packet context + area so it can be undone before we release the packet */ + Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize); + PC(NdisPacket)->DLOffset = Offset; + + if (Adapter->State == LAN_STATE_STARTED) { + switch (Adapter->Media) { + case NdisMedium802_3: + EHeader = (PETH_HEADER)Data; + + if (LinkAddress) + /* Unicast address */ + RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH); + else + /* Broadcast address */ + RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF); + + RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH); + + switch (Type) { + case LAN_PROTO_IPv4: + EHeader->EType = ETYPE_IPv4; + break; + case LAN_PROTO_ARP: + EHeader->EType = ETYPE_ARP; + break; + case LAN_PROTO_IPv6: + EHeader->EType = ETYPE_IPv6; + break; + default: +#if DBG + /* Should not happen */ + TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n")); + + ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_FAILURE); +#endif + return; + } + break; + + default: + /* FIXME: Support other medias */ + break; + } + + NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket); + if (NdisStatus != NDIS_STATUS_PENDING) + ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus); + } else + ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED); +} + + +VOID BindAdapter( + PLAN_ADAPTER Adapter) +/* + * FUNCTION: Binds a LAN adapter to IP layer + * ARGUMENTS: + * Adapter = Pointer to LAN_ADAPTER structure + * NOTES: + * We set the lookahead buffer size, set the packet filter and + * bind the adapter to IP layer + */ +{ + INT i; + PIP_INTERFACE IF; + PIP_ADDRESS Address; + PNDIS_PACKET Packet; + NDIS_STATUS NdisStatus; + LLIP_BIND_INFO BindInfo; + ULONG Lookahead = LOOKAHEAD_SIZE; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + Adapter->State = LAN_STATE_OPENING; + + NdisStatus = NDISCall(Adapter, NdisRequestSetInformation, + OID_GEN_CURRENT_LOOKAHEAD, &Lookahead, sizeof(ULONG)); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus)); + return; + } + + /* Allocate packets for NdisTransferData */ + /* FIXME: How many should we allocate? */ + Adapter->TDPackets = NULL; + for (i = 0; i < 2; i++) { + Packet = AllocateTDPacket(Adapter); + PC(Packet)->Context = Adapter->TDPackets; + Adapter->TDPackets = Packet; + if (!Packet) { + TI_DbgPrint(MID_TRACE, ("Could not allocate transfer data packet (out of resources).\n")); + FreeTDPackets(Adapter); + return; + } + } + + /* Bind the adapter to IP layer */ + BindInfo.Context = Adapter; + BindInfo.HeaderSize = Adapter->HeaderSize; + BindInfo.MinFrameSize = Adapter->MinFrameSize; + BindInfo.MTU = Adapter->MTU; + BindInfo.Address = (PUCHAR)&Adapter->HWAddress; + BindInfo.AddressLength = Adapter->HWAddressLength; + BindInfo.Transmit = LANTransmit; + + IF = IPCreateInterface(&BindInfo); + if (!IF) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + FreeTDPackets(Adapter); + return; + } + + /* FIXME: Get address from registry. + For now just use a private address, eg. 10.0.0.10 */ + Address = AddrBuildIPv4(0x0A00000A); + if (!Address) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + FreeTDPackets(Adapter); + IPDestroyInterface(Adapter->Context); + return; + } + /* Create a net table entry for this interface */ + if (!IPCreateNTE(IF, Address, 8)) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + FreeTDPackets(Adapter); + IPDestroyInterface(IF); + return; + } + + /* Reference the interface for the NTE. The reference for + the address is just passed on to the NTE */ + ReferenceObject(IF); + + /* Register interface with IP layer */ + IPRegisterInterface(IF); + + /* Set packet filter so we can send and receive packets */ + NdisStatus = NDISCall(Adapter, NdisRequestSetInformation, + OID_GEN_CURRENT_PACKET_FILTER, &Adapter->PacketFilter, sizeof(UINT)); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus)); + FreeTDPackets(Adapter); + IPDestroyInterface(IF); + return; + } + + Adapter->Context = IF; + + Adapter->State = LAN_STATE_STARTED; +} + + +VOID UnbindAdapter( + PLAN_ADAPTER Adapter) +/* + * FUNCTION: Unbinds a LAN adapter from IP layer + * ARGUMENTS: + * Adapter = Pointer to LAN_ADAPTER structure + */ +{ + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + if (Adapter->State == LAN_STATE_STARTED) { + PIP_INTERFACE IF = Adapter->Context; + + IPUnregisterInterface(IF); + + IPDestroyInterface(IF); + + /* Free transfer data packets */ + FreeTDPackets(Adapter); + } +} + + +NDIS_STATUS LANRegisterAdapter( + PNDIS_STRING AdapterName, + PLAN_ADAPTER *Adapter) +/* + * FUNCTION: Registers protocol with an NDIS adapter + * ARGUMENTS: + * AdapterName = Pointer to string with name of adapter to register + * Adapter = Address of pointer to a LAN_ADAPTER structure + * RETURNS: + * Status of operation + */ +{ + PLAN_ADAPTER IF; + NDIS_STATUS NdisStatus; + NDIS_STATUS OpenStatus; + UINT MediaIndex; + NDIS_MEDIUM MediaArray[MAX_MEDIA]; + UINT AddressOID; + UINT Speed; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER)); + if (!IF) + return NDIS_STATUS_RESOURCES; + + RtlZeroMemory(IF, sizeof(LAN_ADAPTER)); + + /* Put adapter in stopped state */ + IF->State = LAN_STATE_STOPPED; + + /* Initialize protecting spin lock */ + KeInitializeSpinLock(&IF->Lock); + + KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE); + + /* Initialize array with media IDs we support */ + MediaArray[MEDIA_ETH] = NdisMedium802_3; + + /* Open the adapter. */ + NdisOpenAdapter(&NdisStatus, &OpenStatus, &IF->NdisHandle, &MediaIndex, + MediaArray, MAX_MEDIA, NdisProtocolHandle, IF, AdapterName, 0, NULL); + + /* Wait until the adapter is opened */ + if (NdisStatus == NDIS_STATUS_PENDING) + KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL); + else if (NdisStatus != NDIS_STATUS_SUCCESS) { + ExFreePool(IF); + return NdisStatus; + } + + IF->Media = MediaArray[MediaIndex]; + + /* Fill LAN_ADAPTER structure with some adapter specific information */ + switch (IF->Media) { + case NdisMedium802_3: + IF->HWAddressLength = IEEE_802_ADDR_LENGTH; + IF->BCastMask = BCAST_ETH_MASK; + IF->BCastCheck = BCAST_ETH_CHECK; + IF->BCastOffset = BCAST_ETH_OFFSET; + IF->HeaderSize = sizeof(ETH_HEADER); + IF->MinFrameSize = 60; + AddressOID = OID_802_3_CURRENT_ADDRESS; + IF->PacketFilter = + NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_MULTICAST; + break; + + default: + /* Unsupported media */ + TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n")); + ExFreePool(IF); + return NDIS_STATUS_NOT_SUPPORTED; + } + + /* Get maximum frame size */ + NdisStatus = NDISCall(IF, NdisRequestQueryInformation, + OID_GEN_MAXIMUM_FRAME_SIZE, &IF->MTU, sizeof(UINT)); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + ExFreePool(IF); + return NdisStatus; + } + + /* Get maximum packet size */ + NdisStatus = NDISCall(IF, NdisRequestQueryInformation, + OID_GEN_MAXIMUM_TOTAL_SIZE, &IF->MaxPacketSize, sizeof(UINT)); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n")); + ExFreePool(IF); + return NdisStatus; + } + + /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */ + NdisStatus = NDISCall(IF, NdisRequestQueryInformation, + OID_GEN_MAXIMUM_SEND_PACKETS, &IF->MaxSendPackets, sizeof(UINT)); + if (NdisStatus != NDIS_STATUS_SUCCESS) + /* Legacy NIC drivers may not support this query, if it fails we + assume it can send at least one packet per call to NdisSend(Packets) */ + IF->MaxSendPackets = 1; + + /* Get current hardware address */ + NdisStatus = NDISCall(IF, NdisRequestQueryInformation, AddressOID, + IF->HWAddress, IF->HWAddressLength); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n")); + ExFreePool(IF); + return NdisStatus; + } + + /* Get maximum link speed */ + NdisStatus = NDISCall(IF, NdisRequestQueryInformation, + OID_GEN_LINK_SPEED, &Speed, sizeof(UINT)); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n")); + ExFreePool(IF); + return NdisStatus; + } + + /* Convert returned link speed to bps (it is in 100bps increments) */ + IF->Speed = Speed * 100L; + + *Adapter = IF; + + /* Add adapter to the adapter list */ + IF->Next = Adapters; + Adapters = IF; + + /* Bind adapter to IP layer */ + BindAdapter(IF); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); + + return NDIS_STATUS_SUCCESS; +} + + +NDIS_STATUS LANUnregisterAdapter( + PLAN_ADAPTER Adapter) +/* + * FUNCTION: Unregisters protocol with NDIS adapter + * ARGUMENTS: + * Adapter = Pointer to a LAN_ADAPTER structure + * RETURNS: + * Status of operation + */ +{ + KIRQL OldIrql; + NDIS_HANDLE NdisHandle; + PLAN_ADAPTER IF, PrevIF; + BOOLEAN Found = FALSE; + NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + /* Search the adapter list for the specified adapter and remove it */ + IF = Adapters; + if (IF) { + if (Adapter != Adapters) { + PrevIF = IF; + while ((IF) && (!Found)) { + if (IF == Adapter) { + /* We've found the adapter, now remove it from the list */ + PrevIF->Next = IF->Next; + Found = TRUE; + } + PrevIF = IF; + IF = IF->Next; + } + } else { + Adapters = NULL; + Found = TRUE; + } + } + if (!Found) { + TI_DbgPrint(MIN_TRACE, ("Leaving (adapter was not in list).\n")); + return NDIS_STATUS_ADAPTER_NOT_FOUND; + } + + /* Unbind adapter from IP layer */ + UnbindAdapter(Adapter); + + KeAcquireSpinLock(&Adapter->Lock, &OldIrql); + NdisHandle = Adapter->NdisHandle; + if (NdisHandle) { + Adapter->NdisHandle = NULL; + KeReleaseSpinLock(&Adapter->Lock, OldIrql); + + NdisCloseAdapter(&NdisStatus, NdisHandle); + if (NdisStatus == NDIS_STATUS_PENDING) { + KeWaitForSingleObject(&Adapter->Event, + UserRequest, KernelMode, FALSE, NULL); + NdisStatus = Adapter->NdisStatus; + } + } else + KeReleaseSpinLock(&Adapter->Lock, OldIrql); + + FreeAdapter(Adapter); + + return NDIS_STATUS_SUCCESS; +} + + +NTSTATUS LANRegisterProtocol( + PSTRING Name) +/* + * FUNCTION: Registers this protocol driver with NDIS + * ARGUMENTS: + * Name = Name of this protocol driver + * RETURNS: + * Status of operation + */ +{ + NDIS_STATUS NdisStatus; + NDIS_PROTOCOL_CHARACTERISTICS ProtChars; + + /* Set up protocol characteristics */ + RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS)); + ProtChars.MajorNdisVersion = NDIS_VERSION_MAJOR; + ProtChars.MinorNdisVersion = NDIS_VERSION_MINOR; + ProtChars.Name.Length = Name->Length; + ProtChars.Name.Buffer = (PVOID)Name->Buffer; + ProtChars.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete; + ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete; + ProtChars.ResetCompleteHandler = ProtocolResetComplete; + ProtChars.RequestCompleteHandler = ProtocolRequestComplete; + ProtChars.SendCompleteHandler = ProtocolSendComplete; + ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete; + ProtChars.ReceiveHandler = ProtocolReceive; + ProtChars.ReceiveCompleteHandler = ProtocolReceiveComplete; + ProtChars.StatusHandler = ProtocolStatus; + ProtChars.StatusCompleteHandler = ProtocolStatusComplete; + + /* Try to register protocol */ + NdisRegisterProtocol( + &NdisStatus, &NdisProtocolHandle, &ProtChars, + sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length); + if (NdisStatus != NDIS_STATUS_SUCCESS) + return (NTSTATUS)NdisStatus; + + ProtocolRegistered = TRUE; + + return STATUS_SUCCESS; +} + + +VOID LANUnregisterProtocol( + VOID) +/* + * FUNCTION: Unregisters this protocol driver with NDIS + * NOTES: Does not care wether we are already registered + */ +{ + if (ProtocolRegistered) { + NDIS_STATUS NdisStatus; + + while (Adapters) + NdisStatus = LANUnregisterAdapter(Adapters); + + NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle); + ProtocolRegistered = FALSE; + } +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/datalink/loopback.c b/reactos/drivers/net/tcpip/datalink/loopback.c index d42e499fa56..309f98d082e 100644 --- a/reactos/drivers/net/tcpip/datalink/loopback.c +++ b/reactos/drivers/net/tcpip/datalink/loopback.c @@ -1,224 +1,224 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: datalink/loopback.c - * PURPOSE: Loopback adapter - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include - - -WORK_QUEUE_ITEM LoopWorkItem; -PIP_INTERFACE Loopback = NULL; -/* Indicates wether the loopback interface is currently transmitting */ -BOOLEAN LoopBusy = FALSE; -/* Loopback transmit queue */ -PNDIS_PACKET LoopQueueHead = (PNDIS_PACKET)NULL; -PNDIS_PACKET LoopQueueTail = (PNDIS_PACKET)NULL; -/* Spin lock for protecting loopback transmit queue */ -KSPIN_LOCK LoopLock; - - -VOID RealTransmit( - PVOID Context) -/* - * FUNCTION: Transmits one or more packet(s) in loopback queue to ourselves - * ARGUMENTS: - * Context = Pointer to context information (loopback interface) - */ -{ - KIRQL OldIrql; - PNDIS_PACKET NdisPacket; - IP_PACKET IPPacket; - PNDIS_BUFFER Buffer; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); - - KeAcquireSpinLockAtDpcLevel(&LoopLock); - - for (;;) { - /* Get the next packet from the queue (if any) */ - NdisPacket = LoopQueueHead; - if (!NdisPacket) - break; - - LoopQueueHead = *(PNDIS_PACKET*)NdisPacket->MacReserved; - - KeReleaseSpinLockFromDpcLevel(&LoopLock); - - IPPacket.NdisPacket = NdisPacket; - - NdisGetFirstBufferFromPacket(NdisPacket, - &Buffer, - &IPPacket.Header, - &IPPacket.ContigSize, - &IPPacket.TotalSize); - - IPReceive(Context, &IPPacket); - - AdjustPacket(NdisPacket, 0, PC(NdisPacket)->DLOffset); - - PC(NdisPacket)->DLComplete(Context, NdisPacket, NDIS_STATUS_SUCCESS); - - /* Lower IRQL for a moment to prevent starvation */ - KeLowerIrql(OldIrql); - - KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); - - KeAcquireSpinLockAtDpcLevel(&LoopLock); - } - - LoopBusy = FALSE; - - KeReleaseSpinLockFromDpcLevel(&LoopLock); - - KeLowerIrql(OldIrql); -} - - -VOID LoopTransmit( - PVOID Context, - PNDIS_PACKET NdisPacket, - UINT Offset, - PVOID LinkAddress, - USHORT Type) -/* - * FUNCTION: Transmits a packet - * ARGUMENTS: - * Context = Pointer to context information (NULL) - * NdisPacket = Pointer to NDIS packet to send - * Offset = Offset in packet where packet data starts - * LinkAddress = Pointer to link address - * Type = LAN protocol type (unused) - */ -{ - PNDIS_PACKET *pNdisPacket; - KIRQL OldIrql; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - /* NDIS send routines don't have an offset argument so we - must offset the data in upper layers and adjust the - packet here. We save the offset in the packet context - area so it can be undone before we release the packet */ - AdjustPacket(NdisPacket, Offset, 0); - PC(NdisPacket)->DLOffset = Offset; - - pNdisPacket = (PNDIS_PACKET*)NdisPacket->MacReserved; - *pNdisPacket = NULL; - - KeAcquireSpinLock(&LoopLock, &OldIrql); - - /* Add packet to transmit queue */ - if (LoopQueueHead) { - /* Transmit queue is not empty */ - pNdisPacket = (PNDIS_PACKET*)LoopQueueTail->MacReserved; - *pNdisPacket = NdisPacket; - } else - /* Transmit queue is empty */ - LoopQueueHead = NdisPacket; - - LoopQueueTail = NdisPacket; - - /* If LoopTransmit is not running (or scheduled), schedule it to run */ - if (!LoopBusy) { - ExQueueWorkItem(&LoopWorkItem, CriticalWorkQueue); - LoopBusy = TRUE; - } - - KeReleaseSpinLock(&LoopLock, OldIrql); -} - - -NDIS_STATUS LoopRegisterAdapter( - PNDIS_STRING AdapterName, - PLAN_ADAPTER *Adapter) -/* - * FUNCTION: Registers loopback adapter - * ARGUMENTS: - * AdapterName = Unused - * Adapter = Unused - * RETURNS: - * Status of operation - */ -{ - PIP_ADDRESS Address; - NDIS_STATUS Status = NDIS_STATUS_SUCCESS; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - Address = AddrBuildIPv4(LOOPBACK_ADDRESS_IPv4); - if (Address) { - LLIP_BIND_INFO BindInfo; - - /* Bind the adapter to IP layer */ - BindInfo.Context = NULL; - BindInfo.HeaderSize = 0; - BindInfo.MinFrameSize = 0; - BindInfo.MTU = 16384; - BindInfo.Address = NULL; - BindInfo.AddressLength = 0; - BindInfo.Transmit = LoopTransmit; - - Loopback = IPCreateInterface(&BindInfo); - if ((Loopback) && (IPCreateNTE(Loopback, Address, 8))) { - /* Reference the interface for the NTE. The reference for - the address is just passed on to the NTE */ - ReferenceObject(Loopback); - - IPRegisterInterface(Loopback); - - ExInitializeWorkItem(&LoopWorkItem, RealTransmit, Loopback); - - KeInitializeSpinLock(&LoopLock); - LoopBusy = FALSE; - } else - Status = NDIS_STATUS_RESOURCES; - } else - Status = NDIS_STATUS_RESOURCES; - - if (!NT_SUCCESS(Status)) - LoopUnregisterAdapter(NULL); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); - - return Status; -} - - -NDIS_STATUS LoopUnregisterAdapter( - PLAN_ADAPTER Adapter) -/* - * FUNCTION: Unregisters loopback adapter - * ARGUMENTS: - * Adapter = Unused - * RETURNS: - * Status of operation - * NOTES: - * Does not care wether we have registered loopback adapter - */ -{ - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - if (Loopback) { - IPUnregisterInterface(Loopback); - IPDestroyInterface(Loopback); - Loopback = NULL; - } - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); - - return NDIS_STATUS_SUCCESS; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: datalink/loopback.c + * PURPOSE: Loopback adapter + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include + + +WORK_QUEUE_ITEM LoopWorkItem; +PIP_INTERFACE Loopback = NULL; +/* Indicates wether the loopback interface is currently transmitting */ +BOOLEAN LoopBusy = FALSE; +/* Loopback transmit queue */ +PNDIS_PACKET LoopQueueHead = (PNDIS_PACKET)NULL; +PNDIS_PACKET LoopQueueTail = (PNDIS_PACKET)NULL; +/* Spin lock for protecting loopback transmit queue */ +KSPIN_LOCK LoopLock; + + +VOID RealTransmit( + PVOID Context) +/* + * FUNCTION: Transmits one or more packet(s) in loopback queue to ourselves + * ARGUMENTS: + * Context = Pointer to context information (loopback interface) + */ +{ + KIRQL OldIrql; + PNDIS_PACKET NdisPacket; + IP_PACKET IPPacket; + PNDIS_BUFFER Buffer; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + KeAcquireSpinLockAtDpcLevel(&LoopLock); + + for (;;) { + /* Get the next packet from the queue (if any) */ + NdisPacket = LoopQueueHead; + if (!NdisPacket) + break; + + LoopQueueHead = *(PNDIS_PACKET*)NdisPacket->MacReserved; + + KeReleaseSpinLockFromDpcLevel(&LoopLock); + + IPPacket.NdisPacket = NdisPacket; + + NdisGetFirstBufferFromPacket(NdisPacket, + &Buffer, + &IPPacket.Header, + &IPPacket.ContigSize, + &IPPacket.TotalSize); + + IPReceive(Context, &IPPacket); + + AdjustPacket(NdisPacket, 0, PC(NdisPacket)->DLOffset); + + PC(NdisPacket)->DLComplete(Context, NdisPacket, NDIS_STATUS_SUCCESS); + + /* Lower IRQL for a moment to prevent starvation */ + KeLowerIrql(OldIrql); + + KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); + + KeAcquireSpinLockAtDpcLevel(&LoopLock); + } + + LoopBusy = FALSE; + + KeReleaseSpinLockFromDpcLevel(&LoopLock); + + KeLowerIrql(OldIrql); +} + + +VOID LoopTransmit( + PVOID Context, + PNDIS_PACKET NdisPacket, + UINT Offset, + PVOID LinkAddress, + USHORT Type) +/* + * FUNCTION: Transmits a packet + * ARGUMENTS: + * Context = Pointer to context information (NULL) + * NdisPacket = Pointer to NDIS packet to send + * Offset = Offset in packet where packet data starts + * LinkAddress = Pointer to link address + * Type = LAN protocol type (unused) + */ +{ + PNDIS_PACKET *pNdisPacket; + KIRQL OldIrql; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + /* NDIS send routines don't have an offset argument so we + must offset the data in upper layers and adjust the + packet here. We save the offset in the packet context + area so it can be undone before we release the packet */ + AdjustPacket(NdisPacket, Offset, 0); + PC(NdisPacket)->DLOffset = Offset; + + pNdisPacket = (PNDIS_PACKET*)NdisPacket->MacReserved; + *pNdisPacket = NULL; + + KeAcquireSpinLock(&LoopLock, &OldIrql); + + /* Add packet to transmit queue */ + if (LoopQueueHead) { + /* Transmit queue is not empty */ + pNdisPacket = (PNDIS_PACKET*)LoopQueueTail->MacReserved; + *pNdisPacket = NdisPacket; + } else + /* Transmit queue is empty */ + LoopQueueHead = NdisPacket; + + LoopQueueTail = NdisPacket; + + /* If LoopTransmit is not running (or scheduled), schedule it to run */ + if (!LoopBusy) { + ExQueueWorkItem(&LoopWorkItem, CriticalWorkQueue); + LoopBusy = TRUE; + } + + KeReleaseSpinLock(&LoopLock, OldIrql); +} + + +NDIS_STATUS LoopRegisterAdapter( + PNDIS_STRING AdapterName, + PLAN_ADAPTER *Adapter) +/* + * FUNCTION: Registers loopback adapter + * ARGUMENTS: + * AdapterName = Unused + * Adapter = Unused + * RETURNS: + * Status of operation + */ +{ + PIP_ADDRESS Address; + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + Address = AddrBuildIPv4(LOOPBACK_ADDRESS_IPv4); + if (Address) { + LLIP_BIND_INFO BindInfo; + + /* Bind the adapter to IP layer */ + BindInfo.Context = NULL; + BindInfo.HeaderSize = 0; + BindInfo.MinFrameSize = 0; + BindInfo.MTU = 16384; + BindInfo.Address = NULL; + BindInfo.AddressLength = 0; + BindInfo.Transmit = LoopTransmit; + + Loopback = IPCreateInterface(&BindInfo); + if ((Loopback) && (IPCreateNTE(Loopback, Address, 8))) { + /* Reference the interface for the NTE. The reference for + the address is just passed on to the NTE */ + ReferenceObject(Loopback); + + IPRegisterInterface(Loopback); + + ExInitializeWorkItem(&LoopWorkItem, RealTransmit, Loopback); + + KeInitializeSpinLock(&LoopLock); + LoopBusy = FALSE; + } else + Status = NDIS_STATUS_RESOURCES; + } else + Status = NDIS_STATUS_RESOURCES; + + if (!NT_SUCCESS(Status)) + LoopUnregisterAdapter(NULL); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); + + return Status; +} + + +NDIS_STATUS LoopUnregisterAdapter( + PLAN_ADAPTER Adapter) +/* + * FUNCTION: Unregisters loopback adapter + * ARGUMENTS: + * Adapter = Unused + * RETURNS: + * Status of operation + * NOTES: + * Does not care wether we have registered loopback adapter + */ +{ + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + if (Loopback) { + IPUnregisterInterface(Loopback); + IPDestroyInterface(Loopback); + Loopback = NULL; + } + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); + + return NDIS_STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/address.h b/reactos/drivers/net/tcpip/include/address.h index aeb953d5c90..c8835913c13 100644 --- a/reactos/drivers/net/tcpip/include/address.h +++ b/reactos/drivers/net/tcpip/include/address.h @@ -1,63 +1,63 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/address.h - * PURPOSE: Address manipulation prototypes - */ -#ifndef __ADDRESS_H -#define __ADDRESS_H - - -/* - * Initialize an IPv4 style address - * VOID AddrInitIPv4( - * PIP_ADDRESS IPAddress, - * IPv4_RAW_ADDRESS RawAddress) - */ -#define AddrInitIPv4(IPAddress, RawAddress) \ -{ \ - (IPAddress)->RefCount = 1; \ - (IPAddress)->Type = IP_ADDRESS_V4; \ - (IPAddress)->Address.IPv4Address = (RawAddress); \ -} - - -BOOLEAN AddrIsUnspecified( - PIP_ADDRESS Address); - -NTSTATUS AddrGetAddress( - PTRANSPORT_ADDRESS AddrList, - PIP_ADDRESS *Address, - PUSHORT Port, - PIP_ADDRESS *Cache); - -BOOLEAN AddrIsEqual( - PIP_ADDRESS Address1, - PIP_ADDRESS Address2); - -INT AddrCompare( - PIP_ADDRESS Address1, - PIP_ADDRESS Address2); - -BOOLEAN AddrIsEqualIPv4( - PIP_ADDRESS Address1, - IPv4_RAW_ADDRESS Address2); - -PIP_ADDRESS AddrBuildIPv4( - IPv4_RAW_ADDRESS Address); - -PADDRESS_ENTRY AddrLocateADEv4( - IPv4_RAW_ADDRESS Address); - -PADDRESS_FILE AddrSearchFirst( - PIP_ADDRESS Address, - USHORT Port, - USHORT Protocol, - PAF_SEARCH SearchContext); - -PADDRESS_FILE AddrSearchNext( - PAF_SEARCH SearchContext); - -#endif /* __ADDRESS_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/address.h + * PURPOSE: Address manipulation prototypes + */ +#ifndef __ADDRESS_H +#define __ADDRESS_H + + +/* + * Initialize an IPv4 style address + * VOID AddrInitIPv4( + * PIP_ADDRESS IPAddress, + * IPv4_RAW_ADDRESS RawAddress) + */ +#define AddrInitIPv4(IPAddress, RawAddress) \ +{ \ + (IPAddress)->RefCount = 1; \ + (IPAddress)->Type = IP_ADDRESS_V4; \ + (IPAddress)->Address.IPv4Address = (RawAddress); \ +} + + +BOOLEAN AddrIsUnspecified( + PIP_ADDRESS Address); + +NTSTATUS AddrGetAddress( + PTRANSPORT_ADDRESS AddrList, + PIP_ADDRESS *Address, + PUSHORT Port, + PIP_ADDRESS *Cache); + +BOOLEAN AddrIsEqual( + PIP_ADDRESS Address1, + PIP_ADDRESS Address2); + +INT AddrCompare( + PIP_ADDRESS Address1, + PIP_ADDRESS Address2); + +BOOLEAN AddrIsEqualIPv4( + PIP_ADDRESS Address1, + IPv4_RAW_ADDRESS Address2); + +PIP_ADDRESS AddrBuildIPv4( + IPv4_RAW_ADDRESS Address); + +PADDRESS_ENTRY AddrLocateADEv4( + IPv4_RAW_ADDRESS Address); + +PADDRESS_FILE AddrSearchFirst( + PIP_ADDRESS Address, + USHORT Port, + USHORT Protocol, + PAF_SEARCH SearchContext); + +PADDRESS_FILE AddrSearchNext( + PAF_SEARCH SearchContext); + +#endif /* __ADDRESS_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/arp.h b/reactos/drivers/net/tcpip/include/arp.h index b33ad147b38..bd1c6bfafea 100644 --- a/reactos/drivers/net/tcpip/include/arp.h +++ b/reactos/drivers/net/tcpip/include/arp.h @@ -1,37 +1,37 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/arp.h - * PURPOSE: Address Resolution Protocol definitions - */ -#ifndef __ARP_H -#define __ARP_H - -typedef struct ARP_HEADER { - USHORT HWType; /* Hardware Type */ - USHORT ProtoType; /* Protocol Type */ - UCHAR HWAddrLen; /* Hardware Address Length */ - UCHAR ProtoAddrLen; /* Protocol Address Length */ - USHORT Opcode; /* Opcode */ - /* Sender's Hardware Address */ - /* Sender's Protocol Address */ - /* Target's Hardware Address */ - /* Target's Protocol Address */ -} ARP_HEADER, *PARP_HEADER; - -/* We swap constants so we can compare values at runtime without swapping them */ -#define ARP_OPCODE_REQUEST WH2N(0x0001) /* ARP request */ -#define ARP_OPCODE_REPLY WH2N(0x0002) /* ARP reply */ - - -BOOLEAN ARPTransmit( - PIP_ADDRESS Address, - PNET_TABLE_ENTRY NTE); - -VOID ARPReceive( - PVOID Context, - PIP_PACKET Packet); - -#endif /* __ARP_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/arp.h + * PURPOSE: Address Resolution Protocol definitions + */ +#ifndef __ARP_H +#define __ARP_H + +typedef struct ARP_HEADER { + USHORT HWType; /* Hardware Type */ + USHORT ProtoType; /* Protocol Type */ + UCHAR HWAddrLen; /* Hardware Address Length */ + UCHAR ProtoAddrLen; /* Protocol Address Length */ + USHORT Opcode; /* Opcode */ + /* Sender's Hardware Address */ + /* Sender's Protocol Address */ + /* Target's Hardware Address */ + /* Target's Protocol Address */ +} ARP_HEADER, *PARP_HEADER; + +/* We swap constants so we can compare values at runtime without swapping them */ +#define ARP_OPCODE_REQUEST WH2N(0x0001) /* ARP request */ +#define ARP_OPCODE_REPLY WH2N(0x0002) /* ARP reply */ + + +BOOLEAN ARPTransmit( + PIP_ADDRESS Address, + PNET_TABLE_ENTRY NTE); + +VOID ARPReceive( + PVOID Context, + PIP_PACKET Packet); + +#endif /* __ARP_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/checksum.h b/reactos/drivers/net/tcpip/include/checksum.h index 5805b514c0e..e23c0a5a81d 100644 --- a/reactos/drivers/net/tcpip/include/checksum.h +++ b/reactos/drivers/net/tcpip/include/checksum.h @@ -1,27 +1,27 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/checksum.h - * PURPOSE: Checksum routine definitions - */ -#ifndef __CHECKSUM_H -#define __CHECKSUM_H - - -ULONG ChecksumCompute( - PVOID Data, - UINT Count, - ULONG Seed); - -#define IPv4Checksum(Data, Count, Seed)(ChecksumCompute(Data, Count, Seed)) - -/* - * Macro to check for a correct checksum - * BOOLEAN CorrectChecksum(PVOID Data, UINT Count) - */ -#define CorrectChecksum(Data, Count) \ - (BOOLEAN)(IPv4Checksum(Data, Count, 0) == DH2N(0x0000FFFF)) - -#endif /* __CHECKSUM_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/checksum.h + * PURPOSE: Checksum routine definitions + */ +#ifndef __CHECKSUM_H +#define __CHECKSUM_H + + +ULONG ChecksumCompute( + PVOID Data, + UINT Count, + ULONG Seed); + +#define IPv4Checksum(Data, Count, Seed)(ChecksumCompute(Data, Count, Seed)) + +/* + * Macro to check for a correct checksum + * BOOLEAN CorrectChecksum(PVOID Data, UINT Count) + */ +#define CorrectChecksum(Data, Count) \ + (BOOLEAN)(IPv4Checksum(Data, Count, 0) == DH2N(0x0000FFFF)) + +#endif /* __CHECKSUM_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/datagram.h b/reactos/drivers/net/tcpip/include/datagram.h index 3dd3a7964df..9dc7e656d54 100644 --- a/reactos/drivers/net/tcpip/include/datagram.h +++ b/reactos/drivers/net/tcpip/include/datagram.h @@ -1,49 +1,49 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/datagram.h - * PURPOSE: Datagram types and constants - */ -#ifndef __DATAGRAM_H -#define __DATAGRAM_H - -#include - - -VOID DGSend( - PVOID Context, - PDATAGRAM_SEND_REQUEST SendRequest); - -VOID DGCancelSendRequest( - PADDRESS_FILE AddrFile, - PVOID Context); - -VOID DGCancelReceiveRequest( - PADDRESS_FILE AddrFile, - PVOID Context); - -NTSTATUS DGSendDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG DataSize, - DATAGRAM_BUILD_ROUTINE Build); - -NTSTATUS DGReceiveDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG ReceiveLength, - ULONG ReceiveFlags, - PTDI_CONNECTION_INFORMATION ReturnInfo, - PULONG BytesReceived); - -NTSTATUS DGStartup( - VOID); - -NTSTATUS DGShutdown( - VOID); - -#endif /* __DATAGRAM_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/datagram.h + * PURPOSE: Datagram types and constants + */ +#ifndef __DATAGRAM_H +#define __DATAGRAM_H + +#include + + +VOID DGSend( + PVOID Context, + PDATAGRAM_SEND_REQUEST SendRequest); + +VOID DGCancelSendRequest( + PADDRESS_FILE AddrFile, + PVOID Context); + +VOID DGCancelReceiveRequest( + PADDRESS_FILE AddrFile, + PVOID Context); + +NTSTATUS DGSendDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG DataSize, + DATAGRAM_BUILD_ROUTINE Build); + +NTSTATUS DGReceiveDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG ReceiveLength, + ULONG ReceiveFlags, + PTDI_CONNECTION_INFORMATION ReturnInfo, + PULONG BytesReceived); + +NTSTATUS DGStartup( + VOID); + +NTSTATUS DGShutdown( + VOID); + +#endif /* __DATAGRAM_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/debug.h b/reactos/drivers/net/tcpip/include/debug.h index a296d5ff820..b86b6209306 100644 --- a/reactos/drivers/net/tcpip/include/debug.h +++ b/reactos/drivers/net/tcpip/include/debug.h @@ -1,99 +1,99 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/debug.h - * PURPOSE: Debugging support macros - * DEFINES: DBG - Enable debug output - * NASSERT - Disable assertions - */ -#ifndef __DEBUG_H -#define __DEBUG_H - -#define NORMAL_MASK 0x000000FF -#define SPECIAL_MASK 0xFFFFFF00 -#define MIN_TRACE 0x00000001 -#define MID_TRACE 0x00000002 -#define MAX_TRACE 0x00000003 - -#define DEBUG_MEMORY 0x00000100 -#define DEBUG_BUFFER 0x00000200 -#define DEBUG_IRP 0x00000400 -#define DEBUG_REFCOUNT 0x00000800 -#define DEBUG_ADDRFILE 0x00001000 -#define DEBUG_IP 0x00002000 -#define DEBUG_ROUTER 0x00004000 -#define DEBUG_RCACHE 0x00008000 -#define DEBUG_NCACHE 0x00010000 -#define DEBUG_ULTRA 0xFFFFFFFF - -#ifdef DBG - -extern DWORD DebugTraceLevel; - -#ifdef _MSC_VER - -#define TI_DbgPrint(_t_, _x_) \ - if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \ - ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \ - DbgPrint("(%s:%d) ", __FILE__, __LINE__); \ - DbgPrint _x_ ; \ - } - -#else /* _MSC_VER */ - -#define TI_DbgPrint(_t_, _x_) \ - if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \ - ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \ - DbgPrint("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \ - DbgPrint _x_ ; \ - } - -#endif /* _MSC_VER */ - -#ifdef ASSERT -#undef ASSERT -#endif - -#ifdef NASSERT -#define ASSERT(x) -#else /* NASSERT */ -#define ASSERT(x) if (!(x)) { TI_DbgPrint(MIN_TRACE, ("Assertion "#x" failed at %s:%d\n", __FILE__, __LINE__)); KeBugCheck(0); } -#endif /* NASSERT */ - -#define ASSERT_IRQL(x) ASSERT(KeGetCurrentIrql() <= (x)) - -#else /* DBG */ - -#define TI_DbgPrint(_t_, _x_) - -#define ASSERT_IRQL(x) -#define ASSERT(x) - -#endif /* DBG */ - - -#define assert(x) ASSERT(x) -#define assert_irql(x) ASSERT_IRQL(x) - - -#ifdef _MSC_VER - -#define UNIMPLEMENTED \ - TI_DbgPrint(MIN_TRACE, ("The function at %s:%d is unimplemented, \ - but come back another day.\n", __FILE__, __LINE__)); - -#else /* _MSC_VER */ - -#define UNIMPLEMENTED \ - TI_DbgPrint(MIN_TRACE, ("(%s:%d)(%s) is unimplemented, \ - but come back another day.\n", __FILE__, __LINE__, __FUNCTION__)); - -#endif /* _MSC_VER */ - - -#define CHECKPOINT \ - do { TI_DbgPrint(MIN_TRACE, ("(%s:%d)\n", __FILE__, __LINE__)); } while(0); - -#endif /* __DEBUG_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/debug.h + * PURPOSE: Debugging support macros + * DEFINES: DBG - Enable debug output + * NASSERT - Disable assertions + */ +#ifndef __DEBUG_H +#define __DEBUG_H + +#define NORMAL_MASK 0x000000FF +#define SPECIAL_MASK 0xFFFFFF00 +#define MIN_TRACE 0x00000001 +#define MID_TRACE 0x00000002 +#define MAX_TRACE 0x00000003 + +#define DEBUG_MEMORY 0x00000100 +#define DEBUG_BUFFER 0x00000200 +#define DEBUG_IRP 0x00000400 +#define DEBUG_REFCOUNT 0x00000800 +#define DEBUG_ADDRFILE 0x00001000 +#define DEBUG_IP 0x00002000 +#define DEBUG_ROUTER 0x00004000 +#define DEBUG_RCACHE 0x00008000 +#define DEBUG_NCACHE 0x00010000 +#define DEBUG_ULTRA 0xFFFFFFFF + +#ifdef DBG + +extern DWORD DebugTraceLevel; + +#ifdef _MSC_VER + +#define TI_DbgPrint(_t_, _x_) \ + if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \ + ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \ + DbgPrint("(%s:%d) ", __FILE__, __LINE__); \ + DbgPrint _x_ ; \ + } + +#else /* _MSC_VER */ + +#define TI_DbgPrint(_t_, _x_) \ + if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \ + ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \ + DbgPrint("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \ + DbgPrint _x_ ; \ + } + +#endif /* _MSC_VER */ + +#ifdef ASSERT +#undef ASSERT +#endif + +#ifdef NASSERT +#define ASSERT(x) +#else /* NASSERT */ +#define ASSERT(x) if (!(x)) { TI_DbgPrint(MIN_TRACE, ("Assertion "#x" failed at %s:%d\n", __FILE__, __LINE__)); KeBugCheck(0); } +#endif /* NASSERT */ + +#define ASSERT_IRQL(x) ASSERT(KeGetCurrentIrql() <= (x)) + +#else /* DBG */ + +#define TI_DbgPrint(_t_, _x_) + +#define ASSERT_IRQL(x) +#define ASSERT(x) + +#endif /* DBG */ + + +#define assert(x) ASSERT(x) +#define assert_irql(x) ASSERT_IRQL(x) + + +#ifdef _MSC_VER + +#define UNIMPLEMENTED \ + TI_DbgPrint(MIN_TRACE, ("The function at %s:%d is unimplemented, \ + but come back another day.\n", __FILE__, __LINE__)); + +#else /* _MSC_VER */ + +#define UNIMPLEMENTED \ + TI_DbgPrint(MIN_TRACE, ("(%s:%d)(%s) is unimplemented, \ + but come back another day.\n", __FILE__, __LINE__, __FUNCTION__)); + +#endif /* _MSC_VER */ + + +#define CHECKPOINT \ + do { TI_DbgPrint(MIN_TRACE, ("(%s:%d)\n", __FILE__, __LINE__)); } while(0); + +#endif /* __DEBUG_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/dispatch.h b/reactos/drivers/net/tcpip/include/dispatch.h index 9f704859517..5108ff55695 100644 --- a/reactos/drivers/net/tcpip/include/dispatch.h +++ b/reactos/drivers/net/tcpip/include/dispatch.h @@ -1,61 +1,61 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/dispatch.h - * PURPOSE: Dispatch routine prototypes - */ -#ifndef __DISPATCH_H -#define __DISPATCH_H - - -NTSTATUS DispTdiAccept( - PIRP Irp); - -NTSTATUS DispTdiAssociateAddress( - PIRP Irp); - -NTSTATUS DispTdiConnect( - PIRP Irp); - -NTSTATUS DispTdiDisassociateAddress( - PIRP Irp); - -NTSTATUS DispTdiDisconnect( - PIRP Irp); - -NTSTATUS DispTdiListen( - PIRP Irp); - -NTSTATUS DispTdiQueryInformation( - PDEVICE_OBJECT DeviceObject, - PIRP Irp); - -NTSTATUS DispTdiReceive( - PIRP Irp); - -NTSTATUS DispTdiReceiveDatagram( - PIRP Irp); - -NTSTATUS DispTdiSend( - PIRP Irp); - -NTSTATUS DispTdiSendDatagram( - PIRP Irp); - -NTSTATUS DispTdiSetEventHandler( - PIRP Irp); - -NTSTATUS DispTdiSetInformation( - PIRP Irp); - -NTSTATUS DispTdiQueryInformationEx( - PIRP Irp, - PIO_STACK_LOCATION IrpSp); - -NTSTATUS DispTdiSetInformationEx( - PIRP Irp, - PIO_STACK_LOCATION IrpSp); - -#endif /* __DISPATCH_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/dispatch.h + * PURPOSE: Dispatch routine prototypes + */ +#ifndef __DISPATCH_H +#define __DISPATCH_H + + +NTSTATUS DispTdiAccept( + PIRP Irp); + +NTSTATUS DispTdiAssociateAddress( + PIRP Irp); + +NTSTATUS DispTdiConnect( + PIRP Irp); + +NTSTATUS DispTdiDisassociateAddress( + PIRP Irp); + +NTSTATUS DispTdiDisconnect( + PIRP Irp); + +NTSTATUS DispTdiListen( + PIRP Irp); + +NTSTATUS DispTdiQueryInformation( + PDEVICE_OBJECT DeviceObject, + PIRP Irp); + +NTSTATUS DispTdiReceive( + PIRP Irp); + +NTSTATUS DispTdiReceiveDatagram( + PIRP Irp); + +NTSTATUS DispTdiSend( + PIRP Irp); + +NTSTATUS DispTdiSendDatagram( + PIRP Irp); + +NTSTATUS DispTdiSetEventHandler( + PIRP Irp); + +NTSTATUS DispTdiSetInformation( + PIRP Irp); + +NTSTATUS DispTdiQueryInformationEx( + PIRP Irp, + PIO_STACK_LOCATION IrpSp); + +NTSTATUS DispTdiSetInformationEx( + PIRP Irp, + PIO_STACK_LOCATION IrpSp); + +#endif /* __DISPATCH_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/fileobjs.h b/reactos/drivers/net/tcpip/include/fileobjs.h index e69e5fe1e53..caef8e828bf 100644 --- a/reactos/drivers/net/tcpip/include/fileobjs.h +++ b/reactos/drivers/net/tcpip/include/fileobjs.h @@ -1,32 +1,32 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/fileobjs.h - * PURPOSE: File object routine prototypes - */ -#ifndef __FILEOBJS_H -#define __FILEOBJS_H - - -extern LIST_ENTRY AddressFileListHead; -extern KSPIN_LOCK AddressFileListLock; - - -NTSTATUS FileOpenAddress( - PTDI_REQUEST Request, - PTA_ADDRESS_IP AddrList, - USHORT Protocol, - PVOID Options); - -NTSTATUS FileCloseAddress( - PTDI_REQUEST Request); - -NTSTATUS FileCloseConnection( - PTDI_REQUEST Request); - -NTSTATUS FileCloseControlChannel( - PTDI_REQUEST Request); - -#endif /* __FILEOBJS_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/fileobjs.h + * PURPOSE: File object routine prototypes + */ +#ifndef __FILEOBJS_H +#define __FILEOBJS_H + + +extern LIST_ENTRY AddressFileListHead; +extern KSPIN_LOCK AddressFileListLock; + + +NTSTATUS FileOpenAddress( + PTDI_REQUEST Request, + PTA_ADDRESS_IP AddrList, + USHORT Protocol, + PVOID Options); + +NTSTATUS FileCloseAddress( + PTDI_REQUEST Request); + +NTSTATUS FileCloseConnection( + PTDI_REQUEST Request); + +NTSTATUS FileCloseControlChannel( + PTDI_REQUEST Request); + +#endif /* __FILEOBJS_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/icmp.h b/reactos/drivers/net/tcpip/include/icmp.h index 225e62de449..10bd22cd9fc 100644 --- a/reactos/drivers/net/tcpip/include/icmp.h +++ b/reactos/drivers/net/tcpip/include/icmp.h @@ -1,68 +1,68 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/icmp.h - * PURPOSE: Internet Control Message Protocol definitions - */ -#ifndef __ICMP_H -#define __ICMP_H - -typedef struct ICMP_HEADER { - UCHAR Type; /* ICMP message type */ - UCHAR Code; /* ICMP message code */ - USHORT Checksum; /* ICMP message checksum */ - ULONG Unused; /* ICMP unused */ -} ICMP_HEADER, *PICMP_HEADER; - -/* ICMP message types */ -#define ICMP_TYPE_ECHO_REPLY 0 /* Echo reply */ -#define ICMP_TYPE_DEST_UNREACH 3 /* Destination unreachable */ -#define ICMP_TYPE_SOURCE_QUENCH 4 /* Source quench */ -#define ICMP_TYPE_REDIRECT 5 /* Redirect */ -#define ICMP_TYPE_ECHO_REQUEST 8 /* Echo request */ -#define ICMP_TYPE_TIME_EXCEEDED 11 /* Time exceeded */ -#define ICMP_TYPE_PARAMETER 12 /* Parameter problem */ -#define ICMP_TYPE_TIMESTAMP_REQUEST 13 /* Timestamp request */ -#define ICMP_TYPE_TIMESTAMP_REPLY 14 /* Timestamp reply */ -#define ICMP_TYPE_INFO_REQUEST 15 /* Information request */ -#define ICMP_TYPE_INFO_REPLY 16 /* Information reply */ - -/* ICMP codes for ICMP_TYPE_DEST_UNREACH */ -#define ICMP_CODE_DU_NET_UNREACH 0 /* Network unreachable */ -#define ICMP_CODE_DU_HOST_UNREACH 1 /* Host unreachable */ -#define ICMP_CODE_DU_PROTOCOL_UNREACH 2 /* Protocol unreachable */ -#define ICMP_CODE_DU_PORT_UNREACH 3 /* Port unreachable */ -#define ICMP_CODE_DU_FRAG_DF_SET 4 /* Fragmentation needed and DF set */ -#define ICMP_CODE_DU_SOURCE_ROUTE_FAILED 5 /* Source route failed */ - -/* ICMP codes for ICMP_TYPE_REDIRECT */ -#define ICMP_CODE_RD_NET 0 /* Redirect datagrams for the network */ -#define ICMP_CODE_RD_HOST 1 /* Redirect datagrams for the host */ -#define ICMP_CODE_RD_TOS_NET 2 /* Redirect datagrams for the Type of Service and network */ -#define ICMP_CODE_RD_TOS_HOST 3 /* Redirect datagrams for the Type of Service and host */ - -/* ICMP codes for ICMP_TYPE_TIME_EXCEEDED */ -#define ICMP_CODE_TE_TTL 0 /* Time to live exceeded in transit */ -#define ICMP_CODE_TE_REASSEMBLY 1 /* Fragment reassembly time exceeded */ - -/* ICMP codes for ICMP_TYPE_PARAMETER */ -#define ICMP_CODE_TP_POINTER 1 /* Pointer indicates the error */ - - -VOID ICMPReceive( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket); - -VOID ICMPTransmit( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket); - -VOID ICMPReply( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket, - UCHAR Type, - UCHAR Code); - -#endif /* __ICMP_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/icmp.h + * PURPOSE: Internet Control Message Protocol definitions + */ +#ifndef __ICMP_H +#define __ICMP_H + +typedef struct ICMP_HEADER { + UCHAR Type; /* ICMP message type */ + UCHAR Code; /* ICMP message code */ + USHORT Checksum; /* ICMP message checksum */ + ULONG Unused; /* ICMP unused */ +} ICMP_HEADER, *PICMP_HEADER; + +/* ICMP message types */ +#define ICMP_TYPE_ECHO_REPLY 0 /* Echo reply */ +#define ICMP_TYPE_DEST_UNREACH 3 /* Destination unreachable */ +#define ICMP_TYPE_SOURCE_QUENCH 4 /* Source quench */ +#define ICMP_TYPE_REDIRECT 5 /* Redirect */ +#define ICMP_TYPE_ECHO_REQUEST 8 /* Echo request */ +#define ICMP_TYPE_TIME_EXCEEDED 11 /* Time exceeded */ +#define ICMP_TYPE_PARAMETER 12 /* Parameter problem */ +#define ICMP_TYPE_TIMESTAMP_REQUEST 13 /* Timestamp request */ +#define ICMP_TYPE_TIMESTAMP_REPLY 14 /* Timestamp reply */ +#define ICMP_TYPE_INFO_REQUEST 15 /* Information request */ +#define ICMP_TYPE_INFO_REPLY 16 /* Information reply */ + +/* ICMP codes for ICMP_TYPE_DEST_UNREACH */ +#define ICMP_CODE_DU_NET_UNREACH 0 /* Network unreachable */ +#define ICMP_CODE_DU_HOST_UNREACH 1 /* Host unreachable */ +#define ICMP_CODE_DU_PROTOCOL_UNREACH 2 /* Protocol unreachable */ +#define ICMP_CODE_DU_PORT_UNREACH 3 /* Port unreachable */ +#define ICMP_CODE_DU_FRAG_DF_SET 4 /* Fragmentation needed and DF set */ +#define ICMP_CODE_DU_SOURCE_ROUTE_FAILED 5 /* Source route failed */ + +/* ICMP codes for ICMP_TYPE_REDIRECT */ +#define ICMP_CODE_RD_NET 0 /* Redirect datagrams for the network */ +#define ICMP_CODE_RD_HOST 1 /* Redirect datagrams for the host */ +#define ICMP_CODE_RD_TOS_NET 2 /* Redirect datagrams for the Type of Service and network */ +#define ICMP_CODE_RD_TOS_HOST 3 /* Redirect datagrams for the Type of Service and host */ + +/* ICMP codes for ICMP_TYPE_TIME_EXCEEDED */ +#define ICMP_CODE_TE_TTL 0 /* Time to live exceeded in transit */ +#define ICMP_CODE_TE_REASSEMBLY 1 /* Fragment reassembly time exceeded */ + +/* ICMP codes for ICMP_TYPE_PARAMETER */ +#define ICMP_CODE_TP_POINTER 1 /* Pointer indicates the error */ + + +VOID ICMPReceive( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket); + +VOID ICMPTransmit( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket); + +VOID ICMPReply( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket, + UCHAR Type, + UCHAR Code); + +#endif /* __ICMP_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/info.h b/reactos/drivers/net/tcpip/include/info.h index 1fd37d69225..a1b4f679ac4 100644 --- a/reactos/drivers/net/tcpip/include/info.h +++ b/reactos/drivers/net/tcpip/include/info.h @@ -1,93 +1,93 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/info.h - * PURPOSE: TdiQueryInformation definitions - */ -#ifndef __INFO_H -#define __INFO_H - - -typedef struct IPSNMP_INFO { - ULONG Forwarding; - ULONG DefaultTTL; - ULONG InReceives; - ULONG InHdrErrors; - ULONG InAddrErrors; - ULONG ForwDatagrams; - ULONG InUnknownProtos; - ULONG InDiscards; - ULONG InDelivers; - ULONG OutRequests; - ULONG RoutingDiscards; - ULONG OutDiscards; - ULONG OutNoRoutes; - ULONG ReasmTimeout; - ULONG ReasmReqds; - ULONG ReasmOks; - ULONG ReasmFails; - ULONG FragOks; - ULONG FragFails; - ULONG FragCreates; - ULONG NumIf; - ULONG NumAddr; - ULONG NumRoutes; -} IPSNMP_INFO, *PIPSNMP_INFO; - -typedef struct IPADDR_ENTRY { - ULONG Addr; - ULONG Index; - ULONG Mask; - ULONG BcastAddr; - ULONG ReasmSize; - USHORT Context; - USHORT Pad; -} IPADDR_ENTRY, *PIPADDR_ENTRY; - -#define IP_MIB_STATS_ID 1 -#define IP_MIB_ADDRTABLE_ENTRY_ID 0x102 - -#define MAX_PHYSADDR_SIZE 8 - - -/* Only UDP is supported */ -#define TDI_SERVICE_FLAGS (TDI_SERVICE_CONNECTIONLESS_MODE | \ - TDI_SERVICE_BROADCAST_SUPPORTED) - -#define TCP_MIB_STAT_ID 1 -#define UDP_MIB_STAT_ID 1 -#define TCP_MIB_TABLE_ID 0x101 -#define UDP_MIB_TABLE_ID 0x101 - -#define TL_INSTANCE 0 - - -typedef struct ADDRESS_INFO { - ULONG LocalAddress; - ULONG LocalPort; -} ADDRESS_INFO, *PADDRESS_INFO; - -typedef union TDI_INFO { - TDI_CONNECTION_INFO ConnInfo; - TDI_ADDRESS_INFO AddrInfo; - TDI_PROVIDER_INFO ProviderInfo; - TDI_PROVIDER_STATISTICS ProviderStats; -} TDI_INFO, *PTDI_INFO; - - -TDI_STATUS InfoTdiQueryInformationEx( - PTDI_REQUEST Request, - TDIObjectID *ID, - PNDIS_BUFFER Buffer, - PUINT BufferSize, - PVOID Context); - -TDI_STATUS InfoTdiSetInformationEx( - PTDI_REQUEST Request, - TDIObjectID *ID, - PVOID Buffer, - UINT BufferSize); - -#endif /* __INFO_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/info.h + * PURPOSE: TdiQueryInformation definitions + */ +#ifndef __INFO_H +#define __INFO_H + + +typedef struct IPSNMP_INFO { + ULONG Forwarding; + ULONG DefaultTTL; + ULONG InReceives; + ULONG InHdrErrors; + ULONG InAddrErrors; + ULONG ForwDatagrams; + ULONG InUnknownProtos; + ULONG InDiscards; + ULONG InDelivers; + ULONG OutRequests; + ULONG RoutingDiscards; + ULONG OutDiscards; + ULONG OutNoRoutes; + ULONG ReasmTimeout; + ULONG ReasmReqds; + ULONG ReasmOks; + ULONG ReasmFails; + ULONG FragOks; + ULONG FragFails; + ULONG FragCreates; + ULONG NumIf; + ULONG NumAddr; + ULONG NumRoutes; +} IPSNMP_INFO, *PIPSNMP_INFO; + +typedef struct IPADDR_ENTRY { + ULONG Addr; + ULONG Index; + ULONG Mask; + ULONG BcastAddr; + ULONG ReasmSize; + USHORT Context; + USHORT Pad; +} IPADDR_ENTRY, *PIPADDR_ENTRY; + +#define IP_MIB_STATS_ID 1 +#define IP_MIB_ADDRTABLE_ENTRY_ID 0x102 + +#define MAX_PHYSADDR_SIZE 8 + + +/* Only UDP is supported */ +#define TDI_SERVICE_FLAGS (TDI_SERVICE_CONNECTIONLESS_MODE | \ + TDI_SERVICE_BROADCAST_SUPPORTED) + +#define TCP_MIB_STAT_ID 1 +#define UDP_MIB_STAT_ID 1 +#define TCP_MIB_TABLE_ID 0x101 +#define UDP_MIB_TABLE_ID 0x101 + +#define TL_INSTANCE 0 + + +typedef struct ADDRESS_INFO { + ULONG LocalAddress; + ULONG LocalPort; +} ADDRESS_INFO, *PADDRESS_INFO; + +typedef union TDI_INFO { + TDI_CONNECTION_INFO ConnInfo; + TDI_ADDRESS_INFO AddrInfo; + TDI_PROVIDER_INFO ProviderInfo; + TDI_PROVIDER_STATISTICS ProviderStats; +} TDI_INFO, *PTDI_INFO; + + +TDI_STATUS InfoTdiQueryInformationEx( + PTDI_REQUEST Request, + TDIObjectID *ID, + PNDIS_BUFFER Buffer, + PUINT BufferSize, + PVOID Context); + +TDI_STATUS InfoTdiSetInformationEx( + PTDI_REQUEST Request, + TDIObjectID *ID, + PVOID Buffer, + UINT BufferSize); + +#endif /* __INFO_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/ip.h b/reactos/drivers/net/tcpip/include/ip.h index 4cbcd190b35..3ee693a74f4 100644 --- a/reactos/drivers/net/tcpip/include/ip.h +++ b/reactos/drivers/net/tcpip/include/ip.h @@ -1,245 +1,245 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/ip.h - * PURPOSE: Internet Protocol related definitions - */ -#ifndef __IP_H -#define __IP_H - -/* Raw IPv4 style address */ -typedef ULONG IPv4_RAW_ADDRESS; -typedef IPv4_RAW_ADDRESS *PIPv4_RAW_ADDRESS; - -/* Raw IPv6 style address */ -typedef USHORT IPv6_RAW_ADDRESS[8]; -typedef IPv6_RAW_ADDRESS *PIPv6_RAW_ADDRESS; - -/* IP style address */ -typedef struct IP_ADDRESS { - ULONG RefCount; /* Number of references to this address */ - UCHAR Type; /* Type of IP address */ - union { - IPv4_RAW_ADDRESS IPv4Address; /* IPv4 address */ - PIPv6_RAW_ADDRESS IPv6Address; /* IPv6 address */ - } Address; -} IP_ADDRESS, *PIP_ADDRESS; - -/* IP type constants */ -#define IP_ADDRESS_V4 0x00 /* IPv4 style address */ -#define IP_ADDRESS_V6 0x01 /* IPv6 style address */ - - -/* IPv4 header format */ -typedef struct IPv4_HEADER { - UCHAR VerIHL; /* 4-bit version, 4-bit Internet Header Length */ - UCHAR Tos; /* Type of Service */ - USHORT TotalLength; /* Total Length */ - USHORT Id; /* Identification */ - USHORT FlagsFragOfs; /* 3-bit Flags, 13-bit Fragment Offset */ - UCHAR Ttl; /* Time to Live */ - UCHAR Protocol; /* Protocol */ - USHORT Checksum; /* Header Checksum */ - IPv4_RAW_ADDRESS SrcAddr; /* Source Address */ - IPv4_RAW_ADDRESS DstAddr; /* Destination Address */ -} IPv4_HEADER, *PIPv4_HEADER; - -#define IPv4_FRAGOFS_MASK 0x1FFF -#define IPv4_MF_MASK 0x2000 -#define IPv4_MAX_HEADER_SIZE 60 - -/* Packet completion handler prototype */ -typedef VOID (*PACKET_COMPLETION_ROUTINE)( - PVOID Context, - PNDIS_PACKET NdisPacket, - NDIS_STATUS NdisStatus); - -/* Structure for an IP packet */ -typedef struct IP_PACKET { - ULONG RefCount; /* Reference count for this object */ - UCHAR Type; /* Type of IP packet (see IP_ADDRESS_xx above) */ - PVOID Header; /* Pointer to IP header for this packet */ - UINT HeaderSize; /* Size of IP header */ - PVOID Data; /* Current pointer into packet data */ - UINT TotalSize; /* Total amount of data in packet (IP header and data) */ - UINT ContigSize; /* Number of contiguous bytes left in current buffer */ - UINT Position; /* Current logical offset into packet */ - PNDIS_PACKET NdisPacket; /* Pointer to NDIS packet */ - IP_ADDRESS SrcAddr; /* Source address */ - IP_ADDRESS DstAddr; /* Destination address */ -} IP_PACKET, *PIP_PACKET; - -/* Packet context */ -typedef struct PACKET_CONTEXT { - PACKET_COMPLETION_ROUTINE Complete; /* Transport level completion handler */ - PVOID Context; /* Context information for handler */ - PACKET_COMPLETION_ROUTINE DLComplete; /* Data link level completion handler. Also - used to link to next packet in a queue */ - UINT DLOffset; /* Offset where data (IP header) starts */ -} PACKET_CONTEXT, *PPACKET_CONTEXT; - -/* The ProtocolReserved field is structured as a PACKET_CONTEXT */ -#define PC(Packet) ((PPACKET_CONTEXT)(&Packet->ProtocolReserved)) - - -/* Address information a.k.a ADE */ -typedef struct _ADDRESS_ENTRY { - LIST_ENTRY ListEntry; /* Entry on list */ - ULONG RefCount; /* Reference count */ - struct _NET_TABLE_ENTRY *NTE; /* NTE associated with this address */ - UCHAR Type; /* Address type */ - PIP_ADDRESS Address; /* Pointer to address identifying this entry */ -} ADDRESS_ENTRY, *PADDRESS_ENTRY; - -/* Values for address type */ -#define ADE_UNICAST 0x01 -#define ADE_MULTICAST 0x02 -#define ADE_ADDRMASK 0x03 - -/* There is one NTE for each source (unicast) address assigned to an interface */ -typedef struct _NET_TABLE_ENTRY { - LIST_ENTRY IFListEntry; /* Entry on interface list */ - LIST_ENTRY NTListEntry; /* Entry on net table list */ - struct _IP_INTERFACE *Interface; /* Pointer to interface on this net */ - struct _PREFIX_LIST_ENTRY *PLE; /* Pointer to prefix list entry for this net */ - ULONG RefCount; /* Reference count */ - PIP_ADDRESS Address; /* Pointer to unicast address for this net */ -} NET_TABLE_ENTRY, *PNET_TABLE_ENTRY; - - -/* Link layer transmit prototype */ -typedef VOID (*LL_TRANSMIT_ROUTINE)( - PVOID Context, - PNDIS_PACKET NdisPacket, - UINT Offset, - PVOID LinkAddress, - USHORT Type); - -/* Link layer to IP binding information */ -typedef struct _LLIP_BIND_INFO { - PVOID Context; /* Pointer to link layer context information */ - UINT HeaderSize; /* Size of link level header */ - UINT MinFrameSize; /* Minimum frame size in bytes */ - UINT MTU; /* Maximum transmission unit */ - PUCHAR Address; /* Pointer to interface address */ - UINT AddressLength; /* Length of address in bytes */ - LL_TRANSMIT_ROUTINE Transmit; /* Transmit function for this interface */ -} LLIP_BIND_INFO, *PLLIP_BIND_INFO; - - -/* Information about an IP interface */ -typedef struct _IP_INTERFACE { - LIST_ENTRY ListEntry; /* Entry on list */ - ULONG RefCount; /* Reference count */ - KSPIN_LOCK Lock; /* Spin lock for this object */ - LIST_ENTRY NTEListHead; /* List of NTEs on this interface */ - LIST_ENTRY ADEListHead; /* List of ADEs on this interface */ - PVOID Context; /* Pointer to link layer context information */ - UINT HeaderSize; /* Size of link level header */ - UINT MinFrameSize; /* Minimum frame size in bytes */ - UINT MTU; /* Maximum transmission unit */ - PUCHAR Address; /* Pointer to interface address */ - UINT AddressLength; /* Length of address in bytes */ - LL_TRANSMIT_ROUTINE Transmit; /* Pointer to transmit function */ -} IP_INTERFACE, *PIP_INTERFACE; - - -/* Prefix List Entry */ -typedef struct _PREFIX_LIST_ENTRY { - LIST_ENTRY ListEntry; /* Entry on list */ - ULONG RefCount; /* Reference count */ - PIP_INTERFACE Interface; /* Pointer to interface */ - PIP_ADDRESS Prefix; /* Pointer to prefix */ - UINT PrefixLength; /* Length of prefix */ -} PREFIX_LIST_ENTRY, *PPREFIX_LIST_ENTRY; - - -#define IP_PROTOCOL_TABLE_SIZE 0x100 - -typedef VOID (*IP_PROTOCOL_HANDLER)( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket); - -/* Loopback adapter address information (network byte order) */ -#define LOOPBACK_ADDRESS_IPv4 ((IPv4_RAW_ADDRESS)DH2N(0x7F000001)) -#define LOOPBACK_BCASTADDR_IPv4 ((IPv4_RAW_ADDRESS)DH2N(0x7F0000FF)) -#define LOOPBACK_ADDRMASK_IPv4 ((IPv4_RAW_ADDRESS)DH2N(0xFFFFFF00)) - -/* Protocol definitions */ -#define IPPROTO_ICMP 1 /* Internet Control Message Protocol */ -#define IPPROTO_IGMP 2 /* Internet Group Management Protocol */ -#define IPPROTO_TCP 6 /* Transmission Control Protocol */ -#define IPPROTO_UDP 17 /* User Datagram Protocol */ - -/* Timeout timer constants */ -#define IP_TICKS_SECOND 2 /* Two ticks per second */ -#define IP_TIMEOUT (1000 / IP_TICKS_SECOND) /* Timeout in milliseconds */ - - -extern LIST_ENTRY InterfaceListHead; -extern KSPIN_LOCK InterfaceListLock; -extern LIST_ENTRY NetTableListHead; -extern KSPIN_LOCK NetTableListLock; -extern LIST_ENTRY PrefixListHead; -extern KSPIN_LOCK PrefixListLock; -extern UINT MaxLLHeaderSize; -extern UINT MinLLFrameSize; - - -PNET_TABLE_ENTRY IPCreateNTE( - PIP_INTERFACE IF, - PIP_ADDRESS Address, - UINT PrefixLength); - -PIP_INTERFACE IPCreateInterface( - PLLIP_BIND_INFO BindInfo); - -VOID IPDestroyInterface( - PIP_INTERFACE IF); - -BOOLEAN IPRegisterInterface( - PIP_INTERFACE IF); - -VOID IPUnregisterInterface( - PIP_INTERFACE IF); - -PNET_TABLE_ENTRY IPLocateNTEOnInterface( - PIP_INTERFACE IF, - PIP_ADDRESS Address, - PUINT AddressType); - -PNET_TABLE_ENTRY IPLocateNTE( - PIP_ADDRESS Address, - PUINT AddressType); - -PADDRESS_ENTRY IPLocateADE( - PIP_ADDRESS Address, - UINT AddressType); - -PADDRESS_ENTRY IPGetDefaultADE( - UINT AddressType); - -VOID IPTimeout( - PKDPC Dpc, - PVOID DeferredContext, - PVOID SystemArgument1, - PVOID SystemArgument2); - -VOID IPDispatchProtocol( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket); - -VOID IPRegisterProtocol( - UINT ProtocolNumber, - IP_PROTOCOL_HANDLER Handler); - -NTSTATUS IPStartup( - PDRIVER_OBJECT DriverObject, - PUNICODE_STRING RegistryPath); - -NTSTATUS IPShutdown( - VOID); - -#endif /* __IP_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/ip.h + * PURPOSE: Internet Protocol related definitions + */ +#ifndef __IP_H +#define __IP_H + +/* Raw IPv4 style address */ +typedef ULONG IPv4_RAW_ADDRESS; +typedef IPv4_RAW_ADDRESS *PIPv4_RAW_ADDRESS; + +/* Raw IPv6 style address */ +typedef USHORT IPv6_RAW_ADDRESS[8]; +typedef IPv6_RAW_ADDRESS *PIPv6_RAW_ADDRESS; + +/* IP style address */ +typedef struct IP_ADDRESS { + ULONG RefCount; /* Number of references to this address */ + UCHAR Type; /* Type of IP address */ + union { + IPv4_RAW_ADDRESS IPv4Address; /* IPv4 address */ + PIPv6_RAW_ADDRESS IPv6Address; /* IPv6 address */ + } Address; +} IP_ADDRESS, *PIP_ADDRESS; + +/* IP type constants */ +#define IP_ADDRESS_V4 0x00 /* IPv4 style address */ +#define IP_ADDRESS_V6 0x01 /* IPv6 style address */ + + +/* IPv4 header format */ +typedef struct IPv4_HEADER { + UCHAR VerIHL; /* 4-bit version, 4-bit Internet Header Length */ + UCHAR Tos; /* Type of Service */ + USHORT TotalLength; /* Total Length */ + USHORT Id; /* Identification */ + USHORT FlagsFragOfs; /* 3-bit Flags, 13-bit Fragment Offset */ + UCHAR Ttl; /* Time to Live */ + UCHAR Protocol; /* Protocol */ + USHORT Checksum; /* Header Checksum */ + IPv4_RAW_ADDRESS SrcAddr; /* Source Address */ + IPv4_RAW_ADDRESS DstAddr; /* Destination Address */ +} IPv4_HEADER, *PIPv4_HEADER; + +#define IPv4_FRAGOFS_MASK 0x1FFF +#define IPv4_MF_MASK 0x2000 +#define IPv4_MAX_HEADER_SIZE 60 + +/* Packet completion handler prototype */ +typedef VOID (*PACKET_COMPLETION_ROUTINE)( + PVOID Context, + PNDIS_PACKET NdisPacket, + NDIS_STATUS NdisStatus); + +/* Structure for an IP packet */ +typedef struct IP_PACKET { + ULONG RefCount; /* Reference count for this object */ + UCHAR Type; /* Type of IP packet (see IP_ADDRESS_xx above) */ + PVOID Header; /* Pointer to IP header for this packet */ + UINT HeaderSize; /* Size of IP header */ + PVOID Data; /* Current pointer into packet data */ + UINT TotalSize; /* Total amount of data in packet (IP header and data) */ + UINT ContigSize; /* Number of contiguous bytes left in current buffer */ + UINT Position; /* Current logical offset into packet */ + PNDIS_PACKET NdisPacket; /* Pointer to NDIS packet */ + IP_ADDRESS SrcAddr; /* Source address */ + IP_ADDRESS DstAddr; /* Destination address */ +} IP_PACKET, *PIP_PACKET; + +/* Packet context */ +typedef struct PACKET_CONTEXT { + PACKET_COMPLETION_ROUTINE Complete; /* Transport level completion handler */ + PVOID Context; /* Context information for handler */ + PACKET_COMPLETION_ROUTINE DLComplete; /* Data link level completion handler. Also + used to link to next packet in a queue */ + UINT DLOffset; /* Offset where data (IP header) starts */ +} PACKET_CONTEXT, *PPACKET_CONTEXT; + +/* The ProtocolReserved field is structured as a PACKET_CONTEXT */ +#define PC(Packet) ((PPACKET_CONTEXT)(&Packet->ProtocolReserved)) + + +/* Address information a.k.a ADE */ +typedef struct _ADDRESS_ENTRY { + LIST_ENTRY ListEntry; /* Entry on list */ + ULONG RefCount; /* Reference count */ + struct _NET_TABLE_ENTRY *NTE; /* NTE associated with this address */ + UCHAR Type; /* Address type */ + PIP_ADDRESS Address; /* Pointer to address identifying this entry */ +} ADDRESS_ENTRY, *PADDRESS_ENTRY; + +/* Values for address type */ +#define ADE_UNICAST 0x01 +#define ADE_MULTICAST 0x02 +#define ADE_ADDRMASK 0x03 + +/* There is one NTE for each source (unicast) address assigned to an interface */ +typedef struct _NET_TABLE_ENTRY { + LIST_ENTRY IFListEntry; /* Entry on interface list */ + LIST_ENTRY NTListEntry; /* Entry on net table list */ + struct _IP_INTERFACE *Interface; /* Pointer to interface on this net */ + struct _PREFIX_LIST_ENTRY *PLE; /* Pointer to prefix list entry for this net */ + ULONG RefCount; /* Reference count */ + PIP_ADDRESS Address; /* Pointer to unicast address for this net */ +} NET_TABLE_ENTRY, *PNET_TABLE_ENTRY; + + +/* Link layer transmit prototype */ +typedef VOID (*LL_TRANSMIT_ROUTINE)( + PVOID Context, + PNDIS_PACKET NdisPacket, + UINT Offset, + PVOID LinkAddress, + USHORT Type); + +/* Link layer to IP binding information */ +typedef struct _LLIP_BIND_INFO { + PVOID Context; /* Pointer to link layer context information */ + UINT HeaderSize; /* Size of link level header */ + UINT MinFrameSize; /* Minimum frame size in bytes */ + UINT MTU; /* Maximum transmission unit */ + PUCHAR Address; /* Pointer to interface address */ + UINT AddressLength; /* Length of address in bytes */ + LL_TRANSMIT_ROUTINE Transmit; /* Transmit function for this interface */ +} LLIP_BIND_INFO, *PLLIP_BIND_INFO; + + +/* Information about an IP interface */ +typedef struct _IP_INTERFACE { + LIST_ENTRY ListEntry; /* Entry on list */ + ULONG RefCount; /* Reference count */ + KSPIN_LOCK Lock; /* Spin lock for this object */ + LIST_ENTRY NTEListHead; /* List of NTEs on this interface */ + LIST_ENTRY ADEListHead; /* List of ADEs on this interface */ + PVOID Context; /* Pointer to link layer context information */ + UINT HeaderSize; /* Size of link level header */ + UINT MinFrameSize; /* Minimum frame size in bytes */ + UINT MTU; /* Maximum transmission unit */ + PUCHAR Address; /* Pointer to interface address */ + UINT AddressLength; /* Length of address in bytes */ + LL_TRANSMIT_ROUTINE Transmit; /* Pointer to transmit function */ +} IP_INTERFACE, *PIP_INTERFACE; + + +/* Prefix List Entry */ +typedef struct _PREFIX_LIST_ENTRY { + LIST_ENTRY ListEntry; /* Entry on list */ + ULONG RefCount; /* Reference count */ + PIP_INTERFACE Interface; /* Pointer to interface */ + PIP_ADDRESS Prefix; /* Pointer to prefix */ + UINT PrefixLength; /* Length of prefix */ +} PREFIX_LIST_ENTRY, *PPREFIX_LIST_ENTRY; + + +#define IP_PROTOCOL_TABLE_SIZE 0x100 + +typedef VOID (*IP_PROTOCOL_HANDLER)( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket); + +/* Loopback adapter address information (network byte order) */ +#define LOOPBACK_ADDRESS_IPv4 ((IPv4_RAW_ADDRESS)DH2N(0x7F000001)) +#define LOOPBACK_BCASTADDR_IPv4 ((IPv4_RAW_ADDRESS)DH2N(0x7F0000FF)) +#define LOOPBACK_ADDRMASK_IPv4 ((IPv4_RAW_ADDRESS)DH2N(0xFFFFFF00)) + +/* Protocol definitions */ +#define IPPROTO_ICMP 1 /* Internet Control Message Protocol */ +#define IPPROTO_IGMP 2 /* Internet Group Management Protocol */ +#define IPPROTO_TCP 6 /* Transmission Control Protocol */ +#define IPPROTO_UDP 17 /* User Datagram Protocol */ + +/* Timeout timer constants */ +#define IP_TICKS_SECOND 2 /* Two ticks per second */ +#define IP_TIMEOUT (1000 / IP_TICKS_SECOND) /* Timeout in milliseconds */ + + +extern LIST_ENTRY InterfaceListHead; +extern KSPIN_LOCK InterfaceListLock; +extern LIST_ENTRY NetTableListHead; +extern KSPIN_LOCK NetTableListLock; +extern LIST_ENTRY PrefixListHead; +extern KSPIN_LOCK PrefixListLock; +extern UINT MaxLLHeaderSize; +extern UINT MinLLFrameSize; + + +PNET_TABLE_ENTRY IPCreateNTE( + PIP_INTERFACE IF, + PIP_ADDRESS Address, + UINT PrefixLength); + +PIP_INTERFACE IPCreateInterface( + PLLIP_BIND_INFO BindInfo); + +VOID IPDestroyInterface( + PIP_INTERFACE IF); + +BOOLEAN IPRegisterInterface( + PIP_INTERFACE IF); + +VOID IPUnregisterInterface( + PIP_INTERFACE IF); + +PNET_TABLE_ENTRY IPLocateNTEOnInterface( + PIP_INTERFACE IF, + PIP_ADDRESS Address, + PUINT AddressType); + +PNET_TABLE_ENTRY IPLocateNTE( + PIP_ADDRESS Address, + PUINT AddressType); + +PADDRESS_ENTRY IPLocateADE( + PIP_ADDRESS Address, + UINT AddressType); + +PADDRESS_ENTRY IPGetDefaultADE( + UINT AddressType); + +VOID IPTimeout( + PKDPC Dpc, + PVOID DeferredContext, + PVOID SystemArgument1, + PVOID SystemArgument2); + +VOID IPDispatchProtocol( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket); + +VOID IPRegisterProtocol( + UINT ProtocolNumber, + IP_PROTOCOL_HANDLER Handler); + +NTSTATUS IPStartup( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath); + +NTSTATUS IPShutdown( + VOID); + +#endif /* __IP_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/lan.h b/reactos/drivers/net/tcpip/include/lan.h index 20799d7b88a..87b06f842e8 100644 --- a/reactos/drivers/net/tcpip/include/lan.h +++ b/reactos/drivers/net/tcpip/include/lan.h @@ -1,100 +1,100 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/lan.h - * PURPOSE: LAN adapter definitions - */ -#ifndef __LAN_H -#define __LAN_H - - -/* Medias we support */ -#define MEDIA_ETH 0 - -#define MAX_MEDIA 1 - -#define IEEE_802_ADDR_LENGTH 6 - -/* Ethernet header layout */ -typedef struct ETH_HEADER { - UCHAR DstAddr[IEEE_802_ADDR_LENGTH]; /* Destination MAC address */ - UCHAR SrcAddr[IEEE_802_ADDR_LENGTH]; /* Source MAC address */ - USHORT EType; /* Ethernet protocol type */ -} ETH_HEADER, *PETH_HEADER; - -#define MAX_MEDIA_ETH sizeof(ETH_HEADER) - -/* Broadcast masks */ -#define BCAST_ETH_MASK 0x01 - -/* Broadcast values to check against */ -#define BCAST_ETH_CHECK 0x01 - -/* Offset of broadcast address */ -#define BCAST_ETH_OFFSET 0x00 - -/* Per adapter information */ -typedef struct LAN_ADAPTER { - struct LAN_ADAPTER *Next; /* Pointer to next adapter */ - KSPIN_LOCK Lock; /* Lock for this structure */ - UCHAR State; /* State of the adapter */ - KEVENT Event; /* Opening event */ - PVOID Context; /* Upper layer context information */ - NDIS_HANDLE NdisHandle; /* NDIS binding handle */ - NDIS_STATUS NdisStatus; /* NDIS status of last request */ - NDIS_MEDIUM Media; /* Media type */ - UCHAR HWAddress[IEEE_802_ADDR_LENGTH]; /* Local HW address */ - UINT HWAddressLength; /* Length of HW address */ - UCHAR BCastMask; /* Mask for checking broadcast */ - UCHAR BCastCheck; /* Value to check against */ - UCHAR BCastOffset; /* Offset in frame to check against */ - UCHAR HeaderSize; /* Size of link-level header */ - USHORT MTU; /* Maximum Transfer Unit */ - UINT MinFrameSize; /* Minimum frame size in bytes */ - UINT MaxPacketSize; /* Maximum packet size when sending */ - UINT MaxSendPackets; /* Maximum number of packets per send */ - UINT MacOptions; /* MAC options for NIC driver/adapter */ - UINT Speed; /* Link speed */ - UINT PacketFilter; /* Packet filter for this adapter */ - PNDIS_PACKET TDPackets; /* Transfer Data packets */ -} LAN_ADAPTER, *PLAN_ADAPTER; - -/* LAN adapter state constants */ -#define LAN_STATE_OPENING 0 -#define LAN_STATE_RESETTING 1 -#define LAN_STATE_STARTED 2 -#define LAN_STATE_STOPPED 3 - -/* Size of out lookahead buffer */ -#define LOOKAHEAD_SIZE 128 - -/* Ethernet types. We swap constants so we can compare values at runtime - without swapping them */ -#define ETYPE_IPv4 WH2N(0x0800) -#define ETYPE_IPv6 WH2N(0x0000) /* FIXME */ -#define ETYPE_ARP WH2N(0x0806) - -/* Protocols */ -#define LAN_PROTO_IPv4 0x0000 /* Internet Protocol version 4 */ -#define LAN_PROTO_IPv6 0x0001 /* Internet Protocol version 6 */ -#define LAN_PROTO_ARP 0x0002 /* Address Resolution Protocol */ - -extern PLAN_ADAPTER Adapters; - - -NDIS_STATUS LANRegisterAdapter( - PNDIS_STRING AdapterName, - PLAN_ADAPTER *Adapter); - -NDIS_STATUS LANUnregisterAdapter( - PLAN_ADAPTER Adapter); - -NTSTATUS LANRegisterProtocol( - STRING *Name); - -VOID LANUnregisterProtocol( - VOID); - -#endif /* __LAN_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/lan.h + * PURPOSE: LAN adapter definitions + */ +#ifndef __LAN_H +#define __LAN_H + + +/* Medias we support */ +#define MEDIA_ETH 0 + +#define MAX_MEDIA 1 + +#define IEEE_802_ADDR_LENGTH 6 + +/* Ethernet header layout */ +typedef struct ETH_HEADER { + UCHAR DstAddr[IEEE_802_ADDR_LENGTH]; /* Destination MAC address */ + UCHAR SrcAddr[IEEE_802_ADDR_LENGTH]; /* Source MAC address */ + USHORT EType; /* Ethernet protocol type */ +} ETH_HEADER, *PETH_HEADER; + +#define MAX_MEDIA_ETH sizeof(ETH_HEADER) + +/* Broadcast masks */ +#define BCAST_ETH_MASK 0x01 + +/* Broadcast values to check against */ +#define BCAST_ETH_CHECK 0x01 + +/* Offset of broadcast address */ +#define BCAST_ETH_OFFSET 0x00 + +/* Per adapter information */ +typedef struct LAN_ADAPTER { + struct LAN_ADAPTER *Next; /* Pointer to next adapter */ + KSPIN_LOCK Lock; /* Lock for this structure */ + UCHAR State; /* State of the adapter */ + KEVENT Event; /* Opening event */ + PVOID Context; /* Upper layer context information */ + NDIS_HANDLE NdisHandle; /* NDIS binding handle */ + NDIS_STATUS NdisStatus; /* NDIS status of last request */ + NDIS_MEDIUM Media; /* Media type */ + UCHAR HWAddress[IEEE_802_ADDR_LENGTH]; /* Local HW address */ + UINT HWAddressLength; /* Length of HW address */ + UCHAR BCastMask; /* Mask for checking broadcast */ + UCHAR BCastCheck; /* Value to check against */ + UCHAR BCastOffset; /* Offset in frame to check against */ + UCHAR HeaderSize; /* Size of link-level header */ + USHORT MTU; /* Maximum Transfer Unit */ + UINT MinFrameSize; /* Minimum frame size in bytes */ + UINT MaxPacketSize; /* Maximum packet size when sending */ + UINT MaxSendPackets; /* Maximum number of packets per send */ + UINT MacOptions; /* MAC options for NIC driver/adapter */ + UINT Speed; /* Link speed */ + UINT PacketFilter; /* Packet filter for this adapter */ + PNDIS_PACKET TDPackets; /* Transfer Data packets */ +} LAN_ADAPTER, *PLAN_ADAPTER; + +/* LAN adapter state constants */ +#define LAN_STATE_OPENING 0 +#define LAN_STATE_RESETTING 1 +#define LAN_STATE_STARTED 2 +#define LAN_STATE_STOPPED 3 + +/* Size of out lookahead buffer */ +#define LOOKAHEAD_SIZE 128 + +/* Ethernet types. We swap constants so we can compare values at runtime + without swapping them */ +#define ETYPE_IPv4 WH2N(0x0800) +#define ETYPE_IPv6 WH2N(0x0000) /* FIXME */ +#define ETYPE_ARP WH2N(0x0806) + +/* Protocols */ +#define LAN_PROTO_IPv4 0x0000 /* Internet Protocol version 4 */ +#define LAN_PROTO_IPv6 0x0001 /* Internet Protocol version 6 */ +#define LAN_PROTO_ARP 0x0002 /* Address Resolution Protocol */ + +extern PLAN_ADAPTER Adapters; + + +NDIS_STATUS LANRegisterAdapter( + PNDIS_STRING AdapterName, + PLAN_ADAPTER *Adapter); + +NDIS_STATUS LANUnregisterAdapter( + PLAN_ADAPTER Adapter); + +NTSTATUS LANRegisterProtocol( + STRING *Name); + +VOID LANUnregisterProtocol( + VOID); + +#endif /* __LAN_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/loopback.h b/reactos/drivers/net/tcpip/include/loopback.h index abf3e1db72b..e5c31c49ff1 100644 --- a/reactos/drivers/net/tcpip/include/loopback.h +++ b/reactos/drivers/net/tcpip/include/loopback.h @@ -1,25 +1,25 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/loopback.h - * PURPOSE: Loopback adapter definitions - */ -#ifndef __LOOPBACK_H -#define __LOOPBACK_H - -#include - - -extern PIP_INTERFACE Loopback; - - -NDIS_STATUS LoopRegisterAdapter( - PNDIS_STRING AdapterName, - PLAN_ADAPTER *Adapter); - -NDIS_STATUS LoopUnregisterAdapter( - PLAN_ADAPTER Adapter); - -#endif /* __LOOPBACK_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/loopback.h + * PURPOSE: Loopback adapter definitions + */ +#ifndef __LOOPBACK_H +#define __LOOPBACK_H + +#include + + +extern PIP_INTERFACE Loopback; + + +NDIS_STATUS LoopRegisterAdapter( + PNDIS_STRING AdapterName, + PLAN_ADAPTER *Adapter); + +NDIS_STATUS LoopUnregisterAdapter( + PLAN_ADAPTER Adapter); + +#endif /* __LOOPBACK_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/neighbor.h b/reactos/drivers/net/tcpip/include/neighbor.h index a2c50feb76b..460c25e62f7 100644 --- a/reactos/drivers/net/tcpip/include/neighbor.h +++ b/reactos/drivers/net/tcpip/include/neighbor.h @@ -1,101 +1,101 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/neighbor.h - * PURPOSE: Neighbor definitions - */ -#ifndef __NEIGHBOR_H -#define __NEIGHBOR_H - - -#define NB_HASHMASK 0xF /* Hash mask for neighbor cache */ - -typedef struct NEIGHBOR_CACHE_TABLE { - struct NEIGHBOR_CACHE_ENTRY *Cache; /* Pointer to cache */ - KSPIN_LOCK Lock; /* Protecting lock */ -} NEIGHBOR_CACHE_TABLE, *PNEIGHBOR_CACHE_TABLE; - -/* Information about a neighbor */ -typedef struct NEIGHBOR_CACHE_ENTRY { - struct NEIGHBOR_CACHE_ENTRY *Next; /* Pointer to next entry */ - struct NEIGHBOR_CACHE_TABLE *Table; /* Pointer to table */ - ULONG RefCount; /* Number of references */ - UCHAR State; /* State of NCE */ - UINT EventTimer; /* Ticks since last event */ - UINT EventCount; /* Number of events */ - PIP_INTERFACE Interface; /* Pointer to interface */ - PIP_ADDRESS Address; /* IP address of neighbor */ - UINT LinkAddressLength; /* Length of link address */ - PVOID LinkAddress; /* Pointer to link address */ - PNDIS_PACKET WaitQueue; /* Pointer to NDIS packets - waiting to be sent */ -} NEIGHBOR_CACHE_ENTRY, *PNEIGHBOR_CACHE_ENTRY; - -/* NCE states */ -#define NUD_NONE 0x00 -#define NUD_INCOMPLETE 0x01 -#define NUD_REACHABLE 0x02 -#define NUD_STALE 0x04 -#define NUD_DELAY 0x08 -#define NUD_PROBE 0x10 -#define NUD_FAILED 0x20 -#define NUD_NOARP 0x40 -#define NUD_PERMANENT 0x80 - -#define NUD_IN_TIMER (NUD_INCOMPLETE | NUD_DELAY | NUD_PROBE) -#define NUD_VALID (NUD_REACHABLE | NUD_NOARP | NUD_STALE | NUD_DELAY | \ - NUD_PROBE | NUD_PERMANENT) -#define NUD_CONNECTED (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE) - - -/* Maximum number of retransmissions of multicast solicits */ -#define MAX_MULTICAST_SOLICIT 3 /* 3 transmissions */ - -/* Number of ticks between address resolution messages */ -#define RETRANS_TIMER IP_TICKS_SECOND /* One second */ - - -extern NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1]; - - -VOID NBTimeout( - VOID); - -VOID NBStartup( - VOID); - -VOID NBShutdown( - VOID); - -VOID NBSendSolicit( - PNEIGHBOR_CACHE_ENTRY NCE); - -PNEIGHBOR_CACHE_ENTRY NBAddNeighbor( - PIP_INTERFACE Interface, - PIP_ADDRESS Address, - PVOID LinkAddress, - UINT LinkAddressLength, - UCHAR Type); - -VOID NBUpdateNeighbor( - PNEIGHBOR_CACHE_ENTRY NCE, - PVOID LinkAddress, - UCHAR State); - -PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor( - PIP_ADDRESS Address); - -PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor( - PIP_INTERFACE Interface, - PIP_ADDRESS Address); - -BOOLEAN NBQueuePacket( - PNEIGHBOR_CACHE_ENTRY NCE, - PNDIS_PACKET NdisPacket); - -VOID NBRemoveNeighbor( - PNEIGHBOR_CACHE_ENTRY NCE); - -#endif /* __NEIGHBOR_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/neighbor.h + * PURPOSE: Neighbor definitions + */ +#ifndef __NEIGHBOR_H +#define __NEIGHBOR_H + + +#define NB_HASHMASK 0xF /* Hash mask for neighbor cache */ + +typedef struct NEIGHBOR_CACHE_TABLE { + struct NEIGHBOR_CACHE_ENTRY *Cache; /* Pointer to cache */ + KSPIN_LOCK Lock; /* Protecting lock */ +} NEIGHBOR_CACHE_TABLE, *PNEIGHBOR_CACHE_TABLE; + +/* Information about a neighbor */ +typedef struct NEIGHBOR_CACHE_ENTRY { + struct NEIGHBOR_CACHE_ENTRY *Next; /* Pointer to next entry */ + struct NEIGHBOR_CACHE_TABLE *Table; /* Pointer to table */ + ULONG RefCount; /* Number of references */ + UCHAR State; /* State of NCE */ + UINT EventTimer; /* Ticks since last event */ + UINT EventCount; /* Number of events */ + PIP_INTERFACE Interface; /* Pointer to interface */ + PIP_ADDRESS Address; /* IP address of neighbor */ + UINT LinkAddressLength; /* Length of link address */ + PVOID LinkAddress; /* Pointer to link address */ + PNDIS_PACKET WaitQueue; /* Pointer to NDIS packets + waiting to be sent */ +} NEIGHBOR_CACHE_ENTRY, *PNEIGHBOR_CACHE_ENTRY; + +/* NCE states */ +#define NUD_NONE 0x00 +#define NUD_INCOMPLETE 0x01 +#define NUD_REACHABLE 0x02 +#define NUD_STALE 0x04 +#define NUD_DELAY 0x08 +#define NUD_PROBE 0x10 +#define NUD_FAILED 0x20 +#define NUD_NOARP 0x40 +#define NUD_PERMANENT 0x80 + +#define NUD_IN_TIMER (NUD_INCOMPLETE | NUD_DELAY | NUD_PROBE) +#define NUD_VALID (NUD_REACHABLE | NUD_NOARP | NUD_STALE | NUD_DELAY | \ + NUD_PROBE | NUD_PERMANENT) +#define NUD_CONNECTED (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE) + + +/* Maximum number of retransmissions of multicast solicits */ +#define MAX_MULTICAST_SOLICIT 3 /* 3 transmissions */ + +/* Number of ticks between address resolution messages */ +#define RETRANS_TIMER IP_TICKS_SECOND /* One second */ + + +extern NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1]; + + +VOID NBTimeout( + VOID); + +VOID NBStartup( + VOID); + +VOID NBShutdown( + VOID); + +VOID NBSendSolicit( + PNEIGHBOR_CACHE_ENTRY NCE); + +PNEIGHBOR_CACHE_ENTRY NBAddNeighbor( + PIP_INTERFACE Interface, + PIP_ADDRESS Address, + PVOID LinkAddress, + UINT LinkAddressLength, + UCHAR Type); + +VOID NBUpdateNeighbor( + PNEIGHBOR_CACHE_ENTRY NCE, + PVOID LinkAddress, + UCHAR State); + +PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor( + PIP_ADDRESS Address); + +PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor( + PIP_INTERFACE Interface, + PIP_ADDRESS Address); + +BOOLEAN NBQueuePacket( + PNEIGHBOR_CACHE_ENTRY NCE, + PNDIS_PACKET NdisPacket); + +VOID NBRemoveNeighbor( + PNEIGHBOR_CACHE_ENTRY NCE); + +#endif /* __NEIGHBOR_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/pool.h b/reactos/drivers/net/tcpip/include/pool.h index 653b0a4fa8d..04b088af1bf 100644 --- a/reactos/drivers/net/tcpip/include/pool.h +++ b/reactos/drivers/net/tcpip/include/pool.h @@ -1,19 +1,19 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/pool.h - * PURPOSE: Prototypes for memory pooling - */ -#ifndef __POOL_H -#define __POOL_H - - -PVOID PoolAllocateBuffer( - ULONG Size); - -VOID PoolFreeBuffer( - PVOID Buffer); - -#endif /* __POOL_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/pool.h + * PURPOSE: Prototypes for memory pooling + */ +#ifndef __POOL_H +#define __POOL_H + + +PVOID PoolAllocateBuffer( + ULONG Size); + +VOID PoolFreeBuffer( + PVOID Buffer); + +#endif /* __POOL_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/rawip.h b/reactos/drivers/net/tcpip/include/rawip.h index b1322293438..0029ef1d5ba 100644 --- a/reactos/drivers/net/tcpip/include/rawip.h +++ b/reactos/drivers/net/tcpip/include/rawip.h @@ -1,24 +1,24 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/rawip.h - * PURPOSE: Raw IP types and constants - */ -#ifndef __RAWIP_H -#define __RAWIP_H - -NTSTATUS RawIPSendDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG DataSize); - -NTSTATUS RawIPStartup( - VOID); - -NTSTATUS RawIPShutdown( - VOID); - -#endif /* __RAWIP_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/rawip.h + * PURPOSE: Raw IP types and constants + */ +#ifndef __RAWIP_H +#define __RAWIP_H + +NTSTATUS RawIPSendDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG DataSize); + +NTSTATUS RawIPStartup( + VOID); + +NTSTATUS RawIPShutdown( + VOID); + +#endif /* __RAWIP_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/receive.h b/reactos/drivers/net/tcpip/include/receive.h index 2dab3d4f0f7..36dcac27540 100644 --- a/reactos/drivers/net/tcpip/include/receive.h +++ b/reactos/drivers/net/tcpip/include/receive.h @@ -1,61 +1,61 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/receive.h - * PURPOSE: Internet Protocol receive prototypes - */ -#ifndef __RECEIVE_H -#define __RECEIVE_H - -#include - - -/* IP datagram fragment descriptor. Used to store IP datagram fragments */ -typedef struct IP_FRAGMENT { - LIST_ENTRY ListEntry; /* Entry on list */ - PVOID Data; /* Pointer to fragment data */ - UINT Offset; /* Offset into datagram where this fragment is */ - UINT Size; /* Size of this fragment */ -} IP_FRAGMENT, *PIP_FRAGMENT; - -/* IP datagram hole descriptor. Used to reassemble IP datagrams */ -typedef struct IPDATAGRAM_HOLE { - LIST_ENTRY ListEntry; /* Entry on list */ - UINT First; /* Offset of first octet of the hole */ - UINT Last; /* Offset of last octet of the hole */ -} IPDATAGRAM_HOLE, *PIPDATAGRAM_HOLE; - -/* IP datagram reassembly information */ -typedef struct IPDATAGRAM_REASSEMBLY { - LIST_ENTRY ListEntry; /* Entry on list */ - KSPIN_LOCK Lock; /* Protecting spin lock */ - ULONG RefCount; /* Reference count for this object */ - UINT DataSize; /* Size of datagram data area */ - IP_ADDRESS SrcAddr; /* Source address */ - IP_ADDRESS DstAddr; /* Destination address */ - UCHAR Protocol; /* Internet Protocol number */ - USHORT Id; /* Identification number */ - PIPv4_HEADER IPv4Header; /* Pointer to IP header */ - UINT HeaderSize; /* Length of IP header */ - LIST_ENTRY FragmentListHead; /* IP fragment list */ - LIST_ENTRY HoleListHead; /* IP datagram hole list */ -} IPDATAGRAM_REASSEMBLY, *PIPDATAGRAM_REASSEMBLY; - - -extern LIST_ENTRY ReassemblyListHead; -extern KSPIN_LOCK ReassemblyListLock; - - -VOID IPFreeReassemblyList( - VOID); - -VOID IPDatagramReassemblyTimeout( - VOID); - -VOID IPReceive( - PVOID Context, - PIP_PACKET IPPacket); - -#endif /* __RECEIVE_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/receive.h + * PURPOSE: Internet Protocol receive prototypes + */ +#ifndef __RECEIVE_H +#define __RECEIVE_H + +#include + + +/* IP datagram fragment descriptor. Used to store IP datagram fragments */ +typedef struct IP_FRAGMENT { + LIST_ENTRY ListEntry; /* Entry on list */ + PVOID Data; /* Pointer to fragment data */ + UINT Offset; /* Offset into datagram where this fragment is */ + UINT Size; /* Size of this fragment */ +} IP_FRAGMENT, *PIP_FRAGMENT; + +/* IP datagram hole descriptor. Used to reassemble IP datagrams */ +typedef struct IPDATAGRAM_HOLE { + LIST_ENTRY ListEntry; /* Entry on list */ + UINT First; /* Offset of first octet of the hole */ + UINT Last; /* Offset of last octet of the hole */ +} IPDATAGRAM_HOLE, *PIPDATAGRAM_HOLE; + +/* IP datagram reassembly information */ +typedef struct IPDATAGRAM_REASSEMBLY { + LIST_ENTRY ListEntry; /* Entry on list */ + KSPIN_LOCK Lock; /* Protecting spin lock */ + ULONG RefCount; /* Reference count for this object */ + UINT DataSize; /* Size of datagram data area */ + IP_ADDRESS SrcAddr; /* Source address */ + IP_ADDRESS DstAddr; /* Destination address */ + UCHAR Protocol; /* Internet Protocol number */ + USHORT Id; /* Identification number */ + PIPv4_HEADER IPv4Header; /* Pointer to IP header */ + UINT HeaderSize; /* Length of IP header */ + LIST_ENTRY FragmentListHead; /* IP fragment list */ + LIST_ENTRY HoleListHead; /* IP datagram hole list */ +} IPDATAGRAM_REASSEMBLY, *PIPDATAGRAM_REASSEMBLY; + + +extern LIST_ENTRY ReassemblyListHead; +extern KSPIN_LOCK ReassemblyListLock; + + +VOID IPFreeReassemblyList( + VOID); + +VOID IPDatagramReassemblyTimeout( + VOID); + +VOID IPReceive( + PVOID Context, + PIP_PACKET IPPacket); + +#endif /* __RECEIVE_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/route.h b/reactos/drivers/net/tcpip/include/route.h index d2c827c8d76..c6c7d2c0c20 100644 --- a/reactos/drivers/net/tcpip/include/route.h +++ b/reactos/drivers/net/tcpip/include/route.h @@ -1,75 +1,75 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/route.h - * PURPOSE: Routing cache definitions - */ -#ifndef __ROUTE_H -#define __ROUTE_H - -#include -#include -#include -#include -#include - - -/* Route Cache Node structure. - * The primary purpose of the RCN is to cache selected source and - * next-hop addresses. The routing cache is implemented as a binary - * search tree to provide fast lookups when many RCNs are in the cache. - */ -typedef struct ROUTE_CACHE_NODE { - struct ROUTE_CACHE_NODE *Parent; /* Pointer to parent */ - struct ROUTE_CACHE_NODE *Left; /* Pointer to left child */ - struct ROUTE_CACHE_NODE *Right; /* Pointer to right child */ - /* Memebers above this line must not be moved */ - ULONG RefCount; /* Reference count */ - UCHAR State; /* RCN state (RCN_STATE_*) */ - IP_ADDRESS Destination; /* Destination address */ - PNET_TABLE_ENTRY NTE; /* Preferred NTE */ - PNEIGHBOR_CACHE_ENTRY NCE; /* Pointer to NCE for first hop (NULL if none) */ - UINT PathMTU; /* Path MTU to destination */ -} ROUTE_CACHE_NODE, *PROUTE_CACHE_NODE; - -/* RCN states */ -#define RCN_STATE_PERMANENT 0x00 /* RCN is permanent (properly local) */ -#define RCN_STATE_COMPUTED 0x01 /* RCN is computed */ - - -#define IsExternalRCN(RCN) \ - (RCN == ExternalRCN) - -#define IsInternalRCN(RCN) \ - (RCN != ExternalRCN) - - -NTSTATUS RouteStartup( - VOID); - -NTSTATUS RouteShutdown( - VOID); - -UINT RouteGetRouteToDestination( - PIP_ADDRESS Destination, - PNET_TABLE_ENTRY NTE, - PROUTE_CACHE_NODE *RCN); - -PROUTE_CACHE_NODE RouteAddRouteToDestination( - PIP_ADDRESS Destination, - PNET_TABLE_ENTRY NTE, - PIP_INTERFACE IF, - PNEIGHBOR_CACHE_ENTRY NCE); - -VOID RouteRemoveRouteToDestination( - PROUTE_CACHE_NODE RCN); - -VOID RouteInvalidateNTE( - PNET_TABLE_ENTRY NTE); - -VOID RouteInvalidateNCE( - PNEIGHBOR_CACHE_ENTRY NCE); - -#endif /* __ROUTE_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/route.h + * PURPOSE: Routing cache definitions + */ +#ifndef __ROUTE_H +#define __ROUTE_H + +#include +#include +#include +#include +#include + + +/* Route Cache Node structure. + * The primary purpose of the RCN is to cache selected source and + * next-hop addresses. The routing cache is implemented as a binary + * search tree to provide fast lookups when many RCNs are in the cache. + */ +typedef struct ROUTE_CACHE_NODE { + struct ROUTE_CACHE_NODE *Parent; /* Pointer to parent */ + struct ROUTE_CACHE_NODE *Left; /* Pointer to left child */ + struct ROUTE_CACHE_NODE *Right; /* Pointer to right child */ + /* Memebers above this line must not be moved */ + ULONG RefCount; /* Reference count */ + UCHAR State; /* RCN state (RCN_STATE_*) */ + IP_ADDRESS Destination; /* Destination address */ + PNET_TABLE_ENTRY NTE; /* Preferred NTE */ + PNEIGHBOR_CACHE_ENTRY NCE; /* Pointer to NCE for first hop (NULL if none) */ + UINT PathMTU; /* Path MTU to destination */ +} ROUTE_CACHE_NODE, *PROUTE_CACHE_NODE; + +/* RCN states */ +#define RCN_STATE_PERMANENT 0x00 /* RCN is permanent (properly local) */ +#define RCN_STATE_COMPUTED 0x01 /* RCN is computed */ + + +#define IsExternalRCN(RCN) \ + (RCN == ExternalRCN) + +#define IsInternalRCN(RCN) \ + (RCN != ExternalRCN) + + +NTSTATUS RouteStartup( + VOID); + +NTSTATUS RouteShutdown( + VOID); + +UINT RouteGetRouteToDestination( + PIP_ADDRESS Destination, + PNET_TABLE_ENTRY NTE, + PROUTE_CACHE_NODE *RCN); + +PROUTE_CACHE_NODE RouteAddRouteToDestination( + PIP_ADDRESS Destination, + PNET_TABLE_ENTRY NTE, + PIP_INTERFACE IF, + PNEIGHBOR_CACHE_ENTRY NCE); + +VOID RouteRemoveRouteToDestination( + PROUTE_CACHE_NODE RCN); + +VOID RouteInvalidateNTE( + PNET_TABLE_ENTRY NTE); + +VOID RouteInvalidateNCE( + PNEIGHBOR_CACHE_ENTRY NCE); + +#endif /* __ROUTE_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/router.h b/reactos/drivers/net/tcpip/include/router.h index e8d52ef1601..c585f833db8 100644 --- a/reactos/drivers/net/tcpip/include/router.h +++ b/reactos/drivers/net/tcpip/include/router.h @@ -1,62 +1,62 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/router.h - * PURPOSE: IP routing definitions - */ -#ifndef __ROUTER_H -#define __ROUTER_H - -#include - - -/* Forward Information Base Entry */ -typedef struct _FIB_ENTRY { - LIST_ENTRY ListEntry; /* Entry on list */ - ULONG RefCount; /* Reference count */ - PIP_ADDRESS NetworkAddress; /* Address of network */ - PIP_ADDRESS Netmask; /* Netmask of network */ - PNET_TABLE_ENTRY NTE; /* Pointer to NTE to use */ - PNEIGHBOR_CACHE_ENTRY Router; /* Pointer to NCE of router to use */ - UINT Metric; /* Cost of this route */ -} FIB_ENTRY, *PFIB_ENTRY; - - -PNET_TABLE_ENTRY RouterFindBestNTE( - PIP_INTERFACE Interface, - PIP_ADDRESS Destination); - -PIP_INTERFACE RouterFindOnLinkInterface( - PIP_ADDRESS Address, - PNET_TABLE_ENTRY NTE); - -PFIB_ENTRY RouterAddRoute( - PIP_ADDRESS NetworkAddress, - PIP_ADDRESS Netmask, - PNET_TABLE_ENTRY NTE, - PNEIGHBOR_CACHE_ENTRY Router, - UINT Metric); - -PNEIGHBOR_CACHE_ENTRY RouterGetRoute( - PIP_ADDRESS Destination, - PNET_TABLE_ENTRY NTE); - -VOID RouterRemoveRoute( - PFIB_ENTRY FIBE); - -PFIB_ENTRY RouterCreateRouteIPv4( - IPv4_RAW_ADDRESS NetworkAddress, - IPv4_RAW_ADDRESS Netmask, - IPv4_RAW_ADDRESS RouterAddress, - PNET_TABLE_ENTRY NTE, - UINT Metric); - -NTSTATUS RouterStartup( - VOID); - -NTSTATUS RouterShutdown( - VOID); - -#endif /* __ROUTER_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/router.h + * PURPOSE: IP routing definitions + */ +#ifndef __ROUTER_H +#define __ROUTER_H + +#include + + +/* Forward Information Base Entry */ +typedef struct _FIB_ENTRY { + LIST_ENTRY ListEntry; /* Entry on list */ + ULONG RefCount; /* Reference count */ + PIP_ADDRESS NetworkAddress; /* Address of network */ + PIP_ADDRESS Netmask; /* Netmask of network */ + PNET_TABLE_ENTRY NTE; /* Pointer to NTE to use */ + PNEIGHBOR_CACHE_ENTRY Router; /* Pointer to NCE of router to use */ + UINT Metric; /* Cost of this route */ +} FIB_ENTRY, *PFIB_ENTRY; + + +PNET_TABLE_ENTRY RouterFindBestNTE( + PIP_INTERFACE Interface, + PIP_ADDRESS Destination); + +PIP_INTERFACE RouterFindOnLinkInterface( + PIP_ADDRESS Address, + PNET_TABLE_ENTRY NTE); + +PFIB_ENTRY RouterAddRoute( + PIP_ADDRESS NetworkAddress, + PIP_ADDRESS Netmask, + PNET_TABLE_ENTRY NTE, + PNEIGHBOR_CACHE_ENTRY Router, + UINT Metric); + +PNEIGHBOR_CACHE_ENTRY RouterGetRoute( + PIP_ADDRESS Destination, + PNET_TABLE_ENTRY NTE); + +VOID RouterRemoveRoute( + PFIB_ENTRY FIBE); + +PFIB_ENTRY RouterCreateRouteIPv4( + IPv4_RAW_ADDRESS NetworkAddress, + IPv4_RAW_ADDRESS Netmask, + IPv4_RAW_ADDRESS RouterAddress, + PNET_TABLE_ENTRY NTE, + UINT Metric); + +NTSTATUS RouterStartup( + VOID); + +NTSTATUS RouterShutdown( + VOID); + +#endif /* __ROUTER_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/routines.h b/reactos/drivers/net/tcpip/include/routines.h index dcd0347b555..b73f27e7b2d 100644 --- a/reactos/drivers/net/tcpip/include/routines.h +++ b/reactos/drivers/net/tcpip/include/routines.h @@ -1,53 +1,53 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/routines.h - * PURPOSE: Common routine prototypes - */ -#ifndef __ROUTINES_H -#define __ROUTINES_H - - -UINT Random( - VOID); - -UINT CopyBufferToBufferChain( - PNDIS_BUFFER DstBuffer, - UINT DstOffset, - PUCHAR SrcData, - UINT Length); - -UINT CopyBufferChainToBuffer( - PUCHAR DstData, - PNDIS_BUFFER SrcBuffer, - UINT SrcOffset, - UINT Length); - -UINT CopyPacketToBuffer( - PUCHAR DstData, - PNDIS_PACKET SrcPacket, - UINT SrcOffset, - UINT Length); - -UINT CopyPacketToBufferChain( - PNDIS_BUFFER DstBuffer, - UINT DstOffset, - PNDIS_PACKET SrcPacket, - UINT SrcOffset, - UINT Length); - -VOID FreeNdisPacket( - PNDIS_PACKET Packet); - -PVOID AdjustPacket( - PNDIS_PACKET Packet, - UINT Available, - UINT Needed); - -UINT ResizePacket( - PNDIS_PACKET Packet, - UINT Size); - -#endif /* __ROUTINES_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/routines.h + * PURPOSE: Common routine prototypes + */ +#ifndef __ROUTINES_H +#define __ROUTINES_H + + +UINT Random( + VOID); + +UINT CopyBufferToBufferChain( + PNDIS_BUFFER DstBuffer, + UINT DstOffset, + PUCHAR SrcData, + UINT Length); + +UINT CopyBufferChainToBuffer( + PUCHAR DstData, + PNDIS_BUFFER SrcBuffer, + UINT SrcOffset, + UINT Length); + +UINT CopyPacketToBuffer( + PUCHAR DstData, + PNDIS_PACKET SrcPacket, + UINT SrcOffset, + UINT Length); + +UINT CopyPacketToBufferChain( + PNDIS_BUFFER DstBuffer, + UINT DstOffset, + PNDIS_PACKET SrcPacket, + UINT SrcOffset, + UINT Length); + +VOID FreeNdisPacket( + PNDIS_PACKET Packet); + +PVOID AdjustPacket( + PNDIS_PACKET Packet, + UINT Available, + UINT Needed); + +UINT ResizePacket( + PNDIS_PACKET Packet, + UINT Size); + +#endif /* __ROUTINES_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/tcp.h b/reactos/drivers/net/tcpip/include/tcp.h index d58654a1f30..22e38ef5f38 100644 --- a/reactos/drivers/net/tcpip/include/tcp.h +++ b/reactos/drivers/net/tcpip/include/tcp.h @@ -1,18 +1,18 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/tcp.h - * PURPOSE: Transmission Control Protocol definitions - */ -#ifndef __TCP_H -#define __TCP_H - -NTSTATUS TCPStartup( - VOID); - -NTSTATUS TCPShutdown( - VOID); - -#endif /* __TCP_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/tcp.h + * PURPOSE: Transmission Control Protocol definitions + */ +#ifndef __TCP_H +#define __TCP_H + +NTSTATUS TCPStartup( + VOID); + +NTSTATUS TCPShutdown( + VOID); + +#endif /* __TCP_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/tcpip.h b/reactos/drivers/net/tcpip/include/tcpip.h index 7a56e2a847f..1c3eb02c7f9 100644 --- a/reactos/drivers/net/tcpip/include/tcpip.h +++ b/reactos/drivers/net/tcpip/include/tcpip.h @@ -1,131 +1,131 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/tcpip.h - * PURPOSE: TCP/IP protocol driver definitions - * NOTES: Spin lock acquire order: - * - Net table list lock - * - Interface lock - * - Interface list lock - * - Prefix list lock - * - Neighbor cache lock - * - Route cache lock - */ -#ifndef __TCPIP_H -#define __TCPIP_H - -#ifdef _MSC_VER -#include -#include -#include -#include -#include -#include -#else -#include -#include -#include -#include -#endif - -#include - - -/* Define _NTTEST_ to make test version. Device names are prefixed with - 'NT' to allow the driver to run side by side with MS TCP/IP driver */ -#define _NTTEST_ - -/* FIXME: The following should be moved to ntddk.h or tdi headers */ -#ifndef _MSC_VER - -#ifndef IO_NETWORK_INCREMENT -#define IO_NETWORK_INCREMENT 2 -#endif - -#endif - -#ifdef _MSC_VER -/* EXPORTED is already defined ddk/defines.h */ -#define EXPORTED __declspec(dllexport) - -#endif - -#include -#include -#include - - -/* Macros */ - -#define MIN(value1, value2) \ - ((value1 < value2)? value1 : value2) - -#define MAX(value1, value2) \ - ((value1 > value2)? value1 : value2) - - -#ifdef i386 - -/* DWORD network to host byte order conversion for i386 */ -#define DN2H(dw) \ - ((((dw) & 0xFF000000L) >> 24) | \ - (((dw) & 0x00FF0000L) >> 8) | \ - (((dw) & 0x0000FF00L) << 8) | \ - (((dw) & 0x000000FFL) << 24)) - -/* DWORD host to network byte order conversion for i386 */ -#define DH2N(dw) \ - ((((dw) & 0xFF000000L) >> 24) | \ - (((dw) & 0x00FF0000L) >> 8) | \ - (((dw) & 0x0000FF00L) << 8) | \ - (((dw) & 0x000000FFL) << 24)) - -/* WORD network to host order conversion for i386 */ -#define WN2H(w) \ - ((((w) & 0xFF00) >> 8) | \ - (((w) & 0x00FF) << 8)) - -/* WORD host to network byte order conversion for i386 */ -#define WH2N(w) \ - ((((w) & 0xFF00) >> 8) | \ - (((w) & 0x00FF) << 8)) - -#else /* i386 */ - -/* DWORD network to host byte order conversion for other architectures */ -#define DN2H(dw) \ - (dw) - -/* DWORD host to network byte order conversion for other architectures */ -#define DH2N(dw) \ - (dw) - -/* WORD network to host order conversion for other architectures */ -#define WN2H(w) \ - (w) - -/* WORD host to network byte order conversion for other architectures */ -#define WH2N(w) \ - (w) - -#endif /* i386 */ - - -/* Global variable */ -extern PDEVICE_OBJECT TCPDeviceObject; -extern PDEVICE_OBJECT UDPDeviceObject; -extern PDEVICE_OBJECT IPDeviceObject; -extern PDEVICE_OBJECT RawIPDeviceObject; -extern LIST_ENTRY InterfaceListHead; -extern KSPIN_LOCK InterfaceListLock; -extern LIST_ENTRY AddressFileListHead; -extern KSPIN_LOCK AddressFileListLock; -extern NDIS_HANDLE GlobalPacketPool; -extern NDIS_HANDLE GlobalBufferPool; -extern TDIEntityID *EntityList; -extern ULONG EntityCount; -extern UDP_STATISTICS UDPStats; - -#endif /* __TCPIP_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/tcpip.h + * PURPOSE: TCP/IP protocol driver definitions + * NOTES: Spin lock acquire order: + * - Net table list lock + * - Interface lock + * - Interface list lock + * - Prefix list lock + * - Neighbor cache lock + * - Route cache lock + */ +#ifndef __TCPIP_H +#define __TCPIP_H + +#ifdef _MSC_VER +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif + +#include + + +/* Define _NTTEST_ to make test version. Device names are prefixed with + 'NT' to allow the driver to run side by side with MS TCP/IP driver */ +#define _NTTEST_ + +/* FIXME: The following should be moved to ntddk.h or tdi headers */ +#ifndef _MSC_VER + +#ifndef IO_NETWORK_INCREMENT +#define IO_NETWORK_INCREMENT 2 +#endif + +#endif + +#ifdef _MSC_VER +/* EXPORTED is already defined ddk/defines.h */ +#define EXPORTED __declspec(dllexport) + +#endif + +#include +#include +#include + + +/* Macros */ + +#define MIN(value1, value2) \ + ((value1 < value2)? value1 : value2) + +#define MAX(value1, value2) \ + ((value1 > value2)? value1 : value2) + + +#ifdef i386 + +/* DWORD network to host byte order conversion for i386 */ +#define DN2H(dw) \ + ((((dw) & 0xFF000000L) >> 24) | \ + (((dw) & 0x00FF0000L) >> 8) | \ + (((dw) & 0x0000FF00L) << 8) | \ + (((dw) & 0x000000FFL) << 24)) + +/* DWORD host to network byte order conversion for i386 */ +#define DH2N(dw) \ + ((((dw) & 0xFF000000L) >> 24) | \ + (((dw) & 0x00FF0000L) >> 8) | \ + (((dw) & 0x0000FF00L) << 8) | \ + (((dw) & 0x000000FFL) << 24)) + +/* WORD network to host order conversion for i386 */ +#define WN2H(w) \ + ((((w) & 0xFF00) >> 8) | \ + (((w) & 0x00FF) << 8)) + +/* WORD host to network byte order conversion for i386 */ +#define WH2N(w) \ + ((((w) & 0xFF00) >> 8) | \ + (((w) & 0x00FF) << 8)) + +#else /* i386 */ + +/* DWORD network to host byte order conversion for other architectures */ +#define DN2H(dw) \ + (dw) + +/* DWORD host to network byte order conversion for other architectures */ +#define DH2N(dw) \ + (dw) + +/* WORD network to host order conversion for other architectures */ +#define WN2H(w) \ + (w) + +/* WORD host to network byte order conversion for other architectures */ +#define WH2N(w) \ + (w) + +#endif /* i386 */ + + +/* Global variable */ +extern PDEVICE_OBJECT TCPDeviceObject; +extern PDEVICE_OBJECT UDPDeviceObject; +extern PDEVICE_OBJECT IPDeviceObject; +extern PDEVICE_OBJECT RawIPDeviceObject; +extern LIST_ENTRY InterfaceListHead; +extern KSPIN_LOCK InterfaceListLock; +extern LIST_ENTRY AddressFileListHead; +extern KSPIN_LOCK AddressFileListLock; +extern NDIS_HANDLE GlobalPacketPool; +extern NDIS_HANDLE GlobalBufferPool; +extern TDIEntityID *EntityList; +extern ULONG EntityCount; +extern UDP_STATISTICS UDPStats; + +#endif /* __TCPIP_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/ticonsts.h b/reactos/drivers/net/tcpip/include/ticonsts.h index 2ed72467286..d73436c8524 100644 --- a/reactos/drivers/net/tcpip/include/ticonsts.h +++ b/reactos/drivers/net/tcpip/include/ticonsts.h @@ -1,56 +1,56 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/ticonsts.h - * PURPOSE: TCP/IP protocol driver constants - */ -#ifndef __TICONSTS_H -#define __TICONSTS_H - -/* NDIS version this driver supports */ -#define NDIS_VERSION_MAJOR 3 -#define NDIS_VERSION_MINOR 0 - -#ifdef _NTTEST_ -/* Name of devices */ -#define DD_TCP_DEVICE_NAME L"\\Device\\NTTcp" -#define DD_UDP_DEVICE_NAME L"\\Device\\NTUdp" -#define DD_IP_DEVICE_NAME L"\\Device\\NTIp" -#define DD_RAWIP_DEVICE_NAME L"\\Device\\NTRawIp" - -/* For NDIS protocol registration */ -#define IP_DEVICE_NAME "\\Device\\NTIp" -#else -#define DD_TCP_DEVICE_NAME L"\\Device\\Tcp" -#define DD_UDP_DEVICE_NAME L"\\Device\\Udp" -#define DD_IP_DEVICE_NAME L"\\Device\\Ip" -#define DD_RAWIP_DEVICE_NAME L"\\Device\\RawIp" - -/* For NDIS protocol registration */ -#define IP_DEVICE_NAME "\\Device\\Ip" -#endif /* _NTTEST_ */ - -/* TCP/UDP/RawIP IOCTL code definitions */ - -#define FSCTL_TCP_BASE FILE_DEVICE_NETWORK - -#define _TCP_CTL_CODE(Function, Method, Access) \ - CTL_CODE(FSCTL_TCP_BASE, Function, Method, Access) - -#define IOCTL_TCP_QUERY_INFORMATION_EX \ - _TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS) - -#define IOCTL_TCP_SET_INFORMATION_EX \ - _TCP_CTL_CODE(1, METHOD_BUFFERED, FILE_WRITE_ACCESS) - -/* Unique error values for log entries */ -#define TI_ERROR_DRIVERENTRY 0 - -/* Internal status codes */ -#define IP_SUCCESS 0x0000 /* Successful */ -#define IP_NO_RESOURCES 0x0001 /* Not enough free resources */ -#define IP_NO_ROUTE_TO_DESTINATION 0x0002 /* No route to destination */ - -#endif /* __TICONSTS_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/ticonsts.h + * PURPOSE: TCP/IP protocol driver constants + */ +#ifndef __TICONSTS_H +#define __TICONSTS_H + +/* NDIS version this driver supports */ +#define NDIS_VERSION_MAJOR 3 +#define NDIS_VERSION_MINOR 0 + +#ifdef _NTTEST_ +/* Name of devices */ +#define DD_TCP_DEVICE_NAME L"\\Device\\NTTcp" +#define DD_UDP_DEVICE_NAME L"\\Device\\NTUdp" +#define DD_IP_DEVICE_NAME L"\\Device\\NTIp" +#define DD_RAWIP_DEVICE_NAME L"\\Device\\NTRawIp" + +/* For NDIS protocol registration */ +#define IP_DEVICE_NAME "\\Device\\NTIp" +#else +#define DD_TCP_DEVICE_NAME L"\\Device\\Tcp" +#define DD_UDP_DEVICE_NAME L"\\Device\\Udp" +#define DD_IP_DEVICE_NAME L"\\Device\\Ip" +#define DD_RAWIP_DEVICE_NAME L"\\Device\\RawIp" + +/* For NDIS protocol registration */ +#define IP_DEVICE_NAME "\\Device\\Ip" +#endif /* _NTTEST_ */ + +/* TCP/UDP/RawIP IOCTL code definitions */ + +#define FSCTL_TCP_BASE FILE_DEVICE_NETWORK + +#define _TCP_CTL_CODE(Function, Method, Access) \ + CTL_CODE(FSCTL_TCP_BASE, Function, Method, Access) + +#define IOCTL_TCP_QUERY_INFORMATION_EX \ + _TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define IOCTL_TCP_SET_INFORMATION_EX \ + _TCP_CTL_CODE(1, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +/* Unique error values for log entries */ +#define TI_ERROR_DRIVERENTRY 0 + +/* Internal status codes */ +#define IP_SUCCESS 0x0000 /* Successful */ +#define IP_NO_RESOURCES 0x0001 /* Not enough free resources */ +#define IP_NO_ROUTE_TO_DESTINATION 0x0002 /* No route to destination */ + +#endif /* __TICONSTS_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/titypes.h b/reactos/drivers/net/tcpip/include/titypes.h index 833d671dbf1..998b90dec08 100644 --- a/reactos/drivers/net/tcpip/include/titypes.h +++ b/reactos/drivers/net/tcpip/include/titypes.h @@ -1,215 +1,215 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/titypes.h - * PURPOSE: TCP/IP protocol driver types - */ -#ifndef __TITYPES_H -#define __TITYPES_H - -#include - - -#ifdef DBG - -#define DEBUG_REFCHECK(Object) { \ - if ((Object)->RefCount <= 0) { \ - TI_DbgPrint(MIN_TRACE, ("Object at (0x%X) has invalid reference count (%d).\n", \ - (Object), (Object)->RefCount)); \ - } \ -} - -#else - -#define DEBUG_REFCHECK(Object) - -#endif - - -/* - * VOID ReferenceObject( - * PVOID Object) - */ -#define ReferenceObject(Object) \ -{ \ - DEBUG_REFCHECK(Object); \ - TI_DbgPrint(DEBUG_REFCOUNT, ("Referencing object at (0x%X). RefCount (%d).\n", \ - (Object), (Object)->RefCount)); \ - \ - InterlockedIncrement(&((Object)->RefCount)); \ -} - -/* - * VOID DereferenceObject( - * PVOID Object) - */ -#define DereferenceObject(Object) \ -{ \ - DEBUG_REFCHECK(Object); \ - TI_DbgPrint(DEBUG_REFCOUNT, ("Dereferencing object at (0x%X). RefCount (%d).\n", \ - (Object), (Object)->RefCount)); \ - \ - if (InterlockedDecrement(&((Object)->RefCount)) == 0) \ - PoolFreeBuffer(Object); \ -} - - -typedef NTSTATUS (*DATAGRAM_SEND_ROUTINE)( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG DataSize); - -/* Datagram completion handler prototype */ -typedef VOID (*DATAGRAM_COMPLETION_ROUTINE)( - PVOID Context, - NDIS_STATUS Status, - ULONG Count); - -typedef struct _DATAGRAM_RECEIVE_REQUEST { - LIST_ENTRY ListEntry; /* Entry on list */ - PIP_ADDRESS RemoteAddress; /* Remote address we receive from (NULL means any) */ - USHORT RemotePort; /* Remote port we receive from (0 means any) */ - PTDI_CONNECTION_INFORMATION ReturnInfo; /* Return information */ - PNDIS_BUFFER Buffer; /* Pointer to receive buffer */ - ULONG BufferSize; /* Size of Buffer */ - DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine */ - PVOID Context; /* Pointer to context information */ -} DATAGRAM_RECEIVE_REQUEST, *PDATAGRAM_RECEIVE_REQUEST; - -/* Datagram build routine prototype */ -typedef NTSTATUS (*DATAGRAM_BUILD_ROUTINE)( - PVOID Context, - PIP_ADDRESS LocalAddress, - USHORT LocalPort, - PIP_PACKET *IPPacket); - -typedef struct _DATAGRAM_SEND_REQUEST { - LIST_ENTRY ListEntry; /* Entry on list */ - PIP_ADDRESS RemoteAddress; /* Pointer to remote IP address */ - USHORT RemotePort; /* Remote port number */ - PNDIS_BUFFER Buffer; /* Pointer to NDIS buffer to send */ - DWORD BufferSize; /* Size of Buffer */ - DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine */ - PVOID Context; /* Pointer to context information */ - DATAGRAM_BUILD_ROUTINE Build; /* Datagram build routine */ -} DATAGRAM_SEND_REQUEST, *PDATAGRAM_SEND_REQUEST; - - -/* Transport (TCP/UDP) endpoint context structure. The FileObject->FsContext - field holds a pointer to this structure */ -typedef struct _TRANSPORT_CONTEXT { - union { - HANDLE AddressHandle; - CONNECTION_CONTEXT ConnectionContext; - HANDLE ControlChannel; - } Handle; - ULONG RefCount; - BOOL CancelIrps; - KEVENT CleanupEvent; -} TRANSPORT_CONTEXT, *PTRANSPORT_CONTEXT; - - -typedef struct _ADDRESS_FILE { - LIST_ENTRY ListEntry; /* Entry on list */ - KSPIN_LOCK Lock; /* Spin lock to manipulate this structure */ - ULONG RefCount; /* Number of references to this object */ - USHORT Flags; /* Flags for address file (see below) */ - PADDRESS_ENTRY ADE; /* Associated address entry */ - USHORT Protocol; /* Protocol number */ - USHORT Port; /* Network port (network byte order) */ - WORK_QUEUE_ITEM WorkItem; /* Work queue item handle */ - DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine for delete request */ - PVOID Context; /* Delete request context */ - DATAGRAM_SEND_ROUTINE Send; /* Routine to send a datagram */ - LIST_ENTRY ReceiveQueue; /* List of outstanding receive requests */ - LIST_ENTRY TransmitQueue; /* List of outstanding transmit requests */ - PIP_ADDRESS AddrCache; /* One entry address cache (destination - address of last packet transmitted) */ - - /* The following members are used to control event notification */ - - /* Connection indication handler */ - PTDI_IND_CONNECT ConnectionHandler; - PVOID ConnectionHandlerContext; - BOOL RegisteredConnectionHandler; - /* Disconnect indication handler */ - PTDI_IND_DISCONNECT DisconnectHandler; - PVOID DisconnectHandlerContext; - BOOL RegisteredDisconnectHandler; - /* Receive indication handler */ - PTDI_IND_RECEIVE ReceiveHandler; - PVOID ReceiveHandlerContext; - BOOL RegisteredReceiveHandler; - /* Expedited receive indication handler */ - PTDI_IND_RECEIVE_EXPEDITED ExpeditedReceiveHandler; - PVOID ExpeditedReceiveHandlerContext; - BOOL RegisteredExpeditedReceiveHandler; - /* Receive datagram indication handler */ - PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler; - PVOID ReceiveDatagramHandlerContext; - BOOL RegisteredReceiveDatagramHandler; - /* Error indication handler */ - PTDI_IND_ERROR ErrorHandler; - PVOID ErrorHandlerContext; - PVOID ErrorHandlerOwner; - BOOL RegisteredErrorHandler; -} ADDRESS_FILE, *PADDRESS_FILE; - -/* Address File Flag constants */ -#define AFF_VALID 0x0001 /* Address file object is valid for use */ -#define AFF_BUSY 0x0002 /* Address file object is exclusive to someone */ -#define AFF_DELETE 0x0004 /* Address file object is sheduled to be deleted */ -#define AFF_SEND 0x0008 /* A send request is pending */ -#define AFF_RECEIVE 0x0010 /* A receive request is pending */ -#define AFF_PENDING 0x001C /* A request is pending */ - -/* Macros for manipulating address file object flags */ - -#define AF_IS_VALID(ADF) ((ADF)->Flags & AFF_VALID) -#define AF_SET_VALID(ADF) ((ADF)->Flags |= AFF_VALID) -#define AF_CLR_VALID(ADF) ((ADF)->Flags &= ~AFF_VALID) - -#define AF_IS_BUSY(ADF) ((ADF)->Flags & AFF_BUSY) -#define AF_SET_BUSY(ADF) ((ADF)->Flags |= AFF_BUSY) -#define AF_CLR_BUSY(ADF) ((ADF)->Flags &= ~AFF_BUSY) - -#define AF_IS_PENDING(ADF, X) (ADF->Flags & X) -#define AF_SET_PENDING(ADF, X) (ADF->Flags |= X) -#define AF_CLR_PENDING(ADF, X) (ADF->Flags &= ~X) - - -/* Structure used to search through Address Files */ -typedef struct _AF_SEARCH { - PLIST_ENTRY Next; /* Next address file to check */ - PIP_ADDRESS Address; /* Pointer to address to be found */ - USHORT Port; /* Network port */ - USHORT Protocol; /* Protocol number */ -} AF_SEARCH, *PAF_SEARCH; - -/* Transport connection context structure. The FileObject->FsContext2 - field holds a pointer to this structure */ -typedef struct _CONNECTION_ENDPOINT { - LIST_ENTRY ListEntry; /* Entry on list */ - KSPIN_LOCK Lock; /* Spin lock to protect this structure */ - ULONG RefCount; /* Number of references to this object */ -} CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT; - -/* Transport control channel context structure. The FileObject->FsContext2 - field holds a pointer to this structure */ -typedef struct _CONTROL_CHANNEL { - LIST_ENTRY ListEntry; /* Entry on list */ - KSPIN_LOCK Lock; /* Spin lock to protect this structure */ - ULONG RefCount; /* Number of references to this object */ -} CONTROL_CHANNEL, *PCONTROL_CHANNEL; - -typedef struct _TI_QUERY_CONTEXT { - PIRP Irp; - PMDL InputMdl; - PMDL OutputMdl; - TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo; -} TI_QUERY_CONTEXT, *PTI_QUERY_CONTEXT; - -#endif /* __TITYPES_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/titypes.h + * PURPOSE: TCP/IP protocol driver types + */ +#ifndef __TITYPES_H +#define __TITYPES_H + +#include + + +#ifdef DBG + +#define DEBUG_REFCHECK(Object) { \ + if ((Object)->RefCount <= 0) { \ + TI_DbgPrint(MIN_TRACE, ("Object at (0x%X) has invalid reference count (%d).\n", \ + (Object), (Object)->RefCount)); \ + } \ +} + +#else + +#define DEBUG_REFCHECK(Object) + +#endif + + +/* + * VOID ReferenceObject( + * PVOID Object) + */ +#define ReferenceObject(Object) \ +{ \ + DEBUG_REFCHECK(Object); \ + TI_DbgPrint(DEBUG_REFCOUNT, ("Referencing object at (0x%X). RefCount (%d).\n", \ + (Object), (Object)->RefCount)); \ + \ + InterlockedIncrement(&((Object)->RefCount)); \ +} + +/* + * VOID DereferenceObject( + * PVOID Object) + */ +#define DereferenceObject(Object) \ +{ \ + DEBUG_REFCHECK(Object); \ + TI_DbgPrint(DEBUG_REFCOUNT, ("Dereferencing object at (0x%X). RefCount (%d).\n", \ + (Object), (Object)->RefCount)); \ + \ + if (InterlockedDecrement(&((Object)->RefCount)) == 0) \ + PoolFreeBuffer(Object); \ +} + + +typedef NTSTATUS (*DATAGRAM_SEND_ROUTINE)( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG DataSize); + +/* Datagram completion handler prototype */ +typedef VOID (*DATAGRAM_COMPLETION_ROUTINE)( + PVOID Context, + NDIS_STATUS Status, + ULONG Count); + +typedef struct _DATAGRAM_RECEIVE_REQUEST { + LIST_ENTRY ListEntry; /* Entry on list */ + PIP_ADDRESS RemoteAddress; /* Remote address we receive from (NULL means any) */ + USHORT RemotePort; /* Remote port we receive from (0 means any) */ + PTDI_CONNECTION_INFORMATION ReturnInfo; /* Return information */ + PNDIS_BUFFER Buffer; /* Pointer to receive buffer */ + ULONG BufferSize; /* Size of Buffer */ + DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine */ + PVOID Context; /* Pointer to context information */ +} DATAGRAM_RECEIVE_REQUEST, *PDATAGRAM_RECEIVE_REQUEST; + +/* Datagram build routine prototype */ +typedef NTSTATUS (*DATAGRAM_BUILD_ROUTINE)( + PVOID Context, + PIP_ADDRESS LocalAddress, + USHORT LocalPort, + PIP_PACKET *IPPacket); + +typedef struct _DATAGRAM_SEND_REQUEST { + LIST_ENTRY ListEntry; /* Entry on list */ + PIP_ADDRESS RemoteAddress; /* Pointer to remote IP address */ + USHORT RemotePort; /* Remote port number */ + PNDIS_BUFFER Buffer; /* Pointer to NDIS buffer to send */ + DWORD BufferSize; /* Size of Buffer */ + DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine */ + PVOID Context; /* Pointer to context information */ + DATAGRAM_BUILD_ROUTINE Build; /* Datagram build routine */ +} DATAGRAM_SEND_REQUEST, *PDATAGRAM_SEND_REQUEST; + + +/* Transport (TCP/UDP) endpoint context structure. The FileObject->FsContext + field holds a pointer to this structure */ +typedef struct _TRANSPORT_CONTEXT { + union { + HANDLE AddressHandle; + CONNECTION_CONTEXT ConnectionContext; + HANDLE ControlChannel; + } Handle; + ULONG RefCount; + BOOL CancelIrps; + KEVENT CleanupEvent; +} TRANSPORT_CONTEXT, *PTRANSPORT_CONTEXT; + + +typedef struct _ADDRESS_FILE { + LIST_ENTRY ListEntry; /* Entry on list */ + KSPIN_LOCK Lock; /* Spin lock to manipulate this structure */ + ULONG RefCount; /* Number of references to this object */ + USHORT Flags; /* Flags for address file (see below) */ + PADDRESS_ENTRY ADE; /* Associated address entry */ + USHORT Protocol; /* Protocol number */ + USHORT Port; /* Network port (network byte order) */ + WORK_QUEUE_ITEM WorkItem; /* Work queue item handle */ + DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine for delete request */ + PVOID Context; /* Delete request context */ + DATAGRAM_SEND_ROUTINE Send; /* Routine to send a datagram */ + LIST_ENTRY ReceiveQueue; /* List of outstanding receive requests */ + LIST_ENTRY TransmitQueue; /* List of outstanding transmit requests */ + PIP_ADDRESS AddrCache; /* One entry address cache (destination + address of last packet transmitted) */ + + /* The following members are used to control event notification */ + + /* Connection indication handler */ + PTDI_IND_CONNECT ConnectionHandler; + PVOID ConnectionHandlerContext; + BOOL RegisteredConnectionHandler; + /* Disconnect indication handler */ + PTDI_IND_DISCONNECT DisconnectHandler; + PVOID DisconnectHandlerContext; + BOOL RegisteredDisconnectHandler; + /* Receive indication handler */ + PTDI_IND_RECEIVE ReceiveHandler; + PVOID ReceiveHandlerContext; + BOOL RegisteredReceiveHandler; + /* Expedited receive indication handler */ + PTDI_IND_RECEIVE_EXPEDITED ExpeditedReceiveHandler; + PVOID ExpeditedReceiveHandlerContext; + BOOL RegisteredExpeditedReceiveHandler; + /* Receive datagram indication handler */ + PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler; + PVOID ReceiveDatagramHandlerContext; + BOOL RegisteredReceiveDatagramHandler; + /* Error indication handler */ + PTDI_IND_ERROR ErrorHandler; + PVOID ErrorHandlerContext; + PVOID ErrorHandlerOwner; + BOOL RegisteredErrorHandler; +} ADDRESS_FILE, *PADDRESS_FILE; + +/* Address File Flag constants */ +#define AFF_VALID 0x0001 /* Address file object is valid for use */ +#define AFF_BUSY 0x0002 /* Address file object is exclusive to someone */ +#define AFF_DELETE 0x0004 /* Address file object is sheduled to be deleted */ +#define AFF_SEND 0x0008 /* A send request is pending */ +#define AFF_RECEIVE 0x0010 /* A receive request is pending */ +#define AFF_PENDING 0x001C /* A request is pending */ + +/* Macros for manipulating address file object flags */ + +#define AF_IS_VALID(ADF) ((ADF)->Flags & AFF_VALID) +#define AF_SET_VALID(ADF) ((ADF)->Flags |= AFF_VALID) +#define AF_CLR_VALID(ADF) ((ADF)->Flags &= ~AFF_VALID) + +#define AF_IS_BUSY(ADF) ((ADF)->Flags & AFF_BUSY) +#define AF_SET_BUSY(ADF) ((ADF)->Flags |= AFF_BUSY) +#define AF_CLR_BUSY(ADF) ((ADF)->Flags &= ~AFF_BUSY) + +#define AF_IS_PENDING(ADF, X) (ADF->Flags & X) +#define AF_SET_PENDING(ADF, X) (ADF->Flags |= X) +#define AF_CLR_PENDING(ADF, X) (ADF->Flags &= ~X) + + +/* Structure used to search through Address Files */ +typedef struct _AF_SEARCH { + PLIST_ENTRY Next; /* Next address file to check */ + PIP_ADDRESS Address; /* Pointer to address to be found */ + USHORT Port; /* Network port */ + USHORT Protocol; /* Protocol number */ +} AF_SEARCH, *PAF_SEARCH; + +/* Transport connection context structure. The FileObject->FsContext2 + field holds a pointer to this structure */ +typedef struct _CONNECTION_ENDPOINT { + LIST_ENTRY ListEntry; /* Entry on list */ + KSPIN_LOCK Lock; /* Spin lock to protect this structure */ + ULONG RefCount; /* Number of references to this object */ +} CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT; + +/* Transport control channel context structure. The FileObject->FsContext2 + field holds a pointer to this structure */ +typedef struct _CONTROL_CHANNEL { + LIST_ENTRY ListEntry; /* Entry on list */ + KSPIN_LOCK Lock; /* Spin lock to protect this structure */ + ULONG RefCount; /* Number of references to this object */ +} CONTROL_CHANNEL, *PCONTROL_CHANNEL; + +typedef struct _TI_QUERY_CONTEXT { + PIRP Irp; + PMDL InputMdl; + PMDL OutputMdl; + TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo; +} TI_QUERY_CONTEXT, *PTI_QUERY_CONTEXT; + +#endif /* __TITYPES_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/transmit.h b/reactos/drivers/net/tcpip/include/transmit.h index c0f816787f2..618e6322101 100644 --- a/reactos/drivers/net/tcpip/include/transmit.h +++ b/reactos/drivers/net/tcpip/include/transmit.h @@ -1,47 +1,47 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/transmit.h - * PURPOSE: Internet Protocol transmit prototypes - */ -#ifndef __TRANSMIT_H -#define __TRANSMIT_H - -#include -#include -#include - - -/* IP fragment context information */ -typedef struct IPFRAGMENT_CONTEXT { - struct IPFRAGMENT_CONTEXT *Next; /* Pointer to next in list */ - PNDIS_PACKET Datagram; /* Pointer to original NDIS packet */ - PVOID DatagramData; /* Pointer to datagram data */ - UINT HeaderSize; /* IP datagram header size */ - PNDIS_PACKET NdisPacket; /* Pointer to NDIS packet */ - PNDIS_BUFFER NdisBuffer; /* Pointer to NDIS buffer */ - PVOID Header; /* Pointer to IP header in fragment buffer */ - PVOID Data; /* Pointer to fragment data */ - UINT Position; /* Current fragment offset */ - UINT BytesLeft; /* Number of bytes left to send */ - UINT PathMTU; /* Path Maximum Transmission Unit */ - PNEIGHBOR_CACHE_ENTRY NCE; /* Pointer to NCE to use */ -} IPFRAGMENT_CONTEXT, *PIPFRAGMENT_CONTEXT; - - -VOID IPSendComplete( - PVOID Context, - PNDIS_PACKET NdisPacket, - NDIS_STATUS NdisStatus); - -NTSTATUS IPSendFragment( - PNDIS_PACKET NdisPacket, - PNEIGHBOR_CACHE_ENTRY NCE); - -NTSTATUS IPSendDatagram( - PIP_PACKET IPPacket, - PROUTE_CACHE_NODE RCN); - -#endif /* __TRANSMIT_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/transmit.h + * PURPOSE: Internet Protocol transmit prototypes + */ +#ifndef __TRANSMIT_H +#define __TRANSMIT_H + +#include +#include +#include + + +/* IP fragment context information */ +typedef struct IPFRAGMENT_CONTEXT { + struct IPFRAGMENT_CONTEXT *Next; /* Pointer to next in list */ + PNDIS_PACKET Datagram; /* Pointer to original NDIS packet */ + PVOID DatagramData; /* Pointer to datagram data */ + UINT HeaderSize; /* IP datagram header size */ + PNDIS_PACKET NdisPacket; /* Pointer to NDIS packet */ + PNDIS_BUFFER NdisBuffer; /* Pointer to NDIS buffer */ + PVOID Header; /* Pointer to IP header in fragment buffer */ + PVOID Data; /* Pointer to fragment data */ + UINT Position; /* Current fragment offset */ + UINT BytesLeft; /* Number of bytes left to send */ + UINT PathMTU; /* Path Maximum Transmission Unit */ + PNEIGHBOR_CACHE_ENTRY NCE; /* Pointer to NCE to use */ +} IPFRAGMENT_CONTEXT, *PIPFRAGMENT_CONTEXT; + + +VOID IPSendComplete( + PVOID Context, + PNDIS_PACKET NdisPacket, + NDIS_STATUS NdisStatus); + +NTSTATUS IPSendFragment( + PNDIS_PACKET NdisPacket, + PNEIGHBOR_CACHE_ENTRY NCE); + +NTSTATUS IPSendDatagram( + PIP_PACKET IPPacket, + PROUTE_CACHE_NODE RCN); + +#endif /* __TRANSMIT_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/include/udp.h b/reactos/drivers/net/tcpip/include/udp.h index 919a86b5341..c289575713c 100644 --- a/reactos/drivers/net/tcpip/include/udp.h +++ b/reactos/drivers/net/tcpip/include/udp.h @@ -1,68 +1,68 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: include/udp.h - * PURPOSE: User Datagram Protocol definitions - */ -#ifndef __UDP_H -#define __UDP_H - - -/* UDPv4 header structure */ -typedef struct UDP_HEADER { - USHORT SourcePort; /* Source port */ - USHORT DestPort; /* Destination port */ - USHORT Length; /* Size of header and data */ - USHORT Checksum; /* Checksum of datagram */ -} UDP_HEADER, *PUDP_HEADER; - -/* UDPv4 pseudo header */ -typedef struct UDP_PSEUDO_HEADER { - ULONG SourceAddress; /* Source address */ - ULONG DestAddress; /* Destination address */ - UCHAR Zero; /* Reserved */ - UCHAR Protocol; /* Protocol */ - USHORT UDPLength; /* Size of UDP datagram */ -} UDP_PSEUDO_HEADER, *PUDP_PSEUDO_HEADER; - - -typedef struct UDP_STATISTICS { - ULONG InputDatagrams; - ULONG NumPorts; - ULONG InputErrors; - ULONG OutputDatagrams; - ULONG NumAddresses; -} UDP_STATISTICS, *PUDP_STATISTICS; - -VOID UDPSend( - PVOID Context, - PDATAGRAM_SEND_REQUEST SendRequest); - -NTSTATUS UDPSendDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG DataSize); - -NTSTATUS UDPReceiveDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG ReceiveLength, - ULONG ReceiveFlags, - PTDI_CONNECTION_INFORMATION ReturnInfo, - PULONG BytesReceived); - -VOID UDPReceive( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket); - -NTSTATUS UDPStartup( - VOID); - -NTSTATUS UDPShutdown( - VOID); - -#endif /* __UDP_H */ - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: include/udp.h + * PURPOSE: User Datagram Protocol definitions + */ +#ifndef __UDP_H +#define __UDP_H + + +/* UDPv4 header structure */ +typedef struct UDP_HEADER { + USHORT SourcePort; /* Source port */ + USHORT DestPort; /* Destination port */ + USHORT Length; /* Size of header and data */ + USHORT Checksum; /* Checksum of datagram */ +} UDP_HEADER, *PUDP_HEADER; + +/* UDPv4 pseudo header */ +typedef struct UDP_PSEUDO_HEADER { + ULONG SourceAddress; /* Source address */ + ULONG DestAddress; /* Destination address */ + UCHAR Zero; /* Reserved */ + UCHAR Protocol; /* Protocol */ + USHORT UDPLength; /* Size of UDP datagram */ +} UDP_PSEUDO_HEADER, *PUDP_PSEUDO_HEADER; + + +typedef struct UDP_STATISTICS { + ULONG InputDatagrams; + ULONG NumPorts; + ULONG InputErrors; + ULONG OutputDatagrams; + ULONG NumAddresses; +} UDP_STATISTICS, *PUDP_STATISTICS; + +VOID UDPSend( + PVOID Context, + PDATAGRAM_SEND_REQUEST SendRequest); + +NTSTATUS UDPSendDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG DataSize); + +NTSTATUS UDPReceiveDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG ReceiveLength, + ULONG ReceiveFlags, + PTDI_CONNECTION_INFORMATION ReturnInfo, + PULONG BytesReceived); + +VOID UDPReceive( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket); + +NTSTATUS UDPStartup( + VOID); + +NTSTATUS UDPShutdown( + VOID); + +#endif /* __UDP_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/makefile b/reactos/drivers/net/tcpip/makefile index db914fae34c..b6e4d7feb04 100644 --- a/reactos/drivers/net/tcpip/makefile +++ b/reactos/drivers/net/tcpip/makefile @@ -1,132 +1,132 @@ -# TCPIP.SYS - TCP/IP protocol driver - -TARGETNAME=tcpip - -BASE_CFLAGS = -I./include -I../../../include - -RESOURCE_OBJECT = $(TARGETNAME).coff -TCPIP_OBJECTS = tcpip/main.o tcpip/address.o tcpip/checksum.o \ - tcpip/dispatch.o tcpip/fileobjs.o tcpip/info.o \ - tcpip/pool.o tcpip/routines.o -DATALINK_OBJECTS = datalink/arp.o datalink/lan.o datalink/loopback.o -NETWORK_OBJECTS = network/icmp.o network/ip.o network/neighbor.o \ - network/receive.o network/route.o network/router.o \ - network/transmit.o -DATAGRAM_OBJECTS = transport/datagram/datagram.o -RAWIP_OBJECTS = transport/rawip/rawip.o -TCP_OBJECTS = transport/tcp/tcp.o -UDP_OBJECTS = transport/udp/udp.o - -all: objects $(TARGETNAME).sys - -objects: - mkdir objects - -objects/tcpip.o: $(TCPIP_OBJECTS) - $(LD) -r -o objects/tcpip.o $(TCPIP_OBJECTS) - -objects/datalink.o: $(DATALINK_OBJECTS) - $(LD) -r -o objects/datalink.o $(DATALINK_OBJECTS) - -objects/network.o: $(NETWORK_OBJECTS) - $(LD) -r -o objects/network.o $(NETWORK_OBJECTS) - -objects/datagram.o: $(DATAGRAM_OBJECTS) - $(LD) -r -o objects/datagram.o $(DATAGRAM_OBJECTS) - -objects/rawip.o: $(RAWIP_OBJECTS) - $(LD) -r -o objects/rawip.o $(RAWIP_OBJECTS) - -objects/tcp.o: $(TCP_OBJECTS) - $(LD) -r -o objects/tcp.o $(TCP_OBJECTS) - -objects/udp.o: $(UDP_OBJECTS) - $(LD) -r -o objects/udp.o $(UDP_OBJECTS) - -OBJECTS = objects/tcpip.o objects/datalink.o objects/network.o \ - objects/datagram.o objects/rawip.o objects/tcp.o objects/udp.o \ - $(RESOURCE_OBJECT) \ - ../../../ntoskrnl/ntoskrnl.a ../ndis/ndis.a - -$(TARGETNAME).coff: $(TARGETNAME).rc ../../../include/reactos/resource.h - -ifeq ($(DOSCLI),yes) -CLEAN_FILES = \ - *.o objects\*.o tcpip\*.o datalink\*.o network\*.o \ - transport\datagram\*.o transport\rawip\*.o \ - transport\tcp\*.o transport\udp\*.o $(TARGETNAME).coff \ - $(TARGETNAME).a junk.tmp base.tmp temp.exp \ - $(TARGETNAME).sys $(TARGETNAME).sym -else -CLEAN_FILES = \ - *.o objects/*.o tcpip/*.o datalink/*.o network/*.o \ - transport/datagram/*.o transport/rawip/*.o \ - transport/tcp/*.o transport/udp/*.o $(TARGETNAME).coff \ - $(TARGETNAME).a junk.tmp base.tmp temp.exp \ - $(TARGETNAME).sys $(TARGETNAME).sym -endif - - -$(TARGETNAME).sys: $(OBJECTS) - $(DLLTOOL) \ - --dllname $(TARGETNAME).sys \ - --def $(TARGETNAME).def \ - --kill-at \ - --output-lib $(TARGETNAME).a - $(CC) \ - -mdll \ - -specs=../../svc_specs \ - -Wl,-e,_DriverEntry@8 \ - -Wl,--base-file,base.tmp \ - -Wl,--defsym,_end=end \ - -Wl,--defsym,_edata=__data_end__ \ - -Wl,--defsym,_etext=etext \ - $(OBJECTS) \ - -o junk.tmp - - $(RM) junk.tmp - $(DLLTOOL) \ - --dllname $(TARGETNAME).sys \ - --base-file base.tmp \ - --output-exp temp.exp \ - --def $(TARGETNAME).edf - - $(RM) base.tmp - $(CC) \ - -mdll \ - -specs=../../svc_specs \ - -Wl,--image-base,0x10000 \ - -Wl,-e,_DriverEntry@8 \ - -Wl,temp.exp \ - $(OBJECTS) \ - -o $(TARGETNAME).sys - - $(RM) temp.exp - $(NM) --numeric-sort $(TARGETNAME).sys > $(TARGETNAME).sym - -clean: $(CLEAN_FILES:%=%_clean) - -$(CLEAN_FILES:%=%_clean): %_clean: - - $(RM) $* - -.PHONY: clean $(CLEAN_FILES:%=%_clean) - -floppy: $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys - -$(FLOPPY_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys -ifeq ($(DOSCLI),yes) - $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)\drivers\$(TARGETNAME).sys -else - $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys -endif - -dist: $(DIST_DIR)/drivers/$(TARGETNAME).sys - -$(DIST_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys -ifeq ($(DOSCLI),yes) - $(CP) $(TARGETNAME).sys ..\..\$(DIST_DIR)\drivers\$(TARGETNAME).sys -else - $(CP) $(TARGETNAME).sys ../../$(DIST_DIR)/drivers/$(TARGETNAME).sys -endif - -#WITH_DEBUGGING = yes -#WIN32_LEAN_AND_MEAN = yes -#WARNINGS_ARE_ERRORS = yes -include ../../../rules.mak +# TCPIP.SYS - TCP/IP protocol driver + +TARGETNAME=tcpip + +BASE_CFLAGS = -I./include -I../../../include + +RESOURCE_OBJECT = $(TARGETNAME).coff +TCPIP_OBJECTS = tcpip/main.o tcpip/address.o tcpip/checksum.o \ + tcpip/dispatch.o tcpip/fileobjs.o tcpip/info.o \ + tcpip/pool.o tcpip/routines.o +DATALINK_OBJECTS = datalink/arp.o datalink/lan.o datalink/loopback.o +NETWORK_OBJECTS = network/icmp.o network/ip.o network/neighbor.o \ + network/receive.o network/route.o network/router.o \ + network/transmit.o +DATAGRAM_OBJECTS = transport/datagram/datagram.o +RAWIP_OBJECTS = transport/rawip/rawip.o +TCP_OBJECTS = transport/tcp/tcp.o +UDP_OBJECTS = transport/udp/udp.o + +all: objects $(TARGETNAME).sys + +objects: + mkdir objects + +objects/tcpip.o: $(TCPIP_OBJECTS) + $(LD) -r -o objects/tcpip.o $(TCPIP_OBJECTS) + +objects/datalink.o: $(DATALINK_OBJECTS) + $(LD) -r -o objects/datalink.o $(DATALINK_OBJECTS) + +objects/network.o: $(NETWORK_OBJECTS) + $(LD) -r -o objects/network.o $(NETWORK_OBJECTS) + +objects/datagram.o: $(DATAGRAM_OBJECTS) + $(LD) -r -o objects/datagram.o $(DATAGRAM_OBJECTS) + +objects/rawip.o: $(RAWIP_OBJECTS) + $(LD) -r -o objects/rawip.o $(RAWIP_OBJECTS) + +objects/tcp.o: $(TCP_OBJECTS) + $(LD) -r -o objects/tcp.o $(TCP_OBJECTS) + +objects/udp.o: $(UDP_OBJECTS) + $(LD) -r -o objects/udp.o $(UDP_OBJECTS) + +OBJECTS = objects/tcpip.o objects/datalink.o objects/network.o \ + objects/datagram.o objects/rawip.o objects/tcp.o objects/udp.o \ + $(RESOURCE_OBJECT) \ + ../../../ntoskrnl/ntoskrnl.a ../ndis/ndis.a + +$(TARGETNAME).coff: $(TARGETNAME).rc ../../../include/reactos/resource.h + +ifeq ($(DOSCLI),yes) +CLEAN_FILES = \ + *.o objects\*.o tcpip\*.o datalink\*.o network\*.o \ + transport\datagram\*.o transport\rawip\*.o \ + transport\tcp\*.o transport\udp\*.o $(TARGETNAME).coff \ + $(TARGETNAME).a junk.tmp base.tmp temp.exp \ + $(TARGETNAME).sys $(TARGETNAME).sym +else +CLEAN_FILES = \ + *.o objects/*.o tcpip/*.o datalink/*.o network/*.o \ + transport/datagram/*.o transport/rawip/*.o \ + transport/tcp/*.o transport/udp/*.o $(TARGETNAME).coff \ + $(TARGETNAME).a junk.tmp base.tmp temp.exp \ + $(TARGETNAME).sys $(TARGETNAME).sym +endif + + +$(TARGETNAME).sys: $(OBJECTS) + $(DLLTOOL) \ + --dllname $(TARGETNAME).sys \ + --def $(TARGETNAME).def \ + --kill-at \ + --output-lib $(TARGETNAME).a + $(CC) \ + -mdll \ + -specs=../../svc_specs \ + -Wl,-e,_DriverEntry@8 \ + -Wl,--base-file,base.tmp \ + -Wl,--defsym,_end=end \ + -Wl,--defsym,_edata=__data_end__ \ + -Wl,--defsym,_etext=etext \ + $(OBJECTS) \ + -o junk.tmp + - $(RM) junk.tmp + $(DLLTOOL) \ + --dllname $(TARGETNAME).sys \ + --base-file base.tmp \ + --output-exp temp.exp \ + --def $(TARGETNAME).edf + - $(RM) base.tmp + $(CC) \ + -mdll \ + -specs=../../svc_specs \ + -Wl,--image-base,0x10000 \ + -Wl,-e,_DriverEntry@8 \ + -Wl,temp.exp \ + $(OBJECTS) \ + -o $(TARGETNAME).sys + - $(RM) temp.exp + $(NM) --numeric-sort $(TARGETNAME).sys > $(TARGETNAME).sym + +clean: $(CLEAN_FILES:%=%_clean) + +$(CLEAN_FILES:%=%_clean): %_clean: + - $(RM) $* + +.PHONY: clean $(CLEAN_FILES:%=%_clean) + +floppy: $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys + +$(FLOPPY_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys +ifeq ($(DOSCLI),yes) + $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)\drivers\$(TARGETNAME).sys +else + $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys +endif + +dist: $(DIST_DIR)/drivers/$(TARGETNAME).sys + +$(DIST_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys +ifeq ($(DOSCLI),yes) + $(CP) $(TARGETNAME).sys ..\..\$(DIST_DIR)\drivers\$(TARGETNAME).sys +else + $(CP) $(TARGETNAME).sys ../../$(DIST_DIR)/drivers/$(TARGETNAME).sys +endif + +#WITH_DEBUGGING = yes +#WIN32_LEAN_AND_MEAN = yes +#WARNINGS_ARE_ERRORS = yes +include ../../../rules.mak diff --git a/reactos/drivers/net/tcpip/network/Makefile b/reactos/drivers/net/tcpip/network/Makefile index 9c985f57bc6..58189757d61 100644 --- a/reactos/drivers/net/tcpip/network/Makefile +++ b/reactos/drivers/net/tcpip/network/Makefile @@ -1,7 +1,7 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/reactos/drivers/net/tcpip/network/SOURCES b/reactos/drivers/net/tcpip/network/SOURCES index 076841668fe..3723ad55fae 100644 --- a/reactos/drivers/net/tcpip/network/SOURCES +++ b/reactos/drivers/net/tcpip/network/SOURCES @@ -1,20 +1,20 @@ -TARGETNAME=network -TARGETPATH=..\objects -TARGETTYPE=LIBRARY - -TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ - $(DDK_LIB_PATH)\ndis.lib - -INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net - - -SOURCES= icmp.c \ - ip.c \ - neighbor.c \ - receive.c \ - route.c \ - router.c \ - transmit.c - -MSC_WARNING_LEVEL=/W3 /WX - +TARGETNAME=network +TARGETPATH=..\objects +TARGETTYPE=LIBRARY + +TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ + $(DDK_LIB_PATH)\ndis.lib + +INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net + + +SOURCES= icmp.c \ + ip.c \ + neighbor.c \ + receive.c \ + route.c \ + router.c \ + transmit.c + +MSC_WARNING_LEVEL=/W3 /WX + diff --git a/reactos/drivers/net/tcpip/network/icmp.c b/reactos/drivers/net/tcpip/network/icmp.c index f75e6b094fc..297d69db64f 100644 --- a/reactos/drivers/net/tcpip/network/icmp.c +++ b/reactos/drivers/net/tcpip/network/icmp.c @@ -1,299 +1,299 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: network/icmp.c - * PURPOSE: Internet Control Message Protocol routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include - - -VOID SendICMPComplete( - PVOID Context, - PNDIS_PACKET Packet, - NDIS_STATUS NdisStatus) -/* - * FUNCTION: ICMP datagram transmit completion handler - * ARGUMENTS: - * Context = Pointer to context infomation (IP_PACKET) - * Packet = Pointer to NDIS packet - * NdisStatus = Status of transmit operation - * NOTES: - * This routine is called by IP when a ICMP send completes - */ -{ - PIP_PACKET IPPacket = (PIP_PACKET)Context; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - TI_DbgPrint(MAX_TRACE, ("Freeing NDIS packet (%X).\n", Packet)); - - /* Free packet */ - FreeNdisPacket(Packet); - - TI_DbgPrint(MAX_TRACE, ("Freeing IP packet at %X.\n", IPPacket)); - - PoolFreeBuffer(IPPacket); -} - - -PIP_PACKET PrepareICMPPacket( - PNET_TABLE_ENTRY NTE, - PIP_ADDRESS Destination, - UINT DataSize) -/* - * FUNCTION: Prepares an ICMP packet - * ARGUMENTS: - * NTE = Pointer to net table entry to use - * Destination = Pointer to destination address - * DataSize = Size of dataarea - * RETURNS: - * Pointer to IP packet, NULL if there is not enough free resources - */ -{ - PIP_PACKET IPPacket; - PNDIS_PACKET NdisPacket; - PNDIS_BUFFER NdisBuffer; - NDIS_STATUS NdisStatus; - PIPv4_HEADER IPHeader; - PVOID DataBuffer; - ULONG Size; - - TI_DbgPrint(MAX_TRACE, ("Called. DataSize = %d.\n", DataSize)); - - /* Prepare ICMP packet */ - IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET)); - if (!IPPacket) - return NULL; - - TI_DbgPrint(MAX_TRACE, ("IPPacket at %X.\n", IPPacket)); - - Size = MaxLLHeaderSize + sizeof(IPv4_HEADER) + - sizeof(ICMP_HEADER) + DataSize; - DataBuffer = ExAllocatePool(NonPagedPool, Size); - if (!DataBuffer) { - PoolFreeBuffer(IPPacket); - return NULL; - } - - TI_DbgPrint(MAX_TRACE, ("Size = %d, Data at %X.\n", Size, DataBuffer)); - - /* Allocate NDIS packet */ - NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - PoolFreeBuffer(IPPacket); - ExFreePool(DataBuffer); - return NULL; - } - - TI_DbgPrint(MAX_TRACE, ("NdisPacket at %X.\n", NdisPacket)); - - /* Allocate NDIS buffer for maximum link level header and ICMP packet */ - NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool, - DataBuffer, Size); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - PoolFreeBuffer(IPPacket); - NdisFreePacket(NdisPacket); - ExFreePool(DataBuffer); - return NULL; - } - - TI_DbgPrint(MAX_TRACE, ("NdisBuffer at %X.\n", NdisBuffer)); - - /* Link NDIS buffer into packet */ - NdisChainBufferAtFront(NdisPacket, NdisBuffer); - IPPacket->NdisPacket = NdisPacket; - IPPacket->Header = (PVOID)((ULONG_PTR)DataBuffer + MaxLLHeaderSize); - IPPacket->Data = (PVOID)((ULONG_PTR)DataBuffer + MaxLLHeaderSize + sizeof(IPv4_HEADER)); - - IPPacket->HeaderSize = sizeof(IPv4_HEADER); - IPPacket->TotalSize = Size - MaxLLHeaderSize; - RtlCopyMemory(&IPPacket->DstAddr, Destination, sizeof(IP_ADDRESS)); - - /* Build IPv4 header. FIXME: IPv4 only */ - - IPHeader = (PIPv4_HEADER)IPPacket->Header; - - /* Version = 4, Length = 5 DWORDs */ - IPHeader->VerIHL = 0x45; - /* Normal Type-of-Service */ - IPHeader->Tos = 0; - /* Length of data and header */ - IPHeader->TotalLength = WH2N((USHORT)DataSize + - sizeof(IPv4_HEADER) + sizeof(ICMP_HEADER)); - /* Identification */ - IPHeader->Id = (USHORT)Random(); - /* One fragment at offset 0 */ - IPHeader->FlagsFragOfs = 0; - /* Time-to-Live is 128 */ - IPHeader->Ttl = 128; - /* Internet Control Message Protocol */ - IPHeader->Protocol = IPPROTO_ICMP; - /* Checksum is 0 (for later calculation of this) */ - IPHeader->Checksum = 0; - /* Source address */ - IPHeader->SrcAddr = NTE->Address->Address.IPv4Address; - /* Destination address */ - IPHeader->DstAddr = Destination->Address.IPv4Address; - - /* Completion handler */ - PC(NdisPacket)->Complete = SendICMPComplete; - PC(NdisPacket)->Context = IPPacket; - - return IPPacket; -} - - -VOID ICMPReceive( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket) -/* - * FUNCTION: Receives an ICMP packet - * ARGUMENTS: - * NTE = Pointer to net table entry which the packet was received on - * IPPacket = Pointer to an IP packet that was received - */ -{ - PICMP_HEADER ICMPHeader; - PIP_PACKET NewPacket; - UINT DataSize; - ULONG Checksum; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - ICMPHeader = (PICMP_HEADER)IPPacket->Data; - - TI_DbgPrint(MID_TRACE, ("Size = %d.\n", IPPacket->TotalSize)); - - TI_DbgPrint(MID_TRACE, ("HeaderSize = %d.\n", IPPacket->HeaderSize)); - - TI_DbgPrint(MID_TRACE, ("Type = %d.\n", ICMPHeader->Type)); - - TI_DbgPrint(MID_TRACE, ("Code = %d.\n", ICMPHeader->Code)); - - TI_DbgPrint(MID_TRACE, ("Checksum = %X.\n", ICMPHeader->Checksum)); - - /* Checksum ICMP header and data and compare */ - Checksum = DN2H(IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0)); - if (Checksum != 0xFFFF) { - TI_DbgPrint(MIN_TRACE, ("Bad ICMP checksum (0x%X).\n", Checksum)); - /* Discard packet */ - return; - } - - switch (ICMPHeader->Type) { - case ICMP_TYPE_ECHO_REQUEST: - /* Reply with an ICMP echo reply message */ - DataSize = IPPacket->TotalSize - IPPacket->HeaderSize - sizeof(ICMP_HEADER); - NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize); - if (!NewPacket) - return; - - /* Copy ICMP header and data into new packet */ - RtlCopyMemory(NewPacket->Data, IPPacket->Data, DataSize + sizeof(ICMP_HEADER)); - ((PICMP_HEADER)NewPacket->Data)->Type = ICMP_TYPE_ECHO_REPLY; - ((PICMP_HEADER)NewPacket->Data)->Code = 0; - ((PICMP_HEADER)NewPacket->Data)->Checksum = 0; - - ICMPTransmit(NTE, NewPacket); - - TI_DbgPrint(MID_TRACE, ("Echo reply sent.\n")); - - return; - default: - TI_DbgPrint(MID_TRACE, ("Discarded ICMP datagram of unknown type.\n")); - /* Discard packet */ - break; - } -} - - -VOID ICMPTransmit( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket) -/* - * FUNCTION: Transmits an ICMP packet - * ARGUMENTS: - * NTE = Pointer to net table entry to use (NULL if don't care) - * IPPacket = Pointer to IP packet to transmit - */ -{ - PROUTE_CACHE_NODE RCN; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - /* Calculate checksum of ICMP header and data */ - ((PICMP_HEADER)IPPacket->Data)->Checksum = (USHORT) - IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0); - - /* Get a route to the destination address */ - if (RouteGetRouteToDestination(&IPPacket->DstAddr, NTE, &RCN) == IP_SUCCESS) { - /* Send the packet */ - if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS) { - FreeNdisPacket(IPPacket->NdisPacket); - PoolFreeBuffer(IPPacket); - } - /* We're done with the RCN */ - DereferenceObject(RCN); - } else { - TI_DbgPrint(MIN_TRACE, ("RCN at 0x%X.\n", RCN)); - - /* No route to destination (or no free resources) */ - TI_DbgPrint(MIN_TRACE, ("No route to destination address 0x%X.\n", - IPPacket->DstAddr.Address.IPv4Address)); - /* Discard packet */ - FreeNdisPacket(IPPacket->NdisPacket); - PoolFreeBuffer(IPPacket); - } -} - - -VOID ICMPReply( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket, - UCHAR Type, - UCHAR Code) -/* - * FUNCTION: Transmits an ICMP packet in response to an incoming packet - * ARGUMENTS: - * NTE = Pointer to net table entry to use - * IPPacket = Pointer to IP packet that was received - * Type = ICMP message type - * Code = ICMP message code - * NOTES: - * We have received a packet from someone and is unable to - * process it due to error(s) in the packet or we have run out - * of resources. We transmit an ICMP message to the host to - * notify him of the problem - */ -{ - UINT DataSize; - PIP_PACKET NewPacket; - - TI_DbgPrint(MID_TRACE, ("Called (Type=%d, Code=%d).\n", Type, Code)); - - DataSize = IPPacket->TotalSize; - if ((DataSize) > (576 - sizeof(IPv4_HEADER) - sizeof(ICMP_HEADER))) - DataSize = 576; - - NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize); - if (!NewPacket) - return; - - RtlCopyMemory((PVOID)((ULONG_PTR)NewPacket->Data + sizeof(ICMP_HEADER)), - IPPacket->Header, DataSize); - ((PICMP_HEADER)NewPacket->Data)->Type = Type; - ((PICMP_HEADER)NewPacket->Data)->Code = Code; - ((PICMP_HEADER)NewPacket->Data)->Checksum = 0; - - ICMPTransmit(NTE, NewPacket); -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: network/icmp.c + * PURPOSE: Internet Control Message Protocol routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include + + +VOID SendICMPComplete( + PVOID Context, + PNDIS_PACKET Packet, + NDIS_STATUS NdisStatus) +/* + * FUNCTION: ICMP datagram transmit completion handler + * ARGUMENTS: + * Context = Pointer to context infomation (IP_PACKET) + * Packet = Pointer to NDIS packet + * NdisStatus = Status of transmit operation + * NOTES: + * This routine is called by IP when a ICMP send completes + */ +{ + PIP_PACKET IPPacket = (PIP_PACKET)Context; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + TI_DbgPrint(MAX_TRACE, ("Freeing NDIS packet (%X).\n", Packet)); + + /* Free packet */ + FreeNdisPacket(Packet); + + TI_DbgPrint(MAX_TRACE, ("Freeing IP packet at %X.\n", IPPacket)); + + PoolFreeBuffer(IPPacket); +} + + +PIP_PACKET PrepareICMPPacket( + PNET_TABLE_ENTRY NTE, + PIP_ADDRESS Destination, + UINT DataSize) +/* + * FUNCTION: Prepares an ICMP packet + * ARGUMENTS: + * NTE = Pointer to net table entry to use + * Destination = Pointer to destination address + * DataSize = Size of dataarea + * RETURNS: + * Pointer to IP packet, NULL if there is not enough free resources + */ +{ + PIP_PACKET IPPacket; + PNDIS_PACKET NdisPacket; + PNDIS_BUFFER NdisBuffer; + NDIS_STATUS NdisStatus; + PIPv4_HEADER IPHeader; + PVOID DataBuffer; + ULONG Size; + + TI_DbgPrint(MAX_TRACE, ("Called. DataSize = %d.\n", DataSize)); + + /* Prepare ICMP packet */ + IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET)); + if (!IPPacket) + return NULL; + + TI_DbgPrint(MAX_TRACE, ("IPPacket at %X.\n", IPPacket)); + + Size = MaxLLHeaderSize + sizeof(IPv4_HEADER) + + sizeof(ICMP_HEADER) + DataSize; + DataBuffer = ExAllocatePool(NonPagedPool, Size); + if (!DataBuffer) { + PoolFreeBuffer(IPPacket); + return NULL; + } + + TI_DbgPrint(MAX_TRACE, ("Size = %d, Data at %X.\n", Size, DataBuffer)); + + /* Allocate NDIS packet */ + NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + PoolFreeBuffer(IPPacket); + ExFreePool(DataBuffer); + return NULL; + } + + TI_DbgPrint(MAX_TRACE, ("NdisPacket at %X.\n", NdisPacket)); + + /* Allocate NDIS buffer for maximum link level header and ICMP packet */ + NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool, + DataBuffer, Size); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + PoolFreeBuffer(IPPacket); + NdisFreePacket(NdisPacket); + ExFreePool(DataBuffer); + return NULL; + } + + TI_DbgPrint(MAX_TRACE, ("NdisBuffer at %X.\n", NdisBuffer)); + + /* Link NDIS buffer into packet */ + NdisChainBufferAtFront(NdisPacket, NdisBuffer); + IPPacket->NdisPacket = NdisPacket; + IPPacket->Header = (PVOID)((ULONG_PTR)DataBuffer + MaxLLHeaderSize); + IPPacket->Data = (PVOID)((ULONG_PTR)DataBuffer + MaxLLHeaderSize + sizeof(IPv4_HEADER)); + + IPPacket->HeaderSize = sizeof(IPv4_HEADER); + IPPacket->TotalSize = Size - MaxLLHeaderSize; + RtlCopyMemory(&IPPacket->DstAddr, Destination, sizeof(IP_ADDRESS)); + + /* Build IPv4 header. FIXME: IPv4 only */ + + IPHeader = (PIPv4_HEADER)IPPacket->Header; + + /* Version = 4, Length = 5 DWORDs */ + IPHeader->VerIHL = 0x45; + /* Normal Type-of-Service */ + IPHeader->Tos = 0; + /* Length of data and header */ + IPHeader->TotalLength = WH2N((USHORT)DataSize + + sizeof(IPv4_HEADER) + sizeof(ICMP_HEADER)); + /* Identification */ + IPHeader->Id = (USHORT)Random(); + /* One fragment at offset 0 */ + IPHeader->FlagsFragOfs = 0; + /* Time-to-Live is 128 */ + IPHeader->Ttl = 128; + /* Internet Control Message Protocol */ + IPHeader->Protocol = IPPROTO_ICMP; + /* Checksum is 0 (for later calculation of this) */ + IPHeader->Checksum = 0; + /* Source address */ + IPHeader->SrcAddr = NTE->Address->Address.IPv4Address; + /* Destination address */ + IPHeader->DstAddr = Destination->Address.IPv4Address; + + /* Completion handler */ + PC(NdisPacket)->Complete = SendICMPComplete; + PC(NdisPacket)->Context = IPPacket; + + return IPPacket; +} + + +VOID ICMPReceive( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket) +/* + * FUNCTION: Receives an ICMP packet + * ARGUMENTS: + * NTE = Pointer to net table entry which the packet was received on + * IPPacket = Pointer to an IP packet that was received + */ +{ + PICMP_HEADER ICMPHeader; + PIP_PACKET NewPacket; + UINT DataSize; + ULONG Checksum; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + ICMPHeader = (PICMP_HEADER)IPPacket->Data; + + TI_DbgPrint(MID_TRACE, ("Size = %d.\n", IPPacket->TotalSize)); + + TI_DbgPrint(MID_TRACE, ("HeaderSize = %d.\n", IPPacket->HeaderSize)); + + TI_DbgPrint(MID_TRACE, ("Type = %d.\n", ICMPHeader->Type)); + + TI_DbgPrint(MID_TRACE, ("Code = %d.\n", ICMPHeader->Code)); + + TI_DbgPrint(MID_TRACE, ("Checksum = %X.\n", ICMPHeader->Checksum)); + + /* Checksum ICMP header and data and compare */ + Checksum = DN2H(IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0)); + if (Checksum != 0xFFFF) { + TI_DbgPrint(MIN_TRACE, ("Bad ICMP checksum (0x%X).\n", Checksum)); + /* Discard packet */ + return; + } + + switch (ICMPHeader->Type) { + case ICMP_TYPE_ECHO_REQUEST: + /* Reply with an ICMP echo reply message */ + DataSize = IPPacket->TotalSize - IPPacket->HeaderSize - sizeof(ICMP_HEADER); + NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize); + if (!NewPacket) + return; + + /* Copy ICMP header and data into new packet */ + RtlCopyMemory(NewPacket->Data, IPPacket->Data, DataSize + sizeof(ICMP_HEADER)); + ((PICMP_HEADER)NewPacket->Data)->Type = ICMP_TYPE_ECHO_REPLY; + ((PICMP_HEADER)NewPacket->Data)->Code = 0; + ((PICMP_HEADER)NewPacket->Data)->Checksum = 0; + + ICMPTransmit(NTE, NewPacket); + + TI_DbgPrint(MID_TRACE, ("Echo reply sent.\n")); + + return; + default: + TI_DbgPrint(MID_TRACE, ("Discarded ICMP datagram of unknown type.\n")); + /* Discard packet */ + break; + } +} + + +VOID ICMPTransmit( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket) +/* + * FUNCTION: Transmits an ICMP packet + * ARGUMENTS: + * NTE = Pointer to net table entry to use (NULL if don't care) + * IPPacket = Pointer to IP packet to transmit + */ +{ + PROUTE_CACHE_NODE RCN; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + /* Calculate checksum of ICMP header and data */ + ((PICMP_HEADER)IPPacket->Data)->Checksum = (USHORT) + IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0); + + /* Get a route to the destination address */ + if (RouteGetRouteToDestination(&IPPacket->DstAddr, NTE, &RCN) == IP_SUCCESS) { + /* Send the packet */ + if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS) { + FreeNdisPacket(IPPacket->NdisPacket); + PoolFreeBuffer(IPPacket); + } + /* We're done with the RCN */ + DereferenceObject(RCN); + } else { + TI_DbgPrint(MIN_TRACE, ("RCN at 0x%X.\n", RCN)); + + /* No route to destination (or no free resources) */ + TI_DbgPrint(MIN_TRACE, ("No route to destination address 0x%X.\n", + IPPacket->DstAddr.Address.IPv4Address)); + /* Discard packet */ + FreeNdisPacket(IPPacket->NdisPacket); + PoolFreeBuffer(IPPacket); + } +} + + +VOID ICMPReply( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket, + UCHAR Type, + UCHAR Code) +/* + * FUNCTION: Transmits an ICMP packet in response to an incoming packet + * ARGUMENTS: + * NTE = Pointer to net table entry to use + * IPPacket = Pointer to IP packet that was received + * Type = ICMP message type + * Code = ICMP message code + * NOTES: + * We have received a packet from someone and is unable to + * process it due to error(s) in the packet or we have run out + * of resources. We transmit an ICMP message to the host to + * notify him of the problem + */ +{ + UINT DataSize; + PIP_PACKET NewPacket; + + TI_DbgPrint(MID_TRACE, ("Called (Type=%d, Code=%d).\n", Type, Code)); + + DataSize = IPPacket->TotalSize; + if ((DataSize) > (576 - sizeof(IPv4_HEADER) - sizeof(ICMP_HEADER))) + DataSize = 576; + + NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize); + if (!NewPacket) + return; + + RtlCopyMemory((PVOID)((ULONG_PTR)NewPacket->Data + sizeof(ICMP_HEADER)), + IPPacket->Header, DataSize); + ((PICMP_HEADER)NewPacket->Data)->Type = Type; + ((PICMP_HEADER)NewPacket->Data)->Code = Code; + ((PICMP_HEADER)NewPacket->Data)->Checksum = 0; + + ICMPTransmit(NTE, NewPacket); +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/network/ip.c b/reactos/drivers/net/tcpip/network/ip.c index f15449c2165..1ea5af98582 100644 --- a/reactos/drivers/net/tcpip/network/ip.c +++ b/reactos/drivers/net/tcpip/network/ip.c @@ -1,979 +1,979 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - - -KTIMER IPTimer; -KDPC IPTimeoutDpc; -LIST_ENTRY InterfaceListHead; -KSPIN_LOCK InterfaceListLock; -LIST_ENTRY NetTableListHead; -KSPIN_LOCK NetTableListLock; -LIST_ENTRY PrefixListHead; -KSPIN_LOCK PrefixListLock; -UINT MaxLLHeaderSize; /* Largest maximum header size */ -UINT MinLLFrameSize; /* Largest minimum frame size */ -BOOLEAN IPInitialized = FALSE; - -IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE]; - - -PADDRESS_ENTRY CreateADE( - PIP_INTERFACE IF, - PIP_ADDRESS Address, - UCHAR Type, - PNET_TABLE_ENTRY NTE) -/* - * FUNCTION: Creates an address entry and binds it to an interface - * ARGUMENTS: - * IF = Pointer to interface - * Address = Pointer to referenced interface address - * Type = Type of address (ADE_*) - * NTE = Pointer to net table entry - * RETURNS: - * Pointer to ADE, NULL if there was not enough free resources - * NOTES: - * The interface lock must be held when called. The address entry - * retains a reference to the provided address and NTE. The caller - * is responsible for referencing the these before calling. - * As long as you have referenced an ADE you can safely use the - * address and NTE as the ADE references both - */ -{ - PADDRESS_ENTRY ADE; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) Type (0x%X) NTE (0x%X).\n", - IF, Address, Type, NTE)); - - /* Allocate space for an ADE and set it up */ - ADE = PoolAllocateBuffer(sizeof(ADDRESS_ENTRY)); - if (!ADE) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - ADE->RefCount = 1; - ADE->NTE = NTE; - ADE->Type = Type; - ADE->Address = Address; - - /* Add ADE to the list on the interface */ - InsertTailList(&IF->ADEListHead, &ADE->ListEntry); - - return ADE; -} - - -VOID DestroyADE( - PIP_INTERFACE IF, - PADDRESS_ENTRY ADE) -/* - * FUNCTION: Destroys an address entry - * ARGUMENTS: - * IF = Pointer to interface - * ADE = Pointer to address entry - * NOTES: - * The interface lock must be held when called - */ -{ - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) ADE (0x%X).\n", IF, ADE)); - - /* Unlink the address entry from the list */ - RemoveEntryList(&ADE->ListEntry); - - /* Dereference the address */ - DereferenceObject(ADE->Address); - - /* Dereference the NTE */ - DereferenceObject(ADE->NTE); - -#ifdef DBG - ADE->RefCount--; - - if (ADE->RefCount != 0) { - TI_DbgPrint(MIN_TRACE, ("Address entry at (0x%X) has (%d) references (should be 0).\n", ADE, ADE->RefCount)); - } -#endif - - /* And free the ADE */ - PoolFreeBuffer(ADE); - TI_DbgPrint(MIN_TRACE, ("Check.\n")); -} - - -VOID DestroyADEs( - PIP_INTERFACE IF) -/* - * FUNCTION: Destroys all address entries on an interface - * ARGUMENTS: - * IF = Pointer to interface - * NOTES: - * The interface lock must be held when called - */ -{ - PLIST_ENTRY CurrentEntry; - PLIST_ENTRY NextEntry; - PADDRESS_ENTRY Current; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); - - /* Search the list and remove every ADE we find */ - CurrentEntry = IF->ADEListHead.Flink; - while (CurrentEntry != &IF->ADEListHead) { - NextEntry = CurrentEntry->Flink; - Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry); - /* Destroy the ADE */ - DestroyADE(IF, Current); - CurrentEntry = NextEntry; - } -} - - -PPREFIX_LIST_ENTRY CreatePLE( - PIP_INTERFACE IF, - PIP_ADDRESS Prefix, - UINT Length) -/* - * FUNCTION: Creates a prefix list entry and binds it to an interface - * ARGUMENTS: - * IF = Pointer to interface - * Prefix = Pointer to prefix - * Length = Length of prefix - * RETURNS: - * Pointer to PLE, NULL if there was not enough free resources - * NOTES: - * The prefix list entry retains a reference to the interface and - * the provided address. The caller is responsible for providing - * these references - */ -{ - PPREFIX_LIST_ENTRY PLE; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Prefix (0x%X) Length (%d).\n", IF, Prefix, Length)); - - /* Allocate space for an PLE and set it up */ - PLE = PoolAllocateBuffer(sizeof(PREFIX_LIST_ENTRY)); - if (!PLE) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - PLE->RefCount = 1; - PLE->Interface = IF; - PLE->Prefix = Prefix; - PLE->PrefixLength = Length; - - /* Add PLE to the global prefix list */ - ExInterlockedInsertTailList(&PrefixListHead, &PLE->ListEntry, &PrefixListLock); - - return PLE; -} - - -VOID DestroyPLE( - PPREFIX_LIST_ENTRY PLE) -/* - * FUNCTION: Destroys an prefix list entry - * ARGUMENTS: - * PLE = Pointer to prefix list entry - * NOTES: - * The prefix list lock must be held when called - */ -{ - TI_DbgPrint(DEBUG_IP, ("Called. PLE (0x%X).\n", PLE)); - - /* Unlink the prefix list entry from the list */ - RemoveEntryList(&PLE->ListEntry); - - /* Dereference the address */ - DereferenceObject(PLE->Prefix); - - /* Dereference the interface */ - DereferenceObject(PLE->Interface); - -#ifdef DBG - PLE->RefCount--; - - if (PLE->RefCount != 0) { - TI_DbgPrint(MIN_TRACE, ("Prefix list entry at (0x%X) has (%d) references (should be 0).\n", PLE, PLE->RefCount)); - } -#endif - - /* And free the PLE */ - PoolFreeBuffer(PLE); -} - - -VOID DestroyPLEs( - VOID) -/* - * FUNCTION: Destroys all prefix list entries - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PLIST_ENTRY NextEntry; - PPREFIX_LIST_ENTRY Current; - - TI_DbgPrint(DEBUG_IP, ("Called.\n")); - - KeAcquireSpinLock(&PrefixListLock, &OldIrql); - - /* Search the list and remove every PLE we find */ - CurrentEntry = PrefixListHead.Flink; - while (CurrentEntry != &PrefixListHead) { - NextEntry = CurrentEntry->Flink; - Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry); - /* Destroy the PLE */ - DestroyPLE(Current); - CurrentEntry = NextEntry; - } - KeReleaseSpinLock(&PrefixListLock, OldIrql); -} - - -PNET_TABLE_ENTRY IPCreateNTE( - PIP_INTERFACE IF, - PIP_ADDRESS Address, - UINT PrefixLength) -/* - * FUNCTION: Creates a net table entry and binds it to an interface - * ARGUMENTS: - * IF = Pointer to interface - * Address = Pointer to interface address - * PrefixLength = Length of prefix - * RETURNS: - * Pointer to NTE, NULL if there was not enough free resources - * NOTES: - * The interface lock must be held when called. - * The net table entry retains a reference to the interface and - * the provided address. The caller is responsible for providing - * these references - */ -{ - PNET_TABLE_ENTRY NTE; - PADDRESS_ENTRY ADE; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) PrefixLength (%d).\n", IF, Address, PrefixLength)); - - /* Allocate room for an NTE */ - NTE = PoolAllocateBuffer(sizeof(NET_TABLE_ENTRY)); - if (!NTE) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - NTE->Interface = IF; - - /* One reference is for beeing alive and one reference is for the ADE */ - NTE->RefCount = 2; - - NTE->Address = Address; - /* One reference is for NTE, one reference is given to the - address entry, and one reference is given to the prefix - list entry */ - ReferenceObject(Address); - ReferenceObject(Address); - ReferenceObject(Address); - - /* Create an address entry and add it to the list */ - ADE = CreateADE(IF, NTE->Address, ADE_UNICAST, NTE); - if (!ADE) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - PoolFreeBuffer(NTE); - return NULL; - } - - /* Create a prefix list entry for unicast address */ - NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength); - if (!NTE->PLE) { - DestroyADE(IF, ADE); - PoolFreeBuffer(NTE); - return NULL; - } - - /* Reference the interface for the prefix list entry */ - ReferenceObject(IF); - - /* Add NTE to the list on the interface */ - InsertTailList(&IF->NTEListHead, &NTE->IFListEntry); - - /* Add NTE to the global net table list */ - ExInterlockedInsertTailList(&NetTableListHead, &NTE->NTListEntry, &NetTableListLock); - - return NTE; -} - - -VOID DestroyNTE( - PIP_INTERFACE IF, - PNET_TABLE_ENTRY NTE) -/* - * FUNCTION: Destroys a net table entry - * ARGUMENTS: - * IF = Pointer to interface - * NTE = Pointer to net table entry - * NOTES: - * The net table list lock must be held when called - * The interface lock must be held when called - */ -{ - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) NTE (0x%X).\n", IF, NTE)); - - /* Invalidate the prefix list entry for this NTE */ - KeAcquireSpinLock(&PrefixListLock, &OldIrql); - DestroyPLE(NTE->PLE); - KeReleaseSpinLock(&PrefixListLock, OldIrql); - - /* Remove NTE from the interface list */ - RemoveEntryList(&NTE->IFListEntry); - /* Remove NTE from the net table list */ - RemoveEntryList(&NTE->NTListEntry); - /* Dereference the objects that are referenced */ - DereferenceObject(NTE->Address); - DereferenceObject(NTE->Interface); -#ifdef DBG - NTE->RefCount--; - - if (NTE->RefCount != 0) { - TI_DbgPrint(MIN_TRACE, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE, NTE->RefCount)); - } -#endif - /* And free the NTE */ - PoolFreeBuffer(NTE); -} - - -VOID DestroyNTEs( - PIP_INTERFACE IF) -/* - * FUNCTION: Destroys all net table entries on an interface - * ARGUMENTS: - * IF = Pointer to interface - * NOTES: - * The net table list lock must be held when called - * The interface lock may be held when called - */ -{ - PLIST_ENTRY CurrentEntry; - PLIST_ENTRY NextEntry; - PNET_TABLE_ENTRY Current; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); - - /* Search the list and remove every NTE we find */ - CurrentEntry = IF->NTEListHead.Flink; - while (CurrentEntry != &IF->NTEListHead) { - NextEntry = CurrentEntry->Flink; - Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); - /* Destroy the NTE */ - DestroyNTE(IF, Current); - CurrentEntry = NextEntry; - } -} - - -PNET_TABLE_ENTRY IPLocateNTEOnInterface( - PIP_INTERFACE IF, - PIP_ADDRESS Address, - PUINT AddressType) -/* - * FUNCTION: Locates an NTE on an interface - * ARGUMENTS: - * IF = Pointer to interface - * Address = Pointer to IP address - * AddressType = Address of type of IP address - * NOTES: - * If found, the NTE is referenced for the caller. The caller is - * responsible for dereferencing after use - * RETURNS: - * Pointer to net table entry, NULL if none was found - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PADDRESS_ENTRY Current; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) AddressType (0x%X).\n", - IF, Address, AddressType)); - - KeAcquireSpinLock(&IF->Lock, &OldIrql); - - /* Search the list and return the NTE if found */ - CurrentEntry = IF->ADEListHead.Flink; - while (CurrentEntry != &IF->ADEListHead) { - Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry); - if (AddrIsEqual(Address, Current->Address)) { - ReferenceObject(Current->NTE); - *AddressType = Current->Type; - KeReleaseSpinLock(&IF->Lock, OldIrql); - return Current->NTE; - } - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&IF->Lock, OldIrql); - - return NULL; -} - - -PNET_TABLE_ENTRY IPLocateNTE( - PIP_ADDRESS Address, - PUINT AddressType) -/* - * FUNCTION: Locates an NTE for the network Address is on - * ARGUMENTS: - * Address = Pointer to an address to find associated NTE of - * AddressType = Address of address type - * NOTES: - * If found the NTE is referenced for the caller. The caller is - * responsible for dereferencing after use - * RETURNS: - * Pointer to NTE if the address was found, NULL if not. - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PNET_TABLE_ENTRY Current; - PNET_TABLE_ENTRY NTE; - - TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n", - Address, AddressType)); - - KeAcquireSpinLock(&NetTableListLock, &OldIrql); - - /* Search the list and return the NTE if found */ - CurrentEntry = NetTableListHead.Flink; - while (CurrentEntry != &NetTableListHead) { - Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, NTListEntry); - NTE = IPLocateNTEOnInterface(Current->Interface, Address, AddressType); - if (NTE) { - ReferenceObject(NTE); - KeReleaseSpinLock(&NetTableListLock, OldIrql); - return NTE; - } - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&NetTableListLock, OldIrql); - - return NULL; -} - - -PADDRESS_ENTRY IPLocateADE( - PIP_ADDRESS Address, - UINT AddressType) -/* - * FUNCTION: Locates an ADE for the address - * ARGUMENTS: - * Address = Pointer to an address to find associated ADE of - * AddressType = Type of address - * RETURNS: - * Pointer to ADE if the address was found, NULL if not. - * NOTES: - * If found the ADE is referenced for the caller. The caller is - * responsible for dereferencing after use - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentIFEntry; - PLIST_ENTRY CurrentADEEntry; - PIP_INTERFACE CurrentIF; - PADDRESS_ENTRY CurrentADE; - - TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n", - Address, AddressType)); - - KeAcquireSpinLock(&InterfaceListLock, &OldIrql); - - /* Search the interface list */ - CurrentIFEntry = InterfaceListHead.Flink; - while (CurrentIFEntry != &InterfaceListHead) { - CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); - - /* Search the address entry list and return the ADE if found */ - CurrentADEEntry = CurrentIF->ADEListHead.Flink; - while (CurrentADEEntry != &CurrentIF->ADEListHead) { - CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); - if ((AddrIsEqual(Address, CurrentADE->Address)) && - (CurrentADE->Type == AddressType)) { - ReferenceObject(CurrentADE); - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - return CurrentADE; - } - CurrentADEEntry = CurrentADEEntry->Flink; - } - CurrentIFEntry = CurrentIFEntry->Flink; - } - - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - - return NULL; -} - - -PADDRESS_ENTRY IPGetDefaultADE( - UINT AddressType) -/* - * FUNCTION: Returns a default address entry - * ARGUMENTS: - * AddressType = Type of address - * RETURNS: - * Pointer to ADE if found, NULL if not. - * NOTES: - * Loopback interface is only considered if it is the only interface. - * If found, the address entry is referenced - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentIFEntry; - PLIST_ENTRY CurrentADEEntry; - PIP_INTERFACE CurrentIF; - PADDRESS_ENTRY CurrentADE; -#if 0 - BOOLEAN LoopbackIsRegistered = FALSE; -#endif - TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType)); - - KeAcquireSpinLock(&InterfaceListLock, &OldIrql); - - /* Search the interface list */ - CurrentIFEntry = InterfaceListHead.Flink; - while (CurrentIFEntry != &InterfaceListHead) { - CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); -#if 0 - if (CurrentIF != Loopback) { -#endif - /* Search the address entry list and return the first appropriate ADE found */ - CurrentADEEntry = CurrentIF->ADEListHead.Flink; - while (CurrentADEEntry != &CurrentIF->ADEListHead) { - CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); - if (CurrentADE->Type == AddressType) - ReferenceObject(CurrentADE); - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - return CurrentADE; - } - CurrentADEEntry = CurrentADEEntry->Flink; -#if 0 - } else - LoopbackIsRegistered = TRUE; -#endif - CurrentIFEntry = CurrentIFEntry->Flink; - } -#if 0 - /* No address was found. Use loopback interface if available */ - if (LoopbackIsRegistered) { - CurrentADEEntry = Loopback->ADEListHead.Flink; - while (CurrentADEEntry != &Loopback->ADEListHead) { - CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); - if (CurrentADE->Type == AddressType) { - ReferenceObject(CurrentADE); - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - return CurrentADE; - } - CurrentADEEntry = CurrentADEEntry->Flink; - } - } -#endif - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - - return NULL; -} - - -VOID IPTimeout( - 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 maintainance jobs - */ -{ - /* Check if datagram fragments have taken too long to assemble */ - IPDatagramReassemblyTimeout(); - - /* Clean possible outdated cached neighbor addresses */ - NBTimeout(); -} - - -VOID IPDispatchProtocol( - PNET_TABLE_ENTRY NTE, - 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; - - switch (IPPacket->Type) { - case IP_ADDRESS_V4: - Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol; - break; - case IP_ADDRESS_V6: - /* FIXME: IPv6 adresses not supported */ - TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n")); - return; - default: - Protocol = 0; - } - - /* Call the appropriate protocol handler */ - (*ProtocolTable[Protocol])(NTE, 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 = PoolAllocateBuffer(sizeof(IP_INTERFACE)); - if (!IF) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - IF->RefCount = 1; - IF->Context = BindInfo->Context; - IF->HeaderSize = BindInfo->HeaderSize; - if (IF->HeaderSize > MaxLLHeaderSize) - MaxLLHeaderSize = IF->HeaderSize; - - IF->MinFrameSize = BindInfo->MinFrameSize; - if (IF->MinFrameSize > MinLLFrameSize) - MinLLFrameSize = IF->MinFrameSize; - - IF->MTU = BindInfo->MTU; - IF->Address = BindInfo->Address; - IF->AddressLength = BindInfo->AddressLength; - IF->Transmit = BindInfo->Transmit; - - InitializeListHead(&IF->ADEListHead); - InitializeListHead(&IF->NTEListHead); - - KeInitializeSpinLock(&IF->Lock); - - return IF; -} - - -VOID IPDestroyInterface( - PIP_INTERFACE IF) -/* - * FUNCTION: Destroys an IP interface - * ARGUMENTS: - * IF = Pointer to interface to destroy - */ -{ - KIRQL OldIrql1; - KIRQL OldIrql2; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); - - KeAcquireSpinLock(&NetTableListLock, &OldIrql1); - KeAcquireSpinLock(&IF->Lock, &OldIrql2); - DestroyADEs(IF); - DestroyNTEs(IF); - KeReleaseSpinLock(&IF->Lock, OldIrql2); - KeReleaseSpinLock(&NetTableListLock, OldIrql1); - -#ifdef DBG - IF->RefCount--; - - if (IF->RefCount != 0) { - TI_DbgPrint(MIN_TRACE, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF, IF->RefCount)); - } -#endif - PoolFreeBuffer(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; - PLIST_ENTRY CurrentEntry; - PNET_TABLE_ENTRY Current; - PROUTE_CACHE_NODE RCN; - PNEIGHBOR_CACHE_ENTRY NCE; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); - - KeAcquireSpinLock(&IF->Lock, &OldIrql); - - /* Add routes to all NTEs on this interface */ - CurrentEntry = IF->NTEListHead.Flink; - while (CurrentEntry != &IF->NTEListHead) { - Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); - - /* Add a permanent neighbor for this NTE */ - ReferenceObject(Current->Address); - NCE = NBAddNeighbor(IF, Current->Address, IF->Address, - IF->AddressLength, NUD_PERMANENT); - if (!NCE) { - TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n")); - DereferenceObject(Current->Address); - KeReleaseSpinLock(&IF->Lock, OldIrql); - return FALSE; - } - RCN = RouteAddRouteToDestination(Current->Address, Current, IF, NCE); - if (!RCN) { - TI_DbgPrint(MIN_TRACE, ("Could not create RCN.\n")); - DereferenceObject(Current->Address); - KeReleaseSpinLock(&IF->Lock, OldIrql); - return FALSE; - } - /* Don't need this any more since the route cache references the NCE */ - DereferenceObject(NCE); - - CurrentEntry = CurrentEntry->Flink; - } - - /* Add interface to the global interface list */ - ExInterlockedInsertTailList(&InterfaceListHead, &IF->ListEntry, &InterfaceListLock); - - KeReleaseSpinLock(&IF->Lock, OldIrql); - - return TRUE; -} - - -VOID IPUnregisterInterface( - PIP_INTERFACE IF) -/* - * FUNCTION: Unregisters an IP interface with IP layer - * ARGUMENTS: - * IF = Pointer to interface to unregister - */ -{ - KIRQL OldIrql1; - KIRQL OldIrql2; - KIRQL OldIrql3; - PLIST_ENTRY CurrentEntry; - PNET_TABLE_ENTRY Current; - PNEIGHBOR_CACHE_ENTRY NCE; - - TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); - - KeAcquireSpinLock(&NetTableListLock, &OldIrql1); - KeAcquireSpinLock(&IF->Lock, &OldIrql2); - - /* Remove routes to all NTEs on this interface */ - CurrentEntry = IF->NTEListHead.Flink; - while (CurrentEntry != &IF->NTEListHead) { - Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); - - /* Remove NTE from global net table list */ - RemoveEntryList(&Current->NTListEntry); - - /* Remove all references from route cache to NTE */ - RouteInvalidateNTE(Current); - - /* Remove permanent NCE, but first we have to find it */ - NCE = NBLocateNeighbor(Current->Address); - if (NCE) { - DereferenceObject(NCE); - NBRemoveNeighbor(NCE); - } - - CurrentEntry = CurrentEntry->Flink; - } - - KeAcquireSpinLock(&InterfaceListLock, &OldIrql3); - /* Ouch...three spinlocks acquired! Fortunately - we don't unregister interfaces very often */ - RemoveEntryList(&IF->ListEntry); - KeReleaseSpinLock(&InterfaceListLock, OldIrql3); - - KeReleaseSpinLock(&IF->Lock, OldIrql2); - KeReleaseSpinLock(&NetTableListLock, OldIrql1); -} - - -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 - */ -{ -#ifdef DBG - if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE) - TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber)); -#endif - - ProtocolTable[ProtocolNumber] = Handler; -} - - -VOID DefaultProtocolHandler( - PNET_TABLE_ENTRY NTE, - 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, ("Packet of unknown Internet protocol discarded.\n")); -} - - -NTSTATUS IPStartup( - PDRIVER_OBJECT DriverObject, - PUNICODE_STRING RegistryPath) -/* - * FUNCTION: Initializes the IP subsystem - * ARGUMENTS: - * DriverObject = Pointer to a driver object for this driver - * RegistryPath = Our registry node for configuration parameters - * RETURNS: - * Status of operation - */ -{ - UINT i; - LARGE_INTEGER DueTime; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - MaxLLHeaderSize = 0; - MinLLFrameSize = 0; - - /* Start routing subsystem */ - RouterStartup(); - - /* Start route cache subsystem */ - RouteStartup(); - - /* 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); - - /* Register network level protocol receive handlers */ - IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive); - - /* Initialize NTE list and protecting lock */ - InitializeListHead(&NetTableListHead); - KeInitializeSpinLock(&NetTableListLock); - - /* Initialize reassembly list and protecting lock */ - InitializeListHead(&ReassemblyListHead); - KeInitializeSpinLock(&ReassemblyListLock); - - /* Initialize the prefix list and protecting lock */ - InitializeListHead(&PrefixListHead); - KeInitializeSpinLock(&PrefixListLock); - - /* Initialize our periodic timer and its associated DPC object. When the - timer expires, the IPTimeout deferred procedure call (DPC) is queued */ - KeInitializeDpc(&IPTimeoutDpc, IPTimeout, NULL); - KeInitializeTimer(&IPTimer); - - /* Start the periodic timer with an initial and periodic - relative expiration time of IP_TIMEOUT milliseconds */ - DueTime.QuadPart = -(LONGLONG)IP_TIMEOUT * 10000; - KeSetTimerEx(&IPTimer, DueTime, IP_TIMEOUT, &IPTimeoutDpc); - - 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; - - /* Cancel timer */ - KeCancelTimer(&IPTimer); - - /* Shutdown neighbor cache subsystem */ - NBShutdown(); - - /* Shutdown route cache subsystem */ - RouteShutdown(); - - /* Shutdown routing subsystem */ - RouterShutdown(); - - IPFreeReassemblyList(); - - /* Clear prefix list */ - DestroyPLEs(); - - IPInitialized = FALSE; - - return STATUS_SUCCESS; -} - -/* EOF */ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + + +KTIMER IPTimer; +KDPC IPTimeoutDpc; +LIST_ENTRY InterfaceListHead; +KSPIN_LOCK InterfaceListLock; +LIST_ENTRY NetTableListHead; +KSPIN_LOCK NetTableListLock; +LIST_ENTRY PrefixListHead; +KSPIN_LOCK PrefixListLock; +UINT MaxLLHeaderSize; /* Largest maximum header size */ +UINT MinLLFrameSize; /* Largest minimum frame size */ +BOOLEAN IPInitialized = FALSE; + +IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE]; + + +PADDRESS_ENTRY CreateADE( + PIP_INTERFACE IF, + PIP_ADDRESS Address, + UCHAR Type, + PNET_TABLE_ENTRY NTE) +/* + * FUNCTION: Creates an address entry and binds it to an interface + * ARGUMENTS: + * IF = Pointer to interface + * Address = Pointer to referenced interface address + * Type = Type of address (ADE_*) + * NTE = Pointer to net table entry + * RETURNS: + * Pointer to ADE, NULL if there was not enough free resources + * NOTES: + * The interface lock must be held when called. The address entry + * retains a reference to the provided address and NTE. The caller + * is responsible for referencing the these before calling. + * As long as you have referenced an ADE you can safely use the + * address and NTE as the ADE references both + */ +{ + PADDRESS_ENTRY ADE; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) Type (0x%X) NTE (0x%X).\n", + IF, Address, Type, NTE)); + + /* Allocate space for an ADE and set it up */ + ADE = PoolAllocateBuffer(sizeof(ADDRESS_ENTRY)); + if (!ADE) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + ADE->RefCount = 1; + ADE->NTE = NTE; + ADE->Type = Type; + ADE->Address = Address; + + /* Add ADE to the list on the interface */ + InsertTailList(&IF->ADEListHead, &ADE->ListEntry); + + return ADE; +} + + +VOID DestroyADE( + PIP_INTERFACE IF, + PADDRESS_ENTRY ADE) +/* + * FUNCTION: Destroys an address entry + * ARGUMENTS: + * IF = Pointer to interface + * ADE = Pointer to address entry + * NOTES: + * The interface lock must be held when called + */ +{ + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) ADE (0x%X).\n", IF, ADE)); + + /* Unlink the address entry from the list */ + RemoveEntryList(&ADE->ListEntry); + + /* Dereference the address */ + DereferenceObject(ADE->Address); + + /* Dereference the NTE */ + DereferenceObject(ADE->NTE); + +#ifdef DBG + ADE->RefCount--; + + if (ADE->RefCount != 0) { + TI_DbgPrint(MIN_TRACE, ("Address entry at (0x%X) has (%d) references (should be 0).\n", ADE, ADE->RefCount)); + } +#endif + + /* And free the ADE */ + PoolFreeBuffer(ADE); + TI_DbgPrint(MIN_TRACE, ("Check.\n")); +} + + +VOID DestroyADEs( + PIP_INTERFACE IF) +/* + * FUNCTION: Destroys all address entries on an interface + * ARGUMENTS: + * IF = Pointer to interface + * NOTES: + * The interface lock must be held when called + */ +{ + PLIST_ENTRY CurrentEntry; + PLIST_ENTRY NextEntry; + PADDRESS_ENTRY Current; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); + + /* Search the list and remove every ADE we find */ + CurrentEntry = IF->ADEListHead.Flink; + while (CurrentEntry != &IF->ADEListHead) { + NextEntry = CurrentEntry->Flink; + Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry); + /* Destroy the ADE */ + DestroyADE(IF, Current); + CurrentEntry = NextEntry; + } +} + + +PPREFIX_LIST_ENTRY CreatePLE( + PIP_INTERFACE IF, + PIP_ADDRESS Prefix, + UINT Length) +/* + * FUNCTION: Creates a prefix list entry and binds it to an interface + * ARGUMENTS: + * IF = Pointer to interface + * Prefix = Pointer to prefix + * Length = Length of prefix + * RETURNS: + * Pointer to PLE, NULL if there was not enough free resources + * NOTES: + * The prefix list entry retains a reference to the interface and + * the provided address. The caller is responsible for providing + * these references + */ +{ + PPREFIX_LIST_ENTRY PLE; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Prefix (0x%X) Length (%d).\n", IF, Prefix, Length)); + + /* Allocate space for an PLE and set it up */ + PLE = PoolAllocateBuffer(sizeof(PREFIX_LIST_ENTRY)); + if (!PLE) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + PLE->RefCount = 1; + PLE->Interface = IF; + PLE->Prefix = Prefix; + PLE->PrefixLength = Length; + + /* Add PLE to the global prefix list */ + ExInterlockedInsertTailList(&PrefixListHead, &PLE->ListEntry, &PrefixListLock); + + return PLE; +} + + +VOID DestroyPLE( + PPREFIX_LIST_ENTRY PLE) +/* + * FUNCTION: Destroys an prefix list entry + * ARGUMENTS: + * PLE = Pointer to prefix list entry + * NOTES: + * The prefix list lock must be held when called + */ +{ + TI_DbgPrint(DEBUG_IP, ("Called. PLE (0x%X).\n", PLE)); + + /* Unlink the prefix list entry from the list */ + RemoveEntryList(&PLE->ListEntry); + + /* Dereference the address */ + DereferenceObject(PLE->Prefix); + + /* Dereference the interface */ + DereferenceObject(PLE->Interface); + +#ifdef DBG + PLE->RefCount--; + + if (PLE->RefCount != 0) { + TI_DbgPrint(MIN_TRACE, ("Prefix list entry at (0x%X) has (%d) references (should be 0).\n", PLE, PLE->RefCount)); + } +#endif + + /* And free the PLE */ + PoolFreeBuffer(PLE); +} + + +VOID DestroyPLEs( + VOID) +/* + * FUNCTION: Destroys all prefix list entries + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PLIST_ENTRY NextEntry; + PPREFIX_LIST_ENTRY Current; + + TI_DbgPrint(DEBUG_IP, ("Called.\n")); + + KeAcquireSpinLock(&PrefixListLock, &OldIrql); + + /* Search the list and remove every PLE we find */ + CurrentEntry = PrefixListHead.Flink; + while (CurrentEntry != &PrefixListHead) { + NextEntry = CurrentEntry->Flink; + Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry); + /* Destroy the PLE */ + DestroyPLE(Current); + CurrentEntry = NextEntry; + } + KeReleaseSpinLock(&PrefixListLock, OldIrql); +} + + +PNET_TABLE_ENTRY IPCreateNTE( + PIP_INTERFACE IF, + PIP_ADDRESS Address, + UINT PrefixLength) +/* + * FUNCTION: Creates a net table entry and binds it to an interface + * ARGUMENTS: + * IF = Pointer to interface + * Address = Pointer to interface address + * PrefixLength = Length of prefix + * RETURNS: + * Pointer to NTE, NULL if there was not enough free resources + * NOTES: + * The interface lock must be held when called. + * The net table entry retains a reference to the interface and + * the provided address. The caller is responsible for providing + * these references + */ +{ + PNET_TABLE_ENTRY NTE; + PADDRESS_ENTRY ADE; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) PrefixLength (%d).\n", IF, Address, PrefixLength)); + + /* Allocate room for an NTE */ + NTE = PoolAllocateBuffer(sizeof(NET_TABLE_ENTRY)); + if (!NTE) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + NTE->Interface = IF; + + /* One reference is for beeing alive and one reference is for the ADE */ + NTE->RefCount = 2; + + NTE->Address = Address; + /* One reference is for NTE, one reference is given to the + address entry, and one reference is given to the prefix + list entry */ + ReferenceObject(Address); + ReferenceObject(Address); + ReferenceObject(Address); + + /* Create an address entry and add it to the list */ + ADE = CreateADE(IF, NTE->Address, ADE_UNICAST, NTE); + if (!ADE) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + PoolFreeBuffer(NTE); + return NULL; + } + + /* Create a prefix list entry for unicast address */ + NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength); + if (!NTE->PLE) { + DestroyADE(IF, ADE); + PoolFreeBuffer(NTE); + return NULL; + } + + /* Reference the interface for the prefix list entry */ + ReferenceObject(IF); + + /* Add NTE to the list on the interface */ + InsertTailList(&IF->NTEListHead, &NTE->IFListEntry); + + /* Add NTE to the global net table list */ + ExInterlockedInsertTailList(&NetTableListHead, &NTE->NTListEntry, &NetTableListLock); + + return NTE; +} + + +VOID DestroyNTE( + PIP_INTERFACE IF, + PNET_TABLE_ENTRY NTE) +/* + * FUNCTION: Destroys a net table entry + * ARGUMENTS: + * IF = Pointer to interface + * NTE = Pointer to net table entry + * NOTES: + * The net table list lock must be held when called + * The interface lock must be held when called + */ +{ + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) NTE (0x%X).\n", IF, NTE)); + + /* Invalidate the prefix list entry for this NTE */ + KeAcquireSpinLock(&PrefixListLock, &OldIrql); + DestroyPLE(NTE->PLE); + KeReleaseSpinLock(&PrefixListLock, OldIrql); + + /* Remove NTE from the interface list */ + RemoveEntryList(&NTE->IFListEntry); + /* Remove NTE from the net table list */ + RemoveEntryList(&NTE->NTListEntry); + /* Dereference the objects that are referenced */ + DereferenceObject(NTE->Address); + DereferenceObject(NTE->Interface); +#ifdef DBG + NTE->RefCount--; + + if (NTE->RefCount != 0) { + TI_DbgPrint(MIN_TRACE, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE, NTE->RefCount)); + } +#endif + /* And free the NTE */ + PoolFreeBuffer(NTE); +} + + +VOID DestroyNTEs( + PIP_INTERFACE IF) +/* + * FUNCTION: Destroys all net table entries on an interface + * ARGUMENTS: + * IF = Pointer to interface + * NOTES: + * The net table list lock must be held when called + * The interface lock may be held when called + */ +{ + PLIST_ENTRY CurrentEntry; + PLIST_ENTRY NextEntry; + PNET_TABLE_ENTRY Current; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); + + /* Search the list and remove every NTE we find */ + CurrentEntry = IF->NTEListHead.Flink; + while (CurrentEntry != &IF->NTEListHead) { + NextEntry = CurrentEntry->Flink; + Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); + /* Destroy the NTE */ + DestroyNTE(IF, Current); + CurrentEntry = NextEntry; + } +} + + +PNET_TABLE_ENTRY IPLocateNTEOnInterface( + PIP_INTERFACE IF, + PIP_ADDRESS Address, + PUINT AddressType) +/* + * FUNCTION: Locates an NTE on an interface + * ARGUMENTS: + * IF = Pointer to interface + * Address = Pointer to IP address + * AddressType = Address of type of IP address + * NOTES: + * If found, the NTE is referenced for the caller. The caller is + * responsible for dereferencing after use + * RETURNS: + * Pointer to net table entry, NULL if none was found + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PADDRESS_ENTRY Current; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X) Address (0x%X) AddressType (0x%X).\n", + IF, Address, AddressType)); + + KeAcquireSpinLock(&IF->Lock, &OldIrql); + + /* Search the list and return the NTE if found */ + CurrentEntry = IF->ADEListHead.Flink; + while (CurrentEntry != &IF->ADEListHead) { + Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry); + if (AddrIsEqual(Address, Current->Address)) { + ReferenceObject(Current->NTE); + *AddressType = Current->Type; + KeReleaseSpinLock(&IF->Lock, OldIrql); + return Current->NTE; + } + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&IF->Lock, OldIrql); + + return NULL; +} + + +PNET_TABLE_ENTRY IPLocateNTE( + PIP_ADDRESS Address, + PUINT AddressType) +/* + * FUNCTION: Locates an NTE for the network Address is on + * ARGUMENTS: + * Address = Pointer to an address to find associated NTE of + * AddressType = Address of address type + * NOTES: + * If found the NTE is referenced for the caller. The caller is + * responsible for dereferencing after use + * RETURNS: + * Pointer to NTE if the address was found, NULL if not. + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PNET_TABLE_ENTRY Current; + PNET_TABLE_ENTRY NTE; + + TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n", + Address, AddressType)); + + KeAcquireSpinLock(&NetTableListLock, &OldIrql); + + /* Search the list and return the NTE if found */ + CurrentEntry = NetTableListHead.Flink; + while (CurrentEntry != &NetTableListHead) { + Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, NTListEntry); + NTE = IPLocateNTEOnInterface(Current->Interface, Address, AddressType); + if (NTE) { + ReferenceObject(NTE); + KeReleaseSpinLock(&NetTableListLock, OldIrql); + return NTE; + } + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&NetTableListLock, OldIrql); + + return NULL; +} + + +PADDRESS_ENTRY IPLocateADE( + PIP_ADDRESS Address, + UINT AddressType) +/* + * FUNCTION: Locates an ADE for the address + * ARGUMENTS: + * Address = Pointer to an address to find associated ADE of + * AddressType = Type of address + * RETURNS: + * Pointer to ADE if the address was found, NULL if not. + * NOTES: + * If found the ADE is referenced for the caller. The caller is + * responsible for dereferencing after use + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentIFEntry; + PLIST_ENTRY CurrentADEEntry; + PIP_INTERFACE CurrentIF; + PADDRESS_ENTRY CurrentADE; + + TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n", + Address, AddressType)); + + KeAcquireSpinLock(&InterfaceListLock, &OldIrql); + + /* Search the interface list */ + CurrentIFEntry = InterfaceListHead.Flink; + while (CurrentIFEntry != &InterfaceListHead) { + CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); + + /* Search the address entry list and return the ADE if found */ + CurrentADEEntry = CurrentIF->ADEListHead.Flink; + while (CurrentADEEntry != &CurrentIF->ADEListHead) { + CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); + if ((AddrIsEqual(Address, CurrentADE->Address)) && + (CurrentADE->Type == AddressType)) { + ReferenceObject(CurrentADE); + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + return CurrentADE; + } + CurrentADEEntry = CurrentADEEntry->Flink; + } + CurrentIFEntry = CurrentIFEntry->Flink; + } + + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + + return NULL; +} + + +PADDRESS_ENTRY IPGetDefaultADE( + UINT AddressType) +/* + * FUNCTION: Returns a default address entry + * ARGUMENTS: + * AddressType = Type of address + * RETURNS: + * Pointer to ADE if found, NULL if not. + * NOTES: + * Loopback interface is only considered if it is the only interface. + * If found, the address entry is referenced + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentIFEntry; + PLIST_ENTRY CurrentADEEntry; + PIP_INTERFACE CurrentIF; + PADDRESS_ENTRY CurrentADE; +#if 0 + BOOLEAN LoopbackIsRegistered = FALSE; +#endif + TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType)); + + KeAcquireSpinLock(&InterfaceListLock, &OldIrql); + + /* Search the interface list */ + CurrentIFEntry = InterfaceListHead.Flink; + while (CurrentIFEntry != &InterfaceListHead) { + CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); +#if 0 + if (CurrentIF != Loopback) { +#endif + /* Search the address entry list and return the first appropriate ADE found */ + CurrentADEEntry = CurrentIF->ADEListHead.Flink; + while (CurrentADEEntry != &CurrentIF->ADEListHead) { + CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); + if (CurrentADE->Type == AddressType) + ReferenceObject(CurrentADE); + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + return CurrentADE; + } + CurrentADEEntry = CurrentADEEntry->Flink; +#if 0 + } else + LoopbackIsRegistered = TRUE; +#endif + CurrentIFEntry = CurrentIFEntry->Flink; + } +#if 0 + /* No address was found. Use loopback interface if available */ + if (LoopbackIsRegistered) { + CurrentADEEntry = Loopback->ADEListHead.Flink; + while (CurrentADEEntry != &Loopback->ADEListHead) { + CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); + if (CurrentADE->Type == AddressType) { + ReferenceObject(CurrentADE); + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + return CurrentADE; + } + CurrentADEEntry = CurrentADEEntry->Flink; + } + } +#endif + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + + return NULL; +} + + +VOID IPTimeout( + 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 maintainance jobs + */ +{ + /* Check if datagram fragments have taken too long to assemble */ + IPDatagramReassemblyTimeout(); + + /* Clean possible outdated cached neighbor addresses */ + NBTimeout(); +} + + +VOID IPDispatchProtocol( + PNET_TABLE_ENTRY NTE, + 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; + + switch (IPPacket->Type) { + case IP_ADDRESS_V4: + Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol; + break; + case IP_ADDRESS_V6: + /* FIXME: IPv6 adresses not supported */ + TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n")); + return; + default: + Protocol = 0; + } + + /* Call the appropriate protocol handler */ + (*ProtocolTable[Protocol])(NTE, 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 = PoolAllocateBuffer(sizeof(IP_INTERFACE)); + if (!IF) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + IF->RefCount = 1; + IF->Context = BindInfo->Context; + IF->HeaderSize = BindInfo->HeaderSize; + if (IF->HeaderSize > MaxLLHeaderSize) + MaxLLHeaderSize = IF->HeaderSize; + + IF->MinFrameSize = BindInfo->MinFrameSize; + if (IF->MinFrameSize > MinLLFrameSize) + MinLLFrameSize = IF->MinFrameSize; + + IF->MTU = BindInfo->MTU; + IF->Address = BindInfo->Address; + IF->AddressLength = BindInfo->AddressLength; + IF->Transmit = BindInfo->Transmit; + + InitializeListHead(&IF->ADEListHead); + InitializeListHead(&IF->NTEListHead); + + KeInitializeSpinLock(&IF->Lock); + + return IF; +} + + +VOID IPDestroyInterface( + PIP_INTERFACE IF) +/* + * FUNCTION: Destroys an IP interface + * ARGUMENTS: + * IF = Pointer to interface to destroy + */ +{ + KIRQL OldIrql1; + KIRQL OldIrql2; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); + + KeAcquireSpinLock(&NetTableListLock, &OldIrql1); + KeAcquireSpinLock(&IF->Lock, &OldIrql2); + DestroyADEs(IF); + DestroyNTEs(IF); + KeReleaseSpinLock(&IF->Lock, OldIrql2); + KeReleaseSpinLock(&NetTableListLock, OldIrql1); + +#ifdef DBG + IF->RefCount--; + + if (IF->RefCount != 0) { + TI_DbgPrint(MIN_TRACE, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF, IF->RefCount)); + } +#endif + PoolFreeBuffer(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; + PLIST_ENTRY CurrentEntry; + PNET_TABLE_ENTRY Current; + PROUTE_CACHE_NODE RCN; + PNEIGHBOR_CACHE_ENTRY NCE; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); + + KeAcquireSpinLock(&IF->Lock, &OldIrql); + + /* Add routes to all NTEs on this interface */ + CurrentEntry = IF->NTEListHead.Flink; + while (CurrentEntry != &IF->NTEListHead) { + Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); + + /* Add a permanent neighbor for this NTE */ + ReferenceObject(Current->Address); + NCE = NBAddNeighbor(IF, Current->Address, IF->Address, + IF->AddressLength, NUD_PERMANENT); + if (!NCE) { + TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n")); + DereferenceObject(Current->Address); + KeReleaseSpinLock(&IF->Lock, OldIrql); + return FALSE; + } + RCN = RouteAddRouteToDestination(Current->Address, Current, IF, NCE); + if (!RCN) { + TI_DbgPrint(MIN_TRACE, ("Could not create RCN.\n")); + DereferenceObject(Current->Address); + KeReleaseSpinLock(&IF->Lock, OldIrql); + return FALSE; + } + /* Don't need this any more since the route cache references the NCE */ + DereferenceObject(NCE); + + CurrentEntry = CurrentEntry->Flink; + } + + /* Add interface to the global interface list */ + ExInterlockedInsertTailList(&InterfaceListHead, &IF->ListEntry, &InterfaceListLock); + + KeReleaseSpinLock(&IF->Lock, OldIrql); + + return TRUE; +} + + +VOID IPUnregisterInterface( + PIP_INTERFACE IF) +/* + * FUNCTION: Unregisters an IP interface with IP layer + * ARGUMENTS: + * IF = Pointer to interface to unregister + */ +{ + KIRQL OldIrql1; + KIRQL OldIrql2; + KIRQL OldIrql3; + PLIST_ENTRY CurrentEntry; + PNET_TABLE_ENTRY Current; + PNEIGHBOR_CACHE_ENTRY NCE; + + TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF)); + + KeAcquireSpinLock(&NetTableListLock, &OldIrql1); + KeAcquireSpinLock(&IF->Lock, &OldIrql2); + + /* Remove routes to all NTEs on this interface */ + CurrentEntry = IF->NTEListHead.Flink; + while (CurrentEntry != &IF->NTEListHead) { + Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); + + /* Remove NTE from global net table list */ + RemoveEntryList(&Current->NTListEntry); + + /* Remove all references from route cache to NTE */ + RouteInvalidateNTE(Current); + + /* Remove permanent NCE, but first we have to find it */ + NCE = NBLocateNeighbor(Current->Address); + if (NCE) { + DereferenceObject(NCE); + NBRemoveNeighbor(NCE); + } + + CurrentEntry = CurrentEntry->Flink; + } + + KeAcquireSpinLock(&InterfaceListLock, &OldIrql3); + /* Ouch...three spinlocks acquired! Fortunately + we don't unregister interfaces very often */ + RemoveEntryList(&IF->ListEntry); + KeReleaseSpinLock(&InterfaceListLock, OldIrql3); + + KeReleaseSpinLock(&IF->Lock, OldIrql2); + KeReleaseSpinLock(&NetTableListLock, OldIrql1); +} + + +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 + */ +{ +#ifdef DBG + if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE) + TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber)); +#endif + + ProtocolTable[ProtocolNumber] = Handler; +} + + +VOID DefaultProtocolHandler( + PNET_TABLE_ENTRY NTE, + 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, ("Packet of unknown Internet protocol discarded.\n")); +} + + +NTSTATUS IPStartup( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +/* + * FUNCTION: Initializes the IP subsystem + * ARGUMENTS: + * DriverObject = Pointer to a driver object for this driver + * RegistryPath = Our registry node for configuration parameters + * RETURNS: + * Status of operation + */ +{ + UINT i; + LARGE_INTEGER DueTime; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + MaxLLHeaderSize = 0; + MinLLFrameSize = 0; + + /* Start routing subsystem */ + RouterStartup(); + + /* Start route cache subsystem */ + RouteStartup(); + + /* 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); + + /* Register network level protocol receive handlers */ + IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive); + + /* Initialize NTE list and protecting lock */ + InitializeListHead(&NetTableListHead); + KeInitializeSpinLock(&NetTableListLock); + + /* Initialize reassembly list and protecting lock */ + InitializeListHead(&ReassemblyListHead); + KeInitializeSpinLock(&ReassemblyListLock); + + /* Initialize the prefix list and protecting lock */ + InitializeListHead(&PrefixListHead); + KeInitializeSpinLock(&PrefixListLock); + + /* Initialize our periodic timer and its associated DPC object. When the + timer expires, the IPTimeout deferred procedure call (DPC) is queued */ + KeInitializeDpc(&IPTimeoutDpc, IPTimeout, NULL); + KeInitializeTimer(&IPTimer); + + /* Start the periodic timer with an initial and periodic + relative expiration time of IP_TIMEOUT milliseconds */ + DueTime.QuadPart = -(LONGLONG)IP_TIMEOUT * 10000; + KeSetTimerEx(&IPTimer, DueTime, IP_TIMEOUT, &IPTimeoutDpc); + + 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; + + /* Cancel timer */ + KeCancelTimer(&IPTimer); + + /* Shutdown neighbor cache subsystem */ + NBShutdown(); + + /* Shutdown route cache subsystem */ + RouteShutdown(); + + /* Shutdown routing subsystem */ + RouterShutdown(); + + IPFreeReassemblyList(); + + /* Clear prefix list */ + DestroyPLEs(); + + IPInitialized = FALSE; + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/network/neighbor.c b/reactos/drivers/net/tcpip/network/neighbor.c index 2e17cb4225c..3cd103a4934 100644 --- a/reactos/drivers/net/tcpip/network/neighbor.c +++ b/reactos/drivers/net/tcpip/network/neighbor.c @@ -1,506 +1,506 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: network/neighbor.c - * PURPOSE: Neighbor address cache - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1]; - - -VOID NCETimeout( - PNEIGHBOR_CACHE_ENTRY NCE) -/* - * FUNCTION: Neighbor cache entry timeout handler - * NOTES: - * The neighbor cache lock must be held - */ -{ - PNDIS_PACKET NdisPacket, Next; - - TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE)); - - TI_DbgPrint(DEBUG_NCACHE, ("NCE->State is (0x%X).\n", NCE->State)); - - switch (NCE->State) { - case NUD_INCOMPLETE: - /* Retransmission timer expired */ - if (NCE->EventCount++ > MAX_MULTICAST_SOLICIT) { - /* We have retransmitted too many times */ - - /* Calling IPSendComplete with cache lock held is not - a great thing to do. We don't get here very often - so maybe it's not that big a problem */ - - /* Flush packet queue */ - NdisPacket = NCE->WaitQueue; - while (NdisPacket) { - Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete; - IPSendComplete((PVOID)NCE->Interface, NdisPacket, - NDIS_STATUS_REQUEST_ABORTED); - NdisPacket = Next; - } - NCE->WaitQueue = NULL; - - NCE->EventCount = 0; - - /* Remove route cache entries with references to this NCE. - Remember that neighbor cache lock is taken before - route cache lock */ - RouteInvalidateNCE(NCE); - } else - /* Retransmit request */ - NBSendSolicit(NCE); - break; - - case NUD_DELAY: - /* FIXME: Delayed state */ - TI_DbgPrint(DEBUG_NCACHE, ("NCE delay state.\n")); - break; - - case NUD_PROBE: - /* FIXME: Probe state */ - TI_DbgPrint(DEBUG_NCACHE, ("NCE probe state.\n")); - break; - - default: - /* Should not happen since other states don't use the event timer */ - TI_DbgPrint(MIN_TRACE, ("Invalid NCE state (%d).\n", NCE->State)); - break; - } -} - - -VOID NBTimeout( - VOID) -/* - * FUNCTION: Neighbor address cache timeout handler - * NOTES: - * This routine is called by IPTimeout to remove outdated cache - * entries. - */ -{ - UINT i; - KIRQL OldIrql; - PNEIGHBOR_CACHE_ENTRY NCE; - - for (i = 0; i <= NB_HASHMASK; i++) { - KeAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql); - - for (NCE = NeighborCache[i].Cache; - NCE != NULL; NCE = NCE->Next) { - /* Check if event timer is running */ - if (NCE->EventTimer != 0) { - if (--NCE->EventTimer == 0) { - /* Call timeout handler for NCE */ - NCETimeout(NCE); - } - } - } - - KeReleaseSpinLock(&NeighborCache[i].Lock, OldIrql); - } -} - - -VOID NBStartup( - VOID) -/* - * FUNCTION: Starts the neighbor cache - */ -{ - UINT i; - - TI_DbgPrint(DEBUG_NCACHE, ("Called.\n")); - - for (i = 0; i <= NB_HASHMASK; i++) { - NeighborCache[i].Cache = NULL; - KeInitializeSpinLock(&NeighborCache[i].Lock); - } -} - - -VOID NBShutdown( - VOID) -/* - * FUNCTION: Shuts down the neighbor cache - */ -{ - UINT i; - KIRQL OldIrql; - PNDIS_PACKET NdisPacket, Next; - PNEIGHBOR_CACHE_ENTRY CurNCE, NextNCE; - - TI_DbgPrint(DEBUG_NCACHE, ("Called.\n")); - - /* Remove possible entries from the cache */ - for (i = 0; i <= NB_HASHMASK; i++) { - KeAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql); - - CurNCE = NeighborCache[i].Cache; - while (CurNCE) { - NextNCE = CurNCE->Next; - - /* Remove all references from route cache */ - RouteInvalidateNCE(CurNCE); - - /* Flush wait queue */ - NdisPacket = CurNCE->WaitQueue; - while (NdisPacket) { - Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete; - FreeNdisPacket(NdisPacket); - NdisPacket = Next; - } - -#if DBG - if (CurNCE->RefCount != 1) { - TI_DbgPrint(DEBUG_REFCOUNT, ("NCE at (0x%X) has (%d) references (should be 1).\n", CurNCE, CurNCE->RefCount)); - } -#endif - - /* Remove reference for being alive */ - DereferenceObject(CurNCE); - - CurNCE = NextNCE; - } - NeighborCache[i].Cache = NULL; - - KeReleaseSpinLock(&NeighborCache[i].Lock, OldIrql); - } - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); -} - - -VOID NBSendSolicit( - PNEIGHBOR_CACHE_ENTRY NCE) -/* - * FUNCTION: Sends a neighbor solicitation message - * ARGUMENTS: - * NCE = Pointer to NCE of neighbor to solicit - * NOTES: - * May be called with lock held on NCE's table - */ -{ - PLIST_ENTRY CurrentEntry; - PNET_TABLE_ENTRY NTE; - - TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE)); - - if (NCE->State == NUD_INCOMPLETE) { - /* This is the first solicitation of this neighbor. Broadcast - a request for the neighbor */ - - /* FIXME: Choose first NTE. We might want to give an NTE as argument */ - CurrentEntry = NCE->Interface->NTEListHead.Flink; - if (!IsListEmpty(CurrentEntry)) { - NTE = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); - ARPTransmit(NCE->Address, NTE); - } else { - TI_DbgPrint(MIN_TRACE, ("Interface at 0x%X has zero NTE.\n", NCE->Interface)); - } - } else { - /* FIXME: Unicast solicitation since we have a cached address */ - TI_DbgPrint(MIN_TRACE, ("Uninplemented unicast solicitation.\n")); - } -} - - -PNEIGHBOR_CACHE_ENTRY NBAddNeighbor( - PIP_INTERFACE Interface, - PIP_ADDRESS Address, - PVOID LinkAddress, - UINT LinkAddressLength, - UCHAR State) -/* - * 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 - */ -{ - ULONG HashValue; - KIRQL OldIrql; - PNEIGHBOR_CACHE_ENTRY NCE; - - 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 = PoolAllocateBuffer(sizeof(NEIGHBOR_CACHE_ENTRY) + LinkAddressLength); - if (!NCE) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - /* Reference once for beeing alive and once for the caller */ - NCE->RefCount = 2; - NCE->Interface = Interface; - NCE->Address = Address; - NCE->LinkAddressLength = LinkAddressLength; - NCE->LinkAddress = (PVOID)((ULONG_PTR)NCE + sizeof(NEIGHBOR_CACHE_ENTRY)); - if (LinkAddress) - RtlCopyMemory(NCE->LinkAddress, LinkAddress, LinkAddressLength); - NCE->State = State; - NCE->EventTimer = 0; /* Not in use */ - NCE->WaitQueue = NULL; - - HashValue = *(PULONG)&Address->Address; - HashValue ^= HashValue >> 16; - HashValue ^= HashValue >> 8; - HashValue ^= HashValue >> 4; - HashValue &= NB_HASHMASK; - - NCE->Table = &NeighborCache[HashValue]; - - KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); - - NCE->Next = NeighborCache[HashValue].Cache; - NeighborCache[HashValue].Cache = NCE; - - KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); - - 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; - PNDIS_PACKET Current; - PNDIS_PACKET Next; - - TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X) LinkAddress (0x%X) State (0x%X).\n", NCE, LinkAddress, State)); - - KeAcquireSpinLock(&NCE->Table->Lock, &OldIrql); - - RtlCopyMemory(NCE->LinkAddress, LinkAddress, NCE->LinkAddressLength); - NCE->State = State; - Current = NCE->WaitQueue; - NCE->WaitQueue = NULL; - - KeReleaseSpinLock(&NCE->Table->Lock, OldIrql); -#if 1 - /* Send any waiting packets */ - while (Current) { - /* Our link to the next packet is broken by the - datalink layer code so we must save it here */ - Next = (PNDIS_PACKET)PC(Current)->DLComplete; - IPSendFragment(Current, NCE); - Current = Next; - } -#endif -} - - -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 - */ -{ - UINT HashValue; - KIRQL OldIrql; - PNEIGHBOR_CACHE_ENTRY NCE; - - 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; - - KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); - - NCE = NeighborCache[HashValue].Cache; - - while ((NCE) && (!AddrIsEqual(Address, NCE->Address))) - NCE = NCE->Next; - - if (NCE) - ReferenceObject(NCE); - - KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); - - return NCE; -} - - -PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor( - PIP_INTERFACE Interface, - PIP_ADDRESS Address) -/* - * FUNCTION: Tries to find a neighbor and if unsuccesful, creates a new NCE - * ARGUMENTS: - * Interface = Pointer to interface to use (if 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); - if (!NCE) { - ReferenceObject(Address); - NCE = NBAddNeighbor(Interface, Address, NULL, - Interface->AddressLength, NUD_INCOMPLETE); - NCE->EventTimer = 1; - NCE->EventCount = 0; - } - - return NCE; -} - - -BOOLEAN NBQueuePacket( - PNEIGHBOR_CACHE_ENTRY NCE, - PNDIS_PACKET NdisPacket) -/* - * 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; - PKSPIN_LOCK Lock; - - TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X) NdisPacket (0x%X).\n", NCE, NdisPacket)); - - /* FIXME: Should we limit the number of queued packets? */ - - Lock = &NCE->Table->Lock; - - KeAcquireSpinLock(Lock, &OldIrql); - - /* Use data link level completion handler pointer to link - queued packets together */ - PC(NdisPacket)->DLComplete = (PACKET_COMPLETION_ROUTINE)NCE->WaitQueue; - NCE->WaitQueue = NdisPacket; - - KeReleaseSpinLock(Lock, OldIrql); - - 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 - */ -{ - ULONG HashValue; - KIRQL OldIrql; - PNEIGHBOR_CACHE_ENTRY *PrevNCE; - PNEIGHBOR_CACHE_ENTRY CurNCE; - PNDIS_PACKET NdisPacket, Next; - - 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; - - KeAcquireSpinLock(&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; - - /* Purge wait queue */ - NdisPacket = CurNCE->WaitQueue; - while (NdisPacket) { - Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete; - FreeNdisPacket(NdisPacket); - NdisPacket = Next; - } - - /* Remove all references from route cache */ - RouteInvalidateNCE(CurNCE); - - /* Remove reference to the address */ - DereferenceObject(CurNCE->Address); - -#if DBG - CurNCE->RefCount--; - - if (CurNCE->RefCount != 0) { - TI_DbgPrint(DEBUG_REFCOUNT, ("NCE at (0x%X) has (%d) references (should be 0).\n", CurNCE, CurNCE->RefCount)); - } -#endif - PoolFreeBuffer(CurNCE); - - KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); - - return; - } - } - - KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: network/neighbor.c + * PURPOSE: Neighbor address cache + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1]; + + +VOID NCETimeout( + PNEIGHBOR_CACHE_ENTRY NCE) +/* + * FUNCTION: Neighbor cache entry timeout handler + * NOTES: + * The neighbor cache lock must be held + */ +{ + PNDIS_PACKET NdisPacket, Next; + + TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE)); + + TI_DbgPrint(DEBUG_NCACHE, ("NCE->State is (0x%X).\n", NCE->State)); + + switch (NCE->State) { + case NUD_INCOMPLETE: + /* Retransmission timer expired */ + if (NCE->EventCount++ > MAX_MULTICAST_SOLICIT) { + /* We have retransmitted too many times */ + + /* Calling IPSendComplete with cache lock held is not + a great thing to do. We don't get here very often + so maybe it's not that big a problem */ + + /* Flush packet queue */ + NdisPacket = NCE->WaitQueue; + while (NdisPacket) { + Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete; + IPSendComplete((PVOID)NCE->Interface, NdisPacket, + NDIS_STATUS_REQUEST_ABORTED); + NdisPacket = Next; + } + NCE->WaitQueue = NULL; + + NCE->EventCount = 0; + + /* Remove route cache entries with references to this NCE. + Remember that neighbor cache lock is taken before + route cache lock */ + RouteInvalidateNCE(NCE); + } else + /* Retransmit request */ + NBSendSolicit(NCE); + break; + + case NUD_DELAY: + /* FIXME: Delayed state */ + TI_DbgPrint(DEBUG_NCACHE, ("NCE delay state.\n")); + break; + + case NUD_PROBE: + /* FIXME: Probe state */ + TI_DbgPrint(DEBUG_NCACHE, ("NCE probe state.\n")); + break; + + default: + /* Should not happen since other states don't use the event timer */ + TI_DbgPrint(MIN_TRACE, ("Invalid NCE state (%d).\n", NCE->State)); + break; + } +} + + +VOID NBTimeout( + VOID) +/* + * FUNCTION: Neighbor address cache timeout handler + * NOTES: + * This routine is called by IPTimeout to remove outdated cache + * entries. + */ +{ + UINT i; + KIRQL OldIrql; + PNEIGHBOR_CACHE_ENTRY NCE; + + for (i = 0; i <= NB_HASHMASK; i++) { + KeAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql); + + for (NCE = NeighborCache[i].Cache; + NCE != NULL; NCE = NCE->Next) { + /* Check if event timer is running */ + if (NCE->EventTimer != 0) { + if (--NCE->EventTimer == 0) { + /* Call timeout handler for NCE */ + NCETimeout(NCE); + } + } + } + + KeReleaseSpinLock(&NeighborCache[i].Lock, OldIrql); + } +} + + +VOID NBStartup( + VOID) +/* + * FUNCTION: Starts the neighbor cache + */ +{ + UINT i; + + TI_DbgPrint(DEBUG_NCACHE, ("Called.\n")); + + for (i = 0; i <= NB_HASHMASK; i++) { + NeighborCache[i].Cache = NULL; + KeInitializeSpinLock(&NeighborCache[i].Lock); + } +} + + +VOID NBShutdown( + VOID) +/* + * FUNCTION: Shuts down the neighbor cache + */ +{ + UINT i; + KIRQL OldIrql; + PNDIS_PACKET NdisPacket, Next; + PNEIGHBOR_CACHE_ENTRY CurNCE, NextNCE; + + TI_DbgPrint(DEBUG_NCACHE, ("Called.\n")); + + /* Remove possible entries from the cache */ + for (i = 0; i <= NB_HASHMASK; i++) { + KeAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql); + + CurNCE = NeighborCache[i].Cache; + while (CurNCE) { + NextNCE = CurNCE->Next; + + /* Remove all references from route cache */ + RouteInvalidateNCE(CurNCE); + + /* Flush wait queue */ + NdisPacket = CurNCE->WaitQueue; + while (NdisPacket) { + Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete; + FreeNdisPacket(NdisPacket); + NdisPacket = Next; + } + +#if DBG + if (CurNCE->RefCount != 1) { + TI_DbgPrint(DEBUG_REFCOUNT, ("NCE at (0x%X) has (%d) references (should be 1).\n", CurNCE, CurNCE->RefCount)); + } +#endif + + /* Remove reference for being alive */ + DereferenceObject(CurNCE); + + CurNCE = NextNCE; + } + NeighborCache[i].Cache = NULL; + + KeReleaseSpinLock(&NeighborCache[i].Lock, OldIrql); + } + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); +} + + +VOID NBSendSolicit( + PNEIGHBOR_CACHE_ENTRY NCE) +/* + * FUNCTION: Sends a neighbor solicitation message + * ARGUMENTS: + * NCE = Pointer to NCE of neighbor to solicit + * NOTES: + * May be called with lock held on NCE's table + */ +{ + PLIST_ENTRY CurrentEntry; + PNET_TABLE_ENTRY NTE; + + TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE)); + + if (NCE->State == NUD_INCOMPLETE) { + /* This is the first solicitation of this neighbor. Broadcast + a request for the neighbor */ + + /* FIXME: Choose first NTE. We might want to give an NTE as argument */ + CurrentEntry = NCE->Interface->NTEListHead.Flink; + if (!IsListEmpty(CurrentEntry)) { + NTE = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); + ARPTransmit(NCE->Address, NTE); + } else { + TI_DbgPrint(MIN_TRACE, ("Interface at 0x%X has zero NTE.\n", NCE->Interface)); + } + } else { + /* FIXME: Unicast solicitation since we have a cached address */ + TI_DbgPrint(MIN_TRACE, ("Uninplemented unicast solicitation.\n")); + } +} + + +PNEIGHBOR_CACHE_ENTRY NBAddNeighbor( + PIP_INTERFACE Interface, + PIP_ADDRESS Address, + PVOID LinkAddress, + UINT LinkAddressLength, + UCHAR State) +/* + * 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 + */ +{ + ULONG HashValue; + KIRQL OldIrql; + PNEIGHBOR_CACHE_ENTRY NCE; + + 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 = PoolAllocateBuffer(sizeof(NEIGHBOR_CACHE_ENTRY) + LinkAddressLength); + if (!NCE) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + /* Reference once for beeing alive and once for the caller */ + NCE->RefCount = 2; + NCE->Interface = Interface; + NCE->Address = Address; + NCE->LinkAddressLength = LinkAddressLength; + NCE->LinkAddress = (PVOID)((ULONG_PTR)NCE + sizeof(NEIGHBOR_CACHE_ENTRY)); + if (LinkAddress) + RtlCopyMemory(NCE->LinkAddress, LinkAddress, LinkAddressLength); + NCE->State = State; + NCE->EventTimer = 0; /* Not in use */ + NCE->WaitQueue = NULL; + + HashValue = *(PULONG)&Address->Address; + HashValue ^= HashValue >> 16; + HashValue ^= HashValue >> 8; + HashValue ^= HashValue >> 4; + HashValue &= NB_HASHMASK; + + NCE->Table = &NeighborCache[HashValue]; + + KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); + + NCE->Next = NeighborCache[HashValue].Cache; + NeighborCache[HashValue].Cache = NCE; + + KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); + + 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; + PNDIS_PACKET Current; + PNDIS_PACKET Next; + + TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X) LinkAddress (0x%X) State (0x%X).\n", NCE, LinkAddress, State)); + + KeAcquireSpinLock(&NCE->Table->Lock, &OldIrql); + + RtlCopyMemory(NCE->LinkAddress, LinkAddress, NCE->LinkAddressLength); + NCE->State = State; + Current = NCE->WaitQueue; + NCE->WaitQueue = NULL; + + KeReleaseSpinLock(&NCE->Table->Lock, OldIrql); +#if 1 + /* Send any waiting packets */ + while (Current) { + /* Our link to the next packet is broken by the + datalink layer code so we must save it here */ + Next = (PNDIS_PACKET)PC(Current)->DLComplete; + IPSendFragment(Current, NCE); + Current = Next; + } +#endif +} + + +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 + */ +{ + UINT HashValue; + KIRQL OldIrql; + PNEIGHBOR_CACHE_ENTRY NCE; + + 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; + + KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql); + + NCE = NeighborCache[HashValue].Cache; + + while ((NCE) && (!AddrIsEqual(Address, NCE->Address))) + NCE = NCE->Next; + + if (NCE) + ReferenceObject(NCE); + + KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); + + return NCE; +} + + +PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor( + PIP_INTERFACE Interface, + PIP_ADDRESS Address) +/* + * FUNCTION: Tries to find a neighbor and if unsuccesful, creates a new NCE + * ARGUMENTS: + * Interface = Pointer to interface to use (if 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); + if (!NCE) { + ReferenceObject(Address); + NCE = NBAddNeighbor(Interface, Address, NULL, + Interface->AddressLength, NUD_INCOMPLETE); + NCE->EventTimer = 1; + NCE->EventCount = 0; + } + + return NCE; +} + + +BOOLEAN NBQueuePacket( + PNEIGHBOR_CACHE_ENTRY NCE, + PNDIS_PACKET NdisPacket) +/* + * 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; + PKSPIN_LOCK Lock; + + TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X) NdisPacket (0x%X).\n", NCE, NdisPacket)); + + /* FIXME: Should we limit the number of queued packets? */ + + Lock = &NCE->Table->Lock; + + KeAcquireSpinLock(Lock, &OldIrql); + + /* Use data link level completion handler pointer to link + queued packets together */ + PC(NdisPacket)->DLComplete = (PACKET_COMPLETION_ROUTINE)NCE->WaitQueue; + NCE->WaitQueue = NdisPacket; + + KeReleaseSpinLock(Lock, OldIrql); + + 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 + */ +{ + ULONG HashValue; + KIRQL OldIrql; + PNEIGHBOR_CACHE_ENTRY *PrevNCE; + PNEIGHBOR_CACHE_ENTRY CurNCE; + PNDIS_PACKET NdisPacket, Next; + + 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; + + KeAcquireSpinLock(&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; + + /* Purge wait queue */ + NdisPacket = CurNCE->WaitQueue; + while (NdisPacket) { + Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete; + FreeNdisPacket(NdisPacket); + NdisPacket = Next; + } + + /* Remove all references from route cache */ + RouteInvalidateNCE(CurNCE); + + /* Remove reference to the address */ + DereferenceObject(CurNCE->Address); + +#if DBG + CurNCE->RefCount--; + + if (CurNCE->RefCount != 0) { + TI_DbgPrint(DEBUG_REFCOUNT, ("NCE at (0x%X) has (%d) references (should be 0).\n", CurNCE, CurNCE->RefCount)); + } +#endif + PoolFreeBuffer(CurNCE); + + KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); + + return; + } + } + + KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql); +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/network/receive.c b/reactos/drivers/net/tcpip/network/receive.c index 679a899915a..01ee7ac4af1 100644 --- a/reactos/drivers/net/tcpip/network/receive.c +++ b/reactos/drivers/net/tcpip/network/receive.c @@ -1,638 +1,638 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: network/receive.c - * PURPOSE: Internet Protocol receive routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * NOTES: The IP datagram reassembly algorithm is taken from - * from RFC 815 - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include -#include - - -LIST_ENTRY ReassemblyListHead; -KSPIN_LOCK ReassemblyListLock; - - -PIPDATAGRAM_HOLE CreateHoleDescriptor( - ULONG First, - ULONG Last) -/* - * FUNCTION: Returns a pointer to a IP datagram hole descriptor - * ARGUMENTS: - * First = Offset of first octet of the hole - * Last = Offset of last octet of the hole - * RETURNS: - * Pointer to descriptor, NULL if there was not enough free - * resources - */ -{ - PIPDATAGRAM_HOLE Hole; - - TI_DbgPrint(DEBUG_IP, ("Called. First (%d) Last (%d).\n", First, Last)); - - Hole = PoolAllocateBuffer(sizeof(IPDATAGRAM_HOLE)); - if (!Hole) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - Hole->First = First; - Hole->Last = Last; - - TI_DbgPrint(DEBUG_IP, ("Returning hole descriptor at (0x%X).\n", Hole)); - - return Hole; -} - - -VOID FreeIPDR( - PIPDATAGRAM_REASSEMBLY IPDR) -/* - * FUNCTION: Frees an IP datagram reassembly structure - * ARGUMENTS: - * IPDR = Pointer to IP datagram reassembly structure - */ -{ - PLIST_ENTRY CurrentEntry; - PLIST_ENTRY NextEntry; - PIPDATAGRAM_HOLE CurrentH; - PIP_FRAGMENT CurrentF; - - TI_DbgPrint(DEBUG_IP, ("Freeing IP datagram reassembly descriptor (0x%X).\n", IPDR)); - - /* Free all descriptors */ - CurrentEntry = IPDR->HoleListHead.Flink; - while (CurrentEntry != &IPDR->HoleListHead) { - NextEntry = CurrentEntry->Flink; - CurrentH = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry); - /* Unlink it from the list */ - RemoveEntryList(CurrentEntry); - - TI_DbgPrint(DEBUG_IP, ("Freeing hole descriptor at (0x%X).\n", CurrentH)); - - /* And free the hole descriptor */ - PoolFreeBuffer(CurrentH); - - CurrentEntry = NextEntry; - } - - /* Free all fragments */ - CurrentEntry = IPDR->FragmentListHead.Flink; - while (CurrentEntry != &IPDR->FragmentListHead) { - NextEntry = CurrentEntry->Flink; - CurrentF = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry); - /* Unlink it from the list */ - RemoveEntryList(CurrentEntry); - - TI_DbgPrint(DEBUG_IP, ("Freeing fragment data at (0x%X).\n", CurrentF->Data)); - - /* Free the fragment data buffer */ - ExFreePool(CurrentF->Data); - - TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF)); - - /* And free the fragment descriptor */ - PoolFreeBuffer(CurrentF); - CurrentEntry = NextEntry; - } - - /* Free resources for the header, if it exists */ - if (IPDR->IPv4Header) { - TI_DbgPrint(DEBUG_IP, ("Freeing IPv4 header data at (0x%X).\n", IPDR->IPv4Header)); - ExFreePool(IPDR->IPv4Header); - } - - TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR)); - - PoolFreeBuffer(IPDR); -} - - -VOID RemoveIPDR( - PIPDATAGRAM_REASSEMBLY IPDR) -/* - * FUNCTION: Removes an IP datagram reassembly structure from the global list - * ARGUMENTS: - * IPDR = Pointer to IP datagram reassembly structure - */ -{ - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR)); - - KeAcquireSpinLock(&ReassemblyListLock, &OldIrql); - RemoveEntryList(&IPDR->ListEntry); - KeReleaseSpinLock(&ReassemblyListLock, OldIrql); -} - - -PIPDATAGRAM_REASSEMBLY GetReassemblyInfo( - PIP_PACKET IPPacket) -/* - * FUNCTION: Returns a pointer to an IP datagram reassembly structure - * ARGUMENTS: - * IPPacket = Pointer to IP packet - * NOTES: - * A datagram is identified by four paramters, which are - * Source and destination address, protocol number and - * identification number - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PIPDATAGRAM_REASSEMBLY Current; - PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header; - - TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket)); - - KeAcquireSpinLock(&ReassemblyListLock, &OldIrql); - - /* FIXME: Assume IPv4 */ - - CurrentEntry = ReassemblyListHead.Flink; - while (CurrentEntry != &ReassemblyListHead) { - Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry); - if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) && - (Header->Id == Current->Id) && - (Header->Protocol == Current->Protocol) && - (AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) { - KeReleaseSpinLock(&ReassemblyListLock, OldIrql); - - return Current; - } - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&ReassemblyListLock, OldIrql); - - return NULL; -} - - -PIP_PACKET ReassembleDatagram( - PIPDATAGRAM_REASSEMBLY IPDR) -/* - * FUNCTION: Reassembles an IP datagram - * ARGUMENTS: - * IPDR = Pointer to IP datagram reassembly structure - * NOTES: - * This routine concatenates fragments into a complete IP datagram. - * The lock is held when this routine is called - * RETURNS: - * Pointer to IP packet, NULL if there was not enough free resources - */ -{ - PIP_PACKET IPPacket; - PLIST_ENTRY CurrentEntry; - PIP_FRAGMENT Current; - PVOID Data; - - TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR)); - - IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET)); - if (!IPPacket) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - /* FIXME: Assume IPv4 */ - - IPPacket->Type = IP_ADDRESS_V4; - IPPacket->RefCount = 1; - IPPacket->TotalSize = IPDR->HeaderSize + IPDR->DataSize; - IPPacket->HeaderSize = IPDR->HeaderSize; - IPPacket->Position = IPDR->HeaderSize; - - RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS)); - RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS)); - - /* Allocate space for full IP datagram */ - IPPacket->Header = ExAllocatePool(NonPagedPool, IPPacket->TotalSize); - if (!IPPacket->Header) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - PoolFreeBuffer(IPPacket); - return NULL; - } - - /* Copy the header into the buffer */ - RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize); - - Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize); - IPPacket->Data = Data; - - /* Copy data from all fragments into buffer */ - CurrentEntry = IPDR->FragmentListHead.Flink; - while (CurrentEntry != &IPDR->FragmentListHead) { - Current = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry); - - TI_DbgPrint(DEBUG_IP, ("Copying (%d) bytes of fragment data from (0x%X) to offset (%d).\n", - Current->Size, Data, Current->Offset)); - /* Copy fragment data to the destination buffer at the correct offset */ - RtlCopyMemory((PVOID)((ULONG_PTR)Data + Current->Offset), - Current->Data, - Current->Size); - - CurrentEntry = CurrentEntry->Flink; - } - - return IPPacket; -} - - -__inline VOID Cleanup( - PKSPIN_LOCK Lock, - KIRQL OldIrql, - PIPDATAGRAM_REASSEMBLY IPDR, - PVOID Buffer OPTIONAL) -/* - * FUNCTION: Performs cleaning operations on errors - * ARGUMENTS: - * Lock = Pointer to spin lock to be released - * OldIrql = Value of IRQL when spin lock was acquired - * IPDR = Pointer to IP datagram reassembly structure to free - * Buffer = Optional pointer to a buffer to free - */ -{ - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - - KeReleaseSpinLock(Lock, OldIrql); - RemoveIPDR(IPDR); - FreeIPDR(IPDR); - if (Buffer) - PoolFreeBuffer(Buffer); -} - - -VOID ProcessFragment( - PIP_INTERFACE IF, - PIP_PACKET IPPacket, - PNET_TABLE_ENTRY NTE) -/* - * FUNCTION: Processes an IP datagram or fragment - * ARGUMENTS: - * IF = Pointer to IP interface packet was receive on - * IPPacket = Pointer to IP packet - * NTE = Pointer to NTE packet was received on - * NOTES: - * This routine reassembles fragments and, if a whole datagram can - * be assembled, passes the datagram on to the IP protocol dispatcher - */ -{ - KIRQL OldIrql; - PIPDATAGRAM_REASSEMBLY IPDR; - PLIST_ENTRY CurrentEntry; - PIPDATAGRAM_HOLE Hole, NewHole; - USHORT FragFirst; - USHORT FragLast; - BOOLEAN MoreFragments; - PIPv4_HEADER IPv4Header; - PIP_PACKET Datagram; - PIP_FRAGMENT Fragment; - - /* FIXME: Assume IPv4 */ - - IPv4Header = (PIPv4_HEADER)IPPacket->Header; - - /* Check if we already have an reassembly structure for this datagram */ - IPDR = GetReassemblyInfo(IPPacket); - if (IPDR) { - TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n")); - /* We have a reassembly structure */ - KeAcquireSpinLock(&IPDR->Lock, &OldIrql); - CurrentEntry = IPDR->HoleListHead.Flink; - Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry); - } else { - TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n")); - - /* We don't have a reassembly structure, create one */ - IPDR = PoolAllocateBuffer(sizeof(IPDATAGRAM_REASSEMBLY)); - if (!IPDR) { - /* We don't have the resources to process this packet, discard it */ - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return; - } - - /* Create a descriptor spanning from zero to infinity. - Actually, we use a value slightly greater than the - maximum number of octets an IP datagram can contain */ - Hole = CreateHoleDescriptor(0, 65536); - if (!Hole) { - /* We don't have the resources to process this packet, discard it */ - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - PoolFreeBuffer(IPDR); - return; - } - AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr); - AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr); - IPDR->Id = IPv4Header->Id; - IPDR->Protocol = IPv4Header->Protocol; - IPDR->IPv4Header = NULL; - InitializeListHead(&IPDR->FragmentListHead); - InitializeListHead(&IPDR->HoleListHead); - InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry); - CurrentEntry = IPDR->HoleListHead.Flink; - - KeInitializeSpinLock(&IPDR->Lock); - - KeAcquireSpinLock(&IPDR->Lock, &OldIrql); - - /* Update the reassembly list */ - ExInterlockedInsertTailList(&ReassemblyListHead, - &IPDR->ListEntry, - &ReassemblyListLock); - } - - FragFirst = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3; - FragLast = FragFirst + WN2H(IPv4Header->TotalLength); - MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0; - - for (;;) { - if (CurrentEntry == &IPDR->HoleListHead) - /* No more entries */ - break; - - TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n", - FragFirst, FragLast, Hole->First, Hole->Last)); - - if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) { - TI_DbgPrint(MID_TRACE, ("No overlap.\n")); - /* The fragment does not overlap with the hole, try next - descriptor in the list */ - - CurrentEntry = CurrentEntry->Flink; - if (CurrentEntry != &IPDR->HoleListHead) - Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry); - continue; - } - - /* The fragment overlap with the hole, unlink the descriptor */ - RemoveEntryList(CurrentEntry); - - if (FragFirst > Hole->First) { - NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1); - if (!NewHole) { - /* We don't have the resources to process this packet, discard it */ - Cleanup(&IPDR->Lock, OldIrql, IPDR, Hole); - return; - } - - /* Put the new descriptor in the list */ - InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry); - } - - if ((FragLast < Hole->Last) && (MoreFragments)) { - /* We can reuse the descriptor for the new hole */ - Hole->First = FragLast + 1; - - /* Put the new hole descriptor in the list */ - InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry); - } else - PoolFreeBuffer(Hole); - - /* If this is the first fragment, save the IP header */ - if (FragFirst == 0) { - IPDR->IPv4Header = ExAllocatePool(NonPagedPool, IPPacket->HeaderSize); - if (!IPDR->IPv4Header) { - /* We don't have the resources to process this packet, discard it */ - Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL); - return; - } - - TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). " - "Header size is (%d).\n", IPDR->IPv4Header, IPPacket->HeaderSize)); - - RtlCopyMemory(IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize); - IPDR->HeaderSize = IPPacket->HeaderSize; - } - - /* Create a buffer, copy the data into it and put it - in the fragment list */ - - Fragment = PoolAllocateBuffer(sizeof(IP_FRAGMENT)); - if (!Fragment) { - /* We don't have the resources to process this packet, discard it */ - Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL); - return; - } - - TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment)); - - Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize; - Fragment->Data = ExAllocatePool(NonPagedPool, Fragment->Size); - if (!Fragment->Data) { - /* We don't have the resources to process this packet, discard it */ - Cleanup(&IPDR->Lock, OldIrql, IPDR, Fragment); - return; - } - - TI_DbgPrint(DEBUG_IP, ("Fragment data buffer allocated at (0x%X) Size (%d).\n", - Fragment->Data, Fragment->Size)); - - /* Copy datagram data into fragment buffer */ - CopyPacketToBuffer(Fragment->Data, - IPPacket->NdisPacket, - IPPacket->Position, - Fragment->Size); - Fragment->Offset = FragFirst; - - /* If this is the last fragment, compute and save the datagram data size */ - if (!MoreFragments) - IPDR->DataSize = FragFirst + Fragment->Size; - - /* Put the fragment in the list */ - InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry); - break; - } - - TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n")); - - if (IsListEmpty(&IPDR->HoleListHead)) { - /* Hole list is empty which means a complete datagram can be assembled. - Assemble the datagram and pass it to an upper layer protocol */ - - TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n")); - - Datagram = ReassembleDatagram(IPDR); - KeReleaseSpinLock(&IPDR->Lock, OldIrql); - - RemoveIPDR(IPDR); - FreeIPDR(IPDR); - - if (!Datagram) { - /* Not enough free resources, discard the packet */ - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return; - } - - /* Give the packet to the protocol dispatcher */ - IPDispatchProtocol(NTE, Datagram); - - /* We're done with this datagram */ - ExFreePool(Datagram->Header); - PoolFreeBuffer(Datagram); - } else - KeReleaseSpinLock(&IPDR->Lock, OldIrql); -} - - -VOID IPFreeReassemblyList( - VOID) -/* - * FUNCTION: Frees all IP datagram reassembly structures in the list - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PIPDATAGRAM_REASSEMBLY Current; - - KeAcquireSpinLock(&ReassemblyListLock, &OldIrql); - - CurrentEntry = ReassemblyListHead.Flink; - while (CurrentEntry != &ReassemblyListHead) { - Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry); - /* Unlink it from the list */ - RemoveEntryList(CurrentEntry); - - /* And free the descriptor */ - FreeIPDR(Current); - - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&ReassemblyListLock, OldIrql); -} - - -VOID IPDatagramReassemblyTimeout( - VOID) -/* - * FUNCTION: IP datagram reassembly timeout handler - * NOTES: - * This routine is called by IPTimeout to free any resources used - * to hold IP fragments that are being reassembled to form a - * complete IP datagram - */ -{ -} - - -VOID IPv4Receive( - PVOID Context, - PIP_PACKET IPPacket) -/* - * FUNCTION: Receives an IPv4 datagram (or fragment) - * ARGUMENTS: - * Context = Pointer to context information (IP_INTERFACE) - * IPPacket = Pointer to IP packet - */ -{ -// PNEIGHBOR_CACHE_ENTRY NCE; - PNET_TABLE_ENTRY NTE; - UINT AddressType; - - TI_DbgPrint(MAX_TRACE, ("Received IPv4 datagram.\n")); - - IPPacket->HeaderSize = (((PIPv4_HEADER)IPPacket->Header)->VerIHL & 0x0F) << 2; - - if (IPPacket->HeaderSize > IPv4_MAX_HEADER_SIZE) { - TI_DbgPrint(MIN_TRACE, ("Datagram received with incorrect header size (%d).\n", - IPPacket->HeaderSize)); - /* Discard packet */ - return; - } - - /* Checksum IPv4 header */ - if (!CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) { - TI_DbgPrint(MIN_TRACE, ("Datagram received with bad checksum. Checksum field (0x%X)\n", - WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum))); - /* Discard packet */ - return; - } - - TI_DbgPrint(MAX_TRACE, ("TotalSize (datalink) is (%d).\n", IPPacket->TotalSize)); - - IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength); - - TI_DbgPrint(MAX_TRACE, ("TotalSize (IPv4) is (%d).\n", IPPacket->TotalSize)); - - AddrInitIPv4(&IPPacket->SrcAddr, ((PIPv4_HEADER)IPPacket->Header)->SrcAddr); - AddrInitIPv4(&IPPacket->DstAddr, ((PIPv4_HEADER)IPPacket->Header)->DstAddr); - - IPPacket->Position = IPPacket->HeaderSize; - IPPacket->Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPPacket->HeaderSize); - - /* FIXME: Possibly forward packets with multicast addresses */ - - /* FIXME: Should we allow packets to be received on the wrong interface? */ -#if 0 - NTE = IPLocateNTE(&IPPacket->DstAddr, &AddressType); -#else - NTE = IPLocateNTEOnInterface((PIP_INTERFACE)Context, &IPPacket->DstAddr, &AddressType); -#endif - if (NTE) { - /* This packet is destined for us */ - ProcessFragment((PIP_INTERFACE)Context, IPPacket, NTE); - /* Done with this NTE */ - DereferenceObject(NTE); - } else { - /* This packet is not destined for us. If we are a router, - try to find a route and forward the packet */ - - /* FIXME: Check if acting as a router */ -#if 0 - NCE = RouteFindRouter(&IPPacket->DstAddr, NULL); - if (NCE) { - /* FIXME: Possibly fragment datagram */ - /* Forward the packet */ - IPSendFragment(IPPacket, NCE); - } else { - TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n", - IPPacket->DstAddr.Address.IPv4Address)); - - /* FIXME: Send ICMP error code */ - } -#endif - } -} - - -VOID IPReceive( - PVOID Context, - PIP_PACKET IPPacket) -/* - * FUNCTION: Receives an IP datagram (or fragment) - * ARGUMENTS: - * Context = Pointer to context information (IP_INTERFACE) - * IPPacket = Pointer to IP packet - */ -{ - UINT Version; - - /* Check that IP header has a supported version */ - Version = (((PIPv4_HEADER)IPPacket->Header)->VerIHL >> 4); - switch (Version) { - case 4: - IPPacket->Type = IP_ADDRESS_V4; - IPv4Receive(Context, IPPacket); - break; - case 6: - IPPacket->Type = IP_ADDRESS_V6; - TI_DbgPrint(MIN_TRACE, ("Datagram of type IPv6 discarded.\n")); - return; - default: - TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version)); - return; - } -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: network/receive.c + * PURPOSE: Internet Protocol receive routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * NOTES: The IP datagram reassembly algorithm is taken from + * from RFC 815 + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +LIST_ENTRY ReassemblyListHead; +KSPIN_LOCK ReassemblyListLock; + + +PIPDATAGRAM_HOLE CreateHoleDescriptor( + ULONG First, + ULONG Last) +/* + * FUNCTION: Returns a pointer to a IP datagram hole descriptor + * ARGUMENTS: + * First = Offset of first octet of the hole + * Last = Offset of last octet of the hole + * RETURNS: + * Pointer to descriptor, NULL if there was not enough free + * resources + */ +{ + PIPDATAGRAM_HOLE Hole; + + TI_DbgPrint(DEBUG_IP, ("Called. First (%d) Last (%d).\n", First, Last)); + + Hole = PoolAllocateBuffer(sizeof(IPDATAGRAM_HOLE)); + if (!Hole) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + Hole->First = First; + Hole->Last = Last; + + TI_DbgPrint(DEBUG_IP, ("Returning hole descriptor at (0x%X).\n", Hole)); + + return Hole; +} + + +VOID FreeIPDR( + PIPDATAGRAM_REASSEMBLY IPDR) +/* + * FUNCTION: Frees an IP datagram reassembly structure + * ARGUMENTS: + * IPDR = Pointer to IP datagram reassembly structure + */ +{ + PLIST_ENTRY CurrentEntry; + PLIST_ENTRY NextEntry; + PIPDATAGRAM_HOLE CurrentH; + PIP_FRAGMENT CurrentF; + + TI_DbgPrint(DEBUG_IP, ("Freeing IP datagram reassembly descriptor (0x%X).\n", IPDR)); + + /* Free all descriptors */ + CurrentEntry = IPDR->HoleListHead.Flink; + while (CurrentEntry != &IPDR->HoleListHead) { + NextEntry = CurrentEntry->Flink; + CurrentH = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry); + /* Unlink it from the list */ + RemoveEntryList(CurrentEntry); + + TI_DbgPrint(DEBUG_IP, ("Freeing hole descriptor at (0x%X).\n", CurrentH)); + + /* And free the hole descriptor */ + PoolFreeBuffer(CurrentH); + + CurrentEntry = NextEntry; + } + + /* Free all fragments */ + CurrentEntry = IPDR->FragmentListHead.Flink; + while (CurrentEntry != &IPDR->FragmentListHead) { + NextEntry = CurrentEntry->Flink; + CurrentF = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry); + /* Unlink it from the list */ + RemoveEntryList(CurrentEntry); + + TI_DbgPrint(DEBUG_IP, ("Freeing fragment data at (0x%X).\n", CurrentF->Data)); + + /* Free the fragment data buffer */ + ExFreePool(CurrentF->Data); + + TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF)); + + /* And free the fragment descriptor */ + PoolFreeBuffer(CurrentF); + CurrentEntry = NextEntry; + } + + /* Free resources for the header, if it exists */ + if (IPDR->IPv4Header) { + TI_DbgPrint(DEBUG_IP, ("Freeing IPv4 header data at (0x%X).\n", IPDR->IPv4Header)); + ExFreePool(IPDR->IPv4Header); + } + + TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR)); + + PoolFreeBuffer(IPDR); +} + + +VOID RemoveIPDR( + PIPDATAGRAM_REASSEMBLY IPDR) +/* + * FUNCTION: Removes an IP datagram reassembly structure from the global list + * ARGUMENTS: + * IPDR = Pointer to IP datagram reassembly structure + */ +{ + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR)); + + KeAcquireSpinLock(&ReassemblyListLock, &OldIrql); + RemoveEntryList(&IPDR->ListEntry); + KeReleaseSpinLock(&ReassemblyListLock, OldIrql); +} + + +PIPDATAGRAM_REASSEMBLY GetReassemblyInfo( + PIP_PACKET IPPacket) +/* + * FUNCTION: Returns a pointer to an IP datagram reassembly structure + * ARGUMENTS: + * IPPacket = Pointer to IP packet + * NOTES: + * A datagram is identified by four paramters, which are + * Source and destination address, protocol number and + * identification number + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PIPDATAGRAM_REASSEMBLY Current; + PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header; + + TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket)); + + KeAcquireSpinLock(&ReassemblyListLock, &OldIrql); + + /* FIXME: Assume IPv4 */ + + CurrentEntry = ReassemblyListHead.Flink; + while (CurrentEntry != &ReassemblyListHead) { + Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry); + if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) && + (Header->Id == Current->Id) && + (Header->Protocol == Current->Protocol) && + (AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) { + KeReleaseSpinLock(&ReassemblyListLock, OldIrql); + + return Current; + } + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&ReassemblyListLock, OldIrql); + + return NULL; +} + + +PIP_PACKET ReassembleDatagram( + PIPDATAGRAM_REASSEMBLY IPDR) +/* + * FUNCTION: Reassembles an IP datagram + * ARGUMENTS: + * IPDR = Pointer to IP datagram reassembly structure + * NOTES: + * This routine concatenates fragments into a complete IP datagram. + * The lock is held when this routine is called + * RETURNS: + * Pointer to IP packet, NULL if there was not enough free resources + */ +{ + PIP_PACKET IPPacket; + PLIST_ENTRY CurrentEntry; + PIP_FRAGMENT Current; + PVOID Data; + + TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR)); + + IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET)); + if (!IPPacket) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + /* FIXME: Assume IPv4 */ + + IPPacket->Type = IP_ADDRESS_V4; + IPPacket->RefCount = 1; + IPPacket->TotalSize = IPDR->HeaderSize + IPDR->DataSize; + IPPacket->HeaderSize = IPDR->HeaderSize; + IPPacket->Position = IPDR->HeaderSize; + + RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS)); + RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS)); + + /* Allocate space for full IP datagram */ + IPPacket->Header = ExAllocatePool(NonPagedPool, IPPacket->TotalSize); + if (!IPPacket->Header) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + PoolFreeBuffer(IPPacket); + return NULL; + } + + /* Copy the header into the buffer */ + RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize); + + Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize); + IPPacket->Data = Data; + + /* Copy data from all fragments into buffer */ + CurrentEntry = IPDR->FragmentListHead.Flink; + while (CurrentEntry != &IPDR->FragmentListHead) { + Current = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry); + + TI_DbgPrint(DEBUG_IP, ("Copying (%d) bytes of fragment data from (0x%X) to offset (%d).\n", + Current->Size, Data, Current->Offset)); + /* Copy fragment data to the destination buffer at the correct offset */ + RtlCopyMemory((PVOID)((ULONG_PTR)Data + Current->Offset), + Current->Data, + Current->Size); + + CurrentEntry = CurrentEntry->Flink; + } + + return IPPacket; +} + + +__inline VOID Cleanup( + PKSPIN_LOCK Lock, + KIRQL OldIrql, + PIPDATAGRAM_REASSEMBLY IPDR, + PVOID Buffer OPTIONAL) +/* + * FUNCTION: Performs cleaning operations on errors + * ARGUMENTS: + * Lock = Pointer to spin lock to be released + * OldIrql = Value of IRQL when spin lock was acquired + * IPDR = Pointer to IP datagram reassembly structure to free + * Buffer = Optional pointer to a buffer to free + */ +{ + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + + KeReleaseSpinLock(Lock, OldIrql); + RemoveIPDR(IPDR); + FreeIPDR(IPDR); + if (Buffer) + PoolFreeBuffer(Buffer); +} + + +VOID ProcessFragment( + PIP_INTERFACE IF, + PIP_PACKET IPPacket, + PNET_TABLE_ENTRY NTE) +/* + * FUNCTION: Processes an IP datagram or fragment + * ARGUMENTS: + * IF = Pointer to IP interface packet was receive on + * IPPacket = Pointer to IP packet + * NTE = Pointer to NTE packet was received on + * NOTES: + * This routine reassembles fragments and, if a whole datagram can + * be assembled, passes the datagram on to the IP protocol dispatcher + */ +{ + KIRQL OldIrql; + PIPDATAGRAM_REASSEMBLY IPDR; + PLIST_ENTRY CurrentEntry; + PIPDATAGRAM_HOLE Hole, NewHole; + USHORT FragFirst; + USHORT FragLast; + BOOLEAN MoreFragments; + PIPv4_HEADER IPv4Header; + PIP_PACKET Datagram; + PIP_FRAGMENT Fragment; + + /* FIXME: Assume IPv4 */ + + IPv4Header = (PIPv4_HEADER)IPPacket->Header; + + /* Check if we already have an reassembly structure for this datagram */ + IPDR = GetReassemblyInfo(IPPacket); + if (IPDR) { + TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n")); + /* We have a reassembly structure */ + KeAcquireSpinLock(&IPDR->Lock, &OldIrql); + CurrentEntry = IPDR->HoleListHead.Flink; + Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry); + } else { + TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n")); + + /* We don't have a reassembly structure, create one */ + IPDR = PoolAllocateBuffer(sizeof(IPDATAGRAM_REASSEMBLY)); + if (!IPDR) { + /* We don't have the resources to process this packet, discard it */ + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return; + } + + /* Create a descriptor spanning from zero to infinity. + Actually, we use a value slightly greater than the + maximum number of octets an IP datagram can contain */ + Hole = CreateHoleDescriptor(0, 65536); + if (!Hole) { + /* We don't have the resources to process this packet, discard it */ + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + PoolFreeBuffer(IPDR); + return; + } + AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr); + AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr); + IPDR->Id = IPv4Header->Id; + IPDR->Protocol = IPv4Header->Protocol; + IPDR->IPv4Header = NULL; + InitializeListHead(&IPDR->FragmentListHead); + InitializeListHead(&IPDR->HoleListHead); + InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry); + CurrentEntry = IPDR->HoleListHead.Flink; + + KeInitializeSpinLock(&IPDR->Lock); + + KeAcquireSpinLock(&IPDR->Lock, &OldIrql); + + /* Update the reassembly list */ + ExInterlockedInsertTailList(&ReassemblyListHead, + &IPDR->ListEntry, + &ReassemblyListLock); + } + + FragFirst = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3; + FragLast = FragFirst + WN2H(IPv4Header->TotalLength); + MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0; + + for (;;) { + if (CurrentEntry == &IPDR->HoleListHead) + /* No more entries */ + break; + + TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n", + FragFirst, FragLast, Hole->First, Hole->Last)); + + if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) { + TI_DbgPrint(MID_TRACE, ("No overlap.\n")); + /* The fragment does not overlap with the hole, try next + descriptor in the list */ + + CurrentEntry = CurrentEntry->Flink; + if (CurrentEntry != &IPDR->HoleListHead) + Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry); + continue; + } + + /* The fragment overlap with the hole, unlink the descriptor */ + RemoveEntryList(CurrentEntry); + + if (FragFirst > Hole->First) { + NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1); + if (!NewHole) { + /* We don't have the resources to process this packet, discard it */ + Cleanup(&IPDR->Lock, OldIrql, IPDR, Hole); + return; + } + + /* Put the new descriptor in the list */ + InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry); + } + + if ((FragLast < Hole->Last) && (MoreFragments)) { + /* We can reuse the descriptor for the new hole */ + Hole->First = FragLast + 1; + + /* Put the new hole descriptor in the list */ + InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry); + } else + PoolFreeBuffer(Hole); + + /* If this is the first fragment, save the IP header */ + if (FragFirst == 0) { + IPDR->IPv4Header = ExAllocatePool(NonPagedPool, IPPacket->HeaderSize); + if (!IPDR->IPv4Header) { + /* We don't have the resources to process this packet, discard it */ + Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL); + return; + } + + TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). " + "Header size is (%d).\n", IPDR->IPv4Header, IPPacket->HeaderSize)); + + RtlCopyMemory(IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize); + IPDR->HeaderSize = IPPacket->HeaderSize; + } + + /* Create a buffer, copy the data into it and put it + in the fragment list */ + + Fragment = PoolAllocateBuffer(sizeof(IP_FRAGMENT)); + if (!Fragment) { + /* We don't have the resources to process this packet, discard it */ + Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL); + return; + } + + TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment)); + + Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize; + Fragment->Data = ExAllocatePool(NonPagedPool, Fragment->Size); + if (!Fragment->Data) { + /* We don't have the resources to process this packet, discard it */ + Cleanup(&IPDR->Lock, OldIrql, IPDR, Fragment); + return; + } + + TI_DbgPrint(DEBUG_IP, ("Fragment data buffer allocated at (0x%X) Size (%d).\n", + Fragment->Data, Fragment->Size)); + + /* Copy datagram data into fragment buffer */ + CopyPacketToBuffer(Fragment->Data, + IPPacket->NdisPacket, + IPPacket->Position, + Fragment->Size); + Fragment->Offset = FragFirst; + + /* If this is the last fragment, compute and save the datagram data size */ + if (!MoreFragments) + IPDR->DataSize = FragFirst + Fragment->Size; + + /* Put the fragment in the list */ + InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry); + break; + } + + TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n")); + + if (IsListEmpty(&IPDR->HoleListHead)) { + /* Hole list is empty which means a complete datagram can be assembled. + Assemble the datagram and pass it to an upper layer protocol */ + + TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n")); + + Datagram = ReassembleDatagram(IPDR); + KeReleaseSpinLock(&IPDR->Lock, OldIrql); + + RemoveIPDR(IPDR); + FreeIPDR(IPDR); + + if (!Datagram) { + /* Not enough free resources, discard the packet */ + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return; + } + + /* Give the packet to the protocol dispatcher */ + IPDispatchProtocol(NTE, Datagram); + + /* We're done with this datagram */ + ExFreePool(Datagram->Header); + PoolFreeBuffer(Datagram); + } else + KeReleaseSpinLock(&IPDR->Lock, OldIrql); +} + + +VOID IPFreeReassemblyList( + VOID) +/* + * FUNCTION: Frees all IP datagram reassembly structures in the list + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PIPDATAGRAM_REASSEMBLY Current; + + KeAcquireSpinLock(&ReassemblyListLock, &OldIrql); + + CurrentEntry = ReassemblyListHead.Flink; + while (CurrentEntry != &ReassemblyListHead) { + Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry); + /* Unlink it from the list */ + RemoveEntryList(CurrentEntry); + + /* And free the descriptor */ + FreeIPDR(Current); + + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&ReassemblyListLock, OldIrql); +} + + +VOID IPDatagramReassemblyTimeout( + VOID) +/* + * FUNCTION: IP datagram reassembly timeout handler + * NOTES: + * This routine is called by IPTimeout to free any resources used + * to hold IP fragments that are being reassembled to form a + * complete IP datagram + */ +{ +} + + +VOID IPv4Receive( + PVOID Context, + PIP_PACKET IPPacket) +/* + * FUNCTION: Receives an IPv4 datagram (or fragment) + * ARGUMENTS: + * Context = Pointer to context information (IP_INTERFACE) + * IPPacket = Pointer to IP packet + */ +{ +// PNEIGHBOR_CACHE_ENTRY NCE; + PNET_TABLE_ENTRY NTE; + UINT AddressType; + + TI_DbgPrint(MAX_TRACE, ("Received IPv4 datagram.\n")); + + IPPacket->HeaderSize = (((PIPv4_HEADER)IPPacket->Header)->VerIHL & 0x0F) << 2; + + if (IPPacket->HeaderSize > IPv4_MAX_HEADER_SIZE) { + TI_DbgPrint(MIN_TRACE, ("Datagram received with incorrect header size (%d).\n", + IPPacket->HeaderSize)); + /* Discard packet */ + return; + } + + /* Checksum IPv4 header */ + if (!CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) { + TI_DbgPrint(MIN_TRACE, ("Datagram received with bad checksum. Checksum field (0x%X)\n", + WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum))); + /* Discard packet */ + return; + } + + TI_DbgPrint(MAX_TRACE, ("TotalSize (datalink) is (%d).\n", IPPacket->TotalSize)); + + IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength); + + TI_DbgPrint(MAX_TRACE, ("TotalSize (IPv4) is (%d).\n", IPPacket->TotalSize)); + + AddrInitIPv4(&IPPacket->SrcAddr, ((PIPv4_HEADER)IPPacket->Header)->SrcAddr); + AddrInitIPv4(&IPPacket->DstAddr, ((PIPv4_HEADER)IPPacket->Header)->DstAddr); + + IPPacket->Position = IPPacket->HeaderSize; + IPPacket->Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPPacket->HeaderSize); + + /* FIXME: Possibly forward packets with multicast addresses */ + + /* FIXME: Should we allow packets to be received on the wrong interface? */ +#if 0 + NTE = IPLocateNTE(&IPPacket->DstAddr, &AddressType); +#else + NTE = IPLocateNTEOnInterface((PIP_INTERFACE)Context, &IPPacket->DstAddr, &AddressType); +#endif + if (NTE) { + /* This packet is destined for us */ + ProcessFragment((PIP_INTERFACE)Context, IPPacket, NTE); + /* Done with this NTE */ + DereferenceObject(NTE); + } else { + /* This packet is not destined for us. If we are a router, + try to find a route and forward the packet */ + + /* FIXME: Check if acting as a router */ +#if 0 + NCE = RouteFindRouter(&IPPacket->DstAddr, NULL); + if (NCE) { + /* FIXME: Possibly fragment datagram */ + /* Forward the packet */ + IPSendFragment(IPPacket, NCE); + } else { + TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n", + IPPacket->DstAddr.Address.IPv4Address)); + + /* FIXME: Send ICMP error code */ + } +#endif + } +} + + +VOID IPReceive( + PVOID Context, + PIP_PACKET IPPacket) +/* + * FUNCTION: Receives an IP datagram (or fragment) + * ARGUMENTS: + * Context = Pointer to context information (IP_INTERFACE) + * IPPacket = Pointer to IP packet + */ +{ + UINT Version; + + /* Check that IP header has a supported version */ + Version = (((PIPv4_HEADER)IPPacket->Header)->VerIHL >> 4); + switch (Version) { + case 4: + IPPacket->Type = IP_ADDRESS_V4; + IPv4Receive(Context, IPPacket); + break; + case 6: + IPPacket->Type = IP_ADDRESS_V6; + TI_DbgPrint(MIN_TRACE, ("Datagram of type IPv6 discarded.\n")); + return; + default: + TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version)); + return; + } +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/network/route.c b/reactos/drivers/net/tcpip/network/route.c index f113b0b8917..89020f5a1b5 100644 --- a/reactos/drivers/net/tcpip/network/route.c +++ b/reactos/drivers/net/tcpip/network/route.c @@ -1,665 +1,665 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: network/route.c - * PURPOSE: Route cache - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * NOTES: The route cache is implemented as a binary search - * tree to obtain fast searches - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include - - -/* This RCN is shared by all external nodes. It complicates things, - but the memory.requirements are reduced by approximately 50%. - The RCN is protected by the route cache spin lock */ -PROUTE_CACHE_NODE ExternalRCN; -PROUTE_CACHE_NODE RouteCache; -KSPIN_LOCK RouteCacheLock; - - -#if DBG -VOID PrintTree( - PROUTE_CACHE_NODE Node) -/* - * FUNCTION: Prints all nodes on tree - * ARGUMENTS: - * Node = Pointer to root node of tree - * NOTES: - * This function must be called with the route cache lock held. - */ -{ - if (IsInternalRCN(Node)) { - /* Traverse left subtree */ - PrintTree(Node->Left); - - /* Traverse right subtree */ - PrintTree(Node->Right); - - /* Finally check the node itself */ - TI_DbgPrint(MIN_TRACE, ("(Internal) Self,Parent,Left,Right,Data = (%08X, %08X, %08X, %08X, %08X).\n", - Node, Node->Parent, Node->Left, Node->Right, (ULONG_PTR)Node->Destination.Address.IPv4Address)); - } else - TI_DbgPrint(MIN_TRACE, ("(External) Self,Parent,Left,Right = (%08X, %08X, %08X, %08X).\n", - Node, Node->Parent, Node->Left, Node->Right)); -} -#endif - - -VOID RemoveAboveExternal(VOID) -/* - * FUNCTION: Removes the parent node of the selected external node from the route cache tree - * NOTES: - * This function must be called with the route cache lock held. - * ExternalRCN->Parent must be initialized - */ -{ - PROUTE_CACHE_NODE Parent; - PROUTE_CACHE_NODE Sibling; - - TI_DbgPrint(DEBUG_RCACHE, ("Called.\n")); - -#if 0 - TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n")); - PrintTree(RouteCache); -#endif - - Parent = ExternalRCN->Parent; - /* Find sibling of external node */ - if (ExternalRCN == Parent->Left) - Sibling = Parent->Right; - else - Sibling = Parent->Left; - - /* Replace parent node with sibling of external node */ - if (Parent != RouteCache) { - if (Parent->Parent->Left == Parent) - Parent->Parent->Left = Sibling; - else - Parent->Parent->Right = Sibling; - /* Give sibling a new parent */ - Sibling->Parent = Parent->Parent; - } else { - /* This is the root we're removing */ - RouteCache = Sibling; - Sibling->Parent = NULL; - } - - DereferenceObject(Parent); - -#if 0 - TI_DbgPrint(MIN_TRACE, ("Displaying tree (after).\n")); - PrintTree(RouteCache); -#endif -} - - -PROUTE_CACHE_NODE SearchRouteCache( - PIP_ADDRESS Destination, - PROUTE_CACHE_NODE Node) -/* - * FUNCTION: Searches route cache for a RCN for a destination address - * ARGUMENTS: - * Destination = Pointer to destination address (key) - * Node = Pointer to start route cache node - * NOTES: - * This function must be called with the route cache lock held - * RETURNS: - * Pointer to internal node if a matching node was found, or - * external node where it should be if none was found - */ -{ - INT Value; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X) Node (0x%X)\n", Destination, Node)); - - /* Is this an external node? */ - if (IsExternalRCN(Node)) - return Node; - - /* Is it this node we are looking for? */ - Value = AddrCompare(Destination, &Node->Destination); - if (Value == 0) - return Node; - - /* Traverse down the left subtree if the key is smaller than - the key of the node, otherwise traverse the right subtree */ - if (Value < 0) { - Node->Left->Parent = Node; - ExternalRCN->Left = (PROUTE_CACHE_NODE)&Node->Left; - return SearchRouteCache(Destination, Node->Left); - } else { - Node->Right->Parent = Node; - ExternalRCN->Left = (PROUTE_CACHE_NODE)&Node->Right; - return SearchRouteCache(Destination, Node->Right); - } -} - - -PROUTE_CACHE_NODE ExpandExternalRCN(VOID) -/* - * FUNCTION: Expands an external route cache node - * NOTES: - * This function must be called with the route cache lock held. - * We cheat a little here to save memory. We don't actually allocate memory - * for external nodes. We wait until they're turned into internal nodes. - * ExternalRCN->Parent must be initialized - * ExternalRCN->Left must be a pointer to the correct child link of it's parent - * RETURNS: - * Pointer to new internal node if the external node was expanded, NULL if not - */ -{ - PROUTE_CACHE_NODE RCN; - - TI_DbgPrint(DEBUG_RCACHE, ("Called.\n")); - - RCN = PoolAllocateBuffer(sizeof(ROUTE_CACHE_NODE)); - if (!RCN) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - if (ExternalRCN->Left) - /* Register RCN as a child with it's parent */ - *(PROUTE_CACHE_NODE*)ExternalRCN->Left = RCN; - - RCN->Parent = ExternalRCN->Parent; - RCN->Left = ExternalRCN; - RCN->Right = ExternalRCN; - - return RCN; -} - -#if 0 -VOID SwapRCN( - PROUTE_CACHE_NODE *Node1, - PROUTE_CACHE_NODE *Node2) -/* - * FUNCTION: Swaps two nodes - * ARGUMENTS: - * Node1 = Address of pointer to first node - * Node2 = Address of pointer to second node - */ -{ - PROUTE_CACHE_NODE Temp; - - Temp = *Node2; - *Node2 = *Node1; - *Node1 = Temp; -} -#endif - -/* - * FUNCTION: Removes a route to a destination - * ARGUMENTS: - * RCN = Pointer to route cache node to remove - * NOTES: - * Internal version. Route cache lock must be held - */ -VOID RemoveRouteToDestination( - PROUTE_CACHE_NODE RCN) -{ - PROUTE_CACHE_NODE RemNode, Parent, SwapNode; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. RCN (0x%X).\n", RCN)); - - if (IsExternalRCN(RCN->Left)) { - /* Left node is external */ - RemNode = RCN->Left; - RemNode->Parent = RCN; - } else if (IsExternalRCN(RCN->Right)) { - /* Right node is external */ - RemNode = RCN->Right; - RemNode->Parent = RCN; - } else { - /* The node has internal children */ -#if 0 - /* Normally we would replace - the item of RCN with the item of the leftmost external - node on the right subtree of RCN. This we cannot do here - because there may be references directly to that node. - Instead we swap pointer values (parent, left and right) - of the two nodes */ -#endif - RemNode = RCN->Right; - do { - Parent = RemNode; - RemNode = RemNode->Left; - } while (IsInternalRCN(RemNode)); - RemNode->Parent = Parent; - - SwapNode = RemNode->Parent; -#if 0 - if (RCN != RouteCache) { - /* Set SwapNode to be child of RCN's parent instead of RCN */ - Parent = RCN->Parent; - if (RCN == Parent->Left) - Parent->Left = SwapNode; - else - Parent->Right = SwapNode; - } else - /* SwapNode is the new cache root */ - RouteCache = SwapNode; - - /* Set RCN to be child of SwapNode's parent instead of SwapNode */ - Parent = SwapNode->Parent; - if (SwapNode == Parent->Left) - Parent->Left = RCN; - else - Parent->Right = RCN; - - /* Swap parents */ - SwapRCN(&SwapNode->Parent, &RCN->Parent); - /* Swap children */ - SwapRCN(&SwapNode->Left, &RCN->Left); - SwapRCN(&SwapNode->Right, &RCN->Right); -#endif - } - - /* Dereference NTE and NCE */ - DereferenceObject(RCN->NTE); - DereferenceObject(RCN->NCE); - - ExternalRCN->Parent = RemNode->Parent; - - RemoveAboveExternal(); -} - - -VOID InvalidateNTEOnSubtree( - PNET_TABLE_ENTRY NTE, - PROUTE_CACHE_NODE Node) -/* - * FUNCTION: Removes all RCNs with references to an NTE on a subtree - * ARGUMENNTS: - * NTE = Pointer to NTE to invalidate - * Node = Pointer to RCN to start removing nodes at - * NOTES: - * This function must be called with the route cache lock held. - */ -{ - TI_DbgPrint(DEBUG_RCACHE, ("Called. NTE (0x%X) Node (0x%X).\n", NTE, Node)); - - if (IsInternalRCN(Node)) { - /* Traverse left subtree */ - InvalidateNTEOnSubtree(NTE, Node->Left); - - /* Traverse right subtree */ - InvalidateNTEOnSubtree(NTE, Node->Right); - - /* Finally check the node itself */ - if (Node->NTE == NTE) - RemoveRouteToDestination(Node); - } -} - - -VOID InvalidateNCEOnSubtree( - PNEIGHBOR_CACHE_ENTRY NCE, - PROUTE_CACHE_NODE Node) -/* - * FUNCTION: Removes all RCNs with references to an NCE on a subtree - * ARGUMENNTS: - * NCE = Pointer to NCE to invalidate - * Node = Pointer to RCN to start removing nodes at - * NOTES: - * This function must be called with the route cache lock held - */ -{ - TI_DbgPrint(DEBUG_RCACHE, ("Called. NCE (0x%X) Node (0x%X).\n", NCE, Node)); - - if (IsInternalRCN(Node)) { - /* Traverse left subtree */ - InvalidateNCEOnSubtree(NCE, Node->Left); - - /* Traverse right subtree */ - InvalidateNCEOnSubtree(NCE, Node->Right); - - /* Finally check the node itself */ - if (Node->NCE == NCE) - RemoveRouteToDestination(Node); - } -} - - -VOID RemoveSubtree( - PROUTE_CACHE_NODE Node) -/* - * FUNCTION: Removes a subtree from the tree using recursion - * ARGUMENNTS: - * Node = Pointer to RCN to start removing nodes at - * NOTES: - * This function must be called with the route cache lock held - */ -{ - TI_DbgPrint(DEBUG_RCACHE, ("Called. Node (0x%X).\n", Node)); - - if (IsInternalRCN(Node)) { - /* Traverse left subtree */ - RemoveSubtree(Node->Left); - - /* Traverse right subtree */ - RemoveSubtree(Node->Right); - - /* Finally remove the node itself */ - - /* It's an internal node, so dereference NTE and NCE */ - DereferenceObject(Node->NTE); - DereferenceObject(Node->NCE); - -#if DBG - if (Node->RefCount != 1) - TI_DbgPrint(MIN_TRACE, ("RCN at (0x%X) has (%d) references (should be 1).\n", Node, Node->RefCount)); -#endif - - /* Remove reference for being alive */ - DereferenceObject(Node); - } -} - - -NTSTATUS RouteStartup( - VOID) -/* - * FUNCTION: Initializes the routing subsystem - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_RCACHE, ("Called.\n")); - - /* Initialize the pseudo external route cache node */ - ExternalRCN = PoolAllocateBuffer(sizeof(ROUTE_CACHE_NODE)); - if (!ExternalRCN) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return STATUS_INSUFFICIENT_RESOURCES; - } - ExternalRCN->Parent = NULL; - ExternalRCN->Left = NULL; - ExternalRCN->Right = NULL; - - /* Initialize the route cache root */ - RouteCache = ExternalRCN; - - KeInitializeSpinLock(&RouteCacheLock); - -#if 0 - TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n")); - PrintTree(RouteCache); -#endif - return STATUS_SUCCESS; -} - - -NTSTATUS RouteShutdown( - VOID) -/* - * FUNCTION: Shuts down the routing subsystem - * RETURNS: - * Status of operation - */ -{ - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_RCACHE, ("Called.\n")); - - KeAcquireSpinLock(&RouteCacheLock, &OldIrql); -#if 0 - TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n")); - PrintTree(RouteCache); -#endif - /* Clear route cache */ - RemoveSubtree(RouteCache); - - PoolFreeBuffer(ExternalRCN); - - KeReleaseSpinLock(&RouteCacheLock, OldIrql); - - return STATUS_SUCCESS; -} - - -UINT RouteGetRouteToDestination( - PIP_ADDRESS Destination, - PNET_TABLE_ENTRY NTE, - PROUTE_CACHE_NODE *RCN) -/* - * FUNCTION: Locates an RCN describing a route to a destination address - * ARGUMENTS: - * Destination = Pointer to destination address to find route to - * NTE = Pointer to NTE describing net to send on - * (NULL means routing module choose NTE to send on) - * RCN = Address of pointer to an RCN - * RETURNS: - * Status of operation - * NOTES: - * The RCN is referenced for the caller. The caller is responsible - * for dereferencing it after use - */ -{ - KIRQL OldIrql; - PROUTE_CACHE_NODE RCN2; - PNEIGHBOR_CACHE_ENTRY NCE; - PIP_INTERFACE Interface; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X) NTE (0x%X).\n", Destination, NTE)); - - KeAcquireSpinLock(&RouteCacheLock, &OldIrql); - -#if 0 - TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n")); - PrintTree(RouteCache); -#endif - - ExternalRCN->Left = NULL; - RCN2 = SearchRouteCache(Destination, RouteCache); - if (IsExternalRCN(RCN2)) { - /* No route was found in the cache */ - - /* Check if the destination is on-link */ - Interface = RouterFindOnLinkInterface(Destination, NTE); - if (Interface) { - if (!NTE) { - NTE = RouterFindBestNTE(Interface, Destination); - if (!NTE) { - /* We cannot get to the specified destination. Return error */ - KeReleaseSpinLock(&RouteCacheLock, OldIrql); - return IP_NO_ROUTE_TO_DESTINATION; - } - } else - ReferenceObject(NTE); - - /* The destination address is on-link. Check our neighbor cache */ - NCE = NBFindOrCreateNeighbor(Interface, Destination); - if (!NCE) { - DereferenceObject(NTE); - KeReleaseSpinLock(&RouteCacheLock, OldIrql); - return IP_NO_RESOURCES; - } - } else { - /* Destination is not on any subnets we're on. Find a router to use */ - NCE = RouterGetRoute(Destination, NTE); - if (!NCE) { - /* We cannot get to the specified destination. Return error */ - KeReleaseSpinLock(&RouteCacheLock, OldIrql); - return IP_NO_ROUTE_TO_DESTINATION; - } - } - - /* Add the new route to the route cache */ - if (RCN2 == RouteCache) { - RCN2 = ExpandExternalRCN(); - RouteCache = RCN2; - } else - RCN2 = ExpandExternalRCN(); - if (!RCN2) { - DereferenceObject(NTE); - DereferenceObject(NCE); - KeReleaseSpinLock(&RouteCacheLock, OldIrql); - return IP_NO_RESOURCES; - } - - RCN2->RefCount = 1; - RCN2->State = RCN_STATE_COMPUTED; - RCN2->NTE = NTE; - RtlCopyMemory(&RCN2->Destination, Destination, sizeof(IP_ADDRESS)); - RCN2->PathMTU = NCE->Interface->MTU; - RCN2->NCE = NCE; - - /* The route cache node references the NTE and the NCE. The - NTE was referenced before and NCE is already referenced by - RouteGetRoute() or NBFindOrCreateNeighbor() so we don't - reference them here */ - } - - /* Reference the RCN for the user */ - ReferenceObject(RCN2); - -#if 0 - TI_DbgPrint(MIN_TRACE, ("Displaying tree (after).\n")); - PrintTree(RouteCache); -#endif - - KeReleaseSpinLock(&RouteCacheLock, OldIrql); - - *RCN = RCN2; - - return IP_SUCCESS; -} - - -PROUTE_CACHE_NODE RouteAddRouteToDestination( - PIP_ADDRESS Destination, - PNET_TABLE_ENTRY NTE, - PIP_INTERFACE IF, - PNEIGHBOR_CACHE_ENTRY NCE) -/* - * FUNCTION: Adds a (permanent) route to a destination - * ARGUMENTS: - * Destination = Pointer to destination address - * NTE = Pointer to net table entry - * IF = Pointer to interface to use - * NCE = Pointer to first hop to destination - * RETURNS: - * Pointer to RCN if the route was added, NULL if not. - * There can be at most one RCN per destination address / interface pair - */ -{ - KIRQL OldIrql; - PROUTE_CACHE_NODE RCN; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X) NTE (0x%X) IF (0x%X) NCE (0x%X).\n", Destination, NTE, IF, NCE)); - - KeAcquireSpinLock(&RouteCacheLock, &OldIrql); - - /* Locate an external RCN we can expand */ - RCN = RouteCache; - ExternalRCN->Left = NULL; - for (;;) { - RCN = SearchRouteCache(Destination, RCN); - if (IsInternalRCN(RCN)) { - ExternalRCN->Left = (PROUTE_CACHE_NODE)&RCN->Right; - /* This is an internal node, continue the search to the right */ - RCN = RCN->Right; - } else - /* This is an external node, we've found an empty spot */ - break; - } - - /* Expand the external node */ - if (RCN == RouteCache) { - RCN = ExpandExternalRCN(); - RouteCache = RCN; - } else - RCN = ExpandExternalRCN(); - if (!RCN) { - KeReleaseSpinLock(&RouteCacheLock, OldIrql); - return NULL; - } - - /* Initialize the newly created internal node */ - - /* Reference once for beeing alive */ - RCN->RefCount = 1; - RCN->State = RCN_STATE_PERMANENT; - RCN->NTE = NTE; - RtlCopyMemory(&RCN->Destination, Destination, sizeof(IP_ADDRESS)); - RCN->PathMTU = IF->MTU; - RCN->NCE = NCE; - - KeReleaseSpinLock(&RouteCacheLock, OldIrql); - - /* The route cache node references the NTE and the NCE */ - ReferenceObject(NTE); - if (NCE) - ReferenceObject(NCE); - -#if 0 - TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n")); - PrintTree(RouteCache); -#endif - - return RCN; -} - - -VOID RouteRemoveRouteToDestination( - PROUTE_CACHE_NODE RCN) -/* - * FUNCTION: Removes a route to a destination - * ARGUMENTS: - * RCN = Pointer to route cache node to remove - */ -{ - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. RCN (0x%X).\n", RCN)); - - KeAcquireSpinLock(&RouteCacheLock, &OldIrql); - - RemoveRouteToDestination(RCN); - - KeReleaseSpinLock(&RouteCacheLock, OldIrql); -} - - -VOID RouteInvalidateNTE( - PNET_TABLE_ENTRY NTE) -/* - * FUNCTION: Removes all RCNs with references to an NTE - * ARGUMENTS: - * NTE = Pointer to net table entry to invalidate - */ -{ - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. NTE (0x%X).\n", NTE)); - - KeAcquireSpinLock(&RouteCacheLock, &OldIrql); - InvalidateNTEOnSubtree(NTE, RouteCache); - KeReleaseSpinLock(&RouteCacheLock, OldIrql); -} - - -VOID RouteInvalidateNCE( - PNEIGHBOR_CACHE_ENTRY NCE) -/* - * FUNCTION: Removes all RCNs with references to an NCE - * ARGUMENTS: - * NCE = Pointer to neighbor cache entry to invalidate - */ -{ - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. NCE (0x%X).\n", NCE)); - - KeAcquireSpinLock(&RouteCacheLock, &OldIrql); - InvalidateNCEOnSubtree(NCE, RouteCache); - KeReleaseSpinLock(&RouteCacheLock, OldIrql); -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: network/route.c + * PURPOSE: Route cache + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * NOTES: The route cache is implemented as a binary search + * tree to obtain fast searches + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include + + +/* This RCN is shared by all external nodes. It complicates things, + but the memory.requirements are reduced by approximately 50%. + The RCN is protected by the route cache spin lock */ +PROUTE_CACHE_NODE ExternalRCN; +PROUTE_CACHE_NODE RouteCache; +KSPIN_LOCK RouteCacheLock; + + +#if DBG +VOID PrintTree( + PROUTE_CACHE_NODE Node) +/* + * FUNCTION: Prints all nodes on tree + * ARGUMENTS: + * Node = Pointer to root node of tree + * NOTES: + * This function must be called with the route cache lock held. + */ +{ + if (IsInternalRCN(Node)) { + /* Traverse left subtree */ + PrintTree(Node->Left); + + /* Traverse right subtree */ + PrintTree(Node->Right); + + /* Finally check the node itself */ + TI_DbgPrint(MIN_TRACE, ("(Internal) Self,Parent,Left,Right,Data = (%08X, %08X, %08X, %08X, %08X).\n", + Node, Node->Parent, Node->Left, Node->Right, (ULONG_PTR)Node->Destination.Address.IPv4Address)); + } else + TI_DbgPrint(MIN_TRACE, ("(External) Self,Parent,Left,Right = (%08X, %08X, %08X, %08X).\n", + Node, Node->Parent, Node->Left, Node->Right)); +} +#endif + + +VOID RemoveAboveExternal(VOID) +/* + * FUNCTION: Removes the parent node of the selected external node from the route cache tree + * NOTES: + * This function must be called with the route cache lock held. + * ExternalRCN->Parent must be initialized + */ +{ + PROUTE_CACHE_NODE Parent; + PROUTE_CACHE_NODE Sibling; + + TI_DbgPrint(DEBUG_RCACHE, ("Called.\n")); + +#if 0 + TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n")); + PrintTree(RouteCache); +#endif + + Parent = ExternalRCN->Parent; + /* Find sibling of external node */ + if (ExternalRCN == Parent->Left) + Sibling = Parent->Right; + else + Sibling = Parent->Left; + + /* Replace parent node with sibling of external node */ + if (Parent != RouteCache) { + if (Parent->Parent->Left == Parent) + Parent->Parent->Left = Sibling; + else + Parent->Parent->Right = Sibling; + /* Give sibling a new parent */ + Sibling->Parent = Parent->Parent; + } else { + /* This is the root we're removing */ + RouteCache = Sibling; + Sibling->Parent = NULL; + } + + DereferenceObject(Parent); + +#if 0 + TI_DbgPrint(MIN_TRACE, ("Displaying tree (after).\n")); + PrintTree(RouteCache); +#endif +} + + +PROUTE_CACHE_NODE SearchRouteCache( + PIP_ADDRESS Destination, + PROUTE_CACHE_NODE Node) +/* + * FUNCTION: Searches route cache for a RCN for a destination address + * ARGUMENTS: + * Destination = Pointer to destination address (key) + * Node = Pointer to start route cache node + * NOTES: + * This function must be called with the route cache lock held + * RETURNS: + * Pointer to internal node if a matching node was found, or + * external node where it should be if none was found + */ +{ + INT Value; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X) Node (0x%X)\n", Destination, Node)); + + /* Is this an external node? */ + if (IsExternalRCN(Node)) + return Node; + + /* Is it this node we are looking for? */ + Value = AddrCompare(Destination, &Node->Destination); + if (Value == 0) + return Node; + + /* Traverse down the left subtree if the key is smaller than + the key of the node, otherwise traverse the right subtree */ + if (Value < 0) { + Node->Left->Parent = Node; + ExternalRCN->Left = (PROUTE_CACHE_NODE)&Node->Left; + return SearchRouteCache(Destination, Node->Left); + } else { + Node->Right->Parent = Node; + ExternalRCN->Left = (PROUTE_CACHE_NODE)&Node->Right; + return SearchRouteCache(Destination, Node->Right); + } +} + + +PROUTE_CACHE_NODE ExpandExternalRCN(VOID) +/* + * FUNCTION: Expands an external route cache node + * NOTES: + * This function must be called with the route cache lock held. + * We cheat a little here to save memory. We don't actually allocate memory + * for external nodes. We wait until they're turned into internal nodes. + * ExternalRCN->Parent must be initialized + * ExternalRCN->Left must be a pointer to the correct child link of it's parent + * RETURNS: + * Pointer to new internal node if the external node was expanded, NULL if not + */ +{ + PROUTE_CACHE_NODE RCN; + + TI_DbgPrint(DEBUG_RCACHE, ("Called.\n")); + + RCN = PoolAllocateBuffer(sizeof(ROUTE_CACHE_NODE)); + if (!RCN) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + if (ExternalRCN->Left) + /* Register RCN as a child with it's parent */ + *(PROUTE_CACHE_NODE*)ExternalRCN->Left = RCN; + + RCN->Parent = ExternalRCN->Parent; + RCN->Left = ExternalRCN; + RCN->Right = ExternalRCN; + + return RCN; +} + +#if 0 +VOID SwapRCN( + PROUTE_CACHE_NODE *Node1, + PROUTE_CACHE_NODE *Node2) +/* + * FUNCTION: Swaps two nodes + * ARGUMENTS: + * Node1 = Address of pointer to first node + * Node2 = Address of pointer to second node + */ +{ + PROUTE_CACHE_NODE Temp; + + Temp = *Node2; + *Node2 = *Node1; + *Node1 = Temp; +} +#endif + +/* + * FUNCTION: Removes a route to a destination + * ARGUMENTS: + * RCN = Pointer to route cache node to remove + * NOTES: + * Internal version. Route cache lock must be held + */ +VOID RemoveRouteToDestination( + PROUTE_CACHE_NODE RCN) +{ + PROUTE_CACHE_NODE RemNode, Parent, SwapNode; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. RCN (0x%X).\n", RCN)); + + if (IsExternalRCN(RCN->Left)) { + /* Left node is external */ + RemNode = RCN->Left; + RemNode->Parent = RCN; + } else if (IsExternalRCN(RCN->Right)) { + /* Right node is external */ + RemNode = RCN->Right; + RemNode->Parent = RCN; + } else { + /* The node has internal children */ +#if 0 + /* Normally we would replace + the item of RCN with the item of the leftmost external + node on the right subtree of RCN. This we cannot do here + because there may be references directly to that node. + Instead we swap pointer values (parent, left and right) + of the two nodes */ +#endif + RemNode = RCN->Right; + do { + Parent = RemNode; + RemNode = RemNode->Left; + } while (IsInternalRCN(RemNode)); + RemNode->Parent = Parent; + + SwapNode = RemNode->Parent; +#if 0 + if (RCN != RouteCache) { + /* Set SwapNode to be child of RCN's parent instead of RCN */ + Parent = RCN->Parent; + if (RCN == Parent->Left) + Parent->Left = SwapNode; + else + Parent->Right = SwapNode; + } else + /* SwapNode is the new cache root */ + RouteCache = SwapNode; + + /* Set RCN to be child of SwapNode's parent instead of SwapNode */ + Parent = SwapNode->Parent; + if (SwapNode == Parent->Left) + Parent->Left = RCN; + else + Parent->Right = RCN; + + /* Swap parents */ + SwapRCN(&SwapNode->Parent, &RCN->Parent); + /* Swap children */ + SwapRCN(&SwapNode->Left, &RCN->Left); + SwapRCN(&SwapNode->Right, &RCN->Right); +#endif + } + + /* Dereference NTE and NCE */ + DereferenceObject(RCN->NTE); + DereferenceObject(RCN->NCE); + + ExternalRCN->Parent = RemNode->Parent; + + RemoveAboveExternal(); +} + + +VOID InvalidateNTEOnSubtree( + PNET_TABLE_ENTRY NTE, + PROUTE_CACHE_NODE Node) +/* + * FUNCTION: Removes all RCNs with references to an NTE on a subtree + * ARGUMENNTS: + * NTE = Pointer to NTE to invalidate + * Node = Pointer to RCN to start removing nodes at + * NOTES: + * This function must be called with the route cache lock held. + */ +{ + TI_DbgPrint(DEBUG_RCACHE, ("Called. NTE (0x%X) Node (0x%X).\n", NTE, Node)); + + if (IsInternalRCN(Node)) { + /* Traverse left subtree */ + InvalidateNTEOnSubtree(NTE, Node->Left); + + /* Traverse right subtree */ + InvalidateNTEOnSubtree(NTE, Node->Right); + + /* Finally check the node itself */ + if (Node->NTE == NTE) + RemoveRouteToDestination(Node); + } +} + + +VOID InvalidateNCEOnSubtree( + PNEIGHBOR_CACHE_ENTRY NCE, + PROUTE_CACHE_NODE Node) +/* + * FUNCTION: Removes all RCNs with references to an NCE on a subtree + * ARGUMENNTS: + * NCE = Pointer to NCE to invalidate + * Node = Pointer to RCN to start removing nodes at + * NOTES: + * This function must be called with the route cache lock held + */ +{ + TI_DbgPrint(DEBUG_RCACHE, ("Called. NCE (0x%X) Node (0x%X).\n", NCE, Node)); + + if (IsInternalRCN(Node)) { + /* Traverse left subtree */ + InvalidateNCEOnSubtree(NCE, Node->Left); + + /* Traverse right subtree */ + InvalidateNCEOnSubtree(NCE, Node->Right); + + /* Finally check the node itself */ + if (Node->NCE == NCE) + RemoveRouteToDestination(Node); + } +} + + +VOID RemoveSubtree( + PROUTE_CACHE_NODE Node) +/* + * FUNCTION: Removes a subtree from the tree using recursion + * ARGUMENNTS: + * Node = Pointer to RCN to start removing nodes at + * NOTES: + * This function must be called with the route cache lock held + */ +{ + TI_DbgPrint(DEBUG_RCACHE, ("Called. Node (0x%X).\n", Node)); + + if (IsInternalRCN(Node)) { + /* Traverse left subtree */ + RemoveSubtree(Node->Left); + + /* Traverse right subtree */ + RemoveSubtree(Node->Right); + + /* Finally remove the node itself */ + + /* It's an internal node, so dereference NTE and NCE */ + DereferenceObject(Node->NTE); + DereferenceObject(Node->NCE); + +#if DBG + if (Node->RefCount != 1) + TI_DbgPrint(MIN_TRACE, ("RCN at (0x%X) has (%d) references (should be 1).\n", Node, Node->RefCount)); +#endif + + /* Remove reference for being alive */ + DereferenceObject(Node); + } +} + + +NTSTATUS RouteStartup( + VOID) +/* + * FUNCTION: Initializes the routing subsystem + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_RCACHE, ("Called.\n")); + + /* Initialize the pseudo external route cache node */ + ExternalRCN = PoolAllocateBuffer(sizeof(ROUTE_CACHE_NODE)); + if (!ExternalRCN) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + ExternalRCN->Parent = NULL; + ExternalRCN->Left = NULL; + ExternalRCN->Right = NULL; + + /* Initialize the route cache root */ + RouteCache = ExternalRCN; + + KeInitializeSpinLock(&RouteCacheLock); + +#if 0 + TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n")); + PrintTree(RouteCache); +#endif + return STATUS_SUCCESS; +} + + +NTSTATUS RouteShutdown( + VOID) +/* + * FUNCTION: Shuts down the routing subsystem + * RETURNS: + * Status of operation + */ +{ + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_RCACHE, ("Called.\n")); + + KeAcquireSpinLock(&RouteCacheLock, &OldIrql); +#if 0 + TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n")); + PrintTree(RouteCache); +#endif + /* Clear route cache */ + RemoveSubtree(RouteCache); + + PoolFreeBuffer(ExternalRCN); + + KeReleaseSpinLock(&RouteCacheLock, OldIrql); + + return STATUS_SUCCESS; +} + + +UINT RouteGetRouteToDestination( + PIP_ADDRESS Destination, + PNET_TABLE_ENTRY NTE, + PROUTE_CACHE_NODE *RCN) +/* + * FUNCTION: Locates an RCN describing a route to a destination address + * ARGUMENTS: + * Destination = Pointer to destination address to find route to + * NTE = Pointer to NTE describing net to send on + * (NULL means routing module choose NTE to send on) + * RCN = Address of pointer to an RCN + * RETURNS: + * Status of operation + * NOTES: + * The RCN is referenced for the caller. The caller is responsible + * for dereferencing it after use + */ +{ + KIRQL OldIrql; + PROUTE_CACHE_NODE RCN2; + PNEIGHBOR_CACHE_ENTRY NCE; + PIP_INTERFACE Interface; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X) NTE (0x%X).\n", Destination, NTE)); + + KeAcquireSpinLock(&RouteCacheLock, &OldIrql); + +#if 0 + TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n")); + PrintTree(RouteCache); +#endif + + ExternalRCN->Left = NULL; + RCN2 = SearchRouteCache(Destination, RouteCache); + if (IsExternalRCN(RCN2)) { + /* No route was found in the cache */ + + /* Check if the destination is on-link */ + Interface = RouterFindOnLinkInterface(Destination, NTE); + if (Interface) { + if (!NTE) { + NTE = RouterFindBestNTE(Interface, Destination); + if (!NTE) { + /* We cannot get to the specified destination. Return error */ + KeReleaseSpinLock(&RouteCacheLock, OldIrql); + return IP_NO_ROUTE_TO_DESTINATION; + } + } else + ReferenceObject(NTE); + + /* The destination address is on-link. Check our neighbor cache */ + NCE = NBFindOrCreateNeighbor(Interface, Destination); + if (!NCE) { + DereferenceObject(NTE); + KeReleaseSpinLock(&RouteCacheLock, OldIrql); + return IP_NO_RESOURCES; + } + } else { + /* Destination is not on any subnets we're on. Find a router to use */ + NCE = RouterGetRoute(Destination, NTE); + if (!NCE) { + /* We cannot get to the specified destination. Return error */ + KeReleaseSpinLock(&RouteCacheLock, OldIrql); + return IP_NO_ROUTE_TO_DESTINATION; + } + } + + /* Add the new route to the route cache */ + if (RCN2 == RouteCache) { + RCN2 = ExpandExternalRCN(); + RouteCache = RCN2; + } else + RCN2 = ExpandExternalRCN(); + if (!RCN2) { + DereferenceObject(NTE); + DereferenceObject(NCE); + KeReleaseSpinLock(&RouteCacheLock, OldIrql); + return IP_NO_RESOURCES; + } + + RCN2->RefCount = 1; + RCN2->State = RCN_STATE_COMPUTED; + RCN2->NTE = NTE; + RtlCopyMemory(&RCN2->Destination, Destination, sizeof(IP_ADDRESS)); + RCN2->PathMTU = NCE->Interface->MTU; + RCN2->NCE = NCE; + + /* The route cache node references the NTE and the NCE. The + NTE was referenced before and NCE is already referenced by + RouteGetRoute() or NBFindOrCreateNeighbor() so we don't + reference them here */ + } + + /* Reference the RCN for the user */ + ReferenceObject(RCN2); + +#if 0 + TI_DbgPrint(MIN_TRACE, ("Displaying tree (after).\n")); + PrintTree(RouteCache); +#endif + + KeReleaseSpinLock(&RouteCacheLock, OldIrql); + + *RCN = RCN2; + + return IP_SUCCESS; +} + + +PROUTE_CACHE_NODE RouteAddRouteToDestination( + PIP_ADDRESS Destination, + PNET_TABLE_ENTRY NTE, + PIP_INTERFACE IF, + PNEIGHBOR_CACHE_ENTRY NCE) +/* + * FUNCTION: Adds a (permanent) route to a destination + * ARGUMENTS: + * Destination = Pointer to destination address + * NTE = Pointer to net table entry + * IF = Pointer to interface to use + * NCE = Pointer to first hop to destination + * RETURNS: + * Pointer to RCN if the route was added, NULL if not. + * There can be at most one RCN per destination address / interface pair + */ +{ + KIRQL OldIrql; + PROUTE_CACHE_NODE RCN; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X) NTE (0x%X) IF (0x%X) NCE (0x%X).\n", Destination, NTE, IF, NCE)); + + KeAcquireSpinLock(&RouteCacheLock, &OldIrql); + + /* Locate an external RCN we can expand */ + RCN = RouteCache; + ExternalRCN->Left = NULL; + for (;;) { + RCN = SearchRouteCache(Destination, RCN); + if (IsInternalRCN(RCN)) { + ExternalRCN->Left = (PROUTE_CACHE_NODE)&RCN->Right; + /* This is an internal node, continue the search to the right */ + RCN = RCN->Right; + } else + /* This is an external node, we've found an empty spot */ + break; + } + + /* Expand the external node */ + if (RCN == RouteCache) { + RCN = ExpandExternalRCN(); + RouteCache = RCN; + } else + RCN = ExpandExternalRCN(); + if (!RCN) { + KeReleaseSpinLock(&RouteCacheLock, OldIrql); + return NULL; + } + + /* Initialize the newly created internal node */ + + /* Reference once for beeing alive */ + RCN->RefCount = 1; + RCN->State = RCN_STATE_PERMANENT; + RCN->NTE = NTE; + RtlCopyMemory(&RCN->Destination, Destination, sizeof(IP_ADDRESS)); + RCN->PathMTU = IF->MTU; + RCN->NCE = NCE; + + KeReleaseSpinLock(&RouteCacheLock, OldIrql); + + /* The route cache node references the NTE and the NCE */ + ReferenceObject(NTE); + if (NCE) + ReferenceObject(NCE); + +#if 0 + TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n")); + PrintTree(RouteCache); +#endif + + return RCN; +} + + +VOID RouteRemoveRouteToDestination( + PROUTE_CACHE_NODE RCN) +/* + * FUNCTION: Removes a route to a destination + * ARGUMENTS: + * RCN = Pointer to route cache node to remove + */ +{ + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. RCN (0x%X).\n", RCN)); + + KeAcquireSpinLock(&RouteCacheLock, &OldIrql); + + RemoveRouteToDestination(RCN); + + KeReleaseSpinLock(&RouteCacheLock, OldIrql); +} + + +VOID RouteInvalidateNTE( + PNET_TABLE_ENTRY NTE) +/* + * FUNCTION: Removes all RCNs with references to an NTE + * ARGUMENTS: + * NTE = Pointer to net table entry to invalidate + */ +{ + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. NTE (0x%X).\n", NTE)); + + KeAcquireSpinLock(&RouteCacheLock, &OldIrql); + InvalidateNTEOnSubtree(NTE, RouteCache); + KeReleaseSpinLock(&RouteCacheLock, OldIrql); +} + + +VOID RouteInvalidateNCE( + PNEIGHBOR_CACHE_ENTRY NCE) +/* + * FUNCTION: Removes all RCNs with references to an NCE + * ARGUMENTS: + * NCE = Pointer to neighbor cache entry to invalidate + */ +{ + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. NCE (0x%X).\n", NCE)); + + KeAcquireSpinLock(&RouteCacheLock, &OldIrql); + InvalidateNCEOnSubtree(NCE, RouteCache); + KeReleaseSpinLock(&RouteCacheLock, OldIrql); +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/network/router.c b/reactos/drivers/net/tcpip/network/router.c index 1791dc40e9c..90da67993aa 100644 --- a/reactos/drivers/net/tcpip/network/router.c +++ b/reactos/drivers/net/tcpip/network/router.c @@ -1,500 +1,500 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: network/router.c - * PURPOSE: IP routing subsystem - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include - - -LIST_ENTRY FIBListHead; -KSPIN_LOCK FIBLock; - - -VOID DestroyFIBE( - PFIB_ENTRY FIBE) -/* - * FUNCTION: Destroys an forward information base entry - * ARGUMENTS: - * FIBE = Pointer to FIB entry - * NOTES: - * The forward information base lock must be held when called - */ -{ - /* Unlink the FIB entry from the list */ - RemoveEntryList(&FIBE->ListEntry); - - /* Dereference the referenced objects */ - DereferenceObject(FIBE->NetworkAddress); - DereferenceObject(FIBE->Netmask); - DereferenceObject(FIBE->Router); - DereferenceObject(FIBE->NTE); - -#ifdef DBG - FIBE->RefCount--; - - if (FIBE->RefCount != 0) { - TI_DbgPrint(MIN_TRACE, ("FIB entry at (0x%X) has (%d) references (Should be 0).\n", FIBE, FIBE->RefCount)); - } -#endif - - /* And free the FIB entry */ - PoolFreeBuffer(FIBE); -} - - -VOID DestroyFIBEs( - VOID) -/* - * FUNCTION: Destroys all forward information base entries - * NOTES: - * The forward information base lock must be held when called - */ -{ - PLIST_ENTRY CurrentEntry; - PLIST_ENTRY NextEntry; - PFIB_ENTRY Current; - - /* Search the list and remove every FIB entry we find */ - CurrentEntry = FIBListHead.Flink; - while (CurrentEntry != &FIBListHead) { - NextEntry = CurrentEntry->Flink; - Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); - /* Destroy the FIB entry */ - DestroyFIBE(Current); - CurrentEntry = NextEntry; - } -} - - -UINT CommonPrefixLength( - PIP_ADDRESS Address1, - PIP_ADDRESS Address2) -/* - * FUNCTION: Computes the length of the longest prefix common to two addresses - * ARGUMENTS: - * Address1 = Pointer to first address - * Address2 = Pointer to second address - * NOTES: - * The two addresses must be of the same type - * RETURNS: - * Length of longest common prefix - */ -{ - PUCHAR Addr1, Addr2; - UINT Size; - UINT i, j; - UINT Bitmask; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. Address1 (0x%X) Address2 (0x%X).\n", Address1, Address2)); - - if (Address1->Type == IP_ADDRESS_V4) - Size = sizeof(IPv4_RAW_ADDRESS); - else - Size = sizeof(IPv6_RAW_ADDRESS); - - Addr1 = (PUCHAR)&Address1->Address; - Addr2 = (PUCHAR)&Address2->Address; - - /* Find first non-matching byte */ - for (i = 0; ; i++) { - if (i == Size) - return 8 * i; /* The two addresses are equal */ - - if (Addr1[i] != Addr2[i]) - break; - } - - /* Find first non-matching bit */ - Bitmask = 0x80; - for (j = 0; ; j++) { - if ((Addr1[i] & Bitmask) != (Addr2[i] & Bitmask)) - break; - Bitmask >>= 1; - } - - return 8 * i + j; -} - - -BOOLEAN HasPrefix( - PIP_ADDRESS Address, - PIP_ADDRESS Prefix, - UINT Length) -/* - * FUNCTION: Determines wether an address has an given prefix - * ARGUMENTS: - * Address = Pointer to address to use - * Prefix = Pointer to prefix to check for - * Length = Length of prefix - * RETURNS: - * TRUE if the address has the prefix, FALSE if not - * NOTES: - * The two addresses must be of the same type - */ -{ - PUCHAR pAddress = (PUCHAR)&Address->Address; - PUCHAR pPrefix = (PUCHAR)&Prefix->Address; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. Address (0x%X) Prefix (0x%X) Length (%d).\n", Address, Prefix, Length)); - - /* Check that initial integral bytes match */ - while (Length > 8) { - if (*pAddress++ != *pPrefix++) - return FALSE; - Length -= 8; - } - - /* Check any remaining bits */ - if ((Length > 0) && ((*pAddress >> (8 - Length)) != (*pPrefix >> (8 - Length)))) - return FALSE; - - return TRUE; -} - - -PNET_TABLE_ENTRY RouterFindBestNTE( - PIP_INTERFACE Interface, - PIP_ADDRESS Destination) -/* - * FUNCTION: Checks all on-link prefixes to find out if an address is on-link - * ARGUMENTS: - * Interface = Pointer to interface to use - * Destination = Pointer to destination address - * NOTES: - * If found the NTE if referenced - * RETURNS: - * Pointer to NTE if found, NULL if not - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PNET_TABLE_ENTRY Current; - UINT Length, BestLength = 0; - PNET_TABLE_ENTRY BestNTE = NULL; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. Interface (0x%X) Destination (0x%X).\n", Interface, Destination)); - - KeAcquireSpinLock(&Interface->Lock, &OldIrql); - - CurrentEntry = Interface->NTEListHead.Flink; - while (CurrentEntry != &Interface->NTEListHead) { - Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); - - Length = CommonPrefixLength(Destination, Current->Address); - if (BestNTE) { - if (Length > BestLength) { - /* This seems to be a better NTE */ - DereferenceObject(BestNTE); - ReferenceObject(Current); - BestNTE = Current; - BestLength = Length; - } - } else { - /* First suitable NTE found, save it */ - ReferenceObject(Current); - BestNTE = Current; - BestLength = Length; - } - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&Interface->Lock, OldIrql); - - return BestNTE; -} - - -PIP_INTERFACE RouterFindOnLinkInterface( - PIP_ADDRESS Address, - PNET_TABLE_ENTRY NTE) -/* - * FUNCTION: Checks all on-link prefixes to find out if an address is on-link - * ARGUMENTS: - * Address = Pointer to address to check - * NTE = Pointer to NTE to check (NULL = check all interfaces) - * RETURNS: - * Pointer to interface if address is on-link, NULL if not - */ -{ - PLIST_ENTRY CurrentEntry; - PPREFIX_LIST_ENTRY Current; - - TI_DbgPrint(DEBUG_RCACHE, ("Called. Address (0x%X) NTE (0x%X).\n", Address, NTE)); - - CurrentEntry = PrefixListHead.Flink; - while (CurrentEntry != &PrefixListHead) { - Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry); - - if (HasPrefix(Address, Current->Prefix, Current->PrefixLength) && - ((!NTE) || (NTE->Interface == Current->Interface))) - return Current->Interface; - - CurrentEntry = CurrentEntry->Flink; - } - - return NULL; -} - - -PFIB_ENTRY RouterAddRoute( - PIP_ADDRESS NetworkAddress, - PIP_ADDRESS Netmask, - PNET_TABLE_ENTRY NTE, - PNEIGHBOR_CACHE_ENTRY Router, - UINT Metric) -/* - * FUNCTION: Adds a route to the Forward Information Base (FIB) - * ARGUMENTS: - * NetworkAddress = Pointer to address of network - * Netmask = Pointer to netmask of network - * NTE = Pointer to NTE to use - * Router = Pointer to NCE of router to use - * Metric = Cost of this route - * RETURNS: - * Pointer to FIB entry if the route was added, NULL if not - * NOTES: - * The FIB entry references the NetworkAddress, Netmask, NTE and - * the NCE of the router. The caller is responsible for providing - * these references - */ -{ - PFIB_ENTRY FIBE; - - TI_DbgPrint(DEBUG_ROUTER, ("Called. NetworkAddress (0x%X) Netmask (0x%X) NTE (0x%X) " - "Router (0x%X) Metric (%d).\n", NetworkAddress, Netmask, NTE, Router, Metric)); - - FIBE = PoolAllocateBuffer(sizeof(FIB_ENTRY)); - if (!FIBE) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - FIBE->NetworkAddress = NetworkAddress; - FIBE->Netmask = Netmask; - FIBE->NTE = NTE; - FIBE->Router = Router; - FIBE->Metric = Metric; - - /* Add FIB to the forward information base */ - ExInterlockedInsertTailList(&FIBListHead, &FIBE->ListEntry, &FIBLock); - - return FIBE; -} - - -PNEIGHBOR_CACHE_ENTRY RouterGetRoute( - PIP_ADDRESS Destination, - PNET_TABLE_ENTRY NTE) -/* - * FUNCTION: Finds a router to use to get to Destination - * ARGUMENTS: - * Destination = Pointer to destination address (NULL means don't care) - * NTE = Pointer to NTE describing net to send on - * (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; - PNEIGHBOR_CACHE_ENTRY NCE, BestNCE = NULL; - - TI_DbgPrint(DEBUG_ROUTER, ("Called. Destination (0x%X) NTE (0x%X).\n", Destination, NTE)); - - KeAcquireSpinLock(&FIBLock, &OldIrql); - - CurrentEntry = FIBListHead.Flink; - while (CurrentEntry != &FIBListHead) { - NextEntry = CurrentEntry->Flink; - Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); - - NCE = Current->Router; - State = NCE->State; - - if ((!NTE) || (NTE->Interface == NCE->Interface)) { - if (Destination) - Length = CommonPrefixLength(Destination, NCE->Address); - else - Length = 0; - - if (BestNCE) { - if ((State > BestState) || - ((State == BestState) && - (Length > BestLength))) { - /* This seems to be a better router */ - DereferenceObject(BestNCE); - ReferenceObject(NCE); - BestNCE = NCE; - BestLength = Length; - BestState = State; - } - } else { - /* First suitable router found, save it */ - ReferenceObject(NCE); - BestNCE = NCE; - BestLength = Length; - BestState = State; - } - } - CurrentEntry = NextEntry; - } - - KeReleaseSpinLock(&FIBLock, OldIrql); - - return BestNCE; -} - - -VOID RouterRemoveRoute( - PFIB_ENTRY FIBE) -/* - * FUNCTION: Removes a route from the Forward Information Base (FIB) - * ARGUMENTS: - * FIBE = Pointer to FIB entry describing route - */ -{ - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_ROUTER, ("Called. FIBE (0x%X).\n", FIBE)); - - KeAcquireSpinLock(&FIBLock, &OldIrql); - DestroyFIBE(FIBE); - KeReleaseSpinLock(&FIBLock, OldIrql); -} - - -PFIB_ENTRY RouterCreateRouteIPv4( - IPv4_RAW_ADDRESS NetworkAddress, - IPv4_RAW_ADDRESS Netmask, - IPv4_RAW_ADDRESS RouterAddress, - PNET_TABLE_ENTRY NTE, - 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 - */ -{ - PIP_ADDRESS pNetworkAddress; - PIP_ADDRESS pNetmask; - PIP_ADDRESS pRouterAddress; - PNEIGHBOR_CACHE_ENTRY NCE; - PFIB_ENTRY FIBE; - - pNetworkAddress = AddrBuildIPv4(NetworkAddress); - if (!NetworkAddress) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return NULL; - } - - pNetmask = AddrBuildIPv4(Netmask); - if (!Netmask) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - DereferenceObject(pNetworkAddress); - return NULL; - } - - pRouterAddress = AddrBuildIPv4(RouterAddress); - if (!RouterAddress) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - DereferenceObject(pNetworkAddress); - DereferenceObject(pNetmask); - return NULL; - } - - /* The NCE references RouterAddress. The NCE is referenced for us */ - NCE = NBAddNeighbor(NTE->Interface, - pRouterAddress, - NULL, - NTE->Interface->AddressLength, - NUD_PROBE); - if (!NCE) { - /* Not enough free resources */ - DereferenceObject(pNetworkAddress); - DereferenceObject(pNetmask); - DereferenceObject(pRouterAddress); - return NULL; - } - - ReferenceObject(pNetworkAddress); - ReferenceObject(pNetmask); - FIBE = RouterAddRoute(pNetworkAddress, pNetmask, NTE, NCE, 1); - if (!FIBE) { - /* Not enough free resources */ - NBRemoveNeighbor(NCE); - PoolFreeBuffer(pNetworkAddress); - PoolFreeBuffer(pNetmask); - PoolFreeBuffer(pRouterAddress); - } - - return FIBE; -} - - -NTSTATUS RouterStartup( - VOID) -/* - * FUNCTION: Initializes the routing subsystem - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_ROUTER, ("Called.\n")); - - /* Initialize the Forward Information Base */ - InitializeListHead(&FIBListHead); - KeInitializeSpinLock(&FIBLock); - -#if 0 - /* TEST: Create a test route */ - /* Network is 10.0.0.0 */ - /* Netmask is 255.0.0.0 */ - /* Router is 10.0.0.1 */ - RouterCreateRouteIPv4(0x0000000A, 0x000000FF, 0x0100000A, NTE?, 1); -#endif - return STATUS_SUCCESS; -} - - -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 */ - KeAcquireSpinLock(&FIBLock, &OldIrql); - DestroyFIBEs(); - KeReleaseSpinLock(&FIBLock, OldIrql); - - return STATUS_SUCCESS; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: network/router.c + * PURPOSE: IP routing subsystem + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include + + +LIST_ENTRY FIBListHead; +KSPIN_LOCK FIBLock; + + +VOID DestroyFIBE( + PFIB_ENTRY FIBE) +/* + * FUNCTION: Destroys an forward information base entry + * ARGUMENTS: + * FIBE = Pointer to FIB entry + * NOTES: + * The forward information base lock must be held when called + */ +{ + /* Unlink the FIB entry from the list */ + RemoveEntryList(&FIBE->ListEntry); + + /* Dereference the referenced objects */ + DereferenceObject(FIBE->NetworkAddress); + DereferenceObject(FIBE->Netmask); + DereferenceObject(FIBE->Router); + DereferenceObject(FIBE->NTE); + +#ifdef DBG + FIBE->RefCount--; + + if (FIBE->RefCount != 0) { + TI_DbgPrint(MIN_TRACE, ("FIB entry at (0x%X) has (%d) references (Should be 0).\n", FIBE, FIBE->RefCount)); + } +#endif + + /* And free the FIB entry */ + PoolFreeBuffer(FIBE); +} + + +VOID DestroyFIBEs( + VOID) +/* + * FUNCTION: Destroys all forward information base entries + * NOTES: + * The forward information base lock must be held when called + */ +{ + PLIST_ENTRY CurrentEntry; + PLIST_ENTRY NextEntry; + PFIB_ENTRY Current; + + /* Search the list and remove every FIB entry we find */ + CurrentEntry = FIBListHead.Flink; + while (CurrentEntry != &FIBListHead) { + NextEntry = CurrentEntry->Flink; + Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); + /* Destroy the FIB entry */ + DestroyFIBE(Current); + CurrentEntry = NextEntry; + } +} + + +UINT CommonPrefixLength( + PIP_ADDRESS Address1, + PIP_ADDRESS Address2) +/* + * FUNCTION: Computes the length of the longest prefix common to two addresses + * ARGUMENTS: + * Address1 = Pointer to first address + * Address2 = Pointer to second address + * NOTES: + * The two addresses must be of the same type + * RETURNS: + * Length of longest common prefix + */ +{ + PUCHAR Addr1, Addr2; + UINT Size; + UINT i, j; + UINT Bitmask; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. Address1 (0x%X) Address2 (0x%X).\n", Address1, Address2)); + + if (Address1->Type == IP_ADDRESS_V4) + Size = sizeof(IPv4_RAW_ADDRESS); + else + Size = sizeof(IPv6_RAW_ADDRESS); + + Addr1 = (PUCHAR)&Address1->Address; + Addr2 = (PUCHAR)&Address2->Address; + + /* Find first non-matching byte */ + for (i = 0; ; i++) { + if (i == Size) + return 8 * i; /* The two addresses are equal */ + + if (Addr1[i] != Addr2[i]) + break; + } + + /* Find first non-matching bit */ + Bitmask = 0x80; + for (j = 0; ; j++) { + if ((Addr1[i] & Bitmask) != (Addr2[i] & Bitmask)) + break; + Bitmask >>= 1; + } + + return 8 * i + j; +} + + +BOOLEAN HasPrefix( + PIP_ADDRESS Address, + PIP_ADDRESS Prefix, + UINT Length) +/* + * FUNCTION: Determines wether an address has an given prefix + * ARGUMENTS: + * Address = Pointer to address to use + * Prefix = Pointer to prefix to check for + * Length = Length of prefix + * RETURNS: + * TRUE if the address has the prefix, FALSE if not + * NOTES: + * The two addresses must be of the same type + */ +{ + PUCHAR pAddress = (PUCHAR)&Address->Address; + PUCHAR pPrefix = (PUCHAR)&Prefix->Address; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. Address (0x%X) Prefix (0x%X) Length (%d).\n", Address, Prefix, Length)); + + /* Check that initial integral bytes match */ + while (Length > 8) { + if (*pAddress++ != *pPrefix++) + return FALSE; + Length -= 8; + } + + /* Check any remaining bits */ + if ((Length > 0) && ((*pAddress >> (8 - Length)) != (*pPrefix >> (8 - Length)))) + return FALSE; + + return TRUE; +} + + +PNET_TABLE_ENTRY RouterFindBestNTE( + PIP_INTERFACE Interface, + PIP_ADDRESS Destination) +/* + * FUNCTION: Checks all on-link prefixes to find out if an address is on-link + * ARGUMENTS: + * Interface = Pointer to interface to use + * Destination = Pointer to destination address + * NOTES: + * If found the NTE if referenced + * RETURNS: + * Pointer to NTE if found, NULL if not + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PNET_TABLE_ENTRY Current; + UINT Length, BestLength = 0; + PNET_TABLE_ENTRY BestNTE = NULL; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. Interface (0x%X) Destination (0x%X).\n", Interface, Destination)); + + KeAcquireSpinLock(&Interface->Lock, &OldIrql); + + CurrentEntry = Interface->NTEListHead.Flink; + while (CurrentEntry != &Interface->NTEListHead) { + Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry); + + Length = CommonPrefixLength(Destination, Current->Address); + if (BestNTE) { + if (Length > BestLength) { + /* This seems to be a better NTE */ + DereferenceObject(BestNTE); + ReferenceObject(Current); + BestNTE = Current; + BestLength = Length; + } + } else { + /* First suitable NTE found, save it */ + ReferenceObject(Current); + BestNTE = Current; + BestLength = Length; + } + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&Interface->Lock, OldIrql); + + return BestNTE; +} + + +PIP_INTERFACE RouterFindOnLinkInterface( + PIP_ADDRESS Address, + PNET_TABLE_ENTRY NTE) +/* + * FUNCTION: Checks all on-link prefixes to find out if an address is on-link + * ARGUMENTS: + * Address = Pointer to address to check + * NTE = Pointer to NTE to check (NULL = check all interfaces) + * RETURNS: + * Pointer to interface if address is on-link, NULL if not + */ +{ + PLIST_ENTRY CurrentEntry; + PPREFIX_LIST_ENTRY Current; + + TI_DbgPrint(DEBUG_RCACHE, ("Called. Address (0x%X) NTE (0x%X).\n", Address, NTE)); + + CurrentEntry = PrefixListHead.Flink; + while (CurrentEntry != &PrefixListHead) { + Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry); + + if (HasPrefix(Address, Current->Prefix, Current->PrefixLength) && + ((!NTE) || (NTE->Interface == Current->Interface))) + return Current->Interface; + + CurrentEntry = CurrentEntry->Flink; + } + + return NULL; +} + + +PFIB_ENTRY RouterAddRoute( + PIP_ADDRESS NetworkAddress, + PIP_ADDRESS Netmask, + PNET_TABLE_ENTRY NTE, + PNEIGHBOR_CACHE_ENTRY Router, + UINT Metric) +/* + * FUNCTION: Adds a route to the Forward Information Base (FIB) + * ARGUMENTS: + * NetworkAddress = Pointer to address of network + * Netmask = Pointer to netmask of network + * NTE = Pointer to NTE to use + * Router = Pointer to NCE of router to use + * Metric = Cost of this route + * RETURNS: + * Pointer to FIB entry if the route was added, NULL if not + * NOTES: + * The FIB entry references the NetworkAddress, Netmask, NTE and + * the NCE of the router. The caller is responsible for providing + * these references + */ +{ + PFIB_ENTRY FIBE; + + TI_DbgPrint(DEBUG_ROUTER, ("Called. NetworkAddress (0x%X) Netmask (0x%X) NTE (0x%X) " + "Router (0x%X) Metric (%d).\n", NetworkAddress, Netmask, NTE, Router, Metric)); + + FIBE = PoolAllocateBuffer(sizeof(FIB_ENTRY)); + if (!FIBE) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + FIBE->NetworkAddress = NetworkAddress; + FIBE->Netmask = Netmask; + FIBE->NTE = NTE; + FIBE->Router = Router; + FIBE->Metric = Metric; + + /* Add FIB to the forward information base */ + ExInterlockedInsertTailList(&FIBListHead, &FIBE->ListEntry, &FIBLock); + + return FIBE; +} + + +PNEIGHBOR_CACHE_ENTRY RouterGetRoute( + PIP_ADDRESS Destination, + PNET_TABLE_ENTRY NTE) +/* + * FUNCTION: Finds a router to use to get to Destination + * ARGUMENTS: + * Destination = Pointer to destination address (NULL means don't care) + * NTE = Pointer to NTE describing net to send on + * (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; + PNEIGHBOR_CACHE_ENTRY NCE, BestNCE = NULL; + + TI_DbgPrint(DEBUG_ROUTER, ("Called. Destination (0x%X) NTE (0x%X).\n", Destination, NTE)); + + KeAcquireSpinLock(&FIBLock, &OldIrql); + + CurrentEntry = FIBListHead.Flink; + while (CurrentEntry != &FIBListHead) { + NextEntry = CurrentEntry->Flink; + Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry); + + NCE = Current->Router; + State = NCE->State; + + if ((!NTE) || (NTE->Interface == NCE->Interface)) { + if (Destination) + Length = CommonPrefixLength(Destination, NCE->Address); + else + Length = 0; + + if (BestNCE) { + if ((State > BestState) || + ((State == BestState) && + (Length > BestLength))) { + /* This seems to be a better router */ + DereferenceObject(BestNCE); + ReferenceObject(NCE); + BestNCE = NCE; + BestLength = Length; + BestState = State; + } + } else { + /* First suitable router found, save it */ + ReferenceObject(NCE); + BestNCE = NCE; + BestLength = Length; + BestState = State; + } + } + CurrentEntry = NextEntry; + } + + KeReleaseSpinLock(&FIBLock, OldIrql); + + return BestNCE; +} + + +VOID RouterRemoveRoute( + PFIB_ENTRY FIBE) +/* + * FUNCTION: Removes a route from the Forward Information Base (FIB) + * ARGUMENTS: + * FIBE = Pointer to FIB entry describing route + */ +{ + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_ROUTER, ("Called. FIBE (0x%X).\n", FIBE)); + + KeAcquireSpinLock(&FIBLock, &OldIrql); + DestroyFIBE(FIBE); + KeReleaseSpinLock(&FIBLock, OldIrql); +} + + +PFIB_ENTRY RouterCreateRouteIPv4( + IPv4_RAW_ADDRESS NetworkAddress, + IPv4_RAW_ADDRESS Netmask, + IPv4_RAW_ADDRESS RouterAddress, + PNET_TABLE_ENTRY NTE, + 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 + */ +{ + PIP_ADDRESS pNetworkAddress; + PIP_ADDRESS pNetmask; + PIP_ADDRESS pRouterAddress; + PNEIGHBOR_CACHE_ENTRY NCE; + PFIB_ENTRY FIBE; + + pNetworkAddress = AddrBuildIPv4(NetworkAddress); + if (!NetworkAddress) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return NULL; + } + + pNetmask = AddrBuildIPv4(Netmask); + if (!Netmask) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + DereferenceObject(pNetworkAddress); + return NULL; + } + + pRouterAddress = AddrBuildIPv4(RouterAddress); + if (!RouterAddress) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + DereferenceObject(pNetworkAddress); + DereferenceObject(pNetmask); + return NULL; + } + + /* The NCE references RouterAddress. The NCE is referenced for us */ + NCE = NBAddNeighbor(NTE->Interface, + pRouterAddress, + NULL, + NTE->Interface->AddressLength, + NUD_PROBE); + if (!NCE) { + /* Not enough free resources */ + DereferenceObject(pNetworkAddress); + DereferenceObject(pNetmask); + DereferenceObject(pRouterAddress); + return NULL; + } + + ReferenceObject(pNetworkAddress); + ReferenceObject(pNetmask); + FIBE = RouterAddRoute(pNetworkAddress, pNetmask, NTE, NCE, 1); + if (!FIBE) { + /* Not enough free resources */ + NBRemoveNeighbor(NCE); + PoolFreeBuffer(pNetworkAddress); + PoolFreeBuffer(pNetmask); + PoolFreeBuffer(pRouterAddress); + } + + return FIBE; +} + + +NTSTATUS RouterStartup( + VOID) +/* + * FUNCTION: Initializes the routing subsystem + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_ROUTER, ("Called.\n")); + + /* Initialize the Forward Information Base */ + InitializeListHead(&FIBListHead); + KeInitializeSpinLock(&FIBLock); + +#if 0 + /* TEST: Create a test route */ + /* Network is 10.0.0.0 */ + /* Netmask is 255.0.0.0 */ + /* Router is 10.0.0.1 */ + RouterCreateRouteIPv4(0x0000000A, 0x000000FF, 0x0100000A, NTE?, 1); +#endif + return STATUS_SUCCESS; +} + + +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 */ + KeAcquireSpinLock(&FIBLock, &OldIrql); + DestroyFIBEs(); + KeReleaseSpinLock(&FIBLock, OldIrql); + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/network/transmit.c b/reactos/drivers/net/tcpip/network/transmit.c index cb3c4f5f5fc..3bcdf29fc16 100644 --- a/reactos/drivers/net/tcpip/network/transmit.c +++ b/reactos/drivers/net/tcpip/network/transmit.c @@ -1,328 +1,328 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: network/transmit.c - * PURPOSE: Internet Protocol transmit routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include - - -BOOLEAN PrepareNextFragment( - PIPFRAGMENT_CONTEXT IFC) -/* - * FUNCTION: Prepares the next fragment of an IP datagram for transmission - * ARGUMENTS: - * IFC = Pointer to IP fragment context - * RETURNS: - * TRUE if a fragment was prepared for transmission, FALSE if - * there are no more fragments to send - */ -{ - UINT MaxData; - UINT DataSize; - PIPv4_HEADER Header; - BOOLEAN MoreFragments; - USHORT FragOfs; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - if (IFC->BytesLeft != 0) { - - TI_DbgPrint(MAX_TRACE, ("Preparing 1 fragment.\n")); - - MaxData = IFC->PathMTU - IFC->HeaderSize; - /* Make fragment a multiplum of 64bit */ - MaxData -= MaxData % 8; - if (IFC->BytesLeft > MaxData) { - DataSize = MaxData; - MoreFragments = TRUE; - } else { - DataSize = IFC->BytesLeft; - MoreFragments = FALSE; - } - - RtlCopyMemory(IFC->Data, IFC->DatagramData, DataSize); - - FragOfs = (USHORT)IFC->Position; // Swap? - if (MoreFragments) - FragOfs |= IPv4_MF_MASK; - else - FragOfs &= ~IPv4_MF_MASK; - - Header = IFC->Header; - Header->FlagsFragOfs = FragOfs; - - /* FIXME: Handle options */ - - /* Calculate checksum of IP header */ - Header->Checksum = 0; - Header->Checksum = (USHORT)IPv4Checksum(Header, IFC->HeaderSize, 0); - - /* Update pointers */ - (ULONG_PTR)IFC->DatagramData += DataSize; - IFC->Position += DataSize; - IFC->BytesLeft -= DataSize; - - return TRUE; - } else { - TI_DbgPrint(MAX_TRACE, ("No more fragments.\n")); - return FALSE; - } -} - - -NTSTATUS SendFragments( - PIP_PACKET IPPacket, - PNEIGHBOR_CACHE_ENTRY NCE, - UINT PathMTU) -/* - * FUNCTION: Fragments and sends the first fragment of an IP datagram - * ARGUMENTS: - * IPPacket = Pointer to an IP packet - * NCE = Pointer to NCE for first hop to destination - * PathMTU = Size of Maximum Transmission Unit of path - * RETURNS: - * Status of operation - * NOTES: - * IP datagram is larger than PathMTU when this is called - */ -{ - PIPFRAGMENT_CONTEXT IFC; - NDIS_STATUS NdisStatus; - PVOID Data; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - IFC = PoolAllocateBuffer(sizeof(IPFRAGMENT_CONTEXT)); - if (!IFC) - return STATUS_INSUFFICIENT_RESOURCES; - - /* We allocate a buffer for a PathMTU sized packet and reuse - it for all fragments */ - Data = ExAllocatePool(NonPagedPool, MaxLLHeaderSize + PathMTU); - if (!IFC->Header) { - PoolFreeBuffer(IFC); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Allocate NDIS packet */ - NdisAllocatePacket(&NdisStatus, &IFC->NdisPacket, GlobalPacketPool); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - ExFreePool(Data); - PoolFreeBuffer(IFC); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Allocate NDIS buffer */ - NdisAllocateBuffer(&NdisStatus, &IFC->NdisBuffer, - GlobalBufferPool, Data, MaxLLHeaderSize + PathMTU); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - NdisFreePacket(IFC->NdisPacket); - ExFreePool(Data); - PoolFreeBuffer(IFC); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Link NDIS buffer into packet */ - NdisChainBufferAtFront(IFC->NdisPacket, IFC->NdisBuffer); - - IFC->Header = (PVOID)((ULONG_PTR)Data + MaxLLHeaderSize); - IFC->Datagram = IPPacket->NdisPacket; - IFC->DatagramData = IPPacket->Header; - IFC->HeaderSize = IPPacket->HeaderSize; - IFC->PathMTU = PathMTU; - IFC->NCE = NCE; - IFC->Position = 0; - IFC->BytesLeft = IPPacket->TotalSize - IPPacket->HeaderSize; - IFC->Data = (PVOID)((ULONG_PTR)IFC->Header + IPPacket->HeaderSize); - - PC(IFC->NdisPacket)->DLComplete = IPSendComplete; - /* Set upper layer completion function to NULL to indicate that - this packet is an IP datagram fragment and thus we should - check for more fragments to send. If this is NULL the - Context field is a pointer to an IPFRAGMENT_CONTEXT structure */ - PC(IFC->NdisPacket)->Complete = NULL; - PC(IFC->NdisPacket)->Context = IFC; - - /* Copy IP datagram header to fragment buffer */ - RtlCopyMemory(IFC->Header, IPPacket->Header, IPPacket->HeaderSize); - - /* Prepare next fragment for transmission and send it */ - - PrepareNextFragment(IFC); - - IPSendFragment(IFC->NdisPacket, NCE); - - return STATUS_SUCCESS; -} - - -VOID IPSendComplete( - PVOID Context, - PNDIS_PACKET NdisPacket, - NDIS_STATUS NdisStatus) -/* - * FUNCTION: IP datagram fragment send completion handler - * ARGUMENTS: - * Context = Pointer to context information (IP_INTERFACE) - * Packet = Pointer to NDIS packet that was sent - * NdisStatus = NDIS status of operation - * NOTES: - * This routine is called when an IP datagram fragment has been sent - */ -{ - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - /* FIXME: Stop sending fragments and cleanup datagram buffers if - there was an error */ - - if (PC(NdisPacket)->Complete) - /* This datagram was only one fragment long so call completion handler now */ - (*PC(NdisPacket)->Complete)(PC(NdisPacket)->Context, NdisPacket, NdisStatus); - else { - /* This was one of many fragments of an IP datagram. Prepare - next fragment and send it or if there are no more fragments, - call upper layer completion routine */ - - PIPFRAGMENT_CONTEXT IFC = (PIPFRAGMENT_CONTEXT)PC(NdisPacket)->Context; - - if (PrepareNextFragment(IFC)) { - /* A fragment was prepared for transmission, so send it */ - IPSendFragment(IFC->NdisPacket, IFC->NCE); - } else { - TI_DbgPrint(MAX_TRACE, ("Calling completion handler.\n")); - - /* There are no more fragments to transmit, so call completion handler */ - NdisPacket = IFC->Datagram; - FreeNdisPacket(IFC->NdisPacket); - PoolFreeBuffer(IFC); - (*PC(NdisPacket)->Complete)(PC(NdisPacket)->Context, NdisPacket, NdisStatus); - } - } -} - - -NTSTATUS IPSendFragment( - PNDIS_PACKET NdisPacket, - PNEIGHBOR_CACHE_ENTRY NCE) -/* - * FUNCTION: Sends an IP datagram fragment to a neighbor - * ARGUMENTS: - * NdisPacket = Pointer to an NDIS packet containing fragment - * NCE = Pointer to NCE for first hop to destination - * RETURNS: - * Status of operation - * NOTES: - * Lowest level IP send routine - */ -{ - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - TI_DbgPrint(MAX_TRACE, ("NCE->State = %d.\n", NCE->State)); - - switch (NCE->State) { - case NUD_PERMANENT: - /* Neighbor is always valid */ - break; - - case NUD_REACHABLE: - /* Neighbor is reachable */ - - /* FIXME: Set reachable timer */ - - break; - - case NUD_STALE: - /* Enter delay state and send packet */ - - /* FIXME: Enter delay state */ - - break; - - case NUD_DELAY: - case NUD_PROBE: - /* In these states we send the packet and hope the neighbor - hasn't changed hardware address */ - break; - - case NUD_INCOMPLETE: - TI_DbgPrint(MAX_TRACE, ("Queueing packet.\n")); - - /* We don't know the hardware address of the first hop to - the destination. Queue the packet on the NCE and return */ - NBQueuePacket(NCE, NdisPacket); - - return STATUS_SUCCESS; - default: - /* Should not happen */ - TI_DbgPrint(MIN_TRACE, ("Unknown NCE state.\n")); - - return STATUS_SUCCESS; - } - - PC(NdisPacket)->DLComplete = IPSendComplete; - (*NCE->Interface->Transmit)(NCE->Interface->Context, NdisPacket, - MaxLLHeaderSize, NCE->LinkAddress, LAN_PROTO_IPv4); - - return STATUS_SUCCESS; -} - - -NTSTATUS IPSendDatagram( - PIP_PACKET IPPacket, - PROUTE_CACHE_NODE RCN) -/* - * FUNCTION: Sends an IP datagram to a remote address - * ARGUMENTS: - * IPPacket = Pointer to an IP packet - * RCN = Pointer to route cache node - * RETURNS: - * Status of operation - * NOTES: - * This is the highest level IP send routine. It possibly breaks the packet - * into two or more fragments before passing it on to the next lower level - * send routine (IPSendFragment) - */ -{ - PNEIGHBOR_CACHE_ENTRY NCE; - UINT PathMTU; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - NCE = RCN->NCE; - -#if DBG - if (!NCE) { - TI_DbgPrint(MIN_TRACE, ("No NCE to use.\n")); - FreeNdisPacket(IPPacket->NdisPacket); - return STATUS_SUCCESS; - } -#endif - - /* Fetch path MTU now, because it may change */ - PathMTU = RCN->PathMTU; - if (IPPacket->TotalSize > PathMTU) { - return SendFragments(IPPacket, NCE, PathMTU); - } else { - /* Calculate checksum of IP header */ - ((PIPv4_HEADER)IPPacket->Header)->Checksum = 0; - - ((PIPv4_HEADER)IPPacket->Header)->Checksum = (USHORT) - IPv4Checksum(IPPacket->Header, IPPacket->HeaderSize, 0); - - TI_DbgPrint(MAX_TRACE, ("Sending packet (length is %d).\n", WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength))); - - return IPSendFragment(IPPacket->NdisPacket, NCE); - } -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: network/transmit.c + * PURPOSE: Internet Protocol transmit routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include + + +BOOLEAN PrepareNextFragment( + PIPFRAGMENT_CONTEXT IFC) +/* + * FUNCTION: Prepares the next fragment of an IP datagram for transmission + * ARGUMENTS: + * IFC = Pointer to IP fragment context + * RETURNS: + * TRUE if a fragment was prepared for transmission, FALSE if + * there are no more fragments to send + */ +{ + UINT MaxData; + UINT DataSize; + PIPv4_HEADER Header; + BOOLEAN MoreFragments; + USHORT FragOfs; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + if (IFC->BytesLeft != 0) { + + TI_DbgPrint(MAX_TRACE, ("Preparing 1 fragment.\n")); + + MaxData = IFC->PathMTU - IFC->HeaderSize; + /* Make fragment a multiplum of 64bit */ + MaxData -= MaxData % 8; + if (IFC->BytesLeft > MaxData) { + DataSize = MaxData; + MoreFragments = TRUE; + } else { + DataSize = IFC->BytesLeft; + MoreFragments = FALSE; + } + + RtlCopyMemory(IFC->Data, IFC->DatagramData, DataSize); + + FragOfs = (USHORT)IFC->Position; // Swap? + if (MoreFragments) + FragOfs |= IPv4_MF_MASK; + else + FragOfs &= ~IPv4_MF_MASK; + + Header = IFC->Header; + Header->FlagsFragOfs = FragOfs; + + /* FIXME: Handle options */ + + /* Calculate checksum of IP header */ + Header->Checksum = 0; + Header->Checksum = (USHORT)IPv4Checksum(Header, IFC->HeaderSize, 0); + + /* Update pointers */ + (ULONG_PTR)IFC->DatagramData += DataSize; + IFC->Position += DataSize; + IFC->BytesLeft -= DataSize; + + return TRUE; + } else { + TI_DbgPrint(MAX_TRACE, ("No more fragments.\n")); + return FALSE; + } +} + + +NTSTATUS SendFragments( + PIP_PACKET IPPacket, + PNEIGHBOR_CACHE_ENTRY NCE, + UINT PathMTU) +/* + * FUNCTION: Fragments and sends the first fragment of an IP datagram + * ARGUMENTS: + * IPPacket = Pointer to an IP packet + * NCE = Pointer to NCE for first hop to destination + * PathMTU = Size of Maximum Transmission Unit of path + * RETURNS: + * Status of operation + * NOTES: + * IP datagram is larger than PathMTU when this is called + */ +{ + PIPFRAGMENT_CONTEXT IFC; + NDIS_STATUS NdisStatus; + PVOID Data; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + IFC = PoolAllocateBuffer(sizeof(IPFRAGMENT_CONTEXT)); + if (!IFC) + return STATUS_INSUFFICIENT_RESOURCES; + + /* We allocate a buffer for a PathMTU sized packet and reuse + it for all fragments */ + Data = ExAllocatePool(NonPagedPool, MaxLLHeaderSize + PathMTU); + if (!IFC->Header) { + PoolFreeBuffer(IFC); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Allocate NDIS packet */ + NdisAllocatePacket(&NdisStatus, &IFC->NdisPacket, GlobalPacketPool); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + ExFreePool(Data); + PoolFreeBuffer(IFC); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Allocate NDIS buffer */ + NdisAllocateBuffer(&NdisStatus, &IFC->NdisBuffer, + GlobalBufferPool, Data, MaxLLHeaderSize + PathMTU); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + NdisFreePacket(IFC->NdisPacket); + ExFreePool(Data); + PoolFreeBuffer(IFC); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Link NDIS buffer into packet */ + NdisChainBufferAtFront(IFC->NdisPacket, IFC->NdisBuffer); + + IFC->Header = (PVOID)((ULONG_PTR)Data + MaxLLHeaderSize); + IFC->Datagram = IPPacket->NdisPacket; + IFC->DatagramData = IPPacket->Header; + IFC->HeaderSize = IPPacket->HeaderSize; + IFC->PathMTU = PathMTU; + IFC->NCE = NCE; + IFC->Position = 0; + IFC->BytesLeft = IPPacket->TotalSize - IPPacket->HeaderSize; + IFC->Data = (PVOID)((ULONG_PTR)IFC->Header + IPPacket->HeaderSize); + + PC(IFC->NdisPacket)->DLComplete = IPSendComplete; + /* Set upper layer completion function to NULL to indicate that + this packet is an IP datagram fragment and thus we should + check for more fragments to send. If this is NULL the + Context field is a pointer to an IPFRAGMENT_CONTEXT structure */ + PC(IFC->NdisPacket)->Complete = NULL; + PC(IFC->NdisPacket)->Context = IFC; + + /* Copy IP datagram header to fragment buffer */ + RtlCopyMemory(IFC->Header, IPPacket->Header, IPPacket->HeaderSize); + + /* Prepare next fragment for transmission and send it */ + + PrepareNextFragment(IFC); + + IPSendFragment(IFC->NdisPacket, NCE); + + return STATUS_SUCCESS; +} + + +VOID IPSendComplete( + PVOID Context, + PNDIS_PACKET NdisPacket, + NDIS_STATUS NdisStatus) +/* + * FUNCTION: IP datagram fragment send completion handler + * ARGUMENTS: + * Context = Pointer to context information (IP_INTERFACE) + * Packet = Pointer to NDIS packet that was sent + * NdisStatus = NDIS status of operation + * NOTES: + * This routine is called when an IP datagram fragment has been sent + */ +{ + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + /* FIXME: Stop sending fragments and cleanup datagram buffers if + there was an error */ + + if (PC(NdisPacket)->Complete) + /* This datagram was only one fragment long so call completion handler now */ + (*PC(NdisPacket)->Complete)(PC(NdisPacket)->Context, NdisPacket, NdisStatus); + else { + /* This was one of many fragments of an IP datagram. Prepare + next fragment and send it or if there are no more fragments, + call upper layer completion routine */ + + PIPFRAGMENT_CONTEXT IFC = (PIPFRAGMENT_CONTEXT)PC(NdisPacket)->Context; + + if (PrepareNextFragment(IFC)) { + /* A fragment was prepared for transmission, so send it */ + IPSendFragment(IFC->NdisPacket, IFC->NCE); + } else { + TI_DbgPrint(MAX_TRACE, ("Calling completion handler.\n")); + + /* There are no more fragments to transmit, so call completion handler */ + NdisPacket = IFC->Datagram; + FreeNdisPacket(IFC->NdisPacket); + PoolFreeBuffer(IFC); + (*PC(NdisPacket)->Complete)(PC(NdisPacket)->Context, NdisPacket, NdisStatus); + } + } +} + + +NTSTATUS IPSendFragment( + PNDIS_PACKET NdisPacket, + PNEIGHBOR_CACHE_ENTRY NCE) +/* + * FUNCTION: Sends an IP datagram fragment to a neighbor + * ARGUMENTS: + * NdisPacket = Pointer to an NDIS packet containing fragment + * NCE = Pointer to NCE for first hop to destination + * RETURNS: + * Status of operation + * NOTES: + * Lowest level IP send routine + */ +{ + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + TI_DbgPrint(MAX_TRACE, ("NCE->State = %d.\n", NCE->State)); + + switch (NCE->State) { + case NUD_PERMANENT: + /* Neighbor is always valid */ + break; + + case NUD_REACHABLE: + /* Neighbor is reachable */ + + /* FIXME: Set reachable timer */ + + break; + + case NUD_STALE: + /* Enter delay state and send packet */ + + /* FIXME: Enter delay state */ + + break; + + case NUD_DELAY: + case NUD_PROBE: + /* In these states we send the packet and hope the neighbor + hasn't changed hardware address */ + break; + + case NUD_INCOMPLETE: + TI_DbgPrint(MAX_TRACE, ("Queueing packet.\n")); + + /* We don't know the hardware address of the first hop to + the destination. Queue the packet on the NCE and return */ + NBQueuePacket(NCE, NdisPacket); + + return STATUS_SUCCESS; + default: + /* Should not happen */ + TI_DbgPrint(MIN_TRACE, ("Unknown NCE state.\n")); + + return STATUS_SUCCESS; + } + + PC(NdisPacket)->DLComplete = IPSendComplete; + (*NCE->Interface->Transmit)(NCE->Interface->Context, NdisPacket, + MaxLLHeaderSize, NCE->LinkAddress, LAN_PROTO_IPv4); + + return STATUS_SUCCESS; +} + + +NTSTATUS IPSendDatagram( + PIP_PACKET IPPacket, + PROUTE_CACHE_NODE RCN) +/* + * FUNCTION: Sends an IP datagram to a remote address + * ARGUMENTS: + * IPPacket = Pointer to an IP packet + * RCN = Pointer to route cache node + * RETURNS: + * Status of operation + * NOTES: + * This is the highest level IP send routine. It possibly breaks the packet + * into two or more fragments before passing it on to the next lower level + * send routine (IPSendFragment) + */ +{ + PNEIGHBOR_CACHE_ENTRY NCE; + UINT PathMTU; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + NCE = RCN->NCE; + +#if DBG + if (!NCE) { + TI_DbgPrint(MIN_TRACE, ("No NCE to use.\n")); + FreeNdisPacket(IPPacket->NdisPacket); + return STATUS_SUCCESS; + } +#endif + + /* Fetch path MTU now, because it may change */ + PathMTU = RCN->PathMTU; + if (IPPacket->TotalSize > PathMTU) { + return SendFragments(IPPacket, NCE, PathMTU); + } else { + /* Calculate checksum of IP header */ + ((PIPv4_HEADER)IPPacket->Header)->Checksum = 0; + + ((PIPv4_HEADER)IPPacket->Header)->Checksum = (USHORT) + IPv4Checksum(IPPacket->Header, IPPacket->HeaderSize, 0); + + TI_DbgPrint(MAX_TRACE, ("Sending packet (length is %d).\n", WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength))); + + return IPSendFragment(IPPacket->NdisPacket, NCE); + } +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/readme.txt b/reactos/drivers/net/tcpip/readme.txt index a4f061ea43e..b87c9dfc158 100644 --- a/reactos/drivers/net/tcpip/readme.txt +++ b/reactos/drivers/net/tcpip/readme.txt @@ -1,19 +1,19 @@ -Build instructions for TCP/IP protocol driver ---------------------------------------------- - -Building with Visual C++ and Windows NT DDK: - -Variables: -%BASEDIR% = path to NT4 DDK (e.g. c:\ntddk) -%DDKBUILDENV% = DDK build environment (free or checked) - -DDK environment variables must be set! (run setenv.bat) - - - Create the directory objects/i386/%DDKBUILDENV% - - Run "build" to build the driver - - -Building with Mingw32 and ReactOS include files: - - - Build NDIS.SYS (i.e. "make ndis") - - Run "make tcpip" FROM THE ReactOS ROOT DIRECTORY to build the driver +Build instructions for TCP/IP protocol driver +--------------------------------------------- + +Building with Visual C++ and Windows NT DDK: + +Variables: +%BASEDIR% = path to NT4 DDK (e.g. c:\ntddk) +%DDKBUILDENV% = DDK build environment (free or checked) + +DDK environment variables must be set! (run setenv.bat) + + - Create the directory objects/i386/%DDKBUILDENV% + - Run "build" to build the driver + + +Building with Mingw32 and ReactOS include files: + + - Build NDIS.SYS (i.e. "make ndis") + - Run "make tcpip" FROM THE ReactOS ROOT DIRECTORY to build the driver diff --git a/reactos/drivers/net/tcpip/tcpip.def b/reactos/drivers/net/tcpip/tcpip.def index 43b9506306d..cec8466f6ad 100644 --- a/reactos/drivers/net/tcpip/tcpip.def +++ b/reactos/drivers/net/tcpip/tcpip.def @@ -1,32 +1,32 @@ -; TCPIP.SYS - TCP/IP protocol driver - -LIBRARY tcpip.sys - -EXPORTS -;FreeIprBuff -;GetIFAndLink -IPAddInterface@20 -;IPAllocBuff -IPDelInterface@4 -;IPDelayedNdisReEnumerateBindings -;IPDeregisterARP -;IPDisableSniffer -;IPEnableSniffer -;IPFreeBuff -;IPGetAddrType -;IPGetBestInterface -;IPGetInfo -;IPInjectPkt -;IPProxyNdisRequest -;IPRegisterARP -;IPRegisterProtocol -;IPSetIPSecStatus -;IPTransmit -LookupRoute@8 -;LookupRouteInformation -;SendICMPErr -;SetIPSecPtr -;UnSetIPSecPtr -;UnSetIPSecSendPtr - -; EOF +; TCPIP.SYS - TCP/IP protocol driver + +LIBRARY tcpip.sys + +EXPORTS +;FreeIprBuff +;GetIFAndLink +IPAddInterface@20 +;IPAllocBuff +IPDelInterface@4 +;IPDelayedNdisReEnumerateBindings +;IPDeregisterARP +;IPDisableSniffer +;IPEnableSniffer +;IPFreeBuff +;IPGetAddrType +;IPGetBestInterface +;IPGetInfo +;IPInjectPkt +;IPProxyNdisRequest +;IPRegisterARP +;IPRegisterProtocol +;IPSetIPSecStatus +;IPTransmit +LookupRoute@8 +;LookupRouteInformation +;SendICMPErr +;SetIPSecPtr +;UnSetIPSecPtr +;UnSetIPSecSendPtr + +; EOF diff --git a/reactos/drivers/net/tcpip/tcpip.edf b/reactos/drivers/net/tcpip/tcpip.edf index 08f8b9b3587..56e0c626511 100644 --- a/reactos/drivers/net/tcpip/tcpip.edf +++ b/reactos/drivers/net/tcpip/tcpip.edf @@ -1,32 +1,32 @@ -; TCPIP.SYS - TCP/IP protocol driver - -LIBRARY tcpip.sys - -EXPORTS -;FreeIprBuff -;GetIFAndLink -IPAddInterface=IPAddInterface@20 -;IPAllocBuff -IPDelInterface=IPDelInterface@4 -;IPDelayedNdisReEnumerateBindings -;IPDeregisterARP -;IPDisableSniffer -;IPEnableSniffer -;IPFreeBuff -;IPGetAddrType -;IPGetBestInterface -;IPGetInfo -;IPInjectPkt -;IPProxyNdisRequest -;IPRegisterARP -;IPRegisterProtocol -;IPSetIPSecStatus -;IPTransmit -LookupRoute=LookupRoute@8 -;LookupRouteInformation -;SendICMPErr -;SetIPSecPtr -;UnSetIPSecPtr -;UnSetIPSecSendPtr - -; EOF +; TCPIP.SYS - TCP/IP protocol driver + +LIBRARY tcpip.sys + +EXPORTS +;FreeIprBuff +;GetIFAndLink +IPAddInterface=IPAddInterface@20 +;IPAllocBuff +IPDelInterface=IPDelInterface@4 +;IPDelayedNdisReEnumerateBindings +;IPDeregisterARP +;IPDisableSniffer +;IPEnableSniffer +;IPFreeBuff +;IPGetAddrType +;IPGetBestInterface +;IPGetInfo +;IPInjectPkt +;IPProxyNdisRequest +;IPRegisterARP +;IPRegisterProtocol +;IPSetIPSecStatus +;IPTransmit +LookupRoute=LookupRoute@8 +;LookupRouteInformation +;SendICMPErr +;SetIPSecPtr +;UnSetIPSecPtr +;UnSetIPSecSendPtr + +; EOF diff --git a/reactos/drivers/net/tcpip/tcpip.rc b/reactos/drivers/net/tcpip/tcpip.rc index 484b00dc098..6f31df8ae57 100644 --- a/reactos/drivers/net/tcpip/tcpip.rc +++ b/reactos/drivers/net/tcpip/tcpip.rc @@ -1,38 +1,38 @@ -#include -#include - -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -VS_VERSION_INFO VERSIONINFO - FILEVERSION RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD - PRODUCTVERSION RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", RES_STR_COMPANY_NAME - VALUE "FileDescription", "TCP/IP protocol driver\0" - VALUE "FileVersion", "0.0.0\0" - VALUE "InternalName", "tcpip\0" - VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT - VALUE "OriginalFilename", "tcpip.sys\0" - VALUE "ProductName", RES_STR_PRODUCT_NAME - VALUE "ProductVersion", RES_STR_PRODUCT_VERSION - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - +#include +#include + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD + PRODUCTVERSION RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", RES_STR_COMPANY_NAME + VALUE "FileDescription", "TCP/IP protocol driver\0" + VALUE "FileVersion", "0.0.0\0" + VALUE "InternalName", "tcpip\0" + VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "tcpip.sys\0" + VALUE "ProductName", RES_STR_PRODUCT_NAME + VALUE "ProductVersion", RES_STR_PRODUCT_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + diff --git a/reactos/drivers/net/tcpip/tcpip/Copy of info.c b/reactos/drivers/net/tcpip/tcpip/Copy of info.c index 6241e539a5a..c5fbdc326b1 100644 --- a/reactos/drivers/net/tcpip/tcpip/Copy of info.c +++ b/reactos/drivers/net/tcpip/tcpip/Copy of info.c @@ -1,335 +1,335 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: tcpip/info.c - * PURPOSE: TDI query and set information routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/07-2000 Created - */ -#include -#include -#include - - -TDI_STATUS IPTdiQueryInformationEx( - PTDI_REQUEST Request, - TDIObjectID *ID, - PNDIS_BUFFER Buffer, - PUINT BufferSize, - PVOID Context) -/* - * FUNCTION: Returns extended information about network layer - * ARGUMENTS: - * Request = Pointer to TDI request structure for the request - * ID = TDI object ID - * Buffer = Pointer to buffer with data to use. - * BufferSize = Pointer to buffer with size of Buffer. On return - * this is filled with number of bytes returned - * Context = Pointer to context buffer - * RETURNS: - * Status of operation - */ -{ - IPADDR_ENTRY IpAddress; - IPSNMP_INFO SnmpInfo; - PADDRESS_ENTRY ADE; - PIP_INTERFACE IF; - ULONG Temp; - UINT Count; - ULONG Entity; - KIRQL OldIrql; - UINT BufSize = *BufferSize; - - /* Make return parameters consistent every time */ - *BufferSize = 0; - - Entity = ID->toi_entity.tei_entity; - if (Entity != CL_NL_ENTITY) { - /* We can't handle this entity */ - return TDI_INVALID_PARAMETER; - } - - if (ID->toi_entity.tei_instance != TL_INSTANCE) - /* We only support a single instance */ - return TDI_INVALID_REQUEST; - if (ID->toi_class == INFO_CLASS_GENERIC) { - if (ID->toi_type == INFO_TYPE_PROVIDER && - ID->toi_id == ENTITY_TYPE_ID) { - - if (BufSize < sizeof(ULONG)) - return TDI_BUFFER_TOO_SMALL; - Temp = CL_NL_IP; - - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG)); - - return TDI_SUCCESS; - } - return TDI_INVALID_PARAMETER; - } - - if (ID->toi_class == INFO_CLASS_PROTOCOL) { - if (ID->toi_type != INFO_TYPE_PROVIDER) - return TDI_INVALID_PARAMETER; - - switch (ID->toi_id) { - case IP_MIB_ADDRTABLE_ENTRY_ID: - Temp = 0; - - KeAcquireSpinLock(&InterfaceLock, &OldIrql); -/* - /* Search the interface list */ - CurrentIFEntry = InterfaceListHead.Flink; - while (CurrentIFEntry != &InterfaceListHead) { - CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); - if (CurrentIF != Loopback) { - /* Search the address entry list and return the first appropriate ADE found */ - CurrentADEEntry = CurrentIF->ADEListHead.Flink; - while (CurrentADEEntry != &CurrentIF->ADEListHead) { - CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); - if (CurrentADE->Type == AddressType) - ReferenceAddress(CurrentADE->Address); - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - return CurrentADE; - } - CurrentADEEntry = CurrentADEEntry->Flink; - } else - LoopbackIsRegistered = TRUE; - CurrentIFEntry = CurrentIFEntry->Flink; - } - - - */ - for (IF = InterfaceList; IF != NULL; IF = IF->Next) { - if (Temp + sizeof(IPADDR_ENTRY) > BufSize) { - KeReleaseSpinLock(&InterfaceLock, OldIrql); - return TDI_BUFFER_TOO_SMALL; - } - - IpAddress.Addr = 0; - IpAddress.BcastAddr = 0; - IpAddress.Mask = 0; - /* Locate the diffrent addresses and put them the right place */ - for (ADE = IF->ADE; ADE != NULL; ADE = ADE->Next) { - switch (ADE->Type) { - case ADE_UNICAST : IpAddress.Addr = ADE->Address->Address.IPv4Address; - case ADE_MULTICAST: IpAddress.BcastAddr = ADE->Address->Address.IPv4Address; - case ADE_ADDRMASK : IpAddress.Mask = ADE->Address->Address.IPv4Address; - } - } - /* Pack the address information into IPADDR_ENTRY structure */ - IpAddress.Index = 0; - IpAddress.ReasmSize = 0; - IpAddress.Context = 0; - IpAddress.Pad = 0; - - Count = CopyBufferToBufferChain(Buffer, Temp, (PUCHAR)&IpAddress, sizeof(IPADDR_ENTRY)); - - Temp += sizeof(IPADDR_ENTRY); - } - KeReleaseSpinLock(&InterfaceLock, OldIrql); - return TDI_SUCCESS; - - case IP_MIB_STATS_ID: - if (BufSize < sizeof(IPSNMP_INFO)) - return TDI_BUFFER_TOO_SMALL; - - RtlZeroMemory(&SnmpInfo, sizeof(IPSNMP_INFO)); - - /* Count number of addresses */ - Count = 0; - KeAcquireSpinLock(&InterfaceLock, &OldIrql); - for (IF = InterfaceList; IF != NULL; IF = IF->Next) - Count++; - KeReleaseSpinLock(&InterfaceLock, OldIrql); - - SnmpInfo.NumAddr = Count; - - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&SnmpInfo, sizeof(IPSNMP_INFO)); - - return TDI_SUCCESS; - - default: - /* We can't handle this ID */ - return TDI_INVALID_PARAMETER; - } - } - - return TDI_INVALID_PARAMETER; -} - - -TDI_STATUS InfoTdiQueryInformationEx( - PTDI_REQUEST Request, - TDIObjectID *ID, - PNDIS_BUFFER Buffer, - PUINT BufferSize, - PVOID Context) -/* - * FUNCTION: Returns extended information - * ARGUMENTS: - * Request = Pointer to TDI request structure for the request - * ID = TDI object ID - * Buffer = Pointer to buffer with data to use - * BufferSize = Pointer to buffer with size of Buffer. On return - * this is filled with number of bytes returned - * Context = Pointer to context buffer - * RETURNS: - * Status of operation - */ -{ - PADDRESS_FILE AddrFile; - PADDRESS_ENTRY ADE; - ADDRESS_INFO Info; - KIRQL OldIrql; - UINT Entity; - UINT Count; - UINT Size; - ULONG Temp; - UINT Offset = 0; - UINT BufSize = *BufferSize; - - /* Check wether it is a query for a list of entities */ - Entity = ID->toi_entity.tei_entity; - if (Entity == GENERIC_ENTITY) { - if (ID->toi_class != INFO_CLASS_GENERIC || - ID->toi_type != INFO_TYPE_PROVIDER || - ID->toi_id != ENTITY_LIST_ID) - return TDI_INVALID_PARAMETER; - - *BufferSize = 0; - - Size = EntityCount * sizeof(TDIEntityID); - if (BufSize < Size) - /* The buffer is too small to contain requested data */ - return TDI_BUFFER_TOO_SMALL; - - /* Return entity list */ - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)EntityList, Size); - - *BufferSize = Size; - - return TDI_SUCCESS; - } - - if ((Entity != CL_TL_ENTITY) && (Entity != CO_TL_ENTITY)) { - /* We can't handle this entity, pass it on */ - return IPTdiQueryInformationEx( - Request, ID, Buffer, BufferSize, Context); - } - - /* Make return parameters consistent every time */ - *BufferSize = 0; - - if (ID->toi_entity.tei_instance != TL_INSTANCE) - /* We only support a single instance */ - return TDI_INVALID_REQUEST; - - if (ID->toi_class == INFO_CLASS_GENERIC) { - - if (ID->toi_type != INFO_TYPE_PROVIDER || - ID->toi_id != ENTITY_TYPE_ID) - return TDI_INVALID_PARAMETER; - - if (BufSize < sizeof(ULONG)) - return TDI_BUFFER_TOO_SMALL; - - if (Entity == CL_TL_ENTITY) - Temp = CL_TL_UDP; - else if (Entity == CO_TL_ENTITY) - Temp = CO_TL_TCP; - else - return TDI_INVALID_PARAMETER; - - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG)); - - return TDI_SUCCESS; - } - - if (ID->toi_class == INFO_CLASS_PROTOCOL) { - - if (ID->toi_type != INFO_TYPE_PROVIDER) - return TDI_INVALID_PARAMETER; - - switch (ID->toi_id) { - case UDP_MIB_STAT_ID: - if (Entity != CL_TL_ENTITY) - return TDI_INVALID_PARAMETER; - - if (BufSize < sizeof(UDPStats)) - return TDI_BUFFER_TOO_SMALL; - - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&UDPStats, sizeof(UDP_STATISTICS)); - - return TDI_SUCCESS; - - case UDP_MIB_TABLE_ID: - if (Entity != CL_TL_ENTITY) - return TDI_INVALID_PARAMETER; - - Offset = 0; - - KeAcquireSpinLock(&AddressFileLock, &OldIrql); - - for (AddrFile = AddressFileList; - AddrFile->Next != NULL; - AddrFile = AddrFile->Next) { - - if (Offset + sizeof(ADDRESS_INFO) > BufSize) { - KeReleaseSpinLock(&AddressFileLock, OldIrql); - *BufferSize = Offset; - return TDI_BUFFER_OVERFLOW; - } - - for (ADE = AddrFile->ADE; ADE != NULL; ADE = ADE->Next) { - /* We only care about IPv4 unicast address */ - if ((ADE->Type == ADE_UNICAST) && - (ADE->Address->Type == IP_ADDRESS_V4)) - Info.LocalAddress = ADE->Address->Address.IPv4Address; - } - - Info.LocalPort = AddrFile->Port; - - Count = CopyBufferToBufferChain(Buffer, Offset, (PUCHAR)&Info, sizeof(ADDRESS_INFO)); - - Offset += Count; - } - - KeReleaseSpinLock(&AddressFileLock, OldIrql); - - *BufferSize = Offset; - - return STATUS_SUCCESS; - - default: - /* We can't handle this ID */ - return TDI_INVALID_PARAMETER; - } - } - - return TDI_INVALID_PARAMETER; -} - - -TDI_STATUS InfoTdiSetInformationEx( - PTDI_REQUEST Request, - TDIObjectID *ID, - PVOID Buffer, - UINT BufferSize) -/* - * FUNCTION: Sets extended information - * ARGUMENTS: - * Request = Pointer to TDI request structure for the request - * ID = Pointer to TDI object ID - * Buffer = Pointer to buffer with data to use - * BufferSize = Size of Buffer - * RETURNS: - * Status of operation - */ -{ - /* FIXME: Set extended information */ - - return TDI_INVALID_REQUEST; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: tcpip/info.c + * PURPOSE: TDI query and set information routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/07-2000 Created + */ +#include +#include +#include + + +TDI_STATUS IPTdiQueryInformationEx( + PTDI_REQUEST Request, + TDIObjectID *ID, + PNDIS_BUFFER Buffer, + PUINT BufferSize, + PVOID Context) +/* + * FUNCTION: Returns extended information about network layer + * ARGUMENTS: + * Request = Pointer to TDI request structure for the request + * ID = TDI object ID + * Buffer = Pointer to buffer with data to use. + * BufferSize = Pointer to buffer with size of Buffer. On return + * this is filled with number of bytes returned + * Context = Pointer to context buffer + * RETURNS: + * Status of operation + */ +{ + IPADDR_ENTRY IpAddress; + IPSNMP_INFO SnmpInfo; + PADDRESS_ENTRY ADE; + PIP_INTERFACE IF; + ULONG Temp; + UINT Count; + ULONG Entity; + KIRQL OldIrql; + UINT BufSize = *BufferSize; + + /* Make return parameters consistent every time */ + *BufferSize = 0; + + Entity = ID->toi_entity.tei_entity; + if (Entity != CL_NL_ENTITY) { + /* We can't handle this entity */ + return TDI_INVALID_PARAMETER; + } + + if (ID->toi_entity.tei_instance != TL_INSTANCE) + /* We only support a single instance */ + return TDI_INVALID_REQUEST; + if (ID->toi_class == INFO_CLASS_GENERIC) { + if (ID->toi_type == INFO_TYPE_PROVIDER && + ID->toi_id == ENTITY_TYPE_ID) { + + if (BufSize < sizeof(ULONG)) + return TDI_BUFFER_TOO_SMALL; + Temp = CL_NL_IP; + + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG)); + + return TDI_SUCCESS; + } + return TDI_INVALID_PARAMETER; + } + + if (ID->toi_class == INFO_CLASS_PROTOCOL) { + if (ID->toi_type != INFO_TYPE_PROVIDER) + return TDI_INVALID_PARAMETER; + + switch (ID->toi_id) { + case IP_MIB_ADDRTABLE_ENTRY_ID: + Temp = 0; + + KeAcquireSpinLock(&InterfaceLock, &OldIrql); +/* + /* Search the interface list */ + CurrentIFEntry = InterfaceListHead.Flink; + while (CurrentIFEntry != &InterfaceListHead) { + CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); + if (CurrentIF != Loopback) { + /* Search the address entry list and return the first appropriate ADE found */ + CurrentADEEntry = CurrentIF->ADEListHead.Flink; + while (CurrentADEEntry != &CurrentIF->ADEListHead) { + CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); + if (CurrentADE->Type == AddressType) + ReferenceAddress(CurrentADE->Address); + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + return CurrentADE; + } + CurrentADEEntry = CurrentADEEntry->Flink; + } else + LoopbackIsRegistered = TRUE; + CurrentIFEntry = CurrentIFEntry->Flink; + } + + + */ + for (IF = InterfaceList; IF != NULL; IF = IF->Next) { + if (Temp + sizeof(IPADDR_ENTRY) > BufSize) { + KeReleaseSpinLock(&InterfaceLock, OldIrql); + return TDI_BUFFER_TOO_SMALL; + } + + IpAddress.Addr = 0; + IpAddress.BcastAddr = 0; + IpAddress.Mask = 0; + /* Locate the diffrent addresses and put them the right place */ + for (ADE = IF->ADE; ADE != NULL; ADE = ADE->Next) { + switch (ADE->Type) { + case ADE_UNICAST : IpAddress.Addr = ADE->Address->Address.IPv4Address; + case ADE_MULTICAST: IpAddress.BcastAddr = ADE->Address->Address.IPv4Address; + case ADE_ADDRMASK : IpAddress.Mask = ADE->Address->Address.IPv4Address; + } + } + /* Pack the address information into IPADDR_ENTRY structure */ + IpAddress.Index = 0; + IpAddress.ReasmSize = 0; + IpAddress.Context = 0; + IpAddress.Pad = 0; + + Count = CopyBufferToBufferChain(Buffer, Temp, (PUCHAR)&IpAddress, sizeof(IPADDR_ENTRY)); + + Temp += sizeof(IPADDR_ENTRY); + } + KeReleaseSpinLock(&InterfaceLock, OldIrql); + return TDI_SUCCESS; + + case IP_MIB_STATS_ID: + if (BufSize < sizeof(IPSNMP_INFO)) + return TDI_BUFFER_TOO_SMALL; + + RtlZeroMemory(&SnmpInfo, sizeof(IPSNMP_INFO)); + + /* Count number of addresses */ + Count = 0; + KeAcquireSpinLock(&InterfaceLock, &OldIrql); + for (IF = InterfaceList; IF != NULL; IF = IF->Next) + Count++; + KeReleaseSpinLock(&InterfaceLock, OldIrql); + + SnmpInfo.NumAddr = Count; + + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&SnmpInfo, sizeof(IPSNMP_INFO)); + + return TDI_SUCCESS; + + default: + /* We can't handle this ID */ + return TDI_INVALID_PARAMETER; + } + } + + return TDI_INVALID_PARAMETER; +} + + +TDI_STATUS InfoTdiQueryInformationEx( + PTDI_REQUEST Request, + TDIObjectID *ID, + PNDIS_BUFFER Buffer, + PUINT BufferSize, + PVOID Context) +/* + * FUNCTION: Returns extended information + * ARGUMENTS: + * Request = Pointer to TDI request structure for the request + * ID = TDI object ID + * Buffer = Pointer to buffer with data to use + * BufferSize = Pointer to buffer with size of Buffer. On return + * this is filled with number of bytes returned + * Context = Pointer to context buffer + * RETURNS: + * Status of operation + */ +{ + PADDRESS_FILE AddrFile; + PADDRESS_ENTRY ADE; + ADDRESS_INFO Info; + KIRQL OldIrql; + UINT Entity; + UINT Count; + UINT Size; + ULONG Temp; + UINT Offset = 0; + UINT BufSize = *BufferSize; + + /* Check wether it is a query for a list of entities */ + Entity = ID->toi_entity.tei_entity; + if (Entity == GENERIC_ENTITY) { + if (ID->toi_class != INFO_CLASS_GENERIC || + ID->toi_type != INFO_TYPE_PROVIDER || + ID->toi_id != ENTITY_LIST_ID) + return TDI_INVALID_PARAMETER; + + *BufferSize = 0; + + Size = EntityCount * sizeof(TDIEntityID); + if (BufSize < Size) + /* The buffer is too small to contain requested data */ + return TDI_BUFFER_TOO_SMALL; + + /* Return entity list */ + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)EntityList, Size); + + *BufferSize = Size; + + return TDI_SUCCESS; + } + + if ((Entity != CL_TL_ENTITY) && (Entity != CO_TL_ENTITY)) { + /* We can't handle this entity, pass it on */ + return IPTdiQueryInformationEx( + Request, ID, Buffer, BufferSize, Context); + } + + /* Make return parameters consistent every time */ + *BufferSize = 0; + + if (ID->toi_entity.tei_instance != TL_INSTANCE) + /* We only support a single instance */ + return TDI_INVALID_REQUEST; + + if (ID->toi_class == INFO_CLASS_GENERIC) { + + if (ID->toi_type != INFO_TYPE_PROVIDER || + ID->toi_id != ENTITY_TYPE_ID) + return TDI_INVALID_PARAMETER; + + if (BufSize < sizeof(ULONG)) + return TDI_BUFFER_TOO_SMALL; + + if (Entity == CL_TL_ENTITY) + Temp = CL_TL_UDP; + else if (Entity == CO_TL_ENTITY) + Temp = CO_TL_TCP; + else + return TDI_INVALID_PARAMETER; + + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG)); + + return TDI_SUCCESS; + } + + if (ID->toi_class == INFO_CLASS_PROTOCOL) { + + if (ID->toi_type != INFO_TYPE_PROVIDER) + return TDI_INVALID_PARAMETER; + + switch (ID->toi_id) { + case UDP_MIB_STAT_ID: + if (Entity != CL_TL_ENTITY) + return TDI_INVALID_PARAMETER; + + if (BufSize < sizeof(UDPStats)) + return TDI_BUFFER_TOO_SMALL; + + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&UDPStats, sizeof(UDP_STATISTICS)); + + return TDI_SUCCESS; + + case UDP_MIB_TABLE_ID: + if (Entity != CL_TL_ENTITY) + return TDI_INVALID_PARAMETER; + + Offset = 0; + + KeAcquireSpinLock(&AddressFileLock, &OldIrql); + + for (AddrFile = AddressFileList; + AddrFile->Next != NULL; + AddrFile = AddrFile->Next) { + + if (Offset + sizeof(ADDRESS_INFO) > BufSize) { + KeReleaseSpinLock(&AddressFileLock, OldIrql); + *BufferSize = Offset; + return TDI_BUFFER_OVERFLOW; + } + + for (ADE = AddrFile->ADE; ADE != NULL; ADE = ADE->Next) { + /* We only care about IPv4 unicast address */ + if ((ADE->Type == ADE_UNICAST) && + (ADE->Address->Type == IP_ADDRESS_V4)) + Info.LocalAddress = ADE->Address->Address.IPv4Address; + } + + Info.LocalPort = AddrFile->Port; + + Count = CopyBufferToBufferChain(Buffer, Offset, (PUCHAR)&Info, sizeof(ADDRESS_INFO)); + + Offset += Count; + } + + KeReleaseSpinLock(&AddressFileLock, OldIrql); + + *BufferSize = Offset; + + return STATUS_SUCCESS; + + default: + /* We can't handle this ID */ + return TDI_INVALID_PARAMETER; + } + } + + return TDI_INVALID_PARAMETER; +} + + +TDI_STATUS InfoTdiSetInformationEx( + PTDI_REQUEST Request, + TDIObjectID *ID, + PVOID Buffer, + UINT BufferSize) +/* + * FUNCTION: Sets extended information + * ARGUMENTS: + * Request = Pointer to TDI request structure for the request + * ID = Pointer to TDI object ID + * Buffer = Pointer to buffer with data to use + * BufferSize = Size of Buffer + * RETURNS: + * Status of operation + */ +{ + /* FIXME: Set extended information */ + + return TDI_INVALID_REQUEST; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/Makefile b/reactos/drivers/net/tcpip/tcpip/Makefile index 9c985f57bc6..58189757d61 100644 --- a/reactos/drivers/net/tcpip/tcpip/Makefile +++ b/reactos/drivers/net/tcpip/tcpip/Makefile @@ -1,7 +1,7 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/reactos/drivers/net/tcpip/tcpip/SOURCES b/reactos/drivers/net/tcpip/tcpip/SOURCES index e39f49ad634..6e2029178bb 100644 --- a/reactos/drivers/net/tcpip/tcpip/SOURCES +++ b/reactos/drivers/net/tcpip/tcpip/SOURCES @@ -1,28 +1,28 @@ -TARGETNAME=tcpip -TARGETPATH=..\objects -TARGETTYPE=EXPORT_DRIVER - -TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ - $(DDK_LIB_PATH)\ndis.lib \ - ..\objects\*\free\datagram.lib \ - ..\objects\*\free\datalink.lib \ - ..\objects\*\free\network.lib \ - ..\objects\*\free\rawip.lib \ - ..\objects\*\free\tcp.lib \ - ..\objects\*\free\udp.lib - -INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net - - -SOURCES= address.c \ - checksum.c \ - dispatch.c \ - fileobjs.c \ - info.c \ - main.c \ - pool.c \ - routines.c \ - RESOURCE.RC - -MSC_WARNING_LEVEL=/W3 /WX - +TARGETNAME=tcpip +TARGETPATH=..\objects +TARGETTYPE=EXPORT_DRIVER + +TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ + $(DDK_LIB_PATH)\ndis.lib \ + ..\objects\*\free\datagram.lib \ + ..\objects\*\free\datalink.lib \ + ..\objects\*\free\network.lib \ + ..\objects\*\free\rawip.lib \ + ..\objects\*\free\tcp.lib \ + ..\objects\*\free\udp.lib + +INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net + + +SOURCES= address.c \ + checksum.c \ + dispatch.c \ + fileobjs.c \ + info.c \ + main.c \ + pool.c \ + routines.c \ + RESOURCE.RC + +MSC_WARNING_LEVEL=/W3 /WX + diff --git a/reactos/drivers/net/tcpip/tcpip/address.c b/reactos/drivers/net/tcpip/tcpip/address.c index eba0e2c064b..1c80aecbbe1 100644 --- a/reactos/drivers/net/tcpip/tcpip/address.c +++ b/reactos/drivers/net/tcpip/tcpip/address.c @@ -1,312 +1,312 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: tcpip/address.c - * PURPOSE: Routines for handling addresses - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include - - -BOOLEAN AddrIsUnspecified( - PIP_ADDRESS Address) -/* - * FUNCTION: Return wether IP address is an unspecified address - * ARGUMENTS: - * Address = Pointer to an IP address structure - * RETURNS: - * TRUE if the IP address is an unspecified address, FALSE if not - */ -{ - switch (Address->Type) { - case IP_ADDRESS_V4: - return (Address->Address.IPv4Address == 0); - - case IP_ADDRESS_V6: - /* FIXME: IPv6 is not supported */ - default: - return FALSE; - } -} - - -/* - * FUNCTION: Extract IP address from TDI address structure - * ARGUMENTS: - * AddrList = Pointer to transport address list to extract from - * Address = Address of a pointer to where an IP address is stored - * Port = Pointer to where port number is stored - * Cache = Address of pointer to a cached address (updated on return) - * RETURNS: - * Status of operation - */ -NTSTATUS AddrGetAddress( - PTRANSPORT_ADDRESS AddrList, - PIP_ADDRESS *Address, - PUSHORT Port, - PIP_ADDRESS *Cache) -{ - PTA_ADDRESS CurAddr; - INT i; - - /* We can only use IP addresses. Search the list until we find one */ - CurAddr = AddrList->Address; - - for (i = 0; i < AddrList->TAAddressCount; i++) { - switch (CurAddr->AddressType) { - case TDI_ADDRESS_TYPE_IP: - if (CurAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP) { - /* This is an IPv4 address */ - PIP_ADDRESS IPAddress; - PTDI_ADDRESS_IP ValidAddr = (PTDI_ADDRESS_IP)CurAddr->Address; - - *Port = ValidAddr->sin_port; - - if (*Cache) { - if (((*Cache)->Type == IP_ADDRESS_V4) && - ((*Cache)->Address.IPv4Address == ValidAddr->in_addr)) { - *Address = *Cache; - return STATUS_SUCCESS; - } else { - /* Release the cached address as we cannot use it this time */ - DereferenceObject(*Cache); - *Cache = NULL; - } - } - - IPAddress = PoolAllocateBuffer(sizeof(IP_ADDRESS)); - if (IPAddress) { - AddrInitIPv4(IPAddress, ValidAddr->in_addr); - *Address = IPAddress; - - /* Update address cache */ - *Cache = IPAddress; - ReferenceObject(*Cache); - return STATUS_SUCCESS; - } else - return STATUS_INSUFFICIENT_RESOURCES; - } else - return STATUS_INVALID_ADDRESS; - default: - /* This is an unsupported address type. - Skip it and go to the next in the list */ - CurAddr = (PTA_ADDRESS)((ULONG_PTR)CurAddr->Address + CurAddr->AddressLength); - } - } - - return STATUS_INVALID_ADDRESS; -} - - -/* - * FUNCTION: Returns wether two addresses are equal - * ARGUMENTS: - * Address1 = Pointer to first address - * Address2 = Pointer to last address - * RETURNS: - * TRUE if Address1 = Address2, FALSE if not - */ -BOOLEAN AddrIsEqual( - PIP_ADDRESS Address1, - PIP_ADDRESS Address2) -{ - if (Address1->Type != Address2->Type) - return FALSE; - - switch (Address1->Type) { - case IP_ADDRESS_V4: - return (Address1->Address.IPv4Address == Address2->Address.IPv4Address); - - case IP_ADDRESS_V6: - return (RtlCompareMemory(&Address1->Address, &Address2->Address, - sizeof(IPv6_RAW_ADDRESS)) == sizeof(IPv6_RAW_ADDRESS)); - break; - } - - return FALSE; -} - - -/* - * FUNCTION: Returns wether Address1 is less than Address2 - * ARGUMENTS: - * Address1 = Pointer to first address - * Address2 = Pointer to last address - * RETURNS: - * -1 if Address1 < Address2, 1 if Address1 > Address2, - * or 0 if they are equal - */ -INT AddrCompare( - PIP_ADDRESS Address1, - PIP_ADDRESS Address2) -{ - switch (Address1->Type) { - case IP_ADDRESS_V4: { - ULONG Addr1, Addr2; - if (Address2->Type == IP_ADDRESS_V4) { - Addr1 = DN2H(Address1->Address.IPv4Address); - Addr2 = DN2H(Address2->Address.IPv4Address); - if (Addr1 < Addr2) - return -1; - else - if (Addr1 == Addr2) - return 0; - else - return 1; - } else - /* FIXME: Support IPv6 */ - return -1; - - case IP_ADDRESS_V6: - /* FIXME: Support IPv6 */ - break; - } - } - - return FALSE; -} - - -/* - * FUNCTION: Returns wether two addresses are equal with IPv4 as input - * ARGUMENTS: - * Address1 = Pointer to first address - * Address2 = Pointer to last address - * RETURNS: - * TRUE if Address1 = Address2, FALSE if not - */ -BOOLEAN AddrIsEqualIPv4( - PIP_ADDRESS Address1, - IPv4_RAW_ADDRESS Address2) -{ - if (Address1->Type == IP_ADDRESS_V4) - return (Address1->Address.IPv4Address == Address2); - - return FALSE; -} - - -/* - * FUNCTION: Build an IPv4 style address - * ARGUMENTS: - * Address = Raw IPv4 address - * RETURNS: - * Pointer to IP address structure, NULL if there was not enough free - * non-paged memory - */ -PIP_ADDRESS AddrBuildIPv4( - IPv4_RAW_ADDRESS Address) -{ - PIP_ADDRESS IPAddress; - - IPAddress = PoolAllocateBuffer(sizeof(IP_ADDRESS)); - if (IPAddress) { - IPAddress->RefCount = 1; - IPAddress->Type = IP_ADDRESS_V4; - IPAddress->Address.IPv4Address = Address; - } - - return IPAddress; -} - - -/* - * FUNCTION: Locates and returns an address entry using IPv4 adress as argument - * ARGUMENTS: - * Address = Raw IPv4 address - * RETURNS: - * Pointer to address entry if found, NULL if not found - * NOTES: - * Only unicast addresses are considered. - * If found, the address is referenced - */ -PADDRESS_ENTRY AddrLocateADEv4( - IPv4_RAW_ADDRESS Address) -{ - IP_ADDRESS Addr; - - AddrInitIPv4(&Addr, Address); - - return IPLocateADE(&Addr, ADE_UNICAST); -} - - -/* - * 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) -{ - SearchContext->Address = Address; - SearchContext->Port = Port; - SearchContext->Next = AddressFileListHead.Flink; - SearchContext->Protocol = Protocol; - - return AddrSearchNext(SearchContext); -} - - -/* - * FUNCTION: Searches through address file entries to find next match - * ARGUMENTS: - * SearchContext = Pointer to search context - * RETURNS: - * Pointer to 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; - - if (IsListEmpty(SearchContext->Next)) - return NULL; - - CurrentEntry = SearchContext->Next; - - KeAcquireSpinLock(&AddressFileListLock, &OldIrql); - - while (CurrentEntry != &AddressFileListHead) { - Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry); - - /* See if this address matches the search criteria */ - IPAddress = Current->ADE->Address; - if (((Current->Port == SearchContext->Port) && - (Current->Protocol == SearchContext->Protocol) && - (AddrIsEqual(IPAddress, SearchContext->Address))) || - (AddrIsUnspecified(IPAddress))) { - /* We've found a match */ - Found = TRUE; - break; - } - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&AddressFileListLock, OldIrql); - - if (Found) { - SearchContext->Next = CurrentEntry->Flink; - return Current; - } else - return NULL; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: tcpip/address.c + * PURPOSE: Routines for handling addresses + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include + + +BOOLEAN AddrIsUnspecified( + PIP_ADDRESS Address) +/* + * FUNCTION: Return wether IP address is an unspecified address + * ARGUMENTS: + * Address = Pointer to an IP address structure + * RETURNS: + * TRUE if the IP address is an unspecified address, FALSE if not + */ +{ + switch (Address->Type) { + case IP_ADDRESS_V4: + return (Address->Address.IPv4Address == 0); + + case IP_ADDRESS_V6: + /* FIXME: IPv6 is not supported */ + default: + return FALSE; + } +} + + +/* + * FUNCTION: Extract IP address from TDI address structure + * ARGUMENTS: + * AddrList = Pointer to transport address list to extract from + * Address = Address of a pointer to where an IP address is stored + * Port = Pointer to where port number is stored + * Cache = Address of pointer to a cached address (updated on return) + * RETURNS: + * Status of operation + */ +NTSTATUS AddrGetAddress( + PTRANSPORT_ADDRESS AddrList, + PIP_ADDRESS *Address, + PUSHORT Port, + PIP_ADDRESS *Cache) +{ + PTA_ADDRESS CurAddr; + INT i; + + /* We can only use IP addresses. Search the list until we find one */ + CurAddr = AddrList->Address; + + for (i = 0; i < AddrList->TAAddressCount; i++) { + switch (CurAddr->AddressType) { + case TDI_ADDRESS_TYPE_IP: + if (CurAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP) { + /* This is an IPv4 address */ + PIP_ADDRESS IPAddress; + PTDI_ADDRESS_IP ValidAddr = (PTDI_ADDRESS_IP)CurAddr->Address; + + *Port = ValidAddr->sin_port; + + if (*Cache) { + if (((*Cache)->Type == IP_ADDRESS_V4) && + ((*Cache)->Address.IPv4Address == ValidAddr->in_addr)) { + *Address = *Cache; + return STATUS_SUCCESS; + } else { + /* Release the cached address as we cannot use it this time */ + DereferenceObject(*Cache); + *Cache = NULL; + } + } + + IPAddress = PoolAllocateBuffer(sizeof(IP_ADDRESS)); + if (IPAddress) { + AddrInitIPv4(IPAddress, ValidAddr->in_addr); + *Address = IPAddress; + + /* Update address cache */ + *Cache = IPAddress; + ReferenceObject(*Cache); + return STATUS_SUCCESS; + } else + return STATUS_INSUFFICIENT_RESOURCES; + } else + return STATUS_INVALID_ADDRESS; + default: + /* This is an unsupported address type. + Skip it and go to the next in the list */ + CurAddr = (PTA_ADDRESS)((ULONG_PTR)CurAddr->Address + CurAddr->AddressLength); + } + } + + return STATUS_INVALID_ADDRESS; +} + + +/* + * FUNCTION: Returns wether two addresses are equal + * ARGUMENTS: + * Address1 = Pointer to first address + * Address2 = Pointer to last address + * RETURNS: + * TRUE if Address1 = Address2, FALSE if not + */ +BOOLEAN AddrIsEqual( + PIP_ADDRESS Address1, + PIP_ADDRESS Address2) +{ + if (Address1->Type != Address2->Type) + return FALSE; + + switch (Address1->Type) { + case IP_ADDRESS_V4: + return (Address1->Address.IPv4Address == Address2->Address.IPv4Address); + + case IP_ADDRESS_V6: + return (RtlCompareMemory(&Address1->Address, &Address2->Address, + sizeof(IPv6_RAW_ADDRESS)) == sizeof(IPv6_RAW_ADDRESS)); + break; + } + + return FALSE; +} + + +/* + * FUNCTION: Returns wether Address1 is less than Address2 + * ARGUMENTS: + * Address1 = Pointer to first address + * Address2 = Pointer to last address + * RETURNS: + * -1 if Address1 < Address2, 1 if Address1 > Address2, + * or 0 if they are equal + */ +INT AddrCompare( + PIP_ADDRESS Address1, + PIP_ADDRESS Address2) +{ + switch (Address1->Type) { + case IP_ADDRESS_V4: { + ULONG Addr1, Addr2; + if (Address2->Type == IP_ADDRESS_V4) { + Addr1 = DN2H(Address1->Address.IPv4Address); + Addr2 = DN2H(Address2->Address.IPv4Address); + if (Addr1 < Addr2) + return -1; + else + if (Addr1 == Addr2) + return 0; + else + return 1; + } else + /* FIXME: Support IPv6 */ + return -1; + + case IP_ADDRESS_V6: + /* FIXME: Support IPv6 */ + break; + } + } + + return FALSE; +} + + +/* + * FUNCTION: Returns wether two addresses are equal with IPv4 as input + * ARGUMENTS: + * Address1 = Pointer to first address + * Address2 = Pointer to last address + * RETURNS: + * TRUE if Address1 = Address2, FALSE if not + */ +BOOLEAN AddrIsEqualIPv4( + PIP_ADDRESS Address1, + IPv4_RAW_ADDRESS Address2) +{ + if (Address1->Type == IP_ADDRESS_V4) + return (Address1->Address.IPv4Address == Address2); + + return FALSE; +} + + +/* + * FUNCTION: Build an IPv4 style address + * ARGUMENTS: + * Address = Raw IPv4 address + * RETURNS: + * Pointer to IP address structure, NULL if there was not enough free + * non-paged memory + */ +PIP_ADDRESS AddrBuildIPv4( + IPv4_RAW_ADDRESS Address) +{ + PIP_ADDRESS IPAddress; + + IPAddress = PoolAllocateBuffer(sizeof(IP_ADDRESS)); + if (IPAddress) { + IPAddress->RefCount = 1; + IPAddress->Type = IP_ADDRESS_V4; + IPAddress->Address.IPv4Address = Address; + } + + return IPAddress; +} + + +/* + * FUNCTION: Locates and returns an address entry using IPv4 adress as argument + * ARGUMENTS: + * Address = Raw IPv4 address + * RETURNS: + * Pointer to address entry if found, NULL if not found + * NOTES: + * Only unicast addresses are considered. + * If found, the address is referenced + */ +PADDRESS_ENTRY AddrLocateADEv4( + IPv4_RAW_ADDRESS Address) +{ + IP_ADDRESS Addr; + + AddrInitIPv4(&Addr, Address); + + return IPLocateADE(&Addr, ADE_UNICAST); +} + + +/* + * 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) +{ + SearchContext->Address = Address; + SearchContext->Port = Port; + SearchContext->Next = AddressFileListHead.Flink; + SearchContext->Protocol = Protocol; + + return AddrSearchNext(SearchContext); +} + + +/* + * FUNCTION: Searches through address file entries to find next match + * ARGUMENTS: + * SearchContext = Pointer to search context + * RETURNS: + * Pointer to 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; + + if (IsListEmpty(SearchContext->Next)) + return NULL; + + CurrentEntry = SearchContext->Next; + + KeAcquireSpinLock(&AddressFileListLock, &OldIrql); + + while (CurrentEntry != &AddressFileListHead) { + Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry); + + /* See if this address matches the search criteria */ + IPAddress = Current->ADE->Address; + if (((Current->Port == SearchContext->Port) && + (Current->Protocol == SearchContext->Protocol) && + (AddrIsEqual(IPAddress, SearchContext->Address))) || + (AddrIsUnspecified(IPAddress))) { + /* We've found a match */ + Found = TRUE; + break; + } + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&AddressFileListLock, OldIrql); + + if (Found) { + SearchContext->Next = CurrentEntry->Flink; + return Current; + } else + return NULL; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/checksum.c b/reactos/drivers/net/tcpip/tcpip/checksum.c index b43b29a6f80..72c08e8fa5d 100644 --- a/reactos/drivers/net/tcpip/tcpip/checksum.c +++ b/reactos/drivers/net/tcpip/tcpip/checksum.c @@ -1,50 +1,50 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: tcpip/checksum.c - * PURPOSE: Checksum routines - * NOTES: The checksum routine is from RFC 1071 - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include - - -ULONG ChecksumCompute( - PVOID Data, - UINT Count, - ULONG Seed) -/* - * FUNCTION: Calculate checksum of a buffer - * ARGUMENTS: - * Data = Pointer to buffer with data - * Count = Number of bytes in buffer - * Seed = Previously calculated checksum (if any) - * RETURNS: - * Checksum of buffer - */ -{ - /* FIXME: This should be done in assembler */ - - register ULONG Sum = Seed; - - while (Count > 1) { - Sum += *(PUSHORT)Data; - Count -= 2; - (ULONG_PTR)Data += 2; - } - - /* Add left-over byte, if any */ - if (Count > 0) - Sum += *(PUCHAR)Data; - - /* Fold 32-bit sum to 16 bits */ - while (Sum >> 16) - Sum = (Sum & 0xFFFF) + (Sum >> 16); - - return ~Sum; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: tcpip/checksum.c + * PURPOSE: Checksum routines + * NOTES: The checksum routine is from RFC 1071 + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include + + +ULONG ChecksumCompute( + PVOID Data, + UINT Count, + ULONG Seed) +/* + * FUNCTION: Calculate checksum of a buffer + * ARGUMENTS: + * Data = Pointer to buffer with data + * Count = Number of bytes in buffer + * Seed = Previously calculated checksum (if any) + * RETURNS: + * Checksum of buffer + */ +{ + /* FIXME: This should be done in assembler */ + + register ULONG Sum = Seed; + + while (Count > 1) { + Sum += *(PUSHORT)Data; + Count -= 2; + (ULONG_PTR)Data += 2; + } + + /* Add left-over byte, if any */ + if (Count > 0) + Sum += *(PUCHAR)Data; + + /* Fold 32-bit sum to 16 bits */ + while (Sum >> 16) + Sum = (Sum & 0xFFFF) + (Sum >> 16); + + return ~Sum; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/dispatch.c b/reactos/drivers/net/tcpip/tcpip/dispatch.c index 5d91ff3a4e4..600d88fc923 100644 --- a/reactos/drivers/net/tcpip/tcpip/dispatch.c +++ b/reactos/drivers/net/tcpip/tcpip/dispatch.c @@ -1,871 +1,871 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: tcpip/dispatch.h - * PURPOSE: TDI dispatch routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include - - -NTSTATUS DispPrepareIrpForCancel( - PTRANSPORT_CONTEXT Context, - PIRP Irp, - PDRIVER_CANCEL CancelRoutine) -/* - * FUNCTION: Prepare an IRP for cancellation - * ARGUMENTS: - * Context = Pointer to context information - * Irp = Pointer to an I/O request packet - * CancelRoutine = Routine to be called when I/O request is cancelled - * RETURNS: - * Status of operation - */ -{ - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - IoAcquireCancelSpinLock(&OldIrql); - - if (!Irp->Cancel) { - IoMarkIrpPending(Irp); - IoSetCancelRoutine(Irp, CancelRoutine); - Context->RefCount++; - IoReleaseCancelSpinLock(OldIrql); - - TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP at 0x%X can now be cancelled).\n", Irp)); - - return STATUS_SUCCESS; - } - - /* IRP has already been cancelled */ - - IoReleaseCancelSpinLock(OldIrql); - - Irp->IoStatus.Status = STATUS_CANCELLED; - Irp->IoStatus.Information = 0; - - TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); - - IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); - - TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP was already cancelled).\n")); - - return STATUS_CANCELLED; -} - - -VOID DispCancelComplete( - PVOID Context) -/* - * FUNCTION: Completes a cancel request - * ARGUMENTS: - * Context = Pointer to context information (FILE_OBJECT) - */ -{ - KIRQL OldIrql; - PFILE_OBJECT FileObject; - PTRANSPORT_CONTEXT TranContext; - - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - FileObject = (PFILE_OBJECT)Context; - TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext; - - IoAcquireCancelSpinLock(&OldIrql); - - /* Remove the reference placed on the endpoint by the cancel routine. - The cancelled IRP will be completed by the completion routine for - the request */ - TranContext->RefCount--; - - if (TranContext->RefCount == 0) { - TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n")); - /* Set the cleanup event */ - KeSetEvent(&TranContext->CleanupEvent, 0, FALSE); - } - - TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount)); - - IoReleaseCancelSpinLock(OldIrql); - - TI_DbgPrint(DEBUG_IRP, ("Leaving.\n")); -} - - -VOID DispCancelRequest( - PDEVICE_OBJECT Device, - PIRP Irp) -/* - * FUNCTION: Cancels an IRP - * ARGUMENTS: - * Device = Pointer to device object - * Irp = Pointer to an I/O request packet - */ -{ - PIO_STACK_LOCATION IrpSp; - PTRANSPORT_CONTEXT TranContext; - PFILE_OBJECT FileObject; - UCHAR MinorFunction; - NTSTATUS Status = STATUS_SUCCESS; - - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - FileObject = IrpSp->FileObject; - TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext; - MinorFunction = IrpSp->MinorFunction; - - TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X) MinorFunction (0x%X) IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp)); - -#ifdef DBG - if (!Irp->Cancel) - TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n")); -#endif - - /* Increase reference count to prevent accidential closure - of the object while inside the cancel routine */ - TranContext->RefCount++; - - IoReleaseCancelSpinLock(Irp->CancelIrql); - - /* Try canceling the request */ - switch(MinorFunction) { - case TDI_SEND: - - case TDI_RECEIVE: - /* FIXME: Close connection */ - break; - - case TDI_SEND_DATAGRAM: - if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) { - TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n")); - break; - } - - DGCancelSendRequest(TranContext->Handle.AddressHandle, Irp); - break; - - case TDI_RECEIVE_DATAGRAM: - if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) { - TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n")); - break; - } - - DGCancelReceiveRequest(TranContext->Handle.AddressHandle, Irp); - break; - - default: - TI_DbgPrint(MIN_TRACE, ("Unknown IRP. MinorFunction (0x%X).\n", MinorFunction)); - break; - } - - if (Status != STATUS_PENDING) - DispCancelComplete(FileObject); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); -} - - -VOID DispDataRequestComplete( - PVOID Context, - NTSTATUS Status, - ULONG Count) -/* - * FUNCTION: Completes a send/receive IRP - * ARGUMENTS: - * Context = Pointer to context information (IRP) - * Status = Status of the request - * Count = Number of bytes sent or received - */ -{ - PIRP Irp; - PIO_STACK_LOCATION IrpSp; - PTRANSPORT_CONTEXT TranContext; - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - Irp = (PIRP)Context; - IrpSp = IoGetCurrentIrpStackLocation(Irp); - TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; - - IoAcquireCancelSpinLock(&OldIrql); - - IoSetCancelRoutine(Irp, NULL); - TranContext->RefCount--; - TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount)); - if (TranContext->RefCount == 0) { - TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n")); - - KeSetEvent(&TranContext->CleanupEvent, 0, FALSE); - } - - if (Irp->Cancel || TranContext->CancelIrps) { - /* The IRP has been cancelled */ - - TI_DbgPrint(DEBUG_IRP, ("IRP is cancelled.\n")); - - Status = STATUS_CANCELLED; - Count = 0; - } - - IoReleaseCancelSpinLock(OldIrql); - - Irp->IoStatus.Status = Status; - Irp->IoStatus.Information = Count; - - TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); - - IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); -} - - -NTSTATUS DispTdiAccept( - PIRP Irp) -/* - * FUNCTION: TDI_ACCEPT handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS DispTdiAssociateAddress( - PIRP Irp) -/* - * FUNCTION: TDI_ASSOCIATE_ADDRESS handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS DispTdiConnect( - PIRP Irp) -/* - * FUNCTION: TDI_CONNECT handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS DispTdiDisassociateAddress( - PIRP Irp) -/* - * FUNCTION: TDI_DISASSOCIATE_ADDRESS handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS DispTdiDisconnect( - PIRP Irp) -/* - * FUNCTION: TDI_DISCONNECT handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS DispTdiListen( - PIRP Irp) -/* - * FUNCTION: TDI_LISTEN handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS DispTdiQueryInformation( - PDEVICE_OBJECT DeviceObject, - PIRP Irp) -/* - * FUNCTION: TDI_QUERY_INFORMATION handler - * ARGUMENTS: - * DeviceObject = Pointer to device object structure - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS DispTdiReceive( - PIRP Irp) -/* - * FUNCTION: TDI_RECEIVE handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS DispTdiReceiveDatagram( - PIRP Irp) -/* - * FUNCTION: TDI_RECEIVE_DATAGRAM handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - PIO_STACK_LOCATION IrpSp; - PTDI_REQUEST_KERNEL_RECEIVEDG DgramInfo; - PTRANSPORT_CONTEXT TranContext; - TDI_REQUEST Request; - NTSTATUS Status; - ULONG BytesReceived; - - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - DgramInfo = (PTDI_REQUEST_KERNEL_RECEIVEDG)&(IrpSp->Parameters); - - TranContext = IrpSp->FileObject->FsContext; - /* Initialize a receive request */ - Request.Handle.AddressHandle = TranContext->Handle.AddressHandle; - Request.RequestNotifyObject = DispDataRequestComplete; - Request.RequestContext = Irp; - Status = DispPrepareIrpForCancel(IrpSp->FileObject->FsContext, Irp, (PDRIVER_CANCEL)DispCancelRequest); - if (NT_SUCCESS(Status)) { - Status = UDPReceiveDatagram(&Request, - DgramInfo->ReceiveDatagramInformation, - (PNDIS_BUFFER)Irp->MdlAddress, - DgramInfo->ReceiveLength, - DgramInfo->ReceiveFlags, - DgramInfo->ReturnDatagramInformation, - &BytesReceived); - if (Status != STATUS_PENDING) { - DispDataRequestComplete(Irp, Status, BytesReceived); - /* Return STATUS_PENDING because DispPrepareIrpForCancel marks Irp as pending */ - Status = STATUS_PENDING; - } - } - - TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status)); - - return Status; -} - - -NTSTATUS DispTdiSend( - PIRP Irp) -/* - * FUNCTION: TDI_SEND handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -NTSTATUS DispTdiSendDatagram( - PIRP Irp) -/* - * FUNCTION: TDI_SEND_DATAGRAM handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - PIO_STACK_LOCATION IrpSp; - TDI_REQUEST Request; - PTDI_REQUEST_KERNEL_SENDDG DgramInfo; - PTRANSPORT_CONTEXT TranContext; - NTSTATUS Status; - - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - DgramInfo = (PTDI_REQUEST_KERNEL_SENDDG)&(IrpSp->Parameters); - - TranContext = IrpSp->FileObject->FsContext; - /* Initialize a send request */ - Request.Handle.AddressHandle = TranContext->Handle.AddressHandle; - Request.RequestNotifyObject = DispDataRequestComplete; - Request.RequestContext = Irp; - - Status = DispPrepareIrpForCancel(IrpSp->FileObject->FsContext, Irp, (PDRIVER_CANCEL)DispCancelRequest); - if (NT_SUCCESS(Status)) { - - /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress - must be of type PTDI_ADDRESS_IP */ - - Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)( - &Request, DgramInfo->SendDatagramInformation, - (PNDIS_BUFFER)Irp->MdlAddress, DgramInfo->SendLength); - if (Status != STATUS_PENDING) { - DispDataRequestComplete(Irp, Status, 0); - /* Return STATUS_PENDING because DispPrepareIrpForCancel marks Irp as pending */ - Status = STATUS_PENDING; - } - } - - TI_DbgPrint(DEBUG_IRP, ("Leaving.\n")); - - return Status; -} - - -NTSTATUS DispTdiSetEventHandler( - PIRP Irp) -/* - * FUNCTION: TDI_SET_EVENT_HANDER handler - * ARGUMENTS: - * Irp = Pointer to a I/O request packet - * RETURNS: - * Status of operation - */ -{ -#ifdef _MSC_VER - PTDI_REQUEST_KERNEL_SET_EVENT Parameters; - PTRANSPORT_CONTEXT TranContext; - PIO_STACK_LOCATION IrpSp; - PADDRESS_FILE AddrFile; - NTSTATUS Status; - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - - /* Get associated address file object. Quit if none exists */ - TranContext = IrpSp->FileObject->FsContext; - if (!TranContext) { - TI_DbgPrint(MIN_TRACE, ("Bad transport context.\n")); - return STATUS_INVALID_PARAMETER; - } - - AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle; - if (!AddrFile) { - TI_DbgPrint(MIN_TRACE, ("No address file object.\n")); - return STATUS_INVALID_PARAMETER; - } - - Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters; - Status = STATUS_SUCCESS; - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - - /* Set the event handler. if an event handler is associated with - a specific event, it's flag (RegisteredXxxHandler) is TRUE. - If an event handler is not used it's flag is FALSE */ - switch (Parameters->EventType) { - case TDI_EVENT_CONNECT: - if (!Parameters->EventHandler) { - AddrFile->ConnectionHandler = - (PTDI_IND_CONNECT)TdiDefaultConnectHandler; - AddrFile->ConnectionHandlerContext = NULL; - AddrFile->RegisteredConnectionHandler = FALSE; - } else { - AddrFile->ConnectionHandler = - (PTDI_IND_CONNECT)Parameters->EventHandler; - AddrFile->ConnectionHandlerContext = Parameters->EventContext; - AddrFile->RegisteredConnectionHandler = TRUE; - } - break; - - case TDI_EVENT_DISCONNECT: - if (!Parameters->EventHandler) { - AddrFile->DisconnectHandler = - (PTDI_IND_DISCONNECT)TdiDefaultDisconnectHandler; - AddrFile->DisconnectHandlerContext = NULL; - AddrFile->RegisteredDisconnectHandler = FALSE; - } else { - AddrFile->DisconnectHandler = - (PTDI_IND_DISCONNECT)Parameters->EventHandler; - AddrFile->DisconnectHandlerContext = Parameters->EventContext; - AddrFile->RegisteredDisconnectHandler = TRUE; - } - break; - - case TDI_EVENT_RECEIVE: - if (Parameters->EventHandler == NULL) { - AddrFile->ReceiveHandler = - (PTDI_IND_RECEIVE)TdiDefaultReceiveHandler; - AddrFile->ReceiveHandlerContext = NULL; - AddrFile->RegisteredReceiveHandler = FALSE; - } else { - AddrFile->ReceiveHandler = - (PTDI_IND_RECEIVE)Parameters->EventHandler; - AddrFile->ReceiveHandlerContext = Parameters->EventContext; - AddrFile->RegisteredReceiveHandler = TRUE; - } - break; - - case TDI_EVENT_RECEIVE_EXPEDITED: - if (Parameters->EventHandler == NULL) { - AddrFile->ExpeditedReceiveHandler = - (PTDI_IND_RECEIVE_EXPEDITED)TdiDefaultRcvExpeditedHandler; - AddrFile->ExpeditedReceiveHandlerContext = NULL; - AddrFile->RegisteredExpeditedReceiveHandler = FALSE; - } else { - AddrFile->ExpeditedReceiveHandler = - (PTDI_IND_RECEIVE_EXPEDITED)Parameters->EventHandler; - AddrFile->ExpeditedReceiveHandlerContext = Parameters->EventContext; - AddrFile->RegisteredExpeditedReceiveHandler = TRUE; - } - break; - - case TDI_EVENT_RECEIVE_DATAGRAM: - if (Parameters->EventHandler == NULL) { - AddrFile->ReceiveDatagramHandler = - (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler; - AddrFile->ReceiveDatagramHandlerContext = NULL; - AddrFile->RegisteredReceiveDatagramHandler = FALSE; - } else { - AddrFile->ReceiveDatagramHandler = - (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler; - AddrFile->ReceiveDatagramHandlerContext = Parameters->EventContext; - AddrFile->RegisteredReceiveDatagramHandler = TRUE; - } - break; - - case TDI_EVENT_ERROR: - if (Parameters->EventHandler == NULL) { - AddrFile->ErrorHandler = - (PTDI_IND_ERROR)TdiDefaultErrorHandler; - AddrFile->ErrorHandlerContext = NULL; - AddrFile->RegisteredErrorHandler = FALSE; - } else { - AddrFile->ErrorHandler = - (PTDI_IND_ERROR)Parameters->EventHandler; - AddrFile->ErrorHandlerContext = Parameters->EventContext; - AddrFile->RegisteredErrorHandler = TRUE; - } - break; - - default: - Status = STATUS_INVALID_PARAMETER; - } - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - return Status; -#else - return STATUS_NOT_IMPLEMENTED; -#endif -} - - -NTSTATUS DispTdiSetInformation( - PIRP Irp) -/* - * FUNCTION: TDI_SET_INFORMATION handler - * ARGUMENTS: - * Irp = Pointer to an I/O request packet - * RETURNS: - * Status of operation - */ -{ - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - return STATUS_NOT_IMPLEMENTED; -} - - -VOID DispTdiQueryInformationExComplete( - PVOID Context, - ULONG Status, - UINT ByteCount) -/* - * FUNCTION: Completes a TDI QueryInformationEx request - * ARGUMENTS: - * Context = Pointer to the IRP for the request - * Status = TDI status of the request - * ByteCount = Number of bytes returned in output buffer - */ -{ - PTI_QUERY_CONTEXT QueryContext; - UINT Count = 0; - - QueryContext = (PTI_QUERY_CONTEXT)Context; - if (NT_SUCCESS(Status)) { - Count = CopyBufferToBufferChain( - QueryContext->InputMdl, - FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context), - (PUCHAR)&QueryContext->QueryInfo.Context, - CONTEXT_SIZE); - } - - MmUnlockPages(QueryContext->InputMdl); - IoFreeMdl(QueryContext->InputMdl); - MmUnlockPages(QueryContext->OutputMdl); - IoFreeMdl(QueryContext->OutputMdl); - - QueryContext->Irp->IoStatus.Information = Count; - QueryContext->Irp->IoStatus.Status = Status; - - ExFreePool(QueryContext); -} - - -NTSTATUS DispTdiQueryInformationEx( - PIRP Irp, - PIO_STACK_LOCATION IrpSp) -/* - * FUNCTION: TDI QueryInformationEx handler - * ARGUMENTS: - * Irp = Pointer to I/O request packet - * IrpSp = Pointer to current stack location of Irp - * RETURNS: - * Status of operation - */ -{ - PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer; - PTRANSPORT_CONTEXT TranContext; - PTI_QUERY_CONTEXT QueryContext; - PVOID OutputBuffer; - TDI_REQUEST Request; - UINT Size; - UINT InputBufferLength; - UINT OutputBufferLength; - BOOLEAN InputMdlLocked = FALSE; - BOOLEAN OutputMdlLocked = FALSE; - PMDL InputMdl = NULL; - PMDL OutputMdl = NULL; - NTSTATUS Status = STATUS_SUCCESS; - - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; - - switch ((ULONG)IrpSp->FileObject->FsContext2) { - case TDI_TRANSPORT_ADDRESS_FILE: - Request.Handle.AddressHandle = TranContext->Handle.AddressHandle; - break; - - case TDI_CONNECTION_FILE: - Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext; - break; - - case TDI_CONTROL_CHANNEL_FILE: - Request.Handle.ControlChannel = TranContext->Handle.ControlChannel; - break; - - default: - TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n")); - return STATUS_INVALID_PARAMETER; - } - - InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; - OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; - - /* Validate parameters */ - if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) && - (OutputBufferLength != 0)) { - - InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX) - IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; - OutputBuffer = Irp->UserBuffer; - - QueryContext = ExAllocatePool(NonPagedPool, sizeof(TI_QUERY_CONTEXT)); - if (QueryContext) { -#ifdef _MSC_VER - try { -#endif - InputMdl = IoAllocateMdl(InputBuffer, - sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), - FALSE, TRUE, NULL); - - OutputMdl = IoAllocateMdl(OutputBuffer, - OutputBufferLength, FALSE, TRUE, NULL); - - if (InputMdl && OutputMdl) { - - MmProbeAndLockPages(InputMdl, Irp->RequestorMode, - IoModifyAccess); - - InputMdlLocked = TRUE; - - MmProbeAndLockPages(OutputMdl, Irp->RequestorMode, - IoWriteAccess); - - OutputMdlLocked = TRUE; - - RtlCopyMemory(&QueryContext->QueryInfo, - InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)); - - } else - Status = STATUS_INSUFFICIENT_RESOURCES; -#ifdef _MSC_VER - } except(EXCEPTION_EXECUTE_HANDLER) { - Status = GetExceptionCode(); - } -#endif - if (NT_SUCCESS(Status)) { - Size = MmGetMdlByteCount(OutputMdl); - - QueryContext->Irp = Irp; - QueryContext->InputMdl = InputMdl; - QueryContext->OutputMdl = OutputMdl; - - Request.RequestNotifyObject = DispTdiQueryInformationExComplete; - Request.RequestContext = QueryContext; - Status = InfoTdiQueryInformationEx(&Request, - &QueryContext->QueryInfo.ID, OutputMdl, - &Size, &QueryContext->QueryInfo.Context); - DispTdiQueryInformationExComplete(QueryContext, Status, Size); - - TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status)); - - return Status; - } - - /* An error occurred if we get here */ - - if (InputMdl) { - if (InputMdlLocked) - MmUnlockPages(InputMdl); - IoFreeMdl(InputMdl); - } - - if (OutputMdl) { - if (OutputMdlLocked) - MmUnlockPages(OutputMdl); - IoFreeMdl(OutputMdl); - } - - ExFreePool(QueryContext); - } else - Status = STATUS_INSUFFICIENT_RESOURCES; - } else - Status = STATUS_INVALID_PARAMETER; - - TI_DbgPrint(MIN_TRACE, ("Leaving. Status = (0x%X)\n", Status)); - - return Status; -} - - -NTSTATUS DispTdiSetInformationEx( - PIRP Irp, - PIO_STACK_LOCATION IrpSp) -/* - * FUNCTION: TDI SetInformationEx handler - * ARGUMENTS: - * Irp = Pointer to I/O request packet - * IrpSp = Pointer to current stack location of Irp - * RETURNS: - * Status of operation - */ -{ - PTRANSPORT_CONTEXT TranContext; - PTCP_REQUEST_SET_INFORMATION_EX Info; - TDI_REQUEST Request; - TDI_STATUS Status; - KIRQL OldIrql; - - TI_DbgPrint(DEBUG_IRP, ("Called.\n")); - - TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; - Info = (PTCP_REQUEST_SET_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer; - - switch ((ULONG)IrpSp->FileObject->FsContext2) { - case TDI_TRANSPORT_ADDRESS_FILE: - Request.Handle.AddressHandle = TranContext->Handle.AddressHandle; - break; - - case TDI_CONNECTION_FILE: - Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext; - break; - - case TDI_CONTROL_CHANNEL_FILE: - Request.Handle.ControlChannel = TranContext->Handle.ControlChannel; - break; - - default: - Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - Irp->IoStatus.Information = 0; - - TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); - - IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); - - return STATUS_INVALID_PARAMETER; - } - - Status = DispPrepareIrpForCancel(TranContext, Irp, NULL); - if (NT_SUCCESS(Status)) { - Request.RequestNotifyObject = DispDataRequestComplete; - Request.RequestContext = Irp; - - Status = InfoTdiSetInformationEx(&Request, &Info->ID, - &Info->Buffer, Info->BufferSize); - - if (Status != STATUS_PENDING) { - IoAcquireCancelSpinLock(&OldIrql); - IoSetCancelRoutine(Irp, NULL); - IoReleaseCancelSpinLock(OldIrql); - } - } - - return Status; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: tcpip/dispatch.h + * PURPOSE: TDI dispatch routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include + + +NTSTATUS DispPrepareIrpForCancel( + PTRANSPORT_CONTEXT Context, + PIRP Irp, + PDRIVER_CANCEL CancelRoutine) +/* + * FUNCTION: Prepare an IRP for cancellation + * ARGUMENTS: + * Context = Pointer to context information + * Irp = Pointer to an I/O request packet + * CancelRoutine = Routine to be called when I/O request is cancelled + * RETURNS: + * Status of operation + */ +{ + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + IoAcquireCancelSpinLock(&OldIrql); + + if (!Irp->Cancel) { + IoMarkIrpPending(Irp); + IoSetCancelRoutine(Irp, CancelRoutine); + Context->RefCount++; + IoReleaseCancelSpinLock(OldIrql); + + TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP at 0x%X can now be cancelled).\n", Irp)); + + return STATUS_SUCCESS; + } + + /* IRP has already been cancelled */ + + IoReleaseCancelSpinLock(OldIrql); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + + TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP was already cancelled).\n")); + + return STATUS_CANCELLED; +} + + +VOID DispCancelComplete( + PVOID Context) +/* + * FUNCTION: Completes a cancel request + * ARGUMENTS: + * Context = Pointer to context information (FILE_OBJECT) + */ +{ + KIRQL OldIrql; + PFILE_OBJECT FileObject; + PTRANSPORT_CONTEXT TranContext; + + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + FileObject = (PFILE_OBJECT)Context; + TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext; + + IoAcquireCancelSpinLock(&OldIrql); + + /* Remove the reference placed on the endpoint by the cancel routine. + The cancelled IRP will be completed by the completion routine for + the request */ + TranContext->RefCount--; + + if (TranContext->RefCount == 0) { + TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n")); + /* Set the cleanup event */ + KeSetEvent(&TranContext->CleanupEvent, 0, FALSE); + } + + TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount)); + + IoReleaseCancelSpinLock(OldIrql); + + TI_DbgPrint(DEBUG_IRP, ("Leaving.\n")); +} + + +VOID DispCancelRequest( + PDEVICE_OBJECT Device, + PIRP Irp) +/* + * FUNCTION: Cancels an IRP + * ARGUMENTS: + * Device = Pointer to device object + * Irp = Pointer to an I/O request packet + */ +{ + PIO_STACK_LOCATION IrpSp; + PTRANSPORT_CONTEXT TranContext; + PFILE_OBJECT FileObject; + UCHAR MinorFunction; + NTSTATUS Status = STATUS_SUCCESS; + + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + FileObject = IrpSp->FileObject; + TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext; + MinorFunction = IrpSp->MinorFunction; + + TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X) MinorFunction (0x%X) IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp)); + +#ifdef DBG + if (!Irp->Cancel) + TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n")); +#endif + + /* Increase reference count to prevent accidential closure + of the object while inside the cancel routine */ + TranContext->RefCount++; + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + /* Try canceling the request */ + switch(MinorFunction) { + case TDI_SEND: + + case TDI_RECEIVE: + /* FIXME: Close connection */ + break; + + case TDI_SEND_DATAGRAM: + if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) { + TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n")); + break; + } + + DGCancelSendRequest(TranContext->Handle.AddressHandle, Irp); + break; + + case TDI_RECEIVE_DATAGRAM: + if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) { + TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n")); + break; + } + + DGCancelReceiveRequest(TranContext->Handle.AddressHandle, Irp); + break; + + default: + TI_DbgPrint(MIN_TRACE, ("Unknown IRP. MinorFunction (0x%X).\n", MinorFunction)); + break; + } + + if (Status != STATUS_PENDING) + DispCancelComplete(FileObject); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); +} + + +VOID DispDataRequestComplete( + PVOID Context, + NTSTATUS Status, + ULONG Count) +/* + * FUNCTION: Completes a send/receive IRP + * ARGUMENTS: + * Context = Pointer to context information (IRP) + * Status = Status of the request + * Count = Number of bytes sent or received + */ +{ + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + PTRANSPORT_CONTEXT TranContext; + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + Irp = (PIRP)Context; + IrpSp = IoGetCurrentIrpStackLocation(Irp); + TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; + + IoAcquireCancelSpinLock(&OldIrql); + + IoSetCancelRoutine(Irp, NULL); + TranContext->RefCount--; + TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount)); + if (TranContext->RefCount == 0) { + TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n")); + + KeSetEvent(&TranContext->CleanupEvent, 0, FALSE); + } + + if (Irp->Cancel || TranContext->CancelIrps) { + /* The IRP has been cancelled */ + + TI_DbgPrint(DEBUG_IRP, ("IRP is cancelled.\n")); + + Status = STATUS_CANCELLED; + Count = 0; + } + + IoReleaseCancelSpinLock(OldIrql); + + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = Count; + + TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); +} + + +NTSTATUS DispTdiAccept( + PIRP Irp) +/* + * FUNCTION: TDI_ACCEPT handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS DispTdiAssociateAddress( + PIRP Irp) +/* + * FUNCTION: TDI_ASSOCIATE_ADDRESS handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS DispTdiConnect( + PIRP Irp) +/* + * FUNCTION: TDI_CONNECT handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS DispTdiDisassociateAddress( + PIRP Irp) +/* + * FUNCTION: TDI_DISASSOCIATE_ADDRESS handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS DispTdiDisconnect( + PIRP Irp) +/* + * FUNCTION: TDI_DISCONNECT handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS DispTdiListen( + PIRP Irp) +/* + * FUNCTION: TDI_LISTEN handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS DispTdiQueryInformation( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +/* + * FUNCTION: TDI_QUERY_INFORMATION handler + * ARGUMENTS: + * DeviceObject = Pointer to device object structure + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS DispTdiReceive( + PIRP Irp) +/* + * FUNCTION: TDI_RECEIVE handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS DispTdiReceiveDatagram( + PIRP Irp) +/* + * FUNCTION: TDI_RECEIVE_DATAGRAM handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + PIO_STACK_LOCATION IrpSp; + PTDI_REQUEST_KERNEL_RECEIVEDG DgramInfo; + PTRANSPORT_CONTEXT TranContext; + TDI_REQUEST Request; + NTSTATUS Status; + ULONG BytesReceived; + + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + DgramInfo = (PTDI_REQUEST_KERNEL_RECEIVEDG)&(IrpSp->Parameters); + + TranContext = IrpSp->FileObject->FsContext; + /* Initialize a receive request */ + Request.Handle.AddressHandle = TranContext->Handle.AddressHandle; + Request.RequestNotifyObject = DispDataRequestComplete; + Request.RequestContext = Irp; + Status = DispPrepareIrpForCancel(IrpSp->FileObject->FsContext, Irp, (PDRIVER_CANCEL)DispCancelRequest); + if (NT_SUCCESS(Status)) { + Status = UDPReceiveDatagram(&Request, + DgramInfo->ReceiveDatagramInformation, + (PNDIS_BUFFER)Irp->MdlAddress, + DgramInfo->ReceiveLength, + DgramInfo->ReceiveFlags, + DgramInfo->ReturnDatagramInformation, + &BytesReceived); + if (Status != STATUS_PENDING) { + DispDataRequestComplete(Irp, Status, BytesReceived); + /* Return STATUS_PENDING because DispPrepareIrpForCancel marks Irp as pending */ + Status = STATUS_PENDING; + } + } + + TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status)); + + return Status; +} + + +NTSTATUS DispTdiSend( + PIRP Irp) +/* + * FUNCTION: TDI_SEND handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +NTSTATUS DispTdiSendDatagram( + PIRP Irp) +/* + * FUNCTION: TDI_SEND_DATAGRAM handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + PIO_STACK_LOCATION IrpSp; + TDI_REQUEST Request; + PTDI_REQUEST_KERNEL_SENDDG DgramInfo; + PTRANSPORT_CONTEXT TranContext; + NTSTATUS Status; + + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + DgramInfo = (PTDI_REQUEST_KERNEL_SENDDG)&(IrpSp->Parameters); + + TranContext = IrpSp->FileObject->FsContext; + /* Initialize a send request */ + Request.Handle.AddressHandle = TranContext->Handle.AddressHandle; + Request.RequestNotifyObject = DispDataRequestComplete; + Request.RequestContext = Irp; + + Status = DispPrepareIrpForCancel(IrpSp->FileObject->FsContext, Irp, (PDRIVER_CANCEL)DispCancelRequest); + if (NT_SUCCESS(Status)) { + + /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress + must be of type PTDI_ADDRESS_IP */ + + Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)( + &Request, DgramInfo->SendDatagramInformation, + (PNDIS_BUFFER)Irp->MdlAddress, DgramInfo->SendLength); + if (Status != STATUS_PENDING) { + DispDataRequestComplete(Irp, Status, 0); + /* Return STATUS_PENDING because DispPrepareIrpForCancel marks Irp as pending */ + Status = STATUS_PENDING; + } + } + + TI_DbgPrint(DEBUG_IRP, ("Leaving.\n")); + + return Status; +} + + +NTSTATUS DispTdiSetEventHandler( + PIRP Irp) +/* + * FUNCTION: TDI_SET_EVENT_HANDER handler + * ARGUMENTS: + * Irp = Pointer to a I/O request packet + * RETURNS: + * Status of operation + */ +{ +#ifdef _MSC_VER + PTDI_REQUEST_KERNEL_SET_EVENT Parameters; + PTRANSPORT_CONTEXT TranContext; + PIO_STACK_LOCATION IrpSp; + PADDRESS_FILE AddrFile; + NTSTATUS Status; + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + /* Get associated address file object. Quit if none exists */ + TranContext = IrpSp->FileObject->FsContext; + if (!TranContext) { + TI_DbgPrint(MIN_TRACE, ("Bad transport context.\n")); + return STATUS_INVALID_PARAMETER; + } + + AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle; + if (!AddrFile) { + TI_DbgPrint(MIN_TRACE, ("No address file object.\n")); + return STATUS_INVALID_PARAMETER; + } + + Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters; + Status = STATUS_SUCCESS; + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + + /* Set the event handler. if an event handler is associated with + a specific event, it's flag (RegisteredXxxHandler) is TRUE. + If an event handler is not used it's flag is FALSE */ + switch (Parameters->EventType) { + case TDI_EVENT_CONNECT: + if (!Parameters->EventHandler) { + AddrFile->ConnectionHandler = + (PTDI_IND_CONNECT)TdiDefaultConnectHandler; + AddrFile->ConnectionHandlerContext = NULL; + AddrFile->RegisteredConnectionHandler = FALSE; + } else { + AddrFile->ConnectionHandler = + (PTDI_IND_CONNECT)Parameters->EventHandler; + AddrFile->ConnectionHandlerContext = Parameters->EventContext; + AddrFile->RegisteredConnectionHandler = TRUE; + } + break; + + case TDI_EVENT_DISCONNECT: + if (!Parameters->EventHandler) { + AddrFile->DisconnectHandler = + (PTDI_IND_DISCONNECT)TdiDefaultDisconnectHandler; + AddrFile->DisconnectHandlerContext = NULL; + AddrFile->RegisteredDisconnectHandler = FALSE; + } else { + AddrFile->DisconnectHandler = + (PTDI_IND_DISCONNECT)Parameters->EventHandler; + AddrFile->DisconnectHandlerContext = Parameters->EventContext; + AddrFile->RegisteredDisconnectHandler = TRUE; + } + break; + + case TDI_EVENT_RECEIVE: + if (Parameters->EventHandler == NULL) { + AddrFile->ReceiveHandler = + (PTDI_IND_RECEIVE)TdiDefaultReceiveHandler; + AddrFile->ReceiveHandlerContext = NULL; + AddrFile->RegisteredReceiveHandler = FALSE; + } else { + AddrFile->ReceiveHandler = + (PTDI_IND_RECEIVE)Parameters->EventHandler; + AddrFile->ReceiveHandlerContext = Parameters->EventContext; + AddrFile->RegisteredReceiveHandler = TRUE; + } + break; + + case TDI_EVENT_RECEIVE_EXPEDITED: + if (Parameters->EventHandler == NULL) { + AddrFile->ExpeditedReceiveHandler = + (PTDI_IND_RECEIVE_EXPEDITED)TdiDefaultRcvExpeditedHandler; + AddrFile->ExpeditedReceiveHandlerContext = NULL; + AddrFile->RegisteredExpeditedReceiveHandler = FALSE; + } else { + AddrFile->ExpeditedReceiveHandler = + (PTDI_IND_RECEIVE_EXPEDITED)Parameters->EventHandler; + AddrFile->ExpeditedReceiveHandlerContext = Parameters->EventContext; + AddrFile->RegisteredExpeditedReceiveHandler = TRUE; + } + break; + + case TDI_EVENT_RECEIVE_DATAGRAM: + if (Parameters->EventHandler == NULL) { + AddrFile->ReceiveDatagramHandler = + (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler; + AddrFile->ReceiveDatagramHandlerContext = NULL; + AddrFile->RegisteredReceiveDatagramHandler = FALSE; + } else { + AddrFile->ReceiveDatagramHandler = + (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler; + AddrFile->ReceiveDatagramHandlerContext = Parameters->EventContext; + AddrFile->RegisteredReceiveDatagramHandler = TRUE; + } + break; + + case TDI_EVENT_ERROR: + if (Parameters->EventHandler == NULL) { + AddrFile->ErrorHandler = + (PTDI_IND_ERROR)TdiDefaultErrorHandler; + AddrFile->ErrorHandlerContext = NULL; + AddrFile->RegisteredErrorHandler = FALSE; + } else { + AddrFile->ErrorHandler = + (PTDI_IND_ERROR)Parameters->EventHandler; + AddrFile->ErrorHandlerContext = Parameters->EventContext; + AddrFile->RegisteredErrorHandler = TRUE; + } + break; + + default: + Status = STATUS_INVALID_PARAMETER; + } + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + return Status; +#else + return STATUS_NOT_IMPLEMENTED; +#endif +} + + +NTSTATUS DispTdiSetInformation( + PIRP Irp) +/* + * FUNCTION: TDI_SET_INFORMATION handler + * ARGUMENTS: + * Irp = Pointer to an I/O request packet + * RETURNS: + * Status of operation + */ +{ + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + return STATUS_NOT_IMPLEMENTED; +} + + +VOID DispTdiQueryInformationExComplete( + PVOID Context, + ULONG Status, + UINT ByteCount) +/* + * FUNCTION: Completes a TDI QueryInformationEx request + * ARGUMENTS: + * Context = Pointer to the IRP for the request + * Status = TDI status of the request + * ByteCount = Number of bytes returned in output buffer + */ +{ + PTI_QUERY_CONTEXT QueryContext; + UINT Count = 0; + + QueryContext = (PTI_QUERY_CONTEXT)Context; + if (NT_SUCCESS(Status)) { + Count = CopyBufferToBufferChain( + QueryContext->InputMdl, + FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context), + (PUCHAR)&QueryContext->QueryInfo.Context, + CONTEXT_SIZE); + } + + MmUnlockPages(QueryContext->InputMdl); + IoFreeMdl(QueryContext->InputMdl); + MmUnlockPages(QueryContext->OutputMdl); + IoFreeMdl(QueryContext->OutputMdl); + + QueryContext->Irp->IoStatus.Information = Count; + QueryContext->Irp->IoStatus.Status = Status; + + ExFreePool(QueryContext); +} + + +NTSTATUS DispTdiQueryInformationEx( + PIRP Irp, + PIO_STACK_LOCATION IrpSp) +/* + * FUNCTION: TDI QueryInformationEx handler + * ARGUMENTS: + * Irp = Pointer to I/O request packet + * IrpSp = Pointer to current stack location of Irp + * RETURNS: + * Status of operation + */ +{ + PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer; + PTRANSPORT_CONTEXT TranContext; + PTI_QUERY_CONTEXT QueryContext; + PVOID OutputBuffer; + TDI_REQUEST Request; + UINT Size; + UINT InputBufferLength; + UINT OutputBufferLength; + BOOLEAN InputMdlLocked = FALSE; + BOOLEAN OutputMdlLocked = FALSE; + PMDL InputMdl = NULL; + PMDL OutputMdl = NULL; + NTSTATUS Status = STATUS_SUCCESS; + + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; + + switch ((ULONG)IrpSp->FileObject->FsContext2) { + case TDI_TRANSPORT_ADDRESS_FILE: + Request.Handle.AddressHandle = TranContext->Handle.AddressHandle; + break; + + case TDI_CONNECTION_FILE: + Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext; + break; + + case TDI_CONTROL_CHANNEL_FILE: + Request.Handle.ControlChannel = TranContext->Handle.ControlChannel; + break; + + default: + TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n")); + return STATUS_INVALID_PARAMETER; + } + + InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; + OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; + + /* Validate parameters */ + if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) && + (OutputBufferLength != 0)) { + + InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX) + IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; + OutputBuffer = Irp->UserBuffer; + + QueryContext = ExAllocatePool(NonPagedPool, sizeof(TI_QUERY_CONTEXT)); + if (QueryContext) { +#ifdef _MSC_VER + try { +#endif + InputMdl = IoAllocateMdl(InputBuffer, + sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), + FALSE, TRUE, NULL); + + OutputMdl = IoAllocateMdl(OutputBuffer, + OutputBufferLength, FALSE, TRUE, NULL); + + if (InputMdl && OutputMdl) { + + MmProbeAndLockPages(InputMdl, Irp->RequestorMode, + IoModifyAccess); + + InputMdlLocked = TRUE; + + MmProbeAndLockPages(OutputMdl, Irp->RequestorMode, + IoWriteAccess); + + OutputMdlLocked = TRUE; + + RtlCopyMemory(&QueryContext->QueryInfo, + InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)); + + } else + Status = STATUS_INSUFFICIENT_RESOURCES; +#ifdef _MSC_VER + } except(EXCEPTION_EXECUTE_HANDLER) { + Status = GetExceptionCode(); + } +#endif + if (NT_SUCCESS(Status)) { + Size = MmGetMdlByteCount(OutputMdl); + + QueryContext->Irp = Irp; + QueryContext->InputMdl = InputMdl; + QueryContext->OutputMdl = OutputMdl; + + Request.RequestNotifyObject = DispTdiQueryInformationExComplete; + Request.RequestContext = QueryContext; + Status = InfoTdiQueryInformationEx(&Request, + &QueryContext->QueryInfo.ID, OutputMdl, + &Size, &QueryContext->QueryInfo.Context); + DispTdiQueryInformationExComplete(QueryContext, Status, Size); + + TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status)); + + return Status; + } + + /* An error occurred if we get here */ + + if (InputMdl) { + if (InputMdlLocked) + MmUnlockPages(InputMdl); + IoFreeMdl(InputMdl); + } + + if (OutputMdl) { + if (OutputMdlLocked) + MmUnlockPages(OutputMdl); + IoFreeMdl(OutputMdl); + } + + ExFreePool(QueryContext); + } else + Status = STATUS_INSUFFICIENT_RESOURCES; + } else + Status = STATUS_INVALID_PARAMETER; + + TI_DbgPrint(MIN_TRACE, ("Leaving. Status = (0x%X)\n", Status)); + + return Status; +} + + +NTSTATUS DispTdiSetInformationEx( + PIRP Irp, + PIO_STACK_LOCATION IrpSp) +/* + * FUNCTION: TDI SetInformationEx handler + * ARGUMENTS: + * Irp = Pointer to I/O request packet + * IrpSp = Pointer to current stack location of Irp + * RETURNS: + * Status of operation + */ +{ + PTRANSPORT_CONTEXT TranContext; + PTCP_REQUEST_SET_INFORMATION_EX Info; + TDI_REQUEST Request; + TDI_STATUS Status; + KIRQL OldIrql; + + TI_DbgPrint(DEBUG_IRP, ("Called.\n")); + + TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; + Info = (PTCP_REQUEST_SET_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer; + + switch ((ULONG)IrpSp->FileObject->FsContext2) { + case TDI_TRANSPORT_ADDRESS_FILE: + Request.Handle.AddressHandle = TranContext->Handle.AddressHandle; + break; + + case TDI_CONNECTION_FILE: + Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext; + break; + + case TDI_CONTROL_CHANNEL_FILE: + Request.Handle.ControlChannel = TranContext->Handle.ControlChannel; + break; + + default: + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + + TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + + return STATUS_INVALID_PARAMETER; + } + + Status = DispPrepareIrpForCancel(TranContext, Irp, NULL); + if (NT_SUCCESS(Status)) { + Request.RequestNotifyObject = DispDataRequestComplete; + Request.RequestContext = Irp; + + Status = InfoTdiSetInformationEx(&Request, &Info->ID, + &Info->Buffer, Info->BufferSize); + + if (Status != STATUS_PENDING) { + IoAcquireCancelSpinLock(&OldIrql); + IoSetCancelRoutine(Irp, NULL); + IoReleaseCancelSpinLock(OldIrql); + } + } + + return Status; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/fileobjs.c b/reactos/drivers/net/tcpip/tcpip/fileobjs.c index 29bb42f0aec..0b24fa5a23d 100644 --- a/reactos/drivers/net/tcpip/tcpip/fileobjs.c +++ b/reactos/drivers/net/tcpip/tcpip/fileobjs.c @@ -1,396 +1,396 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: tcpip/fileobjs.c - * PURPOSE: Routines for handling file objects - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include -#include - -LIST_ENTRY AddressFileListHead; -KSPIN_LOCK AddressFileListLock; - - -/* - * FUNCTION: Deletes an address file object - * ARGUMENTS: - * AddrFile = Pointer to address file object to delete - */ -VOID DeleteAddress( - PADDRESS_FILE AddrFile) -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PLIST_ENTRY NextEntry; - PDATAGRAM_SEND_REQUEST SendRequest; - PDATAGRAM_RECEIVE_REQUEST ReceiveRequest; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - /* Remove address file from the global list */ - KeAcquireSpinLock(&AddressFileListLock, &OldIrql); - RemoveEntryList(&AddrFile->ListEntry); - KeReleaseSpinLock(&AddressFileListLock, OldIrql); - - KeAcquireSpinLock(&AddrFile->Lock, &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 */ - CurrentEntry = AddrFile->ReceiveQueue.Flink; - while (CurrentEntry != &AddrFile->ReceiveQueue) { - NextEntry = CurrentEntry->Flink; - ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry); - /* Abort the request and free its resources */ - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0); - PoolFreeBuffer(ReceiveRequest); - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - CurrentEntry = NextEntry; - } - - 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 */ - CurrentEntry = AddrFile->TransmitQueue.Flink; - while (CurrentEntry != &AddrFile->TransmitQueue) { - NextEntry = CurrentEntry->Flink; - SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); - /* Abort the request and free its resources */ - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0); - PoolFreeBuffer(SendRequest); - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - CurrentEntry = NextEntry; - } - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - /* Dereference address entry */ - DereferenceObject(AddrFile->ADE); - - /* Dereference address cache */ - if (AddrFile->AddrCache) - DereferenceObject(AddrFile->AddrCache); - -#ifdef DBG - /* Remove reference provided at creation time */ - AddrFile->RefCount--; - - if (AddrFile->RefCount != 0) - TI_DbgPrint(DEBUG_REFCOUNT, ("AddrFile->RefCount is (%d) (should be 0).\n", AddrFile->RefCount)); -#endif - - PoolFreeBuffer(AddrFile); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); -} - - -VOID RequestWorker( - PVOID Context) -/* - * FUNCTION: Worker routine for processing address file object requests - * ARGUMENTS: - * Context = Pointer to context information (ADDRESS_FILE) - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PADDRESS_FILE AddrFile = Context; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - - /* Check it the address file should be deleted */ - if (AF_IS_PENDING(AddrFile, AFF_DELETE)) { - DATAGRAM_COMPLETION_ROUTINE RtnComplete; - PVOID RtnContext; - - RtnComplete = AddrFile->Complete; - RtnContext = AddrFile->Context; - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - DeleteAddress(AddrFile); - - (*RtnComplete)(RtnContext, TDI_SUCCESS, 0); - - TI_DbgPrint(MAX_TRACE, ("Leaving (delete).\n")); - - return; - } - - /* Check if there is a pending send request */ - if (AF_IS_PENDING(AddrFile, AFF_SEND)) { - if (!IsListEmpty(&AddrFile->TransmitQueue)) { - PDATAGRAM_SEND_REQUEST SendRequest; - - CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue); - SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); - - AF_CLR_BUSY(AddrFile); - - ReferenceObject(AddrFile); - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - /* The send routine processes the send requests in - the transmit queue on the address file. When the - queue is empty the pending send flag is cleared. - The routine may return with the pending send flag - set. This can happen if there was not enough free - resources available to complete all send requests */ - DGSend(AddrFile, SendRequest); - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - DereferenceObject(AddrFile); - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - TI_DbgPrint(MAX_TRACE, ("Leaving (send request).\n")); - - return; - } else - /* There was a pending send, but no send request. - Print a debug message and continue */ - TI_DbgPrint(MIN_TRACE, ("Pending send, but no send request.\n")); - } - - AF_CLR_BUSY(AddrFile); - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); -} - - -/* - * FUNCTION: Open an address file object - * ARGUMENTS: - * Request = Pointer to TDI request structure for this request - * Address = Pointer to address to be opened - * Protocol = Protocol on which to open the address - * Options = Pointer to option buffer - * RETURNS: - * Status of operation - */ -NTSTATUS FileOpenAddress( - PTDI_REQUEST Request, - PTA_ADDRESS_IP Address, - USHORT Protocol, - PVOID Options) -{ - PADDRESS_FILE AddrFile; - IPv4_RAW_ADDRESS IPv4Address; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - AddrFile = PoolAllocateBuffer(sizeof(ADDRESS_FILE)); - if (!AddrFile) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return STATUS_INSUFFICIENT_RESOURCES; - } - - TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile)); - - RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE)); - - /* Make sure address is a local unicast address or 0 */ - - /* Locate address entry. If specified address is 0, a random address is chosen */ - - IPv4Address = Address->Address[0].Address[0].in_addr; - if (IPv4Address == 0) - AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST); - else - AddrFile->ADE = AddrLocateADEv4(IPv4Address); - - if (!AddrFile->ADE) { - PoolFreeBuffer(AddrFile); - TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address))); - return STATUS_INVALID_PARAMETER; - } - - TI_DbgPrint(DEBUG_ADDRFILE, ("Opening address (0x%X) for communication.\n", - DN2H(AddrFile->ADE->Address->Address.IPv4Address))); - - /* Protocol specific handling */ - switch (Protocol) { - case IPPROTO_TCP: - /* FIXME: TCP */ - TI_DbgPrint(MIN_TRACE, ("TCP is not supported.\n")); - DereferenceObject(AddrFile->ADE); - PoolFreeBuffer(AddrFile); - return STATUS_INVALID_PARAMETER; - case IPPROTO_UDP: - /* FIXME: If specified port is 0, a port is chosen dynamically */ - AddrFile->Port = Address->Address[0].Address[0].sin_port; - AddrFile->Send = UDPSendDatagram; - break; - default: - /* Use raw IP for all other protocols */ - AddrFile->Send = RawIPSendDatagram; - break; - } - - /* Set protocol */ - AddrFile->Protocol = Protocol; - - /* Initialize receive and transmit queues */ - InitializeListHead(&AddrFile->ReceiveQueue); - InitializeListHead(&AddrFile->TransmitQueue); - - /* Initialize work queue item. We use this for pending requests */ - ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile); - - /* Initialize spin lock that protects the address file object */ - KeInitializeSpinLock(&AddrFile->Lock); - - /* Reference the object */ - AddrFile->RefCount = 1; - - /* Set valid flag so the address can be used */ - AF_SET_VALID(AddrFile); - - /* Return address file object */ - Request->Handle.AddressHandle = AddrFile; - - /* Add address file to global list */ - ExInterlockedInsertTailList(&AddressFileListHead, &AddrFile->ListEntry, &AddressFileListLock); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); - - return STATUS_SUCCESS; -} - - -/* - * FUNCTION: Closes an address file object - * ARGUMENTS: - * Request = Pointer to TDI request structure for this request - * RETURNS: - * Status of operation - */ -NTSTATUS FileCloseAddress( - PTDI_REQUEST Request) -{ - KIRQL OldIrql; - PADDRESS_FILE AddrFile; - NTSTATUS Status = STATUS_SUCCESS; - - TI_DbgPrint(MID_TRACE, ("Called.\n")); - - AddrFile = Request->Handle.AddressHandle; - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - - if ((!AF_IS_BUSY(AddrFile)) && (AddrFile->RefCount == 1)) { - /* Set address file object exclusive to us */ - AF_SET_BUSY(AddrFile); - AF_CLR_VALID(AddrFile); - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - DeleteAddress(AddrFile); - } else { - if (!AF_IS_PENDING(AddrFile, AFF_DELETE)) { - AddrFile->Complete = Request->RequestNotifyObject; - AddrFile->Context = Request->RequestContext; - - /* Shedule address file for deletion */ - AF_SET_PENDING(AddrFile, AFF_DELETE); - AF_CLR_VALID(AddrFile); - - if (!AF_IS_BUSY(AddrFile)) { - /* Worker function is not running, so shedule it to run */ - AF_SET_BUSY(AddrFile); - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - ExQueueWorkItem(&AddrFile->WorkItem, CriticalWorkQueue); - } else - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n")); - - return STATUS_PENDING; - } else - Status = STATUS_ADDRESS_CLOSED; - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - } - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); - - return Status; -} - - -/* - * FUNCTION: Opens a connection file object - * ARGUMENTS: - * Request = Pointer to TDI request structure for this request - * RETURNS: - * Status of operation - */ -NTSTATUS FileOpenConnection( - PTDI_REQUEST Request) -{ - return STATUS_NOT_IMPLEMENTED; -} - - -/* - * FUNCTION: Closes an connection file object - * ARGUMENTS: - * Request = Pointer to TDI request structure for this request - * RETURNS: - * Status of operation - */ -NTSTATUS FileCloseConnection( - PTDI_REQUEST Request) -{ - return STATUS_NOT_IMPLEMENTED; -} - - -/* - * FUNCTION: Opens a control channel file object - * ARGUMENTS: - * Request = Pointer to TDI request structure for this request - * RETURNS: - * Status of operation - */ -NTSTATUS FileOpenControlChannel( - PTDI_REQUEST Request) -{ - return STATUS_NOT_IMPLEMENTED; -} - - -/* - * FUNCTION: Closes a control channel file object - * ARGUMENTS: - * Request = Pointer to TDI request structure for this request - * RETURNS: - * Status of operation - */ -NTSTATUS FileCloseControlChannel( - PTDI_REQUEST Request) -{ - return STATUS_NOT_IMPLEMENTED; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: tcpip/fileobjs.c + * PURPOSE: Routines for handling file objects + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include +#include + +LIST_ENTRY AddressFileListHead; +KSPIN_LOCK AddressFileListLock; + + +/* + * FUNCTION: Deletes an address file object + * ARGUMENTS: + * AddrFile = Pointer to address file object to delete + */ +VOID DeleteAddress( + PADDRESS_FILE AddrFile) +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PLIST_ENTRY NextEntry; + PDATAGRAM_SEND_REQUEST SendRequest; + PDATAGRAM_RECEIVE_REQUEST ReceiveRequest; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + /* Remove address file from the global list */ + KeAcquireSpinLock(&AddressFileListLock, &OldIrql); + RemoveEntryList(&AddrFile->ListEntry); + KeReleaseSpinLock(&AddressFileListLock, OldIrql); + + KeAcquireSpinLock(&AddrFile->Lock, &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 */ + CurrentEntry = AddrFile->ReceiveQueue.Flink; + while (CurrentEntry != &AddrFile->ReceiveQueue) { + NextEntry = CurrentEntry->Flink; + ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry); + /* Abort the request and free its resources */ + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0); + PoolFreeBuffer(ReceiveRequest); + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + CurrentEntry = NextEntry; + } + + 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 */ + CurrentEntry = AddrFile->TransmitQueue.Flink; + while (CurrentEntry != &AddrFile->TransmitQueue) { + NextEntry = CurrentEntry->Flink; + SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); + /* Abort the request and free its resources */ + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0); + PoolFreeBuffer(SendRequest); + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + CurrentEntry = NextEntry; + } + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + /* Dereference address entry */ + DereferenceObject(AddrFile->ADE); + + /* Dereference address cache */ + if (AddrFile->AddrCache) + DereferenceObject(AddrFile->AddrCache); + +#ifdef DBG + /* Remove reference provided at creation time */ + AddrFile->RefCount--; + + if (AddrFile->RefCount != 0) + TI_DbgPrint(DEBUG_REFCOUNT, ("AddrFile->RefCount is (%d) (should be 0).\n", AddrFile->RefCount)); +#endif + + PoolFreeBuffer(AddrFile); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); +} + + +VOID RequestWorker( + PVOID Context) +/* + * FUNCTION: Worker routine for processing address file object requests + * ARGUMENTS: + * Context = Pointer to context information (ADDRESS_FILE) + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PADDRESS_FILE AddrFile = Context; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + + /* Check it the address file should be deleted */ + if (AF_IS_PENDING(AddrFile, AFF_DELETE)) { + DATAGRAM_COMPLETION_ROUTINE RtnComplete; + PVOID RtnContext; + + RtnComplete = AddrFile->Complete; + RtnContext = AddrFile->Context; + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + DeleteAddress(AddrFile); + + (*RtnComplete)(RtnContext, TDI_SUCCESS, 0); + + TI_DbgPrint(MAX_TRACE, ("Leaving (delete).\n")); + + return; + } + + /* Check if there is a pending send request */ + if (AF_IS_PENDING(AddrFile, AFF_SEND)) { + if (!IsListEmpty(&AddrFile->TransmitQueue)) { + PDATAGRAM_SEND_REQUEST SendRequest; + + CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue); + SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); + + AF_CLR_BUSY(AddrFile); + + ReferenceObject(AddrFile); + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + /* The send routine processes the send requests in + the transmit queue on the address file. When the + queue is empty the pending send flag is cleared. + The routine may return with the pending send flag + set. This can happen if there was not enough free + resources available to complete all send requests */ + DGSend(AddrFile, SendRequest); + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + DereferenceObject(AddrFile); + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + TI_DbgPrint(MAX_TRACE, ("Leaving (send request).\n")); + + return; + } else + /* There was a pending send, but no send request. + Print a debug message and continue */ + TI_DbgPrint(MIN_TRACE, ("Pending send, but no send request.\n")); + } + + AF_CLR_BUSY(AddrFile); + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); +} + + +/* + * FUNCTION: Open an address file object + * ARGUMENTS: + * Request = Pointer to TDI request structure for this request + * Address = Pointer to address to be opened + * Protocol = Protocol on which to open the address + * Options = Pointer to option buffer + * RETURNS: + * Status of operation + */ +NTSTATUS FileOpenAddress( + PTDI_REQUEST Request, + PTA_ADDRESS_IP Address, + USHORT Protocol, + PVOID Options) +{ + PADDRESS_FILE AddrFile; + IPv4_RAW_ADDRESS IPv4Address; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + AddrFile = PoolAllocateBuffer(sizeof(ADDRESS_FILE)); + if (!AddrFile) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile)); + + RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE)); + + /* Make sure address is a local unicast address or 0 */ + + /* Locate address entry. If specified address is 0, a random address is chosen */ + + IPv4Address = Address->Address[0].Address[0].in_addr; + if (IPv4Address == 0) + AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST); + else + AddrFile->ADE = AddrLocateADEv4(IPv4Address); + + if (!AddrFile->ADE) { + PoolFreeBuffer(AddrFile); + TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address))); + return STATUS_INVALID_PARAMETER; + } + + TI_DbgPrint(DEBUG_ADDRFILE, ("Opening address (0x%X) for communication.\n", + DN2H(AddrFile->ADE->Address->Address.IPv4Address))); + + /* Protocol specific handling */ + switch (Protocol) { + case IPPROTO_TCP: + /* FIXME: TCP */ + TI_DbgPrint(MIN_TRACE, ("TCP is not supported.\n")); + DereferenceObject(AddrFile->ADE); + PoolFreeBuffer(AddrFile); + return STATUS_INVALID_PARAMETER; + case IPPROTO_UDP: + /* FIXME: If specified port is 0, a port is chosen dynamically */ + AddrFile->Port = Address->Address[0].Address[0].sin_port; + AddrFile->Send = UDPSendDatagram; + break; + default: + /* Use raw IP for all other protocols */ + AddrFile->Send = RawIPSendDatagram; + break; + } + + /* Set protocol */ + AddrFile->Protocol = Protocol; + + /* Initialize receive and transmit queues */ + InitializeListHead(&AddrFile->ReceiveQueue); + InitializeListHead(&AddrFile->TransmitQueue); + + /* Initialize work queue item. We use this for pending requests */ + ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile); + + /* Initialize spin lock that protects the address file object */ + KeInitializeSpinLock(&AddrFile->Lock); + + /* Reference the object */ + AddrFile->RefCount = 1; + + /* Set valid flag so the address can be used */ + AF_SET_VALID(AddrFile); + + /* Return address file object */ + Request->Handle.AddressHandle = AddrFile; + + /* Add address file to global list */ + ExInterlockedInsertTailList(&AddressFileListHead, &AddrFile->ListEntry, &AddressFileListLock); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); + + return STATUS_SUCCESS; +} + + +/* + * FUNCTION: Closes an address file object + * ARGUMENTS: + * Request = Pointer to TDI request structure for this request + * RETURNS: + * Status of operation + */ +NTSTATUS FileCloseAddress( + PTDI_REQUEST Request) +{ + KIRQL OldIrql; + PADDRESS_FILE AddrFile; + NTSTATUS Status = STATUS_SUCCESS; + + TI_DbgPrint(MID_TRACE, ("Called.\n")); + + AddrFile = Request->Handle.AddressHandle; + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + + if ((!AF_IS_BUSY(AddrFile)) && (AddrFile->RefCount == 1)) { + /* Set address file object exclusive to us */ + AF_SET_BUSY(AddrFile); + AF_CLR_VALID(AddrFile); + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + DeleteAddress(AddrFile); + } else { + if (!AF_IS_PENDING(AddrFile, AFF_DELETE)) { + AddrFile->Complete = Request->RequestNotifyObject; + AddrFile->Context = Request->RequestContext; + + /* Shedule address file for deletion */ + AF_SET_PENDING(AddrFile, AFF_DELETE); + AF_CLR_VALID(AddrFile); + + if (!AF_IS_BUSY(AddrFile)) { + /* Worker function is not running, so shedule it to run */ + AF_SET_BUSY(AddrFile); + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + ExQueueWorkItem(&AddrFile->WorkItem, CriticalWorkQueue); + } else + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n")); + + return STATUS_PENDING; + } else + Status = STATUS_ADDRESS_CLOSED; + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + } + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); + + return Status; +} + + +/* + * FUNCTION: Opens a connection file object + * ARGUMENTS: + * Request = Pointer to TDI request structure for this request + * RETURNS: + * Status of operation + */ +NTSTATUS FileOpenConnection( + PTDI_REQUEST Request) +{ + return STATUS_NOT_IMPLEMENTED; +} + + +/* + * FUNCTION: Closes an connection file object + * ARGUMENTS: + * Request = Pointer to TDI request structure for this request + * RETURNS: + * Status of operation + */ +NTSTATUS FileCloseConnection( + PTDI_REQUEST Request) +{ + return STATUS_NOT_IMPLEMENTED; +} + + +/* + * FUNCTION: Opens a control channel file object + * ARGUMENTS: + * Request = Pointer to TDI request structure for this request + * RETURNS: + * Status of operation + */ +NTSTATUS FileOpenControlChannel( + PTDI_REQUEST Request) +{ + return STATUS_NOT_IMPLEMENTED; +} + + +/* + * FUNCTION: Closes a control channel file object + * ARGUMENTS: + * Request = Pointer to TDI request structure for this request + * RETURNS: + * Status of operation + */ +NTSTATUS FileCloseControlChannel( + PTDI_REQUEST Request) +{ + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/info.c b/reactos/drivers/net/tcpip/tcpip/info.c index fc8f07d9505..b24c4f790a4 100644 --- a/reactos/drivers/net/tcpip/tcpip/info.c +++ b/reactos/drivers/net/tcpip/tcpip/info.c @@ -1,339 +1,339 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: tcpip/info.c - * PURPOSE: TDI query and set information routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include - - -TDI_STATUS IPTdiQueryInformationEx( - PTDI_REQUEST Request, - TDIObjectID *ID, - PNDIS_BUFFER Buffer, - PUINT BufferSize, - PVOID Context) -/* - * FUNCTION: Returns extended information about network layer - * ARGUMENTS: - * Request = Pointer to TDI request structure for the request - * ID = TDI object ID - * Buffer = Pointer to buffer with data to use. - * BufferSize = Pointer to buffer with size of Buffer. On return - * this is filled with number of bytes returned - * Context = Pointer to context buffer - * RETURNS: - * Status of operation - */ -{ - PLIST_ENTRY CurrentIFEntry; - PLIST_ENTRY CurrentADEEntry; - PIP_INTERFACE CurrentIF; - PADDRESS_ENTRY CurrentADE; - IPADDR_ENTRY IpAddress; - IPSNMP_INFO SnmpInfo; - ULONG Temp; - UINT Count; - ULONG Entity; - KIRQL OldIrql; - UINT BufSize = *BufferSize; - - /* Make return parameters consistent every time */ - *BufferSize = 0; - - Entity = ID->toi_entity.tei_entity; - if (Entity != CL_NL_ENTITY) { - /* We can't handle this entity */ - return TDI_INVALID_PARAMETER; - } - - if (ID->toi_entity.tei_instance != TL_INSTANCE) - /* We only support a single instance */ - return TDI_INVALID_REQUEST; - if (ID->toi_class == INFO_CLASS_GENERIC) { - if (ID->toi_type == INFO_TYPE_PROVIDER && - ID->toi_id == ENTITY_TYPE_ID) { - - if (BufSize < sizeof(ULONG)) - return TDI_BUFFER_TOO_SMALL; - Temp = CL_NL_IP; - - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG)); - - return TDI_SUCCESS; - } - return TDI_INVALID_PARAMETER; - } - - if (ID->toi_class == INFO_CLASS_PROTOCOL) { - if (ID->toi_type != INFO_TYPE_PROVIDER) - return TDI_INVALID_PARAMETER; - - switch (ID->toi_id) { - case IP_MIB_ADDRTABLE_ENTRY_ID: - Temp = 0; - - KeAcquireSpinLock(&InterfaceListLock, &OldIrql); - - CurrentIFEntry = InterfaceListHead.Flink; - while (CurrentIFEntry != &InterfaceListHead) { - CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); - - if (Temp + sizeof(IPADDR_ENTRY) > BufSize) { - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - return TDI_BUFFER_TOO_SMALL; - } - - IpAddress.Addr = 0; - IpAddress.BcastAddr = 0; - IpAddress.Mask = 0; - - /* Locate the diffrent addresses and put them the right place */ - CurrentADEEntry = CurrentIF->ADEListHead.Flink; - while (CurrentADEEntry != &CurrentIF->ADEListHead) { - CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); - - switch (CurrentADE->Type) { - case ADE_UNICAST: - IpAddress.Addr = CurrentADE->Address->Address.IPv4Address; - break; - case ADE_MULTICAST: - IpAddress.BcastAddr = CurrentADE->Address->Address.IPv4Address; - break; - case ADE_ADDRMASK: - IpAddress.Mask = CurrentADE->Address->Address.IPv4Address; - break; - default: - /* Should not happen */ - TI_DbgPrint(MIN_TRACE, ("Unknown address entry type (0x%X)\n", CurrentADE->Type)); - break; - } - CurrentADEEntry = CurrentADEEntry->Flink; - } - /* Pack the address information into IPADDR_ENTRY structure */ - IpAddress.Index = 0; - IpAddress.ReasmSize = 0; - IpAddress.Context = 0; - IpAddress.Pad = 0; - - Count = CopyBufferToBufferChain(Buffer, Temp, (PUCHAR)&IpAddress, sizeof(IPADDR_ENTRY)); - - Temp += sizeof(IPADDR_ENTRY); - - CurrentIFEntry = CurrentIFEntry->Flink; - } - - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - - return TDI_SUCCESS; - - case IP_MIB_STATS_ID: - if (BufSize < sizeof(IPSNMP_INFO)) - return TDI_BUFFER_TOO_SMALL; - - RtlZeroMemory(&SnmpInfo, sizeof(IPSNMP_INFO)); - - /* Count number of addresses */ - Count = 0; - KeAcquireSpinLock(&InterfaceListLock, &OldIrql); - - CurrentIFEntry = InterfaceListHead.Flink; - while (CurrentIFEntry != &InterfaceListHead) { - CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); - Count++; - CurrentIFEntry = CurrentIFEntry->Flink; - } - - KeReleaseSpinLock(&InterfaceListLock, OldIrql); - - SnmpInfo.NumAddr = Count; - - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&SnmpInfo, sizeof(IPSNMP_INFO)); - - return TDI_SUCCESS; - - default: - /* We can't handle this ID */ - return TDI_INVALID_PARAMETER; - } - } - - return TDI_INVALID_PARAMETER; -} - - -TDI_STATUS InfoTdiQueryInformationEx( - PTDI_REQUEST Request, - TDIObjectID *ID, - PNDIS_BUFFER Buffer, - PUINT BufferSize, - PVOID Context) -/* - * FUNCTION: Returns extended information - * ARGUMENTS: - * Request = Pointer to TDI request structure for the request - * ID = TDI object ID - * Buffer = Pointer to buffer with data to use - * BufferSize = Pointer to buffer with size of Buffer. On return - * this is filled with number of bytes returned - * Context = Pointer to context buffer - * RETURNS: - * Status of operation - */ -{ - PLIST_ENTRY CurrentADFEntry; - PADDRESS_FILE CurrentADF; - ADDRESS_INFO Info; - KIRQL OldIrql; - UINT Entity; - UINT Count; - UINT Size; - ULONG Temp; - UINT Offset = 0; - UINT BufSize = *BufferSize; - - /* Check wether it is a query for a list of entities */ - Entity = ID->toi_entity.tei_entity; - if (Entity == GENERIC_ENTITY) { - if (ID->toi_class != INFO_CLASS_GENERIC || - ID->toi_type != INFO_TYPE_PROVIDER || - ID->toi_id != ENTITY_LIST_ID) - return TDI_INVALID_PARAMETER; - - *BufferSize = 0; - - Size = EntityCount * sizeof(TDIEntityID); - if (BufSize < Size) - /* The buffer is too small to contain requested data */ - return TDI_BUFFER_TOO_SMALL; - - /* Return entity list */ - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)EntityList, Size); - - *BufferSize = Size; - - return TDI_SUCCESS; - } - - if ((Entity != CL_TL_ENTITY) && (Entity != CO_TL_ENTITY)) { - /* We can't handle this entity, pass it on */ - return IPTdiQueryInformationEx( - Request, ID, Buffer, BufferSize, Context); - } - - /* Make return parameters consistent every time */ - *BufferSize = 0; - - if (ID->toi_entity.tei_instance != TL_INSTANCE) - /* We only support a single instance */ - return TDI_INVALID_REQUEST; - - if (ID->toi_class == INFO_CLASS_GENERIC) { - - if (ID->toi_type != INFO_TYPE_PROVIDER || - ID->toi_id != ENTITY_TYPE_ID) - return TDI_INVALID_PARAMETER; - - if (BufSize < sizeof(ULONG)) - return TDI_BUFFER_TOO_SMALL; - - if (Entity == CL_TL_ENTITY) - Temp = CL_TL_UDP; - else if (Entity == CO_TL_ENTITY) - Temp = CO_TL_TCP; - else - return TDI_INVALID_PARAMETER; - - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG)); - - return TDI_SUCCESS; - } - - if (ID->toi_class == INFO_CLASS_PROTOCOL) { - - if (ID->toi_type != INFO_TYPE_PROVIDER) - return TDI_INVALID_PARAMETER; - - switch (ID->toi_id) { - case UDP_MIB_STAT_ID: - if (Entity != CL_TL_ENTITY) - return TDI_INVALID_PARAMETER; - - if (BufSize < sizeof(UDPStats)) - return TDI_BUFFER_TOO_SMALL; - - Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&UDPStats, sizeof(UDP_STATISTICS)); - - return TDI_SUCCESS; - - case UDP_MIB_TABLE_ID: - if (Entity != CL_TL_ENTITY) - return TDI_INVALID_PARAMETER; - - Offset = 0; - - KeAcquireSpinLock(&AddressFileListLock, &OldIrql); - - CurrentADFEntry = AddressFileListHead.Flink; - while (CurrentADFEntry != &AddressFileListHead) { - CurrentADF = CONTAINING_RECORD(CurrentADFEntry, ADDRESS_FILE, ListEntry); - - if (Offset + sizeof(ADDRESS_INFO) > BufSize) { - KeReleaseSpinLock(&AddressFileListLock, OldIrql); - *BufferSize = Offset; - return TDI_BUFFER_OVERFLOW; - } - - Info.LocalAddress = CurrentADF->ADE->Address->Address.IPv4Address; - Info.LocalPort = CurrentADF->Port; - - Count = CopyBufferToBufferChain(Buffer, Offset, (PUCHAR)&Info, sizeof(ADDRESS_INFO)); - - Offset += Count; - - CurrentADFEntry = CurrentADFEntry->Flink; - } - - KeReleaseSpinLock(&AddressFileListLock, OldIrql); - - *BufferSize = Offset; - - return STATUS_SUCCESS; - - default: - /* We can't handle this ID */ - return TDI_INVALID_PARAMETER; - } - } - - return TDI_INVALID_PARAMETER; -} - - -TDI_STATUS InfoTdiSetInformationEx( - PTDI_REQUEST Request, - TDIObjectID *ID, - PVOID Buffer, - UINT BufferSize) -/* - * FUNCTION: Sets extended information - * ARGUMENTS: - * Request = Pointer to TDI request structure for the request - * ID = Pointer to TDI object ID - * Buffer = Pointer to buffer with data to use - * BufferSize = Size of Buffer - * RETURNS: - * Status of operation - */ -{ - /* FIXME: Set extended information */ - - return TDI_INVALID_REQUEST; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: tcpip/info.c + * PURPOSE: TDI query and set information routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include + + +TDI_STATUS IPTdiQueryInformationEx( + PTDI_REQUEST Request, + TDIObjectID *ID, + PNDIS_BUFFER Buffer, + PUINT BufferSize, + PVOID Context) +/* + * FUNCTION: Returns extended information about network layer + * ARGUMENTS: + * Request = Pointer to TDI request structure for the request + * ID = TDI object ID + * Buffer = Pointer to buffer with data to use. + * BufferSize = Pointer to buffer with size of Buffer. On return + * this is filled with number of bytes returned + * Context = Pointer to context buffer + * RETURNS: + * Status of operation + */ +{ + PLIST_ENTRY CurrentIFEntry; + PLIST_ENTRY CurrentADEEntry; + PIP_INTERFACE CurrentIF; + PADDRESS_ENTRY CurrentADE; + IPADDR_ENTRY IpAddress; + IPSNMP_INFO SnmpInfo; + ULONG Temp; + UINT Count; + ULONG Entity; + KIRQL OldIrql; + UINT BufSize = *BufferSize; + + /* Make return parameters consistent every time */ + *BufferSize = 0; + + Entity = ID->toi_entity.tei_entity; + if (Entity != CL_NL_ENTITY) { + /* We can't handle this entity */ + return TDI_INVALID_PARAMETER; + } + + if (ID->toi_entity.tei_instance != TL_INSTANCE) + /* We only support a single instance */ + return TDI_INVALID_REQUEST; + if (ID->toi_class == INFO_CLASS_GENERIC) { + if (ID->toi_type == INFO_TYPE_PROVIDER && + ID->toi_id == ENTITY_TYPE_ID) { + + if (BufSize < sizeof(ULONG)) + return TDI_BUFFER_TOO_SMALL; + Temp = CL_NL_IP; + + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG)); + + return TDI_SUCCESS; + } + return TDI_INVALID_PARAMETER; + } + + if (ID->toi_class == INFO_CLASS_PROTOCOL) { + if (ID->toi_type != INFO_TYPE_PROVIDER) + return TDI_INVALID_PARAMETER; + + switch (ID->toi_id) { + case IP_MIB_ADDRTABLE_ENTRY_ID: + Temp = 0; + + KeAcquireSpinLock(&InterfaceListLock, &OldIrql); + + CurrentIFEntry = InterfaceListHead.Flink; + while (CurrentIFEntry != &InterfaceListHead) { + CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); + + if (Temp + sizeof(IPADDR_ENTRY) > BufSize) { + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + return TDI_BUFFER_TOO_SMALL; + } + + IpAddress.Addr = 0; + IpAddress.BcastAddr = 0; + IpAddress.Mask = 0; + + /* Locate the diffrent addresses and put them the right place */ + CurrentADEEntry = CurrentIF->ADEListHead.Flink; + while (CurrentADEEntry != &CurrentIF->ADEListHead) { + CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry); + + switch (CurrentADE->Type) { + case ADE_UNICAST: + IpAddress.Addr = CurrentADE->Address->Address.IPv4Address; + break; + case ADE_MULTICAST: + IpAddress.BcastAddr = CurrentADE->Address->Address.IPv4Address; + break; + case ADE_ADDRMASK: + IpAddress.Mask = CurrentADE->Address->Address.IPv4Address; + break; + default: + /* Should not happen */ + TI_DbgPrint(MIN_TRACE, ("Unknown address entry type (0x%X)\n", CurrentADE->Type)); + break; + } + CurrentADEEntry = CurrentADEEntry->Flink; + } + /* Pack the address information into IPADDR_ENTRY structure */ + IpAddress.Index = 0; + IpAddress.ReasmSize = 0; + IpAddress.Context = 0; + IpAddress.Pad = 0; + + Count = CopyBufferToBufferChain(Buffer, Temp, (PUCHAR)&IpAddress, sizeof(IPADDR_ENTRY)); + + Temp += sizeof(IPADDR_ENTRY); + + CurrentIFEntry = CurrentIFEntry->Flink; + } + + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + + return TDI_SUCCESS; + + case IP_MIB_STATS_ID: + if (BufSize < sizeof(IPSNMP_INFO)) + return TDI_BUFFER_TOO_SMALL; + + RtlZeroMemory(&SnmpInfo, sizeof(IPSNMP_INFO)); + + /* Count number of addresses */ + Count = 0; + KeAcquireSpinLock(&InterfaceListLock, &OldIrql); + + CurrentIFEntry = InterfaceListHead.Flink; + while (CurrentIFEntry != &InterfaceListHead) { + CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry); + Count++; + CurrentIFEntry = CurrentIFEntry->Flink; + } + + KeReleaseSpinLock(&InterfaceListLock, OldIrql); + + SnmpInfo.NumAddr = Count; + + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&SnmpInfo, sizeof(IPSNMP_INFO)); + + return TDI_SUCCESS; + + default: + /* We can't handle this ID */ + return TDI_INVALID_PARAMETER; + } + } + + return TDI_INVALID_PARAMETER; +} + + +TDI_STATUS InfoTdiQueryInformationEx( + PTDI_REQUEST Request, + TDIObjectID *ID, + PNDIS_BUFFER Buffer, + PUINT BufferSize, + PVOID Context) +/* + * FUNCTION: Returns extended information + * ARGUMENTS: + * Request = Pointer to TDI request structure for the request + * ID = TDI object ID + * Buffer = Pointer to buffer with data to use + * BufferSize = Pointer to buffer with size of Buffer. On return + * this is filled with number of bytes returned + * Context = Pointer to context buffer + * RETURNS: + * Status of operation + */ +{ + PLIST_ENTRY CurrentADFEntry; + PADDRESS_FILE CurrentADF; + ADDRESS_INFO Info; + KIRQL OldIrql; + UINT Entity; + UINT Count; + UINT Size; + ULONG Temp; + UINT Offset = 0; + UINT BufSize = *BufferSize; + + /* Check wether it is a query for a list of entities */ + Entity = ID->toi_entity.tei_entity; + if (Entity == GENERIC_ENTITY) { + if (ID->toi_class != INFO_CLASS_GENERIC || + ID->toi_type != INFO_TYPE_PROVIDER || + ID->toi_id != ENTITY_LIST_ID) + return TDI_INVALID_PARAMETER; + + *BufferSize = 0; + + Size = EntityCount * sizeof(TDIEntityID); + if (BufSize < Size) + /* The buffer is too small to contain requested data */ + return TDI_BUFFER_TOO_SMALL; + + /* Return entity list */ + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)EntityList, Size); + + *BufferSize = Size; + + return TDI_SUCCESS; + } + + if ((Entity != CL_TL_ENTITY) && (Entity != CO_TL_ENTITY)) { + /* We can't handle this entity, pass it on */ + return IPTdiQueryInformationEx( + Request, ID, Buffer, BufferSize, Context); + } + + /* Make return parameters consistent every time */ + *BufferSize = 0; + + if (ID->toi_entity.tei_instance != TL_INSTANCE) + /* We only support a single instance */ + return TDI_INVALID_REQUEST; + + if (ID->toi_class == INFO_CLASS_GENERIC) { + + if (ID->toi_type != INFO_TYPE_PROVIDER || + ID->toi_id != ENTITY_TYPE_ID) + return TDI_INVALID_PARAMETER; + + if (BufSize < sizeof(ULONG)) + return TDI_BUFFER_TOO_SMALL; + + if (Entity == CL_TL_ENTITY) + Temp = CL_TL_UDP; + else if (Entity == CO_TL_ENTITY) + Temp = CO_TL_TCP; + else + return TDI_INVALID_PARAMETER; + + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG)); + + return TDI_SUCCESS; + } + + if (ID->toi_class == INFO_CLASS_PROTOCOL) { + + if (ID->toi_type != INFO_TYPE_PROVIDER) + return TDI_INVALID_PARAMETER; + + switch (ID->toi_id) { + case UDP_MIB_STAT_ID: + if (Entity != CL_TL_ENTITY) + return TDI_INVALID_PARAMETER; + + if (BufSize < sizeof(UDPStats)) + return TDI_BUFFER_TOO_SMALL; + + Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&UDPStats, sizeof(UDP_STATISTICS)); + + return TDI_SUCCESS; + + case UDP_MIB_TABLE_ID: + if (Entity != CL_TL_ENTITY) + return TDI_INVALID_PARAMETER; + + Offset = 0; + + KeAcquireSpinLock(&AddressFileListLock, &OldIrql); + + CurrentADFEntry = AddressFileListHead.Flink; + while (CurrentADFEntry != &AddressFileListHead) { + CurrentADF = CONTAINING_RECORD(CurrentADFEntry, ADDRESS_FILE, ListEntry); + + if (Offset + sizeof(ADDRESS_INFO) > BufSize) { + KeReleaseSpinLock(&AddressFileListLock, OldIrql); + *BufferSize = Offset; + return TDI_BUFFER_OVERFLOW; + } + + Info.LocalAddress = CurrentADF->ADE->Address->Address.IPv4Address; + Info.LocalPort = CurrentADF->Port; + + Count = CopyBufferToBufferChain(Buffer, Offset, (PUCHAR)&Info, sizeof(ADDRESS_INFO)); + + Offset += Count; + + CurrentADFEntry = CurrentADFEntry->Flink; + } + + KeReleaseSpinLock(&AddressFileListLock, OldIrql); + + *BufferSize = Offset; + + return STATUS_SUCCESS; + + default: + /* We can't handle this ID */ + return TDI_INVALID_PARAMETER; + } + } + + return TDI_INVALID_PARAMETER; +} + + +TDI_STATUS InfoTdiSetInformationEx( + PTDI_REQUEST Request, + TDIObjectID *ID, + PVOID Buffer, + UINT BufferSize) +/* + * FUNCTION: Sets extended information + * ARGUMENTS: + * Request = Pointer to TDI request structure for the request + * ID = Pointer to TDI object ID + * Buffer = Pointer to buffer with data to use + * BufferSize = Size of Buffer + * RETURNS: + * Status of operation + */ +{ + /* FIXME: Set extended information */ + + return TDI_INVALID_REQUEST; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/main.c b/reactos/drivers/net/tcpip/tcpip/main.c index 3162b910c22..0dab08f29b5 100644 --- a/reactos/drivers/net/tcpip/tcpip/main.c +++ b/reactos/drivers/net/tcpip/tcpip/main.c @@ -1,805 +1,805 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: tcpip/main.c - * PURPOSE: Driver entry point - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifdef DBG -/* See debug.h for debug/trace constants */ -DWORD DebugTraceLevel = MIN_TRACE; -#endif /* DBG */ - -PDEVICE_OBJECT TCPDeviceObject = NULL; -PDEVICE_OBJECT UDPDeviceObject = NULL; -PDEVICE_OBJECT IPDeviceObject = NULL; -PDEVICE_OBJECT RawIPDeviceObject = NULL; -NDIS_HANDLE GlobalPacketPool = NULL; -NDIS_HANDLE GlobalBufferPool = NULL; -TDIEntityID *EntityList = NULL; -ULONG EntityCount = 0; -UDP_STATISTICS UDPStats; - - -VOID TiWriteErrorLog( - PDRIVER_OBJECT DriverContext, - NTSTATUS ErrorCode, - ULONG UniqueErrorValue, - NTSTATUS FinalStatus, - PWSTR String, - ULONG DumpDataCount, - PULONG DumpData) -/* - * FUNCTION: Writes an error log entry - * ARGUMENTS: - * DriverContext = Pointer to the driver or device object - * ErrorCode = An error code to put in the log entry - * UniqueErrorValue = UniqueErrorValue in the error log packet - * FinalStatus = FinalStatus in the error log packet - * String = If not NULL, a pointer to a string to put in log entry - * DumpDataCount = Number of ULONGs of dump data - * DumpData = Pointer to dump data for the log entry - */ -{ -#ifdef _MSC_VER - PIO_ERROR_LOG_PACKET LogEntry; - UCHAR EntrySize; - ULONG StringSize; - PUCHAR pString; - static WCHAR DriverName[] = L"TCP/IP"; - - EntrySize = sizeof(IO_ERROR_LOG_PACKET) + - (DumpDataCount * sizeof(ULONG)) + sizeof(DriverName); - - if (String) { - StringSize = (wcslen(String) * sizeof(WCHAR)) + sizeof(UNICODE_NULL); - EntrySize += (UCHAR)StringSize; - } - - LogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( - DriverContext, EntrySize); - - if (LogEntry) { - LogEntry->MajorFunctionCode = -1; - LogEntry->RetryCount = -1; - LogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG)); - LogEntry->NumberOfStrings = (String == NULL) ? 1 : 2; - LogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) + (DumpDataCount-1) * sizeof(ULONG); - LogEntry->EventCategory = 0; - LogEntry->ErrorCode = ErrorCode; - LogEntry->UniqueErrorValue = UniqueErrorValue; - LogEntry->FinalStatus = FinalStatus; - LogEntry->SequenceNumber = -1; - LogEntry->IoControlCode = 0; - - if (DumpDataCount) - RtlCopyMemory(LogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG)); - - pString = ((PUCHAR)LogEntry) + LogEntry->StringOffset; - RtlCopyMemory(pString, DriverName, sizeof(DriverName)); - pString += sizeof(DriverName); - - if (String) - RtlCopyMemory(pString, String, StringSize); - - IoWriteErrorLogEntry(LogEntry); - } -#endif -} - - -/* - * FUNCTION: Creates a file object - * ARGUMENTS: - * DeviceObject = Pointer to a device object for this driver - * Irp = Pointer to a I/O request packet - * RETURNS: - * Status of the operation - */ -NTSTATUS TiCreateFileObject( - PDEVICE_OBJECT DeviceObject, - PIRP Irp) -{ - PIO_STACK_LOCATION IrpSp; - PFILE_FULL_EA_INFORMATION EaInfo; - PTA_ADDRESS_IP Address; - PTRANSPORT_CONTEXT Context; - TDI_REQUEST Request; - NTSTATUS Status; - - TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp)); - - EaInfo = Irp->AssociatedIrp.SystemBuffer; - - /* Parameter check */ - if (!EaInfo) { - TI_DbgPrint(MIN_TRACE, ("No EA information in IRP.\n")); - return STATUS_INVALID_PARAMETER; - } - - /* Allocate resources here. We release them again if something failed */ - Context = ExAllocatePool(NonPagedPool, sizeof(TRANSPORT_CONTEXT)); - if (!Context) { - TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); - return STATUS_INSUFFICIENT_RESOURCES; - } - - Context->RefCount = 1; - Context->CancelIrps = FALSE; - KeInitializeEvent(&Context->CleanupEvent, NotificationEvent, FALSE); - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - IrpSp->FileObject->FsContext = Context; - Request.RequestContext = Irp; - - /* Branch to the right handler */ - if ((EaInfo->EaNameLength==TDI_TRANSPORT_ADDRESS_LENGTH) && - (RtlCompareMemory(&EaInfo->EaName, TdiTransportAddress, - TDI_TRANSPORT_ADDRESS_LENGTH) == TDI_TRANSPORT_ADDRESS_LENGTH)) { - /* This is a request to open an address */ - - /* Parameter checks */ - Address = (PTA_ADDRESS_IP)(EaInfo->EaName + EaInfo->EaNameLength + 1); - if ((EaInfo->EaValueLength < sizeof(TA_ADDRESS_IP)) || - (Address->TAAddressCount != 1) || - (Address->Address[0].AddressLength < sizeof(TDI_ADDRESS_IP)) || - (Address->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)) { - TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n")); - ExFreePool(Context); - return STATUS_INVALID_PARAMETER; - } - - /* Open address file object */ - /* FIXME: Protocol depends on device object */ - Status = FileOpenAddress(&Request, Address, IPPROTO_UDP, NULL); - if (NT_SUCCESS(Status)) { - IrpSp->FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE; - Context->Handle.AddressHandle = Request.Handle.AddressHandle; - } - } else { - TI_DbgPrint(MIN_TRACE, ("Connection point, and control connections are not supported.\n")); - /* FIXME: Open a connection endpoint, or control connection */ - Status = STATUS_NOT_IMPLEMENTED; - } - - if (!NT_SUCCESS(Status)) - ExFreePool(Context); - - TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status)); - - return Status; -} - - -VOID TiCleanupFileObjectComplete( - PVOID Context, - NTSTATUS Status) -/* - * FUNCTION: Completes an object cleanup IRP I/O request - * ARGUMENTS: - * Context = Pointer to the IRP for this request - * Status = Final status of the operation - */ -{ - PIRP Irp; - PIO_STACK_LOCATION IrpSp; - PTRANSPORT_CONTEXT TranContext; - KIRQL OldIrql; - - Irp = (PIRP)Context; - IrpSp = IoGetCurrentIrpStackLocation(Irp); - TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; - - Irp->IoStatus.Status = Status; - - IoAcquireCancelSpinLock(&OldIrql); - - /* Remove the initial reference provided at object creation time */ - TranContext->RefCount--; - -#ifdef DBG - if (TranContext->RefCount != 0) - TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount is %i, should be 0.\n", TranContext->RefCount)); -#endif - - KeSetEvent(&TranContext->CleanupEvent, 0, FALSE); - - IoReleaseCancelSpinLock(OldIrql); -} - - -/* - * FUNCTION: Releases resources used by a file object - * ARGUMENTS: - * DeviceObject = Pointer to a device object for this driver - * Irp = Pointer to a I/O request packet - * RETURNS: - * Status of the operation - * NOTES: - * This function does not pend - */ -NTSTATUS TiCleanupFileObject( - PDEVICE_OBJECT DeviceObject, - PIRP Irp) -{ - PIO_STACK_LOCATION IrpSp; - PTRANSPORT_CONTEXT Context; - TDI_REQUEST Request; - NTSTATUS Status; - KIRQL OldIrql; - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - Context = IrpSp->FileObject->FsContext; - if (!Context) { - TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n")); - return STATUS_INVALID_PARAMETER; - } - - IoAcquireCancelSpinLock(&OldIrql); - - Context->CancelIrps = TRUE; - KeResetEvent(&Context->CleanupEvent); - - IoReleaseCancelSpinLock(OldIrql); - - Request.RequestNotifyObject = TiCleanupFileObjectComplete; - Request.RequestContext = Irp; - - switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) { - case TDI_TRANSPORT_ADDRESS_FILE: - Request.Handle.AddressHandle = Context->Handle.AddressHandle; - Status = FileCloseAddress(&Request); - break; - - case TDI_CONNECTION_FILE: - Request.Handle.ConnectionContext = Context->Handle.ConnectionContext; - Status = FileCloseConnection(&Request); - break; - - case TDI_CONTROL_CHANNEL_FILE: - Request.Handle.ControlChannel = Context->Handle.ControlChannel; - Status = FileCloseControlChannel(&Request); - break; - - default: - /* This should never happen */ - - TI_DbgPrint(MIN_TRACE, ("Unknown transport context.\n")); - - IoAcquireCancelSpinLock(&OldIrql); - Context->CancelIrps = FALSE; - IoReleaseCancelSpinLock(OldIrql); - - return STATUS_INVALID_PARAMETER; - } - - if (Status != STATUS_PENDING) - TiCleanupFileObjectComplete(Irp, Status); - - KeWaitForSingleObject(&Context->CleanupEvent, - UserRequest, KernelMode, FALSE, NULL); - - return Irp->IoStatus.Status; -} - - -NTSTATUS TiDispatchOpenClose( - PDEVICE_OBJECT DeviceObject, - PIRP Irp) -/* - * FUNCTION: Main dispath routine - * ARGUMENTS: - * DeviceObject = Pointer to a device object for this driver - * Irp = Pointer to a I/O request packet - * RETURNS: - * Status of the operation - */ -{ - PIO_STACK_LOCATION IrpSp; - NTSTATUS Status; - PTRANSPORT_CONTEXT Context; - - TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp)); - - IoMarkIrpPending(Irp); - Irp->IoStatus.Status = STATUS_PENDING; - Irp->IoStatus.Information = 0; - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - - switch (IrpSp->MajorFunction) { - /* Open an address file, connection endpoint, or control connection */ - case IRP_MJ_CREATE: - Status = TiCreateFileObject(DeviceObject, Irp); - break; - - /* Close an address file, connection endpoint, or control connection */ - case IRP_MJ_CLOSE: - Context = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; - if (Context) - ExFreePool(Context); - Status = STATUS_SUCCESS; - break; - - /* Release resources bound to an address file, connection endpoint, - or control connection */ - case IRP_MJ_CLEANUP: - Status = TiCleanupFileObject(DeviceObject, Irp); - break; - - default: - Status = STATUS_INVALID_DEVICE_REQUEST; - } - - if (Status != STATUS_PENDING) { - IrpSp->Control &= ~SL_PENDING_RETURNED; - Irp->IoStatus.Status = Status; - - TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); - - IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); - } - - TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status)); - - return Status; -} - - -NTSTATUS TiDispatchInternal( - PDEVICE_OBJECT DeviceObject, - PIRP Irp) -/* - * FUNCTION: Internal IOCTL dispatch routine - * 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; - - TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp)); - - IrpSp = IoGetCurrentIrpStackLocation(Irp); - - Irp->IoStatus.Status = STATUS_SUCCESS; - Irp->IoStatus.Information = 0; - - switch (IrpSp->MinorFunction) { - case TDI_RECEIVE: - Status = DispTdiReceive(Irp); - break; - - case TDI_RECEIVE_DATAGRAM: - Status = DispTdiReceiveDatagram(Irp); - break; - - case TDI_SEND: - Status = DispTdiSend(Irp); - break; - - case TDI_SEND_DATAGRAM: - Status = DispTdiSendDatagram(Irp); - break; - - case TDI_ACCEPT: - Status = DispTdiAccept(Irp); - break; - - case TDI_LISTEN: - Status = DispTdiListen(Irp); - break; - - case TDI_CONNECT: - Status = DispTdiConnect(Irp); - break; - - case TDI_DISCONNECT: - Status = DispTdiDisconnect(Irp); - break; - - case TDI_ASSOCIATE_ADDRESS: - Status = DispTdiAssociateAddress(Irp); - break; - - case TDI_DISASSOCIATE_ADDRESS: - Status = DispTdiDisassociateAddress(Irp); - break; - - case TDI_QUERY_INFORMATION: - Status = DispTdiQueryInformation(DeviceObject, Irp); - break; - - case TDI_SET_INFORMATION: - Status = DispTdiSetInformation(Irp); - break; - - case TDI_SET_EVENT_HANDLER: - Status = DispTdiSetEventHandler(Irp); - break; - - case TDI_ACTION: - Status = STATUS_SUCCESS; - break; - - /* An unsupported IOCTL code was submitted */ - default: - Status = STATUS_INVALID_DEVICE_REQUEST; - } - - if (Status != STATUS_PENDING) { - Irp->IoStatus.Status = Status; - - TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); - - IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); - } - - TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status)); - - return Status; -} - - -NTSTATUS TiDispatch( - PDEVICE_OBJECT DeviceObject, - PIRP Irp) -/* - * FUNCTION: Dispath 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; - - TI_DbgPrint(DEBUG_IRP, ("Called. IRP is at (0x%X).\n", Irp)); - - Irp->IoStatus.Information = 0; - - IrpSp = IoGetCurrentIrpStackLocation(Irp); -#ifdef _MSC_VER - 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: - Status = DispTdiQueryInformationEx(Irp, IrpSp); - break; - - case IOCTL_TCP_SET_INFORMATION_EX: - Status = DispTdiSetInformationEx(Irp, IrpSp); - break; - - default: - TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n", - IrpSp->Parameters.DeviceIoControl.IoControlCode)); - Status = STATUS_NOT_IMPLEMENTED; - break; - } - } - - if (Status != STATUS_PENDING) { - Irp->IoStatus.Status = Status; - - TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); - - IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); - } - - TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status)); - - return Status; -} - - -VOID TiUnload( - PDRIVER_OBJECT DriverObject) -/* - * FUNCTION: Unloads the driver - * ARGUMENTS: - * DriverObject = Pointer to driver object created by the system - */ -{ -#ifdef BDG - KIRQL OldIrql; - - KeAcquireSpinLock(&AddressFileListLock, &OldIrql); - if (!IsListEmpty(AddressFileList)) { - TI_DbgPrint(MIN_TRACE, ("Open address file objects exists.\n")); - } - KeReleaseSpinLock(&AddressFileListLock, OldIrql); -#endif - - /* Unregister loopback adapter */ - LoopUnregisterAdapter(NULL); - - /* Unregister protocol with NDIS */ -#ifdef _MSC_VER - LANUnregisterProtocol(); -#endif - - /* Shutdown transport level protocol subsystems */ - TCPShutdown(); - UDPShutdown(); - RawIPShutdown(); - DGShutdown(); - - /* 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) - IoDeleteDevice(IPDeviceObject); - - if (EntityList) - ExFreePool(EntityList); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); -} - - -NTSTATUS -#ifndef _MSC_VER -STDCALL -#endif -DriverEntry( - PDRIVER_OBJECT DriverObject, - PUNICODE_STRING RegistryPath) -/* - * FUNCTION: Main driver entry point - * ARGUMENTS: - * DriverObject = Pointer to a driver object for this driver - * RegistryPath = Registry node for configuration parameters - * RETURNS: - * Status of driver initialization - */ -{ - NTSTATUS Status; - UNICODE_STRING strDeviceName; - STRING strNdisDeviceName; - NDIS_STATUS NdisStatus; -#ifdef _MSC_VER - PLAN_ADAPTER Adapter; - NDIS_STRING DeviceName; -#endif - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - /* Create IP device object */ - RtlInitUnicodeString(&strDeviceName, DD_IP_DEVICE_NAME); - Status = IoCreateDevice(DriverObject, 0, &strDeviceName, - FILE_DEVICE_NETWORK, 0, FALSE, &IPDeviceObject); - if (!NT_SUCCESS(Status)) { - TI_DbgPrint(MIN_TRACE, ("Failed to create IP device object. Status (0x%X).\n", Status)); - return Status; - } - - /* Create RawIP device object */ - RtlInitUnicodeString(&strDeviceName, DD_RAWIP_DEVICE_NAME); - Status = IoCreateDevice(DriverObject, 0, &strDeviceName, - FILE_DEVICE_NETWORK, 0, FALSE, &RawIPDeviceObject); - if (!NT_SUCCESS(Status)) { - TI_DbgPrint(MIN_TRACE, ("Failed to create RawIP device object. Status (0x%X).\n", Status)); - TiUnload(DriverObject); - return Status; - } - - /* Create UDP device object */ - RtlInitUnicodeString(&strDeviceName, DD_UDP_DEVICE_NAME); - Status = IoCreateDevice(DriverObject, 0, &strDeviceName, - FILE_DEVICE_NETWORK, 0, FALSE, &UDPDeviceObject); - if (!NT_SUCCESS(Status)) { - TI_DbgPrint(MIN_TRACE, ("Failed to create UDP device object. Status (0x%X).\n", Status)); - TiUnload(DriverObject); - return Status; - } - - /* Create TCP device object */ - RtlInitUnicodeString(&strDeviceName, DD_TCP_DEVICE_NAME); - Status = IoCreateDevice(DriverObject, 0, &strDeviceName, - FILE_DEVICE_NETWORK, 0, FALSE, &TCPDeviceObject); - if (!NT_SUCCESS(Status)) { - TI_DbgPrint(MIN_TRACE, ("Failed to create TCP device object. Status (0x%X).\n", Status)); - TiUnload(DriverObject); - return Status; - } - - /* Allocate NDIS packet descriptors */ - NdisAllocatePacketPool(&NdisStatus, &GlobalPacketPool, 100, sizeof(PACKET_CONTEXT)); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TiUnload(DriverObject); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Allocate NDIS buffer descriptors */ - NdisAllocateBufferPool(&NdisStatus, &GlobalBufferPool, 100); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TiUnload(DriverObject); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Initialize address file list and protecting spin lock */ - InitializeListHead(&AddressFileListHead); - KeInitializeSpinLock(&AddressFileListLock); - - /* Initialize interface list and protecting spin lock */ - InitializeListHead(&InterfaceListHead); - KeInitializeSpinLock(&InterfaceListLock); - - /* Initialize network level protocol subsystem */ - IPStartup(DriverObject, RegistryPath); - - /* Initialize transport level protocol subsystems */ - DGStartup(); - RawIPStartup(); - UDPStartup(); - TCPStartup(); - - /* Register protocol with NDIS */ - RtlInitString(&strNdisDeviceName, IP_DEVICE_NAME); - Status = LANRegisterProtocol(&strNdisDeviceName); - if (!NT_SUCCESS(Status)) { - TiWriteErrorLog( - DriverObject, - EVENT_TRANSPORT_REGISTER_FAILED, - TI_ERROR_DRIVERENTRY, - Status, - NULL, - 0, - NULL); - TiUnload(DriverObject); - return Status; - } - - /* Open loopback adapter */ - if (!NT_SUCCESS(LoopRegisterAdapter(NULL, NULL))) { - TI_DbgPrint(MIN_TRACE, ("Failed to create loopback adapter. Status (0x%X).\n", Status)); - TiUnload(DriverObject); - return STATUS_INSUFFICIENT_RESOURCES; - } -#if 1 -#ifdef _MSC_VER - /* Open underlying adapter(s) we are bound to */ - - /* FIXME: Get binding information from registry */ - - /* Put your own NDIS adapter device name here */ - -#if 0 - /* NT4 */ - NdisInitUnicodeString(&DeviceName, L"\\Device\\El90x1"); -#else - /* NT5 */ - NdisInitUnicodeString(&DeviceName, - L"\\Device\\{56388B49-67BB-4419-A3F4-28DF190B9149}"); -#endif - - NdisStatus = LANRegisterAdapter(&DeviceName, &Adapter); - if (!NT_SUCCESS(NdisStatus)) { - TI_DbgPrint(MIN_TRACE, ("Failed to intialize adapter. Status (0x%X).\n", Status)); - TiWriteErrorLog( - DriverObject, - EVENT_TRANSPORT_ADAPTER_NOT_FOUND, - TI_ERROR_DRIVERENTRY, - NdisStatus, - NULL, - 0, - NULL); - TiUnload(DriverObject); - return STATUS_DEVICE_DOES_NOT_EXIST; - } -#endif -#endif - /* Setup network layer and transport layer entities */ - EntityList = ExAllocatePool(NonPagedPool, sizeof(TDIEntityID) * 2); - if (!NT_SUCCESS(Status)) { - TiUnload(DriverObject); - return STATUS_INSUFFICIENT_RESOURCES; - } - - EntityList[0].tei_entity = CL_NL_ENTITY; - EntityList[0].tei_instance = 0; - EntityList[1].tei_entity = CL_TL_ENTITY; - EntityList[1].tei_instance = 0; - EntityCount = 2; - - /* Use direct I/O */ - IPDeviceObject->Flags |= DO_DIRECT_IO; - RawIPDeviceObject->Flags |= DO_DIRECT_IO; - UDPDeviceObject->Flags |= DO_DIRECT_IO; - TCPDeviceObject->Flags |= DO_DIRECT_IO; - - /* Initialize the driver object with this driver's entry points */ - DriverObject->MajorFunction[IRP_MJ_CREATE] = TiDispatchOpenClose; - DriverObject->MajorFunction[IRP_MJ_CLOSE] = TiDispatchOpenClose; - DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TiDispatchOpenClose; - DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = TiDispatchInternal; - DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TiDispatch; - - DriverObject->DriverUnload = (PDRIVER_UNLOAD)TiUnload; - - return STATUS_SUCCESS; -} - - -VOID -#ifndef _MSC_VER -STDCALL -#endif -IPAddInterface( - DWORD Unknown0, - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3, - DWORD Unknown4) -{ - UNIMPLEMENTED -} - - -VOID -#ifndef _MSC_VER -STDCALL -#endif -IPDelInterface( - DWORD Unknown0) -{ - UNIMPLEMENTED -} - - -VOID -#ifndef _MSC_VER -STDCALL -#endif -LookupRoute( - DWORD Unknown0, - DWORD Unknown1) -{ - UNIMPLEMENTED -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: tcpip/main.c + * PURPOSE: Driver entry point + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef DBG +/* See debug.h for debug/trace constants */ +DWORD DebugTraceLevel = MIN_TRACE; +#endif /* DBG */ + +PDEVICE_OBJECT TCPDeviceObject = NULL; +PDEVICE_OBJECT UDPDeviceObject = NULL; +PDEVICE_OBJECT IPDeviceObject = NULL; +PDEVICE_OBJECT RawIPDeviceObject = NULL; +NDIS_HANDLE GlobalPacketPool = NULL; +NDIS_HANDLE GlobalBufferPool = NULL; +TDIEntityID *EntityList = NULL; +ULONG EntityCount = 0; +UDP_STATISTICS UDPStats; + + +VOID TiWriteErrorLog( + PDRIVER_OBJECT DriverContext, + NTSTATUS ErrorCode, + ULONG UniqueErrorValue, + NTSTATUS FinalStatus, + PWSTR String, + ULONG DumpDataCount, + PULONG DumpData) +/* + * FUNCTION: Writes an error log entry + * ARGUMENTS: + * DriverContext = Pointer to the driver or device object + * ErrorCode = An error code to put in the log entry + * UniqueErrorValue = UniqueErrorValue in the error log packet + * FinalStatus = FinalStatus in the error log packet + * String = If not NULL, a pointer to a string to put in log entry + * DumpDataCount = Number of ULONGs of dump data + * DumpData = Pointer to dump data for the log entry + */ +{ +#ifdef _MSC_VER + PIO_ERROR_LOG_PACKET LogEntry; + UCHAR EntrySize; + ULONG StringSize; + PUCHAR pString; + static WCHAR DriverName[] = L"TCP/IP"; + + EntrySize = sizeof(IO_ERROR_LOG_PACKET) + + (DumpDataCount * sizeof(ULONG)) + sizeof(DriverName); + + if (String) { + StringSize = (wcslen(String) * sizeof(WCHAR)) + sizeof(UNICODE_NULL); + EntrySize += (UCHAR)StringSize; + } + + LogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry( + DriverContext, EntrySize); + + if (LogEntry) { + LogEntry->MajorFunctionCode = -1; + LogEntry->RetryCount = -1; + LogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG)); + LogEntry->NumberOfStrings = (String == NULL) ? 1 : 2; + LogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) + (DumpDataCount-1) * sizeof(ULONG); + LogEntry->EventCategory = 0; + LogEntry->ErrorCode = ErrorCode; + LogEntry->UniqueErrorValue = UniqueErrorValue; + LogEntry->FinalStatus = FinalStatus; + LogEntry->SequenceNumber = -1; + LogEntry->IoControlCode = 0; + + if (DumpDataCount) + RtlCopyMemory(LogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG)); + + pString = ((PUCHAR)LogEntry) + LogEntry->StringOffset; + RtlCopyMemory(pString, DriverName, sizeof(DriverName)); + pString += sizeof(DriverName); + + if (String) + RtlCopyMemory(pString, String, StringSize); + + IoWriteErrorLogEntry(LogEntry); + } +#endif +} + + +/* + * FUNCTION: Creates a file object + * ARGUMENTS: + * DeviceObject = Pointer to a device object for this driver + * Irp = Pointer to a I/O request packet + * RETURNS: + * Status of the operation + */ +NTSTATUS TiCreateFileObject( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PIO_STACK_LOCATION IrpSp; + PFILE_FULL_EA_INFORMATION EaInfo; + PTA_ADDRESS_IP Address; + PTRANSPORT_CONTEXT Context; + TDI_REQUEST Request; + NTSTATUS Status; + + TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp)); + + EaInfo = Irp->AssociatedIrp.SystemBuffer; + + /* Parameter check */ + if (!EaInfo) { + TI_DbgPrint(MIN_TRACE, ("No EA information in IRP.\n")); + return STATUS_INVALID_PARAMETER; + } + + /* Allocate resources here. We release them again if something failed */ + Context = ExAllocatePool(NonPagedPool, sizeof(TRANSPORT_CONTEXT)); + if (!Context) { + TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Context->RefCount = 1; + Context->CancelIrps = FALSE; + KeInitializeEvent(&Context->CleanupEvent, NotificationEvent, FALSE); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + IrpSp->FileObject->FsContext = Context; + Request.RequestContext = Irp; + + /* Branch to the right handler */ + if ((EaInfo->EaNameLength==TDI_TRANSPORT_ADDRESS_LENGTH) && + (RtlCompareMemory(&EaInfo->EaName, TdiTransportAddress, + TDI_TRANSPORT_ADDRESS_LENGTH) == TDI_TRANSPORT_ADDRESS_LENGTH)) { + /* This is a request to open an address */ + + /* Parameter checks */ + Address = (PTA_ADDRESS_IP)(EaInfo->EaName + EaInfo->EaNameLength + 1); + if ((EaInfo->EaValueLength < sizeof(TA_ADDRESS_IP)) || + (Address->TAAddressCount != 1) || + (Address->Address[0].AddressLength < sizeof(TDI_ADDRESS_IP)) || + (Address->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)) { + TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n")); + ExFreePool(Context); + return STATUS_INVALID_PARAMETER; + } + + /* Open address file object */ + /* FIXME: Protocol depends on device object */ + Status = FileOpenAddress(&Request, Address, IPPROTO_UDP, NULL); + if (NT_SUCCESS(Status)) { + IrpSp->FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE; + Context->Handle.AddressHandle = Request.Handle.AddressHandle; + } + } else { + TI_DbgPrint(MIN_TRACE, ("Connection point, and control connections are not supported.\n")); + /* FIXME: Open a connection endpoint, or control connection */ + Status = STATUS_NOT_IMPLEMENTED; + } + + if (!NT_SUCCESS(Status)) + ExFreePool(Context); + + TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status)); + + return Status; +} + + +VOID TiCleanupFileObjectComplete( + PVOID Context, + NTSTATUS Status) +/* + * FUNCTION: Completes an object cleanup IRP I/O request + * ARGUMENTS: + * Context = Pointer to the IRP for this request + * Status = Final status of the operation + */ +{ + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + PTRANSPORT_CONTEXT TranContext; + KIRQL OldIrql; + + Irp = (PIRP)Context; + IrpSp = IoGetCurrentIrpStackLocation(Irp); + TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; + + Irp->IoStatus.Status = Status; + + IoAcquireCancelSpinLock(&OldIrql); + + /* Remove the initial reference provided at object creation time */ + TranContext->RefCount--; + +#ifdef DBG + if (TranContext->RefCount != 0) + TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount is %i, should be 0.\n", TranContext->RefCount)); +#endif + + KeSetEvent(&TranContext->CleanupEvent, 0, FALSE); + + IoReleaseCancelSpinLock(OldIrql); +} + + +/* + * FUNCTION: Releases resources used by a file object + * ARGUMENTS: + * DeviceObject = Pointer to a device object for this driver + * Irp = Pointer to a I/O request packet + * RETURNS: + * Status of the operation + * NOTES: + * This function does not pend + */ +NTSTATUS TiCleanupFileObject( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +{ + PIO_STACK_LOCATION IrpSp; + PTRANSPORT_CONTEXT Context; + TDI_REQUEST Request; + NTSTATUS Status; + KIRQL OldIrql; + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + Context = IrpSp->FileObject->FsContext; + if (!Context) { + TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n")); + return STATUS_INVALID_PARAMETER; + } + + IoAcquireCancelSpinLock(&OldIrql); + + Context->CancelIrps = TRUE; + KeResetEvent(&Context->CleanupEvent); + + IoReleaseCancelSpinLock(OldIrql); + + Request.RequestNotifyObject = TiCleanupFileObjectComplete; + Request.RequestContext = Irp; + + switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) { + case TDI_TRANSPORT_ADDRESS_FILE: + Request.Handle.AddressHandle = Context->Handle.AddressHandle; + Status = FileCloseAddress(&Request); + break; + + case TDI_CONNECTION_FILE: + Request.Handle.ConnectionContext = Context->Handle.ConnectionContext; + Status = FileCloseConnection(&Request); + break; + + case TDI_CONTROL_CHANNEL_FILE: + Request.Handle.ControlChannel = Context->Handle.ControlChannel; + Status = FileCloseControlChannel(&Request); + break; + + default: + /* This should never happen */ + + TI_DbgPrint(MIN_TRACE, ("Unknown transport context.\n")); + + IoAcquireCancelSpinLock(&OldIrql); + Context->CancelIrps = FALSE; + IoReleaseCancelSpinLock(OldIrql); + + return STATUS_INVALID_PARAMETER; + } + + if (Status != STATUS_PENDING) + TiCleanupFileObjectComplete(Irp, Status); + + KeWaitForSingleObject(&Context->CleanupEvent, + UserRequest, KernelMode, FALSE, NULL); + + return Irp->IoStatus.Status; +} + + +NTSTATUS TiDispatchOpenClose( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +/* + * FUNCTION: Main dispath routine + * ARGUMENTS: + * DeviceObject = Pointer to a device object for this driver + * Irp = Pointer to a I/O request packet + * RETURNS: + * Status of the operation + */ +{ + PIO_STACK_LOCATION IrpSp; + NTSTATUS Status; + PTRANSPORT_CONTEXT Context; + + TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp)); + + IoMarkIrpPending(Irp); + Irp->IoStatus.Status = STATUS_PENDING; + Irp->IoStatus.Information = 0; + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + switch (IrpSp->MajorFunction) { + /* Open an address file, connection endpoint, or control connection */ + case IRP_MJ_CREATE: + Status = TiCreateFileObject(DeviceObject, Irp); + break; + + /* Close an address file, connection endpoint, or control connection */ + case IRP_MJ_CLOSE: + Context = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext; + if (Context) + ExFreePool(Context); + Status = STATUS_SUCCESS; + break; + + /* Release resources bound to an address file, connection endpoint, + or control connection */ + case IRP_MJ_CLEANUP: + Status = TiCleanupFileObject(DeviceObject, Irp); + break; + + default: + Status = STATUS_INVALID_DEVICE_REQUEST; + } + + if (Status != STATUS_PENDING) { + IrpSp->Control &= ~SL_PENDING_RETURNED; + Irp->IoStatus.Status = Status; + + TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + } + + TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status)); + + return Status; +} + + +NTSTATUS TiDispatchInternal( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +/* + * FUNCTION: Internal IOCTL dispatch routine + * 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; + + TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp)); + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + switch (IrpSp->MinorFunction) { + case TDI_RECEIVE: + Status = DispTdiReceive(Irp); + break; + + case TDI_RECEIVE_DATAGRAM: + Status = DispTdiReceiveDatagram(Irp); + break; + + case TDI_SEND: + Status = DispTdiSend(Irp); + break; + + case TDI_SEND_DATAGRAM: + Status = DispTdiSendDatagram(Irp); + break; + + case TDI_ACCEPT: + Status = DispTdiAccept(Irp); + break; + + case TDI_LISTEN: + Status = DispTdiListen(Irp); + break; + + case TDI_CONNECT: + Status = DispTdiConnect(Irp); + break; + + case TDI_DISCONNECT: + Status = DispTdiDisconnect(Irp); + break; + + case TDI_ASSOCIATE_ADDRESS: + Status = DispTdiAssociateAddress(Irp); + break; + + case TDI_DISASSOCIATE_ADDRESS: + Status = DispTdiDisassociateAddress(Irp); + break; + + case TDI_QUERY_INFORMATION: + Status = DispTdiQueryInformation(DeviceObject, Irp); + break; + + case TDI_SET_INFORMATION: + Status = DispTdiSetInformation(Irp); + break; + + case TDI_SET_EVENT_HANDLER: + Status = DispTdiSetEventHandler(Irp); + break; + + case TDI_ACTION: + Status = STATUS_SUCCESS; + break; + + /* An unsupported IOCTL code was submitted */ + default: + Status = STATUS_INVALID_DEVICE_REQUEST; + } + + if (Status != STATUS_PENDING) { + Irp->IoStatus.Status = Status; + + TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + } + + TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status)); + + return Status; +} + + +NTSTATUS TiDispatch( + PDEVICE_OBJECT DeviceObject, + PIRP Irp) +/* + * FUNCTION: Dispath 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; + + TI_DbgPrint(DEBUG_IRP, ("Called. IRP is at (0x%X).\n", Irp)); + + Irp->IoStatus.Information = 0; + + IrpSp = IoGetCurrentIrpStackLocation(Irp); +#ifdef _MSC_VER + 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: + Status = DispTdiQueryInformationEx(Irp, IrpSp); + break; + + case IOCTL_TCP_SET_INFORMATION_EX: + Status = DispTdiSetInformationEx(Irp, IrpSp); + break; + + default: + TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n", + IrpSp->Parameters.DeviceIoControl.IoControlCode)); + Status = STATUS_NOT_IMPLEMENTED; + break; + } + } + + if (Status != STATUS_PENDING) { + Irp->IoStatus.Status = Status; + + TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp)); + + IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); + } + + TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status)); + + return Status; +} + + +VOID TiUnload( + PDRIVER_OBJECT DriverObject) +/* + * FUNCTION: Unloads the driver + * ARGUMENTS: + * DriverObject = Pointer to driver object created by the system + */ +{ +#ifdef BDG + KIRQL OldIrql; + + KeAcquireSpinLock(&AddressFileListLock, &OldIrql); + if (!IsListEmpty(AddressFileList)) { + TI_DbgPrint(MIN_TRACE, ("Open address file objects exists.\n")); + } + KeReleaseSpinLock(&AddressFileListLock, OldIrql); +#endif + + /* Unregister loopback adapter */ + LoopUnregisterAdapter(NULL); + + /* Unregister protocol with NDIS */ +#ifdef _MSC_VER + LANUnregisterProtocol(); +#endif + + /* Shutdown transport level protocol subsystems */ + TCPShutdown(); + UDPShutdown(); + RawIPShutdown(); + DGShutdown(); + + /* 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) + IoDeleteDevice(IPDeviceObject); + + if (EntityList) + ExFreePool(EntityList); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); +} + + +NTSTATUS +#ifndef _MSC_VER +STDCALL +#endif +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +/* + * FUNCTION: Main driver entry point + * ARGUMENTS: + * DriverObject = Pointer to a driver object for this driver + * RegistryPath = Registry node for configuration parameters + * RETURNS: + * Status of driver initialization + */ +{ + NTSTATUS Status; + UNICODE_STRING strDeviceName; + STRING strNdisDeviceName; + NDIS_STATUS NdisStatus; +#ifdef _MSC_VER + PLAN_ADAPTER Adapter; + NDIS_STRING DeviceName; +#endif + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + /* Create IP device object */ + RtlInitUnicodeString(&strDeviceName, DD_IP_DEVICE_NAME); + Status = IoCreateDevice(DriverObject, 0, &strDeviceName, + FILE_DEVICE_NETWORK, 0, FALSE, &IPDeviceObject); + if (!NT_SUCCESS(Status)) { + TI_DbgPrint(MIN_TRACE, ("Failed to create IP device object. Status (0x%X).\n", Status)); + return Status; + } + + /* Create RawIP device object */ + RtlInitUnicodeString(&strDeviceName, DD_RAWIP_DEVICE_NAME); + Status = IoCreateDevice(DriverObject, 0, &strDeviceName, + FILE_DEVICE_NETWORK, 0, FALSE, &RawIPDeviceObject); + if (!NT_SUCCESS(Status)) { + TI_DbgPrint(MIN_TRACE, ("Failed to create RawIP device object. Status (0x%X).\n", Status)); + TiUnload(DriverObject); + return Status; + } + + /* Create UDP device object */ + RtlInitUnicodeString(&strDeviceName, DD_UDP_DEVICE_NAME); + Status = IoCreateDevice(DriverObject, 0, &strDeviceName, + FILE_DEVICE_NETWORK, 0, FALSE, &UDPDeviceObject); + if (!NT_SUCCESS(Status)) { + TI_DbgPrint(MIN_TRACE, ("Failed to create UDP device object. Status (0x%X).\n", Status)); + TiUnload(DriverObject); + return Status; + } + + /* Create TCP device object */ + RtlInitUnicodeString(&strDeviceName, DD_TCP_DEVICE_NAME); + Status = IoCreateDevice(DriverObject, 0, &strDeviceName, + FILE_DEVICE_NETWORK, 0, FALSE, &TCPDeviceObject); + if (!NT_SUCCESS(Status)) { + TI_DbgPrint(MIN_TRACE, ("Failed to create TCP device object. Status (0x%X).\n", Status)); + TiUnload(DriverObject); + return Status; + } + + /* Allocate NDIS packet descriptors */ + NdisAllocatePacketPool(&NdisStatus, &GlobalPacketPool, 100, sizeof(PACKET_CONTEXT)); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + TiUnload(DriverObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Allocate NDIS buffer descriptors */ + NdisAllocateBufferPool(&NdisStatus, &GlobalBufferPool, 100); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + TiUnload(DriverObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Initialize address file list and protecting spin lock */ + InitializeListHead(&AddressFileListHead); + KeInitializeSpinLock(&AddressFileListLock); + + /* Initialize interface list and protecting spin lock */ + InitializeListHead(&InterfaceListHead); + KeInitializeSpinLock(&InterfaceListLock); + + /* Initialize network level protocol subsystem */ + IPStartup(DriverObject, RegistryPath); + + /* Initialize transport level protocol subsystems */ + DGStartup(); + RawIPStartup(); + UDPStartup(); + TCPStartup(); + + /* Register protocol with NDIS */ + RtlInitString(&strNdisDeviceName, IP_DEVICE_NAME); + Status = LANRegisterProtocol(&strNdisDeviceName); + if (!NT_SUCCESS(Status)) { + TiWriteErrorLog( + DriverObject, + EVENT_TRANSPORT_REGISTER_FAILED, + TI_ERROR_DRIVERENTRY, + Status, + NULL, + 0, + NULL); + TiUnload(DriverObject); + return Status; + } + + /* Open loopback adapter */ + if (!NT_SUCCESS(LoopRegisterAdapter(NULL, NULL))) { + TI_DbgPrint(MIN_TRACE, ("Failed to create loopback adapter. Status (0x%X).\n", Status)); + TiUnload(DriverObject); + return STATUS_INSUFFICIENT_RESOURCES; + } +#if 1 +#ifdef _MSC_VER + /* Open underlying adapter(s) we are bound to */ + + /* FIXME: Get binding information from registry */ + + /* Put your own NDIS adapter device name here */ + +#if 0 + /* NT4 */ + NdisInitUnicodeString(&DeviceName, L"\\Device\\El90x1"); +#else + /* NT5 */ + NdisInitUnicodeString(&DeviceName, + L"\\Device\\{56388B49-67BB-4419-A3F4-28DF190B9149}"); +#endif + + NdisStatus = LANRegisterAdapter(&DeviceName, &Adapter); + if (!NT_SUCCESS(NdisStatus)) { + TI_DbgPrint(MIN_TRACE, ("Failed to intialize adapter. Status (0x%X).\n", Status)); + TiWriteErrorLog( + DriverObject, + EVENT_TRANSPORT_ADAPTER_NOT_FOUND, + TI_ERROR_DRIVERENTRY, + NdisStatus, + NULL, + 0, + NULL); + TiUnload(DriverObject); + return STATUS_DEVICE_DOES_NOT_EXIST; + } +#endif +#endif + /* Setup network layer and transport layer entities */ + EntityList = ExAllocatePool(NonPagedPool, sizeof(TDIEntityID) * 2); + if (!NT_SUCCESS(Status)) { + TiUnload(DriverObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + EntityList[0].tei_entity = CL_NL_ENTITY; + EntityList[0].tei_instance = 0; + EntityList[1].tei_entity = CL_TL_ENTITY; + EntityList[1].tei_instance = 0; + EntityCount = 2; + + /* Use direct I/O */ + IPDeviceObject->Flags |= DO_DIRECT_IO; + RawIPDeviceObject->Flags |= DO_DIRECT_IO; + UDPDeviceObject->Flags |= DO_DIRECT_IO; + TCPDeviceObject->Flags |= DO_DIRECT_IO; + + /* Initialize the driver object with this driver's entry points */ + DriverObject->MajorFunction[IRP_MJ_CREATE] = TiDispatchOpenClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = TiDispatchOpenClose; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TiDispatchOpenClose; + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = TiDispatchInternal; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TiDispatch; + + DriverObject->DriverUnload = (PDRIVER_UNLOAD)TiUnload; + + return STATUS_SUCCESS; +} + + +VOID +#ifndef _MSC_VER +STDCALL +#endif +IPAddInterface( + DWORD Unknown0, + DWORD Unknown1, + DWORD Unknown2, + DWORD Unknown3, + DWORD Unknown4) +{ + UNIMPLEMENTED +} + + +VOID +#ifndef _MSC_VER +STDCALL +#endif +IPDelInterface( + DWORD Unknown0) +{ + UNIMPLEMENTED +} + + +VOID +#ifndef _MSC_VER +STDCALL +#endif +LookupRoute( + DWORD Unknown0, + DWORD Unknown1) +{ + UNIMPLEMENTED +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/pool.c b/reactos/drivers/net/tcpip/tcpip/pool.c index da7335247bf..ca6782289e3 100644 --- a/reactos/drivers/net/tcpip/tcpip/pool.c +++ b/reactos/drivers/net/tcpip/tcpip/pool.c @@ -1,50 +1,50 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: tcpip/pool.c - * PURPOSE: Routines for controling pools - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include - - -PVOID PoolAllocateBuffer( - ULONG Size) -/* - * FUNCTION: Returns a buffer from the free buffer pool - * RETURNS: - * Pointer to buffer, NULL if there was not enough - * free resources - */ -{ - PVOID Buffer; - - /* FIXME: Get buffer from a free buffer pool with enough room */ - - Buffer = ExAllocatePool(NonPagedPool, Size); - - TI_DbgPrint(DEBUG_MEMORY, ("Allocated (%i) bytes at (0x%X).\n", Size, Buffer)); - - return Buffer; -} - - -VOID PoolFreeBuffer( - PVOID Buffer) -/* - * FUNCTION: Returns a buffer to the free buffer pool - * ARGUMENTS: - * Buffer = Buffer to return to free buffer pool - */ -{ - /* FIXME: Put buffer in free buffer pool */ - - TI_DbgPrint(DEBUG_MEMORY, ("Freeing buffer at (0x%X).\n", Buffer)); - - ExFreePool(Buffer); -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: tcpip/pool.c + * PURPOSE: Routines for controling pools + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include + + +PVOID PoolAllocateBuffer( + ULONG Size) +/* + * FUNCTION: Returns a buffer from the free buffer pool + * RETURNS: + * Pointer to buffer, NULL if there was not enough + * free resources + */ +{ + PVOID Buffer; + + /* FIXME: Get buffer from a free buffer pool with enough room */ + + Buffer = ExAllocatePool(NonPagedPool, Size); + + TI_DbgPrint(DEBUG_MEMORY, ("Allocated (%i) bytes at (0x%X).\n", Size, Buffer)); + + return Buffer; +} + + +VOID PoolFreeBuffer( + PVOID Buffer) +/* + * FUNCTION: Returns a buffer to the free buffer pool + * ARGUMENTS: + * Buffer = Buffer to return to free buffer pool + */ +{ + /* FIXME: Put buffer in free buffer pool */ + + TI_DbgPrint(DEBUG_MEMORY, ("Freeing buffer at (0x%X).\n", Buffer)); + + ExFreePool(Buffer); +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/resource.rc b/reactos/drivers/net/tcpip/tcpip/resource.rc index 0c634d20083..a5c8ca55d54 100644 --- a/reactos/drivers/net/tcpip/tcpip/resource.rc +++ b/reactos/drivers/net/tcpip/tcpip/resource.rc @@ -1,10 +1,10 @@ -#include -#include - -#define VER_FILETYPE VFT_DRV -#define VER_FILESUBTYPE VFT2_DRV_NETWORK -#define VER_FILEDESCRIPTION_STR "TCP/IP protocol driver" -#define VER_INTERNALNAME_STR "TCPIP.SYS" -#define VER_ORIGINALFILENAME_STR "TCPIP.SYS" - -#include "common.ver" +#include +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_NETWORK +#define VER_FILEDESCRIPTION_STR "TCP/IP protocol driver" +#define VER_INTERNALNAME_STR "TCPIP.SYS" +#define VER_ORIGINALFILENAME_STR "TCPIP.SYS" + +#include "common.ver" diff --git a/reactos/drivers/net/tcpip/tcpip/routines.c b/reactos/drivers/net/tcpip/tcpip/routines.c index 223e76bb8d4..9f48df7db8b 100644 --- a/reactos/drivers/net/tcpip/tcpip/routines.c +++ b/reactos/drivers/net/tcpip/tcpip/routines.c @@ -1,403 +1,403 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: tcpip/routines.c - * PURPOSE: Common routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include - - -UINT RandomNumber = 0x12345678; - - -UINT Random( - VOID) -/* - * FUNCTION: Returns a pseudo random number - * RETURNS: - * Pseudo random number - */ -{ - RandomNumber ^= 0x78563412; - - return RandomNumber; -} - - -__inline INT SkipToOffset( - PNDIS_BUFFER Buffer, - UINT Offset, - PUCHAR *Data, - PUINT Size) -/* - * FUNCTION: Skip Offset bytes into a buffer chain - * ARGUMENTS: - * Buffer = Pointer to NDIS buffer - * Offset = Number of bytes to skip - * Data = Address of a pointer that on return will contain the - * address of the offset in the buffer - * Size = Address of a pointer that on return will contain the - * size of the destination buffer - * RETURNS: - * Offset into buffer, -1 if buffer chain was smaller than Offset bytes - * NOTES: - * Buffer may be NULL - */ -{ - for (;;) { - - if (!Buffer) - return -1; - - NdisQueryBuffer(Buffer, Data, Size); - - if (Offset < *Size) { - ((ULONG_PTR)*Data) += Offset; - *Size -= Offset; - break; - } - - Offset -= *Size; - - NdisGetNextBuffer(Buffer, &Buffer); - } - - return Offset; -} - - -UINT CopyBufferToBufferChain( - PNDIS_BUFFER DstBuffer, - UINT DstOffset, - PUCHAR SrcData, - UINT Length) -/* - * FUNCTION: Copies data from a buffer to an NDIS buffer chain - * ARGUMENTS: - * DstBuffer = Pointer to destination NDIS buffer - * DstOffset = Destination start offset - * SrcData = Pointer to source buffer - * Length = Number of bytes to copy - * RETURNS: - * Number of bytes copied to destination buffer - * NOTES: - * The number of bytes copied may be limited by the destination - * buffer size - */ -{ - UINT BytesCopied, BytesToCopy, DstSize; - PUCHAR DstData; - - TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X) DstOffset (0x%X) SrcData (0x%X) Length (%d)\n", DstBuffer, DstOffset, SrcData, Length)); - - /* Skip DstOffset bytes in the destination buffer chain */ - if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1) - return 0; - - /* Start copying the data */ - BytesCopied = 0; - for (;;) { - BytesToCopy = MIN(DstSize, Length); - - RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy); - BytesCopied += BytesToCopy; - (ULONG_PTR)SrcData += BytesToCopy; - - Length -= BytesToCopy; - if (Length == 0) - break; - - DstSize -= BytesToCopy; - if (DstSize == 0) { - /* No more bytes in desination buffer. Proceed to - the next buffer in the destination buffer chain */ - NdisGetNextBuffer(DstBuffer, &DstBuffer); - if (!DstBuffer) - break; - - NdisQueryBuffer(DstBuffer, &DstData, &DstSize); - } - } - - return BytesCopied; -} - - -UINT CopyBufferChainToBuffer( - PUCHAR DstData, - PNDIS_BUFFER SrcBuffer, - UINT SrcOffset, - UINT Length) -/* - * FUNCTION: Copies data from an NDIS buffer chain to a buffer - * ARGUMENTS: - * DstData = Pointer to destination buffer - * SrcBuffer = Pointer to source NDIS buffer - * SrcOffset = Source start offset - * Length = Number of bytes to copy - * RETURNS: - * Number of bytes copied to destination buffer - * NOTES: - * The number of bytes copied may be limited by the source - * buffer size - */ -{ - UINT BytesCopied, BytesToCopy, SrcSize; - PUCHAR SrcData; - - TI_DbgPrint(DEBUG_BUFFER, ("DstData 0x%X SrcBuffer 0x%X SrcOffset 0x%X Length %d\n",DstData,SrcBuffer, SrcOffset, Length)); - - /* Skip SrcOffset bytes in the source buffer chain */ - if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1) - return 0; - - /* Start copying the data */ - BytesCopied = 0; - for (;;) { - BytesToCopy = MIN(SrcSize, Length); - - TI_DbgPrint(DEBUG_BUFFER, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData)); - - RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy); - BytesCopied += BytesToCopy; - (ULONG_PTR)DstData += BytesToCopy; - - Length -= BytesToCopy; - if (Length == 0) - break; - - SrcSize -= BytesToCopy; - if (SrcSize == 0) { - /* No more bytes in source buffer. Proceed to - the next buffer in the source buffer chain */ - NdisGetNextBuffer(SrcBuffer, &SrcBuffer); - if (!SrcBuffer) - break; - - NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize); - } - } - - return BytesCopied; -} - - -UINT CopyPacketToBuffer( - PUCHAR DstData, - PNDIS_PACKET SrcPacket, - UINT SrcOffset, - UINT Length) -/* - * FUNCTION: Copies data from an NDIS packet to a buffer - * ARGUMENTS: - * DstData = Pointer to destination buffer - * SrcPacket = Pointer to source NDIS packet - * SrcOffset = Source start offset - * Length = Number of bytes to copy - * RETURNS: - * Number of bytes copied to destination buffer - * NOTES: - * The number of bytes copied may be limited by the source - * buffer size - */ -{ - PNDIS_BUFFER FirstBuffer; - PVOID Address; - UINT FirstLength; - UINT TotalLength; - - TI_DbgPrint(DEBUG_BUFFER, ("DstData (0x%X) SrcPacket (0x%X) SrcOffset (0x%X) Length (%d)\n", DstData, SrcPacket, SrcOffset, Length)); - - NdisGetFirstBufferFromPacket(SrcPacket, - &FirstBuffer, - &Address, - &FirstLength, - &TotalLength); - - return CopyBufferChainToBuffer(DstData, FirstBuffer, SrcOffset, Length); -} - - -UINT CopyPacketToBufferChain( - PNDIS_BUFFER DstBuffer, - UINT DstOffset, - PNDIS_PACKET SrcPacket, - UINT SrcOffset, - UINT Length) -/* - * FUNCTION: Copies data from an NDIS packet to an NDIS buffer chain - * ARGUMENTS: - * DstBuffer = Pointer to destination NDIS buffer - * DstOffset = Destination start offset - * SrcPacket = Pointer to source NDIS packet - * SrcOffset = Source start offset - * Length = Number of bytes to copy - * RETURNS: - * Number of bytes copied to destination buffer - * NOTES: - * The number of bytes copied may be limited by the source and - * destination buffer sizes - */ -{ - PNDIS_BUFFER SrcBuffer; - PUCHAR DstData, SrcData; - UINT DstSize, SrcSize; - UINT Count, Total; - - TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X) DstOffset (0x%X) SrcPacket (0x%X) SrcOffset (0x%X) Length (%d)\n", DstBuffer, DstOffset, SrcPacket, SrcOffset, Length)); - - /* Skip DstOffset bytes in the destination buffer chain */ - NdisQueryBuffer(DstBuffer, &DstData, &DstSize); - if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1) - return 0; - - /* Skip SrcOffset bytes in the source packet */ - NdisGetFirstBufferFromPacket(SrcPacket, &SrcBuffer, &SrcData, &SrcSize, &Total); - if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1) - return 0; - - /* Copy the data */ - for (Total = 0;;) { - /* Find out how many bytes we can copy at one time */ - if (Length < SrcSize) - Count = Length; - else - Count = SrcSize; - if (DstSize < Count) - Count = DstSize; - - RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, Count); - - Total += Count; - Length -= Count; - if (Length == 0) - break; - - DstSize -= Count; - if (DstSize == 0) { - /* No more bytes in destination buffer. Proceed to - the next buffer in the destination buffer chain */ - NdisGetNextBuffer(DstBuffer, &DstBuffer); - if (!DstBuffer) - break; - - NdisQueryBuffer(DstBuffer, &DstData, &DstSize); - } - - SrcSize -= Count; - if (SrcSize == 0) { - /* No more bytes in source buffer. Proceed to - the next buffer in the source buffer chain */ - NdisGetNextBuffer(SrcBuffer, &SrcBuffer); - if (!SrcBuffer) - break; - - NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize); - } - } - - return Total; -} - - -VOID FreeNdisPacket( - PNDIS_PACKET Packet) -/* - * FUNCTION: Frees an NDIS packet - * ARGUMENTS: - * Packet = Pointer to NDIS packet to be freed - */ -{ - PNDIS_BUFFER Buffer, NextBuffer; - - TI_DbgPrint(DEBUG_BUFFER, ("Packet (0x%X)\n", Packet)); - - /* Free all the buffers in the packet first */ - NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL); - for (; Buffer != NULL; Buffer = NextBuffer) { - PVOID Data; - UINT Length; - - NdisGetNextBuffer(Buffer, &NextBuffer); - NdisQueryBuffer(Buffer, &Data, &Length); - NdisFreeBuffer(Buffer); - ExFreePool(Data); - } - - /* Finally free the NDIS packet discriptor */ - NdisFreePacket(Packet); -} - - -PVOID AdjustPacket( - PNDIS_PACKET Packet, - UINT Available, - UINT Needed) -/* - * FUNCTION: Adjusts the amount of unused space at the beginning of the packet - * ARGUMENTS: - * Packet = Pointer to packet - * Available = Number of bytes available at start of first buffer - * Needed = Number of bytes needed for the header - * RETURNS: - * Pointer to start of packet - */ -{ - PNDIS_BUFFER NdisBuffer; - INT Adjust; - - TI_DbgPrint(DEBUG_BUFFER, ("Available = %d, Needed = %d.\n", Available, Needed)); - - Adjust = Available - Needed; - - NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL); - - /* If Adjust is zero there is no need to adjust this packet as - there is no additional space at start the of first buffer */ - if (Adjust != 0) { -#if 0 - (ULONG_PTR)(NdisBuffer->MappedSystemVa) += Adjust; - (ULONG_PTR)(NdisBuffer->StartVa) += Adjust; - NdisBuffer->ByteCount -= Adjust; -#else - (ULONG_PTR)(NdisBuffer->MappedSystemVa) += Adjust; - NdisBuffer->ByteOffset += Adjust; - NdisBuffer->ByteCount -= Adjust; -#endif - } - - return NdisBuffer->MappedSystemVa; -} - - -UINT ResizePacket( - PNDIS_PACKET Packet, - UINT Size) -/* - * FUNCTION: Resizes an NDIS packet - * ARGUMENTS: - * Packet = Pointer to packet - * Size = Number of bytes in first buffer - * RETURNS: - * Previous size of first buffer - */ -{ - PNDIS_BUFFER NdisBuffer; - UINT OldSize; - - NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL); - - OldSize = NdisBuffer->ByteCount; - - if (Size != OldSize) - NdisBuffer->ByteCount = Size; - - return OldSize; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: tcpip/routines.c + * PURPOSE: Common routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include + + +UINT RandomNumber = 0x12345678; + + +UINT Random( + VOID) +/* + * FUNCTION: Returns a pseudo random number + * RETURNS: + * Pseudo random number + */ +{ + RandomNumber ^= 0x78563412; + + return RandomNumber; +} + + +__inline INT SkipToOffset( + PNDIS_BUFFER Buffer, + UINT Offset, + PUCHAR *Data, + PUINT Size) +/* + * FUNCTION: Skip Offset bytes into a buffer chain + * ARGUMENTS: + * Buffer = Pointer to NDIS buffer + * Offset = Number of bytes to skip + * Data = Address of a pointer that on return will contain the + * address of the offset in the buffer + * Size = Address of a pointer that on return will contain the + * size of the destination buffer + * RETURNS: + * Offset into buffer, -1 if buffer chain was smaller than Offset bytes + * NOTES: + * Buffer may be NULL + */ +{ + for (;;) { + + if (!Buffer) + return -1; + + NdisQueryBuffer(Buffer, Data, Size); + + if (Offset < *Size) { + ((ULONG_PTR)*Data) += Offset; + *Size -= Offset; + break; + } + + Offset -= *Size; + + NdisGetNextBuffer(Buffer, &Buffer); + } + + return Offset; +} + + +UINT CopyBufferToBufferChain( + PNDIS_BUFFER DstBuffer, + UINT DstOffset, + PUCHAR SrcData, + UINT Length) +/* + * FUNCTION: Copies data from a buffer to an NDIS buffer chain + * ARGUMENTS: + * DstBuffer = Pointer to destination NDIS buffer + * DstOffset = Destination start offset + * SrcData = Pointer to source buffer + * Length = Number of bytes to copy + * RETURNS: + * Number of bytes copied to destination buffer + * NOTES: + * The number of bytes copied may be limited by the destination + * buffer size + */ +{ + UINT BytesCopied, BytesToCopy, DstSize; + PUCHAR DstData; + + TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X) DstOffset (0x%X) SrcData (0x%X) Length (%d)\n", DstBuffer, DstOffset, SrcData, Length)); + + /* Skip DstOffset bytes in the destination buffer chain */ + if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1) + return 0; + + /* Start copying the data */ + BytesCopied = 0; + for (;;) { + BytesToCopy = MIN(DstSize, Length); + + RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy); + BytesCopied += BytesToCopy; + (ULONG_PTR)SrcData += BytesToCopy; + + Length -= BytesToCopy; + if (Length == 0) + break; + + DstSize -= BytesToCopy; + if (DstSize == 0) { + /* No more bytes in desination buffer. Proceed to + the next buffer in the destination buffer chain */ + NdisGetNextBuffer(DstBuffer, &DstBuffer); + if (!DstBuffer) + break; + + NdisQueryBuffer(DstBuffer, &DstData, &DstSize); + } + } + + return BytesCopied; +} + + +UINT CopyBufferChainToBuffer( + PUCHAR DstData, + PNDIS_BUFFER SrcBuffer, + UINT SrcOffset, + UINT Length) +/* + * FUNCTION: Copies data from an NDIS buffer chain to a buffer + * ARGUMENTS: + * DstData = Pointer to destination buffer + * SrcBuffer = Pointer to source NDIS buffer + * SrcOffset = Source start offset + * Length = Number of bytes to copy + * RETURNS: + * Number of bytes copied to destination buffer + * NOTES: + * The number of bytes copied may be limited by the source + * buffer size + */ +{ + UINT BytesCopied, BytesToCopy, SrcSize; + PUCHAR SrcData; + + TI_DbgPrint(DEBUG_BUFFER, ("DstData 0x%X SrcBuffer 0x%X SrcOffset 0x%X Length %d\n",DstData,SrcBuffer, SrcOffset, Length)); + + /* Skip SrcOffset bytes in the source buffer chain */ + if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1) + return 0; + + /* Start copying the data */ + BytesCopied = 0; + for (;;) { + BytesToCopy = MIN(SrcSize, Length); + + TI_DbgPrint(DEBUG_BUFFER, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData)); + + RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy); + BytesCopied += BytesToCopy; + (ULONG_PTR)DstData += BytesToCopy; + + Length -= BytesToCopy; + if (Length == 0) + break; + + SrcSize -= BytesToCopy; + if (SrcSize == 0) { + /* No more bytes in source buffer. Proceed to + the next buffer in the source buffer chain */ + NdisGetNextBuffer(SrcBuffer, &SrcBuffer); + if (!SrcBuffer) + break; + + NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize); + } + } + + return BytesCopied; +} + + +UINT CopyPacketToBuffer( + PUCHAR DstData, + PNDIS_PACKET SrcPacket, + UINT SrcOffset, + UINT Length) +/* + * FUNCTION: Copies data from an NDIS packet to a buffer + * ARGUMENTS: + * DstData = Pointer to destination buffer + * SrcPacket = Pointer to source NDIS packet + * SrcOffset = Source start offset + * Length = Number of bytes to copy + * RETURNS: + * Number of bytes copied to destination buffer + * NOTES: + * The number of bytes copied may be limited by the source + * buffer size + */ +{ + PNDIS_BUFFER FirstBuffer; + PVOID Address; + UINT FirstLength; + UINT TotalLength; + + TI_DbgPrint(DEBUG_BUFFER, ("DstData (0x%X) SrcPacket (0x%X) SrcOffset (0x%X) Length (%d)\n", DstData, SrcPacket, SrcOffset, Length)); + + NdisGetFirstBufferFromPacket(SrcPacket, + &FirstBuffer, + &Address, + &FirstLength, + &TotalLength); + + return CopyBufferChainToBuffer(DstData, FirstBuffer, SrcOffset, Length); +} + + +UINT CopyPacketToBufferChain( + PNDIS_BUFFER DstBuffer, + UINT DstOffset, + PNDIS_PACKET SrcPacket, + UINT SrcOffset, + UINT Length) +/* + * FUNCTION: Copies data from an NDIS packet to an NDIS buffer chain + * ARGUMENTS: + * DstBuffer = Pointer to destination NDIS buffer + * DstOffset = Destination start offset + * SrcPacket = Pointer to source NDIS packet + * SrcOffset = Source start offset + * Length = Number of bytes to copy + * RETURNS: + * Number of bytes copied to destination buffer + * NOTES: + * The number of bytes copied may be limited by the source and + * destination buffer sizes + */ +{ + PNDIS_BUFFER SrcBuffer; + PUCHAR DstData, SrcData; + UINT DstSize, SrcSize; + UINT Count, Total; + + TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X) DstOffset (0x%X) SrcPacket (0x%X) SrcOffset (0x%X) Length (%d)\n", DstBuffer, DstOffset, SrcPacket, SrcOffset, Length)); + + /* Skip DstOffset bytes in the destination buffer chain */ + NdisQueryBuffer(DstBuffer, &DstData, &DstSize); + if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1) + return 0; + + /* Skip SrcOffset bytes in the source packet */ + NdisGetFirstBufferFromPacket(SrcPacket, &SrcBuffer, &SrcData, &SrcSize, &Total); + if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1) + return 0; + + /* Copy the data */ + for (Total = 0;;) { + /* Find out how many bytes we can copy at one time */ + if (Length < SrcSize) + Count = Length; + else + Count = SrcSize; + if (DstSize < Count) + Count = DstSize; + + RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, Count); + + Total += Count; + Length -= Count; + if (Length == 0) + break; + + DstSize -= Count; + if (DstSize == 0) { + /* No more bytes in destination buffer. Proceed to + the next buffer in the destination buffer chain */ + NdisGetNextBuffer(DstBuffer, &DstBuffer); + if (!DstBuffer) + break; + + NdisQueryBuffer(DstBuffer, &DstData, &DstSize); + } + + SrcSize -= Count; + if (SrcSize == 0) { + /* No more bytes in source buffer. Proceed to + the next buffer in the source buffer chain */ + NdisGetNextBuffer(SrcBuffer, &SrcBuffer); + if (!SrcBuffer) + break; + + NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize); + } + } + + return Total; +} + + +VOID FreeNdisPacket( + PNDIS_PACKET Packet) +/* + * FUNCTION: Frees an NDIS packet + * ARGUMENTS: + * Packet = Pointer to NDIS packet to be freed + */ +{ + PNDIS_BUFFER Buffer, NextBuffer; + + TI_DbgPrint(DEBUG_BUFFER, ("Packet (0x%X)\n", Packet)); + + /* Free all the buffers in the packet first */ + NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL); + for (; Buffer != NULL; Buffer = NextBuffer) { + PVOID Data; + UINT Length; + + NdisGetNextBuffer(Buffer, &NextBuffer); + NdisQueryBuffer(Buffer, &Data, &Length); + NdisFreeBuffer(Buffer); + ExFreePool(Data); + } + + /* Finally free the NDIS packet discriptor */ + NdisFreePacket(Packet); +} + + +PVOID AdjustPacket( + PNDIS_PACKET Packet, + UINT Available, + UINT Needed) +/* + * FUNCTION: Adjusts the amount of unused space at the beginning of the packet + * ARGUMENTS: + * Packet = Pointer to packet + * Available = Number of bytes available at start of first buffer + * Needed = Number of bytes needed for the header + * RETURNS: + * Pointer to start of packet + */ +{ + PNDIS_BUFFER NdisBuffer; + INT Adjust; + + TI_DbgPrint(DEBUG_BUFFER, ("Available = %d, Needed = %d.\n", Available, Needed)); + + Adjust = Available - Needed; + + NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL); + + /* If Adjust is zero there is no need to adjust this packet as + there is no additional space at start the of first buffer */ + if (Adjust != 0) { +#if 0 + (ULONG_PTR)(NdisBuffer->MappedSystemVa) += Adjust; + (ULONG_PTR)(NdisBuffer->StartVa) += Adjust; + NdisBuffer->ByteCount -= Adjust; +#else + (ULONG_PTR)(NdisBuffer->MappedSystemVa) += Adjust; + NdisBuffer->ByteOffset += Adjust; + NdisBuffer->ByteCount -= Adjust; +#endif + } + + return NdisBuffer->MappedSystemVa; +} + + +UINT ResizePacket( + PNDIS_PACKET Packet, + UINT Size) +/* + * FUNCTION: Resizes an NDIS packet + * ARGUMENTS: + * Packet = Pointer to packet + * Size = Number of bytes in first buffer + * RETURNS: + * Previous size of first buffer + */ +{ + PNDIS_BUFFER NdisBuffer; + UINT OldSize; + + NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL); + + OldSize = NdisBuffer->ByteCount; + + if (Size != OldSize) + NdisBuffer->ByteCount = Size; + + return OldSize; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/tcpip/tcpip.def b/reactos/drivers/net/tcpip/tcpip/tcpip.def new file mode 100644 index 00000000000..136ec91e976 --- /dev/null +++ b/reactos/drivers/net/tcpip/tcpip/tcpip.def @@ -0,0 +1,32 @@ +; TCPIP.SYS - TCP/IP protocol driver + +LIBRARY tcpip.sys + +EXPORTS +;FreeIprBuff +;GetIFAndLink +IPAddInterface +;IPAllocBuff +IPDelInterface +;IPDelayedNdisReEnumerateBindings +;IPDeregisterARP +;IPDisableSniffer +;IPEnableSniffer +;IPFreeBuff +;IPGetAddrType +;IPGetBestInterface +;IPGetInfo +;IPInjectPkt +;IPProxyNdisRequest +;IPRegisterARP +;IPRegisterProtocol +;IPSetIPSecStatus +;IPTransmit +LookupRoute +;LookupRouteInformation +;SendICMPErr +;SetIPSecPtr +;UnSetIPSecPtr +;UnSetIPSecSendPtr + +; EOF diff --git a/reactos/drivers/net/tcpip/transport/DIRS b/reactos/drivers/net/tcpip/transport/DIRS index 901d4264f20..4ff3f7f6bae 100644 --- a/reactos/drivers/net/tcpip/transport/DIRS +++ b/reactos/drivers/net/tcpip/transport/DIRS @@ -1,5 +1,5 @@ -DIRS= datagram \ - rawip \ - tcp \ - udp - +DIRS= datagram \ + rawip \ + tcp \ + udp + diff --git a/reactos/drivers/net/tcpip/transport/datagram/Makefile b/reactos/drivers/net/tcpip/transport/datagram/Makefile index 9c985f57bc6..58189757d61 100644 --- a/reactos/drivers/net/tcpip/transport/datagram/Makefile +++ b/reactos/drivers/net/tcpip/transport/datagram/Makefile @@ -1,7 +1,7 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/reactos/drivers/net/tcpip/transport/datagram/SOURCES b/reactos/drivers/net/tcpip/transport/datagram/SOURCES index aef69b1c025..50cbe51ea52 100644 --- a/reactos/drivers/net/tcpip/transport/datagram/SOURCES +++ b/reactos/drivers/net/tcpip/transport/datagram/SOURCES @@ -1,13 +1,13 @@ -TARGETNAME=datagram -TARGETPATH=..\..\objects -TARGETTYPE=LIBRARY - -TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ - $(DDK_LIB_PATH)\ndis.lib - -INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net - -SOURCES= datagram.c - -MSC_WARNING_LEVEL=/W3 /WX - +TARGETNAME=datagram +TARGETPATH=..\..\objects +TARGETTYPE=LIBRARY + +TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ + $(DDK_LIB_PATH)\ndis.lib + +INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net + +SOURCES= datagram.c + +MSC_WARNING_LEVEL=/W3 /WX + diff --git a/reactos/drivers/net/tcpip/transport/datagram/datagram.c b/reactos/drivers/net/tcpip/transport/datagram/datagram.c index 9f792feaf97..ac9d48e908d 100644 --- a/reactos/drivers/net/tcpip/transport/datagram/datagram.c +++ b/reactos/drivers/net/tcpip/transport/datagram/datagram.c @@ -1,520 +1,520 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: transport/datagram/datagram.c - * PURPOSE: Routines for sending and receiving datagrams - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include - - -/* Pending request queue */ -LIST_ENTRY DGPendingListHead; -KSPIN_LOCK DGPendingListLock; -/* Work queue item for pending requests */ -WORK_QUEUE_ITEM DGWorkItem; - - -VOID DatagramWorker( - PVOID Context) -/* - * FUNCTION: Handles pending requests - * ARGUMENTS: - * Context = Pointer to context information (unused) - * NOTES: - * This routine is called after the driver has run out of resources. - * It processes send requests or shedules them to be processed - */ -{ - PLIST_ENTRY CurrentADFEntry; - PLIST_ENTRY CurrentSREntry; - PADDRESS_FILE CurrentADF; - PDATAGRAM_SEND_REQUEST CurrentSR; - KIRQL OldIrql1; - KIRQL OldIrql2; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - KeAcquireSpinLock(&DGPendingListLock, &OldIrql1); - - CurrentADFEntry = DGPendingListHead.Flink; - while (CurrentADFEntry != &DGPendingListHead) { - RemoveEntryList(CurrentADFEntry); - CurrentADF = CONTAINING_RECORD(CurrentADFEntry, - ADDRESS_FILE, - ListEntry); - - KeAcquireSpinLock(&CurrentADF->Lock, &OldIrql2); - - if (AF_IS_BUSY(CurrentADF)) { - /* The send worker function is already running so we just - set the pending send flag on the address file object */ - - AF_SET_PENDING(CurrentADF, AFF_SEND); - KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2); - } else { - if (!IsListEmpty(&CurrentADF->TransmitQueue)) { - /* The transmit queue is not empty. Dequeue a send - request and process it */ - - CurrentSREntry = RemoveHeadList(&CurrentADF->TransmitQueue); - CurrentSR = CONTAINING_RECORD(CurrentADFEntry, - DATAGRAM_SEND_REQUEST, - ListEntry); - - KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2); - - DGSend(CurrentADF, CurrentSR); - } else - KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2); - } - CurrentADFEntry = CurrentADFEntry->Flink; - } - - KeReleaseSpinLock(&DGPendingListLock, OldIrql1); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); -} - - -VOID SendDatagramComplete( - PVOID Context, - PNDIS_PACKET Packet, - NDIS_STATUS NdisStatus) -/* - * FUNCTION: Datagram transmit completion handler - * ARGUMENTS: - * Context = Pointer to context infomation (DATAGRAM_SEND_REQUEST) - * Packet = Pointer to NDIS packet - * NdisStatus = Status of transmit operation - * NOTES: - * This routine is called by IP when a datagram send completes. - * We shedule the out-of-resource worker function if there - * are pending address files in the queue - */ -{ - KIRQL OldIrql; - ULONG BytesSent; - PVOID CompleteContext; - PNDIS_BUFFER NdisBuffer; - PDATAGRAM_SEND_REQUEST SendRequest; - DATAGRAM_COMPLETION_ROUTINE Complete; - BOOLEAN QueueWorkItem; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - SendRequest = (PDATAGRAM_SEND_REQUEST)Context; - Complete = SendRequest->Complete; - CompleteContext = SendRequest->Context; - BytesSent = SendRequest->BufferSize; - - /* Remove data buffer before releasing memory for packet buffers */ - NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL); - NdisUnchainBufferAtBack(Packet, &NdisBuffer); - FreeNdisPacket(Packet); - DereferenceObject(SendRequest->RemoteAddress); - PoolFreeBuffer(SendRequest); - - /* If there are pending send requests, shedule worker function */ - KeAcquireSpinLock(&DGPendingListLock, &OldIrql); - QueueWorkItem = (!IsListEmpty(&DGPendingListHead)); - KeReleaseSpinLock(&DGPendingListLock, OldIrql); - if (QueueWorkItem) - ExQueueWorkItem(&DGWorkItem, CriticalWorkQueue); - - /* Call completion routine for send request */ - (*Complete)(CompleteContext, NdisStatus, BytesSent); - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); -} - - -VOID DGSend( - PVOID Context, - PDATAGRAM_SEND_REQUEST SendRequest) -/* - * FUNCTION: Sends a datagram to IP layer - * ARGUMENTS: - * Context = Pointer to context information (ADDRESS_FILE) - * SendRequest = Pointer to send request - */ -{ - KIRQL OldIrql; - NTSTATUS Status; - USHORT LocalPort; - PIP_PACKET IPPacket; - PROUTE_CACHE_NODE RCN; - PLIST_ENTRY CurrentEntry; - PADDRESS_FILE AddrFile = Context; - PADDRESS_ENTRY ADE; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - /* Get the information we need from the address file - now so we minimize the time we hold the spin lock */ - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - LocalPort = AddrFile->Port; - ADE = AddrFile->ADE; - ReferenceObject(ADE); - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - /* Loop until there are no more send requests in the - transmit queue or until we run out of resources */ - for (;;) { - Status = SendRequest->Build(SendRequest, ADE->Address, LocalPort, &IPPacket); - if (!NT_SUCCESS(Status)) { - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - /* An error occurred, enqueue the send request again and return */ - InsertTailList(&AddrFile->TransmitQueue, &SendRequest->ListEntry); - DereferenceObject(ADE); - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - TI_DbgPrint(MIN_TRACE, ("Leaving (insufficient resources).\n")); - return; - } - - /* Get a route to the destination address */ - if (RouteGetRouteToDestination(SendRequest->RemoteAddress, ADE->NTE, &RCN) == IP_SUCCESS) { - /* Set completion routine and send the packet */ - PC(IPPacket->NdisPacket)->Complete = SendDatagramComplete; - PC(IPPacket->NdisPacket)->Context = SendRequest; - if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS) - SendDatagramComplete(SendRequest, - IPPacket->NdisPacket, - NDIS_STATUS_REQUEST_ABORTED); - /* We're done with the RCN */ - DereferenceObject(RCN); - } else { - /* No route to destination */ - /* FIXME: Which error code should we use here? */ - TI_DbgPrint(MIN_TRACE, ("No route to destination address (0x%X).\n", - SendRequest->RemoteAddress->Address.IPv4Address)); - SendDatagramComplete(SendRequest, - IPPacket->NdisPacket, - NDIS_STATUS_REQUEST_ABORTED); - } - - PoolFreeBuffer(IPPacket); - - /* Check transmit queue for more to send */ - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - - if (!IsListEmpty(&AddrFile->TransmitQueue)) { - /* Transmit queue is not empty, process one more request */ - CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue); - SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - } else { - /* Transmit queue is empty */ - AF_CLR_PENDING(AddrFile, AFF_SEND); - DereferenceObject(ADE); - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - TI_DbgPrint(MAX_TRACE, ("Leaving (empty queue).\n")); - return; - } - } -} - - -VOID DGCancelSendRequest( - PADDRESS_FILE AddrFile, - PVOID Context) -/* - * FUNCTION: Cancels a datagram send request - * ARGUMENTS: - * AddrFile = Pointer to address file of the request - * Context = Pointer to context information for completion handler - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PDATAGRAM_SEND_REQUEST Current = NULL; - BOOLEAN Found = FALSE; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - - /* Search the request list for the specified request and remove it */ - CurrentEntry = AddrFile->TransmitQueue.Flink; - while ((CurrentEntry != &AddrFile->TransmitQueue) && (!Found)) { - Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); - if (Context == Current->Context) { - /* We've found the request, now remove it from the queue */ - RemoveEntryList(CurrentEntry); - AddrFile->RefCount--; - Found = TRUE; - break; - } - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - if (Found) { - /* Complete the request and free its resources */ - (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0); - PoolFreeBuffer(Current->RemoteAddress); - PoolFreeBuffer(Current); - } else { - TI_DbgPrint(MID_TRACE, ("Cannot find send request.\n")); - } -} - - -VOID DGCancelReceiveRequest( - PADDRESS_FILE AddrFile, - PVOID Context) -/* - * FUNCTION: Cancels a datagram receive request - * ARGUMENTS: - * AddrFile = Pointer to address file of the request - * Context = Pointer to context information for completion handler - */ -{ - KIRQL OldIrql; - PLIST_ENTRY CurrentEntry; - PDATAGRAM_RECEIVE_REQUEST Current = NULL; - BOOLEAN Found = FALSE; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - - /* Search the request list for the specified request and remove it */ - CurrentEntry = AddrFile->ReceiveQueue.Flink; - while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) { - Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry); - if (Context == Current->Context) { - /* We've found the request, now remove it from the queue */ - RemoveEntryList(CurrentEntry); - AddrFile->RefCount--; - Found = TRUE; - break; - } - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - if (Found) { - /* Complete the request and free its resources */ - (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0); - /* Remote address can be NULL if the caller wants to receive - packets sent from any address */ - if (Current->RemoteAddress) - PoolFreeBuffer(Current->RemoteAddress); - PoolFreeBuffer(Current); - } else { - TI_DbgPrint(MID_TRACE, ("Cannot find receive request.\n")); - } -} - - -NTSTATUS DGSendDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG DataSize, - DATAGRAM_BUILD_ROUTINE Build) -/* - * FUNCTION: Sends a datagram to a remote address - * ARGUMENTS: - * Request = Pointer to TDI request - * ConnInfo = Pointer to connection information - * Buffer = Pointer to NDIS buffer with data - * DataSize = Size in bytes of data to be sent - * Build = Pointer to datagram build routine - * RETURNS: - * Status of operation - */ -{ - PADDRESS_FILE AddrFile; - KIRQL OldIrql; - NTSTATUS Status; - PDATAGRAM_SEND_REQUEST SendRequest = NULL; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - AddrFile = Request->Handle.AddressHandle; - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - - if (AF_IS_VALID(AddrFile)) { - SendRequest = PoolAllocateBuffer(sizeof(DATAGRAM_SEND_REQUEST)); - if (SendRequest) { - /* Initialize a send request */ - Status = AddrGetAddress(ConnInfo->RemoteAddress, - &SendRequest->RemoteAddress, &SendRequest->RemotePort, - &AddrFile->AddrCache); - if (NT_SUCCESS(Status)) { - SendRequest->Buffer = Buffer; - SendRequest->BufferSize = DataSize; - SendRequest->Complete = Request->RequestNotifyObject; - SendRequest->Context = Request->RequestContext; - SendRequest->Build = Build; - - if (AF_IS_BUSY(AddrFile)) { - /* Queue send request on the transmit queue */ - InsertTailList(&AddrFile->TransmitQueue, &SendRequest->ListEntry); - - /* Reference address file and set pending send request flag */ - AddrFile->RefCount++; - AF_SET_PENDING(AddrFile, AFF_SEND); - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - TI_DbgPrint(MAX_TRACE, ("Leaving (queued).\n")); - } else { - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - /* Send the datagram */ - DGSend(AddrFile, SendRequest); - - TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n")); - } - return STATUS_PENDING; - } - } else - Status = STATUS_INSUFFICIENT_RESOURCES; - } else - Status = STATUS_ADDRESS_CLOSED; - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - TI_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X)\n", Status)); - - return Status; -} - - -NTSTATUS DGReceiveDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG ReceiveLength, - ULONG ReceiveFlags, - PTDI_CONNECTION_INFORMATION ReturnInfo, - PULONG BytesReceived) -/* - * FUNCTION: Attempts to receive a datagram from a remote address - * ARGUMENTS: - * Request = Pointer to TDI request - * ConnInfo = Pointer to connection information - * Buffer = Pointer to NDIS buffer chain to store received data - * ReceiveLength = Maximum size to use of buffer (0 if all can be used) - * ReceiveFlags = Receive flags (None, Normal, Peek) - * ReturnInfo = Pointer to structure for return information - * BytesReceive = Pointer to structure for number of bytes received - * RETURNS: - * Status of operation - * NOTES: - * This is the high level interface for receiving datagrams - */ -{ - PADDRESS_FILE AddrFile; - KIRQL OldIrql; - NTSTATUS Status; - PDATAGRAM_RECEIVE_REQUEST ReceiveRequest; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - AddrFile = Request->Handle.AddressHandle; - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - - if (AF_IS_VALID(AddrFile)) { - ReceiveRequest = PoolAllocateBuffer(sizeof(DATAGRAM_RECEIVE_REQUEST)); - if (ReceiveRequest) { - /* Initialize a receive request */ - - /* Extract the remote address filter from the request (if any) */ - if (((ConnInfo->RemoteAddressLength != 0)) && (ConnInfo->RemoteAddress)) { - Status = AddrGetAddress(ConnInfo->RemoteAddress, - &ReceiveRequest->RemoteAddress, - &ReceiveRequest->RemotePort, - &AddrFile->AddrCache); - if (!NT_SUCCESS(Status)) { - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - PoolFreeBuffer(ReceiveRequest); - return Status; - } - } else { - ReceiveRequest->RemotePort = 0; - ReceiveRequest->RemoteAddress = NULL; - } - ReceiveRequest->ReturnInfo = ReturnInfo; - ReceiveRequest->Buffer = Buffer; - /* If ReceiveLength is 0, the whole buffer is available to us */ - ReceiveRequest->BufferSize = (ReceiveLength == 0) ? - MmGetMdlByteCount(Buffer) : ReceiveLength; - ReceiveRequest->Complete = Request->RequestNotifyObject; - ReceiveRequest->Context = Request->RequestContext; - - /* Queue receive request */ - InsertTailList(&AddrFile->ReceiveQueue, &ReceiveRequest->ListEntry); - - /* Reference address file and set pending receive request flag */ - AddrFile->RefCount++; - AF_SET_PENDING(AddrFile, AFF_RECEIVE); - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n")); - - return STATUS_PENDING; - } else - Status = STATUS_INSUFFICIENT_RESOURCES; - } else - Status = STATUS_INVALID_ADDRESS; - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - TI_DbgPrint(MAX_TRACE, ("Leaving with errors (0x%X).\n", Status)); - - return Status; -} - - -NTSTATUS DGStartup( - VOID) -/* - * FUNCTION: Initializes the datagram subsystem - * RETURNS: - * Status of operation - */ -{ - InitializeListHead(&DGPendingListHead); - - KeInitializeSpinLock(&DGPendingListLock); - - ExInitializeWorkItem(&DGWorkItem, DatagramWorker, NULL); - - return STATUS_SUCCESS; -} - - -NTSTATUS DGShutdown( - VOID) -/* - * FUNCTION: Shuts down the datagram subsystem - * RETURNS: - * Status of operation - */ -{ - return STATUS_SUCCESS; -} - - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: transport/datagram/datagram.c + * PURPOSE: Routines for sending and receiving datagrams + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include + + +/* Pending request queue */ +LIST_ENTRY DGPendingListHead; +KSPIN_LOCK DGPendingListLock; +/* Work queue item for pending requests */ +WORK_QUEUE_ITEM DGWorkItem; + + +VOID DatagramWorker( + PVOID Context) +/* + * FUNCTION: Handles pending requests + * ARGUMENTS: + * Context = Pointer to context information (unused) + * NOTES: + * This routine is called after the driver has run out of resources. + * It processes send requests or shedules them to be processed + */ +{ + PLIST_ENTRY CurrentADFEntry; + PLIST_ENTRY CurrentSREntry; + PADDRESS_FILE CurrentADF; + PDATAGRAM_SEND_REQUEST CurrentSR; + KIRQL OldIrql1; + KIRQL OldIrql2; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + KeAcquireSpinLock(&DGPendingListLock, &OldIrql1); + + CurrentADFEntry = DGPendingListHead.Flink; + while (CurrentADFEntry != &DGPendingListHead) { + RemoveEntryList(CurrentADFEntry); + CurrentADF = CONTAINING_RECORD(CurrentADFEntry, + ADDRESS_FILE, + ListEntry); + + KeAcquireSpinLock(&CurrentADF->Lock, &OldIrql2); + + if (AF_IS_BUSY(CurrentADF)) { + /* The send worker function is already running so we just + set the pending send flag on the address file object */ + + AF_SET_PENDING(CurrentADF, AFF_SEND); + KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2); + } else { + if (!IsListEmpty(&CurrentADF->TransmitQueue)) { + /* The transmit queue is not empty. Dequeue a send + request and process it */ + + CurrentSREntry = RemoveHeadList(&CurrentADF->TransmitQueue); + CurrentSR = CONTAINING_RECORD(CurrentADFEntry, + DATAGRAM_SEND_REQUEST, + ListEntry); + + KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2); + + DGSend(CurrentADF, CurrentSR); + } else + KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2); + } + CurrentADFEntry = CurrentADFEntry->Flink; + } + + KeReleaseSpinLock(&DGPendingListLock, OldIrql1); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); +} + + +VOID SendDatagramComplete( + PVOID Context, + PNDIS_PACKET Packet, + NDIS_STATUS NdisStatus) +/* + * FUNCTION: Datagram transmit completion handler + * ARGUMENTS: + * Context = Pointer to context infomation (DATAGRAM_SEND_REQUEST) + * Packet = Pointer to NDIS packet + * NdisStatus = Status of transmit operation + * NOTES: + * This routine is called by IP when a datagram send completes. + * We shedule the out-of-resource worker function if there + * are pending address files in the queue + */ +{ + KIRQL OldIrql; + ULONG BytesSent; + PVOID CompleteContext; + PNDIS_BUFFER NdisBuffer; + PDATAGRAM_SEND_REQUEST SendRequest; + DATAGRAM_COMPLETION_ROUTINE Complete; + BOOLEAN QueueWorkItem; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + SendRequest = (PDATAGRAM_SEND_REQUEST)Context; + Complete = SendRequest->Complete; + CompleteContext = SendRequest->Context; + BytesSent = SendRequest->BufferSize; + + /* Remove data buffer before releasing memory for packet buffers */ + NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL); + NdisUnchainBufferAtBack(Packet, &NdisBuffer); + FreeNdisPacket(Packet); + DereferenceObject(SendRequest->RemoteAddress); + PoolFreeBuffer(SendRequest); + + /* If there are pending send requests, shedule worker function */ + KeAcquireSpinLock(&DGPendingListLock, &OldIrql); + QueueWorkItem = (!IsListEmpty(&DGPendingListHead)); + KeReleaseSpinLock(&DGPendingListLock, OldIrql); + if (QueueWorkItem) + ExQueueWorkItem(&DGWorkItem, CriticalWorkQueue); + + /* Call completion routine for send request */ + (*Complete)(CompleteContext, NdisStatus, BytesSent); + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); +} + + +VOID DGSend( + PVOID Context, + PDATAGRAM_SEND_REQUEST SendRequest) +/* + * FUNCTION: Sends a datagram to IP layer + * ARGUMENTS: + * Context = Pointer to context information (ADDRESS_FILE) + * SendRequest = Pointer to send request + */ +{ + KIRQL OldIrql; + NTSTATUS Status; + USHORT LocalPort; + PIP_PACKET IPPacket; + PROUTE_CACHE_NODE RCN; + PLIST_ENTRY CurrentEntry; + PADDRESS_FILE AddrFile = Context; + PADDRESS_ENTRY ADE; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + /* Get the information we need from the address file + now so we minimize the time we hold the spin lock */ + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + LocalPort = AddrFile->Port; + ADE = AddrFile->ADE; + ReferenceObject(ADE); + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + /* Loop until there are no more send requests in the + transmit queue or until we run out of resources */ + for (;;) { + Status = SendRequest->Build(SendRequest, ADE->Address, LocalPort, &IPPacket); + if (!NT_SUCCESS(Status)) { + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + /* An error occurred, enqueue the send request again and return */ + InsertTailList(&AddrFile->TransmitQueue, &SendRequest->ListEntry); + DereferenceObject(ADE); + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + TI_DbgPrint(MIN_TRACE, ("Leaving (insufficient resources).\n")); + return; + } + + /* Get a route to the destination address */ + if (RouteGetRouteToDestination(SendRequest->RemoteAddress, ADE->NTE, &RCN) == IP_SUCCESS) { + /* Set completion routine and send the packet */ + PC(IPPacket->NdisPacket)->Complete = SendDatagramComplete; + PC(IPPacket->NdisPacket)->Context = SendRequest; + if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS) + SendDatagramComplete(SendRequest, + IPPacket->NdisPacket, + NDIS_STATUS_REQUEST_ABORTED); + /* We're done with the RCN */ + DereferenceObject(RCN); + } else { + /* No route to destination */ + /* FIXME: Which error code should we use here? */ + TI_DbgPrint(MIN_TRACE, ("No route to destination address (0x%X).\n", + SendRequest->RemoteAddress->Address.IPv4Address)); + SendDatagramComplete(SendRequest, + IPPacket->NdisPacket, + NDIS_STATUS_REQUEST_ABORTED); + } + + PoolFreeBuffer(IPPacket); + + /* Check transmit queue for more to send */ + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + + if (!IsListEmpty(&AddrFile->TransmitQueue)) { + /* Transmit queue is not empty, process one more request */ + CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue); + SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + } else { + /* Transmit queue is empty */ + AF_CLR_PENDING(AddrFile, AFF_SEND); + DereferenceObject(ADE); + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + TI_DbgPrint(MAX_TRACE, ("Leaving (empty queue).\n")); + return; + } + } +} + + +VOID DGCancelSendRequest( + PADDRESS_FILE AddrFile, + PVOID Context) +/* + * FUNCTION: Cancels a datagram send request + * ARGUMENTS: + * AddrFile = Pointer to address file of the request + * Context = Pointer to context information for completion handler + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PDATAGRAM_SEND_REQUEST Current = NULL; + BOOLEAN Found = FALSE; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + + /* Search the request list for the specified request and remove it */ + CurrentEntry = AddrFile->TransmitQueue.Flink; + while ((CurrentEntry != &AddrFile->TransmitQueue) && (!Found)) { + Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry); + if (Context == Current->Context) { + /* We've found the request, now remove it from the queue */ + RemoveEntryList(CurrentEntry); + AddrFile->RefCount--; + Found = TRUE; + break; + } + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + if (Found) { + /* Complete the request and free its resources */ + (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0); + PoolFreeBuffer(Current->RemoteAddress); + PoolFreeBuffer(Current); + } else { + TI_DbgPrint(MID_TRACE, ("Cannot find send request.\n")); + } +} + + +VOID DGCancelReceiveRequest( + PADDRESS_FILE AddrFile, + PVOID Context) +/* + * FUNCTION: Cancels a datagram receive request + * ARGUMENTS: + * AddrFile = Pointer to address file of the request + * Context = Pointer to context information for completion handler + */ +{ + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + PDATAGRAM_RECEIVE_REQUEST Current = NULL; + BOOLEAN Found = FALSE; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + + /* Search the request list for the specified request and remove it */ + CurrentEntry = AddrFile->ReceiveQueue.Flink; + while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) { + Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry); + if (Context == Current->Context) { + /* We've found the request, now remove it from the queue */ + RemoveEntryList(CurrentEntry); + AddrFile->RefCount--; + Found = TRUE; + break; + } + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + if (Found) { + /* Complete the request and free its resources */ + (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0); + /* Remote address can be NULL if the caller wants to receive + packets sent from any address */ + if (Current->RemoteAddress) + PoolFreeBuffer(Current->RemoteAddress); + PoolFreeBuffer(Current); + } else { + TI_DbgPrint(MID_TRACE, ("Cannot find receive request.\n")); + } +} + + +NTSTATUS DGSendDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG DataSize, + DATAGRAM_BUILD_ROUTINE Build) +/* + * FUNCTION: Sends a datagram to a remote address + * ARGUMENTS: + * Request = Pointer to TDI request + * ConnInfo = Pointer to connection information + * Buffer = Pointer to NDIS buffer with data + * DataSize = Size in bytes of data to be sent + * Build = Pointer to datagram build routine + * RETURNS: + * Status of operation + */ +{ + PADDRESS_FILE AddrFile; + KIRQL OldIrql; + NTSTATUS Status; + PDATAGRAM_SEND_REQUEST SendRequest = NULL; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + AddrFile = Request->Handle.AddressHandle; + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + + if (AF_IS_VALID(AddrFile)) { + SendRequest = PoolAllocateBuffer(sizeof(DATAGRAM_SEND_REQUEST)); + if (SendRequest) { + /* Initialize a send request */ + Status = AddrGetAddress(ConnInfo->RemoteAddress, + &SendRequest->RemoteAddress, &SendRequest->RemotePort, + &AddrFile->AddrCache); + if (NT_SUCCESS(Status)) { + SendRequest->Buffer = Buffer; + SendRequest->BufferSize = DataSize; + SendRequest->Complete = Request->RequestNotifyObject; + SendRequest->Context = Request->RequestContext; + SendRequest->Build = Build; + + if (AF_IS_BUSY(AddrFile)) { + /* Queue send request on the transmit queue */ + InsertTailList(&AddrFile->TransmitQueue, &SendRequest->ListEntry); + + /* Reference address file and set pending send request flag */ + AddrFile->RefCount++; + AF_SET_PENDING(AddrFile, AFF_SEND); + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + TI_DbgPrint(MAX_TRACE, ("Leaving (queued).\n")); + } else { + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + /* Send the datagram */ + DGSend(AddrFile, SendRequest); + + TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n")); + } + return STATUS_PENDING; + } + } else + Status = STATUS_INSUFFICIENT_RESOURCES; + } else + Status = STATUS_ADDRESS_CLOSED; + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + TI_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X)\n", Status)); + + return Status; +} + + +NTSTATUS DGReceiveDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG ReceiveLength, + ULONG ReceiveFlags, + PTDI_CONNECTION_INFORMATION ReturnInfo, + PULONG BytesReceived) +/* + * FUNCTION: Attempts to receive a datagram from a remote address + * ARGUMENTS: + * Request = Pointer to TDI request + * ConnInfo = Pointer to connection information + * Buffer = Pointer to NDIS buffer chain to store received data + * ReceiveLength = Maximum size to use of buffer (0 if all can be used) + * ReceiveFlags = Receive flags (None, Normal, Peek) + * ReturnInfo = Pointer to structure for return information + * BytesReceive = Pointer to structure for number of bytes received + * RETURNS: + * Status of operation + * NOTES: + * This is the high level interface for receiving datagrams + */ +{ + PADDRESS_FILE AddrFile; + KIRQL OldIrql; + NTSTATUS Status; + PDATAGRAM_RECEIVE_REQUEST ReceiveRequest; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + AddrFile = Request->Handle.AddressHandle; + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + + if (AF_IS_VALID(AddrFile)) { + ReceiveRequest = PoolAllocateBuffer(sizeof(DATAGRAM_RECEIVE_REQUEST)); + if (ReceiveRequest) { + /* Initialize a receive request */ + + /* Extract the remote address filter from the request (if any) */ + if (((ConnInfo->RemoteAddressLength != 0)) && (ConnInfo->RemoteAddress)) { + Status = AddrGetAddress(ConnInfo->RemoteAddress, + &ReceiveRequest->RemoteAddress, + &ReceiveRequest->RemotePort, + &AddrFile->AddrCache); + if (!NT_SUCCESS(Status)) { + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + PoolFreeBuffer(ReceiveRequest); + return Status; + } + } else { + ReceiveRequest->RemotePort = 0; + ReceiveRequest->RemoteAddress = NULL; + } + ReceiveRequest->ReturnInfo = ReturnInfo; + ReceiveRequest->Buffer = Buffer; + /* If ReceiveLength is 0, the whole buffer is available to us */ + ReceiveRequest->BufferSize = (ReceiveLength == 0) ? + MmGetMdlByteCount(Buffer) : ReceiveLength; + ReceiveRequest->Complete = Request->RequestNotifyObject; + ReceiveRequest->Context = Request->RequestContext; + + /* Queue receive request */ + InsertTailList(&AddrFile->ReceiveQueue, &ReceiveRequest->ListEntry); + + /* Reference address file and set pending receive request flag */ + AddrFile->RefCount++; + AF_SET_PENDING(AddrFile, AFF_RECEIVE); + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n")); + + return STATUS_PENDING; + } else + Status = STATUS_INSUFFICIENT_RESOURCES; + } else + Status = STATUS_INVALID_ADDRESS; + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + TI_DbgPrint(MAX_TRACE, ("Leaving with errors (0x%X).\n", Status)); + + return Status; +} + + +NTSTATUS DGStartup( + VOID) +/* + * FUNCTION: Initializes the datagram subsystem + * RETURNS: + * Status of operation + */ +{ + InitializeListHead(&DGPendingListHead); + + KeInitializeSpinLock(&DGPendingListLock); + + ExInitializeWorkItem(&DGWorkItem, DatagramWorker, NULL); + + return STATUS_SUCCESS; +} + + +NTSTATUS DGShutdown( + VOID) +/* + * FUNCTION: Shuts down the datagram subsystem + * RETURNS: + * Status of operation + */ +{ + return STATUS_SUCCESS; +} + + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/transport/rawip/Makefile b/reactos/drivers/net/tcpip/transport/rawip/Makefile index 9c985f57bc6..58189757d61 100644 --- a/reactos/drivers/net/tcpip/transport/rawip/Makefile +++ b/reactos/drivers/net/tcpip/transport/rawip/Makefile @@ -1,7 +1,7 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/reactos/drivers/net/tcpip/transport/rawip/SOURCES b/reactos/drivers/net/tcpip/transport/rawip/SOURCES index 1568428d329..7c92afe2144 100644 --- a/reactos/drivers/net/tcpip/transport/rawip/SOURCES +++ b/reactos/drivers/net/tcpip/transport/rawip/SOURCES @@ -1,13 +1,13 @@ -TARGETNAME=rawip -TARGETPATH=..\..\objects -TARGETTYPE=LIBRARY - -TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ - $(DDK_LIB_PATH)\ndis.lib - -INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net - -SOURCES= rawip.c - -MSC_WARNING_LEVEL=/W3 /WX - +TARGETNAME=rawip +TARGETPATH=..\..\objects +TARGETTYPE=LIBRARY + +TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ + $(DDK_LIB_PATH)\ndis.lib + +INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net + +SOURCES= rawip.c + +MSC_WARNING_LEVEL=/W3 /WX + diff --git a/reactos/drivers/net/tcpip/transport/rawip/rawip.c b/reactos/drivers/net/tcpip/transport/rawip/rawip.c index 1aa4a65ee60..bddebe2ad10 100644 --- a/reactos/drivers/net/tcpip/transport/rawip/rawip.c +++ b/reactos/drivers/net/tcpip/transport/rawip/rawip.c @@ -1,113 +1,113 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: transport/rawip/rawip.c - * PURPOSE: Raw IP routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include - - -BOOLEAN RawIPInitialized = FALSE; - - -NTSTATUS BuildRawIPPacket( - PVOID Context, - PIP_ADDRESS LocalAddress, - USHORT LocalPort, - PIP_PACKET *IPPacket) -/* - * FUNCTION: Builds an UDP packet - * ARGUMENTS: - * Context = Pointer to context information (DATAGRAM_SEND_REQUEST) - * LocalAddress = Pointer to our local address (NULL) - * LocalPort = The port we send this datagram from (0) - * IPPacket = Address of pointer to IP packet - * RETURNS: - * Status of operation - */ -{ - PIP_PACKET Packet; - NDIS_STATUS NdisStatus; - PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context; - - /* Prepare packet */ - Packet = PoolAllocateBuffer(sizeof(IP_PACKET)); - if (!Packet) - return STATUS_INSUFFICIENT_RESOURCES; - - RtlZeroMemory(Packet, sizeof(IP_PACKET)); - Packet->RefCount = 1; - Packet->TotalSize = SendRequest->BufferSize; - - /* Allocate NDIS packet */ - NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - PoolFreeBuffer(Packet); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Chain buffer to packet */ - NdisChainBufferAtFront(Packet->NdisPacket, SendRequest->Buffer); - - *IPPacket = Packet; - - return STATUS_SUCCESS; -} - - -NTSTATUS RawIPSendDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG DataSize) -/* - * FUNCTION: Sends a raw IP datagram to a remote address - * ARGUMENTS: - * Request = Pointer to TDI request - * ConnInfo = Pointer to connection information - * Buffer = Pointer to NDIS buffer with data - * DataSize = Size in bytes of data to be sent - * RETURNS: - * Status of operation - */ -{ - return DGSendDatagram(Request, ConnInfo, - Buffer, DataSize, BuildRawIPPacket); -} - - -NTSTATUS RawIPStartup( - VOID) -/* - * FUNCTION: Initializes the Raw IP subsystem - * RETURNS: - * Status of operation - */ -{ - RawIPInitialized = TRUE; - - return STATUS_SUCCESS; -} - - -NTSTATUS RawIPShutdown( - VOID) -/* - * FUNCTION: Shuts down the Raw IP subsystem - * RETURNS: - * Status of operation - */ -{ - if (!RawIPInitialized) - return STATUS_SUCCESS; - - return STATUS_SUCCESS; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: transport/rawip/rawip.c + * PURPOSE: Raw IP routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include + + +BOOLEAN RawIPInitialized = FALSE; + + +NTSTATUS BuildRawIPPacket( + PVOID Context, + PIP_ADDRESS LocalAddress, + USHORT LocalPort, + PIP_PACKET *IPPacket) +/* + * FUNCTION: Builds an UDP packet + * ARGUMENTS: + * Context = Pointer to context information (DATAGRAM_SEND_REQUEST) + * LocalAddress = Pointer to our local address (NULL) + * LocalPort = The port we send this datagram from (0) + * IPPacket = Address of pointer to IP packet + * RETURNS: + * Status of operation + */ +{ + PIP_PACKET Packet; + NDIS_STATUS NdisStatus; + PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context; + + /* Prepare packet */ + Packet = PoolAllocateBuffer(sizeof(IP_PACKET)); + if (!Packet) + return STATUS_INSUFFICIENT_RESOURCES; + + RtlZeroMemory(Packet, sizeof(IP_PACKET)); + Packet->RefCount = 1; + Packet->TotalSize = SendRequest->BufferSize; + + /* Allocate NDIS packet */ + NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + PoolFreeBuffer(Packet); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Chain buffer to packet */ + NdisChainBufferAtFront(Packet->NdisPacket, SendRequest->Buffer); + + *IPPacket = Packet; + + return STATUS_SUCCESS; +} + + +NTSTATUS RawIPSendDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG DataSize) +/* + * FUNCTION: Sends a raw IP datagram to a remote address + * ARGUMENTS: + * Request = Pointer to TDI request + * ConnInfo = Pointer to connection information + * Buffer = Pointer to NDIS buffer with data + * DataSize = Size in bytes of data to be sent + * RETURNS: + * Status of operation + */ +{ + return DGSendDatagram(Request, ConnInfo, + Buffer, DataSize, BuildRawIPPacket); +} + + +NTSTATUS RawIPStartup( + VOID) +/* + * FUNCTION: Initializes the Raw IP subsystem + * RETURNS: + * Status of operation + */ +{ + RawIPInitialized = TRUE; + + return STATUS_SUCCESS; +} + + +NTSTATUS RawIPShutdown( + VOID) +/* + * FUNCTION: Shuts down the Raw IP subsystem + * RETURNS: + * Status of operation + */ +{ + if (!RawIPInitialized) + return STATUS_SUCCESS; + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/transport/tcp/Makefile b/reactos/drivers/net/tcpip/transport/tcp/Makefile index 9c985f57bc6..58189757d61 100644 --- a/reactos/drivers/net/tcpip/transport/tcp/Makefile +++ b/reactos/drivers/net/tcpip/transport/tcp/Makefile @@ -1,7 +1,7 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/reactos/drivers/net/tcpip/transport/tcp/SOURCES b/reactos/drivers/net/tcpip/transport/tcp/SOURCES index 9c3e674e542..82d019f5f8d 100644 --- a/reactos/drivers/net/tcpip/transport/tcp/SOURCES +++ b/reactos/drivers/net/tcpip/transport/tcp/SOURCES @@ -1,13 +1,13 @@ -TARGETNAME=tcp -TARGETPATH=..\..\objects -TARGETTYPE=LIBRARY - -TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ - $(DDK_LIB_PATH)\ndis.lib - -INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net - -SOURCES= tcp.c - -MSC_WARNING_LEVEL=/W3 /WX - +TARGETNAME=tcp +TARGETPATH=..\..\objects +TARGETTYPE=LIBRARY + +TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ + $(DDK_LIB_PATH)\ndis.lib + +INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net + +SOURCES= tcp.c + +MSC_WARNING_LEVEL=/W3 /WX + diff --git a/reactos/drivers/net/tcpip/transport/tcp/tcp.c b/reactos/drivers/net/tcpip/transport/tcp/tcp.c index 11a6ca27e7a..eec133c2f81 100644 --- a/reactos/drivers/net/tcpip/transport/tcp/tcp.c +++ b/reactos/drivers/net/tcpip/transport/tcp/tcp.c @@ -1,44 +1,44 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: transport/tcp/tcp.c - * PURPOSE: Transmission Control Protocol - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include - - -BOOLEAN TCPInitialized = FALSE; - - -NTSTATUS TCPStartup( - VOID) -/* - * FUNCTION: Initializes the TCP subsystem - * RETURNS: - * Status of operation - */ -{ - TCPInitialized = TRUE; - - return STATUS_SUCCESS; -} - - -NTSTATUS TCPShutdown( - VOID) -/* - * FUNCTION: Shuts down the TCP subsystem - * RETURNS: - * Status of operation - */ -{ - if (!TCPInitialized) - return STATUS_SUCCESS; - - return STATUS_SUCCESS; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: transport/tcp/tcp.c + * PURPOSE: Transmission Control Protocol + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include + + +BOOLEAN TCPInitialized = FALSE; + + +NTSTATUS TCPStartup( + VOID) +/* + * FUNCTION: Initializes the TCP subsystem + * RETURNS: + * Status of operation + */ +{ + TCPInitialized = TRUE; + + return STATUS_SUCCESS; +} + + +NTSTATUS TCPShutdown( + VOID) +/* + * FUNCTION: Shuts down the TCP subsystem + * RETURNS: + * Status of operation + */ +{ + if (!TCPInitialized) + return STATUS_SUCCESS; + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/drivers/net/tcpip/transport/udp/Makefile b/reactos/drivers/net/tcpip/transport/udp/Makefile index 9c985f57bc6..58189757d61 100644 --- a/reactos/drivers/net/tcpip/transport/udp/Makefile +++ b/reactos/drivers/net/tcpip/transport/udp/Makefile @@ -1,7 +1,7 @@ -# -# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source -# file to this component. This file merely indirects to the real make file -# that is shared by all the driver components of the Windows NT DDK -# - -!INCLUDE $(NTMAKEENV)\makefile.def +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/reactos/drivers/net/tcpip/transport/udp/SOURCES b/reactos/drivers/net/tcpip/transport/udp/SOURCES index ed16c826be1..ebbec23168c 100644 --- a/reactos/drivers/net/tcpip/transport/udp/SOURCES +++ b/reactos/drivers/net/tcpip/transport/udp/SOURCES @@ -1,12 +1,12 @@ -TARGETNAME=udp -TARGETPATH=..\..\objects -TARGETTYPE=LIBRARY - -TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ - $(DDK_LIB_PATH)\ndis.lib - -INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net - -SOURCES= udp.c - -MSC_WARNING_LEVEL=/W3 /WX +TARGETNAME=udp +TARGETPATH=..\..\objects +TARGETTYPE=LIBRARY + +TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ + $(DDK_LIB_PATH)\ndis.lib + +INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net + +SOURCES= udp.c + +MSC_WARNING_LEVEL=/W3 /WX diff --git a/reactos/drivers/net/tcpip/transport/udp/udp.c b/reactos/drivers/net/tcpip/transport/udp/udp.c index da6574646ce..10e931b91bb 100644 --- a/reactos/drivers/net/tcpip/transport/udp/udp.c +++ b/reactos/drivers/net/tcpip/transport/udp/udp.c @@ -1,437 +1,437 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS TCP/IP protocol driver - * FILE: transport/udp/udp.c - * PURPOSE: User Datagram Protocol routines - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * REVISIONS: - * CSH 01/08-2000 Created - */ -#include -#include -#include -#include -#include -#include -#include -#include - - -BOOLEAN UDPInitialized = FALSE; - - -NTSTATUS AddUDPHeaderIPv4( - PDATAGRAM_SEND_REQUEST SendRequest, - PIP_ADDRESS LocalAddress, - USHORT LocalPort, - PIP_PACKET IPPacket) -/* - * FUNCTION: Adds an IPv4 and UDP header to an IP packet - * ARGUMENTS: - * SendRequest = Pointer to send request - * LocalAddress = Pointer to our local address - * LocalPort = The port we send this datagram from - * IPPacket = Pointer to IP packet - * RETURNS: - * Status of operation - */ -{ - PIPv4_HEADER IPHeader; - PUDP_HEADER UDPHeader; - PVOID Header; - ULONG BufferSize; - NDIS_STATUS NdisStatus; - PNDIS_BUFFER HeaderBuffer; - - BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(UDP_HEADER); - Header = PoolAllocateBuffer(BufferSize); - - if (!Header) { - TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet headers.\n")); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Allocate NDIS buffer for maximum Link level, IP and UDP header */ - NdisAllocateBuffer(&NdisStatus, - &HeaderBuffer, - GlobalBufferPool, - Header, - BufferSize); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS buffer for packet headers. NdisStatus = (0x%X)\n", NdisStatus)); - PoolFreeBuffer(Header); - return STATUS_INSUFFICIENT_RESOURCES; - } - - /* Chain header at front of NDIS packet */ - NdisChainBufferAtFront(IPPacket->NdisPacket, HeaderBuffer); - - IPPacket->Header = (PVOID)((ULONG_PTR)Header + MaxLLHeaderSize); - IPPacket->HeaderSize = 20; - - /* Build IPv4 header */ - IPHeader = (PIPv4_HEADER)IPPacket->Header; - /* Version = 4, Length = 5 DWORDs */ - IPHeader->VerIHL = 0x45; - /* Normal Type-of-Service */ - IPHeader->Tos = 0; - /* Length of header and data */ - IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize); - /* Identification */ - IPHeader->Id = 0; - /* One fragment at offset 0 */ - IPHeader->FlagsFragOfs = 0; - /* Time-to-Live is 128 */ - IPHeader->Ttl = 128; - /* User Datagram Protocol */ - IPHeader->Protocol = IPPROTO_UDP; - /* Checksum is 0 (for later calculation of this) */ - IPHeader->Checksum = 0; - /* Source address */ - IPHeader->SrcAddr = LocalAddress->Address.IPv4Address; - /* Destination address. FIXME: IPv4 only */ - IPHeader->DstAddr = SendRequest->RemoteAddress->Address.IPv4Address; - - /* Build UDP header */ - UDPHeader = (PUDP_HEADER)((ULONG_PTR)IPHeader + sizeof(IPv4_HEADER)); - /* Port values are already big-endian values */ - UDPHeader->SourcePort = LocalPort; - UDPHeader->DestPort = SendRequest->RemotePort; - /* FIXME: Calculate UDP checksum and put it in UDP header */ - UDPHeader->Checksum = 0; - /* Length of UDP header and data */ - UDPHeader->Length = WH2N((USHORT)IPPacket->TotalSize - IPPacket->HeaderSize); - - return STATUS_SUCCESS; -} - - -NTSTATUS BuildUDPPacket( - PVOID Context, - PIP_ADDRESS LocalAddress, - USHORT LocalPort, - PIP_PACKET *IPPacket) -/* - * FUNCTION: Builds an UDP packet - * ARGUMENTS: - * Context = Pointer to context information (DATAGRAM_SEND_REQUEST) - * LocalAddress = Pointer to our local address - * LocalPort = The port we send this datagram from - * IPPacket = Address of pointer to IP packet - * RETURNS: - * Status of operation - */ -{ - NTSTATUS Status; - PIP_PACKET Packet; - NDIS_STATUS NdisStatus; - PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - /* Prepare packet */ - Packet = PoolAllocateBuffer(sizeof(IP_PACKET)); - if (!Packet) { - TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet.\n")); - return STATUS_INSUFFICIENT_RESOURCES; - } - - RtlZeroMemory(Packet, sizeof(IP_PACKET)); - Packet->RefCount = 1; - Packet->TotalSize = sizeof(IPv4_HEADER) + - sizeof(UDP_HEADER) + - SendRequest->BufferSize; - - /* Allocate NDIS packet */ - NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool); - if (NdisStatus != NDIS_STATUS_SUCCESS) { - TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS packet. NdisStatus = (0x%X)\n", NdisStatus)); - PoolFreeBuffer(Packet); - return STATUS_INSUFFICIENT_RESOURCES; - } - - switch (SendRequest->RemoteAddress->Type) { - case IP_ADDRESS_V4: - Status = AddUDPHeaderIPv4(SendRequest, LocalAddress, LocalPort, Packet); - break; - case IP_ADDRESS_V6: - /* FIXME: Support IPv6 */ - TI_DbgPrint(MIN_TRACE, ("IPv6 UDP datagrams are not supported.\n")); - default: - Status = STATUS_UNSUCCESSFUL; - break; - } - if (!NT_SUCCESS(Status)) { - TI_DbgPrint(MIN_TRACE, ("Cannot add UDP header. Status = (0x%X)\n", Status)); - NdisFreePacket(Packet->NdisPacket); - PoolFreeBuffer(Packet); - return Status; - } - - /* Chain data after header */ - NdisChainBufferAtBack(Packet->NdisPacket, SendRequest->Buffer); - - *IPPacket = Packet; - - return STATUS_SUCCESS; -} - - -VOID DeliverUDPData( - PADDRESS_FILE AddrFile, - PIP_ADDRESS Address, - PIP_PACKET IPPacket, - UINT DataSize) -/* - * FUNCTION: Delivers UDP data to a user - * ARGUMENTS: - * AddrFile = Address file to deliver data to - * Address = Remote address the packet came from - * IPPacket = Pointer to IP packet to deliver - * DataSize = Number of bytes in data area - * NOTES: - * If there is a receive request, then we copy the data to the - * buffer supplied by the user and complete the receive request. - * If no suitable receive request exists, then we call the event - * handler if it exists, otherwise we drop the packet. - */ -{ - KIRQL OldIrql; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); - - if (!IsListEmpty(&AddrFile->ReceiveQueue)) { - PLIST_ENTRY CurrentEntry; - PDATAGRAM_RECEIVE_REQUEST Current; - BOOLEAN Found; - - /* Search receive request list to find a match */ - Found = FALSE; - CurrentEntry = AddrFile->ReceiveQueue.Flink; - while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) { - Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry); - if (!Current->RemoteAddress) - Found = TRUE; - else if (AddrIsEqual(Address, Current->RemoteAddress)) - Found = TRUE; - - if (Found) { - /* FIXME: Maybe we should check if the buffer of this - receive request is large enough and if not, search - for another. Also a 'best fit' strategy could be used. */ - - /* Remove the request from the queue */ - RemoveEntryList(&Current->ListEntry); - AddrFile->RefCount--; - break; - } - CurrentEntry = CurrentEntry->Flink; - } - - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - if (Found) { - /* Copy the data into buffer provided by the user */ - CopyBufferToBufferChain(Current->Buffer, - 0, - IPPacket->Data, - DataSize); - - /* Complete the receive request */ - (*Current->Complete)(Current->Context, STATUS_SUCCESS, DataSize); - - /* Finally free the receive request */ - if (Current->RemoteAddress) - PoolFreeBuffer(Current->RemoteAddress); - PoolFreeBuffer(Current); - } - } else { - KeReleaseSpinLock(&AddrFile->Lock, OldIrql); - - /* FIXME: Call event handler */ - TI_DbgPrint(MAX_TRACE, ("Calling receive event handler.\n")); - } - - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); -} - - -NTSTATUS UDPSendDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG DataSize) -/* - * FUNCTION: Sends an UDP datagram to a remote address - * ARGUMENTS: - * Request = Pointer to TDI request - * ConnInfo = Pointer to connection information - * Buffer = Pointer to NDIS buffer with data - * DataSize = Size in bytes of data to be sent - * RETURNS: - * Status of operation - */ -{ - return DGSendDatagram(Request, - ConnInfo, - Buffer, - DataSize, - BuildUDPPacket); -} - - -NTSTATUS UDPReceiveDatagram( - PTDI_REQUEST Request, - PTDI_CONNECTION_INFORMATION ConnInfo, - PNDIS_BUFFER Buffer, - ULONG ReceiveLength, - ULONG ReceiveFlags, - PTDI_CONNECTION_INFORMATION ReturnInfo, - PULONG BytesReceived) -/* - * FUNCTION: Attempts to receive an UDP datagram from a remote address - * ARGUMENTS: - * Request = Pointer to TDI request - * ConnInfo = Pointer to connection information - * Buffer = Pointer to NDIS buffer chain to store received data - * ReceiveLength = Maximum size to use of buffer, 0 if all can be used - * ReceiveFlags = Receive flags (None, Normal, Peek) - * ReturnInfo = Pointer to structure for return information - * BytesReceive = Pointer to structure for number of bytes received - * RETURNS: - * Status of operation - * NOTES: - * This is the high level interface for receiving UDP datagrams - */ -{ - return DGReceiveDatagram(Request, - ConnInfo, - Buffer, - ReceiveLength, - ReceiveFlags, - ReturnInfo, - BytesReceived); -} - - -VOID UDPReceive( - PNET_TABLE_ENTRY NTE, - PIP_PACKET IPPacket) -/* - * FUNCTION: Receives and queues a UDP datagram - * ARGUMENTS: - * NTE = Pointer to net table entry which the packet was received on - * IPPacket = Pointer to an IP packet that was received - * NOTES: - * This is the low level interface for receiving UDP datagrams. It strips - * the UDP header from a packet and delivers the data to anyone that wants it - */ -{ - AF_SEARCH SearchContext; - PIPv4_HEADER IPv4Header; - PADDRESS_FILE AddrFile; - PUDP_HEADER UDPHeader; - PIP_ADDRESS DstAddress; - UINT DataSize, i; - - TI_DbgPrint(MAX_TRACE, ("Called.\n")); - - switch (IPPacket->Type) { - /* IPv4 packet */ - case IP_ADDRESS_V4: - IPv4Header = IPPacket->Header; - DstAddress = &IPPacket->DstAddr; - break; - - /* IPv6 packet */ - case IP_ADDRESS_V6: - TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket->TotalSize)); - - /* FIXME: IPv6 is not supported */ - return; - } - - UDPHeader = (PUDP_HEADER)IPPacket->Data; - - /* FIXME: Calculate and validate UDP checksum */ - - /* Sanity checks */ - i = WH2N(UDPHeader->Length); - if ((i < sizeof(UDP_HEADER)) || (i > IPPacket->TotalSize - IPPacket->Position)) { - /* Incorrect or damaged packet received, discard it */ - TI_DbgPrint(MIN_TRACE, ("Incorrect or damaged UDP packet received.\n")); - return; - } - - DataSize = i - sizeof(UDP_HEADER); - - /* Go to UDP data area */ - (ULONG_PTR)IPPacket->Data += sizeof(UDP_HEADER); - - /* Locate a receive request on destination address file object - and deliver the packet if one is found. If there is no receive - request on the address file object, call the associated receive - handler. If no receive handler is registered, drop the packet */ - - AddrFile = AddrSearchFirst(DstAddress, - UDPHeader->DestPort, - IPPROTO_UDP, - &SearchContext); - if (AddrFile) { - do { - DeliverUDPData(AddrFile, - DstAddress, - IPPacket, - DataSize); - } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL); - } else { - /* There are no open address files that will take this datagram */ - /* FIXME: IPv4 only */ - TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n", - DN2H(DstAddress->Address.IPv4Address))); - - /* FIXME: Send ICMP reply */ - } - TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); -} - - -NTSTATUS UDPStartup( - VOID) -/* - * FUNCTION: Initializes the UDP subsystem - * RETURNS: - * Status of operation - */ -{ - RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS)); - - /* Register this protocol with IP layer */ - IPRegisterProtocol(IPPROTO_UDP, UDPReceive); - - UDPInitialized = TRUE; - - return STATUS_SUCCESS; -} - - -NTSTATUS UDPShutdown( - VOID) -/* - * FUNCTION: Shuts down the UDP subsystem - * RETURNS: - * Status of operation - */ -{ - if (!UDPInitialized) - return STATUS_SUCCESS; - - /* Deregister this protocol with IP layer */ - IPRegisterProtocol(IPPROTO_UDP, NULL); - - return STATUS_SUCCESS; -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TCP/IP protocol driver + * FILE: transport/udp/udp.c + * PURPOSE: User Datagram Protocol routines + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +BOOLEAN UDPInitialized = FALSE; + + +NTSTATUS AddUDPHeaderIPv4( + PDATAGRAM_SEND_REQUEST SendRequest, + PIP_ADDRESS LocalAddress, + USHORT LocalPort, + PIP_PACKET IPPacket) +/* + * FUNCTION: Adds an IPv4 and UDP header to an IP packet + * ARGUMENTS: + * SendRequest = Pointer to send request + * LocalAddress = Pointer to our local address + * LocalPort = The port we send this datagram from + * IPPacket = Pointer to IP packet + * RETURNS: + * Status of operation + */ +{ + PIPv4_HEADER IPHeader; + PUDP_HEADER UDPHeader; + PVOID Header; + ULONG BufferSize; + NDIS_STATUS NdisStatus; + PNDIS_BUFFER HeaderBuffer; + + BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(UDP_HEADER); + Header = PoolAllocateBuffer(BufferSize); + + if (!Header) { + TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet headers.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Allocate NDIS buffer for maximum Link level, IP and UDP header */ + NdisAllocateBuffer(&NdisStatus, + &HeaderBuffer, + GlobalBufferPool, + Header, + BufferSize); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS buffer for packet headers. NdisStatus = (0x%X)\n", NdisStatus)); + PoolFreeBuffer(Header); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Chain header at front of NDIS packet */ + NdisChainBufferAtFront(IPPacket->NdisPacket, HeaderBuffer); + + IPPacket->Header = (PVOID)((ULONG_PTR)Header + MaxLLHeaderSize); + IPPacket->HeaderSize = 20; + + /* Build IPv4 header */ + IPHeader = (PIPv4_HEADER)IPPacket->Header; + /* Version = 4, Length = 5 DWORDs */ + IPHeader->VerIHL = 0x45; + /* Normal Type-of-Service */ + IPHeader->Tos = 0; + /* Length of header and data */ + IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize); + /* Identification */ + IPHeader->Id = 0; + /* One fragment at offset 0 */ + IPHeader->FlagsFragOfs = 0; + /* Time-to-Live is 128 */ + IPHeader->Ttl = 128; + /* User Datagram Protocol */ + IPHeader->Protocol = IPPROTO_UDP; + /* Checksum is 0 (for later calculation of this) */ + IPHeader->Checksum = 0; + /* Source address */ + IPHeader->SrcAddr = LocalAddress->Address.IPv4Address; + /* Destination address. FIXME: IPv4 only */ + IPHeader->DstAddr = SendRequest->RemoteAddress->Address.IPv4Address; + + /* Build UDP header */ + UDPHeader = (PUDP_HEADER)((ULONG_PTR)IPHeader + sizeof(IPv4_HEADER)); + /* Port values are already big-endian values */ + UDPHeader->SourcePort = LocalPort; + UDPHeader->DestPort = SendRequest->RemotePort; + /* FIXME: Calculate UDP checksum and put it in UDP header */ + UDPHeader->Checksum = 0; + /* Length of UDP header and data */ + UDPHeader->Length = WH2N((USHORT)IPPacket->TotalSize - IPPacket->HeaderSize); + + return STATUS_SUCCESS; +} + + +NTSTATUS BuildUDPPacket( + PVOID Context, + PIP_ADDRESS LocalAddress, + USHORT LocalPort, + PIP_PACKET *IPPacket) +/* + * FUNCTION: Builds an UDP packet + * ARGUMENTS: + * Context = Pointer to context information (DATAGRAM_SEND_REQUEST) + * LocalAddress = Pointer to our local address + * LocalPort = The port we send this datagram from + * IPPacket = Address of pointer to IP packet + * RETURNS: + * Status of operation + */ +{ + NTSTATUS Status; + PIP_PACKET Packet; + NDIS_STATUS NdisStatus; + PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + /* Prepare packet */ + Packet = PoolAllocateBuffer(sizeof(IP_PACKET)); + if (!Packet) { + TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(Packet, sizeof(IP_PACKET)); + Packet->RefCount = 1; + Packet->TotalSize = sizeof(IPv4_HEADER) + + sizeof(UDP_HEADER) + + SendRequest->BufferSize; + + /* Allocate NDIS packet */ + NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool); + if (NdisStatus != NDIS_STATUS_SUCCESS) { + TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS packet. NdisStatus = (0x%X)\n", NdisStatus)); + PoolFreeBuffer(Packet); + return STATUS_INSUFFICIENT_RESOURCES; + } + + switch (SendRequest->RemoteAddress->Type) { + case IP_ADDRESS_V4: + Status = AddUDPHeaderIPv4(SendRequest, LocalAddress, LocalPort, Packet); + break; + case IP_ADDRESS_V6: + /* FIXME: Support IPv6 */ + TI_DbgPrint(MIN_TRACE, ("IPv6 UDP datagrams are not supported.\n")); + default: + Status = STATUS_UNSUCCESSFUL; + break; + } + if (!NT_SUCCESS(Status)) { + TI_DbgPrint(MIN_TRACE, ("Cannot add UDP header. Status = (0x%X)\n", Status)); + NdisFreePacket(Packet->NdisPacket); + PoolFreeBuffer(Packet); + return Status; + } + + /* Chain data after header */ + NdisChainBufferAtBack(Packet->NdisPacket, SendRequest->Buffer); + + *IPPacket = Packet; + + return STATUS_SUCCESS; +} + + +VOID DeliverUDPData( + PADDRESS_FILE AddrFile, + PIP_ADDRESS Address, + PIP_PACKET IPPacket, + UINT DataSize) +/* + * FUNCTION: Delivers UDP data to a user + * ARGUMENTS: + * AddrFile = Address file to deliver data to + * Address = Remote address the packet came from + * IPPacket = Pointer to IP packet to deliver + * DataSize = Number of bytes in data area + * NOTES: + * If there is a receive request, then we copy the data to the + * buffer supplied by the user and complete the receive request. + * If no suitable receive request exists, then we call the event + * handler if it exists, otherwise we drop the packet. + */ +{ + KIRQL OldIrql; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + KeAcquireSpinLock(&AddrFile->Lock, &OldIrql); + + if (!IsListEmpty(&AddrFile->ReceiveQueue)) { + PLIST_ENTRY CurrentEntry; + PDATAGRAM_RECEIVE_REQUEST Current; + BOOLEAN Found; + + /* Search receive request list to find a match */ + Found = FALSE; + CurrentEntry = AddrFile->ReceiveQueue.Flink; + while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) { + Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry); + if (!Current->RemoteAddress) + Found = TRUE; + else if (AddrIsEqual(Address, Current->RemoteAddress)) + Found = TRUE; + + if (Found) { + /* FIXME: Maybe we should check if the buffer of this + receive request is large enough and if not, search + for another. Also a 'best fit' strategy could be used. */ + + /* Remove the request from the queue */ + RemoveEntryList(&Current->ListEntry); + AddrFile->RefCount--; + break; + } + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + if (Found) { + /* Copy the data into buffer provided by the user */ + CopyBufferToBufferChain(Current->Buffer, + 0, + IPPacket->Data, + DataSize); + + /* Complete the receive request */ + (*Current->Complete)(Current->Context, STATUS_SUCCESS, DataSize); + + /* Finally free the receive request */ + if (Current->RemoteAddress) + PoolFreeBuffer(Current->RemoteAddress); + PoolFreeBuffer(Current); + } + } else { + KeReleaseSpinLock(&AddrFile->Lock, OldIrql); + + /* FIXME: Call event handler */ + TI_DbgPrint(MAX_TRACE, ("Calling receive event handler.\n")); + } + + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); +} + + +NTSTATUS UDPSendDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG DataSize) +/* + * FUNCTION: Sends an UDP datagram to a remote address + * ARGUMENTS: + * Request = Pointer to TDI request + * ConnInfo = Pointer to connection information + * Buffer = Pointer to NDIS buffer with data + * DataSize = Size in bytes of data to be sent + * RETURNS: + * Status of operation + */ +{ + return DGSendDatagram(Request, + ConnInfo, + Buffer, + DataSize, + BuildUDPPacket); +} + + +NTSTATUS UDPReceiveDatagram( + PTDI_REQUEST Request, + PTDI_CONNECTION_INFORMATION ConnInfo, + PNDIS_BUFFER Buffer, + ULONG ReceiveLength, + ULONG ReceiveFlags, + PTDI_CONNECTION_INFORMATION ReturnInfo, + PULONG BytesReceived) +/* + * FUNCTION: Attempts to receive an UDP datagram from a remote address + * ARGUMENTS: + * Request = Pointer to TDI request + * ConnInfo = Pointer to connection information + * Buffer = Pointer to NDIS buffer chain to store received data + * ReceiveLength = Maximum size to use of buffer, 0 if all can be used + * ReceiveFlags = Receive flags (None, Normal, Peek) + * ReturnInfo = Pointer to structure for return information + * BytesReceive = Pointer to structure for number of bytes received + * RETURNS: + * Status of operation + * NOTES: + * This is the high level interface for receiving UDP datagrams + */ +{ + return DGReceiveDatagram(Request, + ConnInfo, + Buffer, + ReceiveLength, + ReceiveFlags, + ReturnInfo, + BytesReceived); +} + + +VOID UDPReceive( + PNET_TABLE_ENTRY NTE, + PIP_PACKET IPPacket) +/* + * FUNCTION: Receives and queues a UDP datagram + * ARGUMENTS: + * NTE = Pointer to net table entry which the packet was received on + * IPPacket = Pointer to an IP packet that was received + * NOTES: + * This is the low level interface for receiving UDP datagrams. It strips + * the UDP header from a packet and delivers the data to anyone that wants it + */ +{ + AF_SEARCH SearchContext; + PIPv4_HEADER IPv4Header; + PADDRESS_FILE AddrFile; + PUDP_HEADER UDPHeader; + PIP_ADDRESS DstAddress; + UINT DataSize, i; + + TI_DbgPrint(MAX_TRACE, ("Called.\n")); + + switch (IPPacket->Type) { + /* IPv4 packet */ + case IP_ADDRESS_V4: + IPv4Header = IPPacket->Header; + DstAddress = &IPPacket->DstAddr; + break; + + /* IPv6 packet */ + case IP_ADDRESS_V6: + TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket->TotalSize)); + + /* FIXME: IPv6 is not supported */ + return; + } + + UDPHeader = (PUDP_HEADER)IPPacket->Data; + + /* FIXME: Calculate and validate UDP checksum */ + + /* Sanity checks */ + i = WH2N(UDPHeader->Length); + if ((i < sizeof(UDP_HEADER)) || (i > IPPacket->TotalSize - IPPacket->Position)) { + /* Incorrect or damaged packet received, discard it */ + TI_DbgPrint(MIN_TRACE, ("Incorrect or damaged UDP packet received.\n")); + return; + } + + DataSize = i - sizeof(UDP_HEADER); + + /* Go to UDP data area */ + (ULONG_PTR)IPPacket->Data += sizeof(UDP_HEADER); + + /* Locate a receive request on destination address file object + and deliver the packet if one is found. If there is no receive + request on the address file object, call the associated receive + handler. If no receive handler is registered, drop the packet */ + + AddrFile = AddrSearchFirst(DstAddress, + UDPHeader->DestPort, + IPPROTO_UDP, + &SearchContext); + if (AddrFile) { + do { + DeliverUDPData(AddrFile, + DstAddress, + IPPacket, + DataSize); + } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL); + } else { + /* There are no open address files that will take this datagram */ + /* FIXME: IPv4 only */ + TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n", + DN2H(DstAddress->Address.IPv4Address))); + + /* FIXME: Send ICMP reply */ + } + TI_DbgPrint(MAX_TRACE, ("Leaving.\n")); +} + + +NTSTATUS UDPStartup( + VOID) +/* + * FUNCTION: Initializes the UDP subsystem + * RETURNS: + * Status of operation + */ +{ + RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS)); + + /* Register this protocol with IP layer */ + IPRegisterProtocol(IPPROTO_UDP, UDPReceive); + + UDPInitialized = TRUE; + + return STATUS_SUCCESS; +} + + +NTSTATUS UDPShutdown( + VOID) +/* + * FUNCTION: Shuts down the UDP subsystem + * RETURNS: + * Status of operation + */ +{ + if (!UDPInitialized) + return STATUS_SUCCESS; + + /* Deregister this protocol with IP layer */ + IPRegisterProtocol(IPPROTO_UDP, NULL); + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/drivers/net/tditest/DIRS b/reactos/drivers/net/tditest/DIRS new file mode 100644 index 00000000000..0f4605a5db3 --- /dev/null +++ b/reactos/drivers/net/tditest/DIRS @@ -0,0 +1 @@ +DIRS= tditest diff --git a/reactos/drivers/net/tditest/include/debug.h b/reactos/drivers/net/tditest/include/debug.h new file mode 100644 index 00000000000..ee80cc3bc14 --- /dev/null +++ b/reactos/drivers/net/tditest/include/debug.h @@ -0,0 +1,90 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TDI test driver + * FILE: include/debug.h + * PURPOSE: Debugging support macros + * DEFINES: DBG - Enable debug output + * NASSERT - Disable assertions + */ +#ifndef __DEBUG_H +#define __DEBUG_H + +#define NORMAL_MASK 0x000000FF +#define SPECIAL_MASK 0xFFFFFF00 +#define MIN_TRACE 0x00000001 +#define MID_TRACE 0x00000002 +#define MAX_TRACE 0x00000003 + +#define DEBUG_ULTRA 0xFFFFFFFF + +#ifdef DBG + +extern DWORD DebugTraceLevel; + +#ifdef _MSC_VER + +#define TDI_DbgPrint(_t_, _x_) \ + if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \ + ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \ + DbgPrint("(%s:%d) ", __FILE__, __LINE__); \ + DbgPrint _x_ ; \ + } + +#else /* _MSC_VER */ + +#define TDI_DbgPrint(_t_, _x_) \ + if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \ + ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \ + DbgPrint("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \ + DbgPrint _x_ ; \ + } + +#endif /* _MSC_VER */ + +#ifdef ASSERT +#undef ASSERT +#endif + +#ifdef NASSERT +#define ASSERT(x) +#else /* NASSERT */ +#define ASSERT(x) if (!(x)) { TDI_DbgPrint(MIN_TRACE, ("Assertion "#x" failed at %s:%d\n", __FILE__, __LINE__)); KeBugCheck(0); } +#endif /* NASSERT */ + +#define ASSERT_IRQL(x) ASSERT(KeGetCurrentIrql() <= (x)) + +#else /* DBG */ + +#define TDI_DbgPrint(_t_, _x_) + +#define ASSERT_IRQL(x) +#define ASSERT(x) + +#endif /* DBG */ + + +#define assert(x) ASSERT(x) +#define assert_irql(x) ASSERT_IRQL(x) + + +#ifdef _MSC_VER + +#define UNIMPLEMENTED \ + TDI_DbgPrint(MIN_TRACE, ("The function at %s:%d is unimplemented, \ + but come back another day.\n", __FILE__, __LINE__)); + +#else /* _MSC_VER */ + +#define UNIMPLEMENTED \ + TDI_DbgPrint(MIN_TRACE, ("%s at %s:%d is unimplemented, \ + but come back another day.\n", __FUNCTION__, __FILE__, __LINE__)); + +#endif /* _MSC_VER */ + + +#define CHECKPOINT \ +do { TDI_DbgPrint(MIN_TRACE, ("%s:%d\n", __FILE__, __LINE__)); } while(0); + +#endif /* __DEBUG_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tditest/include/tditest.h b/reactos/drivers/net/tditest/include/tditest.h new file mode 100644 index 00000000000..fddda205782 --- /dev/null +++ b/reactos/drivers/net/tditest/include/tditest.h @@ -0,0 +1,131 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TDI test driver + * FILE: include/tditest.h + * PURPOSE: Testing TDI drivers + */ +#ifndef __TDITEST_H +#define __TDITEST_H + +#ifdef _MSC_VER +#include +#include +#include +#include +#include +#else +#include +#include +#include +#endif + +#include + + +/* Name of UDP device */ +//#define UDP_DEVICE_NAME L"\\Device\\Udp" +#define UDP_DEVICE_NAME L"\\Device\\NTUdp" + + +#ifdef i386 + +/* DWORD network to host byte order conversion for i386 */ +#define DN2H(dw) \ + ((((dw) & 0xFF000000L) >> 24) | \ + (((dw) & 0x00FF0000L) >> 8) | \ + (((dw) & 0x0000FF00L) << 8) | \ + (((dw) & 0x000000FFL) << 24)) + +/* DWORD host to network byte order conversion for i386 */ +#define DH2N(dw) \ + ((((dw) & 0xFF000000L) >> 24) | \ + (((dw) & 0x00FF0000L) >> 8) | \ + (((dw) & 0x0000FF00L) << 8) | \ + (((dw) & 0x000000FFL) << 24)) + +/* WORD network to host order conversion for i386 */ +#define WN2H(w) \ + ((((w) & 0xFF00) >> 8) | \ + (((w) & 0x00FF) << 8)) + +/* WORD host to network byte order conversion for i386 */ +#define WH2N(w) \ + ((((w) & 0xFF00) >> 8) | \ + (((w) & 0x00FF) << 8)) + +#else /* i386 */ + +/* DWORD network to host byte order conversion for other architectures */ +#define DN2H(dw) \ + (dw) + +/* DWORD host to network byte order conversion for other architectures */ +#define DH2N(dw) \ + (dw) + +/* WORD network to host order conversion for other architectures */ +#define WN2H(w) \ + (w) + +/* WORD host to network byte order conversion for other architectures */ +#define WH2N(w) \ + (w) + +#endif /* i386 */ + + +typedef struct IPSNMP_INFO { + ULONG Forwarding; + ULONG DefaultTTL; + ULONG InReceives; + ULONG InHdrErrors; + ULONG InAddrErrors; + ULONG ForwDatagrams; + ULONG InUnknownProtos; + ULONG InDiscards; + ULONG InDelivers; + ULONG OutRequests; + ULONG RoutingDiscards; + ULONG OutDiscards; + ULONG OutNoRoutes; + ULONG ReasmTimeout; + ULONG ReasmReqds; + ULONG ReasmOks; + ULONG ReasmFails; + ULONG FragOks; + ULONG FragFails; + ULONG FragCreates; + ULONG NumIf; + ULONG NumAddr; + ULONG NumRoutes; +} IPSNMP_INFO, *PIPSNMP_INFO; + +typedef struct IPADDR_ENTRY { + ULONG Addr; + ULONG Index; + ULONG Mask; + ULONG BcastAddr; + ULONG ReasmSize; + USHORT Context; + USHORT Pad; +} IPADDR_ENTRY, *PIPADDR_ENTRY; + + +#define TL_INSTANCE 0 + +#define IP_MIB_STATS_ID 0x1 +#define IP_MIB_ADDRTABLE_ENTRY_ID 0x102 + + +/* IOCTL codes */ +#define IOCTL_TCP_QUERY_INFORMATION_EX \ + CTL_CODE(FILE_DEVICE_NETWORK, 0, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_TCP_SET_INFORMATION_EX \ + CTL_CODE(FILE_DEVICE_NETWORK, 1, METHOD_BUFFERED, FILE_WRITE_ACCESS) + + +#define TEST_PORT 2000 + +#endif /*__TDITEST_H */ + +/* EOF */ diff --git a/reactos/drivers/net/tditest/makefile b/reactos/drivers/net/tditest/makefile new file mode 100644 index 00000000000..fa42377675d --- /dev/null +++ b/reactos/drivers/net/tditest/makefile @@ -0,0 +1,84 @@ +# TDITEST.SYS - TDI test driver + +TARGETNAME=tditest + +BASE_CFLAGS = -I./include -I../../../include + +RESOURCE_OBJECT = $(TARGETNAME).coff +TDITEST_OBJECTS = tditest/tditest.o + +all: objects $(TARGETNAME).sys + +objects: + mkdir objects + +$(TARGETNAME).coff: $(TARGETNAME).rc ../../../include/reactos/resource.h + +OBJECTS = $(TDITEST_OBJECTS) $(RESOURCE_OBJECT) ../../../ntoskrnl/ntoskrnl.a + + +ifeq ($(DOSCLI),yes) +CLEAN_FILES = *.o objects\*.o tditest\*.o $(TARGETNAME).coff $(TARGETNAME).o \ + junk.tmp base.tmp temp.exp $(TARGETNAME).sys $(TARGETNAME).sym +else +CLEAN_FILES = *.o objects/*.o tditest/*.o $(TARGETNAME).coff $(TARGETNAME).o \ + junk.tmp base.tmp temp.exp $(TARGETNAME).sys $(TARGETNAME).sym +endif + +$(TARGETNAME).sys: $(OBJECTS) + $(CC) \ + -mdll \ + -specs=../../svc_specs \ + -Wl,-e,_DriverEntry@8 \ + -Wl,--base-file,base.tmp \ + -Wl,--defsym,_end=end \ + -Wl,--defsym,_edata=__data_end__ \ + -Wl,--defsym,_etext=etext \ + $(OBJECTS) \ + -o junk.tmp + - $(RM) junk.tmp + $(DLLTOOL) \ + --dllname $(TARGETNAME).sys \ + --base-file base.tmp \ + --output-exp temp.exp + - $(RM) base.tmp + $(CC) \ + -mdll \ + -specs=../../svc_specs \ + -Wl,--image-base,0x10000 \ + -Wl,-e,_DriverEntry@8 \ + -Wl,temp.exp \ + $(OBJECTS) \ + -o $(TARGETNAME).sys + - $(RM) temp.exp + $(NM) --numeric-sort $(TARGETNAME).sys > $(TARGETNAME).sym + +clean: $(CLEAN_FILES:%=%_clean) + +$(CLEAN_FILES:%=%_clean): %_clean: + - $(RM) $* + +.PHONY: clean $(CLEAN_FILES:%=%_clean) + +floppy: $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys + +$(FLOPPY_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys +ifeq ($(DOSCLI),yes) + $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)\drivers\$(TARGETNAME).sys +else + $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys +endif + +dist: $(DIST_DIR)/drivers/$(TARGETNAME).sys + +$(DIST_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys +ifeq ($(DOSCLI),yes) + $(CP) $(TARGETNAME).sys ..\..\$(DIST_DIR)\drivers\$(TARGETNAME).sys +else + $(CP) $(TARGETNAME).sys ../../$(DIST_DIR)/drivers/$(TARGETNAME).sys +endif + +#WITH_DEBUGGING = yes +#WIN32_LEAN_AND_MEAN = yes +#WARNINGS_ARE_ERRORS = yes +include ../../../rules.mak diff --git a/reactos/drivers/net/tditest/readme.txt b/reactos/drivers/net/tditest/readme.txt new file mode 100644 index 00000000000..41e6e9c03f4 --- /dev/null +++ b/reactos/drivers/net/tditest/readme.txt @@ -0,0 +1,18 @@ +Build instructions for TDITEST driver +------------------------------------- + +Building with Visual C++ and Windows NT DDK: + +Variables: +%BASEDIR% = path to NT4 DDK (e.g. c:\ntddk) +%DDKBUILDENV% = DDK build environment (free or checked) + +DDK environment variables must be set! (run setenv.bat) + + - Create the directory objects/i386/%DDKBUILDENV% + - Run "build" to build the driver + + +Building with Mingw32 and ReactOS include files: + + - Run "make tditest" FROM THE ReactOS ROOT DIRECTORY to build the driver diff --git a/reactos/drivers/net/tditest/tditest.def b/reactos/drivers/net/tditest/tditest.def new file mode 100644 index 00000000000..2acbb5be174 --- /dev/null +++ b/reactos/drivers/net/tditest/tditest.def @@ -0,0 +1,7 @@ +; TDI test driver - ReactOS Operating System + +LIBRARY TDITEST.SYS + +EXPORTS + +; EOF diff --git a/reactos/drivers/net/tditest/tditest.rc b/reactos/drivers/net/tditest/tditest.rc new file mode 100644 index 00000000000..37601b26e1f --- /dev/null +++ b/reactos/drivers/net/tditest/tditest.rc @@ -0,0 +1,38 @@ +#include +#include + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +VS_VERSION_INFO VERSIONINFO + FILEVERSION RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD + PRODUCTVERSION RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", RES_STR_COMPANY_NAME + VALUE "FileDescription", "TDI test driver\0" + VALUE "FileVersion", "0.0.0\0" + VALUE "InternalName", "tditest\0" + VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "tditest.sys\0" + VALUE "ProductName", RES_STR_PRODUCT_NAME + VALUE "ProductVersion", RES_STR_PRODUCT_VERSION + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + diff --git a/reactos/drivers/net/tditest/tditest/Makefile b/reactos/drivers/net/tditest/tditest/Makefile new file mode 100644 index 00000000000..0ad3c884a90 --- /dev/null +++ b/reactos/drivers/net/tditest/tditest/Makefile @@ -0,0 +1,8 @@ +# MAKEFILE for ARTICLE +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/reactos/drivers/net/tditest/tditest/SOURCES b/reactos/drivers/net/tditest/tditest/SOURCES new file mode 100644 index 00000000000..c2c4df075ec --- /dev/null +++ b/reactos/drivers/net/tditest/tditest/SOURCES @@ -0,0 +1,14 @@ +TARGETNAME=tditest +TARGETPATH=..\objects +TARGETTYPE=DRIVER + +TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \ + $(DDK_LIB_PATH)\ndis.lib + +C_DEFINES=$(C_DEFINES) -DDBG + +INCLUDES=..\include;..\..\..\..\include\net;$(BASEDIR)\inc + +SOURCES= tditest.c + +MSC_WARNING_LEVEL=/W3 /WX diff --git a/reactos/drivers/net/tditest/tditest/tditest.c b/reactos/drivers/net/tditest/tditest/tditest.c new file mode 100644 index 00000000000..709e8f5a350 --- /dev/null +++ b/reactos/drivers/net/tditest/tditest/tditest.c @@ -0,0 +1,947 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS TDI test driver + * FILE: tditest.c + * PURPOSE: Testing TDI drivers + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * REVISIONS: + * CSH 01/08-2000 Created + */ +#include + + +#ifdef DBG + +/* See debug.h for debug/trace constants */ +DWORD DebugTraceLevel = MIN_TRACE; + +#endif /* DBG */ + + +HANDLE TdiTransport = 0; +PFILE_OBJECT TdiTransportObject = NULL; +ULONG LocalAddress; +BOOLEAN OpenError; +KEVENT StopEvent; +HANDLE SendThread; +KEVENT SendThreadEvent; +HANDLE ReceiveThread; +KEVENT ReceiveThreadEvent; +PVOID ReceiveThreadObject; +PVOID SendThreadObject; + + +NTSTATUS TdiCall( + PIRP Irp, + PDEVICE_OBJECT DeviceObject, + PIO_STATUS_BLOCK IoStatusBlock, + BOOLEAN CanCancel) +/* + * FUNCTION: Calls a transport driver device + * ARGUMENTS: + * Irp = Pointer to I/O Request Packet + * DeviceObject = Pointer to device object to call + * IoStatusBlock = Address of buffer with I/O status block + * CanCancel = TRUE if the IRP can be cancelled, FALSE if not + * RETURNS: + * Status of operation + * NOTES + * All requests are completed synchronously. A request may be cancelled + */ +{ + KEVENT Event; + PKEVENT Events[2]; + NTSTATUS Status; + Events[0] = &StopEvent; + Events[1] = &Event; + + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Irp->UserEvent = &Event; + Irp->UserIosb = IoStatusBlock; + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) { + if (CanCancel) { + Status = KeWaitForMultipleObjects(2, + (PVOID)&Events, + WaitAny, + Executive, + KernelMode, + FALSE, + NULL, + NULL); + + if (KeReadStateEvent(&StopEvent) != 0) { + if (IoCancelIrp(Irp)) { + TDI_DbgPrint(MAX_TRACE, ("Cancelled IRP.\n")); + } else { + TDI_DbgPrint(MIN_TRACE, ("Could not cancel IRP.\n")); + } + return STATUS_CANCELLED; + } + } else + Status = KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + } + + return (Status == STATUS_SUCCESS)? IoStatusBlock->Status : STATUS_SUCCESS; +} + + +NTSTATUS TdiOpenDevice( + PWSTR Protocol, + ULONG EaLength, + PFILE_FULL_EA_INFORMATION EaInfo, + PHANDLE Handle, + PFILE_OBJECT *Object) +/* + * FUNCTION: Opens a device + * ARGUMENTS: + * Protocol = Pointer to buffer with name of device + * EaLength = Length of EA information + * EaInfo = Pointer to buffer with EA information + * Handle = Address of buffer to place device handle + * Object = Address of buffer to place device object + * RETURNS: + * Status of operation + */ +{ + OBJECT_ATTRIBUTES Attr; + IO_STATUS_BLOCK Iosb; + UNICODE_STRING Name; + NTSTATUS Status; + + RtlInitUnicodeString(&Name, Protocol); + InitializeObjectAttributes(&Attr, /* Attribute buffer */ + &Name, /* Device name */ + OBJ_CASE_INSENSITIVE, /* Attributes */ + NULL, /* Root directory */ + NULL); /* Security descriptor */ + + Status = ZwCreateFile(Handle, /* Return file handle */ + GENERIC_READ | GENERIC_WRITE, /* Desired access */ + &Attr, /* Object attributes */ + &Iosb, /* IO status */ + 0, /* Initial allocation size */ + FILE_ATTRIBUTE_NORMAL, /* File attributes */ + FILE_SHARE_READ | FILE_SHARE_WRITE, /* Share access */ + FILE_OPEN_IF, /* Create disposition */ + 0, /* Create options */ + EaInfo, /* EA buffer */ + EaLength); /* EA length */ + if (NT_SUCCESS(Status)) { + Status = ObReferenceObjectByHandle(*Handle, /* Handle to open file */ + GENERIC_READ | GENERIC_WRITE, /* Access mode */ + NULL, /* Object type */ + KernelMode, /* Access mode */ + (PVOID*)Object, /* Pointer to object */ + NULL); /* Handle information */ + if (!NT_SUCCESS(Status)) { + TDI_DbgPrint(MIN_TRACE, ("ObReferenceObjectByHandle() failed with status (0x%X).\n", Status)); + ZwClose(*Handle); + } + } else { + TDI_DbgPrint(MIN_TRACE, ("ZwCreateFile() failed with status (0x%X)\n", Status)); + } + + return Status; +} + + +NTSTATUS TdiCloseDevice( + HANDLE Handle, + PFILE_OBJECT FileObject) +{ + if (FileObject) + ObDereferenceObject(FileObject); + + if (Handle) + ZwClose(Handle); + + return STATUS_SUCCESS; +} + + +NTSTATUS TdiOpenTransport( + PWSTR Protocol, + USHORT Port, + PHANDLE Transport, + PFILE_OBJECT *TransportObject) +/* + * FUNCTION: Opens a transport driver + * ARGUMENTS: + * Protocol = Pointer to buffer with name of device + * Port = Port number to use + * Transport = Address of buffer to place transport device handle + * TransportObject = Address of buffer to place transport object + * RETURNS: + * Status of operation + */ +{ + PFILE_FULL_EA_INFORMATION EaInfo; + PTA_ADDRESS_IP Address; + NTSTATUS Status; + ULONG EaLength; + + EaLength = sizeof(FILE_FULL_EA_INFORMATION) + + sizeof(TdiTransportAddress) + + sizeof(TA_ADDRESS_IP) + 1; + EaInfo = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(NonPagedPool, EaLength); + if (!EaInfo) { + TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(EaInfo, EaLength); + EaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH; + RtlCopyMemory (EaInfo->EaName, + TdiTransportAddress, + sizeof(TdiTransportAddress)); + EaInfo->EaValueLength = sizeof(TA_ADDRESS_IP); + Address = (PTA_ADDRESS_IP)(EaInfo->EaName + sizeof(TdiTransportAddress)); + Address->TAAddressCount = 1; + Address->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); + Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; + Address->Address[0].Address[0].sin_port = WH2N(Port); + Address->Address[0].Address[0].in_addr = 0; + Status = TdiOpenDevice(Protocol, + EaLength, + EaInfo, + Transport, + TransportObject); + ExFreePool(EaInfo); + + return Status; +} + + +NTSTATUS TdiQueryDeviceControl( + PFILE_OBJECT FileObject, + ULONG IoControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength, + PULONG Return) +/* + * FUNCTION: Queries a device for information + * ARGUMENTS: + * FileObject = Pointer to device object + * IoControlCode = I/O control code + * InputBuffer = Pointer to buffer with input data + * InputBufferLength = Length of InputBuffer + * OutputBuffer = Address of buffer to place output data + * OutputBufferLength = Length of OutputBuffer + * RETURNS: + * Status of operation + */ +{ + PDEVICE_OBJECT DeviceObject; + PIO_STACK_LOCATION IoStack; + IO_STATUS_BLOCK Iosb; + NTSTATUS Status; + PIRP Irp; + + DeviceObject = IoGetRelatedDeviceObject(FileObject); + Irp = IoBuildDeviceIoControlRequest(IoControlCode, + DeviceObject, + InputBuffer, + InputBufferLength, + OutputBuffer, + OutputBufferLength, + FALSE, + NULL, + NULL); + if (!Irp) { + TDI_DbgPrint(MIN_TRACE, ("IoBuildDeviceIoControlRequest() failed.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + IoStack = IoGetNextIrpStackLocation(Irp); + IoStack->DeviceObject = DeviceObject; + IoStack->FileObject = FileObject; + Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE); + if (Return) + *Return = Iosb.Information; + + return Status; +} + + +NTSTATUS TdiQueryInformationEx( + PFILE_OBJECT FileObject, + ULONG Entity, + ULONG Instance, + ULONG Class, + ULONG Type, + ULONG Id, + PVOID OutputBuffer, + PULONG OutputLength) +/* + * FUNCTION: Extended query for information + * ARGUMENTS: + * FileObject = Pointer to transport object + * Entity = Entity + * Instance = Instance + * Class = Entity class + * Type = Entity type + * Id = Entity id + * OutputBuffer = Address of buffer to place data + * OutputLength = Address of buffer with length of OutputBuffer (updated) + * RETURNS: + * Status of operation + */ +{ + TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo; + + RtlZeroMemory(&QueryInfo, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)); + QueryInfo.ID.toi_entity.tei_entity = Entity; + QueryInfo.ID.toi_entity.tei_instance = Instance; + QueryInfo.ID.toi_class = Class; + QueryInfo.ID.toi_type = Type; + QueryInfo.ID.toi_id = Id; + + return TdiQueryDeviceControl(FileObject, /* Transport/connection object */ + IOCTL_TCP_QUERY_INFORMATION_EX, /* Control code */ + &QueryInfo, /* Input buffer */ + sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), /* Input buffer length */ + OutputBuffer, /* Output buffer */ + *OutputLength, /* Output buffer length */ + OutputLength); /* Return information */ +} + + +NTSTATUS TdiQueryAddress( + PFILE_OBJECT FileObject, + PULONG Address) +/* + * FUNCTION: Queries for a local IP address + * ARGUMENTS: + * FileObject = Pointer to file object + * Address = Address of buffer to place local address + * RETURNS: + * Status of operation + */ +{ + UINT i; + TDIEntityID *Entities; + ULONG EntityCount; + ULONG EntityType; + IPSNMP_INFO SnmpInfo; + PIPADDR_ENTRY IpAddress; + ULONG BufferSize; + NTSTATUS Status = STATUS_SUCCESS; + + TDI_DbgPrint(MAX_TRACE, ("Called\n")); + + BufferSize = sizeof(TDIEntityID) * 20; + Entities = (TDIEntityID*)ExAllocatePool(NonPagedPool, BufferSize); + if (!Entities) { + TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Query device for supported entities */ + + Status = TdiQueryInformationEx(FileObject, /* File object */ + GENERIC_ENTITY, /* Entity */ + TL_INSTANCE, /* Instance */ + INFO_CLASS_GENERIC, /* Entity class */ + INFO_TYPE_PROVIDER, /* Entity type */ + ENTITY_LIST_ID, /* Entity id */ + Entities, /* Output buffer */ + &BufferSize); /* Output buffer size */ + if (!NT_SUCCESS(Status)) { + TDI_DbgPrint(MIN_TRACE, ("Unable to get list of supported entities (Status = 0x%X).\n", Status)); + ExFreePool(Entities); + return Status; + } + + /* Locate an IP entity */ + EntityCount = BufferSize / sizeof(TDIEntityID); + + TDI_DbgPrint(MAX_TRACE, ("EntityCount = %d\n", EntityCount)); + + for (i = 0; i < EntityCount; i++) { + if (Entities[i].tei_entity == CL_NL_ENTITY) { + /* Query device for entity type */ + + BufferSize = sizeof(EntityType); + Status = TdiQueryInformationEx(FileObject, /* File object */ + CL_NL_ENTITY, /* Entity */ + Entities[i].tei_instance, /* Instance */ + INFO_CLASS_GENERIC, /* Entity class */ + INFO_TYPE_PROVIDER, /* Entity type */ + ENTITY_TYPE_ID, /* Entity id */ + &EntityType, /* Output buffer */ + &BufferSize); /* Output buffer size */ + if (!NT_SUCCESS(Status) || (EntityType != CL_NL_IP)) { + TDI_DbgPrint(MIN_TRACE, ("Unable to get entity of type IP (Status = 0x%X).\n", Status)); + break; + } + + /* Query device for SNMP information */ + + BufferSize = sizeof(SnmpInfo); + Status = TdiQueryInformationEx(FileObject, /* File object */ + CL_NL_ENTITY, /* Entity */ + Entities[i].tei_instance, /* Instance */ + INFO_CLASS_PROTOCOL, /* Entity class */ + INFO_TYPE_PROVIDER, /* Entity type */ + IP_MIB_STATS_ID, /* Entity id */ + &SnmpInfo, /* Output buffer */ + &BufferSize); /* Output buffer size */ + if (!NT_SUCCESS(Status) || (SnmpInfo.NumAddr == 0)) { + TDI_DbgPrint(MIN_TRACE, ("Unable to get SNMP information or no IP addresses available (Status = 0x%X).\n", Status)); + break; + } + + /* Query device for all IP addresses */ + + if (SnmpInfo.NumAddr != 0) { + BufferSize = SnmpInfo.NumAddr * sizeof(IPADDR_ENTRY); + IpAddress = (PIPADDR_ENTRY)ExAllocatePool(NonPagedPool, BufferSize); + if (!IpAddress) { + TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n")); + break; + } + + Status = TdiQueryInformationEx(FileObject, /* File object */ + CL_NL_ENTITY, /* Entity */ + Entities[i].tei_instance, /* Instance */ + INFO_CLASS_PROTOCOL, /* Entity class */ + INFO_TYPE_PROVIDER, /* Entity type */ + IP_MIB_ADDRTABLE_ENTRY_ID, /* Entity id */ + IpAddress, /* Output buffer */ + &BufferSize); /* Output buffer size */ + if (!NT_SUCCESS(Status)) { + TDI_DbgPrint(MIN_TRACE, ("Unable to get IP address (Status = 0x%X).\n", Status)); + ExFreePool(IpAddress); + break; + } + + /* Select the first address returned */ + *Address = DN2H(IpAddress->Addr); + ExFreePool(IpAddress); + } else { + Status = STATUS_UNSUCCESSFUL; + break; + } + } + } + + ExFreePool(Entities); + + TDI_DbgPrint(MAX_TRACE, ("Leaving\n")); + + return Status; +} + + +NTSTATUS TdiSendDatagram( + PFILE_OBJECT TransportObject, + USHORT Port, + ULONG Address, + PVOID Buffer, + ULONG BufferSize) +/* + * FUNCTION: Sends a datagram + * ARGUMENTS: + * TransportObject = Pointer to transport object + * Port = Remote port + * Address = Remote address + * Buffer = Pointer to buffer with data to send + * BufferSize = Length of Buffer + * RETURNS: + * Status of operation + */ +{ + PIRP Irp; + PMDL Mdl; + PDEVICE_OBJECT DeviceObject; + PTDI_CONNECTION_INFORMATION ConnectInfo; + PTA_ADDRESS_IP TA; + PTDI_ADDRESS_IP IpAddress; + IO_STATUS_BLOCK Iosb; + NTSTATUS Status; + + DeviceObject = IoGetRelatedDeviceObject(TransportObject); + ConnectInfo = (PTDI_CONNECTION_INFORMATION) + ExAllocatePool(NonPagedPool, + sizeof(TDI_CONNECTION_INFORMATION) + + sizeof(TA_ADDRESS_IP)); + + if (!ConnectInfo) + return STATUS_INSUFFICIENT_RESOURCES; + + RtlZeroMemory(ConnectInfo, + sizeof(TDI_CONNECTION_INFORMATION) + + sizeof(TA_ADDRESS_IP)); + + ConnectInfo->RemoteAddressLength = sizeof(TA_ADDRESS_IP); + ConnectInfo->RemoteAddress = (PUCHAR) + ((ULONG)ConnectInfo + sizeof(TDI_CONNECTION_INFORMATION)); + + TA = (PTA_ADDRESS_IP)(ConnectInfo->RemoteAddress); + TA->TAAddressCount = 1; + TA->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); + TA->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; + IpAddress = (PTDI_ADDRESS_IP)(TA->Address[0].Address); + IpAddress->sin_port = WH2N(Port); + IpAddress->in_addr = DH2N(Address); + Irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, /* Sub function */ + DeviceObject, /* Device object */ + TransportObject, /* File object */ + NULL, /* Event */ + NULL); /* Return buffer */ + if (!Irp) { + TDI_DbgPrint(MIN_TRACE, ("TdiBuildInternalDeviceControlIrp() failed.\n")); + ExFreePool(ConnectInfo); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Mdl = IoAllocateMdl(Buffer, /* Virtual address of buffer */ + BufferSize, /* Length of buffer */ + FALSE, /* Not secondary */ + FALSE, /* Don't charge quota */ + NULL); /* Don't use IRP */ + if (!Mdl) { + TDI_DbgPrint(MIN_TRACE, ("IoAllocateMdl() failed.\n")); + IoFreeIrp(Irp); + ExFreePool(ConnectInfo); + return STATUS_INSUFFICIENT_RESOURCES; + } + +#ifdef _MSC_VER + try { +#endif + MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess); +#ifdef _MSC_VER + } except(EXCEPTION_EXECUTE_HANDLER) { + TDI_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n")); + IoFreeMdl(Mdl); + IoFreeIrp(Irp); + ExFreePool(ConnectInfo); + return STATUS_UNSUCCESSFUL; + } +#endif + + TdiBuildSendDatagram(Irp, /* I/O Request Packet */ + DeviceObject, /* Device object */ + TransportObject, /* File object */ + NULL, /* Completion routine */ + NULL, /* Completion context */ + Mdl, /* Descriptor for data buffer */ + BufferSize, /* Size of data to send */ + ConnectInfo); /* Connection information */ + + Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE); + + ExFreePool(ConnectInfo); + + return Status; +} + + +NTSTATUS TdiReceiveDatagram( + PFILE_OBJECT TransportObject, + USHORT Port, + PULONG Address, + PUCHAR Buffer, + PULONG BufferSize) +/* + * FUNCTION: Receives a datagram + * ARGUMENTS: + * TransportObject = Pointer to transport object + * Port = Port to receive on + * Address = Address of buffer to place remote address + * Buffer = Address of buffer to place received data + * BufferSize = Address of buffer with length of Buffer (updated) + * RETURNS: + * Status of operation + */ +{ + PTDI_CONNECTION_INFORMATION ReceiveInfo; + PTDI_CONNECTION_INFORMATION ReturnInfo; + PTA_ADDRESS_IP ReturnAddress; + PDEVICE_OBJECT DeviceObject; + PTDI_ADDRESS_IP IpAddress; + IO_STATUS_BLOCK Iosb; + PVOID MdlBuffer; + NTSTATUS Status; + PIRP Irp; + PMDL Mdl; + + DeviceObject = IoGetRelatedDeviceObject(TransportObject); + if (!DeviceObject) + return STATUS_INVALID_PARAMETER; + + ReceiveInfo = (PTDI_CONNECTION_INFORMATION) + ExAllocatePool(NonPagedPool, + sizeof(TDI_CONNECTION_INFORMATION) + + sizeof(TDI_CONNECTION_INFORMATION) + + sizeof(TA_ADDRESS_IP)); + if (!ReceiveInfo) + return STATUS_INSUFFICIENT_RESOURCES; + + MdlBuffer = ExAllocatePool(PagedPool, *BufferSize); + if (!MdlBuffer) + return STATUS_INSUFFICIENT_RESOURCES; + + + RtlZeroMemory(ReceiveInfo, + sizeof(TDI_CONNECTION_INFORMATION) + + sizeof(TDI_CONNECTION_INFORMATION) + + sizeof(TA_ADDRESS_IP)); + RtlCopyMemory(MdlBuffer, Buffer, *BufferSize); + + /* Receive from any address */ + ReceiveInfo->RemoteAddressLength = 0; + ReceiveInfo->RemoteAddress = NULL; + + ReturnInfo = (PTDI_CONNECTION_INFORMATION) + ((ULONG)ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION)); + + ReturnInfo->RemoteAddressLength = sizeof(TA_ADDRESS_IP); + ReturnInfo->RemoteAddress = (PUCHAR) + ((ULONG)ReturnInfo + sizeof(TDI_CONNECTION_INFORMATION)); + + ReturnAddress = (PTA_ADDRESS_IP)(ReturnInfo->RemoteAddress); + ReturnAddress->TAAddressCount = 1; + ReturnAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP); + ReturnAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; + + IpAddress = (PTDI_ADDRESS_IP)(ReturnAddress->Address[0].Address); + IpAddress->sin_port = WH2N(Port); + IpAddress->in_addr = DH2N(LocalAddress); + + Irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM, /* Sub function */ + DeviceObject, /* Device object */ + TransportObject, /* File object */ + NULL, /* Event */ + NULL); /* Return buffer */ + if (!Irp) { + ExFreePool(MdlBuffer); + ExFreePool(ReceiveInfo); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Mdl = IoAllocateMdl(MdlBuffer, /* Virtual address */ + *BufferSize, /* Length of buffer */ + FALSE, /* Not secondary */ + FALSE, /* Don't charge quota */ + NULL); /* Don't use IRP */ + if (!Mdl) { + IoFreeIrp(Irp); + ExFreePool(MdlBuffer); + ExFreePool(ReceiveInfo); + return STATUS_INSUFFICIENT_RESOURCES; + } + +#ifdef _MSC_VER + try { +#endif + MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess); +#ifdef _MSC_VER + } except (EXCEPTION_EXECUTE_HANDLER) { + TDI_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n")); + IoFreeMdl(Mdl); + IoFreeIrp(Irp); + ExFreePool(MdlBuffer); + ExFreePool(ReceiveInfo); + return STATUS_INSUFFICIENT_RESOURCES; + } +#endif + + TdiBuildReceiveDatagram(Irp, /* I/O Request Packet */ + DeviceObject, /* Device object */ + TransportObject, /* File object */ + NULL, /* Completion routine */ + NULL, /* Completion context */ + Mdl, /* Data buffer */ + *BufferSize, /* Size of data buffer */ + ReceiveInfo, /* Connection information */ + ReturnInfo, /* Connection information */ + TDI_RECEIVE_NORMAL); /* Flags */ + Status = TdiCall(Irp, DeviceObject, &Iosb, TRUE); + if (NT_SUCCESS(Status)) { + RtlCopyMemory(Buffer, MdlBuffer, Iosb.Information); + *BufferSize = Iosb.Information; + *Address = DN2H(IpAddress->in_addr); + } + + ExFreePool(MdlBuffer); + ExFreePool(ReceiveInfo); + + return Status; +} + + +VOID TdiSendThread( + PVOID Context) +/* + * FUNCTION: Send thread + * ARGUMENTS: + * Context = Pointer to context information + * NOTES: + * Transmits an UDP packet every two seconds to ourselves on the chosen port + */ +{ + KEVENT Event; + PKEVENT Events[2]; + LARGE_INTEGER Timeout; + NTSTATUS Status = STATUS_SUCCESS; + UCHAR Data[40] = "Testing one, two, three, ..."; + + if (!OpenError) { + Timeout.QuadPart = 10000000L; /* Second factor */ + Timeout.QuadPart *= 2; /* Number of seconds */ + Timeout.QuadPart = -(Timeout.QuadPart); /* Relative time */ + KeInitializeEvent(&Event, SynchronizationEvent, FALSE); + + Events[0] = &StopEvent; + Events[1] = &Event; + + while (NT_SUCCESS(Status)) { + /* Wait until timeout or stop flag is set */ + KeWaitForMultipleObjects( + 2, + (PVOID)&Events, + WaitAny, + Executive, + KernelMode, + FALSE, + &Timeout, + NULL); + + if (KeReadStateEvent(&StopEvent) != 0) { + TDI_DbgPrint(MAX_TRACE, ("Received terminate signal...\n")); + break; + } + + DbgPrint("Sending data - '%s'\n", Data); + + Status = TdiSendDatagram(TdiTransportObject, + TEST_PORT, + LocalAddress, + Data, + sizeof(Data)); + if (!NT_SUCCESS(Status)) + DbgPrint("Failed sending data (Status = 0x%X)\n", Status); + } + } + + TDI_DbgPrint(MAX_TRACE, ("Terminating send thread...\n")); + + KeSetEvent(&SendThreadEvent, 0, FALSE); + + PsTerminateSystemThread(STATUS_SUCCESS); +} + + +VOID TdiReceiveThread( + PVOID Context) +/* + * FUNCTION: Receive thread + * ARGUMENTS: + * Context = Pointer to context information + * NOTES: + * Waits until an UDP packet is received on the chosen endpoint and displays the data + */ +{ + ULONG Address; + UCHAR Data[40]; + ULONG Size; + NTSTATUS Status = STATUS_SUCCESS; + + if (!OpenError) { + while (NT_SUCCESS(Status)) { + Size = sizeof(Data); + RtlZeroMemory(Data, Size); + + Status = TdiReceiveDatagram(TdiTransportObject, + TEST_PORT, + &Address, + Data, + &Size); + if (NT_SUCCESS(Status)) { + DbgPrint("Received data - '%s'\n", Data); + } else + if (Status != STATUS_CANCELLED) { + TDI_DbgPrint(MIN_TRACE, ("Receive error (Status = 0x%X).\n", Status)); + } else { + TDI_DbgPrint(MAX_TRACE, ("IRP was cancelled.\n")); + } + } + } + + TDI_DbgPrint(MAX_TRACE, ("Terminating receive thread...\n")); + + KeSetEvent(&ReceiveThreadEvent, 0, FALSE); + + PsTerminateSystemThread(STATUS_SUCCESS); +} + + +VOID TdiOpenThread( + PVOID Context) +/* + * FUNCTION: Open thread + * ARGUMENTS: + * Context = Pointer to context information (event) + */ +{ + NTSTATUS Status; + + TDI_DbgPrint(MAX_TRACE, ("Called.\n")); + + OpenError = TRUE; + + Status = TdiOpenTransport(UDP_DEVICE_NAME, + TEST_PORT, + &TdiTransport, + &TdiTransportObject); + if (NT_SUCCESS(Status)) { + Status = TdiQueryAddress(TdiTransportObject, &LocalAddress); + if (NT_SUCCESS(Status)) { + OpenError = FALSE; + DbgPrint("Using local IP address 0x%X\n", LocalAddress); + } else { + TDI_DbgPrint(MIN_TRACE, ("Unable to determine local IP address.\n")); + } + } else + TDI_DbgPrint(MIN_TRACE, ("Cannot open transport (Status = 0x%X).\n", Status)); + + TDI_DbgPrint(MAX_TRACE, ("Setting close event.\n")); + + KeSetEvent((PKEVENT)Context, 0, FALSE); + + TDI_DbgPrint(MIN_TRACE, ("Leaving.\n")); +} + + +VOID TdiUnload( + PDRIVER_OBJECT DriverObject) +/* + * FUNCTION: Unload routine + * ARGUMENTS: + * DriverObject = Pointer to a driver object for this driver + */ +{ + TDI_DbgPrint(MAX_TRACE, ("Setting stop flag\n")); + + KeSetEvent(&StopEvent, 0, FALSE); + + /* Wait for send thread to stop */ + KeWaitForSingleObject(&SendThreadEvent, + Executive, + KernelMode, + FALSE, + NULL); + + ObDereferenceObject(SendThreadObject); + + /* Wait for receive thread to stop */ + KeWaitForSingleObject(&ReceiveThreadEvent, + Executive, + KernelMode, + FALSE, + NULL); + + ObDereferenceObject(ReceiveThreadObject); + + /* Close device */ + TdiCloseDevice(TdiTransport, TdiTransportObject); +} + + +NTSTATUS +#ifndef _MSC_VER +STDCALL +#endif +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +/* + * FUNCTION: Main driver entry point + * ARGUMENTS: + * DriverObject = Pointer to a driver object for this driver + * RegistryPath = Registry node for configuration parameters + * RETURNS: + * Status of driver initialization + */ +{ + KEVENT Event; + NTSTATUS Status; + WORK_QUEUE_ITEM WorkItem; + + KeInitializeEvent(&StopEvent, NotificationEvent, FALSE); + KeInitializeEvent(&SendThreadEvent, NotificationEvent, FALSE); + KeInitializeEvent(&ReceiveThreadEvent, NotificationEvent, FALSE); + + KeInitializeEvent(&Event, SynchronizationEvent, FALSE); + ExInitializeWorkItem(&WorkItem, TdiOpenThread, &Event); + ExQueueWorkItem(&WorkItem, DelayedWorkQueue); + + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + TRUE, + NULL); + + + Status = PsCreateSystemThread(&SendThread, /* Thread handle */ + 0, /* Desired access */ + NULL, /* Object attributes */ + NULL, /* Process handle */ + NULL, /* Client id */ + (PKSTART_ROUTINE)TdiSendThread, /* Start routine */ + NULL); /* Start context */ + if (!NT_SUCCESS(Status)) { + TDI_DbgPrint(MIN_TRACE, ("PsCreateSystemThread() failed for send thread (Status = 0x%X).\n", Status)); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Get a pointer to the thread object */ + ObReferenceObjectByHandle(SendThread, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &SendThreadObject, + NULL); + + + Status = PsCreateSystemThread(&ReceiveThread, /* Thread handle */ + 0, /* Desired access */ + NULL, /* Object attributes */ + NULL, /* Process handle */ + NULL, /* Client id */ + (PKSTART_ROUTINE)TdiReceiveThread, /* Start routine */ + NULL); /* Start context */ + if (!NT_SUCCESS(Status)) { + TDI_DbgPrint(MIN_TRACE, ("PsCreateSystemThread() failed for receive thread (Status = 0x%X).\n", Status)); + ZwClose(SendThread); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Get a pointer to the thread object */ + ObReferenceObjectByHandle(ReceiveThread, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &ReceiveThreadObject, + NULL); + + /* Don't need these for anything, so we might as well close them now. + The threads will call PsTerminateSystemThread themselves when they are done */ + ZwClose(SendThread); + ZwClose(ReceiveThread); + + DriverObject->DriverUnload = (PDRIVER_UNLOAD)TdiUnload; + + return STATUS_SUCCESS; +} + +/* EOF */