Annotation of ntddk/src/network/tdi/connobj.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.