-/*\r
- * COPYRIGHT: See COPYING in the top level directory\r
- * PROJECT: ReactOS TCP/IP protocol driver\r
- * FILE: tcpip/fileobjs.c\r
- * PURPOSE: Routines for handling file objects\r
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * REVISIONS:\r
- * CSH 01/08-2000 Created\r
- */\r
-#include <tcpip.h>\r
-#include <datagram.h>\r
-#include <address.h>\r
-#include <pool.h>\r
-#include <rawip.h>\r
-#include <udp.h>\r
-#include <ip.h>\r
-#include <fileobjs.h>\r
-\r
-LIST_ENTRY AddressFileListHead;\r
-KSPIN_LOCK AddressFileListLock;\r
-\r
-\r
-/*\r
- * FUNCTION: Deletes an address file object\r
- * ARGUMENTS:\r
- * AddrFile = Pointer to address file object to delete\r
- */\r
-VOID DeleteAddress(\r
- PADDRESS_FILE AddrFile)\r
-{\r
- KIRQL OldIrql;\r
- PLIST_ENTRY CurrentEntry;\r
- PLIST_ENTRY NextEntry;\r
- PDATAGRAM_SEND_REQUEST SendRequest;\r
- PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;\r
-\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
- /* Remove address file from the global list */\r
- KeAcquireSpinLock(&AddressFileListLock, &OldIrql);\r
- RemoveEntryList(&AddrFile->ListEntry);\r
- KeReleaseSpinLock(&AddressFileListLock, OldIrql);\r
-\r
- KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
- /* FIXME: Kill TCP connections on this address file object */\r
-\r
- /* Return pending requests with error */\r
-\r
- TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));\r
-\r
- /* Go through pending receive request list and cancel them all */\r
- CurrentEntry = AddrFile->ReceiveQueue.Flink;\r
- while (CurrentEntry != &AddrFile->ReceiveQueue) {\r
- NextEntry = CurrentEntry->Flink;\r
- ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);\r
- /* Abort the request and free its resources */\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
- (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0);\r
- PoolFreeBuffer(ReceiveRequest);\r
- KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
- CurrentEntry = NextEntry;\r
- }\r
-\r
- TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));\r
-\r
- /* Go through pending send request list and cancel them all */\r
- CurrentEntry = AddrFile->TransmitQueue.Flink;\r
- while (CurrentEntry != &AddrFile->TransmitQueue) {\r
- NextEntry = CurrentEntry->Flink;\r
- SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);\r
- /* Abort the request and free its resources */\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
- (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);\r
- PoolFreeBuffer(SendRequest);\r
- KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
- CurrentEntry = NextEntry;\r
- }\r
-\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
- /* Dereference address entry */\r
- DereferenceObject(AddrFile->ADE);\r
-\r
- /* Dereference address cache */\r
- if (AddrFile->AddrCache)\r
- DereferenceObject(AddrFile->AddrCache);\r
-\r
-#ifdef DBG\r
- /* Remove reference provided at creation time */\r
- AddrFile->RefCount--;\r
-\r
- if (AddrFile->RefCount != 0)\r
- TI_DbgPrint(DEBUG_REFCOUNT, ("AddrFile->RefCount is (%d) (should be 0).\n", AddrFile->RefCount));\r
-#endif\r
- \r
- PoolFreeBuffer(AddrFile);\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-VOID RequestWorker(\r
- PVOID Context)\r
-/*\r
- * FUNCTION: Worker routine for processing address file object requests\r
- * ARGUMENTS:\r
- * Context = Pointer to context information (ADDRESS_FILE)\r
- */\r
-{\r
- KIRQL OldIrql;\r
- PLIST_ENTRY CurrentEntry;\r
- PADDRESS_FILE AddrFile = Context;\r
-\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
- KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
- /* Check it the address file should be deleted */\r
- if (AF_IS_PENDING(AddrFile, AFF_DELETE)) {\r
- DATAGRAM_COMPLETION_ROUTINE RtnComplete;\r
- PVOID RtnContext;\r
-\r
- RtnComplete = AddrFile->Complete;\r
- RtnContext = AddrFile->Context;\r
-\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
- DeleteAddress(AddrFile);\r
-\r
- (*RtnComplete)(RtnContext, TDI_SUCCESS, 0);\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Leaving (delete).\n"));\r
-\r
- return;\r
- }\r
-\r
- /* Check if there is a pending send request */\r
- if (AF_IS_PENDING(AddrFile, AFF_SEND)) {\r
- if (!IsListEmpty(&AddrFile->TransmitQueue)) {\r
- PDATAGRAM_SEND_REQUEST SendRequest;\r
-\r
- CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);\r
- SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);\r
-\r
- AF_CLR_BUSY(AddrFile);\r
-\r
- ReferenceObject(AddrFile);\r
-\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
- /* The send routine processes the send requests in\r
- the transmit queue on the address file. When the\r
- queue is empty the pending send flag is cleared.\r
- The routine may return with the pending send flag\r
- set. This can happen if there was not enough free\r
- resources available to complete all send requests */\r
- DGSend(AddrFile, SendRequest);\r
-\r
- KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
- DereferenceObject(AddrFile);\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Leaving (send request).\n"));\r
-\r
- return;\r
- } else\r
- /* There was a pending send, but no send request.\r
- Print a debug message and continue */\r
- TI_DbgPrint(MIN_TRACE, ("Pending send, but no send request.\n"));\r
- }\r
-\r
- AF_CLR_BUSY(AddrFile);\r
-\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Open an address file object\r
- * ARGUMENTS:\r
- * Request = Pointer to TDI request structure for this request\r
- * Address = Pointer to address to be opened\r
- * Protocol = Protocol on which to open the address\r
- * Options = Pointer to option buffer\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-NTSTATUS FileOpenAddress(\r
- PTDI_REQUEST Request,\r
- PTA_ADDRESS_IP Address,\r
- USHORT Protocol,\r
- PVOID Options)\r
-{\r
- PADDRESS_FILE AddrFile;\r
- IPv4_RAW_ADDRESS IPv4Address;\r
-\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
- AddrFile = PoolAllocateBuffer(sizeof(ADDRESS_FILE));\r
- if (!AddrFile) {\r
- TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
- return STATUS_INSUFFICIENT_RESOURCES;\r
- }\r
-\r
- TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));\r
-\r
- RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));\r
-\r
- /* Make sure address is a local unicast address or 0 */\r
-\r
- /* Locate address entry. If specified address is 0, a random address is chosen */\r
-\r
- IPv4Address = Address->Address[0].Address[0].in_addr;\r
- if (IPv4Address == 0)\r
- AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST);\r
- else\r
- AddrFile->ADE = AddrLocateADEv4(IPv4Address);\r
-\r
- if (!AddrFile->ADE) {\r
- PoolFreeBuffer(AddrFile);\r
- TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address)));\r
- return STATUS_INVALID_PARAMETER;\r
- }\r
-\r
- TI_DbgPrint(DEBUG_ADDRFILE, ("Opening address (0x%X) for communication.\n",\r
- DN2H(AddrFile->ADE->Address->Address.IPv4Address)));\r
-\r
- /* Protocol specific handling */\r
- switch (Protocol) {\r
- case IPPROTO_TCP:\r
- /* FIXME: TCP */\r
- TI_DbgPrint(MIN_TRACE, ("TCP is not supported.\n"));\r
- DereferenceObject(AddrFile->ADE);\r
- PoolFreeBuffer(AddrFile);\r
- return STATUS_INVALID_PARAMETER;\r
- case IPPROTO_UDP:\r
- /* FIXME: If specified port is 0, a port is chosen dynamically */\r
- AddrFile->Port = Address->Address[0].Address[0].sin_port;\r
- AddrFile->Send = UDPSendDatagram;\r
- break;\r
- default:\r
- /* Use raw IP for all other protocols */\r
- AddrFile->Send = RawIPSendDatagram;\r
- break;\r
- }\r
-\r
- /* Set protocol */\r
- AddrFile->Protocol = Protocol;\r
- \r
- /* Initialize receive and transmit queues */\r
- InitializeListHead(&AddrFile->ReceiveQueue);\r
- InitializeListHead(&AddrFile->TransmitQueue);\r
-\r
- /* Initialize work queue item. We use this for pending requests */\r
- ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile);\r
-\r
- /* Initialize spin lock that protects the address file object */\r
- KeInitializeSpinLock(&AddrFile->Lock);\r
-\r
- /* Reference the object */\r
- AddrFile->RefCount = 1;\r
-\r
- /* Set valid flag so the address can be used */\r
- AF_SET_VALID(AddrFile);\r
-\r
- /* Return address file object */\r
- Request->Handle.AddressHandle = AddrFile;\r
-\r
- /* Add address file to global list */\r
- ExInterlockedInsertTailList(&AddressFileListHead, &AddrFile->ListEntry, &AddressFileListLock);\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Closes an address file object\r
- * ARGUMENTS:\r
- * Request = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-NTSTATUS FileCloseAddress(\r
- PTDI_REQUEST Request)\r
-{\r
- KIRQL OldIrql;\r
- PADDRESS_FILE AddrFile;\r
- NTSTATUS Status = STATUS_SUCCESS;\r
-\r
- TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
- AddrFile = Request->Handle.AddressHandle;\r
-\r
- KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
- if ((!AF_IS_BUSY(AddrFile)) && (AddrFile->RefCount == 1)) {\r
- /* Set address file object exclusive to us */\r
- AF_SET_BUSY(AddrFile);\r
- AF_CLR_VALID(AddrFile);\r
-\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
- DeleteAddress(AddrFile);\r
- } else {\r
- if (!AF_IS_PENDING(AddrFile, AFF_DELETE)) {\r
- AddrFile->Complete = Request->RequestNotifyObject;\r
- AddrFile->Context = Request->RequestContext;\r
-\r
- /* Shedule address file for deletion */\r
- AF_SET_PENDING(AddrFile, AFF_DELETE);\r
- AF_CLR_VALID(AddrFile);\r
-\r
- if (!AF_IS_BUSY(AddrFile)) {\r
- /* Worker function is not running, so shedule it to run */\r
- AF_SET_BUSY(AddrFile);\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
- ExQueueWorkItem(&AddrFile->WorkItem, CriticalWorkQueue);\r
- } else\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));\r
-\r
- return STATUS_PENDING;\r
- } else\r
- Status = STATUS_ADDRESS_CLOSED;\r
-\r
- KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
- }\r
-\r
- TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-\r
- return Status;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Opens a connection file object\r
- * ARGUMENTS:\r
- * Request = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-NTSTATUS FileOpenConnection(\r
- PTDI_REQUEST Request)\r
-{\r
- return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Closes an connection file object\r
- * ARGUMENTS:\r
- * Request = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-NTSTATUS FileCloseConnection(\r
- PTDI_REQUEST Request)\r
-{\r
- return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Opens a control channel file object\r
- * ARGUMENTS:\r
- * Request = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-NTSTATUS FileOpenControlChannel(\r
- PTDI_REQUEST Request)\r
-{\r
- return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Closes a control channel file object\r
- * ARGUMENTS:\r
- * Request = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- * Status of operation\r
- */\r
-NTSTATUS FileCloseControlChannel(\r
- PTDI_REQUEST Request)\r
-{\r
- return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * 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 "precomp.h"
+
+
+/* List of all address file objects managed by this driver */
+LIST_ENTRY AddressFileListHead;
+KSPIN_LOCK AddressFileListLock;
+
+/* List of all connection endpoint file objects managed by this driver */
+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)
+/*
+ * FUNCTION: Frees an address file object
+ * ARGUMENTS:
+ * Object = Pointer to address file object to free
+ */
+{
+ ExFreePool(Object);
+}
+
+
+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:
+ * AddrFile = Pointer to address file object to delete
+ */
+{
+ 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 */
+ TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
+ RemoveEntryList(&AddrFile->ListEntry);
+ TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
+
+ TcpipAcquireSpinLock(&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 */
+ TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
+ (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0);
+ TcpipAcquireSpinLock(&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 */
+ TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
+ (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);
+ ExFreePool(SendRequest);
+ TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+ CurrentEntry = NextEntry;
+ }
+
+ TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+ (*AddrFile->Free)(AddrFile);
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+/*
+ * FUNCTION: Deletes a connection endpoint file object
+ * ARGUMENTS:
+ * Connection = Pointer to connection endpoint to delete
+ */
+VOID DeleteConnectionEndpoint(
+ PCONNECTION_ENDPOINT Connection)
+{
+ KIRQL OldIrql;
+
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ /* Remove connection endpoint from the global list */
+ TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
+ RemoveEntryList(&Connection->ListEntry);
+ TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
+
+ ExFreePool(Connection);
+
+ 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_IP_ADDRESS Address,
+ USHORT Protocol,
+ PVOID Options)
+{
+ IPv4_RAW_ADDRESS IPv4Address;
+ BOOLEAN Matched;
+ PADDRESS_FILE AddrFile;
+
+ TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
+
+ AddrFile = ExAllocatePool(NonPagedPool, 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));
+
+ AddrFile->Free = AddrFileFree;
+
+ /* Make sure address is a local unicast address or 0 */
+
+ /* 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)
+ Matched = IPGetDefaultAddress(&AddrFile->Address);
+ else
+ Matched = AddrLocateADEv4(IPv4Address, &AddrFile->Address);
+
+ 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 (P=%d U=%d).\n",
+ A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
+
+ /* Protocol specific handling */
+ switch (Protocol) {
+ case IPPROTO_TCP:
+ AddrFile->Port =
+ TCPAllocatePort(Address->Address[0].Address[0].sin_port);
+ AddrFile->Send = NULL; /* TCPSendData */
+ break;
+
+ case IPPROTO_UDP:
+ 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 */
+ AddrFile->Port = 0;
+ AddrFile->Send = RawIPSendDatagram;
+ break;
+ }
+
+ TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
+ Protocol));
+
+ TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
+ WN2H(AddrFile->Port)));
+
+ /* Set protocol */
+ AddrFile->Protocol = Protocol;
+
+ /* Initialize receive and transmit queues */
+ InitializeListHead(&AddrFile->ReceiveQueue);
+ InitializeListHead(&AddrFile->TransmitQueue);
+
+ /* Initialize spin lock that protects the address file object */
+ KeInitializeSpinLock(&AddrFile->Lock);
+
+ /* 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;
+
+ TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+ /* Set address file object exclusive to us */
+ AF_SET_BUSY(AddrFile);
+ AF_CLR_VALID(AddrFile);
+
+ TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+ /* Protocol specific handling */
+ switch (AddrFile->Protocol) {
+ case IPPROTO_TCP:
+ TCPFreePort( AddrFile->Port );
+ if( AddrFile->Listener )
+ TCPClose( AddrFile->Listener );
+ break;
+
+ case IPPROTO_UDP:
+ UDPFreePort( AddrFile->Port );
+ break;
+ }
+
+ DeleteAddress(AddrFile);
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return Status;
+}
+
+
+/*
+ * FUNCTION: Opens a connection file object
+ * ARGUMENTS:
+ * Request = Pointer to TDI request structure for this request
+ * ClientContext = Pointer to client context information
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS FileOpenConnection(
+ PTDI_REQUEST Request,
+ PVOID ClientContext)
+{
+ NTSTATUS Status;
+ PCONNECTION_ENDPOINT Connection;
+
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ Connection = TCPAllocateConnectionEndpoint( ClientContext );
+
+ if( !Connection ) return STATUS_NO_MEMORY;
+
+ Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
+
+ /* Return connection endpoint file object */
+ Request->Handle.ConnectionContext = Connection;
+
+ /* Add connection endpoint to global list */
+ ExInterlockedInsertTailList(
+ &ConnectionEndpointListHead,
+ &Connection->ListEntry,
+ &ConnectionEndpointListLock);
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return STATUS_SUCCESS;
+}
+
+
+/*
+ * 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:
+ * Request = Pointer to TDI request structure for this request
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS FileCloseConnection(
+ PTDI_REQUEST Request)
+{
+ PCONNECTION_ENDPOINT Connection;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ Connection = Request->Handle.ConnectionContext;
+
+ TcpipRecursiveMutexEnter( &TCPLock, TRUE );
+ TCPClose(Connection);
+ DeleteConnectionEndpoint(Connection);
+ TcpipRecursiveMutexLeave( &TCPLock );
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return Status;
+}
+
+
+/*
+ * 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)
+{
+ 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
+ * ARGUMENTS:
+ * Request = Pointer to TDI request structure for this request
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS FileCloseControlChannel(
+ PTDI_REQUEST Request)
+{
+ PCONTROL_CHANNEL ControlChannel = Request->Handle.ControlChannel;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ ExFreePool(ControlChannel);
+ Request->Handle.ControlChannel = NULL;
+
+ return Status;
+}
+
+/* EOF */