933c3beea83e014ee9a2e68e583bd873952feec8
[reactos.git] / reactos / drivers / net / tcpip / tcpip / fileobjs.c
1 /*
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)
7 * REVISIONS:
8 * CSH 01/08-2000 Created
9 */
10
11 #include "precomp.h"
12
13
14 /* List of all address file objects managed by this driver */
15 LIST_ENTRY AddressFileListHead;
16 KSPIN_LOCK AddressFileListLock;
17
18 /* List of all connection endpoint file objects managed by this driver */
19 LIST_ENTRY ConnectionEndpointListHead;
20 KSPIN_LOCK ConnectionEndpointListLock;
21
22 /*
23 * FUNCTION: Searches through address file entries to find the first match
24 * ARGUMENTS:
25 * Address = IP address
26 * Port = Port number
27 * Protocol = Protocol number
28 * SearchContext = Pointer to search context
29 * RETURNS:
30 * Pointer to address file, NULL if none was found
31 */
32 PADDRESS_FILE AddrSearchFirst(
33 PIP_ADDRESS Address,
34 USHORT Port,
35 USHORT Protocol,
36 PAF_SEARCH SearchContext)
37 {
38 SearchContext->Address = Address;
39 SearchContext->Port = Port;
40 SearchContext->Next = AddressFileListHead.Flink;
41 SearchContext->Protocol = Protocol;
42
43 return AddrSearchNext(SearchContext);
44 }
45
46 /*
47 * FUNCTION: Searches through address file entries to find next match
48 * ARGUMENTS:
49 * SearchContext = Pointer to search context
50 * RETURNS:
51 * Pointer to address file, NULL if none was found
52 */
53 PADDRESS_FILE AddrSearchNext(
54 PAF_SEARCH SearchContext)
55 {
56 PLIST_ENTRY CurrentEntry;
57 PIP_ADDRESS IPAddress;
58 KIRQL OldIrql;
59 PADDRESS_FILE Current = NULL;
60 BOOLEAN Found = FALSE;
61
62 if (IsListEmpty(SearchContext->Next))
63 return NULL;
64
65 CurrentEntry = SearchContext->Next;
66
67 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
68
69 while (CurrentEntry != &AddressFileListHead) {
70 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
71
72 IPAddress = &Current->ADE->Address;
73
74 TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
75 WN2H(Current->Port),
76 Current->Protocol,
77 A2S(IPAddress),
78 WN2H(SearchContext->Port),
79 SearchContext->Protocol,
80 A2S(SearchContext->Address)));
81
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 */
88 Found = TRUE;
89 break;
90 }
91 CurrentEntry = CurrentEntry->Flink;
92 }
93
94 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
95
96 if (Found) {
97 SearchContext->Next = CurrentEntry->Flink;
98 return Current;
99 } else
100 return NULL;
101 }
102
103 VOID AddrFileFree(
104 PVOID Object)
105 /*
106 * FUNCTION: Frees an address file object
107 * ARGUMENTS:
108 * Object = Pointer to address file object to free
109 */
110 {
111 ExFreePool(Object);
112 }
113
114
115 VOID ControlChannelFree(
116 PVOID Object)
117 /*
118 * FUNCTION: Frees an address file object
119 * ARGUMENTS:
120 * Object = Pointer to address file object to free
121 */
122 {
123 ExFreePool(Object);
124 }
125
126
127 VOID DeleteAddress(PADDRESS_FILE AddrFile)
128 /*
129 * FUNCTION: Deletes an address file object
130 * ARGUMENTS:
131 * AddrFile = Pointer to address file object to delete
132 */
133 {
134 KIRQL OldIrql;
135 PLIST_ENTRY CurrentEntry;
136 PLIST_ENTRY NextEntry;
137 PDATAGRAM_SEND_REQUEST SendRequest;
138 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
139
140 TI_DbgPrint(MID_TRACE, ("Called.\n"));
141
142 /* Remove address file from the global list */
143 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
144 RemoveEntryList(&AddrFile->ListEntry);
145 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
146
147 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
148
149 /* FIXME: Kill TCP connections on this address file object */
150
151 /* Return pending requests with error */
152
153 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
154
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;
165 }
166
167 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
168
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;
181 }
182
183 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
184
185 (*AddrFile->Free)(AddrFile);
186
187 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
188 }
189
190
191 /*
192 * FUNCTION: Deletes a connection endpoint file object
193 * ARGUMENTS:
194 * Connection = Pointer to connection endpoint to delete
195 */
196 VOID DeleteConnectionEndpoint(
197 PCONNECTION_ENDPOINT Connection)
198 {
199 KIRQL OldIrql;
200
201 TI_DbgPrint(MID_TRACE, ("Called.\n"));
202
203 /* Remove connection endpoint from the global list */
204 TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
205 RemoveEntryList(&Connection->ListEntry);
206 TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
207
208 ExFreePool(Connection);
209
210 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
211 }
212
213 /*
214 * FUNCTION: Open an address file object
215 * ARGUMENTS:
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
220 * RETURNS:
221 * Status of operation
222 */
223 NTSTATUS FileOpenAddress(
224 PTDI_REQUEST Request,
225 PTA_IP_ADDRESS Address,
226 USHORT Protocol,
227 PVOID Options)
228 {
229 PADDRESS_FILE AddrFile;
230 IPv4_RAW_ADDRESS IPv4Address;
231
232 TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
233
234 AddrFile = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_FILE));
235 if (!AddrFile) {
236 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
237 return STATUS_INSUFFICIENT_RESOURCES;
238 }
239
240 TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
241
242 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
243
244 AddrFile->Free = AddrFileFree;
245
246 /* Make sure address is a local unicast address or 0 */
247
248 /* Locate address entry. If specified address is 0, a random address is chosen */
249
250 /* FIXME: IPv4 only */
251 IPv4Address = Address->Address[0].Address[0].in_addr;
252 if (IPv4Address == 0)
253 AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST);
254 else
255 AddrFile->ADE = AddrLocateADEv4(IPv4Address);
256
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;
261 }
262
263 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
264 A2S(&AddrFile->ADE->Address), Protocol, IPPROTO_UDP));
265
266 /* Protocol specific handling */
267 switch (Protocol) {
268 case IPPROTO_TCP:
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 */
272 break;
273
274 case IPPROTO_UDP:
275 TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
276 AddrFile->Port =
277 UDPAllocatePort(Address->Address[0].Address[0].sin_port);
278 TI_DbgPrint(MID_TRACE,("Setting port %d\n", AddrFile->Port));
279 AddrFile->Send = UDPSendDatagram;
280 break;
281
282 default:
283 /* Use raw IP for all other protocols */
284 AddrFile->Port = 0;
285 AddrFile->Send = RawIPSendDatagram;
286 break;
287 }
288
289 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
290 Protocol));
291
292 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
293 WN2H(AddrFile->Port)));
294
295 /* Set protocol */
296 AddrFile->Protocol = Protocol;
297
298 /* Initialize receive and transmit queues */
299 InitializeListHead(&AddrFile->ReceiveQueue);
300 InitializeListHead(&AddrFile->TransmitQueue);
301
302 /* Initialize spin lock that protects the address file object */
303 KeInitializeSpinLock(&AddrFile->Lock);
304
305 /* Set valid flag so the address can be used */
306 AF_SET_VALID(AddrFile);
307
308 /* Return address file object */
309 Request->Handle.AddressHandle = AddrFile;
310
311 /* Add address file to global list */
312 ExInterlockedInsertTailList(
313 &AddressFileListHead,
314 &AddrFile->ListEntry,
315 &AddressFileListLock);
316
317 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
318
319 return STATUS_SUCCESS;
320 }
321
322
323 /*
324 * FUNCTION: Closes an address file object
325 * ARGUMENTS:
326 * Request = Pointer to TDI request structure for this request
327 * RETURNS:
328 * Status of operation
329 */
330 NTSTATUS FileCloseAddress(
331 PTDI_REQUEST Request)
332 {
333 KIRQL OldIrql;
334 PADDRESS_FILE AddrFile;
335 NTSTATUS Status = STATUS_SUCCESS;
336
337 TI_DbgPrint(MID_TRACE, ("Called.\n"));
338
339 AddrFile = Request->Handle.AddressHandle;
340
341 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
342
343 /* Set address file object exclusive to us */
344 AF_SET_BUSY(AddrFile);
345 AF_CLR_VALID(AddrFile);
346
347 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
348 UDPFreePort( AddrFile->Port );
349
350 DeleteAddress(AddrFile);
351
352 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
353
354 return Status;
355 }
356
357
358 /*
359 * FUNCTION: Opens a connection file object
360 * ARGUMENTS:
361 * Request = Pointer to TDI request structure for this request
362 * ClientContext = Pointer to client context information
363 * RETURNS:
364 * Status of operation
365 */
366 NTSTATUS FileOpenConnection(
367 PTDI_REQUEST Request,
368 PVOID ClientContext)
369 {
370 NTSTATUS Status;
371 PCONNECTION_ENDPOINT Connection;
372
373 TI_DbgPrint(MID_TRACE, ("Called.\n"));
374
375 Connection = TCPAllocateConnectionEndpoint( ClientContext );
376
377 if( !Connection ) return STATUS_NO_MEMORY;
378
379 Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
380 DbgPrint("STATUS from OSKITTCP was %08x\n", Status);
381
382 /* Initialize received segments queue */
383 InitializeListHead(&Connection->ReceivedSegments);
384
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));
388
389
390 /* Return connection endpoint file object */
391 Request->Handle.ConnectionContext = Connection;
392
393 /* Add connection endpoint to global list */
394 ExInterlockedInsertTailList(
395 &ConnectionEndpointListHead,
396 &Connection->ListEntry,
397 &ConnectionEndpointListLock);
398
399 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
400
401 return STATUS_SUCCESS;
402 }
403
404
405 /*
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.
409 * ARGUMENTS:
410 * Request = Pointer to TDI request structure for this request
411 * RETURNS:
412 * Status of operation
413 */
414 PCONNECTION_ENDPOINT FileFindConnectionByContext( PVOID Context ) {
415 PLIST_ENTRY Entry;
416 KIRQL OldIrql;
417 PCONNECTION_ENDPOINT Connection = NULL;
418
419 KeAcquireSpinLock( &ConnectionEndpointListLock, &OldIrql );
420
421 for( Entry = ConnectionEndpointListHead.Flink;
422 Entry != &ConnectionEndpointListHead;
423 Entry = Entry->Flink ) {
424 Connection =
425 CONTAINING_RECORD( Entry, CONNECTION_ENDPOINT, ListEntry );
426 if( Connection->SocketContext == Context ) break;
427 else Connection = NULL;
428 }
429
430 KeReleaseSpinLock( &ConnectionEndpointListLock, OldIrql );
431
432 return Connection;
433 }
434
435 /*
436 * FUNCTION: Closes an connection file object
437 * ARGUMENTS:
438 * Request = Pointer to TDI request structure for this request
439 * RETURNS:
440 * Status of operation
441 */
442 NTSTATUS FileCloseConnection(
443 PTDI_REQUEST Request)
444 {
445 PCONNECTION_ENDPOINT Connection;
446 NTSTATUS Status = STATUS_SUCCESS;
447
448 TI_DbgPrint(MID_TRACE, ("Called.\n"));
449
450 Connection = Request->Handle.ConnectionContext;
451
452 TCPClose(Connection);
453 DeleteConnectionEndpoint(Connection);
454
455 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
456
457 return Status;
458 }
459
460
461 /*
462 * FUNCTION: Opens a control channel file object
463 * ARGUMENTS:
464 * Request = Pointer to TDI request structure for this request
465 * RETURNS:
466 * Status of operation
467 */
468 NTSTATUS FileOpenControlChannel(
469 PTDI_REQUEST Request)
470 {
471 PCONTROL_CHANNEL ControlChannel;
472 TI_DbgPrint(MID_TRACE, ("Called.\n"));
473
474 ControlChannel = ExAllocatePool(NonPagedPool, sizeof(*ControlChannel));
475
476 if (!ControlChannel) {
477 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
478 return STATUS_INSUFFICIENT_RESOURCES;
479 }
480
481 RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
482
483 /* Make sure address is a local unicast address or 0 */
484
485 /* Locate address entry. If specified address is 0, a random address is chosen */
486
487 /* Initialize receive and transmit queues */
488 InitializeListHead(&ControlChannel->ListEntry);
489
490 /* Initialize spin lock that protects the address file object */
491 KeInitializeSpinLock(&ControlChannel->Lock);
492
493 /* Return address file object */
494 Request->Handle.ControlChannel = ControlChannel;
495
496 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
497
498 return STATUS_SUCCESS;
499 }
500
501 /*
502 * FUNCTION: Closes a control channel file object
503 * ARGUMENTS:
504 * Request = Pointer to TDI request structure for this request
505 * RETURNS:
506 * Status of operation
507 */
508 NTSTATUS FileCloseControlChannel(
509 PTDI_REQUEST Request)
510 {
511 PCONTROL_CHANNEL ControlChannel = Request->Handle.ControlChannel;
512 NTSTATUS Status = STATUS_SUCCESS;
513
514 ExFreePool(ControlChannel);
515 Request->Handle.ControlChannel = NULL;
516
517 return Status;
518 }
519
520 /* EOF */