- Remove AddrFileEntry from CONNECTION_ENDPOINT. It's no longer needed.
[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 #include <tcpip.h>
11 #include <datagram.h>
12 #include <address.h>
13 #include <pool.h>
14 #include <rawip.h>
15 #include <tcp.h>
16 #include <udp.h>
17 #include <ip.h>
18 #include <fileobjs.h>
19
20 /* List of all address file objects managed by this driver */
21 LIST_ENTRY AddressFileListHead;
22 KSPIN_LOCK AddressFileListLock;
23
24 /* List of all connection endpoint file objects managed by this driver */
25 LIST_ENTRY ConnectionEndpointListHead;
26 KSPIN_LOCK ConnectionEndpointListLock;
27
28
29 VOID AddrFileFree(
30 PVOID Object)
31 /*
32 * FUNCTION: Frees an address file object
33 * ARGUMENTS:
34 * Object = Pointer to address file object to free
35 */
36 {
37 ExFreePool(Object);
38 }
39
40
41 VOID DeleteAddress(
42 PADDRESS_FILE AddrFile)
43 /*
44 * FUNCTION: Deletes an address file object
45 * ARGUMENTS:
46 * AddrFile = Pointer to address file object to delete
47 */
48 {
49 KIRQL OldIrql;
50 PLIST_ENTRY CurrentEntry;
51 PLIST_ENTRY NextEntry;
52 PDATAGRAM_SEND_REQUEST SendRequest;
53 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
54
55 TI_DbgPrint(MID_TRACE, ("Called.\n"));
56
57 /* Remove address file from the global list */
58 KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
59 RemoveEntryList(&AddrFile->ListEntry);
60 KeReleaseSpinLock(&AddressFileListLock, OldIrql);
61
62 KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
63
64 /* FIXME: Kill TCP connections on this address file object */
65
66 /* Return pending requests with error */
67
68 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
69
70 /* Go through pending receive request list and cancel them all */
71 CurrentEntry = AddrFile->ReceiveQueue.Flink;
72 while (CurrentEntry != &AddrFile->ReceiveQueue) {
73 NextEntry = CurrentEntry->Flink;
74 ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
75 /* Abort the request and free its resources */
76 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
77 (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0);
78 ExFreePool(ReceiveRequest);
79 KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
80 CurrentEntry = NextEntry;
81 }
82
83 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
84
85 /* Go through pending send request list and cancel them all */
86 CurrentEntry = AddrFile->TransmitQueue.Flink;
87 while (CurrentEntry != &AddrFile->TransmitQueue) {
88 NextEntry = CurrentEntry->Flink;
89 SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
90 /* Abort the request and free its resources */
91 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
92 (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);
93 ExFreePool(SendRequest);
94 KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
95 CurrentEntry = NextEntry;
96 }
97
98 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
99
100 /* Dereference address entry */
101 DereferenceObject(AddrFile->ADE);
102
103 /* Dereference address cache */
104 if (AddrFile->AddrCache)
105 DereferenceObject(AddrFile->AddrCache);
106
107 #ifdef DBG
108 /* Remove reference provided at creation time */
109 AddrFile->RefCount--;
110
111 if (AddrFile->RefCount != 0)
112 TI_DbgPrint(DEBUG_REFCOUNT, ("AddrFile->RefCount is (%d) (should be 0).\n", AddrFile->RefCount));
113 #endif
114
115 (*AddrFile->Free)(AddrFile);
116
117 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
118 }
119
120
121 /*
122 * FUNCTION: Deletes a connection endpoint file object
123 * ARGUMENTS:
124 * Connection = Pointer to connection endpoint to delete
125 */
126 VOID DeleteConnectionEndpoint(
127 PCONNECTION_ENDPOINT Connection)
128 {
129 KIRQL OldIrql;
130 PLIST_ENTRY CurrentEntry;
131 PLIST_ENTRY NextEntry;
132
133 TI_DbgPrint(MID_TRACE, ("Called.\n"));
134
135 /* Remove connection endpoint from the global list */
136 KeAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
137 RemoveEntryList(&Connection->ListEntry);
138 KeReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
139
140 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
141
142 /* Dereference and remove the address file if it exists */
143 if (Connection->AddressFile) {
144 DereferenceObject(Connection->AddressFile);
145 }
146
147 KeReleaseSpinLock(&Connection->Lock, OldIrql);
148
149 #ifdef DBG
150 /* Remove reference provided at creation time */
151 Connection->RefCount--;
152
153 if (Connection->RefCount != 0)
154 TI_DbgPrint(DEBUG_REFCOUNT, ("Connection->RefCount is (%d) (should be 0).\n",
155 Connection->RefCount));
156 #endif
157
158 ExFreePool(Connection);
159
160 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
161 }
162
163
164 VOID RequestWorker(
165 PVOID Context)
166 /*
167 * FUNCTION: Worker routine for processing address file object requests
168 * ARGUMENTS:
169 * Context = Pointer to context information (ADDRESS_FILE)
170 */
171 {
172 KIRQL OldIrql;
173 PLIST_ENTRY CurrentEntry;
174 PADDRESS_FILE AddrFile = Context;
175
176 TI_DbgPrint(MID_TRACE, ("Called.\n"));
177
178 KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
179
180 /* Check it the address file should be deleted */
181 if (AF_IS_PENDING(AddrFile, AFF_DELETE)) {
182 DATAGRAM_COMPLETION_ROUTINE RtnComplete;
183 PVOID RtnContext;
184
185 RtnComplete = AddrFile->Complete;
186 RtnContext = AddrFile->Context;
187
188 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
189
190 DeleteAddress(AddrFile);
191
192 (*RtnComplete)(RtnContext, TDI_SUCCESS, 0);
193
194 TI_DbgPrint(MAX_TRACE, ("Leaving (delete).\n"));
195
196 return;
197 }
198
199 /* Check if there is a pending send request */
200 if (AF_IS_PENDING(AddrFile, AFF_SEND)) {
201 if (!IsListEmpty(&AddrFile->TransmitQueue)) {
202 PDATAGRAM_SEND_REQUEST SendRequest;
203
204 CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);
205 SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
206
207 AF_CLR_BUSY(AddrFile);
208
209 ReferenceObject(AddrFile);
210
211 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
212
213 /* The send routine processes the send requests in
214 the transmit queue on the address file. When the
215 queue is empty the pending send flag is cleared.
216 The routine may return with the pending send flag
217 set. This can happen if there was not enough free
218 resources available to complete all send requests */
219 DGSend(AddrFile, SendRequest);
220
221 KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
222 DereferenceObject(AddrFile);
223 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
224
225 TI_DbgPrint(MAX_TRACE, ("Leaving (send request).\n"));
226
227 return;
228 } else
229 /* There was a pending send, but no send request.
230 Print a debug message and continue */
231 TI_DbgPrint(MIN_TRACE, ("Pending send, but no send request.\n"));
232 }
233
234 AF_CLR_BUSY(AddrFile);
235
236 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
237
238 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
239 }
240
241
242 /*
243 * FUNCTION: Open an address file object
244 * ARGUMENTS:
245 * Request = Pointer to TDI request structure for this request
246 * Address = Pointer to address to be opened
247 * Protocol = Protocol on which to open the address
248 * Options = Pointer to option buffer
249 * RETURNS:
250 * Status of operation
251 */
252 NTSTATUS FileOpenAddress(
253 PTDI_REQUEST Request,
254 PTA_IP_ADDRESS Address,
255 USHORT Protocol,
256 PVOID Options)
257 {
258 PADDRESS_FILE AddrFile;
259 IPv4_RAW_ADDRESS IPv4Address;
260
261 TI_DbgPrint(MID_TRACE, ("Called.\n"));
262
263 AddrFile = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_FILE));
264 if (!AddrFile) {
265 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
266 return STATUS_INSUFFICIENT_RESOURCES;
267 }
268
269 TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
270
271 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
272
273 AddrFile->Free = AddrFileFree;
274
275 /* Make sure address is a local unicast address or 0 */
276
277 /* Locate address entry. If specified address is 0, a random address is chosen */
278
279 /* FIXME: IPv4 only */
280 IPv4Address = Address->Address[0].Address[0].in_addr;
281 if (IPv4Address == 0)
282 AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST);
283 else
284 AddrFile->ADE = AddrLocateADEv4(IPv4Address);
285
286 if (!AddrFile->ADE) {
287 ExFreePool(AddrFile);
288 TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address)));
289 return STATUS_INVALID_PARAMETER;
290 }
291
292 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication.\n",
293 A2S(AddrFile->ADE->Address)));
294
295 /* Protocol specific handling */
296 switch (Protocol) {
297 case IPPROTO_TCP:
298 /* FIXME: If specified port is 0, a port is chosen dynamically */
299 AddrFile->Port = Address->Address[0].Address[0].sin_port;
300 AddrFile->Send = TCPSendDatagram;
301 break;
302
303 case IPPROTO_UDP:
304 /* FIXME: If specified port is 0, a port is chosen dynamically */
305 AddrFile->Port = Address->Address[0].Address[0].sin_port;
306 AddrFile->Send = UDPSendDatagram;
307 break;
308
309 default:
310 /* Use raw IP for all other protocols */
311 AddrFile->Port = 0;
312 AddrFile->Send = RawIPSendDatagram;
313 break;
314 }
315
316 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
317 Protocol));
318
319 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
320 WN2H(AddrFile->Port)));
321
322 /* Set protocol */
323 AddrFile->Protocol = Protocol;
324
325 /* Initialize receive and transmit queues */
326 InitializeListHead(&AddrFile->ReceiveQueue);
327 InitializeListHead(&AddrFile->TransmitQueue);
328
329 /* Initialize work queue item. We use this for pending requests */
330 ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile);
331
332 /* Initialize spin lock that protects the address file object */
333 KeInitializeSpinLock(&AddrFile->Lock);
334
335 /* Reference the object */
336 AddrFile->RefCount = 1;
337
338 /* Set valid flag so the address can be used */
339 AF_SET_VALID(AddrFile);
340
341 /* Return address file object */
342 Request->Handle.AddressHandle = AddrFile;
343
344 /* Add address file to global list */
345 ExInterlockedInsertTailList(
346 &AddressFileListHead,
347 &AddrFile->ListEntry,
348 &AddressFileListLock);
349
350 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
351
352 return STATUS_SUCCESS;
353 }
354
355
356 /*
357 * FUNCTION: Closes an address file object
358 * ARGUMENTS:
359 * Request = Pointer to TDI request structure for this request
360 * RETURNS:
361 * Status of operation
362 */
363 NTSTATUS FileCloseAddress(
364 PTDI_REQUEST Request)
365 {
366 KIRQL OldIrql;
367 PADDRESS_FILE AddrFile;
368 NTSTATUS Status = STATUS_SUCCESS;
369
370 TI_DbgPrint(MID_TRACE, ("Called.\n"));
371
372 AddrFile = Request->Handle.AddressHandle;
373
374 KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
375
376 if ((!AF_IS_BUSY(AddrFile)) && (AddrFile->RefCount == 1)) {
377 /* Set address file object exclusive to us */
378 AF_SET_BUSY(AddrFile);
379 AF_CLR_VALID(AddrFile);
380
381 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
382
383 DeleteAddress(AddrFile);
384 } else {
385 if (!AF_IS_PENDING(AddrFile, AFF_DELETE)) {
386 AddrFile->Complete = Request->RequestNotifyObject;
387 AddrFile->Context = Request->RequestContext;
388
389 /* Shedule address file for deletion */
390 AF_SET_PENDING(AddrFile, AFF_DELETE);
391 AF_CLR_VALID(AddrFile);
392
393 if (!AF_IS_BUSY(AddrFile)) {
394 /* Worker function is not running, so shedule it to run */
395 AF_SET_BUSY(AddrFile);
396 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
397 ExQueueWorkItem(&AddrFile->WorkItem, CriticalWorkQueue);
398 } else
399 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
400
401 TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
402
403 return STATUS_PENDING;
404 } else
405 Status = STATUS_ADDRESS_CLOSED;
406
407 KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
408 }
409
410 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
411
412 return Status;
413 }
414
415
416 /*
417 * FUNCTION: Opens a connection file object
418 * ARGUMENTS:
419 * Request = Pointer to TDI request structure for this request
420 * ClientContext = Pointer to client context information
421 * RETURNS:
422 * Status of operation
423 */
424 NTSTATUS FileOpenConnection(
425 PTDI_REQUEST Request,
426 PVOID ClientContext)
427 {
428 PCONNECTION_ENDPOINT Connection;
429
430 TI_DbgPrint(MID_TRACE, ("Called.\n"));
431
432 Connection = ExAllocatePool(NonPagedPool, sizeof(CONNECTION_ENDPOINT));
433 if (!Connection)
434 return STATUS_INSUFFICIENT_RESOURCES;
435
436 TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
437
438 RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
439
440 /* Initialize spin lock that protects the connection endpoint file object */
441 KeInitializeSpinLock(&Connection->Lock);
442
443 /* Reference the object */
444 Connection->RefCount = 1;
445
446 /* Put connection in the closed state */
447 Connection->State = ctClosed;
448
449 /* Save client context pointer */
450 Connection->ClientContext = ClientContext;
451
452 /* Return connection endpoint file object */
453 Request->Handle.ConnectionContext = Connection;
454
455 /* Add connection endpoint to global list */
456 ExInterlockedInsertTailList(
457 &ConnectionEndpointListHead,
458 &Connection->ListEntry,
459 &ConnectionEndpointListLock);
460
461 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
462
463 return STATUS_SUCCESS;
464 }
465
466
467 /*
468 * FUNCTION: Closes an connection file object
469 * ARGUMENTS:
470 * Request = Pointer to TDI request structure for this request
471 * RETURNS:
472 * Status of operation
473 */
474 NTSTATUS FileCloseConnection(
475 PTDI_REQUEST Request)
476 {
477 KIRQL OldIrql;
478 PCONNECTION_ENDPOINT Connection;
479 NTSTATUS Status = STATUS_SUCCESS;
480
481 TI_DbgPrint(MID_TRACE, ("Called.\n"));
482
483 Connection = Request->Handle.ConnectionContext;
484
485 #if 0
486 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
487 if ((!AF_IS_BUSY(Connection)) && (Connection->RefCount == 1)) {
488 /* Set connection endpoint file object exclusive to us */
489 AF_SET_BUSY(Connection);
490 AF_CLR_VALID(Connection);
491
492 KeReleaseSpinLock(&Connection->Lock, OldIrql);
493 #endif
494 DeleteConnectionEndpoint(Connection);
495 #if 0
496 } else {
497 if (!AF_IS_PENDING(Connection, AFF_DELETE)) {
498 Connection->Complete = Request->RequestNotifyObject;
499 Connection->Context = Request->RequestContext;
500
501 /* Shedule connection endpoint for deletion */
502 AF_SET_PENDING(Connection, AFF_DELETE);
503 AF_CLR_VALID(Connection);
504
505 if (!AF_IS_BUSY(Connection)) {
506 /* Worker function is not running, so shedule it to run */
507 AF_SET_BUSY(Connection);
508 KeReleaseSpinLock(&Connection->Lock, OldIrql);
509 ExQueueWorkItem(&Connection->WorkItem, CriticalWorkQueue);
510 } else
511 KeReleaseSpinLock(&Connection->Lock, OldIrql);
512
513 TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
514
515 return STATUS_PENDING;
516 } else
517 Status = STATUS_ADDRESS_CLOSED;
518
519 KeReleaseSpinLock(&Connection->Lock, OldIrql);
520 }
521 #endif
522 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
523
524 return Status;
525 }
526
527
528 /*
529 * FUNCTION: Opens a control channel file object
530 * ARGUMENTS:
531 * Request = Pointer to TDI request structure for this request
532 * RETURNS:
533 * Status of operation
534 */
535 NTSTATUS FileOpenControlChannel(
536 PTDI_REQUEST Request)
537 {
538 return STATUS_NOT_IMPLEMENTED;
539 }
540
541
542 /*
543 * FUNCTION: Closes a control channel file object
544 * ARGUMENTS:
545 * Request = Pointer to TDI request structure for this request
546 * RETURNS:
547 * Status of operation
548 */
549 NTSTATUS FileCloseControlChannel(
550 PTDI_REQUEST Request)
551 {
552 return STATUS_NOT_IMPLEMENTED;
553 }
554
555 /* EOF */