- Revert 44301
[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 ExFreePoolWithTag(Object, ADDR_FILE_TAG);
157 }
158
159
160 VOID ControlChannelFree(
161 PVOID Object)
162 /*
163 * FUNCTION: Frees an address file object
164 * ARGUMENTS:
165 * Object = Pointer to address file object to free
166 */
167 {
168 ExFreePoolWithTag(Object, CONTROL_CHANNEL_TAG);
169 }
170
171
172 /*
173 * FUNCTION: Open an address file object
174 * ARGUMENTS:
175 * Request = Pointer to TDI request structure for this request
176 * Address = Pointer to address to be opened
177 * Protocol = Protocol on which to open the address
178 * Options = Pointer to option buffer
179 * RETURNS:
180 * Status of operation
181 */
182 NTSTATUS FileOpenAddress(
183 PTDI_REQUEST Request,
184 PTA_IP_ADDRESS Address,
185 USHORT Protocol,
186 PVOID Options)
187 {
188 PADDRESS_FILE AddrFile;
189
190 TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
191
192 AddrFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(ADDRESS_FILE),
193 ADDR_FILE_TAG);
194 if (!AddrFile) {
195 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
196 return STATUS_INSUFFICIENT_RESOURCES;
197 }
198
199 TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
200
201 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
202
203 AddrFile->Free = AddrFileFree;
204
205 /* Set our default TTL */
206 AddrFile->TTL = 128;
207
208 /* Make sure address is a local unicast address or 0 */
209 /* FIXME: IPv4 only */
210 AddrFile->Family = Address->Address[0].AddressType;
211 AddrFile->Address.Address.IPv4Address = Address->Address[0].Address[0].in_addr;
212 AddrFile->Address.Type = IP_ADDRESS_V4;
213
214 if (!AddrIsUnspecified(&AddrFile->Address) &&
215 !AddrLocateInterface(&AddrFile->Address)) {
216 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
217 TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", A2S(&AddrFile->Address)));
218 return STATUS_INVALID_PARAMETER;
219 }
220
221 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
222 A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
223
224 /* Protocol specific handling */
225 switch (Protocol) {
226 case IPPROTO_TCP:
227 AddrFile->Port =
228 TCPAllocatePort(Address->Address[0].Address[0].sin_port);
229
230 if ((Address->Address[0].Address[0].sin_port &&
231 AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
232 AddrFile->Port == 0xffff)
233 {
234 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
235 return STATUS_INVALID_PARAMETER;
236 }
237
238 AddEntity(CO_TL_ENTITY, AddrFile, CO_TL_TCP);
239
240 AddrFile->Send = NULL; /* TCPSendData */
241 break;
242
243 case IPPROTO_UDP:
244 TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
245 AddrFile->Port =
246 UDPAllocatePort(Address->Address[0].Address[0].sin_port);
247
248 if ((Address->Address[0].Address[0].sin_port &&
249 AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
250 AddrFile->Port == 0xffff)
251 {
252 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
253 return STATUS_INVALID_PARAMETER;
254 }
255
256 TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n",
257 AddrFile->Port,
258 Address->Address[0].Address[0].sin_port));
259
260 AddEntity(CL_TL_ENTITY, AddrFile, CL_TL_UDP);
261
262 AddrFile->Send = UDPSendDatagram;
263 break;
264
265 case IPPROTO_ICMP:
266 AddrFile->Port = 0;
267 AddrFile->Send = ICMPSendDatagram;
268
269 /* FIXME: Verify this */
270 AddEntity(ER_ENTITY, AddrFile, ER_ICMP);
271 break;
272
273 default:
274 /* Use raw IP for all other protocols */
275 AddrFile->Port = 0;
276 AddrFile->Send = RawIPSendDatagram;
277
278 /* FIXME: Verify this */
279 AddEntity(CL_TL_ENTITY, AddrFile, 0);
280 break;
281 }
282
283 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
284 Protocol));
285
286 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
287 WN2H(AddrFile->Port)));
288
289 /* Set protocol */
290 AddrFile->Protocol = Protocol;
291
292 /* Initialize receive and transmit queues */
293 InitializeListHead(&AddrFile->ReceiveQueue);
294 InitializeListHead(&AddrFile->TransmitQueue);
295
296 /* Initialize spin lock that protects the address file object */
297 KeInitializeSpinLock(&AddrFile->Lock);
298
299 /* Return address file object */
300 Request->Handle.AddressHandle = AddrFile;
301
302 /* Add address file to global list */
303 ExInterlockedInsertTailList(
304 &AddressFileListHead,
305 &AddrFile->ListEntry,
306 &AddressFileListLock);
307
308 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
309
310 return STATUS_SUCCESS;
311 }
312
313
314 /*
315 * FUNCTION: Closes an address file object
316 * ARGUMENTS:
317 * Request = Pointer to TDI request structure for this request
318 * RETURNS:
319 * Status of operation
320 */
321 NTSTATUS FileCloseAddress(
322 PTDI_REQUEST Request)
323 {
324 PADDRESS_FILE AddrFile;
325 NTSTATUS Status = STATUS_SUCCESS;
326 KIRQL OldIrql;
327 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
328 PDATAGRAM_SEND_REQUEST SendRequest;
329 PLIST_ENTRY CurrentEntry;
330
331 AddrFile = Request->Handle.AddressHandle;
332
333 TI_DbgPrint(MID_TRACE, ("Called.\n"));
334
335 /* Remove address file from the global list */
336 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
337 RemoveEntryList(&AddrFile->ListEntry);
338 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
339
340 /* FIXME: Kill TCP connections on this address file object */
341
342 /* Return pending requests with error */
343
344 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
345
346 /* Go through pending receive request list and cancel them all */
347 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
348 ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
349 (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_CANCELLED, 0);
350 /* ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG); FIXME: WTF? */
351 }
352
353 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
354
355 /* Go through pending send request list and cancel them all */
356 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
357 SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
358 (*SendRequest->Complete)(SendRequest->Context, STATUS_CANCELLED, 0);
359 ExFreePoolWithTag(SendRequest, DATAGRAM_SEND_TAG);
360 }
361
362 /* Protocol specific handling */
363 switch (AddrFile->Protocol) {
364 case IPPROTO_TCP:
365 TCPFreePort( AddrFile->Port );
366 if( AddrFile->Listener )
367 TCPClose( AddrFile->Listener );
368 break;
369
370 case IPPROTO_UDP:
371 UDPFreePort( AddrFile->Port );
372 break;
373 }
374
375 RemoveEntityByContext(AddrFile);
376
377 (*AddrFile->Free)(AddrFile);
378
379 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
380
381 return Status;
382 }
383
384
385 /*
386 * FUNCTION: Opens a connection file object
387 * ARGUMENTS:
388 * Request = Pointer to TDI request structure for this request
389 * ClientContext = Pointer to client context information
390 * RETURNS:
391 * Status of operation
392 */
393 NTSTATUS FileOpenConnection(
394 PTDI_REQUEST Request,
395 PVOID ClientContext)
396 {
397 NTSTATUS Status;
398 PCONNECTION_ENDPOINT Connection;
399
400 TI_DbgPrint(MID_TRACE, ("Called.\n"));
401
402 Connection = TCPAllocateConnectionEndpoint( ClientContext );
403
404 if( !Connection ) return STATUS_NO_MEMORY;
405
406 Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
407
408 if( !NT_SUCCESS(Status) ) {
409 TCPFreeConnectionEndpoint( Connection );
410 return Status;
411 }
412
413 /* Return connection endpoint file object */
414 Request->Handle.ConnectionContext = Connection;
415
416 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
417
418 return STATUS_SUCCESS;
419 }
420
421 /*
422 * FUNCTION: Closes an connection file object
423 * ARGUMENTS:
424 * Request = Pointer to TDI request structure for this request
425 * RETURNS:
426 * Status of operation
427 */
428 NTSTATUS FileCloseConnection(
429 PTDI_REQUEST Request)
430 {
431 PCONNECTION_ENDPOINT Connection;
432
433 TI_DbgPrint(MID_TRACE, ("Called.\n"));
434
435 Connection = Request->Handle.ConnectionContext;
436
437 TCPClose( Connection );
438
439 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
440
441 return STATUS_SUCCESS;
442 }
443
444
445 /*
446 * FUNCTION: Opens a control channel file object
447 * ARGUMENTS:
448 * Request = Pointer to TDI request structure for this request
449 * RETURNS:
450 * Status of operation
451 */
452 NTSTATUS FileOpenControlChannel(
453 PTDI_REQUEST Request)
454 {
455 PCONTROL_CHANNEL ControlChannel;
456 TI_DbgPrint(MID_TRACE, ("Called.\n"));
457
458 ControlChannel = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ControlChannel),
459 CONTROL_CHANNEL_TAG);
460
461 if (!ControlChannel) {
462 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
463 return STATUS_INSUFFICIENT_RESOURCES;
464 }
465
466 RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
467
468 /* Make sure address is a local unicast address or 0 */
469
470 /* Locate address entry. If specified address is 0, a random address is chosen */
471
472 /* Initialize receive and transmit queues */
473 InitializeListHead(&ControlChannel->ListEntry);
474
475 /* Initialize spin lock that protects the address file object */
476 KeInitializeSpinLock(&ControlChannel->Lock);
477
478 /* Return address file object */
479 Request->Handle.ControlChannel = ControlChannel;
480
481 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
482
483 return STATUS_SUCCESS;
484 }
485
486 /*
487 * FUNCTION: Closes a control channel file object
488 * ARGUMENTS:
489 * Request = Pointer to TDI request structure for this request
490 * RETURNS:
491 * Status of operation
492 */
493 NTSTATUS FileCloseControlChannel(
494 PTDI_REQUEST Request)
495 {
496 PCONTROL_CHANNEL ControlChannel = Request->Handle.ControlChannel;
497 NTSTATUS Status = STATUS_SUCCESS;
498
499 ExFreePoolWithTag(ControlChannel, CONTROL_CHANNEL_TAG);
500 Request->Handle.ControlChannel = NULL;
501
502 return Status;
503 }
504
505 /* EOF */