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
156 PADDRESS_FILE AddrFile
= Object
;
158 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest
;
159 PDATAGRAM_SEND_REQUEST SendRequest
;
160 PLIST_ENTRY CurrentEntry
;
162 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
164 /* Remove address file from the global list */
165 TcpipAcquireSpinLock(&AddressFileListLock
, &OldIrql
);
166 RemoveEntryList(&AddrFile
->ListEntry
);
167 TcpipReleaseSpinLock(&AddressFileListLock
, OldIrql
);
169 /* FIXME: Kill TCP connections on this address file object */
171 /* Return pending requests with error */
173 TI_DbgPrint(DEBUG_ADDRFILE
, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile
));
175 /* Go through pending receive request list and cancel them all */
176 while ((CurrentEntry
= ExInterlockedRemoveHeadList(&AddrFile
->ReceiveQueue
, &AddrFile
->Lock
))) {
177 ReceiveRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_RECEIVE_REQUEST
, ListEntry
);
178 (*ReceiveRequest
->Complete
)(ReceiveRequest
->Context
, STATUS_CANCELLED
, 0);
179 /* ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG); FIXME: WTF? */
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 while ((CurrentEntry
= ExInterlockedRemoveHeadList(&AddrFile
->ReceiveQueue
, &AddrFile
->Lock
))) {
186 SendRequest
= CONTAINING_RECORD(CurrentEntry
, DATAGRAM_SEND_REQUEST
, ListEntry
);
187 (*SendRequest
->Complete
)(SendRequest
->Context
, STATUS_CANCELLED
, 0);
188 ExFreePoolWithTag(SendRequest
, DATAGRAM_SEND_TAG
);
191 /* Protocol specific handling */
192 switch (AddrFile
->Protocol
) {
194 TCPFreePort( AddrFile
->Port
);
198 UDPFreePort( AddrFile
->Port
);
202 RemoveEntityByContext(AddrFile
);
204 ExFreePoolWithTag(Object
, ADDR_FILE_TAG
);
208 VOID
ControlChannelFree(
211 * FUNCTION: Frees an address file object
213 * Object = Pointer to address file object to free
216 ExFreePoolWithTag(Object
, CONTROL_CHANNEL_TAG
);
221 * FUNCTION: Open an address file object
223 * Request = Pointer to TDI request structure for this request
224 * Address = Pointer to address to be opened
225 * Protocol = Protocol on which to open the address
226 * Options = Pointer to option buffer
228 * Status of operation
230 NTSTATUS
FileOpenAddress(
231 PTDI_REQUEST Request
,
232 PTA_IP_ADDRESS Address
,
236 PADDRESS_FILE AddrFile
;
238 TI_DbgPrint(MID_TRACE
, ("Called (Proto %d).\n", Protocol
));
240 AddrFile
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(ADDRESS_FILE
),
243 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
244 return STATUS_INSUFFICIENT_RESOURCES
;
247 RtlZeroMemory(AddrFile
, sizeof(ADDRESS_FILE
));
249 AddrFile
->RefCount
= 1;
250 AddrFile
->Free
= AddrFileFree
;
252 /* Set our default options */
256 AddrFile
->HeaderIncl
= 1;
258 /* Make sure address is a local unicast address or 0 */
259 /* FIXME: IPv4 only */
260 AddrFile
->Family
= Address
->Address
[0].AddressType
;
261 AddrFile
->Address
.Address
.IPv4Address
= Address
->Address
[0].Address
[0].in_addr
;
262 AddrFile
->Address
.Type
= IP_ADDRESS_V4
;
264 if (!AddrIsUnspecified(&AddrFile
->Address
) &&
265 !AddrLocateInterface(&AddrFile
->Address
)) {
266 ExFreePoolWithTag(AddrFile
, ADDR_FILE_TAG
);
267 TI_DbgPrint(MIN_TRACE
, ("Non-local address given (0x%X).\n", A2S(&AddrFile
->Address
)));
268 return STATUS_INVALID_ADDRESS
;
271 TI_DbgPrint(MID_TRACE
, ("Opening address %s for communication (P=%d U=%d).\n",
272 A2S(&AddrFile
->Address
), Protocol
, IPPROTO_UDP
));
274 /* Protocol specific handling */
278 TCPAllocatePort(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 ExFreePoolWithTag(AddrFile
, ADDR_FILE_TAG
);
285 return STATUS_ADDRESS_ALREADY_EXISTS
;
288 AddEntity(CO_TL_ENTITY
, AddrFile
, CO_TL_TCP
);
290 AddrFile
->Send
= NULL
; /* TCPSendData */
294 TI_DbgPrint(MID_TRACE
,("Allocating udp port\n"));
296 UDPAllocatePort(Address
->Address
[0].Address
[0].sin_port
);
298 if ((Address
->Address
[0].Address
[0].sin_port
&&
299 AddrFile
->Port
!= Address
->Address
[0].Address
[0].sin_port
) ||
300 AddrFile
->Port
== 0xffff)
302 ExFreePoolWithTag(AddrFile
, ADDR_FILE_TAG
);
303 return STATUS_ADDRESS_ALREADY_EXISTS
;
306 TI_DbgPrint(MID_TRACE
,("Setting port %d (wanted %d)\n",
308 Address
->Address
[0].Address
[0].sin_port
));
310 AddEntity(CL_TL_ENTITY
, AddrFile
, CL_TL_UDP
);
312 AddrFile
->Send
= UDPSendDatagram
;
317 AddrFile
->Send
= ICMPSendDatagram
;
319 /* FIXME: Verify this */
320 AddEntity(ER_ENTITY
, AddrFile
, ER_ICMP
);
324 /* Use raw IP for all other protocols */
326 AddrFile
->Send
= RawIPSendDatagram
;
328 /* FIXME: Verify this */
329 AddEntity(CL_TL_ENTITY
, AddrFile
, 0);
333 TI_DbgPrint(MID_TRACE
, ("IP protocol number for address file object is %d.\n",
336 TI_DbgPrint(MID_TRACE
, ("Port number for address file object is %d.\n",
337 WN2H(AddrFile
->Port
)));
340 AddrFile
->Protocol
= Protocol
;
342 /* Initialize receive and transmit queues */
343 InitializeListHead(&AddrFile
->ReceiveQueue
);
344 InitializeListHead(&AddrFile
->TransmitQueue
);
346 /* Initialize spin lock that protects the address file object */
347 KeInitializeSpinLock(&AddrFile
->Lock
);
349 /* Return address file object */
350 Request
->Handle
.AddressHandle
= AddrFile
;
352 /* Add address file to global list */
353 ExInterlockedInsertTailList(
354 &AddressFileListHead
,
355 &AddrFile
->ListEntry
,
356 &AddressFileListLock
);
358 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
360 return STATUS_SUCCESS
;
365 * FUNCTION: Closes an address file object
367 * Request = Pointer to TDI request structure for this request
369 * Status of operation
371 NTSTATUS
FileCloseAddress(
372 PTDI_REQUEST Request
)
374 PADDRESS_FILE AddrFile
= Request
->Handle
.AddressHandle
;
377 if (!Request
->Handle
.AddressHandle
) return STATUS_INVALID_PARAMETER
;
379 LockObject(AddrFile
, &OldIrql
);
380 /* We have to close this connection because we started it */
381 if( AddrFile
->Listener
)
383 AddrFile
->Listener
->AddressFile
= NULL
;
384 TCPClose( AddrFile
->Listener
);
386 if( AddrFile
->Connection
)
388 AddrFile
->Connection
->AddressFile
= NULL
;
389 DereferenceObject( AddrFile
->Connection
);
391 UnlockObject(AddrFile
, OldIrql
);
393 DereferenceObject(AddrFile
);
395 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
397 return STATUS_SUCCESS
;
402 * FUNCTION: Opens a connection file object
404 * Request = Pointer to TDI request structure for this request
405 * ClientContext = Pointer to client context information
407 * Status of operation
409 NTSTATUS
FileOpenConnection(
410 PTDI_REQUEST Request
,
414 PCONNECTION_ENDPOINT Connection
;
416 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
418 Connection
= TCPAllocateConnectionEndpoint( ClientContext
);
420 if( !Connection
) return STATUS_NO_MEMORY
;
422 Status
= TCPSocket( Connection
, AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
424 if( !NT_SUCCESS(Status
) ) {
425 DereferenceObject( Connection
);
429 /* Return connection endpoint file object */
430 Request
->Handle
.ConnectionContext
= Connection
;
432 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
434 return STATUS_SUCCESS
;
438 * FUNCTION: Closes an connection file object
440 * Request = Pointer to TDI request structure for this request
442 * Status of operation
444 NTSTATUS
FileCloseConnection(
445 PTDI_REQUEST Request
)
447 PCONNECTION_ENDPOINT Connection
;
449 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
451 Connection
= Request
->Handle
.ConnectionContext
;
453 if (!Connection
) return STATUS_INVALID_PARAMETER
;
455 TCPClose( Connection
);
457 Request
->Handle
.ConnectionContext
= NULL
;
459 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
461 return STATUS_SUCCESS
;
465 * FUNCTION: Opens a control channel file object
467 * Request = Pointer to TDI request structure for this request
469 * Status of operation
471 NTSTATUS
FileOpenControlChannel(
472 PTDI_REQUEST Request
)
474 PCONTROL_CHANNEL ControlChannel
;
475 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
477 ControlChannel
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*ControlChannel
),
478 CONTROL_CHANNEL_TAG
);
480 if (!ControlChannel
) {
481 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
482 return STATUS_INSUFFICIENT_RESOURCES
;
485 RtlZeroMemory(ControlChannel
, sizeof(CONTROL_CHANNEL
));
487 /* Make sure address is a local unicast address or 0 */
489 /* Locate address entry. If specified address is 0, a random address is chosen */
491 /* Initialize receive and transmit queues */
492 InitializeListHead(&ControlChannel
->ListEntry
);
494 /* Initialize spin lock that protects the address file object */
495 KeInitializeSpinLock(&ControlChannel
->Lock
);
497 ControlChannel
->RefCount
= 1;
498 ControlChannel
->Free
= ControlChannelFree
;
500 /* Return address file object */
501 Request
->Handle
.ControlChannel
= ControlChannel
;
503 TI_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
505 return STATUS_SUCCESS
;
509 * FUNCTION: Closes a control channel file object
511 * Request = Pointer to TDI request structure for this request
513 * Status of operation
515 NTSTATUS
FileCloseControlChannel(
516 PTDI_REQUEST Request
)
518 if (!Request
->Handle
.ControlChannel
) return STATUS_INVALID_PARAMETER
;
520 DereferenceObject((PCONTROL_CHANNEL
)Request
->Handle
.ControlChannel
);
522 Request
->Handle
.ControlChannel
= NULL
;
524 return STATUS_SUCCESS
;