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