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