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
14 /* List of all address file objects managed by this driver */
15 LIST_ENTRY AddressFileListHead
;
16 KSPIN_LOCK AddressFileListLock
;
18 /* List of all connection endpoint file objects managed by this driver */
19 LIST_ENTRY ConnectionEndpointListHead
;
20 KSPIN_LOCK ConnectionEndpointListLock
;
23 * FUNCTION: Searches through address file entries to find the first match
25 * Address = IP address
27 * Protocol = Protocol number
28 * SearchContext = Pointer to search context
30 * Pointer to address file, NULL if none was found
32 PADDRESS_FILE
AddrSearchFirst(
36 PAF_SEARCH SearchContext
)
38 SearchContext
->Address
= Address
;
39 SearchContext
->Port
= Port
;
40 SearchContext
->Next
= AddressFileListHead
.Flink
;
41 SearchContext
->Protocol
= Protocol
;
43 return AddrSearchNext(SearchContext
);
47 * FUNCTION: Searches through address file entries to find next match
49 * SearchContext = Pointer to search context
51 * Pointer to address file, NULL if none was found
53 PADDRESS_FILE
AddrSearchNext(
54 PAF_SEARCH SearchContext
)
56 PLIST_ENTRY CurrentEntry
;
57 PIP_ADDRESS IPAddress
;
59 PADDRESS_FILE Current
= NULL
;
60 BOOLEAN Found
= FALSE
;
62 if (IsListEmpty(SearchContext
->Next
))
65 CurrentEntry
= SearchContext
->Next
;
67 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
69 while (CurrentEntry
!= &AddressFileListHead
) {
70 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_FILE
, ListEntry
);
72 IPAddress
= Current
->ADE
->Address
;
74 TI_DbgPrint(DEBUG_ADDRFILE
, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
78 WN2H(SearchContext
->Port
),
79 SearchContext
->Protocol
,
80 A2S(SearchContext
->Address
)));
82 /* See if this address matches the search criteria */
83 if (((Current
->Port
== SearchContext
->Port
) &&
84 (Current
->Protocol
== SearchContext
->Protocol
) &&
85 (AddrIsEqual(IPAddress
, SearchContext
->Address
))) ||
86 (AddrIsUnspecified(IPAddress
))) {
87 /* We've found a match */
91 CurrentEntry
= CurrentEntry
->Flink
;
94 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
97 SearchContext
->Next
= CurrentEntry
->Flink
;
106 * FUNCTION: Frees an address file object
108 * Object = Pointer to address file object to free
115 VOID
ControlChannelFree(
118 * FUNCTION: Frees an address file object
120 * Object = Pointer to address file object to free
127 VOID
DeleteAddress(PADDRESS_FILE AddrFile
)
129 * FUNCTION: Deletes an address file object
131 * AddrFile = Pointer to address file object to delete
135 PLIST_ENTRY CurrentEntry
;
136 PLIST_ENTRY NextEntry
;
137 PDATAGRAM_SEND_REQUEST SendRequest
;
138 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
140 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
142 /* Remove address file from the global list */
143 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
144 RemoveEntryList(&AddrFile
->ListEntry
);
145 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
147 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
149 /* FIXME: Kill TCP connections on this address file object */
151 /* Return pending requests with error */
153 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile
));
155 /* Go through pending receive request list and cancel them all */
156 CurrentEntry
= AddrFile
->ReceiveQueue
.Flink
;
157 while (CurrentEntry
!= &AddrFile
->ReceiveQueue
) {
158 NextEntry
= CurrentEntry
->Flink
;
159 ReceiveRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_RECEIVE_REQUEST
, ListEntry
);
160 /* Abort the request and free its resources */
161 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
162 (*ReceiveRequest
->Complete
)(ReceiveRequest
->Context
, STATUS_ADDRESS_CLOSED
, 0);
163 ExFreePool(ReceiveRequest
);
164 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
165 CurrentEntry
= NextEntry
;
168 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting send requests on address file at (0x%X).\n", AddrFile
));
170 /* Go through pending send request list and cancel them all */
171 CurrentEntry
= AddrFile
->TransmitQueue
.Flink
;
172 while (CurrentEntry
!= &AddrFile
->TransmitQueue
) {
173 NextEntry
= CurrentEntry
->Flink
;
174 SendRequest
= CONTAINING_RECORD(CurrentEntry
,
175 DATAGRAM_SEND_REQUEST
, ListEntry
);
176 /* Abort the request and free its resources */
177 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
178 (*SendRequest
->Complete
)(SendRequest
->Context
, STATUS_ADDRESS_CLOSED
, 0);
179 ExFreePool(SendRequest
);
180 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
181 CurrentEntry
= NextEntry
;
184 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
186 (*AddrFile
->Free
)(AddrFile
);
188 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
193 * FUNCTION: Deletes a connection endpoint file object
195 * Connection = Pointer to connection endpoint to delete
197 VOID
DeleteConnectionEndpoint(
198 PCONNECTION_ENDPOINT Connection
)
202 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
204 /* Remove connection endpoint from the global list */
205 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
206 RemoveEntryList(&Connection
->ListEntry
);
207 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
209 ExFreePool(Connection
);
211 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
215 VOID STDCALL
RequestWorker(PVOID Context
)
217 * FUNCTION: Worker routine for processing address file object requests
219 * Context = Pointer to context information (ADDRESS_FILE)
223 PLIST_ENTRY CurrentEntry
;
224 PADDRESS_FILE AddrFile
= Context
;
226 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
228 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
230 /* Check it the address file should be deleted */
231 if (AF_IS_PENDING(AddrFile
, AFF_DELETE
)) {
232 DATAGRAM_COMPLETION_ROUTINE RtnComplete
;
235 RtnComplete
= AddrFile
->Complete
;
236 RtnContext
= AddrFile
->Context
;
238 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
240 DeleteAddress(AddrFile
);
242 (*RtnComplete
)(RtnContext
, TDI_SUCCESS
, 0);
244 TI_DbgPrint(MAX_TRACE
, ("Leaving (delete).\n"));
249 /* Check if there is a pending send request */
250 if (AF_IS_PENDING(AddrFile
, AFF_SEND
)) {
251 if (!IsListEmpty(&AddrFile
->TransmitQueue
)) {
252 PDATAGRAM_SEND_REQUEST SendRequest
;
254 CurrentEntry
= RemoveHeadList(&AddrFile
->TransmitQueue
);
255 SendRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_SEND_REQUEST
, ListEntry
);
257 AF_CLR_BUSY(AddrFile
);
259 ReferenceObject(AddrFile
);
261 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
263 /* The send routine processes the send requests in
264 the transmit queue on the address file. When the
265 queue is empty the pending send flag is cleared.
266 The routine may return with the pending send flag
267 set. This can happen if there was not enough free
268 resources available to complete all send requests */
269 DGSend(AddrFile
, SendRequest
);
271 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
272 DereferenceObject(AddrFile
);
273 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
275 TI_DbgPrint(MAX_TRACE
, ("Leaving (send request).\n"));
279 /* There was a pending send, but no send request.
280 Print a debug message and continue */
281 TI_DbgPrint(MIN_TRACE
, ("Pending send, but no send request.\n"));
284 AF_CLR_BUSY(AddrFile
);
286 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
288 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
293 * FUNCTION: Open an address file object
295 * Request = Pointer to TDI request structure for this request
296 * Address = Pointer to address to be opened
297 * Protocol = Protocol on which to open the address
298 * Options = Pointer to option buffer
300 * Status of operation
302 NTSTATUS
FileOpenAddress(
303 PTDI_REQUEST Request
,
304 PTA_IP_ADDRESS Address
,
308 PADDRESS_FILE AddrFile
;
309 IPv4_RAW_ADDRESS IPv4Address
;
311 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
313 AddrFile
= ExAllocatePool(NonPagedPool
, sizeof(ADDRESS_FILE
));
315 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
316 return STATUS_INSUFFICIENT_RESOURCES
;
319 TI_DbgPrint(DEBUG_ADDRFILE
, ("Address file object allocated at (0x%X).\n", AddrFile
));
321 RtlZeroMemory(AddrFile
, sizeof(ADDRESS_FILE
));
323 AddrFile
->Free
= AddrFileFree
;
325 /* Make sure address is a local unicast address or 0 */
327 /* Locate address entry. If specified address is 0, a random address is chosen */
329 /* FIXME: IPv4 only */
330 IPv4Address
= Address
->Address
[0].Address
[0].in_addr
;
331 if (IPv4Address
== 0)
332 AddrFile
->ADE
= IPGetDefaultADE(ADE_UNICAST
);
334 AddrFile
->ADE
= AddrLocateADEv4(IPv4Address
);
336 if (!AddrFile
->ADE
) {
337 ExFreePool(AddrFile
);
338 TI_DbgPrint(MIN_TRACE
, ("Non-local address given (0x%X).\n", DN2H(IPv4Address
)));
339 return STATUS_INVALID_PARAMETER
;
342 TI_DbgPrint(MID_TRACE
, ("Opening address %s for communication.\n",
343 A2S(AddrFile
->ADE
->Address
)));
345 /* Protocol specific handling */
348 /* FIXME: If specified port is 0, a port is chosen dynamically */
349 AddrFile
->Port
= Address
->Address
[0].Address
[0].sin_port
;
350 AddrFile
->Send
= NULL
; /* TCPSendData */
354 /* FIXME: If specified port is 0, a port is chosen dynamically */
355 AddrFile
->Port
= Address
->Address
[0].Address
[0].sin_port
;
356 AddrFile
->Send
= UDPSendDatagram
;
360 /* Use raw IP for all other protocols */
362 AddrFile
->Send
= RawIPSendDatagram
;
366 TI_DbgPrint(MID_TRACE
, ("IP protocol number for address file object is %d.\n",
369 TI_DbgPrint(MID_TRACE
, ("Port number for address file object is %d.\n",
370 WN2H(AddrFile
->Port
)));
373 AddrFile
->Protocol
= Protocol
;
375 /* Initialize receive and transmit queues */
376 InitializeListHead(&AddrFile
->ReceiveQueue
);
377 InitializeListHead(&AddrFile
->TransmitQueue
);
379 /* Initialize work queue item. We use this for pending requests */
380 /*ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile);*/
382 /* Initialize spin lock that protects the address file object */
383 KeInitializeSpinLock(&AddrFile
->Lock
);
385 /* Set valid flag so the address can be used */
386 AF_SET_VALID(AddrFile
);
388 /* Return address file object */
389 Request
->Handle
.AddressHandle
= AddrFile
;
391 /* Add address file to global list */
392 ExInterlockedInsertTailList(
393 &AddressFileListHead
,
394 &AddrFile
->ListEntry
,
395 &AddressFileListLock
);
397 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
399 return STATUS_SUCCESS
;
404 * FUNCTION: Closes an address file object
406 * Request = Pointer to TDI request structure for this request
408 * Status of operation
410 NTSTATUS
FileCloseAddress(
411 PTDI_REQUEST Request
)
414 PADDRESS_FILE AddrFile
;
415 NTSTATUS Status
= STATUS_SUCCESS
;
417 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
419 AddrFile
= Request
->Handle
.AddressHandle
;
421 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
423 if (!AF_IS_BUSY(AddrFile
)) {
424 /* Set address file object exclusive to us */
425 AF_SET_BUSY(AddrFile
);
426 AF_CLR_VALID(AddrFile
);
428 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
430 DeleteAddress(AddrFile
);
432 if (!AF_IS_PENDING(AddrFile
, AFF_DELETE
)) {
433 AddrFile
->Complete
= Request
->RequestNotifyObject
;
434 AddrFile
->Context
= Request
->RequestContext
;
436 /* Shedule address file for deletion */
437 AF_SET_PENDING(AddrFile
, AFF_DELETE
);
438 AF_CLR_VALID(AddrFile
);
440 if (!AF_IS_BUSY(AddrFile
)) {
441 /* Worker function is not running, so shedule it to run */
442 AF_SET_BUSY(AddrFile
);
443 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
444 ExQueueWorkItem(&AddrFile
->WorkItem
, CriticalWorkQueue
);
446 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
448 TI_DbgPrint(MAX_TRACE
, ("Leaving (pending).\n"));
450 return STATUS_PENDING
;
452 Status
= STATUS_ADDRESS_CLOSED
;
454 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
457 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
464 * FUNCTION: Opens a connection file object
466 * Request = Pointer to TDI request structure for this request
467 * ClientContext = Pointer to client context information
469 * Status of operation
471 NTSTATUS
FileOpenConnection(
472 PTDI_REQUEST Request
,
476 PCONNECTION_ENDPOINT Connection
;
478 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
480 Connection
= TCPAllocateConnectionEndpoint( ClientContext
);
482 if( !Connection
) return STATUS_NO_MEMORY
;
484 Status
= TCPSocket( Connection
, AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
485 DbgPrint("STATUS from OSKITTCP was %08x\n", Status
);
487 /* Initialize received segments queue */
488 InitializeListHead(&Connection
->ReceivedSegments
);
490 TI_DbgPrint(MIN_TRACE
, ("X1 cur 0x%x\n", &Connection
->ReceivedSegments
));
491 TI_DbgPrint(MIN_TRACE
, ("X1 Flink 0x%x\n", Connection
->ReceivedSegments
.Flink
));
492 TI_DbgPrint(MIN_TRACE
, ("X1 Blink 0x%x\n", Connection
->ReceivedSegments
.Blink
));
495 /* Return connection endpoint file object */
496 Request
->Handle
.ConnectionContext
= Connection
;
498 /* Add connection endpoint to global list */
499 ExInterlockedInsertTailList(
500 &ConnectionEndpointListHead
,
501 &Connection
->ListEntry
,
502 &ConnectionEndpointListLock
);
504 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
506 return STATUS_SUCCESS
;
511 * FUNCTION: Closes an connection file object
513 * Request = Pointer to TDI request structure for this request
515 * Status of operation
517 NTSTATUS
FileCloseConnection(
518 PTDI_REQUEST Request
)
520 PCONNECTION_ENDPOINT Connection
;
521 NTSTATUS Status
= STATUS_SUCCESS
;
523 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
525 Connection
= Request
->Handle
.ConnectionContext
;
527 TCPClose(Connection
);
528 DeleteConnectionEndpoint(Connection
);
530 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
537 * FUNCTION: Opens a control channel file object
539 * Request = Pointer to TDI request structure for this request
541 * Status of operation
543 NTSTATUS
FileOpenControlChannel(
544 PTDI_REQUEST Request
)
546 PCONTROL_CHANNEL ControlChannel
;
547 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
549 ControlChannel
= ExAllocatePool(NonPagedPool
, sizeof(*ControlChannel
));
551 if (!ControlChannel
) {
552 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
553 return STATUS_INSUFFICIENT_RESOURCES
;
556 RtlZeroMemory(ControlChannel
, sizeof(CONTROL_CHANNEL
));
558 /* Make sure address is a local unicast address or 0 */
560 /* Locate address entry. If specified address is 0, a random address is chosen */
562 /* Initialize receive and transmit queues */
563 InitializeListHead(&ControlChannel
->ListEntry
);
565 /* Initialize spin lock that protects the address file object */
566 KeInitializeSpinLock(&ControlChannel
->Lock
);
568 /* Return address file object */
569 Request
->Handle
.ControlChannel
= ControlChannel
;
571 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
573 return STATUS_SUCCESS
;
578 * FUNCTION: Closes a control channel file object
580 * Request = Pointer to TDI request structure for this request
582 * Status of operation
584 NTSTATUS
FileCloseControlChannel(
585 PTDI_REQUEST Request
)
587 PCONTROL_CHANNEL ControlChannel
= Request
->Handle
.ControlChannel
;
588 NTSTATUS Status
= STATUS_SUCCESS
;
590 ExFreePool(ControlChannel
);
591 Request
->Handle
.ControlChannel
= NULL
;