Annotation of ntddk/src/network/tdi/connobj.c, revision 1.1.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.