Removed remaining kernel imports from ip lib.
[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 ExFreePool(ReceiveRequest);
164 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
165 CurrentEntry = NextEntry;
166 }
167
168 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
169
170 /* Go through pending send request list and cancel them all */
171 CurrentEntry = AddrFile->TransmitQueue.Flink;
172 while (CurrentEntry != &AddrFile->TransmitQueue) {
173 NextEntry = CurrentEntry->Flink;
174 SendRequest = CONTAINING_RECORD(CurrentEntry,
175 DATAGRAM_SEND_REQUEST, ListEntry);
176 /* Abort the request and free its resources */
177 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
178 (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);
179 ExFreePool(SendRequest);
180 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
181 CurrentEntry = NextEntry;
182 }
183
184 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
185
186 (*AddrFile->Free)(AddrFile);
187
188 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
189 }
190
191
192 /*
193 * FUNCTION: Deletes a connection endpoint file object
194 * ARGUMENTS:
195 * Connection = Pointer to connection endpoint to delete
196 */
197 VOID DeleteConnectionEndpoint(
198 PCONNECTION_ENDPOINT Connection)
199 {
200 KIRQL OldIrql;
201
202 TI_DbgPrint(MID_TRACE, ("Called.\n"));
203
204 /* Remove connection endpoint from the global list */
205 TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
206 RemoveEntryList(&Connection->ListEntry);
207 TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
208
209 ExFreePool(Connection);
210
211 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
212 }
213
214 #if 0
215 VOID STDCALL RequestWorker(PVOID Context)
216 /*
217 * FUNCTION: Worker routine for processing address file object requests
218 * ARGUMENTS:
219 * Context = Pointer to context information (ADDRESS_FILE)
220 */
221 {
222 KIRQL OldIrql;
223 PLIST_ENTRY CurrentEntry;
224 PADDRESS_FILE AddrFile = Context;
225
226 TI_DbgPrint(MID_TRACE, ("Called.\n"));
227
228 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
229
230 /* Check it the address file should be deleted */
231 if (AF_IS_PENDING(AddrFile, AFF_DELETE)) {
232 DATAGRAM_COMPLETION_ROUTINE RtnComplete;
233 PVOID RtnContext;
234
235 RtnComplete = AddrFile->Complete;
236 RtnContext = AddrFile->Context;
237
238 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
239
240 DeleteAddress(AddrFile);
241
242 (*RtnComplete)(RtnContext, TDI_SUCCESS, 0);
243
244 TI_DbgPrint(MAX_TRACE, ("Leaving (delete).\n"));
245
246 return;
247 }
248
249 /* Check if there is a pending send request */
250 if (AF_IS_PENDING(AddrFile, AFF_SEND)) {
251 if (!IsListEmpty(&AddrFile->TransmitQueue)) {
252 PDATAGRAM_SEND_REQUEST SendRequest;
253
254 CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);
255 SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
256
257 AF_CLR_BUSY(AddrFile);
258
259 ReferenceObject(AddrFile);
260
261 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
262
263 /* The send routine processes the send requests in
264 the transmit queue on the address file. When the
265 queue is empty the pending send flag is cleared.
266 The routine may return with the pending send flag
267 set. This can happen if there was not enough free
268 resources available to complete all send requests */
269 DGSend(AddrFile, SendRequest);
270
271 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
272 DereferenceObject(AddrFile);
273 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
274
275 TI_DbgPrint(MAX_TRACE, ("Leaving (send request).\n"));
276
277 return;
278 } else
279 /* There was a pending send, but no send request.
280 Print a debug message and continue */
281 TI_DbgPrint(MIN_TRACE, ("Pending send, but no send request.\n"));
282 }
283
284 AF_CLR_BUSY(AddrFile);
285
286 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
287
288 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
289 }
290 #endif
291
292 /*
293 * FUNCTION: Open an address file object
294 * ARGUMENTS:
295 * Request = Pointer to TDI request structure for this request
296 * Address = Pointer to address to be opened
297 * Protocol = Protocol on which to open the address
298 * Options = Pointer to option buffer
299 * RETURNS:
300 * Status of operation
301 */
302 NTSTATUS FileOpenAddress(
303 PTDI_REQUEST Request,
304 PTA_IP_ADDRESS Address,
305 USHORT Protocol,
306 PVOID Options)
307 {
308 PADDRESS_FILE AddrFile;
309 IPv4_RAW_ADDRESS IPv4Address;
310
311 TI_DbgPrint(MID_TRACE, ("Called.\n"));
312
313 AddrFile = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_FILE));
314 if (!AddrFile) {
315 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
316 return STATUS_INSUFFICIENT_RESOURCES;
317 }
318
319 TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
320
321 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
322
323 AddrFile->Free = AddrFileFree;
324
325 /* Make sure address is a local unicast address or 0 */
326
327 /* Locate address entry. If specified address is 0, a random address is chosen */
328
329 /* FIXME: IPv4 only */
330 IPv4Address = Address->Address[0].Address[0].in_addr;
331 if (IPv4Address == 0)
332 AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST);
333 else
334 AddrFile->ADE = AddrLocateADEv4(IPv4Address);
335
336 if (!AddrFile->ADE) {
337 ExFreePool(AddrFile);
338 TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address)));
339 return STATUS_INVALID_PARAMETER;
340 }
341
342 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication.\n",
343 A2S(AddrFile->ADE->Address)));
344
345 /* Protocol specific handling */
346 switch (Protocol) {
347 case IPPROTO_TCP:
348 /* FIXME: If specified port is 0, a port is chosen dynamically */
349 AddrFile->Port = Address->Address[0].Address[0].sin_port;
350 AddrFile->Send = NULL; /* TCPSendData */
351 break;
352
353 case IPPROTO_UDP:
354 /* FIXME: If specified port is 0, a port is chosen dynamically */
355 AddrFile->Port = Address->Address[0].Address[0].sin_port;
356 AddrFile->Send = UDPSendDatagram;
357 break;
358
359 default:
360 /* Use raw IP for all other protocols */
361 AddrFile->Port = 0;
362 AddrFile->Send = RawIPSendDatagram;
363 break;
364 }
365
366 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
367 Protocol));
368
369 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
370 WN2H(AddrFile->Port)));
371
372 /* Set protocol */
373 AddrFile->Protocol = Protocol;
374
375 /* Initialize receive and transmit queues */
376 InitializeListHead(&AddrFile->ReceiveQueue);
377 InitializeListHead(&AddrFile->TransmitQueue);
378
379 /* Initialize work queue item. We use this for pending requests */
380 /*ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile);*/
381
382 /* Initialize spin lock that protects the address file object */
383 KeInitializeSpinLock(&AddrFile->Lock);
384
385 /* Set valid flag so the address can be used */
386 AF_SET_VALID(AddrFile);
387
388 /* Return address file object */
389 Request->Handle.AddressHandle = AddrFile;
390
391 /* Add address file to global list */
392 ExInterlockedInsertTailList(
393 &AddressFileListHead,
394 &AddrFile->ListEntry,
395 &AddressFileListLock);
396
397 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
398
399 return STATUS_SUCCESS;
400 }
401
402
403 /*
404 * FUNCTION: Closes an address file object
405 * ARGUMENTS:
406 * Request = Pointer to TDI request structure for this request
407 * RETURNS:
408 * Status of operation
409 */
410 NTSTATUS FileCloseAddress(
411 PTDI_REQUEST Request)
412 {
413 KIRQL OldIrql;
414 PADDRESS_FILE AddrFile;
415 NTSTATUS Status = STATUS_SUCCESS;
416
417 TI_DbgPrint(MID_TRACE, ("Called.\n"));
418
419 AddrFile = Request->Handle.AddressHandle;
420
421 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
422
423 if (!AF_IS_BUSY(AddrFile)) {
424 /* Set address file object exclusive to us */
425 AF_SET_BUSY(AddrFile);
426 AF_CLR_VALID(AddrFile);
427
428 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
429
430 DeleteAddress(AddrFile);
431 } else {
432 if (!AF_IS_PENDING(AddrFile, AFF_DELETE)) {
433 AddrFile->Complete = Request->RequestNotifyObject;
434 AddrFile->Context = Request->RequestContext;
435
436 /* Shedule address file for deletion */
437 AF_SET_PENDING(AddrFile, AFF_DELETE);
438 AF_CLR_VALID(AddrFile);
439
440 if (!AF_IS_BUSY(AddrFile)) {
441 /* Worker function is not running, so shedule it to run */
442 AF_SET_BUSY(AddrFile);
443 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
444 ExQueueWorkItem(&AddrFile->WorkItem, CriticalWorkQueue);
445 } else
446 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
447
448 TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
449
450 return STATUS_PENDING;
451 } else
452 Status = STATUS_ADDRESS_CLOSED;
453
454 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
455 }
456
457 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
458
459 return Status;
460 }
461
462
463 /*
464 * FUNCTION: Opens a connection file object
465 * ARGUMENTS:
466 * Request = Pointer to TDI request structure for this request
467 * ClientContext = Pointer to client context information
468 * RETURNS:
469 * Status of operation
470 */
471 NTSTATUS FileOpenConnection(
472 PTDI_REQUEST Request,
473 PVOID ClientContext)
474 {
475 NTSTATUS Status;
476 PCONNECTION_ENDPOINT Connection;
477
478 TI_DbgPrint(MID_TRACE, ("Called.\n"));
479
480 Connection = TCPAllocateConnectionEndpoint( ClientContext );
481
482 if( !Connection ) return STATUS_NO_MEMORY;
483
484 Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
485 DbgPrint("STATUS from OSKITTCP was %08x\n", Status);
486
487 /* Initialize received segments queue */
488 InitializeListHead(&Connection->ReceivedSegments);
489
490 TI_DbgPrint(MIN_TRACE, ("X1 cur 0x%x\n", &Connection->ReceivedSegments));
491 TI_DbgPrint(MIN_TRACE, ("X1 Flink 0x%x\n", Connection->ReceivedSegments.Flink));
492 TI_DbgPrint(MIN_TRACE, ("X1 Blink 0x%x\n", Connection->ReceivedSegments.Blink));
493
494
495 /* Return connection endpoint file object */
496 Request->Handle.ConnectionContext = Connection;
497
498 /* Add connection endpoint to global list */
499 ExInterlockedInsertTailList(
500 &ConnectionEndpointListHead,
501 &Connection->ListEntry,
502 &ConnectionEndpointListLock);
503
504 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
505
506 return STATUS_SUCCESS;
507 }
508
509
510 /*
511 * FUNCTION: Closes an connection file object
512 * ARGUMENTS:
513 * Request = Pointer to TDI request structure for this request
514 * RETURNS:
515 * Status of operation
516 */
517 NTSTATUS FileCloseConnection(
518 PTDI_REQUEST Request)
519 {
520 PCONNECTION_ENDPOINT Connection;
521 NTSTATUS Status = STATUS_SUCCESS;
522
523 TI_DbgPrint(MID_TRACE, ("Called.\n"));
524
525 Connection = Request->Handle.ConnectionContext;
526
527 TCPClose(Connection);
528 DeleteConnectionEndpoint(Connection);
529
530 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
531
532 return Status;
533 }
534
535
536 /*
537 * FUNCTION: Opens a control channel file object
538 * ARGUMENTS:
539 * Request = Pointer to TDI request structure for this request
540 * RETURNS:
541 * Status of operation
542 */
543 NTSTATUS FileOpenControlChannel(
544 PTDI_REQUEST Request)
545 {
546 PCONTROL_CHANNEL ControlChannel;
547 TI_DbgPrint(MID_TRACE, ("Called.\n"));
548
549 ControlChannel = ExAllocatePool(NonPagedPool, sizeof(*ControlChannel));
550
551 if (!ControlChannel) {
552 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
553 return STATUS_INSUFFICIENT_RESOURCES;
554 }
555
556 RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
557
558 /* Make sure address is a local unicast address or 0 */
559
560 /* Locate address entry. If specified address is 0, a random address is chosen */
561
562 /* Initialize receive and transmit queues */
563 InitializeListHead(&ControlChannel->ListEntry);
564
565 /* Initialize spin lock that protects the address file object */
566 KeInitializeSpinLock(&ControlChannel->Lock);
567
568 /* Return address file object */
569 Request->Handle.ControlChannel = ControlChannel;
570
571 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
572
573 return STATUS_SUCCESS;
574 }
575
576
577 /*
578 * FUNCTION: Closes a control channel file object
579 * ARGUMENTS:
580 * Request = Pointer to TDI request structure for this request
581 * RETURNS:
582 * Status of operation
583 */
584 NTSTATUS FileCloseControlChannel(
585 PTDI_REQUEST Request)
586 {
587 PCONTROL_CHANNEL ControlChannel = Request->Handle.ControlChannel;
588 NTSTATUS Status = STATUS_SUCCESS;
589
590 ExFreePool(ControlChannel);
591 Request->Handle.ControlChannel = NULL;
592
593 return Status;
594 }
595
596 /* EOF */