[TCPIP] Save the date when an ADDRESS_FILE is created
[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 referenced 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 PADDRESS_FILE StartingAddrFile;
236
237 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
238
239 if (SearchContext->Next == &AddressFileListHead)
240 {
241 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
242 return NULL;
243 }
244
245 /* Save this pointer so we can dereference it later */
246 StartingAddrFile = CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry);
247
248 CurrentEntry = SearchContext->Next;
249
250 while (CurrentEntry != &AddressFileListHead) {
251 Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
252
253 IPAddress = &Current->Address;
254
255 TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
256 WN2H(Current->Port),
257 Current->Protocol,
258 A2S(IPAddress),
259 WN2H(SearchContext->Port),
260 SearchContext->Protocol,
261 A2S(SearchContext->Address)));
262
263 /* See if this address matches the search criteria */
264 if ((Current->Port == SearchContext->Port) &&
265 (Current->Protocol == SearchContext->Protocol) &&
266 (AddrReceiveMatch(IPAddress, SearchContext->Address))) {
267 /* We've found a match */
268 Found = TRUE;
269 break;
270 }
271 CurrentEntry = CurrentEntry->Flink;
272 }
273
274 if (Found)
275 {
276 SearchContext->Next = CurrentEntry->Flink;
277
278 if (SearchContext->Next != &AddressFileListHead)
279 {
280 /* Reference the next address file to prevent the link from disappearing behind our back */
281 ReferenceObject(CONTAINING_RECORD(SearchContext->Next, ADDRESS_FILE, ListEntry));
282 }
283
284 /* Reference the returned address file before dereferencing the starting
285 * address file because it may be that Current == StartingAddrFile */
286 ReferenceObject(Current);
287 }
288 else
289 Current = NULL;
290
291 DereferenceObject(StartingAddrFile);
292
293 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
294
295 return Current;
296 }
297
298 VOID AddrFileFree(
299 PVOID Object)
300 /*
301 * FUNCTION: Frees an address file object
302 * ARGUMENTS:
303 * Object = Pointer to address file object to free
304 */
305 {
306 PADDRESS_FILE AddrFile = Object;
307 KIRQL OldIrql;
308 PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
309 PDATAGRAM_SEND_REQUEST SendRequest;
310 PLIST_ENTRY CurrentEntry;
311
312 TI_DbgPrint(MID_TRACE, ("Called.\n"));
313
314 /* We should not be associated with a connection here */
315 ASSERT(!AddrFile->Connection);
316
317 /* Remove address file from the global list */
318 TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
319 RemoveEntryList(&AddrFile->ListEntry);
320 TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
321
322 /* FIXME: Kill TCP connections on this address file object */
323
324 /* Return pending requests with error */
325
326 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
327
328 /* Go through pending receive request list and cancel them all */
329 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
330 ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
331 (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_CANCELLED, 0);
332 /* ExFreePoolWithTag(ReceiveRequest, DATAGRAM_RECV_TAG); FIXME: WTF? */
333 }
334
335 TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
336
337 /* Go through pending send request list and cancel them all */
338 while ((CurrentEntry = ExInterlockedRemoveHeadList(&AddrFile->ReceiveQueue, &AddrFile->Lock))) {
339 SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
340 (*SendRequest->Complete)(SendRequest->Context, STATUS_CANCELLED, 0);
341 ExFreePoolWithTag(SendRequest, DATAGRAM_SEND_TAG);
342 }
343
344 /* Protocol specific handling */
345 switch (AddrFile->Protocol) {
346 case IPPROTO_TCP:
347 if (AddrFile->Port)
348 {
349 TCPFreePort(AddrFile->Port);
350 }
351 break;
352
353 case IPPROTO_UDP:
354 UDPFreePort( AddrFile->Port );
355 break;
356 }
357
358 RemoveEntityByContext(AddrFile);
359
360 ExFreePoolWithTag(Object, ADDR_FILE_TAG);
361 }
362
363
364 VOID ControlChannelFree(
365 PVOID Object)
366 /*
367 * FUNCTION: Frees an address file object
368 * ARGUMENTS:
369 * Object = Pointer to address file object to free
370 */
371 {
372 ExFreePoolWithTag(Object, CONTROL_CHANNEL_TAG);
373 }
374
375
376 /*
377 * FUNCTION: Open an address file object
378 * ARGUMENTS:
379 * Request = Pointer to TDI request structure for this request
380 * Address = Pointer to address to be opened
381 * Protocol = Protocol on which to open the address
382 * Shared = Specifies if the address is opened for shared access
383 * Options = Pointer to option buffer
384 * RETURNS:
385 * Status of operation
386 */
387 NTSTATUS FileOpenAddress(
388 PTDI_REQUEST Request,
389 PTA_IP_ADDRESS Address,
390 USHORT Protocol,
391 BOOLEAN Shared,
392 PVOID Options)
393 {
394 PADDRESS_FILE AddrFile;
395
396 TI_DbgPrint(MID_TRACE, ("Called (Proto %d).\n", Protocol));
397
398 /* If it's shared and has a port specified, look for a match */
399 if ((Shared != FALSE) && (Address->Address[0].Address[0].sin_port != 0))
400 {
401 AddrFile = AddrFindShared(NULL, Address->Address[0].Address[0].sin_port, Protocol);
402 if (AddrFile != NULL)
403 {
404 Request->Handle.AddressHandle = AddrFile;
405 return STATUS_SUCCESS;
406 }
407 }
408
409 AddrFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(ADDRESS_FILE),
410 ADDR_FILE_TAG);
411 if (!AddrFile) {
412 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
413 return STATUS_INSUFFICIENT_RESOURCES;
414 }
415
416 RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
417
418 AddrFile->RefCount = 1;
419 AddrFile->Free = AddrFileFree;
420 AddrFile->Sharers = 1;
421
422 /* Set our default options */
423 AddrFile->TTL = 128;
424 AddrFile->DF = 0;
425 AddrFile->BCast = 1;
426 AddrFile->HeaderIncl = 1;
427 AddrFile->ProcessId = PsGetCurrentProcessId();
428 KeQuerySystemTime(&AddrFile->CreationTime);
429
430 /* Make sure address is a local unicast address or 0 */
431 /* FIXME: IPv4 only */
432 AddrFile->Family = Address->Address[0].AddressType;
433 AddrFile->Address.Address.IPv4Address = Address->Address[0].Address[0].in_addr;
434 AddrFile->Address.Type = IP_ADDRESS_V4;
435
436 if (!AddrIsUnspecified(&AddrFile->Address) &&
437 !AddrLocateInterface(&AddrFile->Address)) {
438 TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", A2S(&AddrFile->Address)));
439 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
440 return STATUS_INVALID_ADDRESS;
441 }
442
443 TI_DbgPrint(MID_TRACE, ("Opening address %s for communication (P=%d U=%d).\n",
444 A2S(&AddrFile->Address), Protocol, IPPROTO_UDP));
445
446 /* Protocol specific handling */
447 switch (Protocol) {
448 case IPPROTO_TCP:
449 if (Address->Address[0].Address[0].sin_port)
450 {
451 /* The client specified an explicit port so we force a bind to this */
452 AddrFile->Port = TCPAllocatePort(Address->Address[0].Address[0].sin_port);
453
454 /* Check for bind success */
455 if (AddrFile->Port == 0xffff)
456 {
457 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
458 return STATUS_ADDRESS_ALREADY_EXISTS;
459 }
460
461 /* Sanity check */
462 ASSERT(Address->Address[0].Address[0].sin_port == AddrFile->Port);
463 }
464 else if (!AddrIsUnspecified(&AddrFile->Address))
465 {
466 /* The client is trying to bind to a local address so allocate a port now too */
467 AddrFile->Port = TCPAllocatePort(0);
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 else
477 {
478 /* The client wants an unspecified port with an unspecified address so we wait to see what the TCP library gives us */
479 AddrFile->Port = 0;
480 }
481
482 AddEntity(CO_TL_ENTITY, AddrFile, CO_TL_TCP);
483
484 AddrFile->Send = NULL; /* TCPSendData */
485 break;
486
487 case IPPROTO_UDP:
488 TI_DbgPrint(MID_TRACE,("Allocating udp port\n"));
489 AddrFile->Port =
490 UDPAllocatePort(Address->Address[0].Address[0].sin_port);
491
492 if ((Address->Address[0].Address[0].sin_port &&
493 AddrFile->Port != Address->Address[0].Address[0].sin_port) ||
494 AddrFile->Port == 0xffff)
495 {
496 ExFreePoolWithTag(AddrFile, ADDR_FILE_TAG);
497 return STATUS_ADDRESS_ALREADY_EXISTS;
498 }
499
500 TI_DbgPrint(MID_TRACE,("Setting port %d (wanted %d)\n",
501 AddrFile->Port,
502 Address->Address[0].Address[0].sin_port));
503
504 AddEntity(CL_TL_ENTITY, AddrFile, CL_TL_UDP);
505
506 AddrFile->Send = UDPSendDatagram;
507 break;
508
509 case IPPROTO_ICMP:
510 AddrFile->Port = 0;
511 AddrFile->Send = ICMPSendDatagram;
512
513 /* FIXME: Verify this */
514 AddEntity(ER_ENTITY, AddrFile, ER_ICMP);
515 break;
516
517 default:
518 /* Use raw IP for all other protocols */
519 AddrFile->Port = 0;
520 AddrFile->Send = RawIPSendDatagram;
521
522 /* FIXME: Verify this */
523 AddEntity(CL_TL_ENTITY, AddrFile, 0);
524 break;
525 }
526
527 TI_DbgPrint(MID_TRACE, ("IP protocol number for address file object is %d.\n",
528 Protocol));
529
530 TI_DbgPrint(MID_TRACE, ("Port number for address file object is %d.\n",
531 WN2H(AddrFile->Port)));
532
533 /* Set protocol */
534 AddrFile->Protocol = Protocol;
535
536 /* Initialize receive and transmit queues */
537 InitializeListHead(&AddrFile->ReceiveQueue);
538 InitializeListHead(&AddrFile->TransmitQueue);
539
540 /* Initialize spin lock that protects the address file object */
541 KeInitializeSpinLock(&AddrFile->Lock);
542
543 /* Return address file object */
544 Request->Handle.AddressHandle = AddrFile;
545
546 /* Add address file to global list */
547 ExInterlockedInsertTailList(
548 &AddressFileListHead,
549 &AddrFile->ListEntry,
550 &AddressFileListLock);
551
552 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
553
554 return STATUS_SUCCESS;
555 }
556
557
558 /*
559 * FUNCTION: Closes an address file object
560 * ARGUMENTS:
561 * Request = Pointer to TDI request structure for this request
562 * RETURNS:
563 * Status of operation
564 */
565 NTSTATUS FileCloseAddress(
566 PTDI_REQUEST Request)
567 {
568 PADDRESS_FILE AddrFile = Request->Handle.AddressHandle;
569 KIRQL OldIrql;
570
571 if (!Request->Handle.AddressHandle) return STATUS_INVALID_PARAMETER;
572
573 LockObject(AddrFile, &OldIrql);
574
575 if (InterlockedDecrement(&AddrFile->Sharers) != 0)
576 {
577 /* Still other guys have open handles to this, so keep it around */
578 UnlockObject(AddrFile, OldIrql);
579 return STATUS_SUCCESS;
580 }
581
582 /* We have to close this listener because we started it */
583 if( AddrFile->Listener )
584 {
585 TCPClose( AddrFile->Listener );
586 }
587
588 UnlockObject(AddrFile, OldIrql);
589
590 DereferenceObject(AddrFile);
591
592 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
593
594 return STATUS_SUCCESS;
595 }
596
597
598 /*
599 * FUNCTION: Opens a connection file object
600 * ARGUMENTS:
601 * Request = Pointer to TDI request structure for this request
602 * ClientContext = Pointer to client context information
603 * RETURNS:
604 * Status of operation
605 */
606 NTSTATUS FileOpenConnection(
607 PTDI_REQUEST Request,
608 PVOID ClientContext)
609 {
610 NTSTATUS Status;
611 PCONNECTION_ENDPOINT Connection;
612
613 TI_DbgPrint(MID_TRACE, ("Called.\n"));
614
615 Connection = TCPAllocateConnectionEndpoint( ClientContext );
616
617 if( !Connection ) return STATUS_NO_MEMORY;
618
619 Status = TCPSocket( Connection, AF_INET, SOCK_STREAM, IPPROTO_TCP );
620
621 if( !NT_SUCCESS(Status) ) {
622 DereferenceObject( Connection );
623 return Status;
624 }
625
626 /* Return connection endpoint file object */
627 Request->Handle.ConnectionContext = Connection;
628
629 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
630
631 return STATUS_SUCCESS;
632 }
633
634 /*
635 * FUNCTION: Closes an connection file object
636 * ARGUMENTS:
637 * Request = Pointer to TDI request structure for this request
638 * RETURNS:
639 * Status of operation
640 */
641 NTSTATUS FileCloseConnection(
642 PTDI_REQUEST Request)
643 {
644 PCONNECTION_ENDPOINT Connection;
645
646 TI_DbgPrint(MID_TRACE, ("Called.\n"));
647
648 Connection = Request->Handle.ConnectionContext;
649
650 if (!Connection) return STATUS_INVALID_PARAMETER;
651
652 TCPClose( Connection );
653
654 Request->Handle.ConnectionContext = NULL;
655
656 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
657
658 return STATUS_SUCCESS;
659 }
660
661 /*
662 * FUNCTION: Opens a control channel file object
663 * ARGUMENTS:
664 * Request = Pointer to TDI request structure for this request
665 * RETURNS:
666 * Status of operation
667 */
668 NTSTATUS FileOpenControlChannel(
669 PTDI_REQUEST Request)
670 {
671 PCONTROL_CHANNEL ControlChannel;
672 TI_DbgPrint(MID_TRACE, ("Called.\n"));
673
674 ControlChannel = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ControlChannel),
675 CONTROL_CHANNEL_TAG);
676
677 if (!ControlChannel) {
678 TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
679 return STATUS_INSUFFICIENT_RESOURCES;
680 }
681
682 RtlZeroMemory(ControlChannel, sizeof(CONTROL_CHANNEL));
683
684 /* Make sure address is a local unicast address or 0 */
685
686 /* Locate address entry. If specified address is 0, a random address is chosen */
687
688 /* Initialize receive and transmit queues */
689 InitializeListHead(&ControlChannel->ListEntry);
690
691 /* Initialize spin lock that protects the address file object */
692 KeInitializeSpinLock(&ControlChannel->Lock);
693
694 ControlChannel->RefCount = 1;
695 ControlChannel->Free = ControlChannelFree;
696
697 /* Return address file object */
698 Request->Handle.ControlChannel = ControlChannel;
699
700 TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
701
702 return STATUS_SUCCESS;
703 }
704
705 /*
706 * FUNCTION: Closes a control channel file object
707 * ARGUMENTS:
708 * Request = Pointer to TDI request structure for this request
709 * RETURNS:
710 * Status of operation
711 */
712 NTSTATUS FileCloseControlChannel(
713 PTDI_REQUEST Request)
714 {
715 if (!Request->Handle.ControlChannel) return STATUS_INVALID_PARAMETER;
716
717 DereferenceObject((PCONTROL_CHANNEL)Request->Handle.ControlChannel);
718
719 Request->Handle.ControlChannel = NULL;
720
721 return STATUS_SUCCESS;
722 }
723
724 /* EOF */