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
13 /* List of all address file objects managed by this driver */
14 LIST_ENTRY AddressFileListHead
;
15 KSPIN_LOCK AddressFileListLock
;
17 /* List of all connection endpoint file objects managed by this driver */
18 LIST_ENTRY ConnectionEndpointListHead
;
19 KSPIN_LOCK ConnectionEndpointListLock
;
22 * FUNCTION: Searches through address file entries to find the first match
24 * Address = IP address
26 * Protocol = Protocol number
27 * SearchContext = Pointer to search context
29 * Pointer to address file, NULL if none was found
31 PADDRESS_FILE
AddrSearchFirst(
35 PAF_SEARCH SearchContext
)
37 SearchContext
->Address
= Address
;
38 SearchContext
->Port
= Port
;
39 SearchContext
->Next
= AddressFileListHead
.Flink
;
40 SearchContext
->Protocol
= Protocol
;
42 return AddrSearchNext(SearchContext
);
45 BOOLEAN
AddrIsBroadcast(
46 PIP_ADDRESS PossibleMatch
,
47 PIP_ADDRESS TargetAddress
) {
50 ForEachInterface(IF
) {
51 if( AddrIsEqual( &IF
->Unicast
, PossibleMatch
) &&
52 AddrIsEqual( &IF
->Broadcast
, TargetAddress
) )
60 * FUNCTION: Searches through address file entries to find next match
62 * SearchContext = Pointer to search context
64 * Pointer to address file, NULL if none was found
66 PADDRESS_FILE
AddrSearchNext(
67 PAF_SEARCH SearchContext
)
69 PLIST_ENTRY CurrentEntry
;
70 PIP_ADDRESS IPAddress
;
72 PADDRESS_FILE Current
= NULL
;
73 BOOLEAN Found
= FALSE
;
75 if (IsListEmpty(SearchContext
->Next
))
78 CurrentEntry
= SearchContext
->Next
;
80 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
82 while (CurrentEntry
!= &AddressFileListHead
) {
83 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_FILE
, ListEntry
);
85 IPAddress
= &Current
->Address
;
87 TI_DbgPrint(DEBUG_ADDRFILE
, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
91 WN2H(SearchContext
->Port
),
92 SearchContext
->Protocol
,
93 A2S(SearchContext
->Address
)));
95 /* See if this address matches the search criteria */
96 if ((Current
->Port
== SearchContext
->Port
) &&
97 (Current
->Protocol
== SearchContext
->Protocol
) &&
98 (AddrIsEqual(IPAddress
, SearchContext
->Address
) ||
99 AddrIsBroadcast(IPAddress
, SearchContext
->Address
) ||
100 AddrIsUnspecified(IPAddress
))) {
101 /* We've found a match */
105 CurrentEntry
= CurrentEntry
->Flink
;
108 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
111 SearchContext
->Next
= CurrentEntry
->Flink
;
120 * FUNCTION: Frees an address file object
122 * Object = Pointer to address file object to free
129 VOID
ControlChannelFree(
132 * FUNCTION: Frees an address file object
134 * Object = Pointer to address file object to free
141 VOID
DeleteAddress(PADDRESS_FILE AddrFile
)
143 * FUNCTION: Deletes an address file object
145 * AddrFile = Pointer to address file object to delete
149 PLIST_ENTRY CurrentEntry
;
150 PLIST_ENTRY NextEntry
;
151 PDATAGRAM_SEND_REQUEST SendRequest
;
152 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
154 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
156 /* Remove address file from the global list */
157 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
158 RemoveEntryList(&AddrFile
->ListEntry
);
159 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
161 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
163 /* FIXME: Kill TCP connections on this address file object */
165 /* Return pending requests with error */
167 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile
));
169 /* Go through pending receive request list and cancel them all */
170 CurrentEntry
= AddrFile
->ReceiveQueue
.Flink
;
171 while (CurrentEntry
!= &AddrFile
->ReceiveQueue
) {
172 NextEntry
= CurrentEntry
->Flink
;
173 ReceiveRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_RECEIVE_REQUEST
, ListEntry
);
174 /* Abort the request and free its resources */
175 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
176 (*ReceiveRequest
->Complete
)(ReceiveRequest
->Context
, STATUS_ADDRESS_CLOSED
, 0);
177 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
178 CurrentEntry
= NextEntry
;
181 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting send requests on address file at (0x%X).\n", AddrFile
));
183 /* Go through pending send request list and cancel them all */
184 CurrentEntry
= AddrFile
->TransmitQueue
.Flink
;
185 while (CurrentEntry
!= &AddrFile
->TransmitQueue
) {
186 NextEntry
= CurrentEntry
->Flink
;
187 SendRequest
= CONTAINING_RECORD(CurrentEntry
,
188 DATAGRAM_SEND_REQUEST
, ListEntry
);
189 /* Abort the request and free its resources */
190 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
191 (*SendRequest
->Complete
)(SendRequest
->Context
, STATUS_ADDRESS_CLOSED
, 0);
192 ExFreePool(SendRequest
);
193 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
194 CurrentEntry
= NextEntry
;
197 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
199 (*AddrFile
->Free
)(AddrFile
);
201 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
206 * FUNCTION: Deletes a connection endpoint file object
208 * Connection = Pointer to connection endpoint to delete
210 VOID
DeleteConnectionEndpoint(
211 PCONNECTION_ENDPOINT Connection
)
215 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
217 /* Remove connection endpoint from the global list */
218 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
219 RemoveEntryList(&Connection
->ListEntry
);
220 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
222 ExFreePool(Connection
);
224 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
228 * FUNCTION: Open an address file object
230 * Request = Pointer to TDI request structure for this request
231 * Address = Pointer to address to be opened
232 * Protocol = Protocol on which to open the address
233 * Options = Pointer to option buffer
235 * Status of operation
237 NTSTATUS
FileOpenAddress(
238 PTDI_REQUEST Request
,
239 PTA_IP_ADDRESS Address
,
243 IPv4_RAW_ADDRESS IPv4Address
;
245 PADDRESS_FILE AddrFile
;
247 TI_DbgPrint(MID_TRACE
, ("Called (Proto %d).\n", Protocol
));
249 AddrFile
= ExAllocatePool(NonPagedPool
, sizeof(ADDRESS_FILE
));
251 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
252 return STATUS_INSUFFICIENT_RESOURCES
;
255 TI_DbgPrint(DEBUG_ADDRFILE
, ("Address file object allocated at (0x%X).\n", AddrFile
));
257 RtlZeroMemory(AddrFile
, sizeof(ADDRESS_FILE
));
259 AddrFile
->Free
= AddrFileFree
;
261 /* Make sure address is a local unicast address or 0 */
263 /* Locate address entry. If specified address is 0, a random address is chosen */
265 /* FIXME: IPv4 only */
266 AddrFile
->Family
= Address
->Address
[0].AddressType
;
267 IPv4Address
= Address
->Address
[0].Address
[0].in_addr
;
268 if (IPv4Address
== 0)
269 Matched
= IPGetDefaultAddress(&AddrFile
->Address
);
271 Matched
= AddrLocateADEv4(IPv4Address
, &AddrFile
->Address
);
274 ExFreePool(AddrFile
);
275 TI_DbgPrint(MIN_TRACE
, ("Non-local address given (0x%X).\n", DN2H(IPv4Address
)));
276 return STATUS_INVALID_PARAMETER
;
279 TI_DbgPrint(MID_TRACE
, ("Opening address %s for communication (P=%d U=%d).\n",
280 A2S(&AddrFile
->Address
), Protocol
, IPPROTO_UDP
));
282 /* Protocol specific handling */
286 TCPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
287 AddrFile
->Send
= NULL
; /* TCPSendData */
291 TI_DbgPrint(MID_TRACE
,("Allocating udp port\n"));
293 UDPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
294 TI_DbgPrint(MID_TRACE
,("Setting port %d (wanted %d)\n",
296 Address
->Address
[0].Address
[0].sin_port
));
297 AddrFile
->Send
= UDPSendDatagram
;
301 /* Use raw IP for all other protocols */
303 AddrFile
->Send
= RawIPSendDatagram
;
307 TI_DbgPrint(MID_TRACE
, ("IP protocol number for address file object is %d.\n",
310 TI_DbgPrint(MID_TRACE
, ("Port number for address file object is %d.\n",
311 WN2H(AddrFile
->Port
)));
314 AddrFile
->Protocol
= Protocol
;
316 /* Initialize receive and transmit queues */
317 InitializeListHead(&AddrFile
->ReceiveQueue
);
318 InitializeListHead(&AddrFile
->TransmitQueue
);
320 /* Initialize spin lock that protects the address file object */
321 KeInitializeSpinLock(&AddrFile
->Lock
);
323 /* Set valid flag so the address can be used */
324 AF_SET_VALID(AddrFile
);
326 /* Return address file object */
327 Request
->Handle
.AddressHandle
= AddrFile
;
329 /* Add address file to global list */
330 ExInterlockedInsertTailList(
331 &AddressFileListHead
,
332 &AddrFile
->ListEntry
,
333 &AddressFileListLock
);
335 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
337 return STATUS_SUCCESS
;
342 * FUNCTION: Closes an address file object
344 * Request = Pointer to TDI request structure for this request
346 * Status of operation
348 NTSTATUS
FileCloseAddress(
349 PTDI_REQUEST Request
)
352 PADDRESS_FILE AddrFile
;
353 NTSTATUS Status
= STATUS_SUCCESS
;
354 PCANCEL_REQUEST CancelReq
;
356 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
358 AddrFile
= Request
->Handle
.AddressHandle
;
360 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
362 /* Set address file object exclusive to us */
363 AF_SET_BUSY(AddrFile
);
364 AF_CLR_VALID(AddrFile
);
366 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
368 /* Protocol specific handling */
369 switch (AddrFile
->Protocol
) {
371 TCPFreePort( AddrFile
->Port
);
372 if( AddrFile
->Listener
) {
373 CancelReq
= ExAllocatePoolWithTag
374 ( sizeof(CANCEL_REQUEST
), NonPagedPool
, FOURCC('T','c','l','s') );
376 CancelReq
->Type
= TCP_CANCEL_CLOSE
;
377 CancelReq
->Context
= AddrFile
->Listener
;
378 AddrFile
->Listener
= NULL
;
379 ExQueueWorkItem( &CancelQueueWork
, CriticalWorkQueue
);
385 UDPFreePort( AddrFile
->Port
);
389 DeleteAddress(AddrFile
);
391 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
398 * FUNCTION: Opens a connection file object
400 * Request = Pointer to TDI request structure for this request
401 * ClientContext = Pointer to client context information
403 * Status of operation
405 NTSTATUS
FileOpenConnection(
406 PTDI_REQUEST Request
,
410 PCONNECTION_ENDPOINT Connection
;
412 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
414 Connection
= TCPAllocateConnectionEndpoint( ClientContext
);
416 if( !Connection
) return STATUS_NO_MEMORY
;
418 Status
= TCPSocket( Connection
, AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
420 /* Return connection endpoint file object */
421 Request
->Handle
.ConnectionContext
= Connection
;
423 /* Add connection endpoint to global list */
424 ExInterlockedInsertTailList(
425 &ConnectionEndpointListHead
,
426 &Connection
->ListEntry
,
427 &ConnectionEndpointListLock
);
429 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
431 return STATUS_SUCCESS
;
436 * FUNCTION: Find a connection by examining the context field. This
437 * is needed in some situations where a FIN reply is needed after a
438 * socket is formally broken.
440 * Request = Pointer to TDI request structure for this request
442 * Status of operation
444 PCONNECTION_ENDPOINT
FileFindConnectionByContext( PVOID Context
) {
447 PCONNECTION_ENDPOINT Connection
= NULL
;
449 TcpipAcquireSpinLock( &ConnectionEndpointListLock
, &OldIrql
);
451 for( Entry
= ConnectionEndpointListHead
.Flink
;
452 Entry
!= &ConnectionEndpointListHead
;
453 Entry
= Entry
->Flink
) {
455 CONTAINING_RECORD( Entry
, CONNECTION_ENDPOINT
, ListEntry
);
456 if( Connection
->SocketContext
== Context
) break;
457 else Connection
= NULL
;
460 TcpipReleaseSpinLock( &ConnectionEndpointListLock
, OldIrql
);
466 * FUNCTION: Closes an connection file object
468 * Request = Pointer to TDI request structure for this request
470 * Status of operation
472 NTSTATUS
FileCloseConnection(
473 PTDI_REQUEST Request
)
475 PCONNECTION_ENDPOINT Connection
;
476 NTSTATUS Status
= STATUS_SUCCESS
;
477 PCANCEL_REQUEST CancelReq
;
479 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
481 Connection
= Request
->Handle
.ConnectionContext
;
483 CancelReq
= ExAllocatePoolWithTag
484 ( sizeof(CANCEL_REQUEST
), NonPagedPool
, FOURCC('T','c','l','s') );
486 CancelReq
->Type
= TCP_CANCEL_CLOSE
;
487 CancelReq
->Context
= Connection
;
488 ExQueueWorkItem( &CancelQueueWork
, CriticalWorkQueue
);
491 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
498 * FUNCTION: Opens a control channel file object
500 * Request = Pointer to TDI request structure for this request
502 * Status of operation
504 NTSTATUS
FileOpenControlChannel(
505 PTDI_REQUEST Request
)
507 PCONTROL_CHANNEL ControlChannel
;
508 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
510 ControlChannel
= ExAllocatePool(NonPagedPool
, sizeof(*ControlChannel
));
512 if (!ControlChannel
) {
513 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
514 return STATUS_INSUFFICIENT_RESOURCES
;
517 RtlZeroMemory(ControlChannel
, sizeof(CONTROL_CHANNEL
));
519 /* Make sure address is a local unicast address or 0 */
521 /* Locate address entry. If specified address is 0, a random address is chosen */
523 /* Initialize receive and transmit queues */
524 InitializeListHead(&ControlChannel
->ListEntry
);
526 /* Initialize spin lock that protects the address file object */
527 KeInitializeSpinLock(&ControlChannel
->Lock
);
529 /* Return address file object */
530 Request
->Handle
.ControlChannel
= ControlChannel
;
532 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
534 return STATUS_SUCCESS
;
538 * FUNCTION: Closes a control channel file object
540 * Request = Pointer to TDI request structure for this request
542 * Status of operation
544 NTSTATUS
FileCloseControlChannel(
545 PTDI_REQUEST Request
)
547 PCONTROL_CHANNEL ControlChannel
= Request
->Handle
.ControlChannel
;
548 NTSTATUS Status
= STATUS_SUCCESS
;
550 ExFreePool(ControlChannel
);
551 Request
->Handle
.ControlChannel
= NULL
;