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 /* We've found a match */
106 CurrentEntry
= CurrentEntry
->Flink
;
109 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
112 SearchContext
->Next
= CurrentEntry
->Flink
;
121 * FUNCTION: Frees an address file object
123 * Object = Pointer to address file object to free
130 VOID
ControlChannelFree(
133 * FUNCTION: Frees an address file object
135 * Object = Pointer to address file object to free
142 VOID
DeleteAddress(PADDRESS_FILE AddrFile
)
144 * FUNCTION: Deletes an address file object
146 * AddrFile = Pointer to address file object to delete
150 PLIST_ENTRY CurrentEntry
;
151 PLIST_ENTRY NextEntry
;
152 PDATAGRAM_SEND_REQUEST SendRequest
;
153 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
155 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
157 /* Remove address file from the global list */
158 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
159 RemoveEntryList(&AddrFile
->ListEntry
);
160 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
162 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
164 /* FIXME: Kill TCP connections on this address file object */
166 /* Return pending requests with error */
168 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile
));
170 /* Go through pending receive request list and cancel them all */
171 CurrentEntry
= AddrFile
->ReceiveQueue
.Flink
;
172 while (CurrentEntry
!= &AddrFile
->ReceiveQueue
) {
173 NextEntry
= CurrentEntry
->Flink
;
174 ReceiveRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_RECEIVE_REQUEST
, ListEntry
);
175 /* Abort the request and free its resources */
176 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
177 (*ReceiveRequest
->Complete
)(ReceiveRequest
->Context
, STATUS_ADDRESS_CLOSED
, 0);
178 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
179 CurrentEntry
= NextEntry
;
182 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting send requests on address file at (0x%X).\n", AddrFile
));
184 /* Go through pending send request list and cancel them all */
185 CurrentEntry
= AddrFile
->TransmitQueue
.Flink
;
186 while (CurrentEntry
!= &AddrFile
->TransmitQueue
) {
187 NextEntry
= CurrentEntry
->Flink
;
188 SendRequest
= CONTAINING_RECORD(CurrentEntry
,
189 DATAGRAM_SEND_REQUEST
, ListEntry
);
190 /* Abort the request and free its resources */
191 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
192 (*SendRequest
->Complete
)(SendRequest
->Context
, STATUS_ADDRESS_CLOSED
, 0);
193 exFreePool(SendRequest
);
194 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
195 CurrentEntry
= NextEntry
;
198 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
200 (*AddrFile
->Free
)(AddrFile
);
202 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
207 * FUNCTION: Open an address file object
209 * Request = Pointer to TDI request structure for this request
210 * Address = Pointer to address to be opened
211 * Protocol = Protocol on which to open the address
212 * Options = Pointer to option buffer
214 * Status of operation
216 NTSTATUS
FileOpenAddress(
217 PTDI_REQUEST Request
,
218 PTA_IP_ADDRESS Address
,
222 IPv4_RAW_ADDRESS IPv4Address
;
223 PADDRESS_FILE AddrFile
;
225 TI_DbgPrint(MID_TRACE
, ("Called (Proto %d).\n", Protocol
));
227 AddrFile
= exAllocatePool(NonPagedPool
, sizeof(ADDRESS_FILE
));
229 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
230 return STATUS_INSUFFICIENT_RESOURCES
;
233 TI_DbgPrint(DEBUG_ADDRFILE
, ("Address file object allocated at (0x%X).\n", AddrFile
));
235 RtlZeroMemory(AddrFile
, sizeof(ADDRESS_FILE
));
237 AddrFile
->Free
= AddrFileFree
;
239 /* Make sure address is a local unicast address or 0 */
240 /* FIXME: IPv4 only */
241 AddrFile
->Family
= Address
->Address
[0].AddressType
;
242 IPv4Address
= Address
->Address
[0].Address
[0].in_addr
;
243 if (IPv4Address
!= 0 &&
244 !AddrLocateADEv4(IPv4Address
, &AddrFile
->Address
)) {
245 exFreePool(AddrFile
);
246 TI_DbgPrint(MIN_TRACE
, ("Non-local address given (0x%X).\n", DN2H(IPv4Address
)));
247 return STATUS_INVALID_PARAMETER
;
251 /* Bound to the default address ... Copy the address type */
252 AddrFile
->Address
.Type
= IP_ADDRESS_V4
;
255 TI_DbgPrint(MID_TRACE
, ("Opening address %s for communication (P=%d U=%d).\n",
256 A2S(&AddrFile
->Address
), Protocol
, IPPROTO_UDP
));
258 /* Protocol specific handling */
262 TCPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
264 if ((Address
->Address
[0].Address
[0].sin_port
&&
265 AddrFile
->Port
!= Address
->Address
[0].Address
[0].sin_port
) ||
266 AddrFile
->Port
== 0xffff)
268 exFreePool(AddrFile
);
269 return STATUS_INVALID_PARAMETER
;
272 AddrFile
->Send
= NULL
; /* TCPSendData */
276 TI_DbgPrint(MID_TRACE
,("Allocating udp port\n"));
278 UDPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
280 if ((Address
->Address
[0].Address
[0].sin_port
&&
281 AddrFile
->Port
!= Address
->Address
[0].Address
[0].sin_port
) ||
282 AddrFile
->Port
== 0xffff)
284 exFreePool(AddrFile
);
285 return STATUS_INVALID_PARAMETER
;
288 TI_DbgPrint(MID_TRACE
,("Setting port %d (wanted %d)\n",
290 Address
->Address
[0].Address
[0].sin_port
));
291 AddrFile
->Send
= UDPSendDatagram
;
296 AddrFile
->Send
= ICMPSendDatagram
;
300 /* Use raw IP for all other protocols */
302 AddrFile
->Send
= RawIPSendDatagram
;
306 TI_DbgPrint(MID_TRACE
, ("IP protocol number for address file object is %d.\n",
309 TI_DbgPrint(MID_TRACE
, ("Port number for address file object is %d.\n",
310 WN2H(AddrFile
->Port
)));
313 AddrFile
->Protocol
= Protocol
;
315 /* Initialize receive and transmit queues */
316 InitializeListHead(&AddrFile
->ReceiveQueue
);
317 InitializeListHead(&AddrFile
->TransmitQueue
);
319 /* Initialize spin lock that protects the address file object */
320 KeInitializeSpinLock(&AddrFile
->Lock
);
322 /* Set valid flag so the address can be used */
323 AF_SET_VALID(AddrFile
);
325 /* Return address file object */
326 Request
->Handle
.AddressHandle
= AddrFile
;
328 /* Add address file to global list */
329 ExInterlockedInsertTailList(
330 &AddressFileListHead
,
331 &AddrFile
->ListEntry
,
332 &AddressFileListLock
);
334 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
336 return STATUS_SUCCESS
;
341 * FUNCTION: Closes an address file object
343 * Request = Pointer to TDI request structure for this request
345 * Status of operation
347 NTSTATUS
FileCloseAddress(
348 PTDI_REQUEST Request
)
351 PADDRESS_FILE AddrFile
;
352 NTSTATUS Status
= STATUS_SUCCESS
;
354 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
356 AddrFile
= Request
->Handle
.AddressHandle
;
358 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
360 /* Set address file object exclusive to us */
361 AF_SET_BUSY(AddrFile
);
362 AF_CLR_VALID(AddrFile
);
364 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
366 /* Protocol specific handling */
367 switch (AddrFile
->Protocol
) {
369 TCPFreePort( AddrFile
->Port
);
370 if( AddrFile
->Listener
) {
371 TcpipRecursiveMutexEnter(&TCPLock
, TRUE
);
372 TCPClose( AddrFile
->Listener
);
373 TcpipRecursiveMutexLeave(&TCPLock
);
374 exFreePool( AddrFile
->Listener
);
379 UDPFreePort( AddrFile
->Port
);
383 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
390 * FUNCTION: Closes an address file object
392 * Request = Pointer to TDI request structure for this request
394 * Status of operation
396 NTSTATUS
FileFreeAddress(
397 PTDI_REQUEST Request
)
399 PADDRESS_FILE AddrFile
;
400 NTSTATUS Status
= STATUS_SUCCESS
;
402 AddrFile
= Request
->Handle
.AddressHandle
;
404 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
406 DeleteAddress(AddrFile
);
408 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
415 * FUNCTION: Opens a connection file object
417 * Request = Pointer to TDI request structure for this request
418 * ClientContext = Pointer to client context information
420 * Status of operation
422 NTSTATUS
FileOpenConnection(
423 PTDI_REQUEST Request
,
427 PCONNECTION_ENDPOINT Connection
;
429 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
431 Connection
= TCPAllocateConnectionEndpoint( ClientContext
);
433 if( !Connection
) return STATUS_NO_MEMORY
;
435 TcpipRecursiveMutexEnter(&TCPLock
, TRUE
);
436 Status
= TCPSocket( Connection
, AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
437 TcpipRecursiveMutexLeave(&TCPLock
);
439 if( !NT_SUCCESS(Status
) ) {
440 TCPFreeConnectionEndpoint( Connection
);
444 /* Return connection endpoint file object */
445 Request
->Handle
.ConnectionContext
= Connection
;
447 /* Add connection endpoint to global list */
448 ExInterlockedInsertTailList(
449 &ConnectionEndpointListHead
,
450 &Connection
->ListEntry
,
451 &ConnectionEndpointListLock
);
453 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
455 return STATUS_SUCCESS
;
460 * FUNCTION: Find a connection by examining the context field. This
461 * is needed in some situations where a FIN reply is needed after a
462 * socket is formally broken.
464 * Request = Pointer to TDI request structure for this request
466 * Status of operation
468 PCONNECTION_ENDPOINT
FileFindConnectionByContext( PVOID Context
) {
471 PCONNECTION_ENDPOINT Connection
= NULL
;
473 TcpipAcquireSpinLock( &ConnectionEndpointListLock
, &OldIrql
);
475 for( Entry
= ConnectionEndpointListHead
.Flink
;
476 Entry
!= &ConnectionEndpointListHead
;
477 Entry
= Entry
->Flink
) {
479 CONTAINING_RECORD( Entry
, CONNECTION_ENDPOINT
, ListEntry
);
480 if( Connection
->SocketContext
== Context
) break;
481 else Connection
= NULL
;
484 TcpipReleaseSpinLock( &ConnectionEndpointListLock
, OldIrql
);
490 * FUNCTION: Closes an connection file object
492 * Request = Pointer to TDI request structure for this request
494 * Status of operation
496 NTSTATUS
FileCloseConnection(
497 PTDI_REQUEST Request
)
499 PCONNECTION_ENDPOINT Connection
;
501 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
503 Connection
= Request
->Handle
.ConnectionContext
;
505 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
506 TCPClose( Connection
);
507 TcpipRecursiveMutexLeave( &TCPLock
);
509 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
511 return STATUS_SUCCESS
;
516 * FUNCTION: Frees an connection file object
518 * Request = Pointer to TDI request structure for this request
520 * Status of operation
522 NTSTATUS
FileFreeConnection(
523 PTDI_REQUEST Request
)
526 PCONNECTION_ENDPOINT Connection
;
528 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
530 Connection
= Request
->Handle
.ConnectionContext
;
532 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
533 RemoveEntryList(&Connection
->ListEntry
);
534 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
536 TCPFreeConnectionEndpoint(Connection
);
538 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
540 return STATUS_SUCCESS
;
545 * FUNCTION: Opens a control channel file object
547 * Request = Pointer to TDI request structure for this request
549 * Status of operation
551 NTSTATUS
FileOpenControlChannel(
552 PTDI_REQUEST Request
)
554 PCONTROL_CHANNEL ControlChannel
;
555 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
557 ControlChannel
= exAllocatePool(NonPagedPool
, sizeof(*ControlChannel
));
559 if (!ControlChannel
) {
560 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
561 return STATUS_INSUFFICIENT_RESOURCES
;
564 RtlZeroMemory(ControlChannel
, sizeof(CONTROL_CHANNEL
));
566 /* Make sure address is a local unicast address or 0 */
568 /* Locate address entry. If specified address is 0, a random address is chosen */
570 /* Initialize receive and transmit queues */
571 InitializeListHead(&ControlChannel
->ListEntry
);
573 /* Initialize spin lock that protects the address file object */
574 KeInitializeSpinLock(&ControlChannel
->Lock
);
576 /* Return address file object */
577 Request
->Handle
.ControlChannel
= ControlChannel
;
579 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
581 return STATUS_SUCCESS
;
585 * FUNCTION: Closes a control channel file object
587 * Request = Pointer to TDI request structure for this request
589 * Status of operation
591 NTSTATUS
FileFreeControlChannel(
592 PTDI_REQUEST Request
)
594 PCONTROL_CHANNEL ControlChannel
= Request
->Handle
.ControlChannel
;
595 NTSTATUS Status
= STATUS_SUCCESS
;
597 exFreePool(ControlChannel
);
598 Request
->Handle
.ControlChannel
= NULL
;