Merge from amd64-branch:
[reactos.git] / reactos / drivers / network / 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 BOOLEAN AddrIsBroadcast(
47 PIP_ADDRESS PossibleMatch,
48 PIP_ADDRESS TargetAddress ) {
49 IF_LIST_ITER(IF);
50
51 ForEachInterface(IF) {
52 if( AddrIsEqual( &IF->Unicast, PossibleMatch ) &&
53 AddrIsEqual( &IF->Broadcast, TargetAddress ) )
54 return TRUE;
55 } EndFor(IF);
56
57 return FALSE;
58 }
59
60 /*
61 * FUNCTION: Searches through address file entries to find next match
62 * ARGUMENTS:
63 * SearchContext = Pointer to search context
64 * RETURNS:
65 * Pointer to address file, NULL if none was found
66 */
67 PADDRESS_FILE AddrSearchNext(
68 PAF_SEARCH SearchContext)
69 {
70 PLIST_ENTRY CurrentEntry;
71 PIP_ADDRESS IPAddress;
72 KIRQL OldIrql;
73 PADDRESS_FILE Current = NULL;
74 BOOLEAN Found = FALSE;
75
76 if (IsListEmpty(SearchContext->Next))
77 return NULL;
78
79 CurrentEntry = SearchContext->Next;
80
81 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
82
83 while (CurrentEntry != &AddressFileListHead) {
84 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
85
86 IPAddress = &Current->Address;
87
88 TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
89 WN2H(Current->Port),
90 Current->Protocol,
91 A2S(IPAddress),
92 WN2H(SearchContext->Port),
93 SearchContext->Protocol,
94 A2S(SearchContext->Address)));
95
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 */
103 Found = TRUE;
104 break;
105 }
106 CurrentEntry = CurrentEntry->Flink;
107 }
108
109 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
110
111 if (Found) {
112 SearchContext->Next = CurrentEntry->Flink;
113 return Current;
114 } else
115 return NULL;
116 }
117
118 VOID AddrFileFree(
119 PVOID Object)
120 /*
121 * FUNCTION: Frees an address file object
122 * ARGUMENTS:
123 * Object = Pointer to address file object to free
124 */
125 {
126 exFreePool(Object);
127 }
128
129
130 VOID ControlChannelFree(
131 PVOID Object)
132 /*
133 * FUNCTION: Frees an address file object
134 * ARGUMENTS:
135 * Object = Pointer to address file object to free
136 */
137 {
138 exFreePool(Object);
139 }
140
141
142 VOID DeleteAddress(PADDRESS_FILE AddrFile)
143 /*
144 * FUNCTION: Deletes an address file object
145 * ARGUMENTS:
146 * AddrFile = Pointer to address file object to delete
147 */
148 {
149 KIRQL OldIrql;
150 PLIST_ENTRY CurrentEntry;
151 PLIST_ENTRY NextEntry;
152 PDATAGRAM_SEND_REQUEST SendRequest;
153 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
154
155 TI_DbgPrint(MID_TRACE, ("Called.\n"));
156
157 /* Remove address file from the global list */
158 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
159 RemoveEntryList(&AddrFile->ListEntry);
160 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
161
162 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
163
164 /* FIXME: Kill TCP connections on this address file object */
165
166 /* Return pending requests with error */
167
168 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
169
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;
180 }
181
182 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
183
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;
196 }
197
198 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
199
200 (*AddrFile->Free)(AddrFile);
201
202 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
203 }
204
205
206 /*
207 * FUNCTION: Open an address file object
208 * ARGUMENTS:
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
213 * RETURNS:
214 * Status of operation
215 */
216 NTSTATUS FileOpenAddress(
217 PTDI_REQUEST Request,
218 PTA_IP_ADDRESS Address,
219 USHORT Protocol,
220 PVOID Options)
221 {
222 IPv4_RAW_ADDRESS IPv4Address;
223 PADDRESS_FILE AddrFile;
224
225 TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
226
227 AddrFile = exAllocatePool(NonPagedPool, sizeof(ADDRESS_FILE));
228 if (!AddrFile) {
229 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
230 return STATUS_INSUFFICIENT_RESOURCES;
231 }
232
233 TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
234
235 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
236
237 AddrFile->Free = AddrFileFree;
238
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;
248 }
249 else
250 {
251 /* Bound to the default address ... Copy the address type */
252 AddrFile->Address.Type = IP_ADDRESS_V4;
253 }
254
255 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
256 A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
257
258 /* Protocol specific handling */
259 switch (Protocol) {
260 case IPPROTO_TCP:
261 AddrFile->Port =
262 TCPAllocatePort(Address->Address[0].Address[0].sin_port);
263
264 if ((Address->Address[0].Address[0].sin_port &&
265 AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
266 AddrFile->Port == 0xffff)
267 {
268 exFreePool(AddrFile);
269 return STATUS_INVALID_PARAMETER;
270 }
271
272 AddrFile->Send = NULL; /* TCPSendData */
273 break;
274
275 case IPPROTO_UDP:
276 TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
277 AddrFile->Port =
278 UDPAllocatePort(Address->Address[0].Address[0].sin_port);
279
280 if ((Address->Address[0].Address[0].sin_port &&
281 AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
282 AddrFile->Port == 0xffff)
283 {
284 exFreePool(AddrFile);
285 return STATUS_INVALID_PARAMETER;
286 }
287
288 TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n",
289 AddrFile->Port,
290 Address->Address[0].Address[0].sin_port));
291 AddrFile->Send = UDPSendDatagram;
292 break;
293
294 default:
295 /* Use raw IP for all other protocols */
296 AddrFile->Port = 0;
297 AddrFile->Send = RawIPSendDatagram;
298 break;
299 }
300
301 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
302 Protocol));
303
304 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
305 WN2H(AddrFile->Port)));
306
307 /* Set protocol */
308 AddrFile->Protocol = Protocol;
309
310 /* Initialize receive and transmit queues */
311 InitializeListHead(&AddrFile->ReceiveQueue);
312 InitializeListHead(&AddrFile->TransmitQueue);
313
314 /* Initialize spin lock that protects the address file object */
315 KeInitializeSpinLock(&AddrFile->Lock);
316
317 /* Set valid flag so the address can be used */
318 AF_SET_VALID(AddrFile);
319
320 /* Return address file object */
321 Request->Handle.AddressHandle = AddrFile;
322
323 /* Add address file to global list */
324 ExInterlockedInsertTailList(
325 &AddressFileListHead,
326 &AddrFile->ListEntry,
327 &AddressFileListLock);
328
329 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
330
331 return STATUS_SUCCESS;
332 }
333
334
335 /*
336 * FUNCTION: Closes an address file object
337 * ARGUMENTS:
338 * Request = Pointer to TDI request structure for this request
339 * RETURNS:
340 * Status of operation
341 */
342 NTSTATUS FileCloseAddress(
343 PTDI_REQUEST Request)
344 {
345 KIRQL OldIrql;
346 PADDRESS_FILE AddrFile;
347 NTSTATUS Status = STATUS_SUCCESS;
348
349 TI_DbgPrint(MID_TRACE, ("Called.\n"));
350
351 AddrFile = Request->Handle.AddressHandle;
352
353 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
354
355 /* Set address file object exclusive to us */
356 AF_SET_BUSY(AddrFile);
357 AF_CLR_VALID(AddrFile);
358
359 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
360
361 /* Protocol specific handling */
362 switch (AddrFile->Protocol) {
363 case IPPROTO_TCP:
364 TCPFreePort( AddrFile->Port );
365 if( AddrFile->Listener ) {
366 TCPClose( AddrFile->Listener );
367 exFreePool( AddrFile->Listener );
368 }
369 break;
370
371 case IPPROTO_UDP:
372 UDPFreePort( AddrFile->Port );
373 break;
374 }
375
376 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
377
378 return Status;
379 }
380
381
382 /*
383 * FUNCTION: Closes an address file object
384 * ARGUMENTS:
385 * Request = Pointer to TDI request structure for this request
386 * RETURNS:
387 * Status of operation
388 */
389 NTSTATUS FileFreeAddress(
390 PTDI_REQUEST Request)
391 {
392 PADDRESS_FILE AddrFile;
393 NTSTATUS Status = STATUS_SUCCESS;
394
395 AddrFile = Request->Handle.AddressHandle;
396
397 TI_DbgPrint(MID_TRACE, ("Called.\n"));
398
399 DeleteAddress(AddrFile);
400
401 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
402
403 return Status;
404 }
405
406
407 /*
408 * FUNCTION: Opens a connection file object
409 * ARGUMENTS:
410 * Request = Pointer to TDI request structure for this request
411 * ClientContext = Pointer to client context information
412 * RETURNS:
413 * Status of operation
414 */
415 NTSTATUS FileOpenConnection(
416 PTDI_REQUEST Request,
417 PVOID ClientContext)
418 {
419 NTSTATUS Status;
420 PCONNECTION_ENDPOINT Connection;
421
422 TI_DbgPrint(MID_TRACE, ("Called.\n"));
423
424 Connection = TCPAllocateConnectionEndpoint( ClientContext );
425
426 if( !Connection ) return STATUS_NO_MEMORY;
427
428 Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
429
430 if( !NT_SUCCESS(Status) ) {
431 TCPFreeConnectionEndpoint( Connection );
432 return Status;
433 }
434
435 /* Return connection endpoint file object */
436 Request->Handle.ConnectionContext = Connection;
437
438 /* Add connection endpoint to global list */
439 ExInterlockedInsertTailList(
440 &ConnectionEndpointListHead,
441 &Connection->ListEntry,
442 &ConnectionEndpointListLock);
443
444 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
445
446 return STATUS_SUCCESS;
447 }
448
449
450 /*
451 * FUNCTION: Find a connection by examining the context field. This
452 * is needed in some situations where a FIN reply is needed after a
453 * socket is formally broken.
454 * ARGUMENTS:
455 * Request = Pointer to TDI request structure for this request
456 * RETURNS:
457 * Status of operation
458 */
459 PCONNECTION_ENDPOINT FileFindConnectionByContext( PVOID Context ) {
460 PLIST_ENTRY Entry;
461 KIRQL OldIrql;
462 PCONNECTION_ENDPOINT Connection = NULL;
463
464 TcpipAcquireSpinLock( &ConnectionEndpointListLock, &OldIrql );
465
466 for( Entry = ConnectionEndpointListHead.Flink;
467 Entry != &ConnectionEndpointListHead;
468 Entry = Entry->Flink ) {
469 Connection =
470 CONTAINING_RECORD( Entry, CONNECTION_ENDPOINT, ListEntry );
471 if( Connection->SocketContext == Context ) break;
472 else Connection = NULL;
473 }
474
475 TcpipReleaseSpinLock( &ConnectionEndpointListLock, OldIrql );
476
477 return Connection;
478 }
479
480 /*
481 * FUNCTION: Closes an connection file object
482 * ARGUMENTS:
483 * Request = Pointer to TDI request structure for this request
484 * RETURNS:
485 * Status of operation
486 */
487 NTSTATUS FileCloseConnection(
488 PTDI_REQUEST Request)
489 {
490 PCONNECTION_ENDPOINT Connection;
491
492 TI_DbgPrint(MID_TRACE, ("Called.\n"));
493
494 Connection = Request->Handle.ConnectionContext;
495
496 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
497 TCPClose( Connection );
498 TcpipRecursiveMutexLeave( &TCPLock );
499
500 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
501
502 return STATUS_SUCCESS;
503 }
504
505
506 /*
507 * FUNCTION: Frees an connection file object
508 * ARGUMENTS:
509 * Request = Pointer to TDI request structure for this request
510 * RETURNS:
511 * Status of operation
512 */
513 NTSTATUS FileFreeConnection(
514 PTDI_REQUEST Request)
515 {
516 KIRQL OldIrql;
517 PCONNECTION_ENDPOINT Connection;
518
519 TI_DbgPrint(MID_TRACE, ("Called.\n"));
520
521 Connection = Request->Handle.ConnectionContext;
522
523 TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
524 RemoveEntryList(&Connection->ListEntry);
525 TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
526
527 TCPFreeConnectionEndpoint(Connection);
528
529 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
530
531 return STATUS_SUCCESS;
532 }
533
534
535 /*
536 * FUNCTION: Opens a control channel file object
537 * ARGUMENTS:
538 * Request = Pointer to TDI request structure for this request
539 * RETURNS:
540 * Status of operation
541 */
542 NTSTATUS FileOpenControlChannel(
543 PTDI_REQUEST Request)
544 {
545 PCONTROL_CHANNEL ControlChannel;
546 TI_DbgPrint(MID_TRACE, ("Called.\n"));
547
548 ControlChannel = exAllocatePool(NonPagedPool, sizeof(*ControlChannel));
549
550 if (!ControlChannel) {
551 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
552 return STATUS_INSUFFICIENT_RESOURCES;
553 }
554
555 RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
556
557 /* Make sure address is a local unicast address or 0 */
558
559 /* Locate address entry. If specified address is 0, a random address is chosen */
560
561 /* Initialize receive and transmit queues */
562 InitializeListHead(&ControlChannel->ListEntry);
563
564 /* Initialize spin lock that protects the address file object */
565 KeInitializeSpinLock(&ControlChannel->Lock);
566
567 /* Return address file object */
568 Request->Handle.ControlChannel = ControlChannel;
569
570 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
571
572 return STATUS_SUCCESS;
573 }
574
575 /*
576 * FUNCTION: Closes a control channel file object
577 * ARGUMENTS:
578 * Request = Pointer to TDI request structure for this request
579 * RETURNS:
580 * Status of operation
581 */
582 NTSTATUS FileFreeControlChannel(
583 PTDI_REQUEST Request)
584 {
585 PCONTROL_CHANNEL ControlChannel = Request->Handle.ControlChannel;
586 NTSTATUS Status = STATUS_SUCCESS;
587
588 exFreePool(ControlChannel);
589 Request->Handle.ControlChannel = NULL;
590
591 return Status;
592 }
593
594 /* EOF */