[TCPIP] Don't trust the TEB
[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 /* FIXME: including pstypes.h without ntifs fails */
14 #include <ntifs.h>
15 #include <ndk/pstypes.h>
16
17 /* Uncomment for logging of connections and address files every 10 seconds */
18 //#define LOG_OBJECTS
19
20 /* List of all address file objects managed by this driver */
21 LIST_ENTRY AddressFileListHead;
22 KSPIN_LOCK AddressFileListLock;
23
24 /* List of all connection endpoint file objects managed by this driver */
25 LIST_ENTRY ConnectionEndpointListHead;
26 KSPIN_LOCK ConnectionEndpointListLock;
27
28 /*
29 * FUNCTION: Searches through address file entries to find the first match
30 * ARGUMENTS:
31 * Address = IP address
32 * Port = Port number
33 * Protocol = Protocol number
34 * SearchContext = Pointer to search context
35 * RETURNS:
36 * Pointer to address file, NULL if none was found
37 */
38 PADDRESS_FILE AddrSearchFirst(
39 PIP_ADDRESS Address,
40 USHORT Port,
41 USHORT Protocol,
42 PAF_SEARCH SearchContext)
43 {
44 KIRQL OldIrql;
45
46 SearchContext->Address = Address;
47 SearchContext->Port = Port;
48 SearchContext->Protocol = Protocol;
49
50 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
51
52 SearchContext->Next = AddressFileListHead.Flink;
53
54 if (!IsListEmpty(&AddressFileListHead))
55 ReferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry));
56
57 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
58
59 return AddrSearchNext(SearchContext);
60 }
61
62 BOOLEAN AddrIsBroadcastMatch(
63 PIP_ADDRESS UnicastAddress,
64 PIP_ADDRESS BroadcastAddress ) {
65 IF_LIST_ITER(IF);
66
67 ForEachInterface(IF) {
68 if ((AddrIsUnspecified(UnicastAddress) ||
69 AddrIsEqual(&IF->Unicast, UnicastAddress)) &&
70 (AddrIsEqual(&IF->Broadcast, BroadcastAddress)))
71 return TRUE;
72 } EndFor(IF);
73
74 return FALSE;
75 }
76
77 BOOLEAN AddrReceiveMatch(
78 PIP_ADDRESS LocalAddress,
79 PIP_ADDRESS RemoteAddress)
80 {
81 if (AddrIsEqual(LocalAddress, RemoteAddress))
82 {
83 /* Unicast address match */
84 return TRUE;
85 }
86
87 if (AddrIsBroadcastMatch(LocalAddress, RemoteAddress))
88 {
89 /* Broadcast address match */
90 return TRUE;
91 }
92
93 if (AddrIsUnspecified(LocalAddress))
94 {
95 /* Local address unspecified */
96 return TRUE;
97 }
98
99 if (AddrIsUnspecified(RemoteAddress))
100 {
101 /* Remote address unspecified */
102 return TRUE;
103 }
104
105 return FALSE;
106 }
107
108 VOID
109 LogActiveObjects(VOID)
110 {
111 #ifdef LOG_OBJECTS
112 PLIST_ENTRY CurrentEntry;
113 KIRQL OldIrql;
114 PADDRESS_FILE AddrFile;
115 PCONNECTION_ENDPOINT Conn;
116
117 DbgPrint("----------- TCP/IP Active Object Dump -------------\n");
118
119 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
120
121 CurrentEntry = AddressFileListHead.Flink;
122 while (CurrentEntry != &AddressFileListHead)
123 {
124 AddrFile = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
125
126 DbgPrint("Address File (%s, %d, %d) @ 0x%p | Ref count: %d | Sharers: %d\n",
127 A2S(&AddrFile->Address), WN2H(AddrFile->Port), AddrFile->Protocol,
128 AddrFile, AddrFile->RefCount, AddrFile->Sharers);
129 DbgPrint("\tListener: ");
130 if (AddrFile->Listener == NULL)
131 DbgPrint("<None>\n");
132 else
133 DbgPrint("0x%p\n", AddrFile->Listener);
134 DbgPrint("\tAssociated endpoints: ");
135 if (AddrFile->Connection == NULL)
136 DbgPrint("<None>\n");
137 else
138 {
139 Conn = AddrFile->Connection;
140 while (Conn)
141 {
142 DbgPrint("0x%p ", Conn);
143 Conn = Conn->Next;
144 }
145 DbgPrint("\n");
146 }
147
148 CurrentEntry = CurrentEntry->Flink;
149 }
150
151 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
152
153 TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
154
155 CurrentEntry = ConnectionEndpointListHead.Flink;
156 while (CurrentEntry != &ConnectionEndpointListHead)
157 {
158 Conn = CONTAINING_RECORD(CurrentEntry, CONNECTION_ENDPOINT, ListEntry);
159
160 DbgPrint("Connection @ 0x%p | Ref count: %d\n", Conn, Conn->RefCount);
161 DbgPrint("\tPCB: ");
162 if (Conn->SocketContext == NULL)
163 DbgPrint("<None>\n");
164 else
165 {
166 DbgPrint("0x%p\n", Conn->SocketContext);
167 LibTCPDumpPcb(Conn->SocketContext);
168 }
169 DbgPrint("\tPacket queue status: %s\n", IsListEmpty(&Conn->PacketQueue) ? "Empty" : "Not Empty");
170 DbgPrint("\tRequest lists: Connect: %s | Recv: %s | Send: %s | Shutdown: %s | Listen: %s\n",
171 IsListEmpty(&Conn->ConnectRequest) ? "Empty" : "Not Empty",
172 IsListEmpty(&Conn->ReceiveRequest) ? "Empty" : "Not Empty",
173 IsListEmpty(&Conn->SendRequest) ? "Empty" : "Not Empty",
174 IsListEmpty(&Conn->ShutdownRequest) ? "Empty" : "Not Empty",
175 IsListEmpty(&Conn->ListenRequest) ? "Empty" : "Not Empty");
176 DbgPrint("\tSend shutdown: %s\n", Conn->SendShutdown ? "Yes" : "No");
177 DbgPrint("\tReceive shutdown: %s\n", Conn->ReceiveShutdown ? "Yes" : "No");
178 if (Conn->ReceiveShutdown) DbgPrint("\tReceive shutdown status: 0x%x\n", Conn->ReceiveShutdownStatus);
179 DbgPrint("\tClosing: %s\n", Conn->Closing ? "Yes" : "No");
180
181 CurrentEntry = CurrentEntry->Flink;
182 }
183
184 TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
185
186 DbgPrint("---------------------------------------------------\n");
187 #endif
188 }
189
190 PADDRESS_FILE AddrFindShared(
191 PIP_ADDRESS BindAddress,
192 USHORT Port,
193 USHORT Protocol)
194 {
195 PLIST_ENTRY CurrentEntry;
196 KIRQL OldIrql;
197 PADDRESS_FILE Current = NULL;
198
199 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
200
201 CurrentEntry = AddressFileListHead.Flink;
202 while (CurrentEntry != &AddressFileListHead) {
203 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
204
205 /* See if this address matches the search criteria */
206 if ((Current->Port == Port) &&
207 (Current->Protocol == Protocol))
208 {
209 /* Increase the sharer count */
210 ASSERT(Current->Sharers != 0);
211 InterlockedIncrement(&Current->Sharers);
212 break;
213 }
214
215 CurrentEntry = CurrentEntry->Flink;
216 Current = NULL;
217 }
218
219 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
220
221 return Current;
222 }
223
224 /*
225 * FUNCTION: Searches through address file entries to find next match
226 * ARGUMENTS:
227 * SearchContext = Pointer to search context
228 * RETURNS:
229 * Pointer to referenced address file, NULL if none was found
230 */
231 PADDRESS_FILE AddrSearchNext(
232 PAF_SEARCH SearchContext)
233 {
234 PLIST_ENTRY CurrentEntry;
235 PIP_ADDRESS IPAddress;
236 KIRQL OldIrql;
237 PADDRESS_FILE Current = NULL;
238 BOOLEAN Found = FALSE;
239 PADDRESS_FILE StartingAddrFile;
240
241 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
242
243 if (SearchContext->Next == &AddressFileListHead)
244 {
245 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
246 return NULL;
247 }
248
249 /* Save this pointer so we can dereference it later */
250 StartingAddrFile = CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry);
251
252 CurrentEntry = SearchContext->Next;
253
254 while (CurrentEntry != &AddressFileListHead) {
255 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
256
257 IPAddress = &Current->Address;
258
259 TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
260 WN2H(Current->Port),
261 Current->Protocol,
262 A2S(IPAddress),
263 WN2H(SearchContext->Port),
264 SearchContext->Protocol,
265 A2S(SearchContext->Address)));
266
267 /* See if this address matches the search criteria */
268 if ((Current->Port == SearchContext->Port) &&
269 (Current->Protocol == SearchContext->Protocol) &&
270 (AddrReceiveMatch(IPAddress, SearchContext->Address))) {
271 /* We've found a match */
272 Found = TRUE;
273 break;
274 }
275 CurrentEntry = CurrentEntry->Flink;
276 }
277
278 if (Found)
279 {
280 SearchContext->Next = CurrentEntry->Flink;
281
282 if (SearchContext->Next != &AddressFileListHead)
283 {
284 /* Reference the next address file to prevent the link from disappearing behind our back */
285 ReferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry));
286 }
287
288 /* Reference the returned address file before dereferencing the starting
289 * address file because it may be that Current == StartingAddrFile */
290 ReferenceObject(Current);
291 }
292 else
293 Current = NULL;
294
295 DereferenceObject(StartingAddrFile);
296
297 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
298
299 return Current;
300 }
301
302 VOID AddrFileFree(
303 PVOID Object)
304 /*
305 * FUNCTION: Frees an address file object
306 * ARGUMENTS:
307 * Object = Pointer to address file object to free
308 */
309 {
310 PADDRESS_FILE AddrFile = Object;
311 KIRQL OldIrql;
312 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
313 PDATAGRAM_SEND_REQUEST SendRequest;
314 PLIST_ENTRY CurrentEntry;
315
316 TI_DbgPrint(MID_TRACE, ("Called.\n"));
317
318 /* We should not be associated with a connection here */
319 ASSERT(!AddrFile->Connection);
320
321 /* Remove address file from the global list */
322 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
323 RemoveEntryList(&AddrFile->ListEntry);
324 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
325
326 /* FIXME: Kill TCP connections on this address file object */
327
328 /* Return pending requests with error */
329
330 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
331
332 /* Go through pending receive request list and cancel them all */
333 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
334 ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
335 (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_CANCELLED, 0);
336 /* ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG); FIXME: WTF? */
337 }
338
339 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
340
341 /* Go through pending send request list and cancel them all */
342 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
343 SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
344 (*SendRequest->Complete)(SendRequest->Context, STATUS_CANCELLED, 0);
345 ExFreePoolWithTag(SendRequest, DATAGRAM_SEND_TAG);
346 }
347
348 /* Protocol specific handling */
349 switch (AddrFile->Protocol) {
350 case IPPROTO_TCP:
351 if (AddrFile->Port)
352 {
353 TCPFreePort(AddrFile->Port);
354 }
355 break;
356
357 case IPPROTO_UDP:
358 UDPFreePort( AddrFile->Port );
359 break;
360 }
361
362 RemoveEntityByContext(AddrFile);
363
364 ExFreePoolWithTag(Object, ADDR_FILE_TAG);
365 }
366
367
368 VOID ControlChannelFree(
369 PVOID Object)
370 /*
371 * FUNCTION: Frees an address file object
372 * ARGUMENTS:
373 * Object = Pointer to address file object to free
374 */
375 {
376 ExFreePoolWithTag(Object, CONTROL_CHANNEL_TAG);
377 }
378
379
380 /*
381 * FUNCTION: Open an address file object
382 * ARGUMENTS:
383 * Request = Pointer to TDI request structure for this request
384 * Address = Pointer to address to be opened
385 * Protocol = Protocol on which to open the address
386 * Shared = Specifies if the address is opened for shared access
387 * Options = Pointer to option buffer
388 * RETURNS:
389 * Status of operation
390 */
391 NTSTATUS FileOpenAddress(
392 PTDI_REQUEST Request,
393 PTA_IP_ADDRESS Address,
394 USHORT Protocol,
395 BOOLEAN Shared,
396 PVOID Options)
397 {
398 PADDRESS_FILE AddrFile;
399
400 TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
401
402 /* If it's shared and has a port specified, look for a match */
403 if ((Shared != FALSE) && (Address->Address[0].Address[0].sin_port != 0))
404 {
405 AddrFile = AddrFindShared(NULL, Address->Address[0].Address[0].sin_port, Protocol);
406 if (AddrFile != NULL)
407 {
408 Request->Handle.AddressHandle = AddrFile;
409 return STATUS_SUCCESS;
410 }
411 }
412
413 AddrFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(ADDRESS_FILE),
414 ADDR_FILE_TAG);
415 if (!AddrFile) {
416 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
417 return STATUS_INSUFFICIENT_RESOURCES;
418 }
419
420 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
421
422 AddrFile->RefCount = 1;
423 AddrFile->Free = AddrFileFree;
424 AddrFile->Sharers = 1;
425
426 /* Set our default options */
427 AddrFile->TTL = 128;
428 AddrFile->DF = 0;
429 AddrFile->BCast = 1;
430 AddrFile->HeaderIncl = 1;
431 AddrFile->ProcessId = PsGetCurrentProcessId();
432
433 _SEH2_TRY {
434 PTEB Teb;
435
436 Teb = PsGetCurrentThreadTeb();
437 if (Teb != NULL)
438 AddrFile->SubProcessTag = Teb->SubProcessTag;
439 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
440 AddrFile->SubProcessTag = 0;
441 } _SEH2_END;
442
443 KeQuerySystemTime(&AddrFile->CreationTime);
444
445 /* Make sure address is a local unicast address or 0 */
446 /* FIXME: IPv4 only */
447 AddrFile->Family = Address->Address[0].AddressType;
448 AddrFile->Address.Address.IPv4Address = Address->Address[0].Address[0].in_addr;
449 AddrFile->Address.Type = IP_ADDRESS_V4;
450
451 if (!AddrIsUnspecified(&AddrFile->Address) &&
452 !AddrLocateInterface(&AddrFile->Address)) {
453 TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", A2S(&AddrFile->Address)));
454 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
455 return STATUS_INVALID_ADDRESS;
456 }
457
458 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
459 A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
460
461 /* Protocol specific handling */
462 switch (Protocol) {
463 case IPPROTO_TCP:
464 if (Address->Address[0].Address[0].sin_port)
465 {
466 /* The client specified an explicit port so we force a bind to this */
467 AddrFile->Port = TCPAllocatePort(Address->Address[0].Address[0].sin_port);
468
469 /* Check for bind success */
470 if (AddrFile->Port == 0xffff)
471 {
472 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
473 return STATUS_ADDRESS_ALREADY_EXISTS;
474 }
475
476 /* Sanity check */
477 ASSERT(Address->Address[0].Address[0].sin_port == AddrFile->Port);
478 }
479 else if (!AddrIsUnspecified(&AddrFile->Address))
480 {
481 /* The client is trying to bind to a local address so allocate a port now too */
482 AddrFile->Port = TCPAllocatePort(0);
483
484 /* Check for bind success */
485 if (AddrFile->Port == 0xffff)
486 {
487 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
488 return STATUS_ADDRESS_ALREADY_EXISTS;
489 }
490 }
491 else
492 {
493 /* The client wants an unspecified port with an unspecified address so we wait to see what the TCP library gives us */
494 AddrFile->Port = 0;
495 }
496
497 AddEntity(CO_TL_ENTITY, AddrFile, CO_TL_TCP);
498
499 AddrFile->Send = NULL; /* TCPSendData */
500 break;
501
502 case IPPROTO_UDP:
503 TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
504 AddrFile->Port =
505 UDPAllocatePort(Address->Address[0].Address[0].sin_port);
506
507 if ((Address->Address[0].Address[0].sin_port &&
508 AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
509 AddrFile->Port == 0xffff)
510 {
511 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
512 return STATUS_ADDRESS_ALREADY_EXISTS;
513 }
514
515 TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n",
516 AddrFile->Port,
517 Address->Address[0].Address[0].sin_port));
518
519 AddEntity(CL_TL_ENTITY, AddrFile, CL_TL_UDP);
520
521 AddrFile->Send = UDPSendDatagram;
522 break;
523
524 case IPPROTO_ICMP:
525 AddrFile->Port = 0;
526 AddrFile->Send = ICMPSendDatagram;
527
528 /* FIXME: Verify this */
529 AddEntity(ER_ENTITY, AddrFile, ER_ICMP);
530 break;
531
532 default:
533 /* Use raw IP for all other protocols */
534 AddrFile->Port = 0;
535 AddrFile->Send = RawIPSendDatagram;
536
537 /* FIXME: Verify this */
538 AddEntity(CL_TL_ENTITY, AddrFile, 0);
539 break;
540 }
541
542 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
543 Protocol));
544
545 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
546 WN2H(AddrFile->Port)));
547
548 /* Set protocol */
549 AddrFile->Protocol = Protocol;
550
551 /* Initialize receive and transmit queues */
552 InitializeListHead(&AddrFile->ReceiveQueue);
553 InitializeListHead(&AddrFile->TransmitQueue);
554
555 /* Initialize spin lock that protects the address file object */
556 KeInitializeSpinLock(&AddrFile->Lock);
557
558 /* Return address file object */
559 Request->Handle.AddressHandle = AddrFile;
560
561 /* Add address file to global list */
562 ExInterlockedInsertTailList(
563 &AddressFileListHead,
564 &AddrFile->ListEntry,
565 &AddressFileListLock);
566
567 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
568
569 return STATUS_SUCCESS;
570 }
571
572
573 /*
574 * FUNCTION: Closes an address file object
575 * ARGUMENTS:
576 * Request = Pointer to TDI request structure for this request
577 * RETURNS:
578 * Status of operation
579 */
580 NTSTATUS FileCloseAddress(
581 PTDI_REQUEST Request)
582 {
583 PADDRESS_FILE AddrFile = Request->Handle.AddressHandle;
584 KIRQL OldIrql;
585
586 if (!Request->Handle.AddressHandle) return STATUS_INVALID_PARAMETER;
587
588 LockObject(AddrFile, &OldIrql);
589
590 if (InterlockedDecrement(&AddrFile->Sharers) != 0)
591 {
592 /* Still other guys have open handles to this, so keep it around */
593 UnlockObject(AddrFile, OldIrql);
594 return STATUS_SUCCESS;
595 }
596
597 /* We have to close this listener because we started it */
598 if( AddrFile->Listener )
599 {
600 TCPClose( AddrFile->Listener );
601 }
602
603 UnlockObject(AddrFile, OldIrql);
604
605 DereferenceObject(AddrFile);
606
607 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
608
609 return STATUS_SUCCESS;
610 }
611
612
613 /*
614 * FUNCTION: Opens a connection file object
615 * ARGUMENTS:
616 * Request = Pointer to TDI request structure for this request
617 * ClientContext = Pointer to client context information
618 * RETURNS:
619 * Status of operation
620 */
621 NTSTATUS FileOpenConnection(
622 PTDI_REQUEST Request,
623 PVOID ClientContext)
624 {
625 NTSTATUS Status;
626 PCONNECTION_ENDPOINT Connection;
627
628 TI_DbgPrint(MID_TRACE, ("Called.\n"));
629
630 Connection = TCPAllocateConnectionEndpoint( ClientContext );
631
632 if( !Connection ) return STATUS_NO_MEMORY;
633
634 Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
635
636 if( !NT_SUCCESS(Status) ) {
637 DereferenceObject( Connection );
638 return Status;
639 }
640
641 /* Return connection endpoint file object */
642 Request->Handle.ConnectionContext = Connection;
643
644 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
645
646 return STATUS_SUCCESS;
647 }
648
649 /*
650 * FUNCTION: Closes an connection file object
651 * ARGUMENTS:
652 * Request = Pointer to TDI request structure for this request
653 * RETURNS:
654 * Status of operation
655 */
656 NTSTATUS FileCloseConnection(
657 PTDI_REQUEST Request)
658 {
659 PCONNECTION_ENDPOINT Connection;
660
661 TI_DbgPrint(MID_TRACE, ("Called.\n"));
662
663 Connection = Request->Handle.ConnectionContext;
664
665 if (!Connection) return STATUS_INVALID_PARAMETER;
666
667 TCPClose( Connection );
668
669 Request->Handle.ConnectionContext = NULL;
670
671 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
672
673 return STATUS_SUCCESS;
674 }
675
676 /*
677 * FUNCTION: Opens a control channel file object
678 * ARGUMENTS:
679 * Request = Pointer to TDI request structure for this request
680 * RETURNS:
681 * Status of operation
682 */
683 NTSTATUS FileOpenControlChannel(
684 PTDI_REQUEST Request)
685 {
686 PCONTROL_CHANNEL ControlChannel;
687 TI_DbgPrint(MID_TRACE, ("Called.\n"));
688
689 ControlChannel = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ControlChannel),
690 CONTROL_CHANNEL_TAG);
691
692 if (!ControlChannel) {
693 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
694 return STATUS_INSUFFICIENT_RESOURCES;
695 }
696
697 RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
698
699 /* Make sure address is a local unicast address or 0 */
700
701 /* Locate address entry. If specified address is 0, a random address is chosen */
702
703 /* Initialize receive and transmit queues */
704 InitializeListHead(&ControlChannel->ListEntry);
705
706 /* Initialize spin lock that protects the address file object */
707 KeInitializeSpinLock(&ControlChannel->Lock);
708
709 ControlChannel->RefCount = 1;
710 ControlChannel->Free = ControlChannelFree;
711
712 /* Return address file object */
713 Request->Handle.ControlChannel = ControlChannel;
714
715 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
716
717 return STATUS_SUCCESS;
718 }
719
720 /*
721 * FUNCTION: Closes a control channel file object
722 * ARGUMENTS:
723 * Request = Pointer to TDI request structure for this request
724 * RETURNS:
725 * Status of operation
726 */
727 NTSTATUS FileCloseControlChannel(
728 PTDI_REQUEST Request)
729 {
730 if (!Request->Handle.ControlChannel) return STATUS_INVALID_PARAMETER;
731
732 DereferenceObject((PCONTROL_CHANNEL)Request->Handle.ControlChannel);
733
734 Request->Handle.ControlChannel = NULL;
735
736 return STATUS_SUCCESS;
737 }
738
739 /* EOF */