Added networking code from Casper Hornstrup

svn path=/trunk/; revision=1282
This commit is contained in:
David Welch 2000-08-02 00:02:53 +00:00
parent 792773e953
commit b5ff23bb2f
70 changed files with 12257 additions and 0 deletions

View file

@ -0,0 +1,5 @@
DIRS= datalink \
network \
transport \
tcpip

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +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 <tcpip.h>
#include <arp.h>
#include <routines.h>
#include <neighbor.h>
#include <address.h>
#include <pool.h>
#include <lan.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <lan.h>
#include <address.h>
#include <routines.h>
#include <transmit.h>
#include <receive.h>
#include <arp.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <loopback.h>
#include <ip.h>
#include <address.h>
#include <receive.h>
#include <transmit.h>
#include <routines.h>
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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 <titypes.h>
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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 <lan.h>
extern PIP_INTERFACE Loopback;
NDIS_STATUS LoopRegisterAdapter(
PNDIS_STRING AdapterName,
PLAN_ADAPTER *Adapter);
NDIS_STATUS LoopUnregisterAdapter(
PLAN_ADAPTER Adapter);
#endif /* __LOOPBACK_H */
/* EOF */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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.h>
/* 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 */

View file

@ -0,0 +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 <neighbor.h>
#include <address.h>
#include <router.h>
#include <pool.h>
#include <arp.h>
/* 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 */

View file

@ -0,0 +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 <neighbor.h>
/* 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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 <basetsd.h>
#include <ntddk.h>
#include <windef.h>
#include <ndis.h>
#include <tdikrnl.h>
#include <tdiinfo.h>
#else
#include <ddk/ntddk.h>
#include <net/ndis.h>
#include <net/tdikrnl.h>
#include <net/tdiinfo.h>
#endif
#include <debug.h>
/* 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 <titypes.h>
#include <ticonsts.h>
#include <udp.h>
/* 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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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 <ip.h>
#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 */

View file

@ -0,0 +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 <neighbor.h>
#include <route.h>
#include <ip.h>
/* 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 */

View file

@ -0,0 +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 */

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +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 <tcpip.h>
#include <icmp.h>
#include <checksum.h>
#include <routines.h>
#include <transmit.h>
#include <pool.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <ip.h>
#include <loopback.h>
#include <neighbor.h>
#include <receive.h>
#include <address.h>
#include <route.h>
#include <icmp.h>
#include <pool.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <neighbor.h>
#include <routines.h>
#include <neighbor.h>
#include <transmit.h>
#include <address.h>
#include <route.h>
#include <pool.h>
#include <arp.h>
#include <ip.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <receive.h>
#include <routines.h>
#include <checksum.h>
#include <transmit.h>
#include <address.h>
#include <pool.h>
#include <route.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <route.h>
#include <router.h>
/* 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 */

View file

@ -0,0 +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 <tcpip.h>
#include <address.h>
#include <router.h>
#include <pool.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <transmit.h>
#include <routines.h>
#include <checksum.h>
#include <pool.h>
#include <arp.h>
#include <lan.h>
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 */

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +1,38 @@
#include <defines.h>
#include <reactos/resource.h>
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

View file

@ -0,0 +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 <tcpip.h>
#include <routines.h>
#include <info.h>
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 */

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +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 <tcpip.h>
#include <address.h>
#include <pool.h>
#include <ip.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <checksum.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <dispatch.h>
#include <routines.h>
#include <datagram.h>
#include <info.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <datagram.h>
#include <address.h>
#include <pool.h>
#include <rawip.h>
#include <udp.h>
#include <ip.h>
#include <fileobjs.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <info.h>
#include <routines.h>
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 */

View file

@ -0,0 +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 <tcpip.h>
#include <dispatch.h>
#include <fileobjs.h>
#include <datagram.h>
#include <loopback.h>
#include <rawip.h>
#include <udp.h>
#include <tcp.h>
#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 */

View file

@ -0,0 +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 <tcpip.h>
#include <pool.h>
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 */

View file

@ -0,0 +1,10 @@
#include <windows.h>
#include <ntverp.h>
#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"

View file

@ -0,0 +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 <tcpip.h>
#include <routines.h>
#include <pool.h>
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 */

View file

@ -0,0 +1,5 @@
DIRS= datagram \
rawip \
tcp \
udp

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +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 <tcpip.h>
#include <datagram.h>
#include <routines.h>
#include <transmit.h>
#include <address.h>
#include <route.h>
#include <pool.h>
/* 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 */

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +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 <tcpip.h>
#include <datagram.h>
#include <rawip.h>
#include <pool.h>
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 */

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +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 <tcpip.h>
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 */

View file

@ -0,0 +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

View file

@ -0,0 +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

View file

@ -0,0 +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 <tcpip.h>
#include <udp.h>
#include <routines.h>
#include <transmit.h>
#include <datagram.h>
#include <checksum.h>
#include <address.h>
#include <pool.h>
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 */