|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1989-1993 Microsoft Corporation
4:
5: Module Name:
6:
7: connobj.c
8:
9: Abstract:
10:
11: This module contains code which implements the TP_CONNECTION object.
12: Routines are provided to create, destroy, reference, and dereference,
13: transport connection objects.
14:
15: Environment:
16:
17: Kernel mode
18:
19: Revision History:
20:
21: --*/
22:
23: #include "st.h"
24:
25:
26:
27: VOID
28: StAllocateConnection(
29: IN PDEVICE_CONTEXT DeviceContext,
30: OUT PTP_CONNECTION *TransportConnection
31: )
32:
33: /*++
34:
35: Routine Description:
36:
37: This routine allocates storage for a transport connection. Some
38: minimal initialization is done.
39:
40: NOTE: This routine is called with the device context spinlock
41: held, or at such a time as synchronization is unnecessary.
42:
43: Arguments:
44:
45: DeviceContext - the device context for this connection to be
46: associated with.
47:
48: TransportConnection - Pointer to a place where this routine will
49: return a pointer to a transport connection structure. Returns
50: NULL if the storage cannot be allocated.
51:
52: Return Value:
53:
54: None.
55:
56: --*/
57:
58: {
59:
60: PTP_CONNECTION Connection;
61:
62: if ((DeviceContext->MemoryLimit != 0) &&
63: ((DeviceContext->MemoryUsage + sizeof(TP_CONNECTION)) >
64: DeviceContext->MemoryLimit)) {
65: PANIC("ST: Could not allocate connection: limit\n");
66: StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 103);
67: *TransportConnection = NULL;
68: return;
69: }
70:
71: Connection = (PTP_CONNECTION)ExAllocatePool (NonPagedPool,
72: sizeof (TP_CONNECTION));
73: if (Connection == NULL) {
74: PANIC("ST: Could not allocate connection: no pool\n");
75: StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 203);
76: *TransportConnection = NULL;
77: return;
78: }
79: RtlZeroMemory (Connection, sizeof(TP_CONNECTION));
80:
81: DeviceContext->MemoryUsage += sizeof(TP_CONNECTION);
82: ++DeviceContext->ConnectionAllocated;
83:
84: Connection->Type = ST_CONNECTION_SIGNATURE;
85: Connection->Size = sizeof (TP_CONNECTION);
86:
87: Connection->Provider = DeviceContext;
88: Connection->ProviderInterlock = &DeviceContext->Interlock;
89: KeInitializeSpinLock (&Connection->SpinLock);
90:
91: InitializeListHead (&Connection->LinkList);
92: InitializeListHead (&Connection->AddressFileList);
93: InitializeListHead (&Connection->AddressList);
94: InitializeListHead (&Connection->PacketWaitLinkage);
95: InitializeListHead (&Connection->PacketizeLinkage);
96: InitializeListHead (&Connection->SendQueue);
97: InitializeListHead (&Connection->ReceiveQueue);
98: InitializeListHead (&Connection->InProgressRequest);
99:
100: StAddSendPacket (DeviceContext);
101:
102: *TransportConnection = Connection;
103:
104: } /* StAllocateConnection */
105:
106:
107: VOID
108: StDeallocateConnection(
109: IN PDEVICE_CONTEXT DeviceContext,
110: IN PTP_CONNECTION TransportConnection
111: )
112:
113: /*++
114:
115: Routine Description:
116:
117: This routine frees storage for a transport connection.
118:
119: NOTE: This routine is called with the device context spinlock
120: held, or at such a time as synchronization is unnecessary.
121:
122: Arguments:
123:
124: DeviceContext - the device context for this connection to be
125: associated with.
126:
127: TransportConnection - Pointer to a transport connection structure.
128:
129: Return Value:
130:
131: None.
132:
133: --*/
134:
135: {
136:
137: ExFreePool (TransportConnection);
138: --DeviceContext->ConnectionAllocated;
139: DeviceContext->MemoryUsage -= sizeof(TP_CONNECTION);
140:
141: StRemoveSendPacket (DeviceContext);
142:
143: } /* StDeallocateConnection */
144:
145:
146: NTSTATUS
147: StCreateConnection(
148: IN PDEVICE_CONTEXT DeviceContext,
149: OUT PTP_CONNECTION *TransportConnection
150: )
151:
152: /*++
153:
154: Routine Description:
155:
156: This routine creates a transport connection. The reference count in the
157: connection is automatically set to 1, and the reference count in the
158: DeviceContext is incremented.
159:
160: Arguments:
161:
162: Address - the address for this connection to be associated with.
163:
164: TransportConnection - Pointer to a place where this routine will
165: return a pointer to a transport connection structure.
166:
167: Return Value:
168:
169: NTSTATUS - status of operation.
170:
171: --*/
172:
173: {
174: PTP_CONNECTION Connection;
175: KIRQL oldirql;
176: PLIST_ENTRY p;
177: UINT TempDataLen;
178:
179: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
180:
181: p = RemoveHeadList (&DeviceContext->ConnectionPool);
182: if (p == &DeviceContext->ConnectionPool) {
183:
184: if ((DeviceContext->ConnectionMaxAllocated == 0) ||
185: (DeviceContext->ConnectionAllocated < DeviceContext->ConnectionMaxAllocated)) {
186:
187: StAllocateConnection (DeviceContext, &Connection);
188:
189: } else {
190:
191: StWriteResourceErrorLog (DeviceContext, sizeof(TP_CONNECTION), 403);
192: Connection = NULL;
193:
194: }
195:
196: if (Connection == NULL) {
197: ++DeviceContext->ConnectionExhausted;
198: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
199: PANIC ("StCreateConnection: Could not allocate connection object!\n");
200: return STATUS_INSUFFICIENT_RESOURCES;
201: }
202:
203: } else {
204:
205: Connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
206:
207: }
208:
209: ++DeviceContext->ConnectionInUse;
210: if (DeviceContext->ConnectionInUse > DeviceContext->ConnectionMaxInUse) {
211: ++DeviceContext->ConnectionMaxInUse;
212: }
213:
214: DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
215: ++DeviceContext->ConnectionSamples;
216:
217: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
218:
219:
220: //
221: // We have two references; one is for creation, and the
222: // other is a temporary one so that the connection won't
223: // go away before the creator has a chance to access it.
224: //
225:
226: Connection->SpecialRefCount = 1;
227: Connection->ReferenceCount = -1; // this is -1 based
228:
229: //
230: // Initialize the request queues & components of this connection.
231: //
232:
233: InitializeListHead (&Connection->SendQueue);
234: InitializeListHead (&Connection->ReceiveQueue);
235: InitializeListHead (&Connection->InProgressRequest);
236: InitializeListHead (&Connection->AddressList);
237: InitializeListHead (&Connection->AddressFileList);
238: Connection->SpecialReceiveIrp = (PIRP)NULL;
239: Connection->Flags = 0;
240: Connection->Flags2 = 0;
241: Connection->MessageBytesReceived = (USHORT)0; // no data yet
242: Connection->MessageBytesAcked = (USHORT)0;
243: Connection->Context = NULL; // no context yet.
244: Connection->Status = STATUS_PENDING; // default StStopConnection status.
245: Connection->SendState = CONNECTION_SENDSTATE_IDLE;
246: Connection->CurrentReceiveRequest = (PTP_REQUEST)NULL;
247: Connection->DisconnectIrp = (PIRP)NULL;
248: Connection->CloseIrp = (PIRP)NULL;
249: Connection->AddressFile = NULL;
250: Connection->IndicationInProgress = FALSE;
251:
252: MacReturnMaxDataSize(
253: &DeviceContext->MacInfo,
254: NULL,
255: 0,
256: DeviceContext->MaxSendPacketSize,
257: &TempDataLen);
258: Connection->MaximumDataSize = TempDataLen - sizeof(ST_HEADER);
259:
260: StReferenceDeviceContext ("Create Connection", DeviceContext);
261:
262: *TransportConnection = Connection; // return the connection.
263:
264: return STATUS_SUCCESS;
265: } /* StCreateConnection */
266:
267:
268: NTSTATUS
269: StVerifyConnectionObject (
270: IN PTP_CONNECTION Connection
271: )
272:
273: /*++
274:
275: Routine Description:
276:
277: This routine is called to verify that the pointer given us in a file
278: object is in fact a valid connection object.
279:
280: Arguments:
281:
282: Connection - potential pointer to a TP_CONNECTION object.
283:
284: Return Value:
285:
286: STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
287:
288: --*/
289:
290: {
291: KIRQL oldirql;
292: NTSTATUS status = STATUS_SUCCESS;
293:
294: //
295: // try to verify the connection signature. If the signature is valid,
296: // get the connection spinlock, check its state, and increment the
297: // reference count if it's ok to use it. Note that being in the stopping
298: // state is an OK place to be and reference the connection; we can
299: // disassociate the address while running down.
300: //
301:
302: try {
303:
304: if ((Connection->Size == sizeof (TP_CONNECTION)) &&
305: (Connection->Type == ST_CONNECTION_SIGNATURE)) {
306:
307: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
308:
309: if ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0) {
310:
311: StReferenceConnection ("Verify Temp Use", Connection);
312:
313: } else {
314:
315: status = STATUS_INVALID_CONNECTION;
316: }
317:
318: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
319:
320: } else {
321:
322: status = STATUS_INVALID_CONNECTION;
323: }
324:
325: } except(EXCEPTION_EXECUTE_HANDLER) {
326:
327: return GetExceptionCode();
328: }
329:
330: return status;
331:
332: }
333:
334:
335: NTSTATUS
336: StDestroyAssociation(
337: IN PTP_CONNECTION TransportConnection
338: )
339:
340: /*++
341:
342: Routine Description:
343:
344: This routine destroys the association between a transport connection and
345: the address it was formerly associated with. The only action taken is
346: to disassociate the address and remove the connection from all address
347: queues.
348:
349: This routine is only called by StDereferenceConnection. The reason for
350: this is that there may be multiple streams of execution which are
351: simultaneously referencing the same connection object, and it should
352: not be deleted out from under an interested stream of execution.
353:
354: Arguments:
355:
356: TransportConnection - Pointer to a transport connection structure to
357: be destroyed.
358:
359: Return Value:
360:
361: NTSTATUS - status of operation.
362:
363: --*/
364:
365: {
366: KIRQL oldirql, oldirql2;
367: PTP_ADDRESS_FILE addressFile;
368:
369:
370: ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
371: if ((TransportConnection->Flags2 & CONNECTION_FLAGS2_ASSOCIATED) == 0) {
372: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
373: return STATUS_SUCCESS;
374: } else {
375: TransportConnection->Flags2 &= ~CONNECTION_FLAGS2_ASSOCIATED;
376: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
377: }
378:
379: addressFile = TransportConnection->AddressFile;
380:
381: //
382: // Delink this connection from its associated address connection
383: // database. To do this we must spin lock on the address object as
384: // well as on the connection,
385: //
386:
387: ACQUIRE_SPIN_LOCK (&addressFile->Address->SpinLock, &oldirql);
388: ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql2);
389: RemoveEntryList (&TransportConnection->AddressFileList);
390: RemoveEntryList (&TransportConnection->AddressList);
391:
392: InitializeListHead (&TransportConnection->AddressList);
393: InitializeListHead (&TransportConnection->AddressFileList);
394:
395: //
396: // remove the association between the address and the connection.
397: //
398:
399: TransportConnection->AddressFile = NULL;
400:
401: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql2);
402: RELEASE_SPIN_LOCK (&addressFile->Address->SpinLock, oldirql);
403:
404: //
405: // and remove a reference to the address
406: //
407:
408: StDereferenceAddress ("Destroy association", addressFile->Address);
409:
410:
411: return STATUS_SUCCESS;
412:
413: } /* StDestroyAssociation */
414:
415:
416: NTSTATUS
417: StIndicateDisconnect(
418: IN PTP_CONNECTION TransportConnection
419: )
420:
421: /*++
422:
423: Routine Description:
424:
425: This routine indicates a remote disconnection on this connection if it
426: is necessary to do so. No other action is taken here.
427:
428: This routine is only called by StDereferenceConnection. The reason for
429: this is that there may be multiple streams of execution which are
430: simultaneously referencing the same connection object, and it should
431: not be deleted out from under an interested stream of execution.
432:
433: Arguments:
434:
435: TransportConnection - Pointer to a transport connection structure to
436: be destroyed.
437:
438: Return Value:
439:
440: NTSTATUS - status of operation.
441:
442: --*/
443:
444: {
445: PTP_ADDRESS_FILE addressFile;
446: PDEVICE_CONTEXT DeviceContext;
447: ULONG DisconnectReason;
448: PIRP DisconnectIrp;
449: KIRQL oldirql;
450:
451: ACQUIRE_SPIN_LOCK (&TransportConnection->SpinLock, &oldirql);
452:
453: if (((TransportConnection->Flags2 & CONNECTION_FLAGS2_REQ_COMPLETED) != 0)) {
454:
455: //
456: // Turn off all but the still-relevant bits in the flags.
457: //
458:
459: ASSERT (TransportConnection->Flags & CONNECTION_FLAGS_STOPPING);
460:
461: TransportConnection->Flags = CONNECTION_FLAGS_STOPPING;
462: TransportConnection->Flags2 &=
463: (CONNECTION_FLAGS2_ASSOCIATED |
464: CONNECTION_FLAGS2_DISASSOCIATED |
465: CONNECTION_FLAGS2_CLOSING);
466:
467: //
468: // Clean up other stuff -- basically everything gets
469: // done here except for the flags and the status, since
470: // they are used to block other requests. When the connection
471: // is given back to us (in Accept, Connect, or Listen)
472: // they are cleared.
473: //
474:
475: TransportConnection->MessageBytesReceived = (USHORT)0; // no data yet
476: TransportConnection->MessageBytesAcked = (USHORT)0;
477:
478: TransportConnection->CurrentReceiveRequest = (PTP_REQUEST)NULL;
479:
480: DisconnectIrp = TransportConnection->DisconnectIrp;
481: TransportConnection->DisconnectIrp = (PIRP)NULL;
482:
483: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
484:
485:
486: DeviceContext = TransportConnection->Provider;
487: addressFile = TransportConnection->AddressFile;
488:
489:
490: //
491: // If this connection was stopped by a call to TdiDisconnect,
492: // we have to complete that. We save the Irp so we can return
493: // the connection to the pool before we complete the request.
494: //
495:
496:
497: if (DisconnectIrp != (PIRP)NULL) {
498:
499: //
500: // Now complete the IRP if needed. This will be non-null
501: // only if TdiDisconnect was called, and we have not
502: // yet completed it.
503: //
504:
505: DisconnectIrp->IoStatus.Information = 0;
506: DisconnectIrp->IoStatus.Status = STATUS_SUCCESS;
507: IoCompleteRequest (DisconnectIrp, IO_NETWORK_INCREMENT);
508:
509: } else if ((TransportConnection->Status != STATUS_LOCAL_DISCONNECT) &&
510: (addressFile->RegisteredDisconnectHandler == TRUE)) {
511:
512: //
513: // This was a remotely spawned disconnect, so indicate that
514: // to our client. Note that in the comparison above we
515: // check the status first, since if it is LOCAL_DISCONNECT
516: // addressFile may be NULL (BUGBUG: This is sort of a hack
517: // for PDK2, we should really indicate the disconnect inside
518: // StStopConnection, where we know addressFile is valid).
519: //
520:
521: //
522: // if the disconnection was remotely spawned, then indicate
523: // disconnect. In the case that a disconnect was issued at
524: // the same time as the connection went down remotely, we
525: // won't do this because DisconnectIrp will be non-NULL.
526: //
527:
528: //
529: // Invoke the user's disconnection event handler, if any. We do this here
530: // so that any outstanding sends will complete before we tear down the
531: // connection.
532: //
533:
534: DisconnectReason = 0;
535: if (TransportConnection->Flags & CONNECTION_FLAGS_ABORT) {
536: DisconnectReason |= TDI_DISCONNECT_ABORT;
537: }
538: if (TransportConnection->Flags & CONNECTION_FLAGS_DESTROY) {
539: DisconnectReason |= TDI_DISCONNECT_RELEASE;
540: }
541:
542: (*addressFile->DisconnectHandler)(
543: addressFile->DisconnectHandlerContext,
544: TransportConnection->Context,
545: 0,
546: NULL,
547: 0,
548: NULL,
549: DisconnectReason);
550:
551: }
552:
553: } else {
554:
555: //
556: // The client does not yet think that this connection
557: // is up...generally this happens due to request count
558: // fluctuation during connection setup.
559: //
560:
561: RELEASE_SPIN_LOCK (&TransportConnection->SpinLock, oldirql);
562:
563: }
564:
565:
566: return STATUS_SUCCESS;
567:
568: } /* StIndicateDisconnect */
569:
570:
571: NTSTATUS
572: StDestroyConnection(
573: IN PTP_CONNECTION TransportConnection
574: )
575:
576: /*++
577:
578: Routine Description:
579:
580: This routine destroys a transport connection and removes all references
581: made by it to other objects in the transport. The connection structure
582: is returned to our lookaside list. It is assumed that the caller
583: has removed all IRPs from the connections's queues first.
584:
585: This routine is only called by StDereferenceConnection. The reason for
586: this is that there may be multiple streams of execution which are
587: simultaneously referencing the same connection object, and it should
588: not be deleted out from under an interested stream of execution.
589:
590: Arguments:
591:
592: TransportConnection - Pointer to a transport connection structure to
593: be destroyed.
594:
595: Return Value:
596:
597: NTSTATUS - status of operation.
598:
599: --*/
600:
601: {
602: KIRQL oldirql;
603: PDEVICE_CONTEXT DeviceContext;
604: PIRP CloseIrp;
605:
606:
607: DeviceContext = TransportConnection->Provider;
608:
609: //
610: // Destroy any association that this connection has.
611: //
612:
613: StDestroyAssociation (TransportConnection);
614:
615: //
616: // Clear out any associated nasties hanging around the connection. Note
617: // that the current flags are set to STOPPING; this way anyone that may
618: // maliciously try to use the connection after it's dead and gone will
619: // just get ignored.
620: //
621:
622: TransportConnection->Flags = CONNECTION_FLAGS_STOPPING;
623: TransportConnection->Flags2 = CONNECTION_FLAGS2_CLOSING;
624: TransportConnection->MessageBytesReceived = (USHORT)0; // no data yet
625: TransportConnection->MessageBytesAcked = (USHORT)0;
626:
627:
628: //
629: // Now complete the close IRP. This will be set to non-null
630: // when CloseConnection was called.
631: //
632:
633: CloseIrp = TransportConnection->CloseIrp;
634:
635: if (CloseIrp != (PIRP)NULL) {
636:
637: TransportConnection->CloseIrp = (PIRP)NULL;
638: CloseIrp->IoStatus.Information = 0;
639: CloseIrp->IoStatus.Status = STATUS_SUCCESS;
640: IoCompleteRequest (CloseIrp, IO_NETWORK_INCREMENT);
641:
642: }
643:
644: //
645: // Return the connection to the provider's pool.
646: //
647:
648: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
649:
650: DeviceContext->ConnectionTotal += DeviceContext->ConnectionInUse;
651: ++DeviceContext->ConnectionSamples;
652: --DeviceContext->ConnectionInUse;
653:
654: if ((DeviceContext->ConnectionAllocated - DeviceContext->ConnectionInUse) >
655: DeviceContext->ConnectionInitAllocated) {
656: StDeallocateConnection (DeviceContext, TransportConnection);
657: } else {
658: InsertTailList (&DeviceContext->ConnectionPool, &TransportConnection->LinkList);
659: }
660:
661: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
662:
663: StDereferenceDeviceContext ("Destroy Connection", DeviceContext);
664:
665: return STATUS_SUCCESS;
666:
667: } /* StDestroyConnection */
668:
669:
670: VOID
671: StRefConnection(
672: IN PTP_CONNECTION TransportConnection
673: )
674:
675: /*++
676:
677: Routine Description:
678:
679: This routine increments the reference count on a transport connection.
680:
681: Arguments:
682:
683: TransportConnection - Pointer to a transport connection object.
684:
685: Return Value:
686:
687: none.
688:
689: --*/
690:
691: {
692: INTERLOCKED_RESULT result;
693:
694: result = ExInterlockedIncrementLong (
695: &TransportConnection->ReferenceCount,
696: TransportConnection->ProviderInterlock);
697:
698: if (result == ResultZero) {
699:
700: //
701: // The first increment causes us to increment the
702: // "ref count is not zero" special ref.
703: //
704:
705: ExInterlockedAddUlong(
706: (PULONG)(&TransportConnection->SpecialRefCount),
707: 1,
708: TransportConnection->ProviderInterlock);
709:
710: }
711:
712: ASSERT (result != ResultNegative);
713:
714: } /* StRefConnection */
715:
716:
717: VOID
718: StDerefConnection(
719: IN PTP_CONNECTION TransportConnection
720: )
721:
722: /*++
723:
724: Routine Description:
725:
726: This routine dereferences a transport connection by decrementing the
727: reference count contained in the structure. If, after being
728: decremented, the reference count is zero, then this routine calls
729: StDestroyConnection to remove it from the system.
730:
731: Arguments:
732:
733: TransportConnection - Pointer to a transport connection object.
734:
735: Return Value:
736:
737: none.
738:
739: --*/
740:
741: {
742: INTERLOCKED_RESULT result;
743:
744: result = ExInterlockedDecrementLong (
745: &TransportConnection->ReferenceCount,
746: TransportConnection->ProviderInterlock);
747:
748: //
749: // If all the normal references to this connection are gone, then
750: // we can remove the special reference that stood for
751: // "the regular ref count is non-zero".
752: //
753:
754: if (result == ResultNegative) {
755:
756: //
757: // If the refcount is -1, then we need to indicate
758: // disconnect. However, we need to
759: // do this before we actually do the special deref, since
760: // otherwise the connection might go away while we
761: // are doing that.
762: //
763:
764: StIndicateDisconnect (TransportConnection);
765:
766: //
767: // Now it is OK to let the connection go away.
768: //
769:
770: StDereferenceConnectionSpecial ("Regular ref gone", TransportConnection);
771:
772: }
773:
774: } /* StDerefConnection */
775:
776:
777: VOID
778: StDerefConnectionSpecial(
779: IN PTP_CONNECTION TransportConnection
780: )
781:
782: /*++
783:
784: Routine Description:
785:
786: This routines completes the dereferencing of a connection.
787: It may be called any time, but it does not do its work until
788: the regular reference count is also 0.
789:
790: Arguments:
791:
792: TransportConnection - Pointer to a transport connection object.
793:
794: Return Value:
795:
796: none.
797:
798: --*/
799:
800: {
801: KIRQL oldirql;
802:
803: ACQUIRE_SPIN_LOCK (TransportConnection->ProviderInterlock, &oldirql);
804:
805: --TransportConnection->SpecialRefCount;
806:
807: if ((TransportConnection->SpecialRefCount == 0) &&
808: (TransportConnection->ReferenceCount == -1)) {
809:
810: //
811: // If we have deleted all references to this connection, then we can
812: // destroy the object. It is okay to have already released the spin
813: // lock at this point because there is no possible way that another
814: // stream of execution has access to the connection any longer.
815: //
816:
817: RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
818:
819: StDestroyConnection (TransportConnection);
820:
821: } else {
822:
823: RELEASE_SPIN_LOCK (TransportConnection->ProviderInterlock, oldirql);
824:
825: }
826:
827: } /* StDerefConnectionSpecial */
828:
829:
830: PTP_CONNECTION
831: StFindConnection(
832: IN PDEVICE_CONTEXT DeviceContext,
833: IN PUCHAR LocalName,
834: IN PUCHAR RemoteName
835: )
836:
837: /*++
838:
839: Routine Description:
840:
841: This routine scans the connections associated with a
842: device context, and determines if there is an connection
843: associated with the specific remote address on the
844: specific local address.
845:
846: Arguments:
847:
848: DeviceContext - Pointer to the device context.
849:
850: LocalName - The 16-character Netbios name of the local address.
851:
852: RemoteName - The 16-character Netbios name of the remote.
853:
854: Return Value:
855:
856: The connection if one is found, NULL otherwise.
857:
858: --*/
859:
860: {
861: KIRQL oldirql;
862: PLIST_ENTRY Flink;
863: PTP_ADDRESS Address;
864: BOOLEAN MatchedAddress = FALSE;
865: PTP_CONNECTION Connection;
866:
867: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
868:
869: for (Flink = DeviceContext->AddressDatabase.Flink;
870: Flink != &DeviceContext->AddressDatabase;
871: Flink = Flink->Flink) {
872:
873: Address = CONTAINING_RECORD (
874: Flink,
875: TP_ADDRESS,
876: Linkage);
877:
878: if ((Address->Flags & ADDRESS_FLAGS_STOPPING) != 0) {
879: continue;
880: }
881:
882: if (StMatchNetbiosAddress (Address, LocalName)) {
883:
884: StReferenceAddress ("Looking for connection", Address); // prevent address from being destroyed.
885: MatchedAddress = TRUE;
886: break;
887:
888: }
889: }
890:
891: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
892:
893: if (!MatchedAddress) {
894: return NULL;
895: }
896:
897: Connection = StLookupRemoteName (Address, RemoteName);
898:
899: StDereferenceAddress ("Looking for connection", Address);
900:
901: return Connection;
902:
903: }
904:
905:
906: PTP_CONNECTION
907: StLookupConnectionByContext(
908: IN PTP_ADDRESS Address,
909: IN CONNECTION_CONTEXT ConnectionContext
910: )
911:
912: /*++
913:
914: Routine Description:
915:
916: This routine accepts a connection identifier and an address and
917: returns a pointer to the connection object, TP_CONNECTION. If the
918: connection identifier is not found on the address, then NULL is returned.
919: This routine automatically increments the reference count of the
920: TP_CONNECTION structure if it is found. It is assumed that the
921: TP_ADDRESS structure is already held with a reference count.
922:
923: BUGBUG: Should the ConnectionDatabase go in the address file?
924:
925: Arguments:
926:
927: Address - Pointer to a transport address object.
928:
929: ConnectionContext - Connection Context for this address.
930:
931: Return Value:
932:
933: A pointer to the connection we found
934:
935: --*/
936:
937: {
938: KIRQL oldirql, oldirql1;
939: PLIST_ENTRY p;
940: PTP_CONNECTION Connection;
941:
942: //
943: // Currently, this implementation is inefficient, but brute force so
944: // that a system can get up and running. Later, a cache of the mappings
945: // of popular connection id's and pointers to their TP_CONNECTION structures
946: // will be searched first.
947: //
948:
949: ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
950:
951: for (p=Address->ConnectionDatabase.Flink;
952: p != &Address->ConnectionDatabase;
953: p=p->Flink) {
954:
955:
956: Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
957:
958: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
959:
960: if ((Connection->Context == ConnectionContext) &&
961: ((Connection->Flags2 & CONNECTION_FLAGS2_CLOSING) == 0)) {
962: // This reference is removed by the calling function
963: StReferenceConnection ("Lookup up for request", Connection);
964: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
965: RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
966:
967: return Connection;
968: }
969:
970: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
971:
972: }
973:
974: RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
975:
976: return NULL;
977:
978: } /* StLookupConnectionByContext */
979:
980:
981: PTP_CONNECTION
982: StLookupListeningConnection(
983: IN PTP_ADDRESS Address
984: )
985:
986: /*++
987:
988: Routine Description:
989:
990: This routine scans the connection database on an address to find
991: a TP_CONNECTION object which has CONNECTION_FLAGS_WAIT_NQ
992: flag set. It returns a pointer to the found connection object (and
993: simultaneously resets the flag) or NULL if it could not be found.
994: The reference count is also incremented atomically on the connection.
995:
996: Arguments:
997:
998: Address - Pointer to a transport address object.
999:
1000: Return Value:
1001:
1002: NTSTATUS - status of operation.
1003:
1004: --*/
1005:
1006: {
1007: KIRQL oldirql, oldirql1;
1008: PTP_CONNECTION Connection;
1009: PLIST_ENTRY p;
1010:
1011:
1012: ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql);
1013:
1014: for (p=Address->ConnectionDatabase.Flink;
1015: p != &Address->ConnectionDatabase;
1016: p=p->Flink) {
1017:
1018:
1019: Connection = CONTAINING_RECORD (p, TP_CONNECTION, AddressList);
1020: if (Connection->Flags & CONNECTION_FLAGS_WAIT_LISTEN) {
1021:
1022: // This reference is removed by the calling function
1023: StReferenceConnection ("Found Listening", Connection);
1024:
1025: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
1026: Connection->Flags &= ~CONNECTION_FLAGS_WAIT_LISTEN;
1027: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
1028: RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
1029:
1030: return Connection;
1031: }
1032:
1033: }
1034:
1035: RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql);
1036:
1037: return NULL;
1038:
1039: } /* StLookupListeningConnection */
1040:
1041:
1042: VOID
1043: StStopConnection(
1044: IN PTP_CONNECTION Connection,
1045: IN NTSTATUS Status
1046: )
1047:
1048: /*++
1049:
1050: Routine Description:
1051:
1052: This routine is called to terminate all activity on a connection and
1053: destroy the object. This is done in a graceful manner; i.e., all
1054: outstanding requests are terminated by cancelling them, etc. It is
1055: assumed that the caller has a reference to this connection object,
1056: but this routine will do the dereference for the one issued at creation
1057: time.
1058:
1059: Orderly release is a function of this routine, but it is not a provided
1060: service of this transport provider, so there is no code to do it here.
1061:
1062: Arguments:
1063:
1064: Connection - Pointer to a TP_CONNECTION object.
1065:
1066: Status - The status that caused us to stop the connection. This
1067: will determine what status pending requests are aborted with,
1068: and also how we proceed during the stop (whether to send a
1069: session end, and whether to indicate disconnect).
1070:
1071: Return Value:
1072:
1073: none.
1074:
1075: --*/
1076:
1077: {
1078: KIRQL oldirql, oldirql1, cancelirql;
1079: PLIST_ENTRY p;
1080: PIRP Irp;
1081: PTP_REQUEST Request;
1082: ULONG DisconnectReason;
1083: PULONG StopCounter;
1084: PDEVICE_CONTEXT DeviceContext;
1085: BOOLEAN WasConnected;
1086:
1087:
1088: DeviceContext = Connection->Provider;
1089:
1090: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
1091: if (!(Connection->Flags & CONNECTION_FLAGS_STOPPING)) {
1092:
1093: //
1094: // We are stopping the connection, record statistics
1095: // about it.
1096: //
1097:
1098: if (Connection->Flags & CONNECTION_FLAGS_READY) {
1099:
1100: DECREMENT_COUNTER (DeviceContext, OpenConnections);
1101: WasConnected = TRUE;
1102:
1103: } else {
1104:
1105: WasConnected = FALSE;
1106:
1107: }
1108:
1109: Connection->Flags &= ~CONNECTION_FLAGS_READY; // no longer open for business
1110: Connection->Flags |= CONNECTION_FLAGS_STOPPING;
1111: Connection->Flags2 &= ~CONNECTION_FLAGS2_REMOTE_VALID;
1112: Connection->SendState = CONNECTION_SENDSTATE_IDLE;
1113: Connection->Status = Status;
1114:
1115: //
1116: // If this connection is waiting to packetize,
1117: // remove it from the device context queue it is on.
1118: //
1119: // NOTE: If the connection is currently in the
1120: // packetize queue, it will eventually go to get
1121: // packetized and at that point it will get
1122: // removed.
1123: //
1124:
1125: if (Connection->Flags & CONNECTION_FLAGS_SUSPENDED) {
1126:
1127: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql1);
1128: RemoveEntryList (&Connection->PacketWaitLinkage);
1129: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql1);
1130: }
1131:
1132:
1133: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
1134:
1135: IoAcquireCancelSpinLock(&cancelirql);
1136: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
1137:
1138:
1139: //
1140: // Run down all TdiSend requests on this connection.
1141: //
1142:
1143: while (TRUE) {
1144: p = RemoveHeadList (&Connection->SendQueue);
1145: if (p == &Connection->SendQueue) {
1146: break;
1147: }
1148: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
1149: Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry);
1150: Irp->CancelRoutine = (PDRIVER_CANCEL)NULL;
1151: IoReleaseCancelSpinLock(cancelirql);
1152: StCompleteSendIrp (Irp, Connection->Status, 0);
1153: IoAcquireCancelSpinLock(&cancelirql);
1154: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
1155: }
1156:
1157: //
1158: // NOTE: We hold the connection spinlock AND the
1159: // cancel spinlock here.
1160: //
1161:
1162: Connection->Flags &= ~CONNECTION_FLAGS_ACTIVE_RECEIVE;
1163:
1164: //
1165: // Run down all TdiReceive requests on this connection.
1166: //
1167:
1168: while (TRUE) {
1169: p = RemoveHeadList (&Connection->ReceiveQueue);
1170: if (p == &Connection->ReceiveQueue) {
1171: break;
1172: }
1173: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
1174: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
1175: Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
1176: IoReleaseCancelSpinLock(cancelirql);
1177:
1178: StCompleteRequest (Request, Connection->Status, 0);
1179: IoAcquireCancelSpinLock(&cancelirql);
1180: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
1181: }
1182:
1183:
1184: //
1185: // NOTE: We hold the connection spinlock AND the
1186: // cancel spinlock here.
1187: //
1188:
1189: //
1190: // Run down all TdiConnect/TdiDisconnect/TdiListen requests.
1191: //
1192:
1193: while (TRUE) {
1194: p = RemoveHeadList (&Connection->InProgressRequest);
1195: if (p == &Connection->InProgressRequest) {
1196: break;
1197: }
1198: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
1199: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
1200: Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
1201: IoReleaseCancelSpinLock(cancelirql);
1202:
1203: StCompleteRequest (Request, Connection->Status, 0);
1204:
1205: IoAcquireCancelSpinLock(&cancelirql);
1206: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
1207: }
1208:
1209: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
1210: IoReleaseCancelSpinLock(cancelirql);
1211:
1212: //
1213: // If we aren't DESTROYing the link, then send a SESSION_END frame
1214: // to the remote side. When the SESSION_END frame is acknowleged,
1215: // we will decrement the connection's reference count by one, removing
1216: // its creation reference. This will cause the connection object to
1217: // be disposed of, and will begin running down the link.
1218: // DGB: add logic to avoid blowing away link if one doesn't exist yet.
1219: //
1220:
1221: DisconnectReason = 0;
1222: if (Connection->Flags & CONNECTION_FLAGS_ABORT) {
1223: DisconnectReason |= TDI_DISCONNECT_ABORT;
1224: }
1225: if (Connection->Flags & CONNECTION_FLAGS_DESTROY) {
1226: DisconnectReason |= TDI_DISCONNECT_RELEASE;
1227: }
1228:
1229: //
1230: // When this completes we will dereference the connection.
1231: //
1232:
1233: if (WasConnected) {
1234: StSendDisconnect (Connection);
1235: }
1236:
1237:
1238: switch (Status) {
1239:
1240: case STATUS_LOCAL_DISCONNECT:
1241: StopCounter = &DeviceContext->LocalDisconnects;
1242: break;
1243: case STATUS_REMOTE_DISCONNECT:
1244: StopCounter = &DeviceContext->RemoteDisconnects;
1245: break;
1246: case STATUS_LINK_FAILED:
1247: StopCounter = &DeviceContext->LinkFailures;
1248: break;
1249: case STATUS_IO_TIMEOUT:
1250: StopCounter = &DeviceContext->SessionTimeouts;
1251: break;
1252: case STATUS_CANCELLED:
1253: StopCounter = &DeviceContext->CancelledConnections;
1254: break;
1255: case STATUS_REMOTE_RESOURCES:
1256: StopCounter = &DeviceContext->RemoteResourceFailures;
1257: break;
1258: case STATUS_INSUFFICIENT_RESOURCES:
1259: StopCounter = &DeviceContext->LocalResourceFailures;
1260: break;
1261: case STATUS_BAD_NETWORK_PATH:
1262: StopCounter = &DeviceContext->NotFoundFailures;
1263: break;
1264: case STATUS_REMOTE_NOT_LISTENING:
1265: StopCounter = &DeviceContext->NoListenFailures;
1266: break;
1267:
1268: default:
1269: StopCounter = NULL;
1270: break;
1271:
1272: }
1273:
1274: if (StopCounter != NULL) {
1275:
1276: ExInterlockedIncrementLong(
1277: (PLONG)StopCounter,
1278: &DeviceContext->StatisticsInterlock);
1279:
1280: }
1281:
1282:
1283: //
1284: // Note that we've blocked all new requests being queued during the
1285: // time we have been in this teardown code; StDestroyConnection also
1286: // sets the connection flags to STOPPING when returning the
1287: // connection to the queue. This avoids lingerers using non-existent
1288: // connections.
1289: //
1290:
1291: } else {
1292:
1293: //
1294: // The connection was already stopping.
1295: //
1296:
1297: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
1298:
1299: }
1300:
1301: } /* StStopConnection */
1302:
1303:
1304: VOID
1305: StCancelConnection(
1306: IN PDEVICE_OBJECT DeviceObject,
1307: IN PIRP Irp
1308: )
1309:
1310: /*++
1311:
1312: Routine Description:
1313:
1314: This routine is called by the I/O system to cancel a connect
1315: or a listen. It is simple since there can only be one of these
1316: active on a connection; we just stop the connection, the IRP
1317: will get completed as part of normal session teardown.
1318:
1319: NOTE: This routine is called with the CancelSpinLock held and
1320: is responsible for releasing it.
1321:
1322: Arguments:
1323:
1324: DeviceObject - Pointer to the device object for this driver.
1325:
1326: Irp - Pointer to the request packet representing the I/O request.
1327:
1328: Return Value:
1329:
1330: none.
1331:
1332: --*/
1333:
1334: {
1335: KIRQL oldirql;
1336: PIO_STACK_LOCATION IrpSp;
1337: PTP_CONNECTION Connection;
1338: PTP_REQUEST Request;
1339: PLIST_ENTRY p;
1340:
1341: UNREFERENCED_PARAMETER (DeviceObject);
1342:
1343: //
1344: // Get a pointer to the current stack location in the IRP. This is where
1345: // the function codes and parameters are stored.
1346: //
1347:
1348: IrpSp = IoGetCurrentIrpStackLocation (Irp);
1349:
1350: ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
1351: (IrpSp->MinorFunction == TDI_CONNECT || IrpSp->MinorFunction == TDI_LISTEN));
1352:
1353: Connection = IrpSp->FileObject->FsContext;
1354:
1355: //
1356: // Since this IRP is still in the cancellable state, we know
1357: // that the connection is still around (although it may be in
1358: // the process of being torn down).
1359: //
1360:
1361: ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
1362: StReferenceConnection ("Cancelling Send", Connection);
1363:
1364: p = RemoveHeadList (&Connection->InProgressRequest);
1365: ASSERT (p != &Connection->InProgressRequest);
1366:
1367: RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql);
1368:
1369: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
1370: ASSERT (Request->IoRequestPacket == Irp);
1371: Request->IoRequestPacket->CancelRoutine = (PDRIVER_CANCEL)NULL;
1372:
1373: IoReleaseCancelSpinLock(Irp->CancelIrql);
1374:
1375: StCompleteRequest (Request, STATUS_CANCELLED, 0);
1376: StStopConnection (Connection, STATUS_CANCELLED);
1377:
1378: StDereferenceConnection ("Cancel done", Connection);
1379:
1380: }
1381:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.