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