* REVISIONS:
* CSH 01/08-2000 Created
*/
-#include <tcpip.h>
-#include <datagram.h>
-#include <address.h>
-#include <pool.h>
-#include <rawip.h>
-#include <tcp.h>
-#include <udp.h>
-#include <ip.h>
-#include <fileobjs.h>
+
+#include "precomp.h"
+
/* List of all address file objects managed by this driver */
LIST_ENTRY AddressFileListHead;
LIST_ENTRY ConnectionEndpointListHead;
KSPIN_LOCK ConnectionEndpointListLock;
+/*
+ * 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);
+}
+
+BOOLEAN AddrIsBroadcast(
+ PIP_ADDRESS PossibleMatch,
+ PIP_ADDRESS TargetAddress ) {
+ IF_LIST_ITER(IF);
+
+ ForEachInterface(IF) {
+ if( AddrIsEqual( &IF->Unicast, PossibleMatch ) &&
+ AddrIsEqual( &IF->Broadcast, TargetAddress ) )
+ return TRUE;
+ } EndFor(IF);
+
+ return FALSE;
+}
+
+/*
+ * 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;
+
+ TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
+
+ while (CurrentEntry != &AddressFileListHead) {
+ Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
+
+ IPAddress = &Current->Address;
+
+ TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
+ WN2H(Current->Port),
+ Current->Protocol,
+ A2S(IPAddress),
+ WN2H(SearchContext->Port),
+ SearchContext->Protocol,
+ A2S(SearchContext->Address)));
+
+ /* See if this address matches the search criteria */
+ if ((Current->Port == SearchContext->Port) &&
+ (Current->Protocol == SearchContext->Protocol) &&
+ (AddrIsEqual(IPAddress, SearchContext->Address) ||
+ AddrIsBroadcast(IPAddress, SearchContext->Address) ||
+ AddrIsUnspecified(IPAddress))) {
+ /* We've found a match */
+ Found = TRUE;
+ break;
+ }
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
+
+ if (Found) {
+ SearchContext->Next = CurrentEntry->Flink;
+ return Current;
+ } else
+ return NULL;
+}
VOID AddrFileFree(
PVOID Object)
}
-VOID DeleteAddress(
- PADDRESS_FILE AddrFile)
+VOID ControlChannelFree(
+ PVOID Object)
+/*
+ * FUNCTION: Frees an address file object
+ * ARGUMENTS:
+ * Object = Pointer to address file object to free
+ */
+{
+ ExFreePool(Object);
+}
+
+
+VOID DeleteAddress(PADDRESS_FILE AddrFile)
/*
* FUNCTION: Deletes an address file object
* ARGUMENTS:
TI_DbgPrint(MID_TRACE, ("Called.\n"));
/* Remove address file from the global list */
- KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
+ TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
RemoveEntryList(&AddrFile->ListEntry);
- KeReleaseSpinLock(&AddressFileListLock, OldIrql);
+ TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
- KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+ TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
/* FIXME: Kill TCP connections on this address file object */
NextEntry = CurrentEntry->Flink;
ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
/* Abort the request and free its resources */
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+ TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
(*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0);
- ExFreePool(ReceiveRequest);
- KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+ TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
CurrentEntry = NextEntry;
}
CurrentEntry = AddrFile->TransmitQueue.Flink;
while (CurrentEntry != &AddrFile->TransmitQueue) {
NextEntry = CurrentEntry->Flink;
- SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
+ SendRequest = CONTAINING_RECORD(CurrentEntry,
+ DATAGRAM_SEND_REQUEST, ListEntry);
/* Abort the request and free its resources */
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+ TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
(*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);
ExFreePool(SendRequest);
- KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+ TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
CurrentEntry = NextEntry;
}
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
-
- /* Dereference address entry */
- DereferenceObject(AddrFile->ADE);
+ TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
- /* 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
-
(*AddrFile->Free)(AddrFile);
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
PCONNECTION_ENDPOINT Connection)
{
KIRQL OldIrql;
- PLIST_ENTRY CurrentEntry;
- PLIST_ENTRY NextEntry;
TI_DbgPrint(MID_TRACE, ("Called.\n"));
/* Remove connection endpoint from the global list */
- KeAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
+ TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
RemoveEntryList(&Connection->ListEntry);
- KeReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
-
- KeAcquireSpinLock(&Connection->Lock, &OldIrql);
-
- /* Dereference and remove the address file if it exists */
- if (Connection->AddressFile) {
- DereferenceObject(Connection->AddressFile);
- }
-
- KeReleaseSpinLock(&Connection->Lock, OldIrql);
-
-#ifdef DBG
- /* Remove reference provided at creation time */
- Connection->RefCount--;
-
- if (Connection->RefCount != 0)
- TI_DbgPrint(DEBUG_REFCOUNT, ("Connection->RefCount is (%d) (should be 0).\n",
- Connection->RefCount));
-#endif
+ TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
ExFreePool(Connection);
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:
USHORT Protocol,
PVOID Options)
{
- PADDRESS_FILE AddrFile;
IPv4_RAW_ADDRESS IPv4Address;
+ BOOLEAN Matched;
+ PADDRESS_FILE AddrFile;
- TI_DbgPrint(MID_TRACE, ("Called.\n"));
+ TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
AddrFile = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_FILE));
if (!AddrFile) {
/* Locate address entry. If specified address is 0, a random address is chosen */
/* FIXME: IPv4 only */
+ AddrFile->Family = Address->Address[0].AddressType;
IPv4Address = Address->Address[0].Address[0].in_addr;
if (IPv4Address == 0)
- AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST);
+ Matched = IPGetDefaultAddress(&AddrFile->Address);
else
- AddrFile->ADE = AddrLocateADEv4(IPv4Address);
+ Matched = AddrLocateADEv4(IPv4Address, &AddrFile->Address);
- if (!AddrFile->ADE) {
+ if (!Matched) {
ExFreePool(AddrFile);
TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address)));
return STATUS_INVALID_PARAMETER;
}
- TI_DbgPrint(MID_TRACE, ("Opening address %s for communication.\n",
- A2S(AddrFile->ADE->Address)));
+ TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
+ A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
/* Protocol specific handling */
switch (Protocol) {
case IPPROTO_TCP:
- /* FIXME: If specified port is 0, a port is chosen dynamically */
- AddrFile->Port = ((PTDI_ADDRESS_IP)Address->Address)->sin_port;
- AddrFile->Send = TCPSendDatagram;
- break;
+ AddrFile->Port =
+ TCPAllocatePort(Address->Address[0].Address[0].sin_port);
+ AddrFile->Send = NULL; /* TCPSendData */
+ break;
case IPPROTO_UDP:
- /* FIXME: If specified port is 0, a port is chosen dynamically */
- AddrFile->Port = ((PTDI_ADDRESS_IP)Address->Address)->sin_port;
- AddrFile->Send = UDPSendDatagram;
- break;
+ TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
+ AddrFile->Port =
+ UDPAllocatePort(Address->Address[0].Address[0].sin_port);
+ TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n",
+ AddrFile->Port,
+ Address->Address[0].Address[0].sin_port));
+ AddrFile->Send = UDPSendDatagram;
+ break;
default:
/* Use raw IP for all other protocols */
/* 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);
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);
+ TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
- 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);
+ /* Set address file object exclusive to us */
+ AF_SET_BUSY(AddrFile);
+ AF_CLR_VALID(AddrFile);
- TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
+ TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
- return STATUS_PENDING;
- } else
- Status = STATUS_ADDRESS_CLOSED;
+ /* Protocol specific handling */
+ switch (AddrFile->Protocol) {
+ case IPPROTO_TCP:
+ TCPFreePort( AddrFile->Port );
+ if( AddrFile->Listener )
+ TCPClose( AddrFile->Listener );
+ break;
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+ case IPPROTO_UDP:
+ UDPFreePort( AddrFile->Port );
+ break;
}
+ DeleteAddress(AddrFile);
+
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
return Status;
PTDI_REQUEST Request,
PVOID ClientContext)
{
+ NTSTATUS Status;
PCONNECTION_ENDPOINT Connection;
TI_DbgPrint(MID_TRACE, ("Called.\n"));
- Connection = ExAllocatePool(NonPagedPool, sizeof(CONNECTION_ENDPOINT));
- if (!Connection)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
+ Connection = TCPAllocateConnectionEndpoint( ClientContext );
- RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
+ if( !Connection ) return STATUS_NO_MEMORY;
- /* Initialize spin lock that protects the connection endpoint file object */
- KeInitializeSpinLock(&Connection->Lock);
-
- /* Reference the object */
- Connection->RefCount = 1;
-
- /* Put connection in the closed state */
- Connection->State = ctClosed;
-
- /* Save client context pointer */
- Connection->ClientContext = ClientContext;
+ Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
/* Return connection endpoint file object */
Request->Handle.ConnectionContext = Connection;
}
+/*
+ * FUNCTION: Find a connection by examining the context field. This
+ * is needed in some situations where a FIN reply is needed after a
+ * socket is formally broken.
+ * ARGUMENTS:
+ * Request = Pointer to TDI request structure for this request
+ * RETURNS:
+ * Status of operation
+ */
+PCONNECTION_ENDPOINT FileFindConnectionByContext( PVOID Context ) {
+ PLIST_ENTRY Entry;
+ KIRQL OldIrql;
+ PCONNECTION_ENDPOINT Connection = NULL;
+
+ TcpipAcquireSpinLock( &ConnectionEndpointListLock, &OldIrql );
+
+ for( Entry = ConnectionEndpointListHead.Flink;
+ Entry != &ConnectionEndpointListHead;
+ Entry = Entry->Flink ) {
+ Connection =
+ CONTAINING_RECORD( Entry, CONNECTION_ENDPOINT, ListEntry );
+ if( Connection->SocketContext == Context ) break;
+ else Connection = NULL;
+ }
+
+ TcpipReleaseSpinLock( &ConnectionEndpointListLock, OldIrql );
+
+ return Connection;
+}
+
/*
* FUNCTION: Closes an connection file object
* ARGUMENTS:
NTSTATUS FileCloseConnection(
PTDI_REQUEST Request)
{
- KIRQL OldIrql;
PCONNECTION_ENDPOINT Connection;
NTSTATUS Status = STATUS_SUCCESS;
Connection = Request->Handle.ConnectionContext;
-#if 0
- KeAcquireSpinLock(&Connection->Lock, &OldIrql);
- if ((!AF_IS_BUSY(Connection)) && (Connection->RefCount == 1)) {
- /* Set connection endpoint file object exclusive to us */
- AF_SET_BUSY(Connection);
- AF_CLR_VALID(Connection);
-
- KeReleaseSpinLock(&Connection->Lock, OldIrql);
-#endif
- DeleteConnectionEndpoint(Connection);
-#if 0
- } else {
- if (!AF_IS_PENDING(Connection, AFF_DELETE)) {
- Connection->Complete = Request->RequestNotifyObject;
- Connection->Context = Request->RequestContext;
-
- /* Shedule connection endpoint for deletion */
- AF_SET_PENDING(Connection, AFF_DELETE);
- AF_CLR_VALID(Connection);
-
- if (!AF_IS_BUSY(Connection)) {
- /* Worker function is not running, so shedule it to run */
- AF_SET_BUSY(Connection);
- KeReleaseSpinLock(&Connection->Lock, OldIrql);
- ExQueueWorkItem(&Connection->WorkItem, CriticalWorkQueue);
- } else
- KeReleaseSpinLock(&Connection->Lock, OldIrql);
-
- TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
-
- return STATUS_PENDING;
- } else
- Status = STATUS_ADDRESS_CLOSED;
+ TcpipRecursiveMutexEnter( &TCPLock, TRUE );
+ TCPClose(Connection);
+ DeleteConnectionEndpoint(Connection);
+ TcpipRecursiveMutexLeave( &TCPLock );
- KeReleaseSpinLock(&Connection->Lock, OldIrql);
- }
-#endif
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
return Status;
* Status of operation
*/
NTSTATUS FileOpenControlChannel(
- PTDI_REQUEST Request)
+ PTDI_REQUEST Request)
{
- return STATUS_NOT_IMPLEMENTED;
-}
+ PCONTROL_CHANNEL ControlChannel;
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ ControlChannel = ExAllocatePool(NonPagedPool, sizeof(*ControlChannel));
+
+ if (!ControlChannel) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
+ /* Make sure address is a local unicast address or 0 */
+
+ /* Locate address entry. If specified address is 0, a random address is chosen */
+
+ /* Initialize receive and transmit queues */
+ InitializeListHead(&ControlChannel->ListEntry);
+
+ /* Initialize spin lock that protects the address file object */
+ KeInitializeSpinLock(&ControlChannel->Lock);
+
+ /* Return address file object */
+ Request->Handle.ControlChannel = ControlChannel;
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return STATUS_SUCCESS;
+}
/*
* FUNCTION: Closes a control channel file object
NTSTATUS FileCloseControlChannel(
PTDI_REQUEST Request)
{
- return STATUS_NOT_IMPLEMENTED;
+ PCONTROL_CHANNEL ControlChannel = Request->Handle.ControlChannel;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ ExFreePool(ControlChannel);
+ Request->Handle.ControlChannel = NULL;
+
+ return Status;
}
/* EOF */