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
AddrIsBroadcastMatch(
47 PIP_ADDRESS UnicastAddress
,
48 PIP_ADDRESS BroadcastAddress
) {
51 ForEachInterface(IF
) {
52 if ((AddrIsUnspecified(UnicastAddress
) ||
53 AddrIsEqual(&IF
->Unicast
, UnicastAddress
)) &&
54 (AddrIsEqual(&IF
->Broadcast
, BroadcastAddress
)))
61 BOOLEAN
AddrReceiveMatch(
62 PIP_ADDRESS LocalAddress
,
63 PIP_ADDRESS RemoteAddress
)
65 if (AddrIsEqual(LocalAddress
, RemoteAddress
))
67 /* Unicast address match */
71 if (AddrIsBroadcastMatch(LocalAddress
, RemoteAddress
))
73 /* Broadcast address match */
77 if (AddrIsUnspecified(LocalAddress
))
79 /* Local address unspecified */
83 if (AddrIsUnspecified(RemoteAddress
))
85 /* Remote address unspecified */
93 * FUNCTION: Searches through address file entries to find next match
95 * SearchContext = Pointer to search context
97 * Pointer to address file, NULL if none was found
99 PADDRESS_FILE
AddrSearchNext(
100 PAF_SEARCH SearchContext
)
102 PLIST_ENTRY CurrentEntry
;
103 PIP_ADDRESS IPAddress
;
105 PADDRESS_FILE Current
= NULL
;
106 BOOLEAN Found
= FALSE
;
108 if (IsListEmpty(SearchContext
->Next
))
111 CurrentEntry
= SearchContext
->Next
;
113 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
115 while (CurrentEntry
!= &AddressFileListHead
) {
116 Current
= CONTAINING_RECORD(CurrentEntry
, ADDRESS_FILE
, ListEntry
);
118 IPAddress
= &Current
->Address
;
120 TI_DbgPrint(DEBUG_ADDRFILE
, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
124 WN2H(SearchContext
->Port
),
125 SearchContext
->Protocol
,
126 A2S(SearchContext
->Address
)));
128 /* See if this address matches the search criteria */
129 if ((Current
->Port
== SearchContext
->Port
) &&
130 (Current
->Protocol
== SearchContext
->Protocol
) &&
131 (AddrReceiveMatch(IPAddress
, SearchContext
->Address
))) {
132 /* We've found a match */
136 CurrentEntry
= CurrentEntry
->Flink
;
139 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
142 SearchContext
->Next
= CurrentEntry
->Flink
;
151 * FUNCTION: Frees an address file object
153 * Object = Pointer to address file object to free
160 VOID
ControlChannelFree(
163 * FUNCTION: Frees an address file object
165 * Object = Pointer to address file object to free
173 * FUNCTION: Open an address file object
175 * Request = Pointer to TDI request structure for this request
176 * Address = Pointer to address to be opened
177 * Protocol = Protocol on which to open the address
178 * Options = Pointer to option buffer
180 * Status of operation
182 NTSTATUS
FileOpenAddress(
183 PTDI_REQUEST Request
,
184 PTA_IP_ADDRESS Address
,
188 PADDRESS_FILE AddrFile
;
190 TI_DbgPrint(MID_TRACE
, ("Called (Proto %d).\n", Protocol
));
192 AddrFile
= exAllocatePool(NonPagedPool
, sizeof(ADDRESS_FILE
));
194 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
195 return STATUS_INSUFFICIENT_RESOURCES
;
198 TI_DbgPrint(DEBUG_ADDRFILE
, ("Address file object allocated at (0x%X).\n", AddrFile
));
200 RtlZeroMemory(AddrFile
, sizeof(ADDRESS_FILE
));
202 AddrFile
->Free
= AddrFileFree
;
204 /* Set our default TTL */
207 /* Make sure address is a local unicast address or 0 */
208 /* FIXME: IPv4 only */
209 AddrFile
->Family
= Address
->Address
[0].AddressType
;
210 AddrFile
->Address
.Address
.IPv4Address
= Address
->Address
[0].Address
[0].in_addr
;
211 AddrFile
->Address
.Type
= IP_ADDRESS_V4
;
213 if (!AddrIsUnspecified(&AddrFile
->Address
) &&
214 !AddrLocateInterface(&AddrFile
->Address
)) {
215 exFreePool(AddrFile
);
216 TI_DbgPrint(MIN_TRACE
, ("Non-local address given (0x%X).\n", A2S(&AddrFile
->Address
)));
217 return STATUS_INVALID_PARAMETER
;
220 TI_DbgPrint(MID_TRACE
, ("Opening address %s for communication (P=%d U=%d).\n",
221 A2S(&AddrFile
->Address
), Protocol
, IPPROTO_UDP
));
223 /* Protocol specific handling */
227 TCPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
229 if ((Address
->Address
[0].Address
[0].sin_port
&&
230 AddrFile
->Port
!= Address
->Address
[0].Address
[0].sin_port
) ||
231 AddrFile
->Port
== 0xffff)
233 exFreePool(AddrFile
);
234 return STATUS_INVALID_PARAMETER
;
237 AddEntity(CO_TL_ENTITY
, AddrFile
, CO_TL_TCP
);
239 AddrFile
->Send
= NULL
; /* TCPSendData */
243 TI_DbgPrint(MID_TRACE
,("Allocating udp port\n"));
245 UDPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
247 if ((Address
->Address
[0].Address
[0].sin_port
&&
248 AddrFile
->Port
!= Address
->Address
[0].Address
[0].sin_port
) ||
249 AddrFile
->Port
== 0xffff)
251 exFreePool(AddrFile
);
252 return STATUS_INVALID_PARAMETER
;
255 TI_DbgPrint(MID_TRACE
,("Setting port %d (wanted %d)\n",
257 Address
->Address
[0].Address
[0].sin_port
));
259 AddEntity(CL_TL_ENTITY
, AddrFile
, CL_TL_UDP
);
261 AddrFile
->Send
= UDPSendDatagram
;
266 AddrFile
->Send
= ICMPSendDatagram
;
268 /* FIXME: Verify this */
269 AddEntity(ER_ENTITY
, AddrFile
, ER_ICMP
);
273 /* Use raw IP for all other protocols */
275 AddrFile
->Send
= RawIPSendDatagram
;
277 /* FIXME: Verify this */
278 AddEntity(CL_TL_ENTITY
, AddrFile
, 0);
282 TI_DbgPrint(MID_TRACE
, ("IP protocol number for address file object is %d.\n",
285 TI_DbgPrint(MID_TRACE
, ("Port number for address file object is %d.\n",
286 WN2H(AddrFile
->Port
)));
289 AddrFile
->Protocol
= Protocol
;
291 /* Initialize receive and transmit queues */
292 InitializeListHead(&AddrFile
->ReceiveQueue
);
293 InitializeListHead(&AddrFile
->TransmitQueue
);
295 /* Initialize spin lock that protects the address file object */
296 KeInitializeSpinLock(&AddrFile
->Lock
);
298 /* Set valid flag so the address can be used */
299 AF_SET_VALID(AddrFile
);
301 /* Return address file object */
302 Request
->Handle
.AddressHandle
= AddrFile
;
304 /* Add address file to global list */
305 ExInterlockedInsertTailList(
306 &AddressFileListHead
,
307 &AddrFile
->ListEntry
,
308 &AddressFileListLock
);
310 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
312 return STATUS_SUCCESS
;
317 * FUNCTION: Closes an address file object
319 * Request = Pointer to TDI request structure for this request
321 * Status of operation
323 NTSTATUS
FileCloseAddress(
324 PTDI_REQUEST Request
)
326 PADDRESS_FILE AddrFile
;
327 NTSTATUS Status
= STATUS_SUCCESS
;
329 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
330 PDATAGRAM_SEND_REQUEST SendRequest
;
331 PLIST_ENTRY CurrentEntry
, NextEntry
;
333 AddrFile
= Request
->Handle
.AddressHandle
;
335 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
337 /* Remove address file from the global list */
338 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
339 RemoveEntryList(&AddrFile
->ListEntry
);
340 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
342 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
344 /* FIXME: Kill TCP connections on this address file object */
346 /* Return pending requests with error */
348 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile
));
350 /* Go through pending receive request list and cancel them all */
351 CurrentEntry
= AddrFile
->ReceiveQueue
.Flink
;
352 while (CurrentEntry
!= &AddrFile
->ReceiveQueue
) {
353 NextEntry
= CurrentEntry
->Flink
;
354 ReceiveRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_RECEIVE_REQUEST
, ListEntry
);
355 /* Abort the request and free its resources */
356 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
357 (*ReceiveRequest
->Complete
)(ReceiveRequest
->Context
, STATUS_CANCELLED
, 0);
358 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
359 CurrentEntry
= NextEntry
;
362 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting send requests on address file at (0x%X).\n", AddrFile
));
364 /* Go through pending send request list and cancel them all */
365 CurrentEntry
= AddrFile
->TransmitQueue
.Flink
;
366 while (CurrentEntry
!= &AddrFile
->TransmitQueue
) {
367 NextEntry
= CurrentEntry
->Flink
;
368 SendRequest
= CONTAINING_RECORD(CurrentEntry
,
369 DATAGRAM_SEND_REQUEST
, ListEntry
);
370 /* Abort the request and free its resources */
371 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
372 (*SendRequest
->Complete
)(SendRequest
->Context
, STATUS_CANCELLED
, 0);
373 exFreePool(SendRequest
);
374 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
375 CurrentEntry
= NextEntry
;
378 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
380 /* Protocol specific handling */
381 switch (AddrFile
->Protocol
) {
383 TCPFreePort( AddrFile
->Port
);
384 if( AddrFile
->Listener
) {
385 TcpipRecursiveMutexEnter(&TCPLock
, TRUE
);
386 TCPClose( AddrFile
->Listener
);
387 TcpipRecursiveMutexLeave(&TCPLock
);
388 exFreePool( AddrFile
->Listener
);
393 UDPFreePort( AddrFile
->Port
);
397 RemoveEntityByContext(AddrFile
);
399 (*AddrFile
->Free
)(AddrFile
);
401 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
408 * FUNCTION: Opens a connection file object
410 * Request = Pointer to TDI request structure for this request
411 * ClientContext = Pointer to client context information
413 * Status of operation
415 NTSTATUS
FileOpenConnection(
416 PTDI_REQUEST Request
,
420 PCONNECTION_ENDPOINT Connection
;
422 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
424 Connection
= TCPAllocateConnectionEndpoint( ClientContext
);
426 if( !Connection
) return STATUS_NO_MEMORY
;
428 TcpipRecursiveMutexEnter(&TCPLock
, TRUE
);
429 Status
= TCPSocket( Connection
, AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
430 TcpipRecursiveMutexLeave(&TCPLock
);
432 if( !NT_SUCCESS(Status
) ) {
433 TCPFreeConnectionEndpoint( Connection
);
437 /* Return connection endpoint file object */
438 Request
->Handle
.ConnectionContext
= Connection
;
440 /* Add connection endpoint to global list */
441 ExInterlockedInsertTailList(
442 &ConnectionEndpointListHead
,
443 &Connection
->ListEntry
,
444 &ConnectionEndpointListLock
);
446 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
448 return STATUS_SUCCESS
;
453 * FUNCTION: Find a connection by examining the context field. This
454 * is needed in some situations where a FIN reply is needed after a
455 * socket is formally broken.
457 * Request = Pointer to TDI request structure for this request
459 * Status of operation
461 PCONNECTION_ENDPOINT
FileFindConnectionByContext( PVOID Context
) {
464 PCONNECTION_ENDPOINT Connection
= NULL
;
466 TcpipAcquireSpinLock( &ConnectionEndpointListLock
, &OldIrql
);
468 for( Entry
= ConnectionEndpointListHead
.Flink
;
469 Entry
!= &ConnectionEndpointListHead
;
470 Entry
= Entry
->Flink
) {
472 CONTAINING_RECORD( Entry
, CONNECTION_ENDPOINT
, ListEntry
);
473 if( Connection
->SocketContext
== Context
) break;
474 else Connection
= NULL
;
477 TcpipReleaseSpinLock( &ConnectionEndpointListLock
, OldIrql
);
483 * FUNCTION: Closes an connection file object
485 * Request = Pointer to TDI request structure for this request
487 * Status of operation
489 NTSTATUS
FileCloseConnection(
490 PTDI_REQUEST Request
)
492 PCONNECTION_ENDPOINT Connection
;
495 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
497 Connection
= Request
->Handle
.ConnectionContext
;
499 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
500 RemoveEntryList(&Connection
->ListEntry
);
501 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
503 TcpipRecursiveMutexEnter( &TCPLock
, TRUE
);
504 TCPClose( Connection
);
505 TcpipRecursiveMutexLeave( &TCPLock
);
507 TCPFreeConnectionEndpoint(Connection
);
509 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
511 return STATUS_SUCCESS
;
516 * FUNCTION: Opens a control channel file object
518 * Request = Pointer to TDI request structure for this request
520 * Status of operation
522 NTSTATUS
FileOpenControlChannel(
523 PTDI_REQUEST Request
)
525 PCONTROL_CHANNEL ControlChannel
;
526 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
528 ControlChannel
= exAllocatePool(NonPagedPool
, sizeof(*ControlChannel
));
530 if (!ControlChannel
) {
531 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
532 return STATUS_INSUFFICIENT_RESOURCES
;
535 RtlZeroMemory(ControlChannel
, sizeof(CONTROL_CHANNEL
));
537 /* Make sure address is a local unicast address or 0 */
539 /* Locate address entry. If specified address is 0, a random address is chosen */
541 /* Initialize receive and transmit queues */
542 InitializeListHead(&ControlChannel
->ListEntry
);
544 /* Initialize spin lock that protects the address file object */
545 KeInitializeSpinLock(&ControlChannel
->Lock
);
547 /* Return address file object */
548 Request
->Handle
.ControlChannel
= ControlChannel
;
550 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
552 return STATUS_SUCCESS
;
556 * FUNCTION: Closes a control channel file object
558 * Request = Pointer to TDI request structure for this request
560 * Status of operation
562 NTSTATUS
FileCloseControlChannel(
563 PTDI_REQUEST Request
)
565 PCONTROL_CHANNEL ControlChannel
= Request
->Handle
.ControlChannel
;
566 NTSTATUS Status
= STATUS_SUCCESS
;
568 exFreePool(ControlChannel
);
569 Request
->Handle
.ControlChannel
= NULL
;