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
);
46 BOOLEAN
AddrIsBroadcast(
47 PIP_ADDRESS PossibleMatch
,
48 PIP_ADDRESS TargetAddress
) {
51 ForEachInterface(IF
) {
52 if( AddrIsEqual( &IF
->Unicast
, PossibleMatch
) &&
53 AddrIsEqual( &IF
->Broadcast
, TargetAddress
) )
61 * FUNCTION: Searches through address file entries to find next match
63 * SearchContext = Pointer to search context
65 * Pointer to address file, NULL if none was found
67 PADDRESS_FILE
AddrSearchNext(
68 PAF_SEARCH SearchContext
)
70 PLIST_ENTRY CurrentEntry
;
71 PIP_ADDRESS IPAddress
;
73 PADDRESS_FILE Current
= NULL
;
74 BOOLEAN Found
= FALSE
;
76 if (IsListEmpty(SearchContext
->Next
))
79 CurrentEntry
= SearchContext
->Next
;
81 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
83 while (CurrentEntry
!= &AddressFileListHead
) {
84 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_FILE
, ListEntry
);
86 IPAddress
= &Current
->Address
;
88 TI_DbgPrint(DEBUG_ADDRFILE
, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
92 WN2H(SearchContext
->Port
),
93 SearchContext
->Protocol
,
94 A2S(SearchContext
->Address
)));
96 /* See if this address matches the search criteria */
97 if ((Current
->Port
== SearchContext
->Port
) &&
98 (Current
->Protocol
== SearchContext
->Protocol
) &&
99 (AddrIsEqual(IPAddress
, SearchContext
->Address
) ||
100 AddrIsBroadcast(IPAddress
, SearchContext
->Address
) ||
101 AddrIsUnspecified(IPAddress
) ||
102 AddrIsUnspecified(SearchContext
->Address
))) {
103 /* We've found a match */
107 CurrentEntry
= CurrentEntry
->Flink
;
110 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
113 SearchContext
->Next
= CurrentEntry
->Flink
;
122 * FUNCTION: Frees an address file object
124 * Object = Pointer to address file object to free
131 VOID
ControlChannelFree(
134 * FUNCTION: Frees an address file object
136 * Object = Pointer to address file object to free
144 * FUNCTION: Open an address file object
146 * Request = Pointer to TDI request structure for this request
147 * Address = Pointer to address to be opened
148 * Protocol = Protocol on which to open the address
149 * Options = Pointer to option buffer
151 * Status of operation
153 NTSTATUS
FileOpenAddress(
154 PTDI_REQUEST Request
,
155 PTA_IP_ADDRESS Address
,
159 IPv4_RAW_ADDRESS IPv4Address
;
160 PADDRESS_FILE AddrFile
;
162 TI_DbgPrint(MID_TRACE
, ("Called (Proto %d).\n", Protocol
));
164 AddrFile
= exAllocatePool(NonPagedPool
, sizeof(ADDRESS_FILE
));
166 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
167 return STATUS_INSUFFICIENT_RESOURCES
;
170 TI_DbgPrint(DEBUG_ADDRFILE
, ("Address file object allocated at (0x%X).\n", AddrFile
));
172 RtlZeroMemory(AddrFile
, sizeof(ADDRESS_FILE
));
174 AddrFile
->Free
= AddrFileFree
;
176 /* Make sure address is a local unicast address or 0 */
177 /* FIXME: IPv4 only */
178 AddrFile
->Family
= Address
->Address
[0].AddressType
;
179 IPv4Address
= Address
->Address
[0].Address
[0].in_addr
;
180 if (IPv4Address
!= 0 &&
181 !AddrLocateADEv4(IPv4Address
, &AddrFile
->Address
)) {
182 exFreePool(AddrFile
);
183 TI_DbgPrint(MIN_TRACE
, ("Non-local address given (0x%X).\n", DN2H(IPv4Address
)));
184 return STATUS_INVALID_PARAMETER
;
188 /* Bound to the default address ... Copy the address type */
189 AddrFile
->Address
.Type
= IP_ADDRESS_V4
;
192 TI_DbgPrint(MID_TRACE
, ("Opening address %s for communication (P=%d U=%d).\n",
193 A2S(&AddrFile
->Address
), Protocol
, IPPROTO_UDP
));
195 /* Protocol specific handling */
199 TCPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
201 if ((Address
->Address
[0].Address
[0].sin_port
&&
202 AddrFile
->Port
!= Address
->Address
[0].Address
[0].sin_port
) ||
203 AddrFile
->Port
== 0xffff)
205 exFreePool(AddrFile
);
206 return STATUS_INVALID_PARAMETER
;
209 AddrFile
->Send
= NULL
; /* TCPSendData */
213 TI_DbgPrint(MID_TRACE
,("Allocating udp port\n"));
215 UDPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
217 if ((Address
->Address
[0].Address
[0].sin_port
&&
218 AddrFile
->Port
!= Address
->Address
[0].Address
[0].sin_port
) ||
219 AddrFile
->Port
== 0xffff)
221 exFreePool(AddrFile
);
222 return STATUS_INVALID_PARAMETER
;
225 TI_DbgPrint(MID_TRACE
,("Setting port %d (wanted %d)\n",
227 Address
->Address
[0].Address
[0].sin_port
));
228 AddrFile
->Send
= UDPSendDatagram
;
233 AddrFile
->Send
= ICMPSendDatagram
;
237 /* Use raw IP for all other protocols */
239 AddrFile
->Send
= RawIPSendDatagram
;
243 TI_DbgPrint(MID_TRACE
, ("IP protocol number for address file object is %d.\n",
246 TI_DbgPrint(MID_TRACE
, ("Port number for address file object is %d.\n",
247 WN2H(AddrFile
->Port
)));
250 AddrFile
->Protocol
= Protocol
;
252 /* Initialize receive and transmit queues */
253 InitializeListHead(&AddrFile
->ReceiveQueue
);
254 InitializeListHead(&AddrFile
->TransmitQueue
);
256 /* Initialize spin lock that protects the address file object */
257 KeInitializeSpinLock(&AddrFile
->Lock
);
259 /* Set valid flag so the address can be used */
260 AF_SET_VALID(AddrFile
);
262 /* Return address file object */
263 Request
->Handle
.AddressHandle
= AddrFile
;
265 /* Add address file to global list */
266 ExInterlockedInsertTailList(
267 &AddressFileListHead
,
268 &AddrFile
->ListEntry
,
269 &AddressFileListLock
);
271 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
273 return STATUS_SUCCESS
;
278 * FUNCTION: Closes an address file object
280 * Request = Pointer to TDI request structure for this request
282 * Status of operation
284 NTSTATUS
FileCloseAddress(
285 PTDI_REQUEST Request
)
287 PADDRESS_FILE AddrFile
;
288 NTSTATUS Status
= STATUS_SUCCESS
;
290 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
291 PDATAGRAM_SEND_REQUEST SendRequest
;
292 PLIST_ENTRY CurrentEntry
, NextEntry
;
294 AddrFile
= Request
->Handle
.AddressHandle
;
296 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
298 /* Remove address file from the global list */
299 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
300 RemoveEntryList(&AddrFile
->ListEntry
);
301 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
303 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
305 /* FIXME: Kill TCP connections on this address file object */
307 /* Return pending requests with error */
309 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile
));
311 /* Go through pending receive request list and cancel them all */
312 CurrentEntry
= AddrFile
->ReceiveQueue
.Flink
;
313 while (CurrentEntry
!= &AddrFile
->ReceiveQueue
) {
314 NextEntry
= CurrentEntry
->Flink
;
315 ReceiveRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_RECEIVE_REQUEST
, ListEntry
);
316 /* Abort the request and free its resources */
317 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
318 (*ReceiveRequest
->Complete
)(ReceiveRequest
->Context
, STATUS_CANCELLED
, 0);
319 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
320 CurrentEntry
= NextEntry
;
323 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting send requests on address file at (0x%X).\n", AddrFile
));
325 /* Go through pending send request list and cancel them all */
326 CurrentEntry
= AddrFile
->TransmitQueue
.Flink
;
327 while (CurrentEntry
!= &AddrFile
->TransmitQueue
) {
328 NextEntry
= CurrentEntry
->Flink
;
329 SendRequest
= CONTAINING_RECORD(CurrentEntry
,
330 DATAGRAM_SEND_REQUEST
, ListEntry
);
331 /* Abort the request and free its resources */
332 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
333 (*SendRequest
->Complete
)(SendRequest
->Context
, STATUS_CANCELLED
, 0);
334 exFreePool(SendRequest
);
335 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
336 CurrentEntry
= NextEntry
;
339 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
341 /* Protocol specific handling */
342 switch (AddrFile
->Protocol
) {
344 TCPFreePort( AddrFile
->Port
);
345 if( AddrFile
->Listener
) {
346 TcpipRecursiveMutexEnter(&TCPLock
, TRUE
);
347 TCPClose( AddrFile
->Listener
);
348 TcpipRecursiveMutexLeave(&TCPLock
);
349 exFreePool( AddrFile
->Listener
);
354 UDPFreePort( AddrFile
->Port
);
358 (*AddrFile
->Free
)(AddrFile
);
360 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
367 * FUNCTION: Opens a connection file object
369 * Request = Pointer to TDI request structure for this request
370 * ClientContext = Pointer to client context information
372 * Status of operation
374 NTSTATUS
FileOpenConnection(
375 PTDI_REQUEST Request
,
379 PCONNECTION_ENDPOINT Connection
;
381 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
383 Connection
= TCPAllocateConnectionEndpoint( ClientContext
);
385 if( !Connection
) return STATUS_NO_MEMORY
;
387 TcpipRecursiveMutexEnter(&TCPLock
, TRUE
);
388 Status
= TCPSocket( Connection
, AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
389 TcpipRecursiveMutexLeave(&TCPLock
);
391 if( !NT_SUCCESS(Status
) ) {
392 TCPFreeConnectionEndpoint( Connection
);
396 /* Return connection endpoint file object */
397 Request
->Handle
.ConnectionContext
= Connection
;
399 /* Add connection endpoint to global list */
400 ExInterlockedInsertTailList(
401 &ConnectionEndpointListHead
,
402 &Connection
->ListEntry
,
403 &ConnectionEndpointListLock
);
405 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
407 return STATUS_SUCCESS
;
412 * FUNCTION: Find a connection by examining the context field. This
413 * is needed in some situations where a FIN reply is needed after a
414 * socket is formally broken.
416 * Request = Pointer to TDI request structure for this request
418 * Status of operation
420 PCONNECTION_ENDPOINT
FileFindConnectionByContext( PVOID Context
) {
423 PCONNECTION_ENDPOINT Connection
= NULL
;
425 TcpipAcquireSpinLock( &ConnectionEndpointListLock
, &OldIrql
);
427 for( Entry
= ConnectionEndpointListHead
.Flink
;
428 Entry
!= &ConnectionEndpointListHead
;
429 Entry
= Entry
->Flink
) {
431 CONTAINING_RECORD( Entry
, CONNECTION_ENDPOINT
, ListEntry
);
432 if( Connection
->SocketContext
== Context
) break;
433 else Connection
= NULL
;
436 TcpipReleaseSpinLock( &ConnectionEndpointListLock
, OldIrql
);
442 * FUNCTION: Closes an connection file object
444 * Request = Pointer to TDI request structure for this request
446 * Status of operation
448 NTSTATUS
FileCloseConnection(
449 PTDI_REQUEST Request
)
451 PCONNECTION_ENDPOINT Connection
;
454 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
456 Connection
= Request
->Handle
.ConnectionContext
;
458 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
459 RemoveEntryList(&Connection
->ListEntry
);
460 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
462 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
463 TCPClose( Connection
);
464 TcpipRecursiveMutexLeave( &TCPLock
);
466 TCPFreeConnectionEndpoint(Connection
);
468 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
470 return STATUS_SUCCESS
;
475 * FUNCTION: Opens a control channel file object
477 * Request = Pointer to TDI request structure for this request
479 * Status of operation
481 NTSTATUS
FileOpenControlChannel(
482 PTDI_REQUEST Request
)
484 PCONTROL_CHANNEL ControlChannel
;
485 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
487 ControlChannel
= exAllocatePool(NonPagedPool
, sizeof(*ControlChannel
));
489 if (!ControlChannel
) {
490 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
491 return STATUS_INSUFFICIENT_RESOURCES
;
494 RtlZeroMemory(ControlChannel
, sizeof(CONTROL_CHANNEL
));
496 /* Make sure address is a local unicast address or 0 */
498 /* Locate address entry. If specified address is 0, a random address is chosen */
500 /* Initialize receive and transmit queues */
501 InitializeListHead(&ControlChannel
->ListEntry
);
503 /* Initialize spin lock that protects the address file object */
504 KeInitializeSpinLock(&ControlChannel
->Lock
);
506 /* Return address file object */
507 Request
->Handle
.ControlChannel
= ControlChannel
;
509 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
511 return STATUS_SUCCESS
;
515 * FUNCTION: Closes a control channel file object
517 * Request = Pointer to TDI request structure for this request
519 * Status of operation
521 NTSTATUS
FileCloseControlChannel(
522 PTDI_REQUEST Request
)
524 PCONTROL_CHANNEL ControlChannel
= Request
->Handle
.ControlChannel
;
525 NTSTATUS Status
= STATUS_SUCCESS
;
527 exFreePool(ControlChannel
);
528 Request
->Handle
.ControlChannel
= NULL
;