[TCPIP, IP]
[reactos.git] / 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 AddrIsBroadcastMatch(
47 PIP_ADDRESS UnicastAddress,
48 PIP_ADDRESS BroadcastAddress ) {
49 IF_LIST_ITER(IF);
50
51 ForEachInterface(IF) {
52 if ((AddrIsUnspecified(UnicastAddress) ||
53 AddrIsEqual(&IF->Unicast, UnicastAddress)) &&
54 (AddrIsEqual(&IF->Broadcast, BroadcastAddress)))
55 return TRUE;
56 } EndFor(IF);
57
58 return FALSE;
59 }
60
61 BOOLEAN AddrReceiveMatch(
62 PIP_ADDRESS LocalAddress,
63 PIP_ADDRESS RemoteAddress)
64 {
65 if (AddrIsEqual(LocalAddress, RemoteAddress))
66 {
67 /* Unicast address match */
68 return TRUE;
69 }
70
71 if (AddrIsBroadcastMatch(LocalAddress, RemoteAddress))
72 {
73 /* Broadcast address match */
74 return TRUE;
75 }
76
77 if (AddrIsUnspecified(LocalAddress))
78 {
79 /* Local address unspecified */
80 return TRUE;
81 }
82
83 if (AddrIsUnspecified(RemoteAddress))
84 {
85 /* Remote address unspecified */
86 return TRUE;
87 }
88
89 return FALSE;
90 }
91
92 /*
93 * FUNCTION: Searches through address file entries to find next match
94 * ARGUMENTS:
95 * SearchContext = Pointer to search context
96 * RETURNS:
97 * Pointer to address file, NULL if none was found
98 */
99 PADDRESS_FILE AddrSearchNext(
100 PAF_SEARCH SearchContext)
101 {
102 PLIST_ENTRY CurrentEntry;
103 PIP_ADDRESS IPAddress;
104 KIRQL OldIrql;
105 PADDRESS_FILE Current = NULL;
106 BOOLEAN Found = FALSE;
107
108 if (IsListEmpty(SearchContext->Next))
109 return NULL;
110
111 CurrentEntry = SearchContext->Next;
112
113 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
114
115 while (CurrentEntry != &AddressFileListHead) {
116 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
117
118 IPAddress = &Current->Address;
119
120 TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
121 WN2H(Current->Port),
122 Current->Protocol,
123 A2S(IPAddress),
124 WN2H(SearchContext->Port),
125 SearchContext->Protocol,
126 A2S(SearchContext->Address)));
127
128 /* See if this address matches the search criteria */
129 if ((Current->Port == SearchContext->Port) &&
130 (Current->Protocol == SearchContext->Protocol) &&
131 (AddrReceiveMatch(IPAddress, SearchContext->Address))) {
132 /* We've found a match */
133 Found = TRUE;
134 break;
135 }
136 CurrentEntry = CurrentEntry->Flink;
137 }
138
139 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
140
141 if (Found) {
142 SearchContext->Next = CurrentEntry->Flink;
143 return Current;
144 } else
145 return NULL;
146 }
147
148 VOID AddrFileFree(
149 PVOID Object)
150 /*
151 * FUNCTION: Frees an address file object
152 * ARGUMENTS:
153 * Object = Pointer to address file object to free
154 */
155 {
156 PADDRESS_FILE AddrFile = Object;
157 KIRQL OldIrql;
158 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
159 PDATAGRAM_SEND_REQUEST SendRequest;
160 PLIST_ENTRY CurrentEntry;
161
162 TI_DbgPrint(MID_TRACE, ("Called.\n"));
163
164 /* Remove address file from the global list */
165 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
166 RemoveEntryList(&AddrFile->ListEntry);
167 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
168
169 /* FIXME: Kill TCP connections on this address file object */
170
171 /* Return pending requests with error */
172
173 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
174
175 /* Go through pending receive request list and cancel them all */
176 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
177 ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
178 (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_CANCELLED, 0);
179 /* ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG); FIXME: WTF? */
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 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
186 SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
187 (*SendRequest->Complete)(SendRequest->Context, STATUS_CANCELLED, 0);
188 ExFreePoolWithTag(SendRequest, DATAGRAM_SEND_TAG);
189 }
190
191 /* Protocol specific handling */
192 switch (AddrFile->Protocol) {
193 case IPPROTO_TCP:
194 TCPFreePort( AddrFile->Port );
195 break;
196
197 case IPPROTO_UDP:
198 UDPFreePort( AddrFile->Port );
199 break;
200 }
201
202 RemoveEntityByContext(AddrFile);
203
204 ExFreePoolWithTag(Object, ADDR_FILE_TAG);
205 }
206
207
208 VOID ControlChannelFree(
209 PVOID Object)
210 /*
211 * FUNCTION: Frees an address file object
212 * ARGUMENTS:
213 * Object = Pointer to address file object to free
214 */
215 {
216 ExFreePoolWithTag(Object, CONTROL_CHANNEL_TAG);
217 }
218
219
220 /*
221 * FUNCTION: Open an address file object
222 * ARGUMENTS:
223 * Request = Pointer to TDI request structure for this request
224 * Address = Pointer to address to be opened
225 * Protocol = Protocol on which to open the address
226 * Options = Pointer to option buffer
227 * RETURNS:
228 * Status of operation
229 */
230 NTSTATUS FileOpenAddress(
231 PTDI_REQUEST Request,
232 PTA_IP_ADDRESS Address,
233 USHORT Protocol,
234 PVOID Options)
235 {
236 PADDRESS_FILE AddrFile;
237
238 TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
239
240 AddrFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(ADDRESS_FILE),
241 ADDR_FILE_TAG);
242 if (!AddrFile) {
243 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
244 return STATUS_INSUFFICIENT_RESOURCES;
245 }
246
247 TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
248
249 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
250
251 AddrFile->RefCount = 1;
252 AddrFile->Free = AddrFileFree;
253
254 /* Set our default TTL */
255 AddrFile->TTL = 128;
256
257 /* Make sure address is a local unicast address or 0 */
258 /* FIXME: IPv4 only */
259 AddrFile->Family = Address->Address[0].AddressType;
260 AddrFile->Address.Address.IPv4Address = Address->Address[0].Address[0].in_addr;
261 AddrFile->Address.Type = IP_ADDRESS_V4;
262
263 if (!AddrIsUnspecified(&AddrFile->Address) &&
264 !AddrLocateInterface(&AddrFile->Address)) {
265 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
266 TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", A2S(&AddrFile->Address)));
267 return STATUS_INVALID_PARAMETER;
268 }
269
270 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
271 A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
272
273 /* Protocol specific handling */
274 switch (Protocol) {
275 case IPPROTO_TCP:
276 AddrFile->Port =
277 TCPAllocatePort(Address->Address[0].Address[0].sin_port);
278
279 if ((Address->Address[0].Address[0].sin_port &&
280 AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
281 AddrFile->Port == 0xffff)
282 {
283 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
284 return STATUS_INVALID_PARAMETER;
285 }
286
287 AddEntity(CO_TL_ENTITY, AddrFile, CO_TL_TCP);
288
289 AddrFile->Send = NULL; /* TCPSendData */
290 break;
291
292 case IPPROTO_UDP:
293 TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
294 AddrFile->Port =
295 UDPAllocatePort(Address->Address[0].Address[0].sin_port);
296
297 if ((Address->Address[0].Address[0].sin_port &&
298 AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
299 AddrFile->Port == 0xffff)
300 {
301 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
302 return STATUS_INVALID_PARAMETER;
303 }
304
305 TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n",
306 AddrFile->Port,
307 Address->Address[0].Address[0].sin_port));
308
309 AddEntity(CL_TL_ENTITY, AddrFile, CL_TL_UDP);
310
311 AddrFile->Send = UDPSendDatagram;
312 break;
313
314 case IPPROTO_ICMP:
315 AddrFile->Port = 0;
316 AddrFile->Send = ICMPSendDatagram;
317
318 /* FIXME: Verify this */
319 AddEntity(ER_ENTITY, AddrFile, ER_ICMP);
320 break;
321
322 default:
323 /* Use raw IP for all other protocols */
324 AddrFile->Port = 0;
325 AddrFile->Send = RawIPSendDatagram;
326
327 /* FIXME: Verify this */
328 AddEntity(CL_TL_ENTITY, AddrFile, 0);
329 break;
330 }
331
332 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
333 Protocol));
334
335 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
336 WN2H(AddrFile->Port)));
337
338 /* Set protocol */
339 AddrFile->Protocol = Protocol;
340
341 /* Initialize receive and transmit queues */
342 InitializeListHead(&AddrFile->ReceiveQueue);
343 InitializeListHead(&AddrFile->TransmitQueue);
344
345 /* Initialize spin lock that protects the address file object */
346 KeInitializeSpinLock(&AddrFile->Lock);
347
348 /* Return address file object */
349 Request->Handle.AddressHandle = AddrFile;
350
351 /* Add address file to global list */
352 ExInterlockedInsertTailList(
353 &AddressFileListHead,
354 &AddrFile->ListEntry,
355 &AddressFileListLock);
356
357 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
358
359 return STATUS_SUCCESS;
360 }
361
362
363 /*
364 * FUNCTION: Closes an address file object
365 * ARGUMENTS:
366 * Request = Pointer to TDI request structure for this request
367 * RETURNS:
368 * Status of operation
369 */
370 NTSTATUS FileCloseAddress(
371 PTDI_REQUEST Request)
372 {
373 PADDRESS_FILE AddrFile = Request->Handle.AddressHandle;
374 KIRQL OldIrql;
375
376 if (!Request->Handle.AddressHandle) return STATUS_INVALID_PARAMETER;
377
378 LockObject(AddrFile, &OldIrql);
379 /* We have to close this connection because we started it */
380 if( AddrFile->Listener )
381 TCPClose( AddrFile->Listener );
382 if( AddrFile->Connection )
383 DereferenceObject( AddrFile->Connection );
384 UnlockObject(AddrFile, OldIrql);
385
386 DereferenceObject(AddrFile);
387
388 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
389
390 return STATUS_SUCCESS;
391 }
392
393
394 /*
395 * FUNCTION: Opens a connection file object
396 * ARGUMENTS:
397 * Request = Pointer to TDI request structure for this request
398 * ClientContext = Pointer to client context information
399 * RETURNS:
400 * Status of operation
401 */
402 NTSTATUS FileOpenConnection(
403 PTDI_REQUEST Request,
404 PVOID ClientContext)
405 {
406 NTSTATUS Status;
407 PCONNECTION_ENDPOINT Connection;
408
409 TI_DbgPrint(MID_TRACE, ("Called.\n"));
410
411 Connection = TCPAllocateConnectionEndpoint( ClientContext );
412
413 if( !Connection ) return STATUS_NO_MEMORY;
414
415 Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
416
417 if( !NT_SUCCESS(Status) ) {
418 DereferenceObject( Connection );
419 return Status;
420 }
421
422 /* Return connection endpoint file object */
423 Request->Handle.ConnectionContext = Connection;
424
425 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
426
427 return STATUS_SUCCESS;
428 }
429
430 /*
431 * FUNCTION: Closes an connection file object
432 * ARGUMENTS:
433 * Request = Pointer to TDI request structure for this request
434 * RETURNS:
435 * Status of operation
436 */
437 NTSTATUS FileCloseConnection(
438 PTDI_REQUEST Request)
439 {
440 PCONNECTION_ENDPOINT Connection;
441
442 TI_DbgPrint(MID_TRACE, ("Called.\n"));
443
444 Connection = Request->Handle.ConnectionContext;
445
446 if (!Connection) return STATUS_INVALID_PARAMETER;
447
448 TCPClose( Connection );
449
450 Request->Handle.ConnectionContext = NULL;
451
452 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
453
454 return STATUS_SUCCESS;
455 }
456
457 /*
458 * FUNCTION: Opens a control channel file object
459 * ARGUMENTS:
460 * Request = Pointer to TDI request structure for this request
461 * RETURNS:
462 * Status of operation
463 */
464 NTSTATUS FileOpenControlChannel(
465 PTDI_REQUEST Request)
466 {
467 PCONTROL_CHANNEL ControlChannel;
468 TI_DbgPrint(MID_TRACE, ("Called.\n"));
469
470 ControlChannel = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ControlChannel),
471 CONTROL_CHANNEL_TAG);
472
473 if (!ControlChannel) {
474 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
475 return STATUS_INSUFFICIENT_RESOURCES;
476 }
477
478 RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
479
480 /* Make sure address is a local unicast address or 0 */
481
482 /* Locate address entry. If specified address is 0, a random address is chosen */
483
484 /* Initialize receive and transmit queues */
485 InitializeListHead(&ControlChannel->ListEntry);
486
487 /* Initialize spin lock that protects the address file object */
488 KeInitializeSpinLock(&ControlChannel->Lock);
489
490 ControlChannel->RefCount = 1;
491 ControlChannel->Free = ControlChannelFree;
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 if (!Request->Handle.ControlChannel) return STATUS_INVALID_PARAMETER;
512
513 DereferenceObject((PCONTROL_CHANNEL)Request->Handle.ControlChannel);
514
515 Request->Handle.ControlChannel = NULL;
516
517 return STATUS_SUCCESS;
518 }
519
520 /* EOF */