mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
Added networking code from Casper Hornstrup
svn path=/trunk/; revision=1282
This commit is contained in:
parent
792773e953
commit
b5ff23bb2f
70 changed files with 12257 additions and 0 deletions
5
reactos/drivers/net/tcpip/DIRS
Normal file
5
reactos/drivers/net/tcpip/DIRS
Normal file
|
@ -0,0 +1,5 @@
|
|||
DIRS= datalink \
|
||||
network \
|
||||
transport \
|
||||
tcpip
|
||||
|
7
reactos/drivers/net/tcpip/datalink/Makefile
Normal file
7
reactos/drivers/net/tcpip/datalink/Makefile
Normal 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
|
13
reactos/drivers/net/tcpip/datalink/SOURCES
Normal file
13
reactos/drivers/net/tcpip/datalink/SOURCES
Normal 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
|
277
reactos/drivers/net/tcpip/datalink/arp.c
Normal file
277
reactos/drivers/net/tcpip/datalink/arp.c
Normal 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 */
|
903
reactos/drivers/net/tcpip/datalink/lan.c
Normal file
903
reactos/drivers/net/tcpip/datalink/lan.c
Normal 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 */
|
224
reactos/drivers/net/tcpip/datalink/loopback.c
Normal file
224
reactos/drivers/net/tcpip/datalink/loopback.c
Normal 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 */
|
63
reactos/drivers/net/tcpip/include/address.h
Normal file
63
reactos/drivers/net/tcpip/include/address.h
Normal 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 */
|
37
reactos/drivers/net/tcpip/include/arp.h
Normal file
37
reactos/drivers/net/tcpip/include/arp.h
Normal 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 */
|
27
reactos/drivers/net/tcpip/include/checksum.h
Normal file
27
reactos/drivers/net/tcpip/include/checksum.h
Normal 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 */
|
49
reactos/drivers/net/tcpip/include/datagram.h
Normal file
49
reactos/drivers/net/tcpip/include/datagram.h
Normal 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 */
|
99
reactos/drivers/net/tcpip/include/debug.h
Normal file
99
reactos/drivers/net/tcpip/include/debug.h
Normal 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 */
|
61
reactos/drivers/net/tcpip/include/dispatch.h
Normal file
61
reactos/drivers/net/tcpip/include/dispatch.h
Normal 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 */
|
32
reactos/drivers/net/tcpip/include/fileobjs.h
Normal file
32
reactos/drivers/net/tcpip/include/fileobjs.h
Normal 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 */
|
68
reactos/drivers/net/tcpip/include/icmp.h
Normal file
68
reactos/drivers/net/tcpip/include/icmp.h
Normal 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 */
|
93
reactos/drivers/net/tcpip/include/info.h
Normal file
93
reactos/drivers/net/tcpip/include/info.h
Normal 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 */
|
245
reactos/drivers/net/tcpip/include/ip.h
Normal file
245
reactos/drivers/net/tcpip/include/ip.h
Normal 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 */
|
100
reactos/drivers/net/tcpip/include/lan.h
Normal file
100
reactos/drivers/net/tcpip/include/lan.h
Normal 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 */
|
25
reactos/drivers/net/tcpip/include/loopback.h
Normal file
25
reactos/drivers/net/tcpip/include/loopback.h
Normal 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 */
|
101
reactos/drivers/net/tcpip/include/neighbor.h
Normal file
101
reactos/drivers/net/tcpip/include/neighbor.h
Normal 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 */
|
19
reactos/drivers/net/tcpip/include/pool.h
Normal file
19
reactos/drivers/net/tcpip/include/pool.h
Normal 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 */
|
24
reactos/drivers/net/tcpip/include/rawip.h
Normal file
24
reactos/drivers/net/tcpip/include/rawip.h
Normal 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 */
|
61
reactos/drivers/net/tcpip/include/receive.h
Normal file
61
reactos/drivers/net/tcpip/include/receive.h
Normal 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 */
|
75
reactos/drivers/net/tcpip/include/route.h
Normal file
75
reactos/drivers/net/tcpip/include/route.h
Normal 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 */
|
62
reactos/drivers/net/tcpip/include/router.h
Normal file
62
reactos/drivers/net/tcpip/include/router.h
Normal 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 */
|
53
reactos/drivers/net/tcpip/include/routines.h
Normal file
53
reactos/drivers/net/tcpip/include/routines.h
Normal 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 */
|
18
reactos/drivers/net/tcpip/include/tcp.h
Normal file
18
reactos/drivers/net/tcpip/include/tcp.h
Normal 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 */
|
131
reactos/drivers/net/tcpip/include/tcpip.h
Normal file
131
reactos/drivers/net/tcpip/include/tcpip.h
Normal 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 */
|
56
reactos/drivers/net/tcpip/include/ticonsts.h
Normal file
56
reactos/drivers/net/tcpip/include/ticonsts.h
Normal 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 */
|
215
reactos/drivers/net/tcpip/include/titypes.h
Normal file
215
reactos/drivers/net/tcpip/include/titypes.h
Normal 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 */
|
47
reactos/drivers/net/tcpip/include/transmit.h
Normal file
47
reactos/drivers/net/tcpip/include/transmit.h
Normal 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 */
|
68
reactos/drivers/net/tcpip/include/udp.h
Normal file
68
reactos/drivers/net/tcpip/include/udp.h
Normal 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 */
|
132
reactos/drivers/net/tcpip/makefile
Normal file
132
reactos/drivers/net/tcpip/makefile
Normal 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
|
7
reactos/drivers/net/tcpip/network/Makefile
Normal file
7
reactos/drivers/net/tcpip/network/Makefile
Normal 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
|
20
reactos/drivers/net/tcpip/network/SOURCES
Normal file
20
reactos/drivers/net/tcpip/network/SOURCES
Normal 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
|
||||
|
299
reactos/drivers/net/tcpip/network/icmp.c
Normal file
299
reactos/drivers/net/tcpip/network/icmp.c
Normal 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 */
|
979
reactos/drivers/net/tcpip/network/ip.c
Normal file
979
reactos/drivers/net/tcpip/network/ip.c
Normal 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 */
|
506
reactos/drivers/net/tcpip/network/neighbor.c
Normal file
506
reactos/drivers/net/tcpip/network/neighbor.c
Normal 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 */
|
638
reactos/drivers/net/tcpip/network/receive.c
Normal file
638
reactos/drivers/net/tcpip/network/receive.c
Normal 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 */
|
665
reactos/drivers/net/tcpip/network/route.c
Normal file
665
reactos/drivers/net/tcpip/network/route.c
Normal 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 */
|
500
reactos/drivers/net/tcpip/network/router.c
Normal file
500
reactos/drivers/net/tcpip/network/router.c
Normal 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 */
|
328
reactos/drivers/net/tcpip/network/transmit.c
Normal file
328
reactos/drivers/net/tcpip/network/transmit.c
Normal 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 */
|
19
reactos/drivers/net/tcpip/readme.txt
Normal file
19
reactos/drivers/net/tcpip/readme.txt
Normal 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
|
32
reactos/drivers/net/tcpip/tcpip.def
Normal file
32
reactos/drivers/net/tcpip/tcpip.def
Normal 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
|
32
reactos/drivers/net/tcpip/tcpip.edf
Normal file
32
reactos/drivers/net/tcpip/tcpip.edf
Normal 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
|
38
reactos/drivers/net/tcpip/tcpip.rc
Normal file
38
reactos/drivers/net/tcpip/tcpip.rc
Normal 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
|
||||
|
335
reactos/drivers/net/tcpip/tcpip/Copy of info.c
Normal file
335
reactos/drivers/net/tcpip/tcpip/Copy of info.c
Normal 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 */
|
7
reactos/drivers/net/tcpip/tcpip/Makefile
Normal file
7
reactos/drivers/net/tcpip/tcpip/Makefile
Normal 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
|
28
reactos/drivers/net/tcpip/tcpip/SOURCES
Normal file
28
reactos/drivers/net/tcpip/tcpip/SOURCES
Normal 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
|
||||
|
312
reactos/drivers/net/tcpip/tcpip/address.c
Normal file
312
reactos/drivers/net/tcpip/tcpip/address.c
Normal 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 */
|
50
reactos/drivers/net/tcpip/tcpip/checksum.c
Normal file
50
reactos/drivers/net/tcpip/tcpip/checksum.c
Normal 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 */
|
871
reactos/drivers/net/tcpip/tcpip/dispatch.c
Normal file
871
reactos/drivers/net/tcpip/tcpip/dispatch.c
Normal 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 */
|
396
reactos/drivers/net/tcpip/tcpip/fileobjs.c
Normal file
396
reactos/drivers/net/tcpip/tcpip/fileobjs.c
Normal 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 */
|
339
reactos/drivers/net/tcpip/tcpip/info.c
Normal file
339
reactos/drivers/net/tcpip/tcpip/info.c
Normal 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 */
|
805
reactos/drivers/net/tcpip/tcpip/main.c
Normal file
805
reactos/drivers/net/tcpip/tcpip/main.c
Normal 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 */
|
50
reactos/drivers/net/tcpip/tcpip/pool.c
Normal file
50
reactos/drivers/net/tcpip/tcpip/pool.c
Normal 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 */
|
10
reactos/drivers/net/tcpip/tcpip/resource.rc
Normal file
10
reactos/drivers/net/tcpip/tcpip/resource.rc
Normal 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"
|
403
reactos/drivers/net/tcpip/tcpip/routines.c
Normal file
403
reactos/drivers/net/tcpip/tcpip/routines.c
Normal 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 */
|
5
reactos/drivers/net/tcpip/transport/DIRS
Normal file
5
reactos/drivers/net/tcpip/transport/DIRS
Normal file
|
@ -0,0 +1,5 @@
|
|||
DIRS= datagram \
|
||||
rawip \
|
||||
tcp \
|
||||
udp
|
||||
|
7
reactos/drivers/net/tcpip/transport/datagram/Makefile
Normal file
7
reactos/drivers/net/tcpip/transport/datagram/Makefile
Normal 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
|
13
reactos/drivers/net/tcpip/transport/datagram/SOURCES
Normal file
13
reactos/drivers/net/tcpip/transport/datagram/SOURCES
Normal 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
|
||||
|
520
reactos/drivers/net/tcpip/transport/datagram/datagram.c
Normal file
520
reactos/drivers/net/tcpip/transport/datagram/datagram.c
Normal 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 */
|
7
reactos/drivers/net/tcpip/transport/rawip/Makefile
Normal file
7
reactos/drivers/net/tcpip/transport/rawip/Makefile
Normal 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
|
13
reactos/drivers/net/tcpip/transport/rawip/SOURCES
Normal file
13
reactos/drivers/net/tcpip/transport/rawip/SOURCES
Normal 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
|
||||
|
113
reactos/drivers/net/tcpip/transport/rawip/rawip.c
Normal file
113
reactos/drivers/net/tcpip/transport/rawip/rawip.c
Normal 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 */
|
7
reactos/drivers/net/tcpip/transport/tcp/Makefile
Normal file
7
reactos/drivers/net/tcpip/transport/tcp/Makefile
Normal 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
|
13
reactos/drivers/net/tcpip/transport/tcp/SOURCES
Normal file
13
reactos/drivers/net/tcpip/transport/tcp/SOURCES
Normal 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
|
||||
|
44
reactos/drivers/net/tcpip/transport/tcp/tcp.c
Normal file
44
reactos/drivers/net/tcpip/transport/tcp/tcp.c
Normal 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 */
|
7
reactos/drivers/net/tcpip/transport/udp/Makefile
Normal file
7
reactos/drivers/net/tcpip/transport/udp/Makefile
Normal 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
|
12
reactos/drivers/net/tcpip/transport/udp/SOURCES
Normal file
12
reactos/drivers/net/tcpip/transport/udp/SOURCES
Normal 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
|
437
reactos/drivers/net/tcpip/transport/udp/udp.c
Normal file
437
reactos/drivers/net/tcpip/transport/udp/udp.c
Normal 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 */
|
Loading…
Reference in a new issue