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 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
164 CurrentEntry
= NextEntry
;
167 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting send requests on address file at (0x%X).\n", AddrFile
));
169 /* Go through pending send request list and cancel them all */
170 CurrentEntry
= AddrFile
->TransmitQueue
.Flink
;
171 while (CurrentEntry
!= &AddrFile
->TransmitQueue
) {
172 NextEntry
= CurrentEntry
->Flink
;
173 SendRequest
= CONTAINING_RECORD(CurrentEntry
,
174 DATAGRAM_SEND_REQUEST
, ListEntry
);
175 /* Abort the request and free its resources */
176 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
177 (*SendRequest
->Complete
)(SendRequest
->Context
, STATUS_ADDRESS_CLOSED
, 0);
178 ExFreePool(SendRequest
);
179 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
180 CurrentEntry
= NextEntry
;
183 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
185 (*AddrFile
->Free
)(AddrFile
);
187 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
192 * FUNCTION: Deletes a connection endpoint file object
194 * Connection = Pointer to connection endpoint to delete
196 VOID
DeleteConnectionEndpoint(
197 PCONNECTION_ENDPOINT Connection
)
201 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
203 /* Remove connection endpoint from the global list */
204 TcpipAcquireSpinLock(&ConnectionEndpointListLock
, &OldIrql
);
205 RemoveEntryList(&Connection
->ListEntry
);
206 TcpipReleaseSpinLock(&ConnectionEndpointListLock
, OldIrql
);
208 ExFreePool(Connection
);
210 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
214 * FUNCTION: Open an address file object
216 * Request = Pointer to TDI request structure for this request
217 * Address = Pointer to address to be opened
218 * Protocol = Protocol on which to open the address
219 * Options = Pointer to option buffer
221 * Status of operation
223 NTSTATUS
FileOpenAddress(
224 PTDI_REQUEST Request
,
225 PTA_IP_ADDRESS Address
,
229 PADDRESS_FILE AddrFile
;
230 IPv4_RAW_ADDRESS IPv4Address
;
232 TI_DbgPrint(MID_TRACE
, ("Called (Proto %d).\n", Protocol
));
234 AddrFile
= ExAllocatePool(NonPagedPool
, sizeof(ADDRESS_FILE
));
236 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
237 return STATUS_INSUFFICIENT_RESOURCES
;
240 TI_DbgPrint(DEBUG_ADDRFILE
, ("Address file object allocated at (0x%X).\n", AddrFile
));
242 RtlZeroMemory(AddrFile
, sizeof(ADDRESS_FILE
));
244 AddrFile
->Free
= AddrFileFree
;
246 /* Make sure address is a local unicast address or 0 */
248 /* Locate address entry. If specified address is 0, a random address is chosen */
250 /* FIXME: IPv4 only */
251 IPv4Address
= Address
->Address
[0].Address
[0].in_addr
;
252 if (IPv4Address
== 0)
253 AddrFile
->ADE
= IPGetDefaultADE(ADE_UNICAST
);
255 AddrFile
->ADE
= AddrLocateADEv4(IPv4Address
);
257 if (!AddrFile
->ADE
) {
258 ExFreePool(AddrFile
);
259 TI_DbgPrint(MIN_TRACE
, ("Non-local address given (0x%X).\n", DN2H(IPv4Address
)));
260 return STATUS_INVALID_PARAMETER
;
263 TI_DbgPrint(MID_TRACE
, ("Opening address %s for communication (P=%d U=%d).\n",
264 A2S(&AddrFile
->ADE
->Address
), Protocol
, IPPROTO_UDP
));
266 /* Protocol specific handling */
269 /* FIXME: If specified port is 0, a port is chosen dynamically */
270 AddrFile
->Port
= Address
->Address
[0].Address
[0].sin_port
;
271 AddrFile
->Send
= NULL
; /* TCPSendData */
275 TI_DbgPrint(MID_TRACE
,("Allocating udp port\n"));
277 UDPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
278 TI_DbgPrint(MID_TRACE
,("Setting port %d\n", AddrFile
->Port
));
279 AddrFile
->Send
= UDPSendDatagram
;
283 /* Use raw IP for all other protocols */
285 AddrFile
->Send
= RawIPSendDatagram
;
289 TI_DbgPrint(MID_TRACE
, ("IP protocol number for address file object is %d.\n",
292 TI_DbgPrint(MID_TRACE
, ("Port number for address file object is %d.\n",
293 WN2H(AddrFile
->Port
)));
296 AddrFile
->Protocol
= Protocol
;
298 /* Initialize receive and transmit queues */
299 InitializeListHead(&AddrFile
->ReceiveQueue
);
300 InitializeListHead(&AddrFile
->TransmitQueue
);
302 /* Initialize spin lock that protects the address file object */
303 KeInitializeSpinLock(&AddrFile
->Lock
);
305 /* Set valid flag so the address can be used */
306 AF_SET_VALID(AddrFile
);
308 /* Return address file object */
309 Request
->Handle
.AddressHandle
= AddrFile
;
311 /* Add address file to global list */
312 ExInterlockedInsertTailList(
313 &AddressFileListHead
,
314 &AddrFile
->ListEntry
,
315 &AddressFileListLock
);
317 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
319 return STATUS_SUCCESS
;
324 * FUNCTION: Closes an address file object
326 * Request = Pointer to TDI request structure for this request
328 * Status of operation
330 NTSTATUS
FileCloseAddress(
331 PTDI_REQUEST Request
)
334 PADDRESS_FILE AddrFile
;
335 NTSTATUS Status
= STATUS_SUCCESS
;
337 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
339 AddrFile
= Request
->Handle
.AddressHandle
;
341 TcpipAcquireSpinLock(&AddrFile
->Lock
, &OldIrql
);
343 /* Set address file object exclusive to us */
344 AF_SET_BUSY(AddrFile
);
345 AF_CLR_VALID(AddrFile
);
347 TcpipReleaseSpinLock(&AddrFile
->Lock
, OldIrql
);
348 UDPFreePort( AddrFile
->Port
);
350 DeleteAddress(AddrFile
);
352 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
359 * FUNCTION: Opens a connection file object
361 * Request = Pointer to TDI request structure for this request
362 * ClientContext = Pointer to client context information
364 * Status of operation
366 NTSTATUS
FileOpenConnection(
367 PTDI_REQUEST Request
,
371 PCONNECTION_ENDPOINT Connection
;
373 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
375 Connection
= TCPAllocateConnectionEndpoint( ClientContext
);
377 if( !Connection
) return STATUS_NO_MEMORY
;
379 Status
= TCPSocket( Connection
, AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
380 DbgPrint("STATUS from OSKITTCP was %08x\n", Status
);
382 /* Initialize received segments queue */
383 InitializeListHead(&Connection
->ReceivedSegments
);
385 TI_DbgPrint(MIN_TRACE
, ("X1 cur 0x%x\n", &Connection
->ReceivedSegments
));
386 TI_DbgPrint(MIN_TRACE
, ("X1 Flink 0x%x\n", Connection
->ReceivedSegments
.Flink
));
387 TI_DbgPrint(MIN_TRACE
, ("X1 Blink 0x%x\n", Connection
->ReceivedSegments
.Blink
));
390 /* Return connection endpoint file object */
391 Request
->Handle
.ConnectionContext
= Connection
;
393 /* Add connection endpoint to global list */
394 ExInterlockedInsertTailList(
395 &ConnectionEndpointListHead
,
396 &Connection
->ListEntry
,
397 &ConnectionEndpointListLock
);
399 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
401 return STATUS_SUCCESS
;
406 * FUNCTION: Find a connection by examining the context field. This
407 * is needed in some situations where a FIN reply is needed after a
408 * socket is formally broken.
410 * Request = Pointer to TDI request structure for this request
412 * Status of operation
414 PCONNECTION_ENDPOINT
FileFindConnectionByContext( PVOID Context
) {
417 PCONNECTION_ENDPOINT Connection
= NULL
;
419 KeAcquireSpinLock( &ConnectionEndpointListLock
, &OldIrql
);
421 for( Entry
= ConnectionEndpointListHead
.Flink
;
422 Entry
!= &ConnectionEndpointListHead
;
423 Entry
= Entry
->Flink
) {
425 CONTAINING_RECORD( Entry
, CONNECTION_ENDPOINT
, ListEntry
);
426 if( Connection
->SocketContext
== Context
) break;
427 else Connection
= NULL
;
430 KeReleaseSpinLock( &ConnectionEndpointListLock
, OldIrql
);
436 * FUNCTION: Closes an connection file object
438 * Request = Pointer to TDI request structure for this request
440 * Status of operation
442 NTSTATUS
FileCloseConnection(
443 PTDI_REQUEST Request
)
445 PCONNECTION_ENDPOINT Connection
;
446 NTSTATUS Status
= STATUS_SUCCESS
;
448 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
450 Connection
= Request
->Handle
.ConnectionContext
;
452 TCPClose(Connection
);
453 DeleteConnectionEndpoint(Connection
);
455 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
462 * FUNCTION: Opens a control channel file object
464 * Request = Pointer to TDI request structure for this request
466 * Status of operation
468 NTSTATUS
FileOpenControlChannel(
469 PTDI_REQUEST Request
)
471 PCONTROL_CHANNEL ControlChannel
;
472 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
474 ControlChannel
= ExAllocatePool(NonPagedPool
, sizeof(*ControlChannel
));
476 if (!ControlChannel
) {
477 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
478 return STATUS_INSUFFICIENT_RESOURCES
;
481 RtlZeroMemory(ControlChannel
, sizeof(CONTROL_CHANNEL
));
483 /* Make sure address is a local unicast address or 0 */
485 /* Locate address entry. If specified address is 0, a random address is chosen */
487 /* Initialize receive and transmit queues */
488 InitializeListHead(&ControlChannel
->ListEntry
);
490 /* Initialize spin lock that protects the address file object */
491 KeInitializeSpinLock(&ControlChannel
->Lock
);
493 /* Return address file object */
494 Request
->Handle
.ControlChannel
= ControlChannel
;
496 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
498 return STATUS_SUCCESS
;
502 * FUNCTION: Closes a control channel file object
504 * Request = Pointer to TDI request structure for this request
506 * Status of operation
508 NTSTATUS
FileCloseControlChannel(
509 PTDI_REQUEST Request
)
511 PCONTROL_CHANNEL ControlChannel
= Request
->Handle
.ControlChannel
;
512 NTSTATUS Status
= STATUS_SUCCESS
;
514 ExFreePool(ControlChannel
);
515 Request
->Handle
.ControlChannel
= NULL
;