Copy msimg32
[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->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 IPv4_RAW_ADDRESS IPv4Address;
230 BOOLEAN Matched;
231 PADDRESS_FILE AddrFile;
232
233 TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
234
235 AddrFile = ExAllocatePool(NonPagedPool, sizeof(ADDRESS_FILE));
236 if (!AddrFile) {
237 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
238 return STATUS_INSUFFICIENT_RESOURCES;
239 }
240
241 TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
242
243 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
244
245 AddrFile->Free = AddrFileFree;
246
247 /* Make sure address is a local unicast address or 0 */
248
249 /* Locate address entry. If specified address is 0, a random address is chosen */
250
251 /* FIXME: IPv4 only */
252 AddrFile->Family = Address->Address[0].AddressType;
253 IPv4Address = Address->Address[0].Address[0].in_addr;
254 if (IPv4Address == 0)
255 Matched = IPGetDefaultAddress(&AddrFile->Address);
256 else
257 Matched = AddrLocateADEv4(IPv4Address, &AddrFile->Address);
258
259 if (!Matched) {
260 ExFreePool(AddrFile);
261 TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address)));
262 return STATUS_INVALID_PARAMETER;
263 }
264
265 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
266 A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
267
268 /* Protocol specific handling */
269 switch (Protocol) {
270 case IPPROTO_TCP:
271 /* FIXME: If specified port is 0, a port is chosen dynamically */
272 AddrFile->Port = TCPAllocatePort(Address->Address[0].Address[0].sin_port);
273 AddrFile->Send = NULL; /* TCPSendData */
274 break;
275
276 case IPPROTO_UDP:
277 TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
278 AddrFile->Port =
279 UDPAllocatePort(Address->Address[0].Address[0].sin_port);
280 TI_DbgPrint(MID_TRACE,("Setting port %d\n", AddrFile->Port));
281 AddrFile->Send = UDPSendDatagram;
282 break;
283
284 default:
285 /* Use raw IP for all other protocols */
286 AddrFile->Port = 0;
287 AddrFile->Send = RawIPSendDatagram;
288 break;
289 }
290
291 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
292 Protocol));
293
294 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
295 WN2H(AddrFile->Port)));
296
297 /* Set protocol */
298 AddrFile->Protocol = Protocol;
299
300 /* Initialize receive and transmit queues */
301 InitializeListHead(&AddrFile->ReceiveQueue);
302 InitializeListHead(&AddrFile->TransmitQueue);
303
304 /* Initialize spin lock that protects the address file object */
305 KeInitializeSpinLock(&AddrFile->Lock);
306
307 /* Set valid flag so the address can be used */
308 AF_SET_VALID(AddrFile);
309
310 /* Return address file object */
311 Request->Handle.AddressHandle = AddrFile;
312
313 /* Add address file to global list */
314 ExInterlockedInsertTailList(
315 &AddressFileListHead,
316 &AddrFile->ListEntry,
317 &AddressFileListLock);
318
319 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
320
321 return STATUS_SUCCESS;
322 }
323
324
325 /*
326 * FUNCTION: Closes an address file object
327 * ARGUMENTS:
328 * Request = Pointer to TDI request structure for this request
329 * RETURNS:
330 * Status of operation
331 */
332 NTSTATUS FileCloseAddress(
333 PTDI_REQUEST Request)
334 {
335 KIRQL OldIrql;
336 PADDRESS_FILE AddrFile;
337 NTSTATUS Status = STATUS_SUCCESS;
338
339 TI_DbgPrint(MID_TRACE, ("Called.\n"));
340
341 AddrFile = Request->Handle.AddressHandle;
342
343 TcpipAcquireSpinLock(&AddrFile->Lock, &OldIrql);
344
345 /* Set address file object exclusive to us */
346 AF_SET_BUSY(AddrFile);
347 AF_CLR_VALID(AddrFile);
348
349 TcpipReleaseSpinLock(&AddrFile->Lock, OldIrql);
350
351 /* Protocol specific handling */
352 switch (AddrFile->Protocol) {
353 case IPPROTO_TCP:
354 TCPFreePort( AddrFile->Port );
355 if( AddrFile->Listener )
356 TCPClose( AddrFile->Listener );
357 break;
358
359 case IPPROTO_UDP:
360 UDPFreePort( AddrFile->Port );
361 break;
362 }
363
364 DeleteAddress(AddrFile);
365
366 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
367
368 return Status;
369 }
370
371
372 /*
373 * FUNCTION: Opens a connection file object
374 * ARGUMENTS:
375 * Request = Pointer to TDI request structure for this request
376 * ClientContext = Pointer to client context information
377 * RETURNS:
378 * Status of operation
379 */
380 NTSTATUS FileOpenConnection(
381 PTDI_REQUEST Request,
382 PVOID ClientContext)
383 {
384 NTSTATUS Status;
385 PCONNECTION_ENDPOINT Connection;
386
387 TI_DbgPrint(MID_TRACE, ("Called.\n"));
388
389 Connection = TCPAllocateConnectionEndpoint( ClientContext );
390
391 if( !Connection ) return STATUS_NO_MEMORY;
392
393 Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
394
395 /* Return connection endpoint file object */
396 Request->Handle.ConnectionContext = Connection;
397
398 /* Add connection endpoint to global list */
399 ExInterlockedInsertTailList(
400 &ConnectionEndpointListHead,
401 &Connection->ListEntry,
402 &ConnectionEndpointListLock);
403
404 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
405
406 return STATUS_SUCCESS;
407 }
408
409
410 /*
411 * FUNCTION: Find a connection by examining the context field. This
412 * is needed in some situations where a FIN reply is needed after a
413 * socket is formally broken.
414 * ARGUMENTS:
415 * Request = Pointer to TDI request structure for this request
416 * RETURNS:
417 * Status of operation
418 */
419 PCONNECTION_ENDPOINT FileFindConnectionByContext( PVOID Context ) {
420 PLIST_ENTRY Entry;
421 KIRQL OldIrql;
422 PCONNECTION_ENDPOINT Connection = NULL;
423
424 TcpipAcquireSpinLock( &ConnectionEndpointListLock, &OldIrql );
425
426 for( Entry = ConnectionEndpointListHead.Flink;
427 Entry != &ConnectionEndpointListHead;
428 Entry = Entry->Flink ) {
429 Connection =
430 CONTAINING_RECORD( Entry, CONNECTION_ENDPOINT, ListEntry );
431 if( Connection->SocketContext == Context ) break;
432 else Connection = NULL;
433 }
434
435 TcpipReleaseSpinLock( &ConnectionEndpointListLock, OldIrql );
436
437 return Connection;
438 }
439
440 /*
441 * FUNCTION: Closes an connection file object
442 * ARGUMENTS:
443 * Request = Pointer to TDI request structure for this request
444 * RETURNS:
445 * Status of operation
446 */
447 NTSTATUS FileCloseConnection(
448 PTDI_REQUEST Request)
449 {
450 PCONNECTION_ENDPOINT Connection;
451 NTSTATUS Status = STATUS_SUCCESS;
452
453 TI_DbgPrint(MID_TRACE, ("Called.\n"));
454
455 Connection = Request->Handle.ConnectionContext;
456
457 TCPClose(Connection);
458 DeleteConnectionEndpoint(Connection);
459
460 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
461
462 return Status;
463 }
464
465
466 /*
467 * FUNCTION: Opens a control channel file object
468 * ARGUMENTS:
469 * Request = Pointer to TDI request structure for this request
470 * RETURNS:
471 * Status of operation
472 */
473 NTSTATUS FileOpenControlChannel(
474 PTDI_REQUEST Request)
475 {
476 PCONTROL_CHANNEL ControlChannel;
477 TI_DbgPrint(MID_TRACE, ("Called.\n"));
478
479 ControlChannel = ExAllocatePool(NonPagedPool, sizeof(*ControlChannel));
480
481 if (!ControlChannel) {
482 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
483 return STATUS_INSUFFICIENT_RESOURCES;
484 }
485
486 RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
487
488 /* Make sure address is a local unicast address or 0 */
489
490 /* Locate address entry. If specified address is 0, a random address is chosen */
491
492 /* Initialize receive and transmit queues */
493 InitializeListHead(&ControlChannel->ListEntry);
494
495 /* Initialize spin lock that protects the address file object */
496 KeInitializeSpinLock(&ControlChannel->Lock);
497
498 /* Return address file object */
499 Request->Handle.ControlChannel = ControlChannel;
500
501 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
502
503 return STATUS_SUCCESS;
504 }
505
506 /*
507 * FUNCTION: Closes a control channel file object
508 * ARGUMENTS:
509 * Request = Pointer to TDI request structure for this request
510 * RETURNS:
511 * Status of operation
512 */
513 NTSTATUS FileCloseControlChannel(
514 PTDI_REQUEST Request)
515 {
516 PCONTROL_CHANNEL ControlChannel = Request->Handle.ControlChannel;
517 NTSTATUS Status = STATUS_SUCCESS;
518
519 ExFreePool(ControlChannel);
520 Request->Handle.ControlChannel = NULL;
521
522 return Status;
523 }
524
525 /* EOF */