2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: tcpip/fileobjs.c
5 * PURPOSE: Routines for handling file objects
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
20 /* List of all address file objects managed by this driver */
21 LIST_ENTRY AddressFileListHead
;
22 KSPIN_LOCK AddressFileListLock
;
24 /* List of all connection endpoint file objects managed by this driver */
25 LIST_ENTRY ConnectionEndpointListHead
;
26 KSPIN_LOCK ConnectionEndpointListLock
;
32 * FUNCTION: Frees an address file object
34 * Object = Pointer to address file object to free
42 PADDRESS_FILE AddrFile
)
44 * FUNCTION: Deletes an address file object
46 * AddrFile = Pointer to address file object to delete
50 PLIST_ENTRY CurrentEntry
;
51 PLIST_ENTRY NextEntry
;
52 PDATAGRAM_SEND_REQUEST SendRequest
;
53 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
55 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
57 /* Remove address file from the global list */
58 KeAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
59 RemoveEntryList(&AddrFile
->ListEntry
);
60 KeReleaseSpinLock(&AddressFileListLock
, OldIrql
);
62 KeAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
64 /* FIXME: Kill TCP connections on this address file object */
66 /* Return pending requests with error */
68 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile
));
70 /* Go through pending receive request list and cancel them all */
71 CurrentEntry
= AddrFile
->ReceiveQueue
.Flink
;
72 while (CurrentEntry
!= &AddrFile
->ReceiveQueue
) {
73 NextEntry
= CurrentEntry
->Flink
;
74 ReceiveRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_RECEIVE_REQUEST
, ListEntry
);
75 /* Abort the request and free its resources */
76 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
77 (*ReceiveRequest
->Complete
)(ReceiveRequest
->Context
, STATUS_ADDRESS_CLOSED
, 0);
78 ExFreePool(ReceiveRequest
);
79 KeAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
80 CurrentEntry
= NextEntry
;
83 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting send requests on address file at (0x%X).\n", AddrFile
));
85 /* Go through pending send request list and cancel them all */
86 CurrentEntry
= AddrFile
->TransmitQueue
.Flink
;
87 while (CurrentEntry
!= &AddrFile
->TransmitQueue
) {
88 NextEntry
= CurrentEntry
->Flink
;
89 SendRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_SEND_REQUEST
, ListEntry
);
90 /* Abort the request and free its resources */
91 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
92 (*SendRequest
->Complete
)(SendRequest
->Context
, STATUS_ADDRESS_CLOSED
, 0);
93 ExFreePool(SendRequest
);
94 KeAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
95 CurrentEntry
= NextEntry
;
98 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
100 /* Dereference address entry */
101 DereferenceObject(AddrFile
->ADE
);
103 /* Dereference address cache */
104 if (AddrFile
->AddrCache
)
105 DereferenceObject(AddrFile
->AddrCache
);
108 /* Remove reference provided at creation time */
109 AddrFile
->RefCount
--;
111 if (AddrFile
->RefCount
!= 0)
112 TI_DbgPrint(DEBUG_REFCOUNT
, ("AddrFile->RefCount is (%d) (should be 0).\n", AddrFile
->RefCount
));
115 (*AddrFile
->Free
)(AddrFile
);
117 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
122 * FUNCTION: Deletes a connection endpoint file object
124 * Connection = Pointer to connection endpoint to delete
126 VOID
DeleteConnectionEndpoint(
127 PCONNECTION_ENDPOINT Connection
)
130 PLIST_ENTRY CurrentEntry
;
131 PLIST_ENTRY NextEntry
;
133 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
135 /* Remove connection endpoint from the global list */
136 KeAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
137 RemoveEntryList(&Connection
->ListEntry
);
138 KeReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
140 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
142 /* Dereference and remove the address file if it exists */
143 if (Connection
->AddressFile
) {
144 DereferenceObject(Connection
->AddressFile
);
147 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
150 /* Remove reference provided at creation time */
151 Connection
->RefCount
--;
153 if (Connection
->RefCount
!= 0)
154 TI_DbgPrint(DEBUG_REFCOUNT
, ("Connection->RefCount is (%d) (should be 0).\n",
155 Connection
->RefCount
));
158 ExFreePool(Connection
);
160 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
167 * FUNCTION: Worker routine for processing address file object requests
169 * Context = Pointer to context information (ADDRESS_FILE)
173 PLIST_ENTRY CurrentEntry
;
174 PADDRESS_FILE AddrFile
= Context
;
176 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
178 KeAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
180 /* Check it the address file should be deleted */
181 if (AF_IS_PENDING(AddrFile
, AFF_DELETE
)) {
182 DATAGRAM_COMPLETION_ROUTINE RtnComplete
;
185 RtnComplete
= AddrFile
->Complete
;
186 RtnContext
= AddrFile
->Context
;
188 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
190 DeleteAddress(AddrFile
);
192 (*RtnComplete
)(RtnContext
, TDI_SUCCESS
, 0);
194 TI_DbgPrint(MAX_TRACE
, ("Leaving (delete).\n"));
199 /* Check if there is a pending send request */
200 if (AF_IS_PENDING(AddrFile
, AFF_SEND
)) {
201 if (!IsListEmpty(&AddrFile
->TransmitQueue
)) {
202 PDATAGRAM_SEND_REQUEST SendRequest
;
204 CurrentEntry
= RemoveHeadList(&AddrFile
->TransmitQueue
);
205 SendRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_SEND_REQUEST
, ListEntry
);
207 AF_CLR_BUSY(AddrFile
);
209 ReferenceObject(AddrFile
);
211 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
213 /* The send routine processes the send requests in
214 the transmit queue on the address file. When the
215 queue is empty the pending send flag is cleared.
216 The routine may return with the pending send flag
217 set. This can happen if there was not enough free
218 resources available to complete all send requests */
219 DGSend(AddrFile
, SendRequest
);
221 KeAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
222 DereferenceObject(AddrFile
);
223 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
225 TI_DbgPrint(MAX_TRACE
, ("Leaving (send request).\n"));
229 /* There was a pending send, but no send request.
230 Print a debug message and continue */
231 TI_DbgPrint(MIN_TRACE
, ("Pending send, but no send request.\n"));
234 AF_CLR_BUSY(AddrFile
);
236 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
238 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
243 * FUNCTION: Open an address file object
245 * Request = Pointer to TDI request structure for this request
246 * Address = Pointer to address to be opened
247 * Protocol = Protocol on which to open the address
248 * Options = Pointer to option buffer
250 * Status of operation
252 NTSTATUS
FileOpenAddress(
253 PTDI_REQUEST Request
,
254 PTA_IP_ADDRESS Address
,
258 PADDRESS_FILE AddrFile
;
259 IPv4_RAW_ADDRESS IPv4Address
;
261 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
263 AddrFile
= ExAllocatePool(NonPagedPool
, sizeof(ADDRESS_FILE
));
265 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
266 return STATUS_INSUFFICIENT_RESOURCES
;
269 TI_DbgPrint(DEBUG_ADDRFILE
, ("Address file object allocated at (0x%X).\n", AddrFile
));
271 RtlZeroMemory(AddrFile
, sizeof(ADDRESS_FILE
));
273 AddrFile
->Free
= AddrFileFree
;
275 /* Make sure address is a local unicast address or 0 */
277 /* Locate address entry. If specified address is 0, a random address is chosen */
279 /* FIXME: IPv4 only */
280 IPv4Address
= Address
->Address
[0].Address
[0].in_addr
;
281 if (IPv4Address
== 0)
282 AddrFile
->ADE
= IPGetDefaultADE(ADE_UNICAST
);
284 AddrFile
->ADE
= AddrLocateADEv4(IPv4Address
);
286 if (!AddrFile
->ADE
) {
287 ExFreePool(AddrFile
);
288 TI_DbgPrint(MIN_TRACE
, ("Non-local address given (0x%X).\n", DN2H(IPv4Address
)));
289 return STATUS_INVALID_PARAMETER
;
292 TI_DbgPrint(MID_TRACE
, ("Opening address %s for communication.\n",
293 A2S(AddrFile
->ADE
->Address
)));
295 /* Protocol specific handling */
298 /* FIXME: If specified port is 0, a port is chosen dynamically */
299 AddrFile
->Port
= Address
->Address
[0].Address
[0].sin_port
;
300 AddrFile
->Send
= TCPSendDatagram
;
304 /* FIXME: If specified port is 0, a port is chosen dynamically */
305 AddrFile
->Port
= Address
->Address
[0].Address
[0].sin_port
;
306 AddrFile
->Send
= UDPSendDatagram
;
310 /* Use raw IP for all other protocols */
312 AddrFile
->Send
= RawIPSendDatagram
;
316 TI_DbgPrint(MID_TRACE
, ("IP protocol number for address file object is %d.\n",
319 TI_DbgPrint(MID_TRACE
, ("Port number for address file object is %d.\n",
320 WN2H(AddrFile
->Port
)));
323 AddrFile
->Protocol
= Protocol
;
325 /* Initialize receive and transmit queues */
326 InitializeListHead(&AddrFile
->ReceiveQueue
);
327 InitializeListHead(&AddrFile
->TransmitQueue
);
329 /* Initialize work queue item. We use this for pending requests */
330 ExInitializeWorkItem(&AddrFile
->WorkItem
, RequestWorker
, AddrFile
);
332 /* Initialize spin lock that protects the address file object */
333 KeInitializeSpinLock(&AddrFile
->Lock
);
335 /* Reference the object */
336 AddrFile
->RefCount
= 1;
338 /* Set valid flag so the address can be used */
339 AF_SET_VALID(AddrFile
);
341 /* Return address file object */
342 Request
->Handle
.AddressHandle
= AddrFile
;
344 /* Add address file to global list */
345 ExInterlockedInsertTailList(
346 &AddressFileListHead
,
347 &AddrFile
->ListEntry
,
348 &AddressFileListLock
);
350 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
352 return STATUS_SUCCESS
;
357 * FUNCTION: Closes an address file object
359 * Request = Pointer to TDI request structure for this request
361 * Status of operation
363 NTSTATUS
FileCloseAddress(
364 PTDI_REQUEST Request
)
367 PADDRESS_FILE AddrFile
;
368 NTSTATUS Status
= STATUS_SUCCESS
;
370 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
372 AddrFile
= Request
->Handle
.AddressHandle
;
374 KeAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
376 if ((!AF_IS_BUSY(AddrFile
)) && (AddrFile
->RefCount
== 1)) {
377 /* Set address file object exclusive to us */
378 AF_SET_BUSY(AddrFile
);
379 AF_CLR_VALID(AddrFile
);
381 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
383 DeleteAddress(AddrFile
);
385 if (!AF_IS_PENDING(AddrFile
, AFF_DELETE
)) {
386 AddrFile
->Complete
= Request
->RequestNotifyObject
;
387 AddrFile
->Context
= Request
->RequestContext
;
389 /* Shedule address file for deletion */
390 AF_SET_PENDING(AddrFile
, AFF_DELETE
);
391 AF_CLR_VALID(AddrFile
);
393 if (!AF_IS_BUSY(AddrFile
)) {
394 /* Worker function is not running, so shedule it to run */
395 AF_SET_BUSY(AddrFile
);
396 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
397 ExQueueWorkItem(&AddrFile
->WorkItem
, CriticalWorkQueue
);
399 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
401 TI_DbgPrint(MAX_TRACE
, ("Leaving (pending).\n"));
403 return STATUS_PENDING
;
405 Status
= STATUS_ADDRESS_CLOSED
;
407 KeReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
410 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
417 * FUNCTION: Opens a connection file object
419 * Request = Pointer to TDI request structure for this request
420 * ClientContext = Pointer to client context information
422 * Status of operation
424 NTSTATUS
FileOpenConnection(
425 PTDI_REQUEST Request
,
428 PCONNECTION_ENDPOINT Connection
;
430 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
432 Connection
= ExAllocatePool(NonPagedPool
, sizeof(CONNECTION_ENDPOINT
));
434 return STATUS_INSUFFICIENT_RESOURCES
;
436 TI_DbgPrint(DEBUG_CPOINT
, ("Connection point file object allocated at (0x%X).\n", Connection
));
438 RtlZeroMemory(Connection
, sizeof(CONNECTION_ENDPOINT
));
440 /* Initialize spin lock that protects the connection endpoint file object */
441 KeInitializeSpinLock(&Connection
->Lock
);
443 /* Reference the object */
444 Connection
->RefCount
= 1;
446 /* Put connection in the closed state */
447 Connection
->State
= ctClosed
;
449 /* Save client context pointer */
450 Connection
->ClientContext
= ClientContext
;
452 /* Return connection endpoint file object */
453 Request
->Handle
.ConnectionContext
= Connection
;
455 /* Add connection endpoint to global list */
456 ExInterlockedInsertTailList(
457 &ConnectionEndpointListHead
,
458 &Connection
->ListEntry
,
459 &ConnectionEndpointListLock
);
461 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
463 return STATUS_SUCCESS
;
468 * FUNCTION: Closes an connection file object
470 * Request = Pointer to TDI request structure for this request
472 * Status of operation
474 NTSTATUS
FileCloseConnection(
475 PTDI_REQUEST Request
)
478 PCONNECTION_ENDPOINT Connection
;
479 NTSTATUS Status
= STATUS_SUCCESS
;
481 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
483 Connection
= Request
->Handle
.ConnectionContext
;
486 KeAcquireSpinLock(&Connection
->Lock
, &OldIrql
);
487 if ((!AF_IS_BUSY(Connection
)) && (Connection
->RefCount
== 1)) {
488 /* Set connection endpoint file object exclusive to us */
489 AF_SET_BUSY(Connection
);
490 AF_CLR_VALID(Connection
);
492 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
494 DeleteConnectionEndpoint(Connection
);
497 if (!AF_IS_PENDING(Connection
, AFF_DELETE
)) {
498 Connection
->Complete
= Request
->RequestNotifyObject
;
499 Connection
->Context
= Request
->RequestContext
;
501 /* Shedule connection endpoint for deletion */
502 AF_SET_PENDING(Connection
, AFF_DELETE
);
503 AF_CLR_VALID(Connection
);
505 if (!AF_IS_BUSY(Connection
)) {
506 /* Worker function is not running, so shedule it to run */
507 AF_SET_BUSY(Connection
);
508 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
509 ExQueueWorkItem(&Connection
->WorkItem
, CriticalWorkQueue
);
511 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
513 TI_DbgPrint(MAX_TRACE
, ("Leaving (pending).\n"));
515 return STATUS_PENDING
;
517 Status
= STATUS_ADDRESS_CLOSED
;
519 KeReleaseSpinLock(&Connection
->Lock
, OldIrql
);
522 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
529 * FUNCTION: Opens a control channel file object
531 * Request = Pointer to TDI request structure for this request
533 * Status of operation
535 NTSTATUS
FileOpenControlChannel(
536 PTDI_REQUEST Request
)
538 return STATUS_NOT_IMPLEMENTED
;
543 * FUNCTION: Closes a control channel file object
545 * Request = Pointer to TDI request structure for this request
547 * Status of operation
549 NTSTATUS
FileCloseControlChannel(
550 PTDI_REQUEST Request
)
552 return STATUS_NOT_IMPLEMENTED
;